162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 1999 The Puffin Group
662306a36Sopenharmony_ci * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
762306a36Sopenharmony_ci * Copyright (c) 2001-2023 Helge Deller <deller@gmx.de>
862306a36Sopenharmony_ci * Copyright (c) 2001,2002 Ryan Bradetich
962306a36Sopenharmony_ci * Copyright (c) 2004-2005 Thibaut VARENE <varenet@parisc-linux.org>
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * The file handles registering devices and drivers, then matching them.
1262306a36Sopenharmony_ci * It's the closest we get to a dating agency.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * If you're thinking about modifying this file, here are some gotchas to
1562306a36Sopenharmony_ci * bear in mind:
1662306a36Sopenharmony_ci *  - 715/Mirage device paths have a dummy device between Lasi and its children
1762306a36Sopenharmony_ci *  - The EISA adapter may show up as a sibling or child of Wax
1862306a36Sopenharmony_ci *  - Dino has an optionally functional serial port.  If firmware enables it,
1962306a36Sopenharmony_ci *    it shows up as a child of Dino.  If firmware disables it, the buswalk
2062306a36Sopenharmony_ci *    finds it and it shows up as a child of Cujo
2162306a36Sopenharmony_ci *  - Dino has both parisc and pci devices as children
2262306a36Sopenharmony_ci *  - parisc devices are discovered in a random order, including children
2362306a36Sopenharmony_ci *    before parents in some cases.
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <linux/slab.h>
2762306a36Sopenharmony_ci#include <linux/types.h>
2862306a36Sopenharmony_ci#include <linux/kernel.h>
2962306a36Sopenharmony_ci#include <linux/pci.h>
3062306a36Sopenharmony_ci#include <linux/spinlock.h>
3162306a36Sopenharmony_ci#include <linux/string.h>
3262306a36Sopenharmony_ci#include <linux/export.h>
3362306a36Sopenharmony_ci#include <linux/dma-map-ops.h>
3462306a36Sopenharmony_ci#include <asm/hardware.h>
3562306a36Sopenharmony_ci#include <asm/io.h>
3662306a36Sopenharmony_ci#include <asm/pdc.h>
3762306a36Sopenharmony_ci#include <asm/parisc-device.h>
3862306a36Sopenharmony_ci#include <asm/ropes.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* See comments in include/asm-parisc/pci.h */
4162306a36Sopenharmony_ciconst struct dma_map_ops *hppa_dma_ops __ro_after_init;
4262306a36Sopenharmony_ciEXPORT_SYMBOL(hppa_dma_ops);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic struct device root = {
4562306a36Sopenharmony_ci	.init_name = "parisc",
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic inline int check_dev(struct device *dev)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	if (dev->bus == &parisc_bus_type) {
5162306a36Sopenharmony_ci		struct parisc_device *pdev;
5262306a36Sopenharmony_ci		pdev = to_parisc_device(dev);
5362306a36Sopenharmony_ci		return pdev->id.hw_type != HPHW_FAULTY;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci	return 1;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic struct device *
5962306a36Sopenharmony_ciparse_tree_node(struct device *parent, int index, struct hardware_path *modpath);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct recurse_struct {
6262306a36Sopenharmony_ci	void * obj;
6362306a36Sopenharmony_ci	int (*fn)(struct device *, void *);
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int descend_children(struct device * dev, void * data)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct recurse_struct * recurse_data = (struct recurse_struct *)data;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (recurse_data->fn(dev, recurse_data->obj))
7162306a36Sopenharmony_ci		return 1;
7262306a36Sopenharmony_ci	else
7362306a36Sopenharmony_ci		return device_for_each_child(dev, recurse_data, descend_children);
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/**
7762306a36Sopenharmony_ci * for_each_padev - Iterate over all devices in the tree
7862306a36Sopenharmony_ci * @fn: Function to call for each device.
7962306a36Sopenharmony_ci * @data: Data to pass to the called function.
8062306a36Sopenharmony_ci *
8162306a36Sopenharmony_ci * This performs a depth-first traversal of the tree, calling the
8262306a36Sopenharmony_ci * function passed for each node.  It calls the function for parents
8362306a36Sopenharmony_ci * before children.
8462306a36Sopenharmony_ci */
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic int for_each_padev(int (*fn)(struct device *, void *), void * data)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct recurse_struct recurse_data = {
8962306a36Sopenharmony_ci		.obj	= data,
9062306a36Sopenharmony_ci		.fn	= fn,
9162306a36Sopenharmony_ci	};
9262306a36Sopenharmony_ci	return device_for_each_child(&root, &recurse_data, descend_children);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/**
9662306a36Sopenharmony_ci * match_device - Report whether this driver can handle this device
9762306a36Sopenharmony_ci * @driver: the PA-RISC driver to try
9862306a36Sopenharmony_ci * @dev: the PA-RISC device to try
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_cistatic int match_device(struct parisc_driver *driver, struct parisc_device *dev)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	const struct parisc_device_id *ids;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	for (ids = driver->id_table; ids->sversion; ids++) {
10562306a36Sopenharmony_ci		if ((ids->sversion != SVERSION_ANY_ID) &&
10662306a36Sopenharmony_ci		    (ids->sversion != dev->id.sversion))
10762306a36Sopenharmony_ci			continue;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		if ((ids->hw_type != HWTYPE_ANY_ID) &&
11062306a36Sopenharmony_ci		    (ids->hw_type != dev->id.hw_type))
11162306a36Sopenharmony_ci			continue;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		if ((ids->hversion != HVERSION_ANY_ID) &&
11462306a36Sopenharmony_ci		    (ids->hversion != dev->id.hversion))
11562306a36Sopenharmony_ci			continue;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		return 1;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int parisc_driver_probe(struct device *dev)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	int rc;
12562306a36Sopenharmony_ci	struct parisc_device *pa_dev = to_parisc_device(dev);
12662306a36Sopenharmony_ci	struct parisc_driver *pa_drv = to_parisc_driver(dev->driver);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	rc = pa_drv->probe(pa_dev);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (!rc)
13162306a36Sopenharmony_ci		pa_dev->driver = pa_drv;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return rc;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void __exit parisc_driver_remove(struct device *dev)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct parisc_device *pa_dev = to_parisc_device(dev);
13962306a36Sopenharmony_ci	struct parisc_driver *pa_drv = to_parisc_driver(dev->driver);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (pa_drv->remove)
14262306a36Sopenharmony_ci		pa_drv->remove(pa_dev);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/**
14762306a36Sopenharmony_ci * register_parisc_driver - Register this driver if it can handle a device
14862306a36Sopenharmony_ci * @driver: the PA-RISC driver to try
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_ciint register_parisc_driver(struct parisc_driver *driver)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	/* FIXME: we need this because apparently the sti
15362306a36Sopenharmony_ci	 * driver can be registered twice */
15462306a36Sopenharmony_ci	if (driver->drv.name) {
15562306a36Sopenharmony_ci		pr_warn("BUG: skipping previously registered driver %s\n",
15662306a36Sopenharmony_ci			driver->name);
15762306a36Sopenharmony_ci		return 1;
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (!driver->probe) {
16162306a36Sopenharmony_ci		pr_warn("BUG: driver %s has no probe routine\n", driver->name);
16262306a36Sopenharmony_ci		return 1;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	driver->drv.bus = &parisc_bus_type;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* We install our own probe and remove routines */
16862306a36Sopenharmony_ci	WARN_ON(driver->drv.probe != NULL);
16962306a36Sopenharmony_ci	WARN_ON(driver->drv.remove != NULL);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	driver->drv.name = driver->name;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return driver_register(&driver->drv);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ciEXPORT_SYMBOL(register_parisc_driver);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistruct match_count {
17962306a36Sopenharmony_ci	struct parisc_driver * driver;
18062306a36Sopenharmony_ci	int count;
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int match_and_count(struct device * dev, void * data)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct match_count * m = data;
18662306a36Sopenharmony_ci	struct parisc_device * pdev = to_parisc_device(dev);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (check_dev(dev)) {
18962306a36Sopenharmony_ci		if (match_device(m->driver, pdev))
19062306a36Sopenharmony_ci			m->count++;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci	return 0;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/**
19662306a36Sopenharmony_ci * count_parisc_driver - count # of devices this driver would match
19762306a36Sopenharmony_ci * @driver: the PA-RISC driver to try
19862306a36Sopenharmony_ci *
19962306a36Sopenharmony_ci * Use by IOMMU support to "guess" the right size IOPdir.
20062306a36Sopenharmony_ci * Formula is something like memsize/(num_iommu * entry_size).
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_ciint __init count_parisc_driver(struct parisc_driver *driver)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct match_count m = {
20562306a36Sopenharmony_ci		.driver	= driver,
20662306a36Sopenharmony_ci		.count	= 0,
20762306a36Sopenharmony_ci	};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	for_each_padev(match_and_count, &m);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return m.count;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/**
21762306a36Sopenharmony_ci * unregister_parisc_driver - Unregister this driver from the list of drivers
21862306a36Sopenharmony_ci * @driver: the PA-RISC driver to unregister
21962306a36Sopenharmony_ci */
22062306a36Sopenharmony_ciint unregister_parisc_driver(struct parisc_driver *driver)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	driver_unregister(&driver->drv);
22362306a36Sopenharmony_ci	return 0;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ciEXPORT_SYMBOL(unregister_parisc_driver);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistruct find_data {
22862306a36Sopenharmony_ci	unsigned long hpa;
22962306a36Sopenharmony_ci	struct parisc_device * dev;
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic int find_device(struct device * dev, void * data)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct parisc_device * pdev = to_parisc_device(dev);
23562306a36Sopenharmony_ci	struct find_data * d = (struct find_data*)data;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (check_dev(dev)) {
23862306a36Sopenharmony_ci		if (pdev->hpa.start == d->hpa) {
23962306a36Sopenharmony_ci			d->dev = pdev;
24062306a36Sopenharmony_ci			return 1;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci	return 0;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic struct parisc_device *find_device_by_addr(unsigned long hpa)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct find_data d = {
24962306a36Sopenharmony_ci		.hpa	= hpa,
25062306a36Sopenharmony_ci	};
25162306a36Sopenharmony_ci	int ret;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	ret = for_each_padev(find_device, &d);
25462306a36Sopenharmony_ci	return ret ? d.dev : NULL;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int __init is_IKE_device(struct device *dev, void *data)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	struct parisc_device *pdev = to_parisc_device(dev);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (!check_dev(dev))
26262306a36Sopenharmony_ci		return 0;
26362306a36Sopenharmony_ci	if (pdev->id.hw_type != HPHW_BCPORT)
26462306a36Sopenharmony_ci		return 0;
26562306a36Sopenharmony_ci	if (IS_IKE(pdev) ||
26662306a36Sopenharmony_ci		(pdev->id.hversion == REO_MERCED_PORT) ||
26762306a36Sopenharmony_ci		(pdev->id.hversion == REOG_MERCED_PORT)) {
26862306a36Sopenharmony_ci			return 1;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci	return 0;
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ciint __init machine_has_merced_bus(void)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	int ret;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ret = for_each_padev(is_IKE_device, NULL);
27862306a36Sopenharmony_ci	return ret ? 1 : 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/**
28262306a36Sopenharmony_ci * find_pa_parent_type - Find a parent of a specific type
28362306a36Sopenharmony_ci * @padev: The device to start searching from
28462306a36Sopenharmony_ci * @type: The device type to search for.
28562306a36Sopenharmony_ci *
28662306a36Sopenharmony_ci * Walks up the device tree looking for a device of the specified type.
28762306a36Sopenharmony_ci * If it finds it, it returns it.  If not, it returns NULL.
28862306a36Sopenharmony_ci */
28962306a36Sopenharmony_ciconst struct parisc_device *
29062306a36Sopenharmony_cifind_pa_parent_type(const struct parisc_device *padev, int type)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	const struct device *dev = &padev->dev;
29362306a36Sopenharmony_ci	while (dev != &root) {
29462306a36Sopenharmony_ci		struct parisc_device *candidate = to_parisc_device(dev);
29562306a36Sopenharmony_ci		if (candidate->id.hw_type == type)
29662306a36Sopenharmony_ci			return candidate;
29762306a36Sopenharmony_ci		dev = dev->parent;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return NULL;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/*
30462306a36Sopenharmony_ci * get_node_path fills in @path with the firmware path to the device.
30562306a36Sopenharmony_ci * Note that if @node is a parisc device, we don't fill in the 'mod' field.
30662306a36Sopenharmony_ci * This is because both callers pass the parent and fill in the mod
30762306a36Sopenharmony_ci * themselves.  If @node is a PCI device, we do fill it in, even though this
30862306a36Sopenharmony_ci * is inconsistent.
30962306a36Sopenharmony_ci */
31062306a36Sopenharmony_cistatic void get_node_path(struct device *dev, struct hardware_path *path)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	int i = 5;
31362306a36Sopenharmony_ci	memset(&path->bc, -1, 6);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (dev_is_pci(dev)) {
31662306a36Sopenharmony_ci		unsigned int devfn = to_pci_dev(dev)->devfn;
31762306a36Sopenharmony_ci		path->mod = PCI_FUNC(devfn);
31862306a36Sopenharmony_ci		path->bc[i--] = PCI_SLOT(devfn);
31962306a36Sopenharmony_ci		dev = dev->parent;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	while (dev != &root) {
32362306a36Sopenharmony_ci		if (dev_is_pci(dev)) {
32462306a36Sopenharmony_ci			unsigned int devfn = to_pci_dev(dev)->devfn;
32562306a36Sopenharmony_ci			path->bc[i--] = PCI_SLOT(devfn) | (PCI_FUNC(devfn)<< 5);
32662306a36Sopenharmony_ci		} else if (dev->bus == &parisc_bus_type) {
32762306a36Sopenharmony_ci			path->bc[i--] = to_parisc_device(dev)->hw_path;
32862306a36Sopenharmony_ci		}
32962306a36Sopenharmony_ci		dev = dev->parent;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic char *print_hwpath(struct hardware_path *path, char *output)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	int i;
33662306a36Sopenharmony_ci	for (i = 0; i < 6; i++) {
33762306a36Sopenharmony_ci		if (path->bc[i] == -1)
33862306a36Sopenharmony_ci			continue;
33962306a36Sopenharmony_ci		output += sprintf(output, "%u/", (unsigned char) path->bc[i]);
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci	output += sprintf(output, "%u", (unsigned char) path->mod);
34262306a36Sopenharmony_ci	return output;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/**
34662306a36Sopenharmony_ci * print_pa_hwpath - Returns hardware path for PA devices
34762306a36Sopenharmony_ci * @dev: The device to return the path for
34862306a36Sopenharmony_ci * @output: Pointer to a previously-allocated array to place the path in.
34962306a36Sopenharmony_ci *
35062306a36Sopenharmony_ci * This function fills in the output array with a human-readable path
35162306a36Sopenharmony_ci * to a PA device.  This string is compatible with that used by PDC, and
35262306a36Sopenharmony_ci * may be printed on the outside of the box.
35362306a36Sopenharmony_ci */
35462306a36Sopenharmony_cichar *print_pa_hwpath(struct parisc_device *dev, char *output)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct hardware_path path;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	get_node_path(dev->dev.parent, &path);
35962306a36Sopenharmony_ci	path.mod = dev->hw_path;
36062306a36Sopenharmony_ci	return print_hwpath(&path, output);
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ciEXPORT_SYMBOL(print_pa_hwpath);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
36562306a36Sopenharmony_ci/**
36662306a36Sopenharmony_ci * get_pci_node_path - Determines the hardware path for a PCI device
36762306a36Sopenharmony_ci * @pdev: The device to return the path for
36862306a36Sopenharmony_ci * @path: Pointer to a previously-allocated array to place the path in.
36962306a36Sopenharmony_ci *
37062306a36Sopenharmony_ci * This function fills in the hardware_path structure with the route to
37162306a36Sopenharmony_ci * the specified PCI device.  This structure is suitable for passing to
37262306a36Sopenharmony_ci * PDC calls.
37362306a36Sopenharmony_ci */
37462306a36Sopenharmony_civoid get_pci_node_path(struct pci_dev *pdev, struct hardware_path *path)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	get_node_path(&pdev->dev, path);
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ciEXPORT_SYMBOL(get_pci_node_path);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/**
38162306a36Sopenharmony_ci * print_pci_hwpath - Returns hardware path for PCI devices
38262306a36Sopenharmony_ci * @dev: The device to return the path for
38362306a36Sopenharmony_ci * @output: Pointer to a previously-allocated array to place the path in.
38462306a36Sopenharmony_ci *
38562306a36Sopenharmony_ci * This function fills in the output array with a human-readable path
38662306a36Sopenharmony_ci * to a PCI device.  This string is compatible with that used by PDC, and
38762306a36Sopenharmony_ci * may be printed on the outside of the box.
38862306a36Sopenharmony_ci */
38962306a36Sopenharmony_cichar *print_pci_hwpath(struct pci_dev *dev, char *output)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct hardware_path path;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	get_pci_node_path(dev, &path);
39462306a36Sopenharmony_ci	return print_hwpath(&path, output);
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ciEXPORT_SYMBOL(print_pci_hwpath);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci#endif /* defined(CONFIG_PCI) || defined(CONFIG_ISA) */
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic void setup_bus_id(struct parisc_device *padev)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct hardware_path path;
40362306a36Sopenharmony_ci	char name[28];
40462306a36Sopenharmony_ci	char *output = name;
40562306a36Sopenharmony_ci	int i;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	get_node_path(padev->dev.parent, &path);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	for (i = 0; i < 6; i++) {
41062306a36Sopenharmony_ci		if (path.bc[i] == -1)
41162306a36Sopenharmony_ci			continue;
41262306a36Sopenharmony_ci		output += sprintf(output, "%u:", (unsigned char) path.bc[i]);
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci	sprintf(output, "%u", (unsigned char) padev->hw_path);
41562306a36Sopenharmony_ci	dev_set_name(&padev->dev, name);
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic struct parisc_device * __init create_tree_node(char id,
41962306a36Sopenharmony_ci						      struct device *parent)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct parisc_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
42262306a36Sopenharmony_ci	if (!dev)
42362306a36Sopenharmony_ci		return NULL;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	dev->hw_path = id;
42662306a36Sopenharmony_ci	dev->id.hw_type = HPHW_FAULTY;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	dev->dev.parent = parent;
42962306a36Sopenharmony_ci	setup_bus_id(dev);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	dev->dev.bus = &parisc_bus_type;
43262306a36Sopenharmony_ci	dev->dma_mask = 0xffffffffUL;	/* PARISC devices are 32-bit */
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	/* make the generic dma mask a pointer to the parisc one */
43562306a36Sopenharmony_ci	dev->dev.dma_mask = &dev->dma_mask;
43662306a36Sopenharmony_ci	dev->dev.coherent_dma_mask = dev->dma_mask;
43762306a36Sopenharmony_ci	if (device_register(&dev->dev)) {
43862306a36Sopenharmony_ci		kfree(dev);
43962306a36Sopenharmony_ci		return NULL;
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return dev;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistruct match_id_data {
44662306a36Sopenharmony_ci	char id;
44762306a36Sopenharmony_ci	struct parisc_device * dev;
44862306a36Sopenharmony_ci};
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic int match_by_id(struct device * dev, void * data)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	struct parisc_device * pdev = to_parisc_device(dev);
45362306a36Sopenharmony_ci	struct match_id_data * d = data;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (pdev->hw_path == d->id) {
45662306a36Sopenharmony_ci		d->dev = pdev;
45762306a36Sopenharmony_ci		return 1;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci	return 0;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci/**
46362306a36Sopenharmony_ci * alloc_tree_node - returns a device entry in the iotree
46462306a36Sopenharmony_ci * @parent: the parent node in the tree
46562306a36Sopenharmony_ci * @id: the element of the module path for this entry
46662306a36Sopenharmony_ci *
46762306a36Sopenharmony_ci * Checks all the children of @parent for a matching @id.  If none
46862306a36Sopenharmony_ci * found, it allocates a new device and returns it.
46962306a36Sopenharmony_ci */
47062306a36Sopenharmony_cistatic struct parisc_device * __init alloc_tree_node(
47162306a36Sopenharmony_ci			struct device *parent, char id)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	struct match_id_data d = {
47462306a36Sopenharmony_ci		.id = id,
47562306a36Sopenharmony_ci	};
47662306a36Sopenharmony_ci	if (device_for_each_child(parent, &d, match_by_id))
47762306a36Sopenharmony_ci		return d.dev;
47862306a36Sopenharmony_ci	else
47962306a36Sopenharmony_ci		return create_tree_node(id, parent);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic struct parisc_device *create_parisc_device(struct hardware_path *modpath)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	int i;
48562306a36Sopenharmony_ci	struct device *parent = &root;
48662306a36Sopenharmony_ci	for (i = 0; i < 6; i++) {
48762306a36Sopenharmony_ci		if (modpath->bc[i] == -1)
48862306a36Sopenharmony_ci			continue;
48962306a36Sopenharmony_ci		parent = &alloc_tree_node(parent, modpath->bc[i])->dev;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci	return alloc_tree_node(parent, modpath->mod);
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistruct parisc_device * __init
49562306a36Sopenharmony_cialloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	int status;
49862306a36Sopenharmony_ci	unsigned long bytecnt;
49962306a36Sopenharmony_ci	u8 iodc_data[32];
50062306a36Sopenharmony_ci	struct parisc_device *dev;
50162306a36Sopenharmony_ci	const char *name;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* Check to make sure this device has not already been added - Ryan */
50462306a36Sopenharmony_ci	if (find_device_by_addr(hpa) != NULL)
50562306a36Sopenharmony_ci		return NULL;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	status = pdc_iodc_read(&bytecnt, hpa, 0, &iodc_data, 32);
50862306a36Sopenharmony_ci	if (status != PDC_OK)
50962306a36Sopenharmony_ci		return NULL;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	dev = create_parisc_device(mod_path);
51262306a36Sopenharmony_ci	if (dev->id.hw_type != HPHW_FAULTY) {
51362306a36Sopenharmony_ci		pr_err("Two devices have hardware path [%s].  IODC data for second device: %7phN\n"
51462306a36Sopenharmony_ci		       "Rearranging GSC cards sometimes helps\n",
51562306a36Sopenharmony_ci			parisc_pathname(dev), iodc_data);
51662306a36Sopenharmony_ci		return NULL;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	dev->id.hw_type = iodc_data[3] & 0x1f;
52062306a36Sopenharmony_ci	dev->id.hversion = (iodc_data[0] << 4) | ((iodc_data[1] & 0xf0) >> 4);
52162306a36Sopenharmony_ci	dev->id.hversion_rev = iodc_data[1] & 0x0f;
52262306a36Sopenharmony_ci	dev->id.sversion = ((iodc_data[4] & 0x0f) << 16) |
52362306a36Sopenharmony_ci			(iodc_data[5] << 8) | iodc_data[6];
52462306a36Sopenharmony_ci	dev->hpa.start = hpa;
52562306a36Sopenharmony_ci	/* This is awkward.  The STI spec says that gfx devices may occupy
52662306a36Sopenharmony_ci	 * 32MB or 64MB.  Unfortunately, we don't know how to tell whether
52762306a36Sopenharmony_ci	 * it's the former or the latter.  Assumptions either way can hurt us.
52862306a36Sopenharmony_ci	 */
52962306a36Sopenharmony_ci	if (hpa == 0xf4000000 || hpa == 0xf8000000) {
53062306a36Sopenharmony_ci		dev->hpa.end = hpa + 0x03ffffff;
53162306a36Sopenharmony_ci	} else if (hpa == 0xf6000000 || hpa == 0xfa000000) {
53262306a36Sopenharmony_ci		dev->hpa.end = hpa + 0x01ffffff;
53362306a36Sopenharmony_ci	} else {
53462306a36Sopenharmony_ci		dev->hpa.end = hpa + 0xfff;
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci	dev->hpa.flags = IORESOURCE_MEM;
53762306a36Sopenharmony_ci	dev->hpa.name = dev->name;
53862306a36Sopenharmony_ci	name = parisc_hardware_description(&dev->id) ? : "unknown";
53962306a36Sopenharmony_ci	snprintf(dev->name, sizeof(dev->name), "%s [%s]",
54062306a36Sopenharmony_ci		name, parisc_pathname(dev));
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/* Silently fail things like mouse ports which are subsumed within
54362306a36Sopenharmony_ci	 * the keyboard controller
54462306a36Sopenharmony_ci	 */
54562306a36Sopenharmony_ci	if ((hpa & 0xfff) == 0 && insert_resource(&iomem_resource, &dev->hpa))
54662306a36Sopenharmony_ci		pr_warn("Unable to claim HPA %lx for device %s\n", hpa, name);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	return dev;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic int parisc_generic_match(struct device *dev, struct device_driver *drv)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	return match_device(to_parisc_driver(drv), to_parisc_device(dev));
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic ssize_t make_modalias(const struct device *dev, char *buf)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	const struct parisc_device *padev = to_parisc_device(dev);
55962306a36Sopenharmony_ci	const struct parisc_device_id *id = &padev->id;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	return sprintf(buf, "parisc:t%02Xhv%04Xrev%02Xsv%08X\n",
56262306a36Sopenharmony_ci		(u8)id->hw_type, (u16)id->hversion, (u8)id->hversion_rev,
56362306a36Sopenharmony_ci		(u32)id->sversion);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic int parisc_uevent(const struct device *dev, struct kobj_uevent_env *env)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	const struct parisc_device *padev;
56962306a36Sopenharmony_ci	char modalias[40];
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if (!dev)
57262306a36Sopenharmony_ci		return -ENODEV;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	padev = to_parisc_device(dev);
57562306a36Sopenharmony_ci	if (!padev)
57662306a36Sopenharmony_ci		return -ENODEV;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	if (add_uevent_var(env, "PARISC_NAME=%s", padev->name))
57962306a36Sopenharmony_ci		return -ENOMEM;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	make_modalias(dev, modalias);
58262306a36Sopenharmony_ci	if (add_uevent_var(env, "MODALIAS=%s", modalias))
58362306a36Sopenharmony_ci		return -ENOMEM;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	return 0;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci#define pa_dev_attr(name, field, format_string)				\
58962306a36Sopenharmony_cistatic ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf)		\
59062306a36Sopenharmony_ci{									\
59162306a36Sopenharmony_ci	struct parisc_device *padev = to_parisc_device(dev);		\
59262306a36Sopenharmony_ci	return sprintf(buf, format_string, padev->field);		\
59362306a36Sopenharmony_ci}									\
59462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci#define pa_dev_attr_id(field, format) pa_dev_attr(field, id.field, format)
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cipa_dev_attr(irq, irq, "%u\n");
59962306a36Sopenharmony_cipa_dev_attr_id(hw_type, "0x%02x\n");
60062306a36Sopenharmony_cipa_dev_attr(rev, id.hversion_rev, "0x%x\n");
60162306a36Sopenharmony_cipa_dev_attr_id(hversion, "0x%03x\n");
60262306a36Sopenharmony_cipa_dev_attr_id(sversion, "0x%05x\n");
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	return make_modalias(dev, buf);
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(modalias);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic struct attribute *parisc_device_attrs[] = {
61162306a36Sopenharmony_ci	&dev_attr_irq.attr,
61262306a36Sopenharmony_ci	&dev_attr_hw_type.attr,
61362306a36Sopenharmony_ci	&dev_attr_rev.attr,
61462306a36Sopenharmony_ci	&dev_attr_hversion.attr,
61562306a36Sopenharmony_ci	&dev_attr_sversion.attr,
61662306a36Sopenharmony_ci	&dev_attr_modalias.attr,
61762306a36Sopenharmony_ci	NULL,
61862306a36Sopenharmony_ci};
61962306a36Sopenharmony_ciATTRIBUTE_GROUPS(parisc_device);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistruct bus_type parisc_bus_type = {
62262306a36Sopenharmony_ci	.name = "parisc",
62362306a36Sopenharmony_ci	.match = parisc_generic_match,
62462306a36Sopenharmony_ci	.uevent = parisc_uevent,
62562306a36Sopenharmony_ci	.dev_groups = parisc_device_groups,
62662306a36Sopenharmony_ci	.probe = parisc_driver_probe,
62762306a36Sopenharmony_ci	.remove = __exit_p(parisc_driver_remove),
62862306a36Sopenharmony_ci};
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci/**
63162306a36Sopenharmony_ci * register_parisc_device - Locate a driver to manage this device.
63262306a36Sopenharmony_ci * @dev: The parisc device.
63362306a36Sopenharmony_ci *
63462306a36Sopenharmony_ci * Search the driver list for a driver that is willing to manage
63562306a36Sopenharmony_ci * this device.
63662306a36Sopenharmony_ci */
63762306a36Sopenharmony_ciint __init register_parisc_device(struct parisc_device *dev)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	if (!dev)
64062306a36Sopenharmony_ci		return 0;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (dev->driver)
64362306a36Sopenharmony_ci		return 1;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	return 0;
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci/**
64962306a36Sopenharmony_ci * match_pci_device - Matches a pci device against a given hardware path
65062306a36Sopenharmony_ci * entry.
65162306a36Sopenharmony_ci * @dev: the generic device (known to be contained by a pci_dev).
65262306a36Sopenharmony_ci * @index: the current BC index
65362306a36Sopenharmony_ci * @modpath: the hardware path.
65462306a36Sopenharmony_ci * @return: true if the device matches the hardware path.
65562306a36Sopenharmony_ci */
65662306a36Sopenharmony_cistatic int match_pci_device(struct device *dev, int index,
65762306a36Sopenharmony_ci		struct hardware_path *modpath)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
66062306a36Sopenharmony_ci	int id;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (index == 5) {
66362306a36Sopenharmony_ci		/* we are at the end of the path, and on the actual device */
66462306a36Sopenharmony_ci		unsigned int devfn = pdev->devfn;
66562306a36Sopenharmony_ci		return ((modpath->bc[5] == PCI_SLOT(devfn)) &&
66662306a36Sopenharmony_ci					(modpath->mod == PCI_FUNC(devfn)));
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/* index might be out of bounds for bc[] */
67062306a36Sopenharmony_ci	if (index >= 6)
67162306a36Sopenharmony_ci		return 0;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5);
67462306a36Sopenharmony_ci	return (modpath->bc[index] == id);
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci/**
67862306a36Sopenharmony_ci * match_parisc_device - Matches a parisc device against a given hardware
67962306a36Sopenharmony_ci * path entry.
68062306a36Sopenharmony_ci * @dev: the generic device (known to be contained by a parisc_device).
68162306a36Sopenharmony_ci * @index: the current BC index
68262306a36Sopenharmony_ci * @modpath: the hardware path.
68362306a36Sopenharmony_ci * @return: true if the device matches the hardware path.
68462306a36Sopenharmony_ci */
68562306a36Sopenharmony_cistatic int match_parisc_device(struct device *dev, int index,
68662306a36Sopenharmony_ci		struct hardware_path *modpath)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	struct parisc_device *curr = to_parisc_device(dev);
68962306a36Sopenharmony_ci	char id = (index == 6) ? modpath->mod : modpath->bc[index];
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	return (curr->hw_path == id);
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistruct parse_tree_data {
69562306a36Sopenharmony_ci	int index;
69662306a36Sopenharmony_ci	struct hardware_path * modpath;
69762306a36Sopenharmony_ci	struct device * dev;
69862306a36Sopenharmony_ci};
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic int check_parent(struct device * dev, void * data)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct parse_tree_data * d = data;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (check_dev(dev)) {
70562306a36Sopenharmony_ci		if (dev->bus == &parisc_bus_type) {
70662306a36Sopenharmony_ci			if (match_parisc_device(dev, d->index, d->modpath))
70762306a36Sopenharmony_ci				d->dev = dev;
70862306a36Sopenharmony_ci		} else if (dev_is_pci(dev)) {
70962306a36Sopenharmony_ci			if (match_pci_device(dev, d->index, d->modpath))
71062306a36Sopenharmony_ci				d->dev = dev;
71162306a36Sopenharmony_ci		} else if (dev->bus == NULL) {
71262306a36Sopenharmony_ci			/* we are on a bus bridge */
71362306a36Sopenharmony_ci			struct device *new = parse_tree_node(dev, d->index, d->modpath);
71462306a36Sopenharmony_ci			if (new)
71562306a36Sopenharmony_ci				d->dev = new;
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci	return d->dev != NULL;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci/**
72262306a36Sopenharmony_ci * parse_tree_node - returns a device entry in the iotree
72362306a36Sopenharmony_ci * @parent: the parent node in the tree
72462306a36Sopenharmony_ci * @index: the current BC index
72562306a36Sopenharmony_ci * @modpath: the hardware_path struct to match a device against
72662306a36Sopenharmony_ci * @return: The corresponding device if found, NULL otherwise.
72762306a36Sopenharmony_ci *
72862306a36Sopenharmony_ci * Checks all the children of @parent for a matching @id.  If none
72962306a36Sopenharmony_ci * found, it returns NULL.
73062306a36Sopenharmony_ci */
73162306a36Sopenharmony_cistatic struct device *
73262306a36Sopenharmony_ciparse_tree_node(struct device *parent, int index, struct hardware_path *modpath)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct parse_tree_data d = {
73562306a36Sopenharmony_ci		.index          = index,
73662306a36Sopenharmony_ci		.modpath        = modpath,
73762306a36Sopenharmony_ci	};
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	struct recurse_struct recurse_data = {
74062306a36Sopenharmony_ci		.obj	= &d,
74162306a36Sopenharmony_ci		.fn	= check_parent,
74262306a36Sopenharmony_ci	};
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	if (device_for_each_child(parent, &recurse_data, descend_children))
74562306a36Sopenharmony_ci		{ /* nothing */ };
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return d.dev;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci/**
75162306a36Sopenharmony_ci * hwpath_to_device - Finds the generic device corresponding to a given hardware path.
75262306a36Sopenharmony_ci * @modpath: the hardware path.
75362306a36Sopenharmony_ci * @return: The target device, NULL if not found.
75462306a36Sopenharmony_ci */
75562306a36Sopenharmony_cistruct device *hwpath_to_device(struct hardware_path *modpath)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	int i;
75862306a36Sopenharmony_ci	struct device *parent = &root;
75962306a36Sopenharmony_ci	for (i = 0; i < 6; i++) {
76062306a36Sopenharmony_ci		if (modpath->bc[i] == -1)
76162306a36Sopenharmony_ci			continue;
76262306a36Sopenharmony_ci		parent = parse_tree_node(parent, i, modpath);
76362306a36Sopenharmony_ci		if (!parent)
76462306a36Sopenharmony_ci			return NULL;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci	if (dev_is_pci(parent)) /* pci devices already parse MOD */
76762306a36Sopenharmony_ci		return parent;
76862306a36Sopenharmony_ci	else
76962306a36Sopenharmony_ci		return parse_tree_node(parent, 6, modpath);
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ciEXPORT_SYMBOL(hwpath_to_device);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci/**
77462306a36Sopenharmony_ci * device_to_hwpath - Populates the hwpath corresponding to the given device.
77562306a36Sopenharmony_ci * @dev: the target device
77662306a36Sopenharmony_ci * @path: pointer to a previously allocated hwpath struct to be filled in
77762306a36Sopenharmony_ci */
77862306a36Sopenharmony_civoid device_to_hwpath(struct device *dev, struct hardware_path *path)
77962306a36Sopenharmony_ci{
78062306a36Sopenharmony_ci	struct parisc_device *padev;
78162306a36Sopenharmony_ci	if (dev->bus == &parisc_bus_type) {
78262306a36Sopenharmony_ci		padev = to_parisc_device(dev);
78362306a36Sopenharmony_ci		get_node_path(dev->parent, path);
78462306a36Sopenharmony_ci		path->mod = padev->hw_path;
78562306a36Sopenharmony_ci	} else if (dev_is_pci(dev)) {
78662306a36Sopenharmony_ci		get_node_path(dev, path);
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ciEXPORT_SYMBOL(device_to_hwpath);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci#define BC_PORT_MASK 0x8
79262306a36Sopenharmony_ci#define BC_LOWER_PORT 0x8
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci#define BUS_CONVERTER(dev) \
79562306a36Sopenharmony_ci        ((dev->id.hw_type == HPHW_IOA) || (dev->id.hw_type == HPHW_BCPORT))
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci#define IS_LOWER_PORT(dev) \
79862306a36Sopenharmony_ci        ((gsc_readl(dev->hpa.start + offsetof(struct bc_module, io_status)) \
79962306a36Sopenharmony_ci                & BC_PORT_MASK) == BC_LOWER_PORT)
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci#define MAX_NATIVE_DEVICES 64
80262306a36Sopenharmony_ci#define NATIVE_DEVICE_OFFSET 0x1000
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci#define FLEX_MASK 	F_EXTEND(0xfffc0000)
80562306a36Sopenharmony_ci#define IO_IO_LOW	offsetof(struct bc_module, io_io_low)
80662306a36Sopenharmony_ci#define IO_IO_HIGH	offsetof(struct bc_module, io_io_high)
80762306a36Sopenharmony_ci#define READ_IO_IO_LOW(dev)  (unsigned long)(signed int)gsc_readl(dev->hpa.start + IO_IO_LOW)
80862306a36Sopenharmony_ci#define READ_IO_IO_HIGH(dev) (unsigned long)(signed int)gsc_readl(dev->hpa.start + IO_IO_HIGH)
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_cistatic void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
81162306a36Sopenharmony_ci                            struct device *parent);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_cistatic void __init walk_lower_bus(struct parisc_device *dev)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	unsigned long io_io_low, io_io_high;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	if (!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev))
81862306a36Sopenharmony_ci		return;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	if (dev->id.hw_type == HPHW_IOA) {
82162306a36Sopenharmony_ci		io_io_low = (unsigned long)(signed int)(READ_IO_IO_LOW(dev) << 16);
82262306a36Sopenharmony_ci		io_io_high = io_io_low + MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET;
82362306a36Sopenharmony_ci	} else {
82462306a36Sopenharmony_ci		io_io_low = (READ_IO_IO_LOW(dev) + ~FLEX_MASK) & FLEX_MASK;
82562306a36Sopenharmony_ci		io_io_high = (READ_IO_IO_HIGH(dev)+ ~FLEX_MASK) & FLEX_MASK;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	walk_native_bus(io_io_low, io_io_high, &dev->dev);
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci/**
83262306a36Sopenharmony_ci * walk_native_bus -- Probe a bus for devices
83362306a36Sopenharmony_ci * @io_io_low: Base address of this bus.
83462306a36Sopenharmony_ci * @io_io_high: Last address of this bus.
83562306a36Sopenharmony_ci * @parent: The parent bus device.
83662306a36Sopenharmony_ci *
83762306a36Sopenharmony_ci * A native bus (eg Runway or GSC) may have up to 64 devices on it,
83862306a36Sopenharmony_ci * spaced at intervals of 0x1000 bytes.  PDC may not inform us of these
83962306a36Sopenharmony_ci * devices, so we have to probe for them.  Unfortunately, we may find
84062306a36Sopenharmony_ci * devices which are not physically connected (such as extra serial &
84162306a36Sopenharmony_ci * keyboard ports).  This problem is not yet solved.
84262306a36Sopenharmony_ci */
84362306a36Sopenharmony_cistatic void __init walk_native_bus(unsigned long io_io_low,
84462306a36Sopenharmony_ci	unsigned long io_io_high, struct device *parent)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	int i, devices_found = 0;
84762306a36Sopenharmony_ci	unsigned long hpa = io_io_low;
84862306a36Sopenharmony_ci	struct hardware_path path;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	get_node_path(parent, &path);
85162306a36Sopenharmony_ci	do {
85262306a36Sopenharmony_ci		for(i = 0; i < MAX_NATIVE_DEVICES; i++, hpa += NATIVE_DEVICE_OFFSET) {
85362306a36Sopenharmony_ci			struct parisc_device *dev;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci			/* Was the device already added by Firmware? */
85662306a36Sopenharmony_ci			dev = find_device_by_addr(hpa);
85762306a36Sopenharmony_ci			if (!dev) {
85862306a36Sopenharmony_ci				path.mod = i;
85962306a36Sopenharmony_ci				dev = alloc_pa_dev(hpa, &path);
86062306a36Sopenharmony_ci				if (!dev)
86162306a36Sopenharmony_ci					continue;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci				register_parisc_device(dev);
86462306a36Sopenharmony_ci				devices_found++;
86562306a36Sopenharmony_ci			}
86662306a36Sopenharmony_ci			walk_lower_bus(dev);
86762306a36Sopenharmony_ci		}
86862306a36Sopenharmony_ci	} while(!devices_found && hpa < io_io_high);
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci#define CENTRAL_BUS_ADDR F_EXTEND(0xfff80000)
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci/**
87462306a36Sopenharmony_ci * walk_central_bus - Find devices attached to the central bus
87562306a36Sopenharmony_ci *
87662306a36Sopenharmony_ci * PDC doesn't tell us about all devices in the system.  This routine
87762306a36Sopenharmony_ci * finds devices connected to the central bus.
87862306a36Sopenharmony_ci */
87962306a36Sopenharmony_civoid __init walk_central_bus(void)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	walk_native_bus(CENTRAL_BUS_ADDR,
88262306a36Sopenharmony_ci			CENTRAL_BUS_ADDR + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET),
88362306a36Sopenharmony_ci			&root);
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_cistatic __init void print_parisc_device(struct parisc_device *dev)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	static int count __initdata;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	pr_info("%d. %s at %pap { type:%d, hv:%#x, sv:%#x, rev:%#x }",
89162306a36Sopenharmony_ci		++count, dev->name, &(dev->hpa.start), dev->id.hw_type,
89262306a36Sopenharmony_ci		dev->id.hversion, dev->id.sversion, dev->id.hversion_rev);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	if (dev->num_addrs) {
89562306a36Sopenharmony_ci		int k;
89662306a36Sopenharmony_ci		pr_cont(", additional addresses: ");
89762306a36Sopenharmony_ci		for (k = 0; k < dev->num_addrs; k++)
89862306a36Sopenharmony_ci			pr_cont("0x%lx ", dev->addr[k]);
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci	pr_cont("\n");
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci/**
90462306a36Sopenharmony_ci * init_parisc_bus - Some preparation to be done before inventory
90562306a36Sopenharmony_ci */
90662306a36Sopenharmony_civoid __init init_parisc_bus(void)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	if (bus_register(&parisc_bus_type))
90962306a36Sopenharmony_ci		panic("Could not register PA-RISC bus type\n");
91062306a36Sopenharmony_ci	if (device_register(&root))
91162306a36Sopenharmony_ci		panic("Could not register PA-RISC root device\n");
91262306a36Sopenharmony_ci	get_device(&root);
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic __init void qemu_header(void)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	int num;
91862306a36Sopenharmony_ci	unsigned long *p;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	pr_info("--- cut here ---\n");
92162306a36Sopenharmony_ci	pr_info("/* AUTO-GENERATED HEADER FILE FOR SEABIOS FIRMWARE */\n");
92262306a36Sopenharmony_ci	pr_cont("/* generated with Linux kernel */\n");
92362306a36Sopenharmony_ci	pr_cont("/* search for PARISC_QEMU_MACHINE_HEADER in Linux */\n\n");
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	pr_info("#define PARISC_MODEL \"%s\"\n\n",
92662306a36Sopenharmony_ci			boot_cpu_data.pdc.sys_model_name);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	#define p ((unsigned long *)&boot_cpu_data.pdc.model)
92962306a36Sopenharmony_ci	pr_info("#define PARISC_PDC_MODEL 0x%lx, 0x%lx, 0x%lx, "
93062306a36Sopenharmony_ci		"0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx\n\n",
93162306a36Sopenharmony_ci		p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
93262306a36Sopenharmony_ci	#undef p
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	pr_info("#define PARISC_PDC_VERSION 0x%04lx\n\n",
93562306a36Sopenharmony_ci			boot_cpu_data.pdc.versions);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	pr_info("#define PARISC_PDC_CPUID 0x%04lx\n\n",
93862306a36Sopenharmony_ci			boot_cpu_data.pdc.cpuid);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	pr_info("#define PARISC_PDC_CAPABILITIES 0x%04lx\n\n",
94162306a36Sopenharmony_ci			boot_cpu_data.pdc.capabilities);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	pr_info("#define PARISC_PDC_ENTRY_ORG 0x%04lx\n\n",
94462306a36Sopenharmony_ci#ifdef CONFIG_64BIT
94562306a36Sopenharmony_ci		(unsigned long)(PAGE0->mem_pdc_hi) << 32 |
94662306a36Sopenharmony_ci#endif
94762306a36Sopenharmony_ci		(unsigned long)PAGE0->mem_pdc);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	pr_info("#define PARISC_PDC_CACHE_INFO");
95062306a36Sopenharmony_ci	p = (unsigned long *) &cache_info;
95162306a36Sopenharmony_ci	for (num = 0; num < sizeof(cache_info); num += sizeof(unsigned long)) {
95262306a36Sopenharmony_ci		if (((num % 5) == 0)) {
95362306a36Sopenharmony_ci			pr_cont(" \\\n");
95462306a36Sopenharmony_ci			pr_info("\t");
95562306a36Sopenharmony_ci		}
95662306a36Sopenharmony_ci		pr_cont("%s0x%04lx",
95762306a36Sopenharmony_ci			num?", ":"", *p++);
95862306a36Sopenharmony_ci	}
95962306a36Sopenharmony_ci	pr_cont("\n\n");
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic __init int qemu_print_hpa(struct device *lin_dev, void *data)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	struct parisc_device *dev = to_parisc_device(lin_dev);
96562306a36Sopenharmony_ci	unsigned long hpa = dev->hpa.start;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	pr_cont("\t{\t.hpa = 0x%08lx,\\\n", hpa);
96862306a36Sopenharmony_ci	pr_cont("\t\t.iodc = &iodc_data_hpa_%08lx,\\\n", hpa);
96962306a36Sopenharmony_ci	pr_cont("\t\t.mod_info = &mod_info_hpa_%08lx,\\\n", hpa);
97062306a36Sopenharmony_ci	pr_cont("\t\t.mod_path = &mod_path_hpa_%08lx,\\\n", hpa);
97162306a36Sopenharmony_ci	pr_cont("\t\t.num_addr = HPA_%08lx_num_addr,\\\n", hpa);
97262306a36Sopenharmony_ci	pr_cont("\t\t.add_addr = { HPA_%08lx_add_addr } },\\\n", hpa);
97362306a36Sopenharmony_ci	return 0;
97462306a36Sopenharmony_ci}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_cistatic __init void qemu_footer(void)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	pr_info("\n\n#define PARISC_DEVICE_LIST \\\n");
98062306a36Sopenharmony_ci	for_each_padev(qemu_print_hpa, NULL);
98162306a36Sopenharmony_ci	pr_cont("\t{ 0, }\n");
98262306a36Sopenharmony_ci	pr_info("--- cut here ---\n");
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci/* print iodc data of the various hpa modules for qemu inclusion */
98662306a36Sopenharmony_cistatic __init int qemu_print_iodc_data(struct device *lin_dev, void *data)
98762306a36Sopenharmony_ci{
98862306a36Sopenharmony_ci	struct parisc_device *dev = to_parisc_device(lin_dev);
98962306a36Sopenharmony_ci	unsigned long count;
99062306a36Sopenharmony_ci	unsigned long hpa = dev->hpa.start;
99162306a36Sopenharmony_ci	int status;
99262306a36Sopenharmony_ci	struct pdc_iodc iodc_data;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	int mod_index;
99562306a36Sopenharmony_ci	struct pdc_system_map_mod_info pdc_mod_info;
99662306a36Sopenharmony_ci	struct pdc_module_path mod_path;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	status = pdc_iodc_read(&count, hpa, 0,
99962306a36Sopenharmony_ci		&iodc_data, sizeof(iodc_data));
100062306a36Sopenharmony_ci	if (status != PDC_OK) {
100162306a36Sopenharmony_ci		pr_info("No IODC data for hpa 0x%08lx\n", hpa);
100262306a36Sopenharmony_ci		return 0;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	pr_info("\n");
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	/* Prevent hung task messages when printing on serial console */
100862306a36Sopenharmony_ci	cond_resched();
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	pr_info("#define HPA_%08lx_DESCRIPTION \"%s\"\n",
101162306a36Sopenharmony_ci		hpa, parisc_hardware_description(&dev->id));
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	mod_index = 0;
101462306a36Sopenharmony_ci	do {
101562306a36Sopenharmony_ci		status = pdc_system_map_find_mods(&pdc_mod_info,
101662306a36Sopenharmony_ci				&mod_path, mod_index++);
101762306a36Sopenharmony_ci	} while (status == PDC_OK && pdc_mod_info.mod_addr != hpa);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	pr_info("static struct pdc_system_map_mod_info"
102062306a36Sopenharmony_ci		" mod_info_hpa_%08lx = {\n", hpa);
102162306a36Sopenharmony_ci	#define DO(member) \
102262306a36Sopenharmony_ci		pr_cont("\t." #member " = 0x%x,\n", \
102362306a36Sopenharmony_ci			(unsigned int)pdc_mod_info.member)
102462306a36Sopenharmony_ci	DO(mod_addr);
102562306a36Sopenharmony_ci	DO(mod_pgs);
102662306a36Sopenharmony_ci	DO(add_addrs);
102762306a36Sopenharmony_ci	pr_cont("};\n");
102862306a36Sopenharmony_ci	#undef DO
102962306a36Sopenharmony_ci	pr_info("static struct pdc_module_path "
103062306a36Sopenharmony_ci		"mod_path_hpa_%08lx = {\n", hpa);
103162306a36Sopenharmony_ci	pr_cont("\t.path = { ");
103262306a36Sopenharmony_ci	pr_cont(".flags = 0x%x, ", mod_path.path.flags);
103362306a36Sopenharmony_ci	pr_cont(".bc = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }, ",
103462306a36Sopenharmony_ci		(unsigned char)mod_path.path.bc[0],
103562306a36Sopenharmony_ci		(unsigned char)mod_path.path.bc[1],
103662306a36Sopenharmony_ci		(unsigned char)mod_path.path.bc[2],
103762306a36Sopenharmony_ci		(unsigned char)mod_path.path.bc[3],
103862306a36Sopenharmony_ci		(unsigned char)mod_path.path.bc[4],
103962306a36Sopenharmony_ci		(unsigned char)mod_path.path.bc[5]);
104062306a36Sopenharmony_ci	pr_cont(".mod = 0x%x ", mod_path.path.mod);
104162306a36Sopenharmony_ci	pr_cont(" },\n");
104262306a36Sopenharmony_ci	pr_cont("\t.layers = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }\n",
104362306a36Sopenharmony_ci		mod_path.layers[0], mod_path.layers[1], mod_path.layers[2],
104462306a36Sopenharmony_ci		mod_path.layers[3], mod_path.layers[4], mod_path.layers[5]);
104562306a36Sopenharmony_ci	pr_cont("};\n");
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	pr_info("static struct pdc_iodc iodc_data_hpa_%08lx = {\n", hpa);
104862306a36Sopenharmony_ci	#define DO(member) \
104962306a36Sopenharmony_ci		pr_cont("\t." #member " = 0x%04lx,\n", \
105062306a36Sopenharmony_ci			(unsigned long)iodc_data.member)
105162306a36Sopenharmony_ci	DO(hversion_model);
105262306a36Sopenharmony_ci	DO(hversion);
105362306a36Sopenharmony_ci	DO(spa);
105462306a36Sopenharmony_ci	DO(type);
105562306a36Sopenharmony_ci	DO(sversion_rev);
105662306a36Sopenharmony_ci	DO(sversion_model);
105762306a36Sopenharmony_ci	DO(sversion_opt);
105862306a36Sopenharmony_ci	DO(rev);
105962306a36Sopenharmony_ci	DO(dep);
106062306a36Sopenharmony_ci	DO(features);
106162306a36Sopenharmony_ci	DO(checksum);
106262306a36Sopenharmony_ci	DO(length);
106362306a36Sopenharmony_ci	#undef DO
106462306a36Sopenharmony_ci	pr_cont("\t/* pad: 0x%04x, 0x%04x */\n",
106562306a36Sopenharmony_ci		iodc_data.pad[0], iodc_data.pad[1]);
106662306a36Sopenharmony_ci	pr_cont("};\n");
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	pr_info("#define HPA_%08lx_num_addr %d\n", hpa, dev->num_addrs);
106962306a36Sopenharmony_ci	pr_info("#define HPA_%08lx_add_addr ", hpa);
107062306a36Sopenharmony_ci	count = 0;
107162306a36Sopenharmony_ci	if (dev->num_addrs == 0)
107262306a36Sopenharmony_ci		pr_cont("0");
107362306a36Sopenharmony_ci	while (count < dev->num_addrs) {
107462306a36Sopenharmony_ci		pr_cont("0x%08lx, ", dev->addr[count]);
107562306a36Sopenharmony_ci		count++;
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci	pr_cont("\n\n");
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	return 0;
108062306a36Sopenharmony_ci}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic __init int print_one_device(struct device * dev, void * data)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct parisc_device * pdev = to_parisc_device(dev);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	if (check_dev(dev))
108962306a36Sopenharmony_ci		print_parisc_device(pdev);
109062306a36Sopenharmony_ci	return 0;
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci/**
109462306a36Sopenharmony_ci * print_parisc_devices - Print out a list of devices found in this system
109562306a36Sopenharmony_ci */
109662306a36Sopenharmony_civoid __init print_parisc_devices(void)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	for_each_padev(print_one_device, NULL);
109962306a36Sopenharmony_ci	#define PARISC_QEMU_MACHINE_HEADER 0
110062306a36Sopenharmony_ci	if (PARISC_QEMU_MACHINE_HEADER) {
110162306a36Sopenharmony_ci		qemu_header();
110262306a36Sopenharmony_ci		for_each_padev(qemu_print_iodc_data, NULL);
110362306a36Sopenharmony_ci		qemu_footer();
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci}
1106