diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
|---|---|---|
| committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
| commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
| tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/gpu/vga | |
| parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
| parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) | |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/gpu/vga')
| -rw-r--r-- | drivers/gpu/vga/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/gpu/vga/vga_switcheroo.c | 90 | ||||
| -rw-r--r-- | drivers/gpu/vga/vgaarb.c | 120 |
3 files changed, 169 insertions, 43 deletions
diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig index 8d0e31a22027..96c83a9a76bb 100644 --- a/drivers/gpu/vga/Kconfig +++ b/drivers/gpu/vga/Kconfig | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | config VGA_ARB | 1 | config VGA_ARB |
| 2 | bool "VGA Arbitration" if EMBEDDED | 2 | bool "VGA Arbitration" if EXPERT |
| 3 | default y | 3 | default y |
| 4 | depends on PCI | 4 | depends on PCI |
| 5 | help | 5 | help |
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index c8768f38511e..58434e804d91 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c | |||
| @@ -33,6 +33,7 @@ struct vga_switcheroo_client { | |||
| 33 | struct fb_info *fb_info; | 33 | struct fb_info *fb_info; |
| 34 | int pwr_state; | 34 | int pwr_state; |
| 35 | void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state); | 35 | void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state); |
| 36 | void (*reprobe)(struct pci_dev *pdev); | ||
| 36 | bool (*can_switch)(struct pci_dev *pdev); | 37 | bool (*can_switch)(struct pci_dev *pdev); |
| 37 | int id; | 38 | int id; |
| 38 | bool active; | 39 | bool active; |
| @@ -103,6 +104,7 @@ static void vga_switcheroo_enable(void) | |||
| 103 | 104 | ||
| 104 | int vga_switcheroo_register_client(struct pci_dev *pdev, | 105 | int vga_switcheroo_register_client(struct pci_dev *pdev, |
| 105 | void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state), | 106 | void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state), |
| 107 | void (*reprobe)(struct pci_dev *pdev), | ||
| 106 | bool (*can_switch)(struct pci_dev *pdev)) | 108 | bool (*can_switch)(struct pci_dev *pdev)) |
| 107 | { | 109 | { |
| 108 | int index; | 110 | int index; |
| @@ -117,6 +119,7 @@ int vga_switcheroo_register_client(struct pci_dev *pdev, | |||
| 117 | vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON; | 119 | vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON; |
| 118 | vgasr_priv.clients[index].pdev = pdev; | 120 | vgasr_priv.clients[index].pdev = pdev; |
| 119 | vgasr_priv.clients[index].set_gpu_state = set_gpu_state; | 121 | vgasr_priv.clients[index].set_gpu_state = set_gpu_state; |
| 122 | vgasr_priv.clients[index].reprobe = reprobe; | ||
| 120 | vgasr_priv.clients[index].can_switch = can_switch; | 123 | vgasr_priv.clients[index].can_switch = can_switch; |
| 121 | vgasr_priv.clients[index].id = -1; | 124 | vgasr_priv.clients[index].id = -1; |
| 122 | if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) | 125 | if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) |
| @@ -174,7 +177,8 @@ static int vga_switcheroo_show(struct seq_file *m, void *v) | |||
| 174 | int i; | 177 | int i; |
| 175 | mutex_lock(&vgasr_mutex); | 178 | mutex_lock(&vgasr_mutex); |
| 176 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 179 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { |
| 177 | seq_printf(m, "%d:%c:%s:%s\n", i, | 180 | seq_printf(m, "%d:%s:%c:%s:%s\n", i, |
| 181 | vgasr_priv.clients[i].id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD", | ||
| 178 | vgasr_priv.clients[i].active ? '+' : ' ', | 182 | vgasr_priv.clients[i].active ? '+' : ' ', |
| 179 | vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off", | 183 | vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off", |
| 180 | pci_name(vgasr_priv.clients[i].pdev)); | 184 | pci_name(vgasr_priv.clients[i].pdev)); |
| @@ -190,9 +194,8 @@ static int vga_switcheroo_debugfs_open(struct inode *inode, struct file *file) | |||
| 190 | 194 | ||
| 191 | static int vga_switchon(struct vga_switcheroo_client *client) | 195 | static int vga_switchon(struct vga_switcheroo_client *client) |
| 192 | { | 196 | { |
| 193 | int ret; | 197 | if (vgasr_priv.handler->power_state) |
| 194 | 198 | vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON); | |
| 195 | ret = vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON); | ||
| 196 | /* call the driver callback to turn on device */ | 199 | /* call the driver callback to turn on device */ |
| 197 | client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON); | 200 | client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON); |
| 198 | client->pwr_state = VGA_SWITCHEROO_ON; | 201 | client->pwr_state = VGA_SWITCHEROO_ON; |
| @@ -203,20 +206,18 @@ static int vga_switchoff(struct vga_switcheroo_client *client) | |||
| 203 | { | 206 | { |
| 204 | /* call the driver callback to turn off device */ | 207 | /* call the driver callback to turn off device */ |
| 205 | client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF); | 208 | client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF); |
| 206 | vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF); | 209 | if (vgasr_priv.handler->power_state) |
| 210 | vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF); | ||
| 207 | client->pwr_state = VGA_SWITCHEROO_OFF; | 211 | client->pwr_state = VGA_SWITCHEROO_OFF; |
| 208 | return 0; | 212 | return 0; |
| 209 | } | 213 | } |
| 210 | 214 | ||
| 211 | static int vga_switchto(struct vga_switcheroo_client *new_client) | 215 | /* stage one happens before delay */ |
| 216 | static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) | ||
| 212 | { | 217 | { |
| 213 | int ret; | ||
| 214 | int i; | 218 | int i; |
| 215 | struct vga_switcheroo_client *active = NULL; | 219 | struct vga_switcheroo_client *active = NULL; |
| 216 | 220 | ||
| 217 | if (new_client->active == true) | ||
| 218 | return 0; | ||
| 219 | |||
| 220 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 221 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { |
| 221 | if (vgasr_priv.clients[i].active == true) { | 222 | if (vgasr_priv.clients[i].active == true) { |
| 222 | active = &vgasr_priv.clients[i]; | 223 | active = &vgasr_priv.clients[i]; |
| @@ -226,19 +227,32 @@ static int vga_switchto(struct vga_switcheroo_client *new_client) | |||
| 226 | if (!active) | 227 | if (!active) |
| 227 | return 0; | 228 | return 0; |
| 228 | 229 | ||
| 229 | /* power up the first device */ | ||
| 230 | ret = pci_enable_device(new_client->pdev); | ||
| 231 | if (ret) | ||
| 232 | return ret; | ||
| 233 | |||
| 234 | if (new_client->pwr_state == VGA_SWITCHEROO_OFF) | 230 | if (new_client->pwr_state == VGA_SWITCHEROO_OFF) |
| 235 | vga_switchon(new_client); | 231 | vga_switchon(new_client); |
| 236 | 232 | ||
| 237 | /* swap shadow resource to denote boot VGA device has changed so X starts on new device */ | 233 | /* swap shadow resource to denote boot VGA device has changed so X starts on new device */ |
| 238 | active->active = false; | ||
| 239 | |||
| 240 | active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW; | 234 | active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW; |
| 241 | new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; | 235 | new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; |
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | /* post delay */ | ||
| 240 | static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) | ||
| 241 | { | ||
| 242 | int ret; | ||
| 243 | int i; | ||
| 244 | struct vga_switcheroo_client *active = NULL; | ||
| 245 | |||
| 246 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | ||
| 247 | if (vgasr_priv.clients[i].active == true) { | ||
| 248 | active = &vgasr_priv.clients[i]; | ||
| 249 | break; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | if (!active) | ||
| 253 | return 0; | ||
| 254 | |||
| 255 | active->active = false; | ||
| 242 | 256 | ||
| 243 | if (new_client->fb_info) { | 257 | if (new_client->fb_info) { |
| 244 | struct fb_event event; | 258 | struct fb_event event; |
| @@ -250,6 +264,9 @@ static int vga_switchto(struct vga_switcheroo_client *new_client) | |||
| 250 | if (ret) | 264 | if (ret) |
| 251 | return ret; | 265 | return ret; |
| 252 | 266 | ||
| 267 | if (new_client->reprobe) | ||
| 268 | new_client->reprobe(new_client->pdev); | ||
| 269 | |||
| 253 | if (active->pwr_state == VGA_SWITCHEROO_ON) | 270 | if (active->pwr_state == VGA_SWITCHEROO_ON) |
| 254 | vga_switchoff(active); | 271 | vga_switchoff(active); |
| 255 | 272 | ||
| @@ -265,6 +282,7 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, | |||
| 265 | const char *pdev_name; | 282 | const char *pdev_name; |
| 266 | int i, ret; | 283 | int i, ret; |
| 267 | bool delay = false, can_switch; | 284 | bool delay = false, can_switch; |
| 285 | bool just_mux = false; | ||
| 268 | int client_id = -1; | 286 | int client_id = -1; |
| 269 | struct vga_switcheroo_client *client = NULL; | 287 | struct vga_switcheroo_client *client = NULL; |
| 270 | 288 | ||
| @@ -319,6 +337,15 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, | |||
| 319 | if (strncmp(usercmd, "DIS", 3) == 0) | 337 | if (strncmp(usercmd, "DIS", 3) == 0) |
| 320 | client_id = VGA_SWITCHEROO_DIS; | 338 | client_id = VGA_SWITCHEROO_DIS; |
| 321 | 339 | ||
| 340 | if (strncmp(usercmd, "MIGD", 4) == 0) { | ||
| 341 | just_mux = true; | ||
| 342 | client_id = VGA_SWITCHEROO_IGD; | ||
| 343 | } | ||
| 344 | if (strncmp(usercmd, "MDIS", 4) == 0) { | ||
| 345 | just_mux = true; | ||
| 346 | client_id = VGA_SWITCHEROO_DIS; | ||
| 347 | } | ||
| 348 | |||
| 322 | if (client_id == -1) | 349 | if (client_id == -1) |
| 323 | goto out; | 350 | goto out; |
| 324 | 351 | ||
| @@ -330,6 +357,15 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, | |||
| 330 | } | 357 | } |
| 331 | 358 | ||
| 332 | vgasr_priv.delayed_switch_active = false; | 359 | vgasr_priv.delayed_switch_active = false; |
| 360 | |||
| 361 | if (just_mux) { | ||
| 362 | ret = vgasr_priv.handler->switchto(client_id); | ||
| 363 | goto out; | ||
| 364 | } | ||
| 365 | |||
| 366 | if (client->active == true) | ||
| 367 | goto out; | ||
| 368 | |||
| 333 | /* okay we want a switch - test if devices are willing to switch */ | 369 | /* okay we want a switch - test if devices are willing to switch */ |
| 334 | can_switch = true; | 370 | can_switch = true; |
| 335 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { | 371 | for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { |
| @@ -345,18 +381,22 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, | |||
| 345 | 381 | ||
| 346 | if (can_switch == true) { | 382 | if (can_switch == true) { |
| 347 | pdev_name = pci_name(client->pdev); | 383 | pdev_name = pci_name(client->pdev); |
| 348 | ret = vga_switchto(client); | 384 | ret = vga_switchto_stage1(client); |
| 385 | if (ret) | ||
| 386 | printk(KERN_ERR "vga_switcheroo: switching failed stage 1 %d\n", ret); | ||
| 387 | |||
| 388 | ret = vga_switchto_stage2(client); | ||
| 349 | if (ret) | 389 | if (ret) |
| 350 | printk(KERN_ERR "vga_switcheroo: switching failed %d\n", ret); | 390 | printk(KERN_ERR "vga_switcheroo: switching failed stage 2 %d\n", ret); |
| 391 | |||
| 351 | } else { | 392 | } else { |
| 352 | printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id); | 393 | printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id); |
| 353 | vgasr_priv.delayed_switch_active = true; | 394 | vgasr_priv.delayed_switch_active = true; |
| 354 | vgasr_priv.delayed_client_id = client_id; | 395 | vgasr_priv.delayed_client_id = client_id; |
| 355 | 396 | ||
| 356 | /* we should at least power up the card to | 397 | ret = vga_switchto_stage1(client); |
| 357 | make the switch faster */ | 398 | if (ret) |
| 358 | if (client->pwr_state == VGA_SWITCHEROO_OFF) | 399 | printk(KERN_ERR "vga_switcheroo: delayed switching stage 1 failed %d\n", ret); |
| 359 | vga_switchon(client); | ||
| 360 | } | 400 | } |
| 361 | 401 | ||
| 362 | out: | 402 | out: |
| @@ -438,9 +478,9 @@ int vga_switcheroo_process_delayed_switch(void) | |||
| 438 | goto err; | 478 | goto err; |
| 439 | 479 | ||
| 440 | pdev_name = pci_name(client->pdev); | 480 | pdev_name = pci_name(client->pdev); |
| 441 | ret = vga_switchto(client); | 481 | ret = vga_switchto_stage2(client); |
| 442 | if (ret) | 482 | if (ret) |
| 443 | printk(KERN_ERR "vga_switcheroo: delayed switching failed %d\n", ret); | 483 | printk(KERN_ERR "vga_switcheroo: delayed switching failed stage 2 %d\n", ret); |
| 444 | 484 | ||
| 445 | vgasr_priv.delayed_switch_active = false; | 485 | vgasr_priv.delayed_switch_active = false; |
| 446 | err = 0; | 486 | err = 0; |
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index f366f968155a..8a1021f2e319 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c | |||
| @@ -61,7 +61,7 @@ struct vga_device { | |||
| 61 | unsigned int mem_lock_cnt; /* legacy MEM lock count */ | 61 | unsigned int mem_lock_cnt; /* legacy MEM lock count */ |
| 62 | unsigned int io_norm_cnt; /* normal IO count */ | 62 | unsigned int io_norm_cnt; /* normal IO count */ |
| 63 | unsigned int mem_norm_cnt; /* normal MEM count */ | 63 | unsigned int mem_norm_cnt; /* normal MEM count */ |
| 64 | 64 | bool bridge_has_one_vga; | |
| 65 | /* allow IRQ enable/disable hook */ | 65 | /* allow IRQ enable/disable hook */ |
| 66 | void *cookie; | 66 | void *cookie; |
| 67 | void (*irq_set_state)(void *cookie, bool enable); | 67 | void (*irq_set_state)(void *cookie, bool enable); |
| @@ -151,7 +151,7 @@ static inline void vga_irq_set_state(struct vga_device *vgadev, bool state) | |||
| 151 | static void vga_check_first_use(void) | 151 | static void vga_check_first_use(void) |
| 152 | { | 152 | { |
| 153 | /* we should inform all GPUs in the system that | 153 | /* we should inform all GPUs in the system that |
| 154 | * VGA arb has occured and to try and disable resources | 154 | * VGA arb has occurred and to try and disable resources |
| 155 | * if they can */ | 155 | * if they can */ |
| 156 | if (!vga_arbiter_used) { | 156 | if (!vga_arbiter_used) { |
| 157 | vga_arbiter_used = true; | 157 | vga_arbiter_used = true; |
| @@ -165,6 +165,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, | |||
| 165 | unsigned int wants, legacy_wants, match; | 165 | unsigned int wants, legacy_wants, match; |
| 166 | struct vga_device *conflict; | 166 | struct vga_device *conflict; |
| 167 | unsigned int pci_bits; | 167 | unsigned int pci_bits; |
| 168 | u32 flags = 0; | ||
| 169 | |||
| 168 | /* Account for "normal" resources to lock. If we decode the legacy, | 170 | /* Account for "normal" resources to lock. If we decode the legacy, |
| 169 | * counterpart, we need to request it as well | 171 | * counterpart, we need to request it as well |
| 170 | */ | 172 | */ |
| @@ -237,16 +239,23 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, | |||
| 237 | /* looks like he doesn't have a lock, we can steal | 239 | /* looks like he doesn't have a lock, we can steal |
| 238 | * them from him | 240 | * them from him |
| 239 | */ | 241 | */ |
| 240 | vga_irq_set_state(conflict, false); | ||
| 241 | 242 | ||
| 243 | flags = 0; | ||
| 242 | pci_bits = 0; | 244 | pci_bits = 0; |
| 243 | if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM)) | ||
| 244 | pci_bits |= PCI_COMMAND_MEMORY; | ||
| 245 | if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) | ||
| 246 | pci_bits |= PCI_COMMAND_IO; | ||
| 247 | 245 | ||
| 248 | pci_set_vga_state(conflict->pdev, false, pci_bits, | 246 | if (!conflict->bridge_has_one_vga) { |
| 249 | change_bridge); | 247 | vga_irq_set_state(conflict, false); |
| 248 | flags |= PCI_VGA_STATE_CHANGE_DECODES; | ||
| 249 | if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM)) | ||
| 250 | pci_bits |= PCI_COMMAND_MEMORY; | ||
| 251 | if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) | ||
| 252 | pci_bits |= PCI_COMMAND_IO; | ||
| 253 | } | ||
| 254 | |||
| 255 | if (change_bridge) | ||
| 256 | flags |= PCI_VGA_STATE_CHANGE_BRIDGE; | ||
| 257 | |||
| 258 | pci_set_vga_state(conflict->pdev, false, pci_bits, flags); | ||
| 250 | conflict->owns &= ~lwants; | 259 | conflict->owns &= ~lwants; |
| 251 | /* If he also owned non-legacy, that is no longer the case */ | 260 | /* If he also owned non-legacy, that is no longer the case */ |
| 252 | if (lwants & VGA_RSRC_LEGACY_MEM) | 261 | if (lwants & VGA_RSRC_LEGACY_MEM) |
| @@ -261,14 +270,24 @@ enable_them: | |||
| 261 | * also have in "decodes". We can lock resources we don't decode but | 270 | * also have in "decodes". We can lock resources we don't decode but |
| 262 | * not own them. | 271 | * not own them. |
| 263 | */ | 272 | */ |
| 273 | flags = 0; | ||
| 264 | pci_bits = 0; | 274 | pci_bits = 0; |
| 265 | if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM)) | ||
| 266 | pci_bits |= PCI_COMMAND_MEMORY; | ||
| 267 | if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) | ||
| 268 | pci_bits |= PCI_COMMAND_IO; | ||
| 269 | pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(wants & VGA_RSRC_LEGACY_MASK)); | ||
| 270 | 275 | ||
| 271 | vga_irq_set_state(vgadev, true); | 276 | if (!vgadev->bridge_has_one_vga) { |
| 277 | flags |= PCI_VGA_STATE_CHANGE_DECODES; | ||
| 278 | if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM)) | ||
| 279 | pci_bits |= PCI_COMMAND_MEMORY; | ||
| 280 | if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) | ||
| 281 | pci_bits |= PCI_COMMAND_IO; | ||
| 282 | } | ||
| 283 | if (!!(wants & VGA_RSRC_LEGACY_MASK)) | ||
| 284 | flags |= PCI_VGA_STATE_CHANGE_BRIDGE; | ||
| 285 | |||
| 286 | pci_set_vga_state(vgadev->pdev, true, pci_bits, flags); | ||
| 287 | |||
| 288 | if (!vgadev->bridge_has_one_vga) { | ||
| 289 | vga_irq_set_state(vgadev, true); | ||
| 290 | } | ||
| 272 | vgadev->owns |= (wants & vgadev->decodes); | 291 | vgadev->owns |= (wants & vgadev->decodes); |
| 273 | lock_them: | 292 | lock_them: |
| 274 | vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK); | 293 | vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK); |
| @@ -421,6 +440,62 @@ bail: | |||
| 421 | } | 440 | } |
| 422 | EXPORT_SYMBOL(vga_put); | 441 | EXPORT_SYMBOL(vga_put); |
| 423 | 442 | ||
| 443 | /* Rules for using a bridge to control a VGA descendant decoding: | ||
| 444 | if a bridge has only one VGA descendant then it can be used | ||
| 445 | to control the VGA routing for that device. | ||
| 446 | It should always use the bridge closest to the device to control it. | ||
| 447 | If a bridge has a direct VGA descendant, but also have a sub-bridge | ||
| 448 | VGA descendant then we cannot use that bridge to control the direct VGA descendant. | ||
| 449 | So for every device we register, we need to iterate all its parent bridges | ||
| 450 | so we can invalidate any devices using them properly. | ||
| 451 | */ | ||
| 452 | static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev) | ||
| 453 | { | ||
| 454 | struct vga_device *same_bridge_vgadev; | ||
| 455 | struct pci_bus *new_bus, *bus; | ||
| 456 | struct pci_dev *new_bridge, *bridge; | ||
| 457 | |||
| 458 | vgadev->bridge_has_one_vga = true; | ||
| 459 | |||
| 460 | if (list_empty(&vga_list)) | ||
| 461 | return; | ||
| 462 | |||
| 463 | /* okay iterate the new devices bridge hierarachy */ | ||
| 464 | new_bus = vgadev->pdev->bus; | ||
| 465 | while (new_bus) { | ||
| 466 | new_bridge = new_bus->self; | ||
| 467 | |||
| 468 | if (new_bridge) { | ||
| 469 | /* go through list of devices already registered */ | ||
| 470 | list_for_each_entry(same_bridge_vgadev, &vga_list, list) { | ||
| 471 | bus = same_bridge_vgadev->pdev->bus; | ||
| 472 | bridge = bus->self; | ||
| 473 | |||
| 474 | /* see if the share a bridge with this device */ | ||
| 475 | if (new_bridge == bridge) { | ||
| 476 | /* if their direct parent bridge is the same | ||
| 477 | as any bridge of this device then it can't be used | ||
| 478 | for that device */ | ||
| 479 | same_bridge_vgadev->bridge_has_one_vga = false; | ||
| 480 | } | ||
| 481 | |||
| 482 | /* now iterate the previous devices bridge hierarchy */ | ||
| 483 | /* if the new devices parent bridge is in the other devices | ||
| 484 | hierarchy then we can't use it to control this device */ | ||
| 485 | while (bus) { | ||
| 486 | bridge = bus->self; | ||
| 487 | if (bridge) { | ||
| 488 | if (bridge == vgadev->pdev->bus->self) | ||
| 489 | vgadev->bridge_has_one_vga = false; | ||
| 490 | } | ||
| 491 | bus = bus->parent; | ||
| 492 | } | ||
| 493 | } | ||
| 494 | } | ||
| 495 | new_bus = new_bus->parent; | ||
| 496 | } | ||
| 497 | } | ||
| 498 | |||
| 424 | /* | 499 | /* |
| 425 | * Currently, we assume that the "initial" setup of the system is | 500 | * Currently, we assume that the "initial" setup of the system is |
| 426 | * not sane, that is we come up with conflicting devices and let | 501 | * not sane, that is we come up with conflicting devices and let |
| @@ -500,6 +575,8 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) | |||
| 500 | vga_default = pci_dev_get(pdev); | 575 | vga_default = pci_dev_get(pdev); |
| 501 | #endif | 576 | #endif |
| 502 | 577 | ||
| 578 | vga_arbiter_check_bridge_sharing(vgadev); | ||
| 579 | |||
| 503 | /* Add to the list */ | 580 | /* Add to the list */ |
| 504 | list_add(&vgadev->list, &vga_list); | 581 | list_add(&vgadev->list, &vga_list); |
| 505 | vga_count++; | 582 | vga_count++; |
| @@ -636,7 +713,7 @@ int vga_client_register(struct pci_dev *pdev, void *cookie, | |||
| 636 | void (*irq_set_state)(void *cookie, bool state), | 713 | void (*irq_set_state)(void *cookie, bool state), |
| 637 | unsigned int (*set_vga_decode)(void *cookie, bool decode)) | 714 | unsigned int (*set_vga_decode)(void *cookie, bool decode)) |
| 638 | { | 715 | { |
| 639 | int ret = -1; | 716 | int ret = -ENODEV; |
| 640 | struct vga_device *vgadev; | 717 | struct vga_device *vgadev; |
| 641 | unsigned long flags; | 718 | unsigned long flags; |
| 642 | 719 | ||
| @@ -774,7 +851,7 @@ static ssize_t vga_arb_read(struct file *file, char __user * buf, | |||
| 774 | */ | 851 | */ |
| 775 | spin_lock_irqsave(&vga_lock, flags); | 852 | spin_lock_irqsave(&vga_lock, flags); |
| 776 | 853 | ||
| 777 | /* If we are targetting the default, use it */ | 854 | /* If we are targeting the default, use it */ |
| 778 | pdev = priv->target; | 855 | pdev = priv->target; |
| 779 | if (pdev == NULL || pdev == PCI_INVALID_CARD) { | 856 | if (pdev == NULL || pdev == PCI_INVALID_CARD) { |
| 780 | spin_unlock_irqrestore(&vga_lock, flags); | 857 | spin_unlock_irqrestore(&vga_lock, flags); |
| @@ -1211,6 +1288,7 @@ static const struct file_operations vga_arb_device_fops = { | |||
| 1211 | .poll = vga_arb_fpoll, | 1288 | .poll = vga_arb_fpoll, |
| 1212 | .open = vga_arb_open, | 1289 | .open = vga_arb_open, |
| 1213 | .release = vga_arb_release, | 1290 | .release = vga_arb_release, |
| 1291 | .llseek = noop_llseek, | ||
| 1214 | }; | 1292 | }; |
| 1215 | 1293 | ||
| 1216 | static struct miscdevice vga_arb_device = { | 1294 | static struct miscdevice vga_arb_device = { |
| @@ -1221,6 +1299,7 @@ static int __init vga_arb_device_init(void) | |||
| 1221 | { | 1299 | { |
| 1222 | int rc; | 1300 | int rc; |
| 1223 | struct pci_dev *pdev; | 1301 | struct pci_dev *pdev; |
| 1302 | struct vga_device *vgadev; | ||
| 1224 | 1303 | ||
| 1225 | rc = misc_register(&vga_arb_device); | 1304 | rc = misc_register(&vga_arb_device); |
| 1226 | if (rc < 0) | 1305 | if (rc < 0) |
| @@ -1237,6 +1316,13 @@ static int __init vga_arb_device_init(void) | |||
| 1237 | vga_arbiter_add_pci_device(pdev); | 1316 | vga_arbiter_add_pci_device(pdev); |
| 1238 | 1317 | ||
| 1239 | pr_info("vgaarb: loaded\n"); | 1318 | pr_info("vgaarb: loaded\n"); |
| 1319 | |||
| 1320 | list_for_each_entry(vgadev, &vga_list, list) { | ||
| 1321 | if (vgadev->bridge_has_one_vga) | ||
| 1322 | pr_info("vgaarb: bridge control possible %s\n", pci_name(vgadev->pdev)); | ||
| 1323 | else | ||
| 1324 | pr_info("vgaarb: no bridge control possible %s\n", pci_name(vgadev->pdev)); | ||
| 1325 | } | ||
| 1240 | return rc; | 1326 | return rc; |
| 1241 | } | 1327 | } |
| 1242 | subsys_initcall(vga_arb_device_init); | 1328 | subsys_initcall(vga_arb_device_init); |
