vga_switcheroo.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*
  2. * Copyright (c) 2010 Red Hat Inc.
  3. * Author : Dave Airlie <airlied@redhat.com>
  4. *
  5. *
  6. * Licensed under GPLv2
  7. *
  8. * vga_switcheroo.c - Support for laptop with dual GPU using one set of outputs
  9. Switcher interface - methods require for ATPX and DCM
  10. - switchto - this throws the output MUX switch
  11. - discrete_set_power - sets the power state for the discrete card
  12. GPU driver interface
  13. - set_gpu_state - this should do the equiv of s/r for the card
  14. - this should *not* set the discrete power state
  15. - switch_check - check if the device is in a position to switch now
  16. */
  17. #include <linux/module.h>
  18. #include <linux/dmi.h>
  19. #include <linux/seq_file.h>
  20. #include <linux/uaccess.h>
  21. #include <linux/fs.h>
  22. #include <linux/debugfs.h>
  23. #include <linux/fb.h>
  24. #include <linux/pci.h>
  25. #include <linux/vga_switcheroo.h>
  26. #include <linux/vgaarb.h>
  27. struct vga_switcheroo_client {
  28. struct pci_dev *pdev;
  29. struct fb_info *fb_info;
  30. int pwr_state;
  31. void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state);
  32. void (*reprobe)(struct pci_dev *pdev);
  33. bool (*can_switch)(struct pci_dev *pdev);
  34. int id;
  35. bool active;
  36. struct list_head list;
  37. };
  38. static DEFINE_MUTEX(vgasr_mutex);
  39. struct vgasr_priv {
  40. bool active;
  41. bool delayed_switch_active;
  42. enum vga_switcheroo_client_id delayed_client_id;
  43. struct dentry *debugfs_root;
  44. struct dentry *switch_file;
  45. int registered_clients;
  46. struct list_head clients;
  47. struct vga_switcheroo_handler *handler;
  48. };
  49. static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv);
  50. static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
  51. /* only one switcheroo per system */
  52. static struct vgasr_priv vgasr_priv = {
  53. .clients = LIST_HEAD_INIT(vgasr_priv.clients),
  54. };
  55. int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
  56. {
  57. mutex_lock(&vgasr_mutex);
  58. if (vgasr_priv.handler) {
  59. mutex_unlock(&vgasr_mutex);
  60. return -EINVAL;
  61. }
  62. vgasr_priv.handler = handler;
  63. mutex_unlock(&vgasr_mutex);
  64. return 0;
  65. }
  66. EXPORT_SYMBOL(vga_switcheroo_register_handler);
  67. void vga_switcheroo_unregister_handler(void)
  68. {
  69. mutex_lock(&vgasr_mutex);
  70. vgasr_priv.handler = NULL;
  71. mutex_unlock(&vgasr_mutex);
  72. }
  73. EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
  74. static void vga_switcheroo_enable(void)
  75. {
  76. int ret;
  77. struct vga_switcheroo_client *client;
  78. /* call the handler to init */
  79. vgasr_priv.handler->init();
  80. list_for_each_entry(client, &vgasr_priv.clients, list) {
  81. ret = vgasr_priv.handler->get_client_id(client->pdev);
  82. if (ret < 0)
  83. return;
  84. client->id = ret;
  85. }
  86. vga_switcheroo_debugfs_init(&vgasr_priv);
  87. vgasr_priv.active = true;
  88. }
  89. int vga_switcheroo_register_client(struct pci_dev *pdev,
  90. void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state),
  91. void (*reprobe)(struct pci_dev *pdev),
  92. bool (*can_switch)(struct pci_dev *pdev))
  93. {
  94. struct vga_switcheroo_client *client;
  95. client = kzalloc(sizeof(*client), GFP_KERNEL);
  96. if (!client)
  97. return -ENOMEM;
  98. client->pwr_state = VGA_SWITCHEROO_ON;
  99. client->pdev = pdev;
  100. client->set_gpu_state = set_gpu_state;
  101. client->reprobe = reprobe;
  102. client->can_switch = can_switch;
  103. client->id = -1;
  104. if (pdev == vga_default_device())
  105. client->active = true;
  106. mutex_lock(&vgasr_mutex);
  107. list_add_tail(&client->list, &vgasr_priv.clients);
  108. vgasr_priv.registered_clients++;
  109. /* if we get two clients + handler */
  110. if (vgasr_priv.registered_clients == 2 && vgasr_priv.handler) {
  111. printk(KERN_INFO "vga_switcheroo: enabled\n");
  112. vga_switcheroo_enable();
  113. }
  114. mutex_unlock(&vgasr_mutex);
  115. return 0;
  116. }
  117. EXPORT_SYMBOL(vga_switcheroo_register_client);
  118. static struct vga_switcheroo_client *
  119. find_client_from_pci(struct list_head *head, struct pci_dev *pdev)
  120. {
  121. struct vga_switcheroo_client *client;
  122. list_for_each_entry(client, head, list)
  123. if (client->pdev == pdev)
  124. return client;
  125. return NULL;
  126. }
  127. static struct vga_switcheroo_client *
  128. find_client_from_id(struct list_head *head, int client_id)
  129. {
  130. struct vga_switcheroo_client *client;
  131. list_for_each_entry(client, head, list)
  132. if (client->id == client_id)
  133. return client;
  134. return NULL;
  135. }
  136. static struct vga_switcheroo_client *
  137. find_active_client(struct list_head *head)
  138. {
  139. struct vga_switcheroo_client *client;
  140. list_for_each_entry(client, head, list)
  141. if (client->active == true)
  142. return client;
  143. return NULL;
  144. }
  145. void vga_switcheroo_unregister_client(struct pci_dev *pdev)
  146. {
  147. struct vga_switcheroo_client *client;
  148. mutex_lock(&vgasr_mutex);
  149. client = find_client_from_pci(&vgasr_priv.clients, pdev);
  150. if (client) {
  151. list_del(&client->list);
  152. kfree(client);
  153. vgasr_priv.registered_clients--;
  154. }
  155. printk(KERN_INFO "vga_switcheroo: disabled\n");
  156. vga_switcheroo_debugfs_fini(&vgasr_priv);
  157. vgasr_priv.active = false;
  158. mutex_unlock(&vgasr_mutex);
  159. }
  160. EXPORT_SYMBOL(vga_switcheroo_unregister_client);
  161. void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
  162. struct fb_info *info)
  163. {
  164. struct vga_switcheroo_client *client;
  165. mutex_lock(&vgasr_mutex);
  166. client = find_client_from_pci(&vgasr_priv.clients, pdev);
  167. if (client)
  168. client->fb_info = info;
  169. mutex_unlock(&vgasr_mutex);
  170. }
  171. EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
  172. static int vga_switcheroo_show(struct seq_file *m, void *v)
  173. {
  174. struct vga_switcheroo_client *client;
  175. int i = 0;
  176. mutex_lock(&vgasr_mutex);
  177. list_for_each_entry(client, &vgasr_priv.clients, list) {
  178. seq_printf(m, "%d:%s:%c:%s:%s\n", i,
  179. client->id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD",
  180. client->active ? '+' : ' ',
  181. client->pwr_state ? "Pwr" : "Off",
  182. pci_name(client->pdev));
  183. i++;
  184. }
  185. mutex_unlock(&vgasr_mutex);
  186. return 0;
  187. }
  188. static int vga_switcheroo_debugfs_open(struct inode *inode, struct file *file)
  189. {
  190. return single_open(file, vga_switcheroo_show, NULL);
  191. }
  192. static int vga_switchon(struct vga_switcheroo_client *client)
  193. {
  194. if (vgasr_priv.handler->power_state)
  195. vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON);
  196. /* call the driver callback to turn on device */
  197. client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON);
  198. client->pwr_state = VGA_SWITCHEROO_ON;
  199. return 0;
  200. }
  201. static int vga_switchoff(struct vga_switcheroo_client *client)
  202. {
  203. /* call the driver callback to turn off device */
  204. client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF);
  205. if (vgasr_priv.handler->power_state)
  206. vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF);
  207. client->pwr_state = VGA_SWITCHEROO_OFF;
  208. return 0;
  209. }
  210. /* stage one happens before delay */
  211. static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
  212. {
  213. struct vga_switcheroo_client *active;
  214. active = find_active_client(&vgasr_priv.clients);
  215. if (!active)
  216. return 0;
  217. if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
  218. vga_switchon(new_client);
  219. vga_set_default_device(new_client->pdev);
  220. return 0;
  221. }
  222. /* post delay */
  223. static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
  224. {
  225. int ret;
  226. struct vga_switcheroo_client *active;
  227. active = find_active_client(&vgasr_priv.clients);
  228. if (!active)
  229. return 0;
  230. active->active = false;
  231. if (new_client->fb_info) {
  232. struct fb_event event;
  233. event.info = new_client->fb_info;
  234. fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event);
  235. }
  236. ret = vgasr_priv.handler->switchto(new_client->id);
  237. if (ret)
  238. return ret;
  239. if (new_client->reprobe)
  240. new_client->reprobe(new_client->pdev);
  241. if (active->pwr_state == VGA_SWITCHEROO_ON)
  242. vga_switchoff(active);
  243. new_client->active = true;
  244. return 0;
  245. }
  246. static bool check_can_switch(void)
  247. {
  248. struct vga_switcheroo_client *client;
  249. list_for_each_entry(client, &vgasr_priv.clients, list) {
  250. if (!client->can_switch(client->pdev)) {
  251. printk(KERN_ERR "vga_switcheroo: client %x refused switch\n", client->id);
  252. return false;
  253. }
  254. }
  255. return true;
  256. }
  257. static ssize_t
  258. vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
  259. size_t cnt, loff_t *ppos)
  260. {
  261. char usercmd[64];
  262. const char *pdev_name;
  263. int ret;
  264. bool delay = false, can_switch;
  265. bool just_mux = false;
  266. int client_id = -1;
  267. struct vga_switcheroo_client *client = NULL;
  268. if (cnt > 63)
  269. cnt = 63;
  270. if (copy_from_user(usercmd, ubuf, cnt))
  271. return -EFAULT;
  272. mutex_lock(&vgasr_mutex);
  273. if (!vgasr_priv.active) {
  274. cnt = -EINVAL;
  275. goto out;
  276. }
  277. /* pwr off the device not in use */
  278. if (strncmp(usercmd, "OFF", 3) == 0) {
  279. list_for_each_entry(client, &vgasr_priv.clients, list) {
  280. if (client->active)
  281. continue;
  282. if (client->pwr_state == VGA_SWITCHEROO_ON)
  283. vga_switchoff(client);
  284. }
  285. goto out;
  286. }
  287. /* pwr on the device not in use */
  288. if (strncmp(usercmd, "ON", 2) == 0) {
  289. list_for_each_entry(client, &vgasr_priv.clients, list) {
  290. if (client->active)
  291. continue;
  292. if (client->pwr_state == VGA_SWITCHEROO_OFF)
  293. vga_switchon(client);
  294. }
  295. goto out;
  296. }
  297. /* request a delayed switch - test can we switch now */
  298. if (strncmp(usercmd, "DIGD", 4) == 0) {
  299. client_id = VGA_SWITCHEROO_IGD;
  300. delay = true;
  301. }
  302. if (strncmp(usercmd, "DDIS", 4) == 0) {
  303. client_id = VGA_SWITCHEROO_DIS;
  304. delay = true;
  305. }
  306. if (strncmp(usercmd, "IGD", 3) == 0)
  307. client_id = VGA_SWITCHEROO_IGD;
  308. if (strncmp(usercmd, "DIS", 3) == 0)
  309. client_id = VGA_SWITCHEROO_DIS;
  310. if (strncmp(usercmd, "MIGD", 4) == 0) {
  311. just_mux = true;
  312. client_id = VGA_SWITCHEROO_IGD;
  313. }
  314. if (strncmp(usercmd, "MDIS", 4) == 0) {
  315. just_mux = true;
  316. client_id = VGA_SWITCHEROO_DIS;
  317. }
  318. if (client_id == -1)
  319. goto out;
  320. client = find_client_from_id(&vgasr_priv.clients, client_id);
  321. if (!client)
  322. goto out;
  323. vgasr_priv.delayed_switch_active = false;
  324. if (just_mux) {
  325. ret = vgasr_priv.handler->switchto(client_id);
  326. goto out;
  327. }
  328. if (client->active)
  329. goto out;
  330. /* okay we want a switch - test if devices are willing to switch */
  331. can_switch = check_can_switch();
  332. if (can_switch == false && delay == false)
  333. goto out;
  334. if (can_switch) {
  335. pdev_name = pci_name(client->pdev);
  336. ret = vga_switchto_stage1(client);
  337. if (ret)
  338. printk(KERN_ERR "vga_switcheroo: switching failed stage 1 %d\n", ret);
  339. ret = vga_switchto_stage2(client);
  340. if (ret)
  341. printk(KERN_ERR "vga_switcheroo: switching failed stage 2 %d\n", ret);
  342. } else {
  343. printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id);
  344. vgasr_priv.delayed_switch_active = true;
  345. vgasr_priv.delayed_client_id = client_id;
  346. ret = vga_switchto_stage1(client);
  347. if (ret)
  348. printk(KERN_ERR "vga_switcheroo: delayed switching stage 1 failed %d\n", ret);
  349. }
  350. out:
  351. mutex_unlock(&vgasr_mutex);
  352. return cnt;
  353. }
  354. static const struct file_operations vga_switcheroo_debugfs_fops = {
  355. .owner = THIS_MODULE,
  356. .open = vga_switcheroo_debugfs_open,
  357. .write = vga_switcheroo_debugfs_write,
  358. .read = seq_read,
  359. .llseek = seq_lseek,
  360. .release = single_release,
  361. };
  362. static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv)
  363. {
  364. if (priv->switch_file) {
  365. debugfs_remove(priv->switch_file);
  366. priv->switch_file = NULL;
  367. }
  368. if (priv->debugfs_root) {
  369. debugfs_remove(priv->debugfs_root);
  370. priv->debugfs_root = NULL;
  371. }
  372. }
  373. static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv)
  374. {
  375. /* already initialised */
  376. if (priv->debugfs_root)
  377. return 0;
  378. priv->debugfs_root = debugfs_create_dir("vgaswitcheroo", NULL);
  379. if (!priv->debugfs_root) {
  380. printk(KERN_ERR "vga_switcheroo: Cannot create /sys/kernel/debug/vgaswitcheroo\n");
  381. goto fail;
  382. }
  383. priv->switch_file = debugfs_create_file("switch", 0644,
  384. priv->debugfs_root, NULL, &vga_switcheroo_debugfs_fops);
  385. if (!priv->switch_file) {
  386. printk(KERN_ERR "vga_switcheroo: cannot create /sys/kernel/debug/vgaswitcheroo/switch\n");
  387. goto fail;
  388. }
  389. return 0;
  390. fail:
  391. vga_switcheroo_debugfs_fini(priv);
  392. return -1;
  393. }
  394. int vga_switcheroo_process_delayed_switch(void)
  395. {
  396. struct vga_switcheroo_client *client;
  397. const char *pdev_name;
  398. int ret;
  399. int err = -EINVAL;
  400. mutex_lock(&vgasr_mutex);
  401. if (!vgasr_priv.delayed_switch_active)
  402. goto err;
  403. printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id);
  404. client = find_client_from_id(&vgasr_priv.clients,
  405. vgasr_priv.delayed_client_id);
  406. if (!client || !check_can_switch())
  407. goto err;
  408. pdev_name = pci_name(client->pdev);
  409. ret = vga_switchto_stage2(client);
  410. if (ret)
  411. printk(KERN_ERR "vga_switcheroo: delayed switching failed stage 2 %d\n", ret);
  412. vgasr_priv.delayed_switch_active = false;
  413. err = 0;
  414. err:
  415. mutex_unlock(&vgasr_mutex);
  416. return err;
  417. }
  418. EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);