vga_switcheroo.c 14 KB

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