Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.20 592 lines 15 kB view raw
1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2005-2006 Silicon Graphics, Inc. All rights reserved. 7 * 8 * This work was based on the 2.4/2.6 kernel development by Dick Reigner. 9 * Work to add BIOS PROM support was completed by Mike Habeck. 10 */ 11 12#include <linux/init.h> 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/pci.h> 16#include <linux/pci_hotplug.h> 17#include <linux/proc_fs.h> 18#include <linux/types.h> 19#include <linux/mutex.h> 20 21#include <asm/sn/addrs.h> 22#include <asm/sn/geo.h> 23#include <asm/sn/l1.h> 24#include <asm/sn/module.h> 25#include <asm/sn/pcibr_provider.h> 26#include <asm/sn/pcibus_provider_defs.h> 27#include <asm/sn/pcidev.h> 28#include <asm/sn/sn_feature_sets.h> 29#include <asm/sn/sn_sal.h> 30#include <asm/sn/types.h> 31 32#include "../pci.h" 33 34MODULE_LICENSE("GPL"); 35MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); 36MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); 37 38#define PCIIO_ASIC_TYPE_TIOCA 4 39#define PCI_SLOT_ALREADY_UP 2 /* slot already up */ 40#define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ 41#define PCI_L1_ERR 7 /* L1 console command error */ 42#define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ 43#define PCI_L1_QSIZE 128 /* our L1 message buffer size */ 44#define SN_MAX_HP_SLOTS 32 /* max hotplug slots */ 45#define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */ 46#define SN_SLOT_NAME_SIZE 33 /* size of name string */ 47 48/* internal list head */ 49static struct list_head sn_hp_list; 50 51/* hotplug_slot struct's private pointer */ 52struct slot { 53 int device_num; 54 struct pci_bus *pci_bus; 55 /* this struct for glue internal only */ 56 struct hotplug_slot *hotplug_slot; 57 struct list_head hp_list; 58 char physical_path[SN_SLOT_NAME_SIZE]; 59}; 60 61struct pcibr_slot_enable_resp { 62 int resp_sub_errno; 63 char resp_l1_msg[PCI_L1_QSIZE + 1]; 64}; 65 66struct pcibr_slot_disable_resp { 67 int resp_sub_errno; 68 char resp_l1_msg[PCI_L1_QSIZE + 1]; 69}; 70 71enum sn_pci_req_e { 72 PCI_REQ_SLOT_ELIGIBLE, 73 PCI_REQ_SLOT_DISABLE 74}; 75 76static int enable_slot(struct hotplug_slot *slot); 77static int disable_slot(struct hotplug_slot *slot); 78static inline int get_power_status(struct hotplug_slot *slot, u8 *value); 79 80static struct hotplug_slot_ops sn_hotplug_slot_ops = { 81 .owner = THIS_MODULE, 82 .enable_slot = enable_slot, 83 .disable_slot = disable_slot, 84 .get_power_status = get_power_status, 85}; 86 87static DEFINE_MUTEX(sn_hotplug_mutex); 88 89static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot, 90 char *buf) 91{ 92 int retval = -ENOENT; 93 struct slot *slot = bss_hotplug_slot->private; 94 95 if (!slot) 96 return retval; 97 98 retval = sprintf (buf, "%s\n", slot->physical_path); 99 return retval; 100} 101 102static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path); 103 104static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) 105{ 106 struct pcibus_info *pcibus_info; 107 u16 busnum, segment, ioboard_type; 108 109 pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); 110 111 /* Check to see if this is a valid slot on 'pci_bus' */ 112 if (!(pcibus_info->pbi_valid_devices & (1 << device))) 113 return -EPERM; 114 115 ioboard_type = sn_ioboard_to_pci_bus(pci_bus); 116 busnum = pcibus_info->pbi_buscommon.bs_persist_busnum; 117 segment = pci_domain_nr(pci_bus) & 0xf; 118 119 /* Do not allow hotplug operations on base I/O cards */ 120 if ((ioboard_type == L1_BRICKTYPE_IX || 121 ioboard_type == L1_BRICKTYPE_IA) && 122 (segment == 1 && busnum == 0 && device != 1)) 123 return -EPERM; 124 125 return 1; 126} 127 128static int sn_pci_bus_valid(struct pci_bus *pci_bus) 129{ 130 struct pcibus_info *pcibus_info; 131 u32 asic_type; 132 u16 ioboard_type; 133 134 /* Don't register slots hanging off the TIOCA bus */ 135 pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); 136 asic_type = pcibus_info->pbi_buscommon.bs_asic_type; 137 if (asic_type == PCIIO_ASIC_TYPE_TIOCA) 138 return -EPERM; 139 140 /* Only register slots in I/O Bricks that support hotplug */ 141 ioboard_type = sn_ioboard_to_pci_bus(pci_bus); 142 switch (ioboard_type) { 143 case L1_BRICKTYPE_IX: 144 case L1_BRICKTYPE_PX: 145 case L1_BRICKTYPE_IA: 146 case L1_BRICKTYPE_PA: 147 case L1_BOARDTYPE_PCIX3SLOT: 148 return 1; 149 break; 150 default: 151 return -EPERM; 152 break; 153 } 154 155 return -EIO; 156} 157 158static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, 159 struct pci_bus *pci_bus, int device) 160{ 161 struct pcibus_info *pcibus_info; 162 struct slot *slot; 163 164 pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); 165 166 slot = kzalloc(sizeof(*slot), GFP_KERNEL); 167 if (!slot) 168 return -ENOMEM; 169 bss_hotplug_slot->private = slot; 170 171 bss_hotplug_slot->name = kmalloc(SN_SLOT_NAME_SIZE, GFP_KERNEL); 172 if (!bss_hotplug_slot->name) { 173 kfree(bss_hotplug_slot->private); 174 return -ENOMEM; 175 } 176 177 slot->device_num = device; 178 slot->pci_bus = pci_bus; 179 sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x", 180 pci_domain_nr(pci_bus), 181 ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum), 182 device + 1); 183 184 sn_generate_path(pci_bus, slot->physical_path); 185 186 slot->hotplug_slot = bss_hotplug_slot; 187 list_add(&slot->hp_list, &sn_hp_list); 188 189 return 0; 190} 191 192static struct hotplug_slot * sn_hp_destroy(void) 193{ 194 struct slot *slot; 195 struct hotplug_slot *bss_hotplug_slot = NULL; 196 197 list_for_each_entry(slot, &sn_hp_list, hp_list) { 198 bss_hotplug_slot = slot->hotplug_slot; 199 list_del(&((struct slot *)bss_hotplug_slot->private)-> 200 hp_list); 201 sysfs_remove_file(&bss_hotplug_slot->kobj, 202 &sn_slot_path_attr.attr); 203 break; 204 } 205 return bss_hotplug_slot; 206} 207 208static void sn_bus_free_data(struct pci_dev *dev) 209{ 210 struct pci_bus *subordinate_bus; 211 struct pci_dev *child; 212 213 /* Recursively clean up sn_irq_info structs */ 214 if (dev->subordinate) { 215 subordinate_bus = dev->subordinate; 216 list_for_each_entry(child, &subordinate_bus->devices, bus_list) 217 sn_bus_free_data(child); 218 } 219 /* 220 * Some drivers may use dma accesses during the 221 * driver remove function. We release the sysdata 222 * areas after the driver remove functions have 223 * been called. 224 */ 225 sn_bus_store_sysdata(dev); 226 sn_pci_unfixup_slot(dev); 227} 228 229static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, 230 int device_num) 231{ 232 struct slot *slot = bss_hotplug_slot->private; 233 struct pcibus_info *pcibus_info; 234 struct pcibr_slot_enable_resp resp; 235 int rc; 236 237 pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); 238 239 /* 240 * Power-on and initialize the slot in the SN 241 * PCI infrastructure. 242 */ 243 rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp); 244 245 if (rc == PCI_SLOT_ALREADY_UP) { 246 dev_dbg(slot->pci_bus->self, "is already active\n"); 247 return 1; /* return 1 to user */ 248 } 249 250 if (rc == PCI_L1_ERR) { 251 dev_dbg(slot->pci_bus->self, 252 "L1 failure %d with message: %s", 253 resp.resp_sub_errno, resp.resp_l1_msg); 254 return -EPERM; 255 } 256 257 if (rc) { 258 dev_dbg(slot->pci_bus->self, 259 "insert failed with error %d sub-error %d\n", 260 rc, resp.resp_sub_errno); 261 return -EIO; 262 } 263 264 pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); 265 pcibus_info->pbi_enabled_devices |= (1 << device_num); 266 267 return 0; 268} 269 270static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot, 271 int device_num, int action) 272{ 273 struct slot *slot = bss_hotplug_slot->private; 274 struct pcibus_info *pcibus_info; 275 struct pcibr_slot_disable_resp resp; 276 int rc; 277 278 pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); 279 280 rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp); 281 282 if ((action == PCI_REQ_SLOT_ELIGIBLE) && 283 (rc == PCI_SLOT_ALREADY_DOWN)) { 284 dev_dbg(slot->pci_bus->self, "Slot %s already inactive\n"); 285 return 1; /* return 1 to user */ 286 } 287 288 if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) { 289 dev_dbg(slot->pci_bus->self, 290 "Cannot remove last 33MHz card\n"); 291 return -EPERM; 292 } 293 294 if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) { 295 dev_dbg(slot->pci_bus->self, 296 "L1 failure %d with message \n%s\n", 297 resp.resp_sub_errno, resp.resp_l1_msg); 298 return -EPERM; 299 } 300 301 if ((action == PCI_REQ_SLOT_ELIGIBLE) && rc) { 302 dev_dbg(slot->pci_bus->self, 303 "remove failed with error %d sub-error %d\n", 304 rc, resp.resp_sub_errno); 305 return -EIO; 306 } 307 308 if ((action == PCI_REQ_SLOT_ELIGIBLE) && !rc) 309 return 0; 310 311 if ((action == PCI_REQ_SLOT_DISABLE) && !rc) { 312 pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); 313 pcibus_info->pbi_enabled_devices &= ~(1 << device_num); 314 dev_dbg(slot->pci_bus->self, "remove successful\n"); 315 return 0; 316 } 317 318 if ((action == PCI_REQ_SLOT_DISABLE) && rc) { 319 dev_dbg(slot->pci_bus->self,"remove failed rc = %d\n", rc); 320 } 321 322 return rc; 323} 324 325/* 326 * Power up and configure the slot via a SAL call to PROM. 327 * Scan slot (and any children), do any platform specific fixup, 328 * and find device driver. 329 */ 330static int enable_slot(struct hotplug_slot *bss_hotplug_slot) 331{ 332 struct slot *slot = bss_hotplug_slot->private; 333 struct pci_bus *new_bus = NULL; 334 struct pci_dev *dev; 335 int func, num_funcs; 336 int new_ppb = 0; 337 int rc; 338 void pcibios_fixup_device_resources(struct pci_dev *); 339 340 /* Serialize the Linux PCI infrastructure */ 341 mutex_lock(&sn_hotplug_mutex); 342 343 /* 344 * Power-on and initialize the slot in the SN 345 * PCI infrastructure. 346 */ 347 rc = sn_slot_enable(bss_hotplug_slot, slot->device_num); 348 if (rc) { 349 mutex_unlock(&sn_hotplug_mutex); 350 return rc; 351 } 352 353 num_funcs = pci_scan_slot(slot->pci_bus, 354 PCI_DEVFN(slot->device_num + 1, 0)); 355 if (!num_funcs) { 356 dev_dbg(slot->pci_bus->self, "no device in slot\n"); 357 mutex_unlock(&sn_hotplug_mutex); 358 return -ENODEV; 359 } 360 361 /* 362 * Map SN resources for all functions on the card 363 * to the Linux PCI interface and tell the drivers 364 * about them. 365 */ 366 for (func = 0; func < num_funcs; func++) { 367 dev = pci_get_slot(slot->pci_bus, 368 PCI_DEVFN(slot->device_num + 1, 369 PCI_FUNC(func))); 370 if (dev) { 371 /* Need to do slot fixup on PPB before fixup of children 372 * (PPB's pcidev_info needs to be in pcidev_info list 373 * before child's SN_PCIDEV_INFO() call to setup 374 * pdi_host_pcidev_info). 375 */ 376 pcibios_fixup_device_resources(dev); 377 sn_pci_fixup_slot(dev); 378 if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 379 unsigned char sec_bus; 380 pci_read_config_byte(dev, PCI_SECONDARY_BUS, 381 &sec_bus); 382 new_bus = pci_add_new_bus(dev->bus, dev, 383 sec_bus); 384 pci_scan_child_bus(new_bus); 385 new_ppb = 1; 386 } 387 pci_dev_put(dev); 388 } 389 } 390 391 /* Call the driver for the new device */ 392 pci_bus_add_devices(slot->pci_bus); 393 /* Call the drivers for the new devices subordinate to PPB */ 394 if (new_ppb) 395 pci_bus_add_devices(new_bus); 396 397 mutex_unlock(&sn_hotplug_mutex); 398 399 if (rc == 0) 400 dev_dbg(slot->pci_bus->self, 401 "insert operation successful\n"); 402 else 403 dev_dbg(slot->pci_bus->self, 404 "insert operation failed rc = %d\n", rc); 405 406 return rc; 407} 408 409static int disable_slot(struct hotplug_slot *bss_hotplug_slot) 410{ 411 struct slot *slot = bss_hotplug_slot->private; 412 struct pci_dev *dev; 413 int func; 414 int rc; 415 416 /* Acquire update access to the bus */ 417 mutex_lock(&sn_hotplug_mutex); 418 419 /* is it okay to bring this slot down? */ 420 rc = sn_slot_disable(bss_hotplug_slot, slot->device_num, 421 PCI_REQ_SLOT_ELIGIBLE); 422 if (rc) 423 goto leaving; 424 425 /* Free the SN resources assigned to the Linux device.*/ 426 for (func = 0; func < 8; func++) { 427 dev = pci_get_slot(slot->pci_bus, 428 PCI_DEVFN(slot->device_num + 1, 429 PCI_FUNC(func))); 430 if (dev) { 431 sn_bus_free_data(dev); 432 pci_remove_bus_device(dev); 433 pci_dev_put(dev); 434 } 435 } 436 437 /* free the collected sysdata pointers */ 438 sn_bus_free_sysdata(); 439 440 /* Deactivate slot */ 441 rc = sn_slot_disable(bss_hotplug_slot, slot->device_num, 442 PCI_REQ_SLOT_DISABLE); 443 leaving: 444 /* Release the bus lock */ 445 mutex_unlock(&sn_hotplug_mutex); 446 447 return rc; 448} 449 450static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, 451 u8 *value) 452{ 453 struct slot *slot = bss_hotplug_slot->private; 454 struct pcibus_info *pcibus_info; 455 u32 power; 456 457 pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); 458 mutex_lock(&sn_hotplug_mutex); 459 power = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); 460 *value = power ? 1 : 0; 461 mutex_unlock(&sn_hotplug_mutex); 462 return 0; 463} 464 465static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) 466{ 467 kfree(bss_hotplug_slot->info); 468 kfree(bss_hotplug_slot->name); 469 kfree(bss_hotplug_slot->private); 470 kfree(bss_hotplug_slot); 471} 472 473static int sn_hotplug_slot_register(struct pci_bus *pci_bus) 474{ 475 int device; 476 struct hotplug_slot *bss_hotplug_slot; 477 int rc = 0; 478 479 /* 480 * Currently only four devices are supported, 481 * in the future there maybe more -- up to 32. 482 */ 483 484 for (device = 0; device < SN_MAX_HP_SLOTS ; device++) { 485 if (sn_pci_slot_valid(pci_bus, device) != 1) 486 continue; 487 488 bss_hotplug_slot = kzalloc(sizeof(*bss_hotplug_slot), 489 GFP_KERNEL); 490 if (!bss_hotplug_slot) { 491 rc = -ENOMEM; 492 goto alloc_err; 493 } 494 495 bss_hotplug_slot->info = 496 kzalloc(sizeof(struct hotplug_slot_info), 497 GFP_KERNEL); 498 if (!bss_hotplug_slot->info) { 499 rc = -ENOMEM; 500 goto alloc_err; 501 } 502 503 if (sn_hp_slot_private_alloc(bss_hotplug_slot, 504 pci_bus, device)) { 505 rc = -ENOMEM; 506 goto alloc_err; 507 } 508 509 bss_hotplug_slot->ops = &sn_hotplug_slot_ops; 510 bss_hotplug_slot->release = &sn_release_slot; 511 512 rc = pci_hp_register(bss_hotplug_slot); 513 if (rc) 514 goto register_err; 515 516 rc = sysfs_create_file(&bss_hotplug_slot->kobj, 517 &sn_slot_path_attr.attr); 518 if (rc) 519 goto register_err; 520 } 521 dev_dbg(pci_bus->self, "Registered bus with hotplug\n"); 522 return rc; 523 524register_err: 525 dev_dbg(pci_bus->self, "bus failed to register with err = %d\n", 526 rc); 527 528alloc_err: 529 if (rc == -ENOMEM) 530 dev_dbg(pci_bus->self, "Memory allocation error\n"); 531 532 /* destroy THIS element */ 533 if (bss_hotplug_slot) 534 sn_release_slot(bss_hotplug_slot); 535 536 /* destroy anything else on the list */ 537 while ((bss_hotplug_slot = sn_hp_destroy())) 538 pci_hp_deregister(bss_hotplug_slot); 539 540 return rc; 541} 542 543static int sn_pci_hotplug_init(void) 544{ 545 struct pci_bus *pci_bus = NULL; 546 int rc; 547 int registered = 0; 548 549 if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) { 550 printk(KERN_ERR "%s: PROM version does not support hotplug.\n", 551 __FUNCTION__); 552 return -EPERM; 553 } 554 555 INIT_LIST_HEAD(&sn_hp_list); 556 557 while ((pci_bus = pci_find_next_bus(pci_bus))) { 558 if (!pci_bus->sysdata) 559 continue; 560 561 rc = sn_pci_bus_valid(pci_bus); 562 if (rc != 1) { 563 dev_dbg(pci_bus->self, "not a valid hotplug bus\n"); 564 continue; 565 } 566 dev_dbg(pci_bus->self, "valid hotplug bus\n"); 567 568 rc = sn_hotplug_slot_register(pci_bus); 569 if (!rc) { 570 registered = 1; 571 } else { 572 registered = 0; 573 break; 574 } 575 } 576 577 return registered == 1 ? 0 : -ENODEV; 578} 579 580static void sn_pci_hotplug_exit(void) 581{ 582 struct hotplug_slot *bss_hotplug_slot; 583 584 while ((bss_hotplug_slot = sn_hp_destroy())) 585 pci_hp_deregister(bss_hotplug_slot); 586 587 if (!list_empty(&sn_hp_list)) 588 printk(KERN_ERR "%s: internal list is not empty\n", __FILE__); 589} 590 591module_init(sn_pci_hotplug_init); 592module_exit(sn_pci_hotplug_exit);