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