aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/vga
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-04-26 06:55:59 -0400
committerTakashi Iwai <tiwai@suse.de>2012-05-13 05:21:56 -0400
commit79721e0a91b5e8f662f12eeb50ea205c761e6bf8 (patch)
tree5ab91e6e5342b7b844ace65cda62db364b17c2fe /drivers/gpu/vga
parent218c872bf8285af7aaa50f1f83312020e05451bf (diff)
vga_switcheroo: Refactor using linked list
Refactor the code base a bit for the further work to adapt more clients. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'drivers/gpu/vga')
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c209
1 files changed, 110 insertions, 99 deletions
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 9d830286f883..da29da6aadac 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -39,6 +39,7 @@ struct vga_switcheroo_client {
39 bool (*can_switch)(struct pci_dev *pdev); 39 bool (*can_switch)(struct pci_dev *pdev);
40 int id; 40 int id;
41 bool active; 41 bool active;
42 struct list_head list;
42}; 43};
43 44
44static DEFINE_MUTEX(vgasr_mutex); 45static DEFINE_MUTEX(vgasr_mutex);
@@ -53,7 +54,7 @@ struct vgasr_priv {
53 struct dentry *switch_file; 54 struct dentry *switch_file;
54 55
55 int registered_clients; 56 int registered_clients;
56 struct vga_switcheroo_client clients[VGA_SWITCHEROO_MAX_CLIENTS]; 57 struct list_head clients;
57 58
58 struct vga_switcheroo_handler *handler; 59 struct vga_switcheroo_handler *handler;
59}; 60};
@@ -62,7 +63,9 @@ static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv);
62static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv); 63static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
63 64
64/* only one switcheroo per system */ 65/* only one switcheroo per system */
65static struct vgasr_priv vgasr_priv; 66static struct vgasr_priv vgasr_priv = {
67 .clients = LIST_HEAD_INIT(vgasr_priv.clients),
68};
66 69
67int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) 70int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
68{ 71{
@@ -88,17 +91,18 @@ EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
88 91
89static void vga_switcheroo_enable(void) 92static void vga_switcheroo_enable(void)
90{ 93{
91 int i;
92 int ret; 94 int ret;
95 struct vga_switcheroo_client *client;
96
93 /* call the handler to init */ 97 /* call the handler to init */
94 vgasr_priv.handler->init(); 98 vgasr_priv.handler->init();
95 99
96 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 100 list_for_each_entry(client, &vgasr_priv.clients, list) {
97 ret = vgasr_priv.handler->get_client_id(vgasr_priv.clients[i].pdev); 101 ret = vgasr_priv.handler->get_client_id(client->pdev);
98 if (ret < 0) 102 if (ret < 0)
99 return; 103 return;
100 104
101 vgasr_priv.clients[i].id = ret; 105 client->id = ret;
102 } 106 }
103 vga_switcheroo_debugfs_init(&vgasr_priv); 107 vga_switcheroo_debugfs_init(&vgasr_priv);
104 vgasr_priv.active = true; 108 vgasr_priv.active = true;
@@ -109,28 +113,27 @@ int vga_switcheroo_register_client(struct pci_dev *pdev,
109 void (*reprobe)(struct pci_dev *pdev), 113 void (*reprobe)(struct pci_dev *pdev),
110 bool (*can_switch)(struct pci_dev *pdev)) 114 bool (*can_switch)(struct pci_dev *pdev))
111{ 115{
112 int index; 116 struct vga_switcheroo_client *client;
113 117
114 mutex_lock(&vgasr_mutex); 118 client = kzalloc(sizeof(*client), GFP_KERNEL);
115 /* don't do IGD vs DIS here */ 119 if (!client)
116 if (vgasr_priv.registered_clients & 1) 120 return -ENOMEM;
117 index = 1; 121
118 else 122 client->pwr_state = VGA_SWITCHEROO_ON;
119 index = 0; 123 client->pdev = pdev;
120 124 client->set_gpu_state = set_gpu_state;
121 vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON; 125 client->reprobe = reprobe;
122 vgasr_priv.clients[index].pdev = pdev; 126 client->can_switch = can_switch;
123 vgasr_priv.clients[index].set_gpu_state = set_gpu_state; 127 client->id = -1;
124 vgasr_priv.clients[index].reprobe = reprobe;
125 vgasr_priv.clients[index].can_switch = can_switch;
126 vgasr_priv.clients[index].id = -1;
127 if (pdev == vga_default_device()) 128 if (pdev == vga_default_device())
128 vgasr_priv.clients[index].active = true; 129 client->active = true;
129 130
130 vgasr_priv.registered_clients |= (1 << index); 131 mutex_lock(&vgasr_mutex);
132 list_add_tail(&client->list, &vgasr_priv.clients);
133 vgasr_priv.registered_clients++;
131 134
132 /* if we get two clients + handler */ 135 /* if we get two clients + handler */
133 if (vgasr_priv.registered_clients == 0x3 && vgasr_priv.handler) { 136 if (vgasr_priv.registered_clients == 2 && vgasr_priv.handler) {
134 printk(KERN_INFO "vga_switcheroo: enabled\n"); 137 printk(KERN_INFO "vga_switcheroo: enabled\n");
135 vga_switcheroo_enable(); 138 vga_switcheroo_enable();
136 } 139 }
@@ -139,18 +142,47 @@ int vga_switcheroo_register_client(struct pci_dev *pdev,
139} 142}
140EXPORT_SYMBOL(vga_switcheroo_register_client); 143EXPORT_SYMBOL(vga_switcheroo_register_client);
141 144
145static struct vga_switcheroo_client *
146find_client_from_pci(struct list_head *head, struct pci_dev *pdev)
147{
148 struct vga_switcheroo_client *client;
149 list_for_each_entry(client, head, list)
150 if (client->pdev == pdev)
151 return client;
152 return NULL;
153}
154
155static struct vga_switcheroo_client *
156find_client_from_id(struct list_head *head, int client_id)
157{
158 struct vga_switcheroo_client *client;
159 list_for_each_entry(client, head, list)
160 if (client->id == client_id)
161 return client;
162 return NULL;
163}
164
165static struct vga_switcheroo_client *
166find_active_client(struct list_head *head)
167{
168 struct vga_switcheroo_client *client;
169 list_for_each_entry(client, head, list)
170 if (client->active == true)
171 return client;
172 return NULL;
173}
174
142void vga_switcheroo_unregister_client(struct pci_dev *pdev) 175void vga_switcheroo_unregister_client(struct pci_dev *pdev)
143{ 176{
144 int i; 177 struct vga_switcheroo_client *client;
145 178
146 mutex_lock(&vgasr_mutex); 179 mutex_lock(&vgasr_mutex);
147 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 180 client = find_client_from_pci(&vgasr_priv.clients, pdev);
148 if (vgasr_priv.clients[i].pdev == pdev) { 181 if (client) {
149 vgasr_priv.registered_clients &= ~(1 << i); 182 list_del(&client->list);
150 break; 183 kfree(client);
151 } 184 vgasr_priv.registered_clients--;
152 } 185 }
153
154 printk(KERN_INFO "vga_switcheroo: disabled\n"); 186 printk(KERN_INFO "vga_switcheroo: disabled\n");
155 vga_switcheroo_debugfs_fini(&vgasr_priv); 187 vga_switcheroo_debugfs_fini(&vgasr_priv);
156 vgasr_priv.active = false; 188 vgasr_priv.active = false;
@@ -161,29 +193,28 @@ EXPORT_SYMBOL(vga_switcheroo_unregister_client);
161void vga_switcheroo_client_fb_set(struct pci_dev *pdev, 193void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
162 struct fb_info *info) 194 struct fb_info *info)
163{ 195{
164 int i; 196 struct vga_switcheroo_client *client;
165 197
166 mutex_lock(&vgasr_mutex); 198 mutex_lock(&vgasr_mutex);
167 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 199 client = find_client_from_pci(&vgasr_priv.clients, pdev);
168 if (vgasr_priv.clients[i].pdev == pdev) { 200 if (client)
169 vgasr_priv.clients[i].fb_info = info; 201 client->fb_info = info;
170 break;
171 }
172 }
173 mutex_unlock(&vgasr_mutex); 202 mutex_unlock(&vgasr_mutex);
174} 203}
175EXPORT_SYMBOL(vga_switcheroo_client_fb_set); 204EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
176 205
177static int vga_switcheroo_show(struct seq_file *m, void *v) 206static int vga_switcheroo_show(struct seq_file *m, void *v)
178{ 207{
179 int i; 208 struct vga_switcheroo_client *client;
209 int i = 0;
180 mutex_lock(&vgasr_mutex); 210 mutex_lock(&vgasr_mutex);
181 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 211 list_for_each_entry(client, &vgasr_priv.clients, list) {
182 seq_printf(m, "%d:%s:%c:%s:%s\n", i, 212 seq_printf(m, "%d:%s:%c:%s:%s\n", i,
183 vgasr_priv.clients[i].id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD", 213 client->id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD",
184 vgasr_priv.clients[i].active ? '+' : ' ', 214 client->active ? '+' : ' ',
185 vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off", 215 client->pwr_state ? "Pwr" : "Off",
186 pci_name(vgasr_priv.clients[i].pdev)); 216 pci_name(client->pdev));
217 i++;
187 } 218 }
188 mutex_unlock(&vgasr_mutex); 219 mutex_unlock(&vgasr_mutex);
189 return 0; 220 return 0;
@@ -217,15 +248,9 @@ static int vga_switchoff(struct vga_switcheroo_client *client)
217/* stage one happens before delay */ 248/* stage one happens before delay */
218static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) 249static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
219{ 250{
220 int i; 251 struct vga_switcheroo_client *active;
221 struct vga_switcheroo_client *active = NULL;
222 252
223 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 253 active = find_active_client(&vgasr_priv.clients);
224 if (vgasr_priv.clients[i].active == true) {
225 active = &vgasr_priv.clients[i];
226 break;
227 }
228 }
229 if (!active) 254 if (!active)
230 return 0; 255 return 0;
231 256
@@ -241,15 +266,9 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
241static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) 266static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
242{ 267{
243 int ret; 268 int ret;
244 int i; 269 struct vga_switcheroo_client *active;
245 struct vga_switcheroo_client *active = NULL;
246 270
247 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 271 active = find_active_client(&vgasr_priv.clients);
248 if (vgasr_priv.clients[i].active == true) {
249 active = &vgasr_priv.clients[i];
250 break;
251 }
252 }
253 if (!active) 272 if (!active)
254 return 0; 273 return 0;
255 274
@@ -275,13 +294,26 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
275 return 0; 294 return 0;
276} 295}
277 296
297static bool check_can_switch(void)
298{
299 struct vga_switcheroo_client *client;
300
301 list_for_each_entry(client, &vgasr_priv.clients, list) {
302 if (!client->can_switch(client->pdev)) {
303 printk(KERN_ERR "vga_switcheroo: client %x refused switch\n", client->id);
304 return false;
305 }
306 }
307 return true;
308}
309
278static ssize_t 310static ssize_t
279vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, 311vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
280 size_t cnt, loff_t *ppos) 312 size_t cnt, loff_t *ppos)
281{ 313{
282 char usercmd[64]; 314 char usercmd[64];
283 const char *pdev_name; 315 const char *pdev_name;
284 int i, ret; 316 int ret;
285 bool delay = false, can_switch; 317 bool delay = false, can_switch;
286 bool just_mux = false; 318 bool just_mux = false;
287 int client_id = -1; 319 int client_id = -1;
@@ -302,21 +334,21 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
302 334
303 /* pwr off the device not in use */ 335 /* pwr off the device not in use */
304 if (strncmp(usercmd, "OFF", 3) == 0) { 336 if (strncmp(usercmd, "OFF", 3) == 0) {
305 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 337 list_for_each_entry(client, &vgasr_priv.clients, list) {
306 if (vgasr_priv.clients[i].active) 338 if (client->active)
307 continue; 339 continue;
308 if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_ON) 340 if (client->pwr_state == VGA_SWITCHEROO_ON)
309 vga_switchoff(&vgasr_priv.clients[i]); 341 vga_switchoff(client);
310 } 342 }
311 goto out; 343 goto out;
312 } 344 }
313 /* pwr on the device not in use */ 345 /* pwr on the device not in use */
314 if (strncmp(usercmd, "ON", 2) == 0) { 346 if (strncmp(usercmd, "ON", 2) == 0) {
315 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 347 list_for_each_entry(client, &vgasr_priv.clients, list) {
316 if (vgasr_priv.clients[i].active) 348 if (client->active)
317 continue; 349 continue;
318 if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_OFF) 350 if (client->pwr_state == VGA_SWITCHEROO_OFF)
319 vga_switchon(&vgasr_priv.clients[i]); 351 vga_switchon(client);
320 } 352 }
321 goto out; 353 goto out;
322 } 354 }
@@ -349,13 +381,9 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
349 381
350 if (client_id == -1) 382 if (client_id == -1)
351 goto out; 383 goto out;
352 384 client = find_client_from_id(&vgasr_priv.clients, client_id);
353 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 385 if (!client)
354 if (vgasr_priv.clients[i].id == client_id) { 386 goto out;
355 client = &vgasr_priv.clients[i];
356 break;
357 }
358 }
359 387
360 vgasr_priv.delayed_switch_active = false; 388 vgasr_priv.delayed_switch_active = false;
361 389
@@ -364,23 +392,16 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
364 goto out; 392 goto out;
365 } 393 }
366 394
367 if (client->active == true) 395 if (client->active)
368 goto out; 396 goto out;
369 397
370 /* okay we want a switch - test if devices are willing to switch */ 398 /* okay we want a switch - test if devices are willing to switch */
371 can_switch = true; 399 can_switch = check_can_switch();
372 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
373 can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev);
374 if (can_switch == false) {
375 printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i);
376 break;
377 }
378 }
379 400
380 if (can_switch == false && delay == false) 401 if (can_switch == false && delay == false)
381 goto out; 402 goto out;
382 403
383 if (can_switch == true) { 404 if (can_switch) {
384 pdev_name = pci_name(client->pdev); 405 pdev_name = pci_name(client->pdev);
385 ret = vga_switchto_stage1(client); 406 ret = vga_switchto_stage1(client);
386 if (ret) 407 if (ret)
@@ -452,10 +473,8 @@ fail:
452 473
453int vga_switcheroo_process_delayed_switch(void) 474int vga_switcheroo_process_delayed_switch(void)
454{ 475{
455 struct vga_switcheroo_client *client = NULL; 476 struct vga_switcheroo_client *client;
456 const char *pdev_name; 477 const char *pdev_name;
457 bool can_switch = true;
458 int i;
459 int ret; 478 int ret;
460 int err = -EINVAL; 479 int err = -EINVAL;
461 480
@@ -465,17 +484,9 @@ int vga_switcheroo_process_delayed_switch(void)
465 484
466 printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id); 485 printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id);
467 486
468 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { 487 client = find_client_from_id(&vgasr_priv.clients,
469 if (vgasr_priv.clients[i].id == vgasr_priv.delayed_client_id) 488 vgasr_priv.delayed_client_id);
470 client = &vgasr_priv.clients[i]; 489 if (!client || !check_can_switch())
471 can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev);
472 if (can_switch == false) {
473 printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i);
474 break;
475 }
476 }
477
478 if (can_switch == false || client == NULL)
479 goto err; 490 goto err;
480 491
481 pdev_name = pci_name(client->pdev); 492 pdev_name = pci_name(client->pdev);