Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.36-rc1 140 lines 4.3 kB view raw
1/* 2 * ACPI related functions for PCI Express Hot Plug driver. 3 * 4 * Copyright (C) 2008 Kenji Kaneshige 5 * Copyright (C) 2008 Fujitsu Limited. 6 * 7 * All rights reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or (at 12 * your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 17 * NON INFRINGEMENT. See the GNU General Public License for more 18 * details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 * 24 */ 25 26#include <linux/acpi.h> 27#include <linux/pci.h> 28#include <linux/pci_hotplug.h> 29#include <linux/slab.h> 30#include "pciehp.h" 31 32#define PCIEHP_DETECT_PCIE (0) 33#define PCIEHP_DETECT_ACPI (1) 34#define PCIEHP_DETECT_AUTO (2) 35#define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO 36 37struct dummy_slot { 38 u32 number; 39 struct list_head list; 40}; 41 42static int slot_detection_mode; 43static char *pciehp_detect_mode; 44module_param(pciehp_detect_mode, charp, 0444); 45MODULE_PARM_DESC(pciehp_detect_mode, 46 "Slot detection mode: pcie, acpi, auto\n" 47 " pcie - Use PCIe based slot detection\n" 48 " acpi - Use ACPI for slot detection\n" 49 " auto(default) - Auto select mode. Use acpi option if duplicate\n" 50 " slot ids are found. Otherwise, use pcie option\n"); 51 52int pciehp_acpi_slot_detection_check(struct pci_dev *dev) 53{ 54 if (slot_detection_mode != PCIEHP_DETECT_ACPI) 55 return 0; 56 if (acpi_pci_detect_ejectable(DEVICE_ACPI_HANDLE(&dev->dev))) 57 return 0; 58 return -ENODEV; 59} 60 61static int __init parse_detect_mode(void) 62{ 63 if (!pciehp_detect_mode) 64 return PCIEHP_DETECT_DEFAULT; 65 if (!strcmp(pciehp_detect_mode, "pcie")) 66 return PCIEHP_DETECT_PCIE; 67 if (!strcmp(pciehp_detect_mode, "acpi")) 68 return PCIEHP_DETECT_ACPI; 69 if (!strcmp(pciehp_detect_mode, "auto")) 70 return PCIEHP_DETECT_AUTO; 71 warn("bad specifier '%s' for pciehp_detect_mode. Use default\n", 72 pciehp_detect_mode); 73 return PCIEHP_DETECT_DEFAULT; 74} 75 76static int __initdata dup_slot_id; 77static int __initdata acpi_slot_detected; 78static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots); 79 80/* Dummy driver for dumplicate name detection */ 81static int __init dummy_probe(struct pcie_device *dev) 82{ 83 int pos; 84 u32 slot_cap; 85 acpi_handle handle; 86 struct dummy_slot *slot, *tmp; 87 struct pci_dev *pdev = dev->port; 88 /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ 89 if (pciehp_get_hp_hw_control_from_firmware(pdev)) 90 return -ENODEV; 91 pos = pci_pcie_cap(pdev); 92 if (!pos) 93 return -ENODEV; 94 pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap); 95 slot = kzalloc(sizeof(*slot), GFP_KERNEL); 96 if (!slot) 97 return -ENOMEM; 98 slot->number = slot_cap >> 19; 99 list_for_each_entry(tmp, &dummy_slots, list) { 100 if (tmp->number == slot->number) 101 dup_slot_id++; 102 } 103 list_add_tail(&slot->list, &dummy_slots); 104 handle = DEVICE_ACPI_HANDLE(&pdev->dev); 105 if (!acpi_slot_detected && acpi_pci_detect_ejectable(handle)) 106 acpi_slot_detected = 1; 107 return -ENODEV; /* dummy driver always returns error */ 108} 109 110static struct pcie_port_service_driver __initdata dummy_driver = { 111 .name = "pciehp_dummy", 112 .port_type = PCIE_ANY_PORT, 113 .service = PCIE_PORT_SERVICE_HP, 114 .probe = dummy_probe, 115}; 116 117static int __init select_detection_mode(void) 118{ 119 struct dummy_slot *slot, *tmp; 120 pcie_port_service_register(&dummy_driver); 121 pcie_port_service_unregister(&dummy_driver); 122 list_for_each_entry_safe(slot, tmp, &dummy_slots, list) { 123 list_del(&slot->list); 124 kfree(slot); 125 } 126 if (acpi_slot_detected && dup_slot_id) 127 return PCIEHP_DETECT_ACPI; 128 return PCIEHP_DETECT_PCIE; 129} 130 131void __init pciehp_acpi_slot_detection_init(void) 132{ 133 slot_detection_mode = parse_detect_mode(); 134 if (slot_detection_mode != PCIEHP_DETECT_AUTO) 135 goto out; 136 slot_detection_mode = select_detection_mode(); 137out: 138 if (slot_detection_mode == PCIEHP_DETECT_ACPI) 139 info("Using ACPI for slot detection.\n"); 140}