18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Bus & driver management routines for devices within 48c2ecf20Sopenharmony_ci * a MacIO ASIC. Interface to new driver model mostly 58c2ecf20Sopenharmony_ci * stolen from the PCI version. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2005 Ben. Herrenschmidt (benh@kernel.crashing.org) 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * TODO: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * - Don't probe below media bay by default, but instead provide 128c2ecf20Sopenharmony_ci * some hooks for media bay to dynamically add/remove it's own 138c2ecf20Sopenharmony_ci * sub-devices. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/string.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/pci.h> 198c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/of_address.h> 248c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <asm/machdep.h> 278c2ecf20Sopenharmony_ci#include <asm/macio.h> 288c2ecf20Sopenharmony_ci#include <asm/pmac_feature.h> 298c2ecf20Sopenharmony_ci#include <asm/prom.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#undef DEBUG 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define MAX_NODE_NAME_SIZE (20 - 12) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic struct macio_chip *macio_on_hold; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int macio_bus_match(struct device *dev, struct device_driver *drv) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci const struct of_device_id * matches = drv->of_match_table; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (!matches) 428c2ecf20Sopenharmony_ci return 0; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci return of_match_device(matches, dev) != NULL; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct macio_dev *macio_dev_get(struct macio_dev *dev) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct device *tmp; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (!dev) 528c2ecf20Sopenharmony_ci return NULL; 538c2ecf20Sopenharmony_ci tmp = get_device(&dev->ofdev.dev); 548c2ecf20Sopenharmony_ci if (tmp) 558c2ecf20Sopenharmony_ci return to_macio_device(tmp); 568c2ecf20Sopenharmony_ci else 578c2ecf20Sopenharmony_ci return NULL; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_civoid macio_dev_put(struct macio_dev *dev) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci if (dev) 638c2ecf20Sopenharmony_ci put_device(&dev->ofdev.dev); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int macio_device_probe(struct device *dev) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci int error = -ENODEV; 708c2ecf20Sopenharmony_ci struct macio_driver *drv; 718c2ecf20Sopenharmony_ci struct macio_dev *macio_dev; 728c2ecf20Sopenharmony_ci const struct of_device_id *match; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci drv = to_macio_driver(dev->driver); 758c2ecf20Sopenharmony_ci macio_dev = to_macio_device(dev); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (!drv->probe) 788c2ecf20Sopenharmony_ci return error; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci macio_dev_get(macio_dev); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci match = of_match_device(drv->driver.of_match_table, dev); 838c2ecf20Sopenharmony_ci if (match) 848c2ecf20Sopenharmony_ci error = drv->probe(macio_dev, match); 858c2ecf20Sopenharmony_ci if (error) 868c2ecf20Sopenharmony_ci macio_dev_put(macio_dev); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return error; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int macio_device_remove(struct device *dev) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct macio_dev * macio_dev = to_macio_device(dev); 948c2ecf20Sopenharmony_ci struct macio_driver * drv = to_macio_driver(dev->driver); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (dev->driver && drv->remove) 978c2ecf20Sopenharmony_ci drv->remove(macio_dev); 988c2ecf20Sopenharmony_ci macio_dev_put(macio_dev); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void macio_device_shutdown(struct device *dev) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct macio_dev * macio_dev = to_macio_device(dev); 1068c2ecf20Sopenharmony_ci struct macio_driver * drv = to_macio_driver(dev->driver); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (dev->driver && drv->shutdown) 1098c2ecf20Sopenharmony_ci drv->shutdown(macio_dev); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int macio_device_suspend(struct device *dev, pm_message_t state) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct macio_dev * macio_dev = to_macio_device(dev); 1158c2ecf20Sopenharmony_ci struct macio_driver * drv = to_macio_driver(dev->driver); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (dev->driver && drv->suspend) 1188c2ecf20Sopenharmony_ci return drv->suspend(macio_dev, state); 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int macio_device_resume(struct device * dev) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct macio_dev * macio_dev = to_macio_device(dev); 1258c2ecf20Sopenharmony_ci struct macio_driver * drv = to_macio_driver(dev->driver); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (dev->driver && drv->resume) 1288c2ecf20Sopenharmony_ci return drv->resume(macio_dev); 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciextern const struct attribute_group *macio_dev_groups[]; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistruct bus_type macio_bus_type = { 1358c2ecf20Sopenharmony_ci .name = "macio", 1368c2ecf20Sopenharmony_ci .match = macio_bus_match, 1378c2ecf20Sopenharmony_ci .uevent = of_device_uevent_modalias, 1388c2ecf20Sopenharmony_ci .probe = macio_device_probe, 1398c2ecf20Sopenharmony_ci .remove = macio_device_remove, 1408c2ecf20Sopenharmony_ci .shutdown = macio_device_shutdown, 1418c2ecf20Sopenharmony_ci .suspend = macio_device_suspend, 1428c2ecf20Sopenharmony_ci .resume = macio_device_resume, 1438c2ecf20Sopenharmony_ci .dev_groups = macio_dev_groups, 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int __init macio_bus_driver_init(void) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci return bus_register(&macio_bus_type); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cipostcore_initcall(macio_bus_driver_init); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/** 1558c2ecf20Sopenharmony_ci * macio_release_dev - free a macio device structure when all users of it are 1568c2ecf20Sopenharmony_ci * finished. 1578c2ecf20Sopenharmony_ci * @dev: device that's been disconnected 1588c2ecf20Sopenharmony_ci * 1598c2ecf20Sopenharmony_ci * Will be called only by the device core when all users of this macio device 1608c2ecf20Sopenharmony_ci * are done. This currently means never as we don't hot remove any macio 1618c2ecf20Sopenharmony_ci * device yet, though that will happen with mediabay based devices in a later 1628c2ecf20Sopenharmony_ci * implementation. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_cistatic void macio_release_dev(struct device *dev) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct macio_dev *mdev; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci mdev = to_macio_device(dev); 1698c2ecf20Sopenharmony_ci kfree(mdev); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/** 1738c2ecf20Sopenharmony_ci * macio_resource_quirks - tweak or skip some resources for a device 1748c2ecf20Sopenharmony_ci * @np: pointer to the device node 1758c2ecf20Sopenharmony_ci * @res: resulting resource 1768c2ecf20Sopenharmony_ci * @index: index of resource in node 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * If this routine returns non-null, then the resource is completely 1798c2ecf20Sopenharmony_ci * skipped. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic int macio_resource_quirks(struct device_node *np, struct resource *res, 1828c2ecf20Sopenharmony_ci int index) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci /* Only quirks for memory resources for now */ 1858c2ecf20Sopenharmony_ci if ((res->flags & IORESOURCE_MEM) == 0) 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Grand Central has too large resource 0 on some machines */ 1898c2ecf20Sopenharmony_ci if (index == 0 && of_node_name_eq(np, "gc")) 1908c2ecf20Sopenharmony_ci res->end = res->start + 0x1ffff; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Airport has bogus resource 2 */ 1938c2ecf20Sopenharmony_ci if (index >= 2 && of_node_name_eq(np, "radio")) 1948c2ecf20Sopenharmony_ci return 1; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#ifndef CONFIG_PPC64 1978c2ecf20Sopenharmony_ci /* DBDMAs may have bogus sizes */ 1988c2ecf20Sopenharmony_ci if ((res->start & 0x0001f000) == 0x00008000) 1998c2ecf20Sopenharmony_ci res->end = res->start + 0xff; 2008c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC64 */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* ESCC parent eats child resources. We could have added a 2038c2ecf20Sopenharmony_ci * level of hierarchy, but I don't really feel the need 2048c2ecf20Sopenharmony_ci * for it 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci if (of_node_name_eq(np, "escc")) 2078c2ecf20Sopenharmony_ci return 1; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* ESCC has bogus resources >= 3 */ 2108c2ecf20Sopenharmony_ci if (index >= 3 && (of_node_name_eq(np, "ch-a") || 2118c2ecf20Sopenharmony_ci of_node_name_eq(np, "ch-b"))) 2128c2ecf20Sopenharmony_ci return 1; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* Media bay has too many resources, keep only first one */ 2158c2ecf20Sopenharmony_ci if (index > 0 && of_node_name_eq(np, "media-bay")) 2168c2ecf20Sopenharmony_ci return 1; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* Some older IDE resources have bogus sizes */ 2198c2ecf20Sopenharmony_ci if (of_node_name_eq(np, "IDE") || of_node_name_eq(np, "ATA") || 2208c2ecf20Sopenharmony_ci of_node_is_type(np, "ide") || of_node_is_type(np, "ata")) { 2218c2ecf20Sopenharmony_ci if (index == 0 && (res->end - res->start) > 0xfff) 2228c2ecf20Sopenharmony_ci res->end = res->start + 0xfff; 2238c2ecf20Sopenharmony_ci if (index == 1 && (res->end - res->start) > 0xff) 2248c2ecf20Sopenharmony_ci res->end = res->start + 0xff; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic void macio_create_fixup_irq(struct macio_dev *dev, int index, 2308c2ecf20Sopenharmony_ci unsigned int line) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci unsigned int irq; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci irq = irq_create_mapping(NULL, line); 2358c2ecf20Sopenharmony_ci if (!irq) { 2368c2ecf20Sopenharmony_ci dev->interrupt[index].start = irq; 2378c2ecf20Sopenharmony_ci dev->interrupt[index].flags = IORESOURCE_IRQ; 2388c2ecf20Sopenharmony_ci dev->interrupt[index].name = dev_name(&dev->ofdev.dev); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci if (dev->n_interrupts <= index) 2418c2ecf20Sopenharmony_ci dev->n_interrupts = index + 1; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void macio_add_missing_resources(struct macio_dev *dev) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct device_node *np = dev->ofdev.dev.of_node; 2478c2ecf20Sopenharmony_ci unsigned int irq_base; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* Gatwick has some missing interrupts on child nodes */ 2508c2ecf20Sopenharmony_ci if (dev->bus->chip->type != macio_gatwick) 2518c2ecf20Sopenharmony_ci return; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* irq_base is always 64 on gatwick. I have no cleaner way to get 2548c2ecf20Sopenharmony_ci * that value from here at this point 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_ci irq_base = 64; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Fix SCC */ 2598c2ecf20Sopenharmony_ci if (of_node_name_eq(np, "ch-a")) { 2608c2ecf20Sopenharmony_ci macio_create_fixup_irq(dev, 0, 15 + irq_base); 2618c2ecf20Sopenharmony_ci macio_create_fixup_irq(dev, 1, 4 + irq_base); 2628c2ecf20Sopenharmony_ci macio_create_fixup_irq(dev, 2, 5 + irq_base); 2638c2ecf20Sopenharmony_ci printk(KERN_INFO "macio: fixed SCC irqs on gatwick\n"); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* Fix media-bay */ 2678c2ecf20Sopenharmony_ci if (of_node_name_eq(np, "media-bay")) { 2688c2ecf20Sopenharmony_ci macio_create_fixup_irq(dev, 0, 29 + irq_base); 2698c2ecf20Sopenharmony_ci printk(KERN_INFO "macio: fixed media-bay irq on gatwick\n"); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Fix left media bay childs */ 2738c2ecf20Sopenharmony_ci if (dev->media_bay != NULL && of_node_name_eq(np, "floppy")) { 2748c2ecf20Sopenharmony_ci macio_create_fixup_irq(dev, 0, 19 + irq_base); 2758c2ecf20Sopenharmony_ci macio_create_fixup_irq(dev, 1, 1 + irq_base); 2768c2ecf20Sopenharmony_ci printk(KERN_INFO "macio: fixed left floppy irqs\n"); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci if (dev->media_bay != NULL && of_node_name_eq(np, "ata4")) { 2798c2ecf20Sopenharmony_ci macio_create_fixup_irq(dev, 0, 14 + irq_base); 2808c2ecf20Sopenharmony_ci macio_create_fixup_irq(dev, 0, 3 + irq_base); 2818c2ecf20Sopenharmony_ci printk(KERN_INFO "macio: fixed left ide irqs\n"); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void macio_setup_interrupts(struct macio_dev *dev) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct device_node *np = dev->ofdev.dev.of_node; 2888c2ecf20Sopenharmony_ci unsigned int irq; 2898c2ecf20Sopenharmony_ci int i = 0, j = 0; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci for (;;) { 2928c2ecf20Sopenharmony_ci struct resource *res; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (j >= MACIO_DEV_COUNT_IRQS) 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci res = &dev->interrupt[j]; 2978c2ecf20Sopenharmony_ci irq = irq_of_parse_and_map(np, i++); 2988c2ecf20Sopenharmony_ci if (!irq) 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci res->start = irq; 3018c2ecf20Sopenharmony_ci res->flags = IORESOURCE_IRQ; 3028c2ecf20Sopenharmony_ci res->name = dev_name(&dev->ofdev.dev); 3038c2ecf20Sopenharmony_ci if (macio_resource_quirks(np, res, i - 1)) { 3048c2ecf20Sopenharmony_ci memset(res, 0, sizeof(struct resource)); 3058c2ecf20Sopenharmony_ci continue; 3068c2ecf20Sopenharmony_ci } else 3078c2ecf20Sopenharmony_ci j++; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci dev->n_interrupts = j; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void macio_setup_resources(struct macio_dev *dev, 3138c2ecf20Sopenharmony_ci struct resource *parent_res) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct device_node *np = dev->ofdev.dev.of_node; 3168c2ecf20Sopenharmony_ci struct resource r; 3178c2ecf20Sopenharmony_ci int index; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci for (index = 0; of_address_to_resource(np, index, &r) == 0; index++) { 3208c2ecf20Sopenharmony_ci struct resource *res; 3218c2ecf20Sopenharmony_ci if (index >= MACIO_DEV_COUNT_RESOURCES) 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci res = &dev->resource[index]; 3248c2ecf20Sopenharmony_ci *res = r; 3258c2ecf20Sopenharmony_ci res->name = dev_name(&dev->ofdev.dev); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (macio_resource_quirks(np, res, index)) { 3288c2ecf20Sopenharmony_ci memset(res, 0, sizeof(struct resource)); 3298c2ecf20Sopenharmony_ci continue; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci /* Currently, we consider failure as harmless, this may 3328c2ecf20Sopenharmony_ci * change in the future, once I've found all the device 3338c2ecf20Sopenharmony_ci * tree bugs in older machines & worked around them 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_ci if (insert_resource(parent_res, res)) { 3368c2ecf20Sopenharmony_ci printk(KERN_WARNING "Can't request resource " 3378c2ecf20Sopenharmony_ci "%d for MacIO device %s\n", 3388c2ecf20Sopenharmony_ci index, dev_name(&dev->ofdev.dev)); 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci dev->n_resources = index; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/** 3458c2ecf20Sopenharmony_ci * macio_add_one_device - Add one device from OF node to the device tree 3468c2ecf20Sopenharmony_ci * @chip: pointer to the macio_chip holding the device 3478c2ecf20Sopenharmony_ci * @np: pointer to the device node in the OF tree 3488c2ecf20Sopenharmony_ci * @in_bay: set to 1 if device is part of a media-bay 3498c2ecf20Sopenharmony_ci * 3508c2ecf20Sopenharmony_ci * When media-bay is changed to hotswap drivers, this function will 3518c2ecf20Sopenharmony_ci * be exposed to the bay driver some way... 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_cistatic struct macio_dev * macio_add_one_device(struct macio_chip *chip, 3548c2ecf20Sopenharmony_ci struct device *parent, 3558c2ecf20Sopenharmony_ci struct device_node *np, 3568c2ecf20Sopenharmony_ci struct macio_dev *in_bay, 3578c2ecf20Sopenharmony_ci struct resource *parent_res) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci char name[MAX_NODE_NAME_SIZE + 1]; 3608c2ecf20Sopenharmony_ci struct macio_dev *dev; 3618c2ecf20Sopenharmony_ci const u32 *reg; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (np == NULL) 3648c2ecf20Sopenharmony_ci return NULL; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 3678c2ecf20Sopenharmony_ci if (!dev) 3688c2ecf20Sopenharmony_ci return NULL; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci dev->bus = &chip->lbus; 3718c2ecf20Sopenharmony_ci dev->media_bay = in_bay; 3728c2ecf20Sopenharmony_ci dev->ofdev.dev.of_node = np; 3738c2ecf20Sopenharmony_ci dev->ofdev.archdata.dma_mask = 0xffffffffUL; 3748c2ecf20Sopenharmony_ci dev->ofdev.dev.dma_mask = &dev->ofdev.archdata.dma_mask; 3758c2ecf20Sopenharmony_ci dev->ofdev.dev.coherent_dma_mask = dev->ofdev.archdata.dma_mask; 3768c2ecf20Sopenharmony_ci dev->ofdev.dev.parent = parent; 3778c2ecf20Sopenharmony_ci dev->ofdev.dev.bus = &macio_bus_type; 3788c2ecf20Sopenharmony_ci dev->ofdev.dev.release = macio_release_dev; 3798c2ecf20Sopenharmony_ci dev->ofdev.dev.dma_parms = &dev->dma_parms; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Standard DMA paremeters */ 3828c2ecf20Sopenharmony_ci dma_set_max_seg_size(&dev->ofdev.dev, 65536); 3838c2ecf20Sopenharmony_ci dma_set_seg_boundary(&dev->ofdev.dev, 0xffffffff); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci#if defined(CONFIG_PCI) && defined(CONFIG_DMA_OPS) 3868c2ecf20Sopenharmony_ci /* Set the DMA ops to the ones from the PCI device, this could be 3878c2ecf20Sopenharmony_ci * fishy if we didn't know that on PowerMac it's always direct ops 3888c2ecf20Sopenharmony_ci * or iommu ops that will work fine 3898c2ecf20Sopenharmony_ci * 3908c2ecf20Sopenharmony_ci * To get all the fields, copy all archdata 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci dev->ofdev.dev.archdata = chip->lbus.pdev->dev.archdata; 3938c2ecf20Sopenharmony_ci dev->ofdev.dev.dma_ops = chip->lbus.pdev->dev.dma_ops; 3948c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI && CONFIG_DMA_OPS */ 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci#ifdef DEBUG 3978c2ecf20Sopenharmony_ci printk("preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p\n", 3988c2ecf20Sopenharmony_ci dev, &dev->ofdev, &dev->ofdev.dev, &dev->ofdev.dev.kobj); 3998c2ecf20Sopenharmony_ci#endif 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* MacIO itself has a different reg, we use it's PCI base */ 4028c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "%pOFn", np); 4038c2ecf20Sopenharmony_ci if (np == chip->of_node) { 4048c2ecf20Sopenharmony_ci dev_set_name(&dev->ofdev.dev, "%1d.%08x:%.*s", 4058c2ecf20Sopenharmony_ci chip->lbus.index, 4068c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 4078c2ecf20Sopenharmony_ci (unsigned int)pci_resource_start(chip->lbus.pdev, 0), 4088c2ecf20Sopenharmony_ci#else 4098c2ecf20Sopenharmony_ci 0, /* NuBus may want to do something better here */ 4108c2ecf20Sopenharmony_ci#endif 4118c2ecf20Sopenharmony_ci MAX_NODE_NAME_SIZE, name); 4128c2ecf20Sopenharmony_ci } else { 4138c2ecf20Sopenharmony_ci reg = of_get_property(np, "reg", NULL); 4148c2ecf20Sopenharmony_ci dev_set_name(&dev->ofdev.dev, "%1d.%08x:%.*s", 4158c2ecf20Sopenharmony_ci chip->lbus.index, 4168c2ecf20Sopenharmony_ci reg ? *reg : 0, MAX_NODE_NAME_SIZE, name); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Setup interrupts & resources */ 4208c2ecf20Sopenharmony_ci macio_setup_interrupts(dev); 4218c2ecf20Sopenharmony_ci macio_setup_resources(dev, parent_res); 4228c2ecf20Sopenharmony_ci macio_add_missing_resources(dev); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* Register with core */ 4258c2ecf20Sopenharmony_ci if (of_device_register(&dev->ofdev) != 0) { 4268c2ecf20Sopenharmony_ci printk(KERN_DEBUG"macio: device registration error for %s!\n", 4278c2ecf20Sopenharmony_ci dev_name(&dev->ofdev.dev)); 4288c2ecf20Sopenharmony_ci put_device(&dev->ofdev.dev); 4298c2ecf20Sopenharmony_ci return NULL; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return dev; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int macio_skip_device(struct device_node *np) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci return of_node_name_prefix(np, "battery") || 4388c2ecf20Sopenharmony_ci of_node_name_prefix(np, "escc-legacy"); 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci/** 4428c2ecf20Sopenharmony_ci * macio_pci_add_devices - Adds sub-devices of mac-io to the device tree 4438c2ecf20Sopenharmony_ci * @chip: pointer to the macio_chip holding the devices 4448c2ecf20Sopenharmony_ci * 4458c2ecf20Sopenharmony_ci * This function will do the job of extracting devices from the 4468c2ecf20Sopenharmony_ci * Open Firmware device tree, build macio_dev structures and add 4478c2ecf20Sopenharmony_ci * them to the Linux device tree. 4488c2ecf20Sopenharmony_ci * 4498c2ecf20Sopenharmony_ci * For now, childs of media-bay are added now as well. This will 4508c2ecf20Sopenharmony_ci * change rsn though. 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_cistatic void macio_pci_add_devices(struct macio_chip *chip) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct device_node *np, *pnode; 4558c2ecf20Sopenharmony_ci struct macio_dev *rdev, *mdev, *mbdev = NULL, *sdev = NULL; 4568c2ecf20Sopenharmony_ci struct device *parent = NULL; 4578c2ecf20Sopenharmony_ci struct resource *root_res = &iomem_resource; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* Add a node for the macio bus itself */ 4608c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 4618c2ecf20Sopenharmony_ci if (chip->lbus.pdev) { 4628c2ecf20Sopenharmony_ci parent = &chip->lbus.pdev->dev; 4638c2ecf20Sopenharmony_ci root_res = &chip->lbus.pdev->resource[0]; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci#endif 4668c2ecf20Sopenharmony_ci pnode = of_node_get(chip->of_node); 4678c2ecf20Sopenharmony_ci if (pnode == NULL) 4688c2ecf20Sopenharmony_ci return; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* Add macio itself to hierarchy */ 4718c2ecf20Sopenharmony_ci rdev = macio_add_one_device(chip, parent, pnode, NULL, root_res); 4728c2ecf20Sopenharmony_ci if (rdev == NULL) 4738c2ecf20Sopenharmony_ci return; 4748c2ecf20Sopenharmony_ci root_res = &rdev->resource[0]; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* First scan 1st level */ 4778c2ecf20Sopenharmony_ci for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) { 4788c2ecf20Sopenharmony_ci if (macio_skip_device(np)) 4798c2ecf20Sopenharmony_ci continue; 4808c2ecf20Sopenharmony_ci of_node_get(np); 4818c2ecf20Sopenharmony_ci mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL, 4828c2ecf20Sopenharmony_ci root_res); 4838c2ecf20Sopenharmony_ci if (mdev == NULL) 4848c2ecf20Sopenharmony_ci of_node_put(np); 4858c2ecf20Sopenharmony_ci else if (of_node_name_prefix(np, "media-bay")) 4868c2ecf20Sopenharmony_ci mbdev = mdev; 4878c2ecf20Sopenharmony_ci else if (of_node_name_prefix(np, "escc")) 4888c2ecf20Sopenharmony_ci sdev = mdev; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Add media bay devices if any */ 4928c2ecf20Sopenharmony_ci if (mbdev) { 4938c2ecf20Sopenharmony_ci pnode = mbdev->ofdev.dev.of_node; 4948c2ecf20Sopenharmony_ci for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) { 4958c2ecf20Sopenharmony_ci if (macio_skip_device(np)) 4968c2ecf20Sopenharmony_ci continue; 4978c2ecf20Sopenharmony_ci of_node_get(np); 4988c2ecf20Sopenharmony_ci if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, 4998c2ecf20Sopenharmony_ci mbdev, root_res) == NULL) 5008c2ecf20Sopenharmony_ci of_node_put(np); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Add serial ports if any */ 5058c2ecf20Sopenharmony_ci if (sdev) { 5068c2ecf20Sopenharmony_ci pnode = sdev->ofdev.dev.of_node; 5078c2ecf20Sopenharmony_ci for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) { 5088c2ecf20Sopenharmony_ci if (macio_skip_device(np)) 5098c2ecf20Sopenharmony_ci continue; 5108c2ecf20Sopenharmony_ci of_node_get(np); 5118c2ecf20Sopenharmony_ci if (macio_add_one_device(chip, &sdev->ofdev.dev, np, 5128c2ecf20Sopenharmony_ci NULL, root_res) == NULL) 5138c2ecf20Sopenharmony_ci of_node_put(np); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci/** 5208c2ecf20Sopenharmony_ci * macio_register_driver - Registers a new MacIO device driver 5218c2ecf20Sopenharmony_ci * @drv: pointer to the driver definition structure 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_ciint macio_register_driver(struct macio_driver *drv) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci /* initialize common driver fields */ 5268c2ecf20Sopenharmony_ci drv->driver.bus = &macio_bus_type; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* register with core */ 5298c2ecf20Sopenharmony_ci return driver_register(&drv->driver); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/** 5338c2ecf20Sopenharmony_ci * macio_unregister_driver - Unregisters a new MacIO device driver 5348c2ecf20Sopenharmony_ci * @drv: pointer to the driver definition structure 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_civoid macio_unregister_driver(struct macio_driver *drv) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci driver_unregister(&drv->driver); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/* Managed MacIO resources */ 5428c2ecf20Sopenharmony_cistruct macio_devres { 5438c2ecf20Sopenharmony_ci u32 res_mask; 5448c2ecf20Sopenharmony_ci}; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void maciom_release(struct device *gendev, void *res) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct macio_dev *dev = to_macio_device(gendev); 5498c2ecf20Sopenharmony_ci struct macio_devres *dr = res; 5508c2ecf20Sopenharmony_ci int i, max; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci max = min(dev->n_resources, 32); 5538c2ecf20Sopenharmony_ci for (i = 0; i < max; i++) { 5548c2ecf20Sopenharmony_ci if (dr->res_mask & (1 << i)) 5558c2ecf20Sopenharmony_ci macio_release_resource(dev, i); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ciint macio_enable_devres(struct macio_dev *dev) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct macio_devres *dr; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci dr = devres_find(&dev->ofdev.dev, maciom_release, NULL, NULL); 5648c2ecf20Sopenharmony_ci if (!dr) { 5658c2ecf20Sopenharmony_ci dr = devres_alloc(maciom_release, sizeof(*dr), GFP_KERNEL); 5668c2ecf20Sopenharmony_ci if (!dr) 5678c2ecf20Sopenharmony_ci return -ENOMEM; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci return devres_get(&dev->ofdev.dev, dr, NULL, NULL) != NULL; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic struct macio_devres * find_macio_dr(struct macio_dev *dev) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci return devres_find(&dev->ofdev.dev, maciom_release, NULL, NULL); 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/** 5788c2ecf20Sopenharmony_ci * macio_request_resource - Request an MMIO resource 5798c2ecf20Sopenharmony_ci * @dev: pointer to the device holding the resource 5808c2ecf20Sopenharmony_ci * @resource_no: resource number to request 5818c2ecf20Sopenharmony_ci * @name: resource name 5828c2ecf20Sopenharmony_ci * 5838c2ecf20Sopenharmony_ci * Mark memory region number @resource_no associated with MacIO 5848c2ecf20Sopenharmony_ci * device @dev as being reserved by owner @name. Do not access 5858c2ecf20Sopenharmony_ci * any address inside the memory regions unless this call returns 5868c2ecf20Sopenharmony_ci * successfully. 5878c2ecf20Sopenharmony_ci * 5888c2ecf20Sopenharmony_ci * Returns 0 on success, or %EBUSY on error. A warning 5898c2ecf20Sopenharmony_ci * message is also printed on failure. 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ciint macio_request_resource(struct macio_dev *dev, int resource_no, 5928c2ecf20Sopenharmony_ci const char *name) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct macio_devres *dr = find_macio_dr(dev); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (macio_resource_len(dev, resource_no) == 0) 5978c2ecf20Sopenharmony_ci return 0; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (!request_mem_region(macio_resource_start(dev, resource_no), 6008c2ecf20Sopenharmony_ci macio_resource_len(dev, resource_no), 6018c2ecf20Sopenharmony_ci name)) 6028c2ecf20Sopenharmony_ci goto err_out; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (dr && resource_no < 32) 6058c2ecf20Sopenharmony_ci dr->res_mask |= 1 << resource_no; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cierr_out: 6108c2ecf20Sopenharmony_ci printk (KERN_WARNING "MacIO: Unable to reserve resource #%d:%lx@%lx" 6118c2ecf20Sopenharmony_ci " for device %s\n", 6128c2ecf20Sopenharmony_ci resource_no, 6138c2ecf20Sopenharmony_ci macio_resource_len(dev, resource_no), 6148c2ecf20Sopenharmony_ci macio_resource_start(dev, resource_no), 6158c2ecf20Sopenharmony_ci dev_name(&dev->ofdev.dev)); 6168c2ecf20Sopenharmony_ci return -EBUSY; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci/** 6208c2ecf20Sopenharmony_ci * macio_release_resource - Release an MMIO resource 6218c2ecf20Sopenharmony_ci * @dev: pointer to the device holding the resource 6228c2ecf20Sopenharmony_ci * @resource_no: resource number to release 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_civoid macio_release_resource(struct macio_dev *dev, int resource_no) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct macio_devres *dr = find_macio_dr(dev); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (macio_resource_len(dev, resource_no) == 0) 6298c2ecf20Sopenharmony_ci return; 6308c2ecf20Sopenharmony_ci release_mem_region(macio_resource_start(dev, resource_no), 6318c2ecf20Sopenharmony_ci macio_resource_len(dev, resource_no)); 6328c2ecf20Sopenharmony_ci if (dr && resource_no < 32) 6338c2ecf20Sopenharmony_ci dr->res_mask &= ~(1 << resource_no); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci/** 6378c2ecf20Sopenharmony_ci * macio_request_resources - Reserve all memory resources 6388c2ecf20Sopenharmony_ci * @dev: MacIO device whose resources are to be reserved 6398c2ecf20Sopenharmony_ci * @name: Name to be associated with resource. 6408c2ecf20Sopenharmony_ci * 6418c2ecf20Sopenharmony_ci * Mark all memory regions associated with MacIO device @dev as 6428c2ecf20Sopenharmony_ci * being reserved by owner @name. Do not access any address inside 6438c2ecf20Sopenharmony_ci * the memory regions unless this call returns successfully. 6448c2ecf20Sopenharmony_ci * 6458c2ecf20Sopenharmony_ci * Returns 0 on success, or %EBUSY on error. A warning 6468c2ecf20Sopenharmony_ci * message is also printed on failure. 6478c2ecf20Sopenharmony_ci */ 6488c2ecf20Sopenharmony_ciint macio_request_resources(struct macio_dev *dev, const char *name) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci int i; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci for (i = 0; i < dev->n_resources; i++) 6538c2ecf20Sopenharmony_ci if (macio_request_resource(dev, i, name)) 6548c2ecf20Sopenharmony_ci goto err_out; 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cierr_out: 6588c2ecf20Sopenharmony_ci while(--i >= 0) 6598c2ecf20Sopenharmony_ci macio_release_resource(dev, i); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci return -EBUSY; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci/** 6658c2ecf20Sopenharmony_ci * macio_release_resources - Release reserved memory resources 6668c2ecf20Sopenharmony_ci * @dev: MacIO device whose resources were previously reserved 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_civoid macio_release_resources(struct macio_dev *dev) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci int i; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci for (i = 0; i < dev->n_resources; i++) 6748c2ecf20Sopenharmony_ci macio_release_resource(dev, i); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic int macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci struct device_node* np; 6838c2ecf20Sopenharmony_ci struct macio_chip* chip; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (ent->vendor != PCI_VENDOR_ID_APPLE) 6868c2ecf20Sopenharmony_ci return -ENODEV; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* Note regarding refcounting: We assume pci_device_to_OF_node() is 6898c2ecf20Sopenharmony_ci * ported to new OF APIs and returns a node with refcount incremented. 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci np = pci_device_to_OF_node(pdev); 6928c2ecf20Sopenharmony_ci if (np == NULL) 6938c2ecf20Sopenharmony_ci return -ENODEV; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* The above assumption is wrong !!! 6968c2ecf20Sopenharmony_ci * fix that here for now until I fix the arch code 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_ci of_node_get(np); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* We also assume that pmac_feature will have done a get() on nodes 7018c2ecf20Sopenharmony_ci * stored in the macio chips array 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ci chip = macio_find(np, macio_unknown); 7048c2ecf20Sopenharmony_ci of_node_put(np); 7058c2ecf20Sopenharmony_ci if (chip == NULL) 7068c2ecf20Sopenharmony_ci return -ENODEV; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* XXX Need locking ??? */ 7098c2ecf20Sopenharmony_ci if (chip->lbus.pdev == NULL) { 7108c2ecf20Sopenharmony_ci chip->lbus.pdev = pdev; 7118c2ecf20Sopenharmony_ci chip->lbus.chip = chip; 7128c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, &chip->lbus); 7138c2ecf20Sopenharmony_ci pci_set_master(pdev); 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci printk(KERN_INFO "MacIO PCI driver attached to %s chipset\n", 7178c2ecf20Sopenharmony_ci chip->name); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* 7208c2ecf20Sopenharmony_ci * HACK ALERT: The WallStreet PowerBook and some OHare based machines 7218c2ecf20Sopenharmony_ci * have 2 macio ASICs. I must probe the "main" one first or IDE 7228c2ecf20Sopenharmony_ci * ordering will be incorrect. So I put on "hold" the second one since 7238c2ecf20Sopenharmony_ci * it seem to appear first on PCI 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_ci if (chip->type == macio_gatwick || chip->type == macio_ohareII) 7268c2ecf20Sopenharmony_ci if (macio_chips[0].lbus.pdev == NULL) { 7278c2ecf20Sopenharmony_ci macio_on_hold = chip; 7288c2ecf20Sopenharmony_ci return 0; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci macio_pci_add_devices(chip); 7328c2ecf20Sopenharmony_ci if (macio_on_hold && macio_chips[0].lbus.pdev != NULL) { 7338c2ecf20Sopenharmony_ci macio_pci_add_devices(macio_on_hold); 7348c2ecf20Sopenharmony_ci macio_on_hold = NULL; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci return 0; 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic void macio_pci_remove(struct pci_dev* pdev) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci panic("removing of macio-asic not supported !\n"); 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci/* 7468c2ecf20Sopenharmony_ci * MacIO is matched against any Apple ID, it's probe() function 7478c2ecf20Sopenharmony_ci * will then decide wether it applies or not 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_cistatic const struct pci_device_id pci_ids[] = { { 7508c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_APPLE, 7518c2ecf20Sopenharmony_ci .device = PCI_ANY_ID, 7528c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 7538c2ecf20Sopenharmony_ci .subdevice = PCI_ANY_ID, 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci }, { /* end: all zeroes */ } 7568c2ecf20Sopenharmony_ci}; 7578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (pci, pci_ids); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci/* pci driver glue; this is a "new style" PCI driver module */ 7608c2ecf20Sopenharmony_cistatic struct pci_driver macio_pci_driver = { 7618c2ecf20Sopenharmony_ci .name = (char *) "macio", 7628c2ecf20Sopenharmony_ci .id_table = pci_ids, 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci .probe = macio_pci_probe, 7658c2ecf20Sopenharmony_ci .remove = macio_pci_remove, 7668c2ecf20Sopenharmony_ci}; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic int __init macio_module_init (void) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 7738c2ecf20Sopenharmony_ci int rc; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci rc = pci_register_driver(&macio_pci_driver); 7768c2ecf20Sopenharmony_ci if (rc) 7778c2ecf20Sopenharmony_ci return rc; 7788c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cimodule_init(macio_module_init); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(macio_register_driver); 7858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(macio_unregister_driver); 7868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(macio_dev_get); 7878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(macio_dev_put); 7888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(macio_request_resource); 7898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(macio_release_resource); 7908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(macio_request_resources); 7918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(macio_release_resources); 7928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(macio_enable_devres); 7938c2ecf20Sopenharmony_ci 794