11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 40 $) 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 51da177e4SLinus Torvalds * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 101da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 111da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or (at 121da177e4SLinus Torvalds * your option) any later version. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, but 151da177e4SLinus Torvalds * WITHOUT ANY WARRANTY; without even the implied warranty of 161da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 171da177e4SLinus Torvalds * General Public License for more details. 181da177e4SLinus Torvalds * 191da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License along 201da177e4SLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc., 211da177e4SLinus Torvalds * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 221da177e4SLinus Torvalds * 231da177e4SLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 241da177e4SLinus Torvalds */ 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include <linux/kernel.h> 271da177e4SLinus Torvalds #include <linux/module.h> 281da177e4SLinus Torvalds #include <linux/init.h> 291da177e4SLinus Torvalds #include <linux/types.h> 301da177e4SLinus Torvalds #include <linux/proc_fs.h> 311da177e4SLinus Torvalds #include <linux/spinlock.h> 321da177e4SLinus Torvalds #include <linux/pm.h> 33b67ea761SRafael J. Wysocki #include <linux/pm_runtime.h> 341da177e4SLinus Torvalds #include <linux/pci.h> 35990a7ac5SAndrew Patterson #include <linux/pci-acpi.h> 361da177e4SLinus Torvalds #include <linux/acpi.h> 371da177e4SLinus Torvalds #include <acpi/acpi_bus.h> 381da177e4SLinus Torvalds #include <acpi/acpi_drivers.h> 391da177e4SLinus Torvalds 40a192a958SLen Brown #define PREFIX "ACPI: " 41a192a958SLen Brown 421da177e4SLinus Torvalds #define _COMPONENT ACPI_PCI_COMPONENT 43f52fd66dSLen Brown ACPI_MODULE_NAME("pci_root"); 441da177e4SLinus Torvalds #define ACPI_PCI_ROOT_CLASS "pci_bridge" 451da177e4SLinus Torvalds #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" 461da177e4SLinus Torvalds static int acpi_pci_root_add(struct acpi_device *device); 471da177e4SLinus Torvalds static int acpi_pci_root_remove(struct acpi_device *device, int type); 48c431ada4SRajesh Shah static int acpi_pci_root_start(struct acpi_device *device); 491da177e4SLinus Torvalds 50c97adf9eSMárton Németh static const struct acpi_device_id root_device_ids[] = { 511ba90e3aSThomas Renninger {"PNP0A03", 0}, 521ba90e3aSThomas Renninger {"", 0}, 531ba90e3aSThomas Renninger }; 541ba90e3aSThomas Renninger MODULE_DEVICE_TABLE(acpi, root_device_ids); 551ba90e3aSThomas Renninger 561da177e4SLinus Torvalds static struct acpi_driver acpi_pci_root_driver = { 57c2b6705bSLen Brown .name = "pci_root", 581da177e4SLinus Torvalds .class = ACPI_PCI_ROOT_CLASS, 591ba90e3aSThomas Renninger .ids = root_device_ids, 601da177e4SLinus Torvalds .ops = { 611da177e4SLinus Torvalds .add = acpi_pci_root_add, 621da177e4SLinus Torvalds .remove = acpi_pci_root_remove, 63c431ada4SRajesh Shah .start = acpi_pci_root_start, 641da177e4SLinus Torvalds }, 651da177e4SLinus Torvalds }; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds static LIST_HEAD(acpi_pci_roots); 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds static struct acpi_pci_driver *sub_driver; 7063f10f0fSKenji Kaneshige static DEFINE_MUTEX(osc_lock); 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds int acpi_pci_register_driver(struct acpi_pci_driver *driver) 731da177e4SLinus Torvalds { 741da177e4SLinus Torvalds int n = 0; 75c1aec834SBjorn Helgaas struct acpi_pci_root *root; 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds struct acpi_pci_driver **pptr = &sub_driver; 781da177e4SLinus Torvalds while (*pptr) 791da177e4SLinus Torvalds pptr = &(*pptr)->next; 801da177e4SLinus Torvalds *pptr = driver; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds if (!driver->add) 831da177e4SLinus Torvalds return 0; 841da177e4SLinus Torvalds 85c1aec834SBjorn Helgaas list_for_each_entry(root, &acpi_pci_roots, node) { 862d1e0a02SPatrick Mochel driver->add(root->device->handle); 871da177e4SLinus Torvalds n++; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds return n; 911da177e4SLinus Torvalds } 924be44fcdSLen Brown 931da177e4SLinus Torvalds EXPORT_SYMBOL(acpi_pci_register_driver); 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) 961da177e4SLinus Torvalds { 97c1aec834SBjorn Helgaas struct acpi_pci_root *root; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds struct acpi_pci_driver **pptr = &sub_driver; 1001da177e4SLinus Torvalds while (*pptr) { 101f10bb254SAkinobu Mita if (*pptr == driver) 1021da177e4SLinus Torvalds break; 103f10bb254SAkinobu Mita pptr = &(*pptr)->next; 1041da177e4SLinus Torvalds } 105f10bb254SAkinobu Mita BUG_ON(!*pptr); 106f10bb254SAkinobu Mita *pptr = (*pptr)->next; 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds if (!driver->remove) 1091da177e4SLinus Torvalds return; 1101da177e4SLinus Torvalds 111c1aec834SBjorn Helgaas list_for_each_entry(root, &acpi_pci_roots, node) 1122d1e0a02SPatrick Mochel driver->remove(root->device->handle); 1131da177e4SLinus Torvalds } 1144be44fcdSLen Brown 1151da177e4SLinus Torvalds EXPORT_SYMBOL(acpi_pci_unregister_driver); 1161da177e4SLinus Torvalds 117d91a0078SJustin Chen acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) 118d91a0078SJustin Chen { 119c1aec834SBjorn Helgaas struct acpi_pci_root *root; 120d91a0078SJustin Chen 121c1aec834SBjorn Helgaas list_for_each_entry(root, &acpi_pci_roots, node) 1220705495dSBjorn Helgaas if ((root->segment == (u16) seg) && (root->bus_nr == (u16) bus)) 123c1aec834SBjorn Helgaas return root->device->handle; 124d91a0078SJustin Chen return NULL; 125d91a0078SJustin Chen } 126d91a0078SJustin Chen 127d91a0078SJustin Chen EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); 128d91a0078SJustin Chen 12927558203SAlexander Chiang /** 13027558203SAlexander Chiang * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge 13127558203SAlexander Chiang * @handle - the ACPI CA node in question. 13227558203SAlexander Chiang * 13327558203SAlexander Chiang * Note: we could make this API take a struct acpi_device * instead, but 13427558203SAlexander Chiang * for now, it's more convenient to operate on an acpi_handle. 13527558203SAlexander Chiang */ 13627558203SAlexander Chiang int acpi_is_root_bridge(acpi_handle handle) 13727558203SAlexander Chiang { 13827558203SAlexander Chiang int ret; 13927558203SAlexander Chiang struct acpi_device *device; 14027558203SAlexander Chiang 14127558203SAlexander Chiang ret = acpi_bus_get_device(handle, &device); 14227558203SAlexander Chiang if (ret) 14327558203SAlexander Chiang return 0; 14427558203SAlexander Chiang 14527558203SAlexander Chiang ret = acpi_match_device_ids(device, root_device_ids); 14627558203SAlexander Chiang if (ret) 14727558203SAlexander Chiang return 0; 14827558203SAlexander Chiang else 14927558203SAlexander Chiang return 1; 15027558203SAlexander Chiang } 15127558203SAlexander Chiang EXPORT_SYMBOL_GPL(acpi_is_root_bridge); 15227558203SAlexander Chiang 1531da177e4SLinus Torvalds static acpi_status 1541da177e4SLinus Torvalds get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) 1551da177e4SLinus Torvalds { 15650dd0969SJan Engelhardt int *busnr = data; 1571da177e4SLinus Torvalds struct acpi_resource_address64 address; 1581da177e4SLinus Torvalds 15950eca3ebSBob Moore if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 && 16050eca3ebSBob Moore resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 && 16150eca3ebSBob Moore resource->type != ACPI_RESOURCE_TYPE_ADDRESS64) 1621da177e4SLinus Torvalds return AE_OK; 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds acpi_resource_to_address64(resource, &address); 1651da177e4SLinus Torvalds if ((address.address_length > 0) && 1661da177e4SLinus Torvalds (address.resource_type == ACPI_BUS_NUMBER_RANGE)) 16750eca3ebSBob Moore *busnr = address.minimum; 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds return AE_OK; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 172f5eebbe1SBjorn Helgaas static acpi_status try_get_root_bridge_busnr(acpi_handle handle, 173f5eebbe1SBjorn Helgaas unsigned long long *bus) 1741da177e4SLinus Torvalds { 1751da177e4SLinus Torvalds acpi_status status; 176f5eebbe1SBjorn Helgaas int busnum; 1771da177e4SLinus Torvalds 178f5eebbe1SBjorn Helgaas busnum = -1; 1794be44fcdSLen Brown status = 1804be44fcdSLen Brown acpi_walk_resources(handle, METHOD_NAME__CRS, 181f5eebbe1SBjorn Helgaas get_root_bridge_busnr_callback, &busnum); 1821da177e4SLinus Torvalds if (ACPI_FAILURE(status)) 1831da177e4SLinus Torvalds return status; 1841da177e4SLinus Torvalds /* Check if we really get a bus number from _CRS */ 185f5eebbe1SBjorn Helgaas if (busnum == -1) 1861da177e4SLinus Torvalds return AE_ERROR; 187f5eebbe1SBjorn Helgaas *bus = busnum; 1881da177e4SLinus Torvalds return AE_OK; 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 1912786f6e3SRui Zhang static void acpi_pci_bridge_scan(struct acpi_device *device) 1922786f6e3SRui Zhang { 1932786f6e3SRui Zhang int status; 1942786f6e3SRui Zhang struct acpi_device *child = NULL; 1952786f6e3SRui Zhang 1962786f6e3SRui Zhang if (device->flags.bus_address) 1972786f6e3SRui Zhang if (device->parent && device->parent->ops.bind) { 1982786f6e3SRui Zhang status = device->parent->ops.bind(device); 1992786f6e3SRui Zhang if (!status) { 2002786f6e3SRui Zhang list_for_each_entry(child, &device->children, node) 2012786f6e3SRui Zhang acpi_pci_bridge_scan(child); 2022786f6e3SRui Zhang } 2032786f6e3SRui Zhang } 2042786f6e3SRui Zhang } 2052786f6e3SRui Zhang 2063a9622dcSShaohua Li static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766"; 20763f10f0fSKenji Kaneshige 20863f10f0fSKenji Kaneshige static acpi_status acpi_pci_run_osc(acpi_handle handle, 20963f10f0fSKenji Kaneshige const u32 *capbuf, u32 *retval) 21063f10f0fSKenji Kaneshige { 2113a9622dcSShaohua Li struct acpi_osc_context context = { 2123a9622dcSShaohua Li .uuid_str = pci_osc_uuid_str, 2133a9622dcSShaohua Li .rev = 1, 2143a9622dcSShaohua Li .cap.length = 12, 2153a9622dcSShaohua Li .cap.pointer = (void *)capbuf, 2163a9622dcSShaohua Li }; 21763f10f0fSKenji Kaneshige acpi_status status; 21863f10f0fSKenji Kaneshige 2193a9622dcSShaohua Li status = acpi_run_osc(handle, &context); 2203a9622dcSShaohua Li if (ACPI_SUCCESS(status)) { 2213a9622dcSShaohua Li *retval = *((u32 *)(context.ret.pointer + 8)); 2223a9622dcSShaohua Li kfree(context.ret.pointer); 22363f10f0fSKenji Kaneshige } 22463f10f0fSKenji Kaneshige return status; 22563f10f0fSKenji Kaneshige } 22663f10f0fSKenji Kaneshige 22763f10f0fSKenji Kaneshige static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags) 22863f10f0fSKenji Kaneshige { 22963f10f0fSKenji Kaneshige acpi_status status; 23063f10f0fSKenji Kaneshige u32 support_set, result, capbuf[3]; 23163f10f0fSKenji Kaneshige 23263f10f0fSKenji Kaneshige /* do _OSC query for all possible controls */ 2333a9622dcSShaohua Li support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS); 23463f10f0fSKenji Kaneshige capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; 23563f10f0fSKenji Kaneshige capbuf[OSC_SUPPORT_TYPE] = support_set; 2363a9622dcSShaohua Li capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS; 23763f10f0fSKenji Kaneshige 23863f10f0fSKenji Kaneshige status = acpi_pci_run_osc(root->device->handle, capbuf, &result); 23963f10f0fSKenji Kaneshige if (ACPI_SUCCESS(status)) { 24063f10f0fSKenji Kaneshige root->osc_support_set = support_set; 24163f10f0fSKenji Kaneshige root->osc_control_qry = result; 24263f10f0fSKenji Kaneshige root->osc_queried = 1; 24363f10f0fSKenji Kaneshige } 24463f10f0fSKenji Kaneshige return status; 24563f10f0fSKenji Kaneshige } 24663f10f0fSKenji Kaneshige 24763f10f0fSKenji Kaneshige static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) 24863f10f0fSKenji Kaneshige { 24963f10f0fSKenji Kaneshige acpi_status status; 25063f10f0fSKenji Kaneshige acpi_handle tmp; 25163f10f0fSKenji Kaneshige 25263f10f0fSKenji Kaneshige status = acpi_get_handle(root->device->handle, "_OSC", &tmp); 25363f10f0fSKenji Kaneshige if (ACPI_FAILURE(status)) 25463f10f0fSKenji Kaneshige return status; 25563f10f0fSKenji Kaneshige mutex_lock(&osc_lock); 25663f10f0fSKenji Kaneshige status = acpi_pci_query_osc(root, flags); 25763f10f0fSKenji Kaneshige mutex_unlock(&osc_lock); 25863f10f0fSKenji Kaneshige return status; 25963f10f0fSKenji Kaneshige } 26063f10f0fSKenji Kaneshige 26176d56de5SAlex Chiang struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) 26263f10f0fSKenji Kaneshige { 26363f10f0fSKenji Kaneshige struct acpi_pci_root *root; 264c1aec834SBjorn Helgaas 26563f10f0fSKenji Kaneshige list_for_each_entry(root, &acpi_pci_roots, node) { 26663f10f0fSKenji Kaneshige if (root->device->handle == handle) 26763f10f0fSKenji Kaneshige return root; 26863f10f0fSKenji Kaneshige } 26963f10f0fSKenji Kaneshige return NULL; 27063f10f0fSKenji Kaneshige } 27176d56de5SAlex Chiang EXPORT_SYMBOL_GPL(acpi_pci_find_root); 27263f10f0fSKenji Kaneshige 2732f7bbcebSAlexander Chiang struct acpi_handle_node { 2742f7bbcebSAlexander Chiang struct list_head node; 2752f7bbcebSAlexander Chiang acpi_handle handle; 2762f7bbcebSAlexander Chiang }; 2772f7bbcebSAlexander Chiang 2782f7bbcebSAlexander Chiang /** 2792f7bbcebSAlexander Chiang * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev 2802f7bbcebSAlexander Chiang * @handle: the handle in question 2812f7bbcebSAlexander Chiang * 2822f7bbcebSAlexander Chiang * Given an ACPI CA handle, the desired PCI device is located in the 2832f7bbcebSAlexander Chiang * list of PCI devices. 2842f7bbcebSAlexander Chiang * 2852f7bbcebSAlexander Chiang * If the device is found, its reference count is increased and this 2862f7bbcebSAlexander Chiang * function returns a pointer to its data structure. The caller must 2872f7bbcebSAlexander Chiang * decrement the reference count by calling pci_dev_put(). 2882f7bbcebSAlexander Chiang * If no device is found, %NULL is returned. 2892f7bbcebSAlexander Chiang */ 2902f7bbcebSAlexander Chiang struct pci_dev *acpi_get_pci_dev(acpi_handle handle) 2912f7bbcebSAlexander Chiang { 2922f7bbcebSAlexander Chiang int dev, fn; 2932f7bbcebSAlexander Chiang unsigned long long adr; 2942f7bbcebSAlexander Chiang acpi_status status; 2952f7bbcebSAlexander Chiang acpi_handle phandle; 2962f7bbcebSAlexander Chiang struct pci_bus *pbus; 2972f7bbcebSAlexander Chiang struct pci_dev *pdev = NULL; 2982f7bbcebSAlexander Chiang struct acpi_handle_node *node, *tmp; 2992f7bbcebSAlexander Chiang struct acpi_pci_root *root; 3002f7bbcebSAlexander Chiang LIST_HEAD(device_list); 3012f7bbcebSAlexander Chiang 3022f7bbcebSAlexander Chiang /* 3032f7bbcebSAlexander Chiang * Walk up the ACPI CA namespace until we reach a PCI root bridge. 3042f7bbcebSAlexander Chiang */ 3052f7bbcebSAlexander Chiang phandle = handle; 3062f7bbcebSAlexander Chiang while (!acpi_is_root_bridge(phandle)) { 3072f7bbcebSAlexander Chiang node = kzalloc(sizeof(struct acpi_handle_node), GFP_KERNEL); 3082f7bbcebSAlexander Chiang if (!node) 3092f7bbcebSAlexander Chiang goto out; 3102f7bbcebSAlexander Chiang 3112f7bbcebSAlexander Chiang INIT_LIST_HEAD(&node->node); 3122f7bbcebSAlexander Chiang node->handle = phandle; 3132f7bbcebSAlexander Chiang list_add(&node->node, &device_list); 3142f7bbcebSAlexander Chiang 3152f7bbcebSAlexander Chiang status = acpi_get_parent(phandle, &phandle); 3162f7bbcebSAlexander Chiang if (ACPI_FAILURE(status)) 3172f7bbcebSAlexander Chiang goto out; 3182f7bbcebSAlexander Chiang } 3192f7bbcebSAlexander Chiang 3202f7bbcebSAlexander Chiang root = acpi_pci_find_root(phandle); 3212f7bbcebSAlexander Chiang if (!root) 3222f7bbcebSAlexander Chiang goto out; 3232f7bbcebSAlexander Chiang 3242f7bbcebSAlexander Chiang pbus = root->bus; 3252f7bbcebSAlexander Chiang 3262f7bbcebSAlexander Chiang /* 3272f7bbcebSAlexander Chiang * Now, walk back down the PCI device tree until we return to our 3282f7bbcebSAlexander Chiang * original handle. Assumes that everything between the PCI root 3292f7bbcebSAlexander Chiang * bridge and the device we're looking for must be a P2P bridge. 3302f7bbcebSAlexander Chiang */ 3312f7bbcebSAlexander Chiang list_for_each_entry(node, &device_list, node) { 3322f7bbcebSAlexander Chiang acpi_handle hnd = node->handle; 3332f7bbcebSAlexander Chiang status = acpi_evaluate_integer(hnd, "_ADR", NULL, &adr); 3342f7bbcebSAlexander Chiang if (ACPI_FAILURE(status)) 3352f7bbcebSAlexander Chiang goto out; 3362f7bbcebSAlexander Chiang dev = (adr >> 16) & 0xffff; 3372f7bbcebSAlexander Chiang fn = adr & 0xffff; 3382f7bbcebSAlexander Chiang 3392f7bbcebSAlexander Chiang pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn)); 340412af978STroy Moure if (!pdev || hnd == handle) 3412f7bbcebSAlexander Chiang break; 3422f7bbcebSAlexander Chiang 3432f7bbcebSAlexander Chiang pbus = pdev->subordinate; 3442f7bbcebSAlexander Chiang pci_dev_put(pdev); 345497fb54fSRafael J. Wysocki 346497fb54fSRafael J. Wysocki /* 347497fb54fSRafael J. Wysocki * This function may be called for a non-PCI device that has a 348497fb54fSRafael J. Wysocki * PCI parent (eg. a disk under a PCI SATA controller). In that 349497fb54fSRafael J. Wysocki * case pdev->subordinate will be NULL for the parent. 350497fb54fSRafael J. Wysocki */ 351497fb54fSRafael J. Wysocki if (!pbus) { 352497fb54fSRafael J. Wysocki dev_dbg(&pdev->dev, "Not a PCI-to-PCI bridge\n"); 353497fb54fSRafael J. Wysocki pdev = NULL; 354497fb54fSRafael J. Wysocki break; 355497fb54fSRafael J. Wysocki } 3562f7bbcebSAlexander Chiang } 3572f7bbcebSAlexander Chiang out: 3582f7bbcebSAlexander Chiang list_for_each_entry_safe(node, tmp, &device_list, node) 3592f7bbcebSAlexander Chiang kfree(node); 3602f7bbcebSAlexander Chiang 3612f7bbcebSAlexander Chiang return pdev; 3622f7bbcebSAlexander Chiang } 3632f7bbcebSAlexander Chiang EXPORT_SYMBOL_GPL(acpi_get_pci_dev); 3642f7bbcebSAlexander Chiang 36563f10f0fSKenji Kaneshige /** 3669f5404d8SKenji Kaneshige * acpi_pci_osc_control_set - commit requested control to Firmware 36763f10f0fSKenji Kaneshige * @handle: acpi_handle for the target ACPI object 36863f10f0fSKenji Kaneshige * @flags: driver's requested control bits 36963f10f0fSKenji Kaneshige * 37063f10f0fSKenji Kaneshige * Attempt to take control from Firmware on requested control bits. 37163f10f0fSKenji Kaneshige **/ 3729f5404d8SKenji Kaneshige acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) 37363f10f0fSKenji Kaneshige { 37463f10f0fSKenji Kaneshige acpi_status status; 37563f10f0fSKenji Kaneshige u32 control_req, result, capbuf[3]; 37663f10f0fSKenji Kaneshige acpi_handle tmp; 37763f10f0fSKenji Kaneshige struct acpi_pci_root *root; 37863f10f0fSKenji Kaneshige 37963f10f0fSKenji Kaneshige status = acpi_get_handle(handle, "_OSC", &tmp); 38063f10f0fSKenji Kaneshige if (ACPI_FAILURE(status)) 38163f10f0fSKenji Kaneshige return status; 38263f10f0fSKenji Kaneshige 3833a9622dcSShaohua Li control_req = (flags & OSC_PCI_CONTROL_MASKS); 38463f10f0fSKenji Kaneshige if (!control_req) 38563f10f0fSKenji Kaneshige return AE_TYPE; 38663f10f0fSKenji Kaneshige 38763f10f0fSKenji Kaneshige root = acpi_pci_find_root(handle); 38863f10f0fSKenji Kaneshige if (!root) 38963f10f0fSKenji Kaneshige return AE_NOT_EXIST; 39063f10f0fSKenji Kaneshige 39163f10f0fSKenji Kaneshige mutex_lock(&osc_lock); 39263f10f0fSKenji Kaneshige /* No need to evaluate _OSC if the control was already granted. */ 39363f10f0fSKenji Kaneshige if ((root->osc_control_set & control_req) == control_req) 39463f10f0fSKenji Kaneshige goto out; 39563f10f0fSKenji Kaneshige 39663f10f0fSKenji Kaneshige /* Need to query controls first before requesting them */ 39763f10f0fSKenji Kaneshige if (!root->osc_queried) { 39863f10f0fSKenji Kaneshige status = acpi_pci_query_osc(root, root->osc_support_set); 39963f10f0fSKenji Kaneshige if (ACPI_FAILURE(status)) 40063f10f0fSKenji Kaneshige goto out; 40163f10f0fSKenji Kaneshige } 40263f10f0fSKenji Kaneshige if ((root->osc_control_qry & control_req) != control_req) { 40363f10f0fSKenji Kaneshige printk(KERN_DEBUG 40463f10f0fSKenji Kaneshige "Firmware did not grant requested _OSC control\n"); 40563f10f0fSKenji Kaneshige status = AE_SUPPORT; 40663f10f0fSKenji Kaneshige goto out; 40763f10f0fSKenji Kaneshige } 40863f10f0fSKenji Kaneshige 40963f10f0fSKenji Kaneshige capbuf[OSC_QUERY_TYPE] = 0; 41063f10f0fSKenji Kaneshige capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set; 41163f10f0fSKenji Kaneshige capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req; 41263f10f0fSKenji Kaneshige status = acpi_pci_run_osc(handle, capbuf, &result); 41363f10f0fSKenji Kaneshige if (ACPI_SUCCESS(status)) 41463f10f0fSKenji Kaneshige root->osc_control_set = result; 41563f10f0fSKenji Kaneshige out: 41663f10f0fSKenji Kaneshige mutex_unlock(&osc_lock); 41763f10f0fSKenji Kaneshige return status; 41863f10f0fSKenji Kaneshige } 4199f5404d8SKenji Kaneshige EXPORT_SYMBOL(acpi_pci_osc_control_set); 42063f10f0fSKenji Kaneshige 421b5678a34SSam Ravnborg static int __devinit acpi_pci_root_add(struct acpi_device *device) 4221da177e4SLinus Torvalds { 423f5eebbe1SBjorn Helgaas unsigned long long segment, bus; 424f5eebbe1SBjorn Helgaas acpi_status status; 425f5eebbe1SBjorn Helgaas int result; 426f5eebbe1SBjorn Helgaas struct acpi_pci_root *root; 427f5eebbe1SBjorn Helgaas acpi_handle handle; 4282786f6e3SRui Zhang struct acpi_device *child; 4290ef5f8f6SAndrew Patterson u32 flags, base_flags; 4301da177e4SLinus Torvalds 431f5eebbe1SBjorn Helgaas segment = 0; 432f5eebbe1SBjorn Helgaas status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL, 433f5eebbe1SBjorn Helgaas &segment); 434f5eebbe1SBjorn Helgaas if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 435f5eebbe1SBjorn Helgaas printk(KERN_ERR PREFIX "can't evaluate _SEG\n"); 436f5eebbe1SBjorn Helgaas return -ENODEV; 437f5eebbe1SBjorn Helgaas } 4381da177e4SLinus Torvalds 439f5eebbe1SBjorn Helgaas /* Check _CRS first, then _BBN. If no _BBN, default to zero. */ 440f5eebbe1SBjorn Helgaas bus = 0; 441f5eebbe1SBjorn Helgaas status = try_get_root_bridge_busnr(device->handle, &bus); 442f5eebbe1SBjorn Helgaas if (ACPI_FAILURE(status)) { 443f5eebbe1SBjorn Helgaas status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus); 444f5eebbe1SBjorn Helgaas if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 445f5eebbe1SBjorn Helgaas printk(KERN_ERR PREFIX 446f5eebbe1SBjorn Helgaas "no bus number in _CRS and can't evaluate _BBN\n"); 447f5eebbe1SBjorn Helgaas return -ENODEV; 448f5eebbe1SBjorn Helgaas } 449f5eebbe1SBjorn Helgaas } 4501da177e4SLinus Torvalds 45136bcbec7SBurman Yan root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL); 4521da177e4SLinus Torvalds if (!root) 453d550d98dSPatrick Mochel return -ENOMEM; 4541da177e4SLinus Torvalds 455f5eebbe1SBjorn Helgaas INIT_LIST_HEAD(&root->node); 45632917e5bSPatrick Mochel root->device = device; 4570705495dSBjorn Helgaas root->segment = segment & 0xFFFF; 4580705495dSBjorn Helgaas root->bus_nr = bus & 0xFF; 4591da177e4SLinus Torvalds strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); 4601da177e4SLinus Torvalds strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); 461db89b4f0SPavel Machek device->driver_data = root; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds /* 464990a7ac5SAndrew Patterson * All supported architectures that use ACPI have support for 465990a7ac5SAndrew Patterson * PCI domains, so we indicate this in _OSC support capabilities. 466990a7ac5SAndrew Patterson */ 4670ef5f8f6SAndrew Patterson flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; 46863f10f0fSKenji Kaneshige acpi_pci_osc_support(root, flags); 469990a7ac5SAndrew Patterson 470990a7ac5SAndrew Patterson /* 4711da177e4SLinus Torvalds * TBD: Need PCI interface for enumeration/configuration of roots. 4721da177e4SLinus Torvalds */ 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds /* TBD: Locking */ 4751da177e4SLinus Torvalds list_add_tail(&root->node, &acpi_pci_roots); 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n", 4781da177e4SLinus Torvalds acpi_device_name(device), acpi_device_bid(device), 4790705495dSBjorn Helgaas root->segment, root->bus_nr); 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds /* 4821da177e4SLinus Torvalds * Scan the Root Bridge 4831da177e4SLinus Torvalds * -------------------- 4841da177e4SLinus Torvalds * Must do this prior to any attempt to bind the root device, as the 4851da177e4SLinus Torvalds * PCI namespace does not get created until this call is made (and 4861da177e4SLinus Torvalds * thus the root bridge's pci_dev does not exist). 4871da177e4SLinus Torvalds */ 4880705495dSBjorn Helgaas root->bus = pci_acpi_scan_root(device, segment, bus); 4891da177e4SLinus Torvalds if (!root->bus) { 4906468463aSLen Brown printk(KERN_ERR PREFIX 4916468463aSLen Brown "Bus %04x:%02x not present in PCI namespace\n", 4920705495dSBjorn Helgaas root->segment, root->bus_nr); 4931da177e4SLinus Torvalds result = -ENODEV; 4941da177e4SLinus Torvalds goto end; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds /* 4981da177e4SLinus Torvalds * Attach ACPI-PCI Context 4991da177e4SLinus Torvalds * ----------------------- 5001da177e4SLinus Torvalds * Thus binding the ACPI and PCI devices. 5011da177e4SLinus Torvalds */ 502499650deSAlexander Chiang result = acpi_pci_bind_root(device); 5031da177e4SLinus Torvalds if (result) 5041da177e4SLinus Torvalds goto end; 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds /* 5071da177e4SLinus Torvalds * PCI Routing Table 5081da177e4SLinus Torvalds * ----------------- 5091da177e4SLinus Torvalds * Evaluate and parse _PRT, if exists. 5101da177e4SLinus Torvalds */ 5112d1e0a02SPatrick Mochel status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); 5121da177e4SLinus Torvalds if (ACPI_SUCCESS(status)) 513859a3f86SAlexander Chiang result = acpi_pci_irq_add_prt(device->handle, root->bus); 5141da177e4SLinus Torvalds 5152786f6e3SRui Zhang /* 5162786f6e3SRui Zhang * Scan and bind all _ADR-Based Devices 5172786f6e3SRui Zhang */ 5182786f6e3SRui Zhang list_for_each_entry(child, &device->children, node) 5192786f6e3SRui Zhang acpi_pci_bridge_scan(child); 5202786f6e3SRui Zhang 5210ef5f8f6SAndrew Patterson /* Indicate support for various _OSC capabilities. */ 5220ef5f8f6SAndrew Patterson if (pci_ext_cfg_avail(root->bus->self)) 5230ef5f8f6SAndrew Patterson flags |= OSC_EXT_PCI_CONFIG_SUPPORT; 5243e1b1600SAndrew Patterson if (pcie_aspm_enabled()) 5253e1b1600SAndrew Patterson flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | 5263e1b1600SAndrew Patterson OSC_CLOCK_PWR_CAPABILITY_SUPPORT; 52707ae95f9SAndrew Patterson if (pci_msi_enabled()) 52807ae95f9SAndrew Patterson flags |= OSC_MSI_SUPPORT; 5290ef5f8f6SAndrew Patterson if (flags != base_flags) 53063f10f0fSKenji Kaneshige acpi_pci_osc_support(root, flags); 5310ef5f8f6SAndrew Patterson 532b67ea761SRafael J. Wysocki pci_acpi_add_bus_pm_notifier(device, root->bus); 533b67ea761SRafael J. Wysocki if (device->wakeup.flags.run_wake) 534b67ea761SRafael J. Wysocki device_set_run_wake(root->bus->bridge, true); 535b67ea761SRafael J. Wysocki 536f5eebbe1SBjorn Helgaas return 0; 537f5eebbe1SBjorn Helgaas 5381da177e4SLinus Torvalds end: 539c431ada4SRajesh Shah if (!list_empty(&root->node)) 540c431ada4SRajesh Shah list_del(&root->node); 5411da177e4SLinus Torvalds kfree(root); 542d550d98dSPatrick Mochel return result; 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 5454be44fcdSLen Brown static int acpi_pci_root_start(struct acpi_device *device) 546c431ada4SRajesh Shah { 547caf420c6SBjorn Helgaas struct acpi_pci_root *root = acpi_driver_data(device); 548c431ada4SRajesh Shah 549c431ada4SRajesh Shah pci_bus_add_devices(root->bus); 550d550d98dSPatrick Mochel return 0; 551c431ada4SRajesh Shah } 5521da177e4SLinus Torvalds 5534be44fcdSLen Brown static int acpi_pci_root_remove(struct acpi_device *device, int type) 5541da177e4SLinus Torvalds { 555caf420c6SBjorn Helgaas struct acpi_pci_root *root = acpi_driver_data(device); 5561da177e4SLinus Torvalds 557b67ea761SRafael J. Wysocki device_set_run_wake(root->bus->bridge, false); 558b67ea761SRafael J. Wysocki pci_acpi_remove_bus_pm_notifier(device); 559b67ea761SRafael J. Wysocki 5601da177e4SLinus Torvalds kfree(root); 561d550d98dSPatrick Mochel return 0; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds static int __init acpi_pci_root_init(void) 5651da177e4SLinus Torvalds { 5661da177e4SLinus Torvalds if (acpi_pci_disabled) 567d550d98dSPatrick Mochel return 0; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0) 570d550d98dSPatrick Mochel return -ENODEV; 5711da177e4SLinus Torvalds 572d550d98dSPatrick Mochel return 0; 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds subsys_initcall(acpi_pci_root_init); 576