1 /* 2 * Standard Hot Plug Controller Driver 3 * 4 * Copyright (C) 1995,2001 Compaq Computer Corporation 5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) 6 * Copyright (C) 2001 IBM Corp. 7 * Copyright (C) 2003-2004 Intel Corporation 8 * 9 * All rights reserved. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or (at 14 * your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 19 * NON INFRINGEMENT. See the GNU General Public License for more 20 * details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * 26 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com> 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/pci.h> 35 #include <linux/workqueue.h> 36 #include "shpchp.h" 37 38 /* Global variables */ 39 int shpchp_debug; 40 int shpchp_poll_mode; 41 int shpchp_poll_time; 42 struct workqueue_struct *shpchp_wq; 43 44 #define DRIVER_VERSION "0.4" 45 #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" 46 #define DRIVER_DESC "Standard Hot Plug PCI Controller Driver" 47 48 MODULE_AUTHOR(DRIVER_AUTHOR); 49 MODULE_DESCRIPTION(DRIVER_DESC); 50 MODULE_LICENSE("GPL"); 51 52 module_param(shpchp_debug, bool, 0644); 53 module_param(shpchp_poll_mode, bool, 0644); 54 module_param(shpchp_poll_time, int, 0644); 55 MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not"); 56 MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not"); 57 MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds"); 58 59 #define SHPC_MODULE_NAME "shpchp" 60 61 static int set_attention_status (struct hotplug_slot *slot, u8 value); 62 static int enable_slot (struct hotplug_slot *slot); 63 static int disable_slot (struct hotplug_slot *slot); 64 static int get_power_status (struct hotplug_slot *slot, u8 *value); 65 static int get_attention_status (struct hotplug_slot *slot, u8 *value); 66 static int get_latch_status (struct hotplug_slot *slot, u8 *value); 67 static int get_adapter_status (struct hotplug_slot *slot, u8 *value); 68 69 static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { 70 .set_attention_status = set_attention_status, 71 .enable_slot = enable_slot, 72 .disable_slot = disable_slot, 73 .get_power_status = get_power_status, 74 .get_attention_status = get_attention_status, 75 .get_latch_status = get_latch_status, 76 .get_adapter_status = get_adapter_status, 77 }; 78 79 /** 80 * release_slot - free up the memory used by a slot 81 * @hotplug_slot: slot to free 82 */ 83 static void release_slot(struct hotplug_slot *hotplug_slot) 84 { 85 struct slot *slot = hotplug_slot->private; 86 87 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", 88 __func__, slot_name(slot)); 89 90 kfree(slot->hotplug_slot->info); 91 kfree(slot->hotplug_slot); 92 kfree(slot); 93 } 94 95 static int init_slots(struct controller *ctrl) 96 { 97 struct slot *slot; 98 struct hotplug_slot *hotplug_slot; 99 struct hotplug_slot_info *info; 100 char name[SLOT_NAME_SIZE]; 101 int retval = -ENOMEM; 102 int i; 103 104 for (i = 0; i < ctrl->num_slots; i++) { 105 slot = kzalloc(sizeof(*slot), GFP_KERNEL); 106 if (!slot) 107 goto error; 108 109 hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); 110 if (!hotplug_slot) 111 goto error_slot; 112 slot->hotplug_slot = hotplug_slot; 113 114 info = kzalloc(sizeof(*info), GFP_KERNEL); 115 if (!info) 116 goto error_hpslot; 117 hotplug_slot->info = info; 118 119 slot->hp_slot = i; 120 slot->ctrl = ctrl; 121 slot->bus = ctrl->pci_dev->subordinate->number; 122 slot->device = ctrl->slot_device_offset + i; 123 slot->hpc_ops = ctrl->hpc_ops; 124 slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i); 125 mutex_init(&slot->lock); 126 INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work); 127 128 /* register this slot with the hotplug pci core */ 129 hotplug_slot->private = slot; 130 hotplug_slot->release = &release_slot; 131 snprintf(name, SLOT_NAME_SIZE, "%d", slot->number); 132 hotplug_slot->ops = &shpchp_hotplug_slot_ops; 133 134 ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x " 135 "hp_slot=%x sun=%x slot_device_offset=%x\n", 136 pci_domain_nr(ctrl->pci_dev->subordinate), 137 slot->bus, slot->device, slot->hp_slot, slot->number, 138 ctrl->slot_device_offset); 139 retval = pci_hp_register(slot->hotplug_slot, 140 ctrl->pci_dev->subordinate, slot->device, name); 141 if (retval) { 142 ctrl_err(ctrl, "pci_hp_register failed with error %d\n", 143 retval); 144 goto error_info; 145 } 146 147 get_power_status(hotplug_slot, &info->power_status); 148 get_attention_status(hotplug_slot, &info->attention_status); 149 get_latch_status(hotplug_slot, &info->latch_status); 150 get_adapter_status(hotplug_slot, &info->adapter_status); 151 152 list_add(&slot->slot_list, &ctrl->slot_list); 153 } 154 155 return 0; 156 error_info: 157 kfree(info); 158 error_hpslot: 159 kfree(hotplug_slot); 160 error_slot: 161 kfree(slot); 162 error: 163 return retval; 164 } 165 166 void cleanup_slots(struct controller *ctrl) 167 { 168 struct list_head *tmp; 169 struct list_head *next; 170 struct slot *slot; 171 172 list_for_each_safe(tmp, next, &ctrl->slot_list) { 173 slot = list_entry(tmp, struct slot, slot_list); 174 list_del(&slot->slot_list); 175 cancel_delayed_work(&slot->work); 176 flush_scheduled_work(); 177 flush_workqueue(shpchp_wq); 178 pci_hp_deregister(slot->hotplug_slot); 179 } 180 } 181 182 /* 183 * set_attention_status - Turns the Amber LED for a slot on, off or blink 184 */ 185 static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) 186 { 187 struct slot *slot = get_slot(hotplug_slot); 188 189 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", 190 __func__, slot_name(slot)); 191 192 hotplug_slot->info->attention_status = status; 193 slot->hpc_ops->set_attention_status(slot, status); 194 195 return 0; 196 } 197 198 static int enable_slot (struct hotplug_slot *hotplug_slot) 199 { 200 struct slot *slot = get_slot(hotplug_slot); 201 202 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", 203 __func__, slot_name(slot)); 204 205 return shpchp_sysfs_enable_slot(slot); 206 } 207 208 static int disable_slot (struct hotplug_slot *hotplug_slot) 209 { 210 struct slot *slot = get_slot(hotplug_slot); 211 212 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", 213 __func__, slot_name(slot)); 214 215 return shpchp_sysfs_disable_slot(slot); 216 } 217 218 static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) 219 { 220 struct slot *slot = get_slot(hotplug_slot); 221 int retval; 222 223 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", 224 __func__, slot_name(slot)); 225 226 retval = slot->hpc_ops->get_power_status(slot, value); 227 if (retval < 0) 228 *value = hotplug_slot->info->power_status; 229 230 return 0; 231 } 232 233 static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) 234 { 235 struct slot *slot = get_slot(hotplug_slot); 236 int retval; 237 238 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", 239 __func__, slot_name(slot)); 240 241 retval = slot->hpc_ops->get_attention_status(slot, value); 242 if (retval < 0) 243 *value = hotplug_slot->info->attention_status; 244 245 return 0; 246 } 247 248 static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) 249 { 250 struct slot *slot = get_slot(hotplug_slot); 251 int retval; 252 253 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", 254 __func__, slot_name(slot)); 255 256 retval = slot->hpc_ops->get_latch_status(slot, value); 257 if (retval < 0) 258 *value = hotplug_slot->info->latch_status; 259 260 return 0; 261 } 262 263 static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) 264 { 265 struct slot *slot = get_slot(hotplug_slot); 266 int retval; 267 268 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", 269 __func__, slot_name(slot)); 270 271 retval = slot->hpc_ops->get_adapter_status(slot, value); 272 if (retval < 0) 273 *value = hotplug_slot->info->adapter_status; 274 275 return 0; 276 } 277 278 static int is_shpc_capable(struct pci_dev *dev) 279 { 280 if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == 281 PCI_DEVICE_ID_AMD_GOLAM_7450)) 282 return 1; 283 if (!pci_find_capability(dev, PCI_CAP_ID_SHPC)) 284 return 0; 285 if (get_hp_hw_control_from_firmware(dev)) 286 return 0; 287 return 1; 288 } 289 290 static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 291 { 292 int rc; 293 struct controller *ctrl; 294 295 if (!is_shpc_capable(pdev)) 296 return -ENODEV; 297 298 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); 299 if (!ctrl) { 300 dev_err(&pdev->dev, "%s: Out of memory\n", __func__); 301 goto err_out_none; 302 } 303 INIT_LIST_HEAD(&ctrl->slot_list); 304 305 rc = shpc_init(ctrl, pdev); 306 if (rc) { 307 ctrl_dbg(ctrl, "Controller initialization failed\n"); 308 goto err_out_free_ctrl; 309 } 310 311 pci_set_drvdata(pdev, ctrl); 312 313 /* Setup the slot information structures */ 314 rc = init_slots(ctrl); 315 if (rc) { 316 ctrl_err(ctrl, "Slot initialization failed\n"); 317 goto err_out_release_ctlr; 318 } 319 320 rc = shpchp_create_ctrl_files(ctrl); 321 if (rc) 322 goto err_cleanup_slots; 323 324 return 0; 325 326 err_cleanup_slots: 327 cleanup_slots(ctrl); 328 err_out_release_ctlr: 329 ctrl->hpc_ops->release_ctlr(ctrl); 330 err_out_free_ctrl: 331 kfree(ctrl); 332 err_out_none: 333 return -ENODEV; 334 } 335 336 static void shpc_remove(struct pci_dev *dev) 337 { 338 struct controller *ctrl = pci_get_drvdata(dev); 339 340 shpchp_remove_ctrl_files(ctrl); 341 ctrl->hpc_ops->release_ctlr(ctrl); 342 kfree(ctrl); 343 } 344 345 static struct pci_device_id shpcd_pci_tbl[] = { 346 {PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0)}, 347 { /* end: all zeroes */ } 348 }; 349 MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl); 350 351 static struct pci_driver shpc_driver = { 352 .name = SHPC_MODULE_NAME, 353 .id_table = shpcd_pci_tbl, 354 .probe = shpc_probe, 355 .remove = shpc_remove, 356 }; 357 358 static int __init shpcd_init(void) 359 { 360 int retval = 0; 361 362 retval = pci_register_driver(&shpc_driver); 363 dbg("%s: pci_register_driver = %d\n", __func__, retval); 364 info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); 365 return retval; 366 } 367 368 static void __exit shpcd_cleanup(void) 369 { 370 dbg("unload_shpchpd()\n"); 371 pci_unregister_driver(&shpc_driver); 372 info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); 373 } 374 375 module_init(shpcd_init); 376 module_exit(shpcd_cleanup); 377