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.18-rc7 714 lines 18 kB view raw
1/* 2 * PCI HotPlug Controller Core 3 * 4 * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) 5 * Copyright (C) 2001-2002 IBM Corp. 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 * Send feedback to <greg@kroah.com> 25 * 26 * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs 27 * 28 */ 29 30#include <linux/module.h> 31#include <linux/moduleparam.h> 32#include <linux/kernel.h> 33#include <linux/types.h> 34#include <linux/list.h> 35#include <linux/pagemap.h> 36#include <linux/slab.h> 37#include <linux/smp_lock.h> 38#include <linux/init.h> 39#include <linux/mount.h> 40#include <linux/namei.h> 41#include <linux/pci.h> 42#include <asm/uaccess.h> 43#include <linux/kobject.h> 44#include <linux/sysfs.h> 45#include "pci_hotplug.h" 46 47 48#define MY_NAME "pci_hotplug" 49 50#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0) 51#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) 52#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) 53#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) 54 55 56/* local variables */ 57static int debug; 58 59#define DRIVER_VERSION "0.5" 60#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>" 61#define DRIVER_DESC "PCI Hot Plug PCI Core" 62 63 64////////////////////////////////////////////////////////////////// 65 66static LIST_HEAD(pci_hotplug_slot_list); 67 68struct subsystem pci_hotplug_slots_subsys; 69 70static ssize_t hotplug_slot_attr_show(struct kobject *kobj, 71 struct attribute *attr, char *buf) 72{ 73 struct hotplug_slot *slot = to_hotplug_slot(kobj); 74 struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); 75 return attribute->show ? attribute->show(slot, buf) : -EIO; 76} 77 78static ssize_t hotplug_slot_attr_store(struct kobject *kobj, 79 struct attribute *attr, const char *buf, size_t len) 80{ 81 struct hotplug_slot *slot = to_hotplug_slot(kobj); 82 struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr); 83 return attribute->store ? attribute->store(slot, buf, len) : -EIO; 84} 85 86static struct sysfs_ops hotplug_slot_sysfs_ops = { 87 .show = hotplug_slot_attr_show, 88 .store = hotplug_slot_attr_store, 89}; 90 91static void hotplug_slot_release(struct kobject *kobj) 92{ 93 struct hotplug_slot *slot = to_hotplug_slot(kobj); 94 if (slot->release) 95 slot->release(slot); 96} 97 98static struct kobj_type hotplug_slot_ktype = { 99 .sysfs_ops = &hotplug_slot_sysfs_ops, 100 .release = &hotplug_slot_release, 101}; 102 103decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL); 104 105/* these strings match up with the values in pci_bus_speed */ 106static char *pci_bus_speed_strings[] = { 107 "33 MHz PCI", /* 0x00 */ 108 "66 MHz PCI", /* 0x01 */ 109 "66 MHz PCIX", /* 0x02 */ 110 "100 MHz PCIX", /* 0x03 */ 111 "133 MHz PCIX", /* 0x04 */ 112 NULL, /* 0x05 */ 113 NULL, /* 0x06 */ 114 NULL, /* 0x07 */ 115 NULL, /* 0x08 */ 116 "66 MHz PCIX 266", /* 0x09 */ 117 "100 MHz PCIX 266", /* 0x0a */ 118 "133 MHz PCIX 266", /* 0x0b */ 119 NULL, /* 0x0c */ 120 NULL, /* 0x0d */ 121 NULL, /* 0x0e */ 122 NULL, /* 0x0f */ 123 NULL, /* 0x10 */ 124 "66 MHz PCIX 533", /* 0x11 */ 125 "100 MHz PCIX 533", /* 0x12 */ 126 "133 MHz PCIX 533", /* 0x13 */ 127 "25 GBps PCI-E", /* 0x14 */ 128}; 129 130#ifdef CONFIG_HOTPLUG_PCI_CPCI 131extern int cpci_hotplug_init(int debug); 132extern void cpci_hotplug_exit(void); 133#else 134static inline int cpci_hotplug_init(int debug) { return 0; } 135static inline void cpci_hotplug_exit(void) { } 136#endif 137 138/* Weee, fun with macros... */ 139#define GET_STATUS(name,type) \ 140static int get_##name (struct hotplug_slot *slot, type *value) \ 141{ \ 142 struct hotplug_slot_ops *ops = slot->ops; \ 143 int retval = 0; \ 144 if (try_module_get(ops->owner)) { \ 145 if (ops->get_##name) \ 146 retval = ops->get_##name (slot, value); \ 147 else \ 148 *value = slot->info->name; \ 149 module_put(ops->owner); \ 150 } \ 151 return retval; \ 152} 153 154GET_STATUS(power_status, u8) 155GET_STATUS(attention_status, u8) 156GET_STATUS(latch_status, u8) 157GET_STATUS(adapter_status, u8) 158GET_STATUS(address, u32) 159GET_STATUS(max_bus_speed, enum pci_bus_speed) 160GET_STATUS(cur_bus_speed, enum pci_bus_speed) 161 162static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) 163{ 164 int retval; 165 u8 value; 166 167 retval = get_power_status (slot, &value); 168 if (retval) 169 goto exit; 170 retval = sprintf (buf, "%d\n", value); 171exit: 172 return retval; 173} 174 175static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, 176 size_t count) 177{ 178 unsigned long lpower; 179 u8 power; 180 int retval = 0; 181 182 lpower = simple_strtoul (buf, NULL, 10); 183 power = (u8)(lpower & 0xff); 184 dbg ("power = %d\n", power); 185 186 if (!try_module_get(slot->ops->owner)) { 187 retval = -ENODEV; 188 goto exit; 189 } 190 switch (power) { 191 case 0: 192 if (slot->ops->disable_slot) 193 retval = slot->ops->disable_slot(slot); 194 break; 195 196 case 1: 197 if (slot->ops->enable_slot) 198 retval = slot->ops->enable_slot(slot); 199 break; 200 201 default: 202 err ("Illegal value specified for power\n"); 203 retval = -EINVAL; 204 } 205 module_put(slot->ops->owner); 206 207exit: 208 if (retval) 209 return retval; 210 return count; 211} 212 213static struct hotplug_slot_attribute hotplug_slot_attr_power = { 214 .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, 215 .show = power_read_file, 216 .store = power_write_file 217}; 218 219static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf) 220{ 221 int retval; 222 u8 value; 223 224 retval = get_attention_status (slot, &value); 225 if (retval) 226 goto exit; 227 retval = sprintf (buf, "%d\n", value); 228 229exit: 230 return retval; 231} 232 233static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, 234 size_t count) 235{ 236 unsigned long lattention; 237 u8 attention; 238 int retval = 0; 239 240 lattention = simple_strtoul (buf, NULL, 10); 241 attention = (u8)(lattention & 0xff); 242 dbg (" - attention = %d\n", attention); 243 244 if (!try_module_get(slot->ops->owner)) { 245 retval = -ENODEV; 246 goto exit; 247 } 248 if (slot->ops->set_attention_status) 249 retval = slot->ops->set_attention_status(slot, attention); 250 module_put(slot->ops->owner); 251 252exit: 253 if (retval) 254 return retval; 255 return count; 256} 257 258static struct hotplug_slot_attribute hotplug_slot_attr_attention = { 259 .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, 260 .show = attention_read_file, 261 .store = attention_write_file 262}; 263 264static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) 265{ 266 int retval; 267 u8 value; 268 269 retval = get_latch_status (slot, &value); 270 if (retval) 271 goto exit; 272 retval = sprintf (buf, "%d\n", value); 273 274exit: 275 return retval; 276} 277 278static struct hotplug_slot_attribute hotplug_slot_attr_latch = { 279 .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO}, 280 .show = latch_read_file, 281}; 282 283static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) 284{ 285 int retval; 286 u8 value; 287 288 retval = get_adapter_status (slot, &value); 289 if (retval) 290 goto exit; 291 retval = sprintf (buf, "%d\n", value); 292 293exit: 294 return retval; 295} 296 297static struct hotplug_slot_attribute hotplug_slot_attr_presence = { 298 .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO}, 299 .show = presence_read_file, 300}; 301 302static ssize_t address_read_file (struct hotplug_slot *slot, char *buf) 303{ 304 int retval; 305 u32 address; 306 307 retval = get_address (slot, &address); 308 if (retval) 309 goto exit; 310 retval = sprintf (buf, "%04x:%02x:%02x\n", 311 (address >> 16) & 0xffff, 312 (address >> 8) & 0xff, 313 address & 0xff); 314 315exit: 316 return retval; 317} 318 319static struct hotplug_slot_attribute hotplug_slot_attr_address = { 320 .attr = {.name = "address", .mode = S_IFREG | S_IRUGO}, 321 .show = address_read_file, 322}; 323 324static char *unknown_speed = "Unknown bus speed"; 325 326static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) 327{ 328 char *speed_string; 329 int retval; 330 enum pci_bus_speed value; 331 332 retval = get_max_bus_speed (slot, &value); 333 if (retval) 334 goto exit; 335 336 if (value == PCI_SPEED_UNKNOWN) 337 speed_string = unknown_speed; 338 else 339 speed_string = pci_bus_speed_strings[value]; 340 341 retval = sprintf (buf, "%s\n", speed_string); 342 343exit: 344 return retval; 345} 346 347static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = { 348 .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO}, 349 .show = max_bus_speed_read_file, 350}; 351 352static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) 353{ 354 char *speed_string; 355 int retval; 356 enum pci_bus_speed value; 357 358 retval = get_cur_bus_speed (slot, &value); 359 if (retval) 360 goto exit; 361 362 if (value == PCI_SPEED_UNKNOWN) 363 speed_string = unknown_speed; 364 else 365 speed_string = pci_bus_speed_strings[value]; 366 367 retval = sprintf (buf, "%s\n", speed_string); 368 369exit: 370 return retval; 371} 372 373static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = { 374 .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO}, 375 .show = cur_bus_speed_read_file, 376}; 377 378static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, 379 size_t count) 380{ 381 unsigned long ltest; 382 u32 test; 383 int retval = 0; 384 385 ltest = simple_strtoul (buf, NULL, 10); 386 test = (u32)(ltest & 0xffffffff); 387 dbg ("test = %d\n", test); 388 389 if (!try_module_get(slot->ops->owner)) { 390 retval = -ENODEV; 391 goto exit; 392 } 393 if (slot->ops->hardware_test) 394 retval = slot->ops->hardware_test(slot, test); 395 module_put(slot->ops->owner); 396 397exit: 398 if (retval) 399 return retval; 400 return count; 401} 402 403static struct hotplug_slot_attribute hotplug_slot_attr_test = { 404 .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, 405 .store = test_write_file 406}; 407 408static int has_power_file (struct hotplug_slot *slot) 409{ 410 if ((!slot) || (!slot->ops)) 411 return -ENODEV; 412 if ((slot->ops->enable_slot) || 413 (slot->ops->disable_slot) || 414 (slot->ops->get_power_status)) 415 return 0; 416 return -ENOENT; 417} 418 419static int has_attention_file (struct hotplug_slot *slot) 420{ 421 if ((!slot) || (!slot->ops)) 422 return -ENODEV; 423 if ((slot->ops->set_attention_status) || 424 (slot->ops->get_attention_status)) 425 return 0; 426 return -ENOENT; 427} 428 429static int has_latch_file (struct hotplug_slot *slot) 430{ 431 if ((!slot) || (!slot->ops)) 432 return -ENODEV; 433 if (slot->ops->get_latch_status) 434 return 0; 435 return -ENOENT; 436} 437 438static int has_adapter_file (struct hotplug_slot *slot) 439{ 440 if ((!slot) || (!slot->ops)) 441 return -ENODEV; 442 if (slot->ops->get_adapter_status) 443 return 0; 444 return -ENOENT; 445} 446 447static int has_address_file (struct hotplug_slot *slot) 448{ 449 if ((!slot) || (!slot->ops)) 450 return -ENODEV; 451 if (slot->ops->get_address) 452 return 0; 453 return -ENOENT; 454} 455 456static int has_max_bus_speed_file (struct hotplug_slot *slot) 457{ 458 if ((!slot) || (!slot->ops)) 459 return -ENODEV; 460 if (slot->ops->get_max_bus_speed) 461 return 0; 462 return -ENOENT; 463} 464 465static int has_cur_bus_speed_file (struct hotplug_slot *slot) 466{ 467 if ((!slot) || (!slot->ops)) 468 return -ENODEV; 469 if (slot->ops->get_cur_bus_speed) 470 return 0; 471 return -ENOENT; 472} 473 474static int has_test_file (struct hotplug_slot *slot) 475{ 476 if ((!slot) || (!slot->ops)) 477 return -ENODEV; 478 if (slot->ops->hardware_test) 479 return 0; 480 return -ENOENT; 481} 482 483static int fs_add_slot (struct hotplug_slot *slot) 484{ 485 if (has_power_file(slot) == 0) 486 sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); 487 488 if (has_attention_file(slot) == 0) 489 sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr); 490 491 if (has_latch_file(slot) == 0) 492 sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr); 493 494 if (has_adapter_file(slot) == 0) 495 sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr); 496 497 if (has_address_file(slot) == 0) 498 sysfs_create_file(&slot->kobj, &hotplug_slot_attr_address.attr); 499 500 if (has_max_bus_speed_file(slot) == 0) 501 sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); 502 503 if (has_cur_bus_speed_file(slot) == 0) 504 sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); 505 506 if (has_test_file(slot) == 0) 507 sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr); 508 509 return 0; 510} 511 512static void fs_remove_slot (struct hotplug_slot *slot) 513{ 514 if (has_power_file(slot) == 0) 515 sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); 516 517 if (has_attention_file(slot) == 0) 518 sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); 519 520 if (has_latch_file(slot) == 0) 521 sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); 522 523 if (has_adapter_file(slot) == 0) 524 sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); 525 526 if (has_address_file(slot) == 0) 527 sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr); 528 529 if (has_max_bus_speed_file(slot) == 0) 530 sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); 531 532 if (has_cur_bus_speed_file(slot) == 0) 533 sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); 534 535 if (has_test_file(slot) == 0) 536 sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); 537} 538 539static struct hotplug_slot *get_slot_from_name (const char *name) 540{ 541 struct hotplug_slot *slot; 542 struct list_head *tmp; 543 544 list_for_each (tmp, &pci_hotplug_slot_list) { 545 slot = list_entry (tmp, struct hotplug_slot, slot_list); 546 if (strcmp(slot->name, name) == 0) 547 return slot; 548 } 549 return NULL; 550} 551 552/** 553 * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem 554 * @slot: pointer to the &struct hotplug_slot to register 555 * 556 * Registers a hotplug slot with the pci hotplug subsystem, which will allow 557 * userspace interaction to the slot. 558 * 559 * Returns 0 if successful, anything else for an error. 560 */ 561int pci_hp_register (struct hotplug_slot *slot) 562{ 563 int result; 564 565 if (slot == NULL) 566 return -ENODEV; 567 if ((slot->info == NULL) || (slot->ops == NULL)) 568 return -EINVAL; 569 if (slot->release == NULL) { 570 dbg("Why are you trying to register a hotplug slot" 571 "without a proper release function?\n"); 572 return -EINVAL; 573 } 574 575 kobject_set_name(&slot->kobj, "%s", slot->name); 576 kobj_set_kset_s(slot, pci_hotplug_slots_subsys); 577 578 /* this can fail if we have already registered a slot with the same name */ 579 if (kobject_register(&slot->kobj)) { 580 err("Unable to register kobject"); 581 return -EINVAL; 582 } 583 584 list_add (&slot->slot_list, &pci_hotplug_slot_list); 585 586 result = fs_add_slot (slot); 587 dbg ("Added slot %s to the list\n", slot->name); 588 return result; 589} 590 591/** 592 * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem 593 * @slot: pointer to the &struct hotplug_slot to deregister 594 * 595 * The @slot must have been registered with the pci hotplug subsystem 596 * previously with a call to pci_hp_register(). 597 * 598 * Returns 0 if successful, anything else for an error. 599 */ 600int pci_hp_deregister (struct hotplug_slot *slot) 601{ 602 struct hotplug_slot *temp; 603 604 if (slot == NULL) 605 return -ENODEV; 606 607 temp = get_slot_from_name (slot->name); 608 if (temp != slot) { 609 return -ENODEV; 610 } 611 list_del (&slot->slot_list); 612 613 fs_remove_slot (slot); 614 dbg ("Removed slot %s from the list\n", slot->name); 615 kobject_unregister(&slot->kobj); 616 return 0; 617} 618 619/** 620 * pci_hp_change_slot_info - changes the slot's information structure in the core 621 * @slot: pointer to the slot whose info has changed 622 * @info: pointer to the info copy into the slot's info structure 623 * 624 * @slot must have been registered with the pci 625 * hotplug subsystem previously with a call to pci_hp_register(). 626 * 627 * Returns 0 if successful, anything else for an error. 628 */ 629int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info) 630{ 631 if ((slot == NULL) || (info == NULL)) 632 return -ENODEV; 633 634 /* 635 * check all fields in the info structure, and update timestamps 636 * for the files referring to the fields that have now changed. 637 */ 638 if ((has_power_file(slot) == 0) && 639 (slot->info->power_status != info->power_status)) 640 sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr); 641 642 if ((has_attention_file(slot) == 0) && 643 (slot->info->attention_status != info->attention_status)) 644 sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr); 645 646 if ((has_latch_file(slot) == 0) && 647 (slot->info->latch_status != info->latch_status)) 648 sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr); 649 650 if ((has_adapter_file(slot) == 0) && 651 (slot->info->adapter_status != info->adapter_status)) 652 sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr); 653 654 if ((has_address_file(slot) == 0) && 655 (slot->info->address != info->address)) 656 sysfs_update_file(&slot->kobj, &hotplug_slot_attr_address.attr); 657 658 if ((has_max_bus_speed_file(slot) == 0) && 659 (slot->info->max_bus_speed != info->max_bus_speed)) 660 sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); 661 662 if ((has_cur_bus_speed_file(slot) == 0) && 663 (slot->info->cur_bus_speed != info->cur_bus_speed)) 664 sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); 665 666 memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); 667 668 return 0; 669} 670 671static int __init pci_hotplug_init (void) 672{ 673 int result; 674 675 kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys); 676 result = subsystem_register(&pci_hotplug_slots_subsys); 677 if (result) { 678 err("Register subsys with error %d\n", result); 679 goto exit; 680 } 681 result = cpci_hotplug_init(debug); 682 if (result) { 683 err ("cpci_hotplug_init with error %d\n", result); 684 goto err_subsys; 685 } 686 687 info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); 688 goto exit; 689 690err_subsys: 691 subsystem_unregister(&pci_hotplug_slots_subsys); 692exit: 693 return result; 694} 695 696static void __exit pci_hotplug_exit (void) 697{ 698 cpci_hotplug_exit(); 699 subsystem_unregister(&pci_hotplug_slots_subsys); 700} 701 702module_init(pci_hotplug_init); 703module_exit(pci_hotplug_exit); 704 705MODULE_AUTHOR(DRIVER_AUTHOR); 706MODULE_DESCRIPTION(DRIVER_DESC); 707MODULE_LICENSE("GPL"); 708module_param(debug, bool, 0644); 709MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); 710 711EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys); 712EXPORT_SYMBOL_GPL(pci_hp_register); 713EXPORT_SYMBOL_GPL(pci_hp_deregister); 714EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);