shpchp_core.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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. #include <linux/module.h>
  30. #include <linux/moduleparam.h>
  31. #include <linux/kernel.h>
  32. #include <linux/types.h>
  33. #include <linux/pci.h>
  34. #include "shpchp.h"
  35. /* Global variables */
  36. int shpchp_debug;
  37. int shpchp_poll_mode;
  38. int shpchp_poll_time;
  39. struct controller *shpchp_ctrl_list; /* = NULL */
  40. #define DRIVER_VERSION "0.4"
  41. #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
  42. #define DRIVER_DESC "Standard Hot Plug PCI Controller Driver"
  43. MODULE_AUTHOR(DRIVER_AUTHOR);
  44. MODULE_DESCRIPTION(DRIVER_DESC);
  45. MODULE_LICENSE("GPL");
  46. module_param(shpchp_debug, bool, 0644);
  47. module_param(shpchp_poll_mode, bool, 0644);
  48. module_param(shpchp_poll_time, int, 0644);
  49. MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not");
  50. MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not");
  51. MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
  52. #define SHPC_MODULE_NAME "shpchp"
  53. static int shpc_start_thread (void);
  54. static int set_attention_status (struct hotplug_slot *slot, u8 value);
  55. static int enable_slot (struct hotplug_slot *slot);
  56. static int disable_slot (struct hotplug_slot *slot);
  57. static int get_power_status (struct hotplug_slot *slot, u8 *value);
  58. static int get_attention_status (struct hotplug_slot *slot, u8 *value);
  59. static int get_latch_status (struct hotplug_slot *slot, u8 *value);
  60. static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
  61. static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
  62. static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
  63. static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
  64. .owner = THIS_MODULE,
  65. .set_attention_status = set_attention_status,
  66. .enable_slot = enable_slot,
  67. .disable_slot = disable_slot,
  68. .get_power_status = get_power_status,
  69. .get_attention_status = get_attention_status,
  70. .get_latch_status = get_latch_status,
  71. .get_adapter_status = get_adapter_status,
  72. .get_max_bus_speed = get_max_bus_speed,
  73. .get_cur_bus_speed = get_cur_bus_speed,
  74. };
  75. /**
  76. * release_slot - free up the memory used by a slot
  77. * @hotplug_slot: slot to free
  78. */
  79. static void release_slot(struct hotplug_slot *hotplug_slot)
  80. {
  81. struct slot *slot = hotplug_slot->private;
  82. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  83. kfree(slot->hotplug_slot->info);
  84. kfree(slot->hotplug_slot->name);
  85. kfree(slot->hotplug_slot);
  86. kfree(slot);
  87. }
  88. static int init_slots(struct controller *ctrl)
  89. {
  90. struct slot *new_slot;
  91. u8 number_of_slots;
  92. u8 slot_device;
  93. u32 slot_number, sun;
  94. int result = -ENOMEM;
  95. number_of_slots = ctrl->num_slots;
  96. slot_device = ctrl->slot_device_offset;
  97. slot_number = ctrl->first_slot;
  98. while (number_of_slots) {
  99. new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL);
  100. if (!new_slot)
  101. goto error;
  102. memset(new_slot, 0, sizeof(struct slot));
  103. new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
  104. if (!new_slot->hotplug_slot)
  105. goto error_slot;
  106. memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
  107. new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
  108. if (!new_slot->hotplug_slot->info)
  109. goto error_hpslot;
  110. memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
  111. new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
  112. if (!new_slot->hotplug_slot->name)
  113. goto error_info;
  114. new_slot->magic = SLOT_MAGIC;
  115. new_slot->ctrl = ctrl;
  116. new_slot->bus = ctrl->slot_bus;
  117. new_slot->device = slot_device;
  118. new_slot->hpc_ops = ctrl->hpc_ops;
  119. if (shpchprm_get_physical_slot_number(ctrl, &sun,
  120. new_slot->bus, new_slot->device))
  121. goto error_name;
  122. new_slot->number = sun;
  123. new_slot->hp_slot = slot_device - ctrl->slot_device_offset;
  124. /* register this slot with the hotplug pci core */
  125. new_slot->hotplug_slot->private = new_slot;
  126. new_slot->hotplug_slot->release = &release_slot;
  127. make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);
  128. new_slot->hotplug_slot->ops = &shpchp_hotplug_slot_ops;
  129. new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status));
  130. new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status));
  131. new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status));
  132. new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status));
  133. dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", new_slot->bus,
  134. new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset);
  135. result = pci_hp_register (new_slot->hotplug_slot);
  136. if (result) {
  137. err ("pci_hp_register failed with error %d\n", result);
  138. goto error_name;
  139. }
  140. new_slot->next = ctrl->slot;
  141. ctrl->slot = new_slot;
  142. number_of_slots--;
  143. slot_device++;
  144. slot_number += ctrl->slot_num_inc;
  145. }
  146. return 0;
  147. error_name:
  148. kfree(new_slot->hotplug_slot->name);
  149. error_info:
  150. kfree(new_slot->hotplug_slot->info);
  151. error_hpslot:
  152. kfree(new_slot->hotplug_slot);
  153. error_slot:
  154. kfree(new_slot);
  155. error:
  156. return result;
  157. }
  158. static void cleanup_slots(struct controller *ctrl)
  159. {
  160. struct slot *old_slot, *next_slot;
  161. old_slot = ctrl->slot;
  162. ctrl->slot = NULL;
  163. while (old_slot) {
  164. next_slot = old_slot->next;
  165. pci_hp_deregister(old_slot->hotplug_slot);
  166. old_slot = next_slot;
  167. }
  168. }
  169. static int get_ctlr_slot_config(struct controller *ctrl)
  170. {
  171. int num_ctlr_slots;
  172. int first_device_num;
  173. int physical_slot_num;
  174. int updown;
  175. int rc;
  176. int flags;
  177. rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &updown, &flags);
  178. if (rc) {
  179. err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
  180. return -1;
  181. }
  182. ctrl->num_slots = num_ctlr_slots;
  183. ctrl->slot_device_offset = first_device_num;
  184. ctrl->first_slot = physical_slot_num;
  185. ctrl->slot_num_inc = updown; /* either -1 or 1 */
  186. dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n",
  187. __FUNCTION__, num_ctlr_slots, first_device_num, physical_slot_num, updown, ctrl->bus, ctrl->device);
  188. return 0;
  189. }
  190. /*
  191. * set_attention_status - Turns the Amber LED for a slot on, off or blink
  192. */
  193. static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
  194. {
  195. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  196. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  197. hotplug_slot->info->attention_status = status;
  198. slot->hpc_ops->set_attention_status(slot, status);
  199. return 0;
  200. }
  201. static int enable_slot (struct hotplug_slot *hotplug_slot)
  202. {
  203. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  204. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  205. return shpchp_enable_slot(slot);
  206. }
  207. static int disable_slot (struct hotplug_slot *hotplug_slot)
  208. {
  209. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  210. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  211. return shpchp_disable_slot(slot);
  212. }
  213. static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
  214. {
  215. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  216. int retval;
  217. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  218. retval = slot->hpc_ops->get_power_status(slot, value);
  219. if (retval < 0)
  220. *value = hotplug_slot->info->power_status;
  221. return 0;
  222. }
  223. static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
  224. {
  225. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  226. int retval;
  227. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  228. retval = slot->hpc_ops->get_attention_status(slot, value);
  229. if (retval < 0)
  230. *value = hotplug_slot->info->attention_status;
  231. return 0;
  232. }
  233. static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
  234. {
  235. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  236. int retval;
  237. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  238. retval = slot->hpc_ops->get_latch_status(slot, value);
  239. if (retval < 0)
  240. *value = hotplug_slot->info->latch_status;
  241. return 0;
  242. }
  243. static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
  244. {
  245. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  246. int retval;
  247. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  248. retval = slot->hpc_ops->get_adapter_status(slot, value);
  249. if (retval < 0)
  250. *value = hotplug_slot->info->adapter_status;
  251. return 0;
  252. }
  253. static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
  254. {
  255. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  256. int retval;
  257. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  258. retval = slot->hpc_ops->get_max_bus_speed(slot, value);
  259. if (retval < 0)
  260. *value = PCI_SPEED_UNKNOWN;
  261. return 0;
  262. }
  263. static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
  264. {
  265. struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
  266. int retval;
  267. dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
  268. retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
  269. if (retval < 0)
  270. *value = PCI_SPEED_UNKNOWN;
  271. return 0;
  272. }
  273. static int is_shpc_capable(struct pci_dev *dev)
  274. {
  275. if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device ==
  276. PCI_DEVICE_ID_AMD_GOLAM_7450))
  277. return 1;
  278. if (pci_find_capability(dev, PCI_CAP_ID_SHPC))
  279. return 1;
  280. return 0;
  281. }
  282. static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  283. {
  284. int rc;
  285. struct controller *ctrl;
  286. struct slot *t_slot;
  287. int first_device_num; /* first PCI device number supported by this SHPC */
  288. int num_ctlr_slots; /* number of slots supported by this SHPC */
  289. if (!is_shpc_capable(pdev))
  290. return -ENODEV;
  291. ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
  292. if (!ctrl) {
  293. err("%s : out of memory\n", __FUNCTION__);
  294. goto err_out_none;
  295. }
  296. memset(ctrl, 0, sizeof(struct controller));
  297. rc = shpc_init(ctrl, pdev);
  298. if (rc) {
  299. dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME);
  300. goto err_out_free_ctrl;
  301. }
  302. ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
  303. pci_set_drvdata(pdev, ctrl);
  304. ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);
  305. if (!ctrl->pci_bus) {
  306. err("out of memory\n");
  307. rc = -ENOMEM;
  308. goto err_out_unmap_mmio_region;
  309. }
  310. memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
  311. ctrl->bus = pdev->bus->number;
  312. ctrl->slot_bus = pdev->subordinate->number;
  313. ctrl->device = PCI_SLOT(pdev->devfn);
  314. ctrl->function = PCI_FUNC(pdev->devfn);
  315. dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
  316. /*
  317. * Save configuration headers for this and subordinate PCI buses
  318. */
  319. rc = get_ctlr_slot_config(ctrl);
  320. if (rc) {
  321. err(msg_initialization_err, rc);
  322. goto err_out_free_ctrl_bus;
  323. }
  324. first_device_num = ctrl->slot_device_offset;
  325. num_ctlr_slots = ctrl->num_slots;
  326. ctrl->add_support = 1;
  327. /* Setup the slot information structures */
  328. rc = init_slots(ctrl);
  329. if (rc) {
  330. err(msg_initialization_err, 6);
  331. goto err_out_free_ctrl_slot;
  332. }
  333. /* Now hpc_functions (slot->hpc_ops->functions) are ready */
  334. t_slot = shpchp_find_slot(ctrl, first_device_num);
  335. /* Check for operation bus speed */
  336. rc = t_slot->hpc_ops->get_cur_bus_speed(t_slot, &ctrl->speed);
  337. dbg("%s: t_slot->hp_slot %x\n", __FUNCTION__,t_slot->hp_slot);
  338. if (rc || ctrl->speed == PCI_SPEED_UNKNOWN) {
  339. err(SHPC_MODULE_NAME ": Can't get current bus speed. Set to 33MHz PCI.\n");
  340. ctrl->speed = PCI_SPEED_33MHz;
  341. }
  342. /* Finish setting up the hot plug ctrl device */
  343. ctrl->next_event = 0;
  344. if (!shpchp_ctrl_list) {
  345. shpchp_ctrl_list = ctrl;
  346. ctrl->next = NULL;
  347. } else {
  348. ctrl->next = shpchp_ctrl_list;
  349. shpchp_ctrl_list = ctrl;
  350. }
  351. shpchp_create_ctrl_files(ctrl);
  352. return 0;
  353. err_out_free_ctrl_slot:
  354. cleanup_slots(ctrl);
  355. err_out_free_ctrl_bus:
  356. kfree(ctrl->pci_bus);
  357. err_out_unmap_mmio_region:
  358. ctrl->hpc_ops->release_ctlr(ctrl);
  359. err_out_free_ctrl:
  360. kfree(ctrl);
  361. err_out_none:
  362. return -ENODEV;
  363. }
  364. static int shpc_start_thread(void)
  365. {
  366. int retval = 0;
  367. dbg("Initialize + Start the notification/polling mechanism \n");
  368. retval = shpchp_event_start_thread();
  369. if (retval) {
  370. dbg("shpchp_event_start_thread() failed\n");
  371. return retval;
  372. }
  373. return retval;
  374. }
  375. static void __exit unload_shpchpd(void)
  376. {
  377. struct controller *ctrl;
  378. struct controller *tctrl;
  379. ctrl = shpchp_ctrl_list;
  380. while (ctrl) {
  381. shpchp_remove_ctrl_files(ctrl);
  382. cleanup_slots(ctrl);
  383. kfree (ctrl->pci_bus);
  384. ctrl->hpc_ops->release_ctlr(ctrl);
  385. tctrl = ctrl;
  386. ctrl = ctrl->next;
  387. kfree(tctrl);
  388. }
  389. /* Stop the notification mechanism */
  390. shpchp_event_stop_thread();
  391. }
  392. static struct pci_device_id shpcd_pci_tbl[] = {
  393. {
  394. .class = ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00),
  395. .class_mask = ~0,
  396. .vendor = PCI_ANY_ID,
  397. .device = PCI_ANY_ID,
  398. .subvendor = PCI_ANY_ID,
  399. .subdevice = PCI_ANY_ID,
  400. },
  401. { /* end: all zeroes */ }
  402. };
  403. MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl);
  404. static struct pci_driver shpc_driver = {
  405. .name = SHPC_MODULE_NAME,
  406. .id_table = shpcd_pci_tbl,
  407. .probe = shpc_probe,
  408. /* remove: shpc_remove_one, */
  409. };
  410. static int __init shpcd_init(void)
  411. {
  412. int retval = 0;
  413. #ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
  414. shpchp_poll_mode = 1;
  415. #endif
  416. retval = shpc_start_thread();
  417. if (retval)
  418. goto error_hpc_init;
  419. retval = pci_register_driver(&shpc_driver);
  420. dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
  421. info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
  422. error_hpc_init:
  423. if (retval) {
  424. shpchp_event_stop_thread();
  425. }
  426. return retval;
  427. }
  428. static void __exit shpcd_cleanup(void)
  429. {
  430. dbg("unload_shpchpd()\n");
  431. unload_shpchpd();
  432. pci_unregister_driver(&shpc_driver);
  433. info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
  434. }
  435. module_init(shpcd_init);
  436. module_exit(shpcd_cleanup);