0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <linux/module.h>
0017 #include <linux/moduleparam.h>
0018 #include <linux/kernel.h>
0019 #include <linux/types.h>
0020 #include <linux/slab.h>
0021 #include <linux/pci.h>
0022 #include "shpchp.h"
0023
0024
0025 bool shpchp_debug;
0026 bool shpchp_poll_mode;
0027 int shpchp_poll_time;
0028
0029 #define DRIVER_VERSION "0.4"
0030 #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
0031 #define DRIVER_DESC "Standard Hot Plug PCI Controller Driver"
0032
0033 MODULE_AUTHOR(DRIVER_AUTHOR);
0034 MODULE_DESCRIPTION(DRIVER_DESC);
0035 MODULE_LICENSE("GPL");
0036
0037 module_param(shpchp_debug, bool, 0644);
0038 module_param(shpchp_poll_mode, bool, 0644);
0039 module_param(shpchp_poll_time, int, 0644);
0040 MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not");
0041 MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not");
0042 MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
0043
0044 #define SHPC_MODULE_NAME "shpchp"
0045
0046 static int set_attention_status(struct hotplug_slot *slot, u8 value);
0047 static int enable_slot(struct hotplug_slot *slot);
0048 static int disable_slot(struct hotplug_slot *slot);
0049 static int get_power_status(struct hotplug_slot *slot, u8 *value);
0050 static int get_attention_status(struct hotplug_slot *slot, u8 *value);
0051 static int get_latch_status(struct hotplug_slot *slot, u8 *value);
0052 static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
0053
0054 static const struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
0055 .set_attention_status = set_attention_status,
0056 .enable_slot = enable_slot,
0057 .disable_slot = disable_slot,
0058 .get_power_status = get_power_status,
0059 .get_attention_status = get_attention_status,
0060 .get_latch_status = get_latch_status,
0061 .get_adapter_status = get_adapter_status,
0062 };
0063
0064 static int init_slots(struct controller *ctrl)
0065 {
0066 struct slot *slot;
0067 struct hotplug_slot *hotplug_slot;
0068 char name[SLOT_NAME_SIZE];
0069 int retval;
0070 int i;
0071
0072 for (i = 0; i < ctrl->num_slots; i++) {
0073 slot = kzalloc(sizeof(*slot), GFP_KERNEL);
0074 if (!slot) {
0075 retval = -ENOMEM;
0076 goto error;
0077 }
0078
0079 hotplug_slot = &slot->hotplug_slot;
0080
0081 slot->hp_slot = i;
0082 slot->ctrl = ctrl;
0083 slot->bus = ctrl->pci_dev->subordinate->number;
0084 slot->device = ctrl->slot_device_offset + i;
0085 slot->hpc_ops = ctrl->hpc_ops;
0086 slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i);
0087
0088 slot->wq = alloc_workqueue("shpchp-%d", 0, 0, slot->number);
0089 if (!slot->wq) {
0090 retval = -ENOMEM;
0091 goto error_slot;
0092 }
0093
0094 mutex_init(&slot->lock);
0095 INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work);
0096
0097
0098 snprintf(name, SLOT_NAME_SIZE, "%d", slot->number);
0099 hotplug_slot->ops = &shpchp_hotplug_slot_ops;
0100
0101 ctrl_dbg(ctrl, "Registering domain:bus:dev=%04x:%02x:%02x hp_slot=%x sun=%x slot_device_offset=%x\n",
0102 pci_domain_nr(ctrl->pci_dev->subordinate),
0103 slot->bus, slot->device, slot->hp_slot, slot->number,
0104 ctrl->slot_device_offset);
0105 retval = pci_hp_register(hotplug_slot,
0106 ctrl->pci_dev->subordinate, slot->device, name);
0107 if (retval) {
0108 ctrl_err(ctrl, "pci_hp_register failed with error %d\n",
0109 retval);
0110 goto error_slotwq;
0111 }
0112
0113 get_power_status(hotplug_slot, &slot->pwr_save);
0114 get_attention_status(hotplug_slot, &slot->attention_save);
0115 get_latch_status(hotplug_slot, &slot->latch_save);
0116 get_adapter_status(hotplug_slot, &slot->presence_save);
0117
0118 list_add(&slot->slot_list, &ctrl->slot_list);
0119 }
0120
0121 return 0;
0122 error_slotwq:
0123 destroy_workqueue(slot->wq);
0124 error_slot:
0125 kfree(slot);
0126 error:
0127 return retval;
0128 }
0129
0130 void cleanup_slots(struct controller *ctrl)
0131 {
0132 struct slot *slot, *next;
0133
0134 list_for_each_entry_safe(slot, next, &ctrl->slot_list, slot_list) {
0135 list_del(&slot->slot_list);
0136 cancel_delayed_work(&slot->work);
0137 destroy_workqueue(slot->wq);
0138 pci_hp_deregister(&slot->hotplug_slot);
0139 kfree(slot);
0140 }
0141 }
0142
0143
0144
0145
0146 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
0147 {
0148 struct slot *slot = get_slot(hotplug_slot);
0149
0150 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
0151 __func__, slot_name(slot));
0152
0153 slot->attention_save = status;
0154 slot->hpc_ops->set_attention_status(slot, status);
0155
0156 return 0;
0157 }
0158
0159 static int enable_slot(struct hotplug_slot *hotplug_slot)
0160 {
0161 struct slot *slot = get_slot(hotplug_slot);
0162
0163 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
0164 __func__, slot_name(slot));
0165
0166 return shpchp_sysfs_enable_slot(slot);
0167 }
0168
0169 static int disable_slot(struct hotplug_slot *hotplug_slot)
0170 {
0171 struct slot *slot = get_slot(hotplug_slot);
0172
0173 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
0174 __func__, slot_name(slot));
0175
0176 return shpchp_sysfs_disable_slot(slot);
0177 }
0178
0179 static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
0180 {
0181 struct slot *slot = get_slot(hotplug_slot);
0182 int retval;
0183
0184 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
0185 __func__, slot_name(slot));
0186
0187 retval = slot->hpc_ops->get_power_status(slot, value);
0188 if (retval < 0)
0189 *value = slot->pwr_save;
0190
0191 return 0;
0192 }
0193
0194 static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
0195 {
0196 struct slot *slot = get_slot(hotplug_slot);
0197 int retval;
0198
0199 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
0200 __func__, slot_name(slot));
0201
0202 retval = slot->hpc_ops->get_attention_status(slot, value);
0203 if (retval < 0)
0204 *value = slot->attention_save;
0205
0206 return 0;
0207 }
0208
0209 static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
0210 {
0211 struct slot *slot = get_slot(hotplug_slot);
0212 int retval;
0213
0214 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
0215 __func__, slot_name(slot));
0216
0217 retval = slot->hpc_ops->get_latch_status(slot, value);
0218 if (retval < 0)
0219 *value = slot->latch_save;
0220
0221 return 0;
0222 }
0223
0224 static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
0225 {
0226 struct slot *slot = get_slot(hotplug_slot);
0227 int retval;
0228
0229 ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
0230 __func__, slot_name(slot));
0231
0232 retval = slot->hpc_ops->get_adapter_status(slot, value);
0233 if (retval < 0)
0234 *value = slot->presence_save;
0235
0236 return 0;
0237 }
0238
0239 static bool shpc_capable(struct pci_dev *bridge)
0240 {
0241
0242
0243
0244
0245 if (bridge->vendor == PCI_VENDOR_ID_AMD &&
0246 bridge->device == PCI_DEVICE_ID_AMD_GOLAM_7450)
0247 return true;
0248
0249 if (pci_find_capability(bridge, PCI_CAP_ID_SHPC))
0250 return true;
0251
0252 return false;
0253 }
0254
0255 static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
0256 {
0257 int rc;
0258 struct controller *ctrl;
0259
0260 if (!shpc_capable(pdev))
0261 return -ENODEV;
0262
0263 if (acpi_get_hp_hw_control_from_firmware(pdev))
0264 return -ENODEV;
0265
0266 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
0267 if (!ctrl)
0268 goto err_out_none;
0269
0270 INIT_LIST_HEAD(&ctrl->slot_list);
0271
0272 rc = shpc_init(ctrl, pdev);
0273 if (rc) {
0274 ctrl_dbg(ctrl, "Controller initialization failed\n");
0275 goto err_out_free_ctrl;
0276 }
0277
0278 pci_set_drvdata(pdev, ctrl);
0279
0280
0281 rc = init_slots(ctrl);
0282 if (rc) {
0283 ctrl_err(ctrl, "Slot initialization failed\n");
0284 goto err_out_release_ctlr;
0285 }
0286
0287 rc = shpchp_create_ctrl_files(ctrl);
0288 if (rc)
0289 goto err_cleanup_slots;
0290
0291 pdev->shpc_managed = 1;
0292 return 0;
0293
0294 err_cleanup_slots:
0295 cleanup_slots(ctrl);
0296 err_out_release_ctlr:
0297 ctrl->hpc_ops->release_ctlr(ctrl);
0298 err_out_free_ctrl:
0299 kfree(ctrl);
0300 err_out_none:
0301 return -ENODEV;
0302 }
0303
0304 static void shpc_remove(struct pci_dev *dev)
0305 {
0306 struct controller *ctrl = pci_get_drvdata(dev);
0307
0308 dev->shpc_managed = 0;
0309 shpchp_remove_ctrl_files(ctrl);
0310 ctrl->hpc_ops->release_ctlr(ctrl);
0311 kfree(ctrl);
0312 }
0313
0314 static const struct pci_device_id shpcd_pci_tbl[] = {
0315 {PCI_DEVICE_CLASS(PCI_CLASS_BRIDGE_PCI_NORMAL, ~0)},
0316 { }
0317 };
0318 MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl);
0319
0320 static struct pci_driver shpc_driver = {
0321 .name = SHPC_MODULE_NAME,
0322 .id_table = shpcd_pci_tbl,
0323 .probe = shpc_probe,
0324 .remove = shpc_remove,
0325 };
0326
0327 static int __init shpcd_init(void)
0328 {
0329 int retval;
0330
0331 retval = pci_register_driver(&shpc_driver);
0332 dbg("%s: pci_register_driver = %d\n", __func__, retval);
0333 info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
0334
0335 return retval;
0336 }
0337
0338 static void __exit shpcd_cleanup(void)
0339 {
0340 dbg("unload_shpchpd()\n");
0341 pci_unregister_driver(&shpc_driver);
0342 info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
0343 }
0344
0345 module_init(shpcd_init);
0346 module_exit(shpcd_cleanup);