| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1 | /* | 
| Tiago Vignatti | c0db9cb | 2010-05-24 18:24:31 +0300 | [diff] [blame] | 2 | * vgaarb.c: Implements the VGA arbitration. For details refer to | 
|  | 3 | * Documentation/vgaarbiter.txt | 
|  | 4 | * | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 5 | * | 
|  | 6 | * (C) Copyright 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org> | 
|  | 7 | * (C) Copyright 2007 Paulo R. Zanoni <przanoni@gmail.com> | 
|  | 8 | * (C) Copyright 2007, 2009 Tiago Vignatti <vignatti@freedesktop.org> | 
|  | 9 | * | 
| Tiago Vignatti | c0db9cb | 2010-05-24 18:24:31 +0300 | [diff] [blame] | 10 | * Permission is hereby granted, free of charge, to any person obtaining a | 
|  | 11 | * copy of this software and associated documentation files (the "Software"), | 
|  | 12 | * to deal in the Software without restriction, including without limitation | 
|  | 13 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
|  | 14 | * and/or sell copies of the Software, and to permit persons to whom the | 
|  | 15 | * Software is furnished to do so, subject to the following conditions: | 
|  | 16 | * | 
|  | 17 | * The above copyright notice and this permission notice (including the next | 
|  | 18 | * paragraph) shall be included in all copies or substantial portions of the | 
|  | 19 | * Software. | 
|  | 20 | * | 
|  | 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|  | 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|  | 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | 
|  | 24 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
|  | 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | 
|  | 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
|  | 27 | * DEALINGS | 
|  | 28 | * IN THE SOFTWARE. | 
|  | 29 | * | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 30 | */ | 
|  | 31 |  | 
|  | 32 | #include <linux/module.h> | 
|  | 33 | #include <linux/kernel.h> | 
|  | 34 | #include <linux/pci.h> | 
|  | 35 | #include <linux/errno.h> | 
|  | 36 | #include <linux/init.h> | 
|  | 37 | #include <linux/list.h> | 
|  | 38 | #include <linux/sched.h> | 
|  | 39 | #include <linux/wait.h> | 
|  | 40 | #include <linux/spinlock.h> | 
|  | 41 | #include <linux/poll.h> | 
|  | 42 | #include <linux/miscdevice.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 43 | #include <linux/slab.h> | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 44 |  | 
|  | 45 | #include <linux/uaccess.h> | 
|  | 46 |  | 
|  | 47 | #include <linux/vgaarb.h> | 
|  | 48 |  | 
|  | 49 | static void vga_arbiter_notify_clients(void); | 
|  | 50 | /* | 
|  | 51 | * We keep a list of all vga devices in the system to speed | 
|  | 52 | * up the various operations of the arbiter | 
|  | 53 | */ | 
|  | 54 | struct vga_device { | 
|  | 55 | struct list_head list; | 
|  | 56 | struct pci_dev *pdev; | 
|  | 57 | unsigned int decodes;	/* what does it decodes */ | 
|  | 58 | unsigned int owns;	/* what does it owns */ | 
|  | 59 | unsigned int locks;	/* what does it locks */ | 
|  | 60 | unsigned int io_lock_cnt;	/* legacy IO lock count */ | 
|  | 61 | unsigned int mem_lock_cnt;	/* legacy MEM lock count */ | 
|  | 62 | unsigned int io_norm_cnt;	/* normal IO count */ | 
|  | 63 | unsigned int mem_norm_cnt;	/* normal MEM count */ | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 64 | bool bridge_has_one_vga; | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 65 | /* allow IRQ enable/disable hook */ | 
|  | 66 | void *cookie; | 
|  | 67 | void (*irq_set_state)(void *cookie, bool enable); | 
|  | 68 | unsigned int (*set_vga_decode)(void *cookie, bool decode); | 
|  | 69 | }; | 
|  | 70 |  | 
|  | 71 | static LIST_HEAD(vga_list); | 
|  | 72 | static int vga_count, vga_decode_count; | 
|  | 73 | static bool vga_arbiter_used; | 
|  | 74 | static DEFINE_SPINLOCK(vga_lock); | 
|  | 75 | static DECLARE_WAIT_QUEUE_HEAD(vga_wait_queue); | 
|  | 76 |  | 
|  | 77 |  | 
|  | 78 | static const char *vga_iostate_to_str(unsigned int iostate) | 
|  | 79 | { | 
|  | 80 | /* Ignore VGA_RSRC_IO and VGA_RSRC_MEM */ | 
|  | 81 | iostate &= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; | 
|  | 82 | switch (iostate) { | 
|  | 83 | case VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM: | 
|  | 84 | return "io+mem"; | 
|  | 85 | case VGA_RSRC_LEGACY_IO: | 
|  | 86 | return "io"; | 
|  | 87 | case VGA_RSRC_LEGACY_MEM: | 
|  | 88 | return "mem"; | 
|  | 89 | } | 
|  | 90 | return "none"; | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | static int vga_str_to_iostate(char *buf, int str_size, int *io_state) | 
|  | 94 | { | 
|  | 95 | /* we could in theory hand out locks on IO and mem | 
|  | 96 | * separately to userspace but it can cause deadlocks */ | 
|  | 97 | if (strncmp(buf, "none", 4) == 0) { | 
|  | 98 | *io_state = VGA_RSRC_NONE; | 
|  | 99 | return 1; | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | /* XXX We're not chekcing the str_size! */ | 
|  | 103 | if (strncmp(buf, "io+mem", 6) == 0) | 
|  | 104 | goto both; | 
|  | 105 | else if (strncmp(buf, "io", 2) == 0) | 
|  | 106 | goto both; | 
|  | 107 | else if (strncmp(buf, "mem", 3) == 0) | 
|  | 108 | goto both; | 
|  | 109 | return 0; | 
|  | 110 | both: | 
|  | 111 | *io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; | 
|  | 112 | return 1; | 
|  | 113 | } | 
|  | 114 |  | 
|  | 115 | #ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE | 
|  | 116 | /* this is only used a cookie - it should not be dereferenced */ | 
|  | 117 | static struct pci_dev *vga_default; | 
|  | 118 | #endif | 
|  | 119 |  | 
|  | 120 | static void vga_arb_device_card_gone(struct pci_dev *pdev); | 
|  | 121 |  | 
|  | 122 | /* Find somebody in our list */ | 
|  | 123 | static struct vga_device *vgadev_find(struct pci_dev *pdev) | 
|  | 124 | { | 
|  | 125 | struct vga_device *vgadev; | 
|  | 126 |  | 
|  | 127 | list_for_each_entry(vgadev, &vga_list, list) | 
|  | 128 | if (pdev == vgadev->pdev) | 
|  | 129 | return vgadev; | 
|  | 130 | return NULL; | 
|  | 131 | } | 
|  | 132 |  | 
|  | 133 | /* Returns the default VGA device (vgacon's babe) */ | 
|  | 134 | #ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE | 
|  | 135 | struct pci_dev *vga_default_device(void) | 
|  | 136 | { | 
|  | 137 | return vga_default; | 
|  | 138 | } | 
|  | 139 | #endif | 
|  | 140 |  | 
|  | 141 | static inline void vga_irq_set_state(struct vga_device *vgadev, bool state) | 
|  | 142 | { | 
|  | 143 | if (vgadev->irq_set_state) | 
|  | 144 | vgadev->irq_set_state(vgadev->cookie, state); | 
|  | 145 | } | 
|  | 146 |  | 
|  | 147 |  | 
|  | 148 | /* If we don't ever use VGA arb we should avoid | 
|  | 149 | turning off anything anywhere due to old X servers getting | 
|  | 150 | confused about the boot device not being VGA */ | 
|  | 151 | static void vga_check_first_use(void) | 
|  | 152 | { | 
|  | 153 | /* we should inform all GPUs in the system that | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 154 | * VGA arb has occurred and to try and disable resources | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 155 | * if they can */ | 
|  | 156 | if (!vga_arbiter_used) { | 
|  | 157 | vga_arbiter_used = true; | 
|  | 158 | vga_arbiter_notify_clients(); | 
|  | 159 | } | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | static struct vga_device *__vga_tryget(struct vga_device *vgadev, | 
|  | 163 | unsigned int rsrc) | 
|  | 164 | { | 
|  | 165 | unsigned int wants, legacy_wants, match; | 
|  | 166 | struct vga_device *conflict; | 
|  | 167 | unsigned int pci_bits; | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 168 | u32 flags = 0; | 
|  | 169 |  | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 170 | /* Account for "normal" resources to lock. If we decode the legacy, | 
|  | 171 | * counterpart, we need to request it as well | 
|  | 172 | */ | 
|  | 173 | if ((rsrc & VGA_RSRC_NORMAL_IO) && | 
|  | 174 | (vgadev->decodes & VGA_RSRC_LEGACY_IO)) | 
|  | 175 | rsrc |= VGA_RSRC_LEGACY_IO; | 
|  | 176 | if ((rsrc & VGA_RSRC_NORMAL_MEM) && | 
|  | 177 | (vgadev->decodes & VGA_RSRC_LEGACY_MEM)) | 
|  | 178 | rsrc |= VGA_RSRC_LEGACY_MEM; | 
|  | 179 |  | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 180 | pr_debug("%s: %d\n", __func__, rsrc); | 
|  | 181 | pr_debug("%s: owns: %d\n", __func__, vgadev->owns); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 182 |  | 
|  | 183 | /* Check what resources we need to acquire */ | 
|  | 184 | wants = rsrc & ~vgadev->owns; | 
|  | 185 |  | 
|  | 186 | /* We already own everything, just mark locked & bye bye */ | 
|  | 187 | if (wants == 0) | 
|  | 188 | goto lock_them; | 
|  | 189 |  | 
|  | 190 | /* We don't need to request a legacy resource, we just enable | 
|  | 191 | * appropriate decoding and go | 
|  | 192 | */ | 
|  | 193 | legacy_wants = wants & VGA_RSRC_LEGACY_MASK; | 
|  | 194 | if (legacy_wants == 0) | 
|  | 195 | goto enable_them; | 
|  | 196 |  | 
|  | 197 | /* Ok, we don't, let's find out how we need to kick off */ | 
|  | 198 | list_for_each_entry(conflict, &vga_list, list) { | 
|  | 199 | unsigned int lwants = legacy_wants; | 
|  | 200 | unsigned int change_bridge = 0; | 
|  | 201 |  | 
|  | 202 | /* Don't conflict with myself */ | 
|  | 203 | if (vgadev == conflict) | 
|  | 204 | continue; | 
|  | 205 |  | 
|  | 206 | /* Check if the architecture allows a conflict between those | 
|  | 207 | * 2 devices or if they are on separate domains | 
|  | 208 | */ | 
|  | 209 | if (!vga_conflicts(vgadev->pdev, conflict->pdev)) | 
|  | 210 | continue; | 
|  | 211 |  | 
|  | 212 | /* We have a possible conflict. before we go further, we must | 
|  | 213 | * check if we sit on the same bus as the conflicting device. | 
|  | 214 | * if we don't, then we must tie both IO and MEM resources | 
|  | 215 | * together since there is only a single bit controlling | 
|  | 216 | * VGA forwarding on P2P bridges | 
|  | 217 | */ | 
|  | 218 | if (vgadev->pdev->bus != conflict->pdev->bus) { | 
|  | 219 | change_bridge = 1; | 
|  | 220 | lwants = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; | 
|  | 221 | } | 
|  | 222 |  | 
|  | 223 | /* Check if the guy has a lock on the resource. If he does, | 
|  | 224 | * return the conflicting entry | 
|  | 225 | */ | 
|  | 226 | if (conflict->locks & lwants) | 
|  | 227 | return conflict; | 
|  | 228 |  | 
|  | 229 | /* Ok, now check if he owns the resource we want. We don't need | 
|  | 230 | * to check "decodes" since it should be impossible to own | 
|  | 231 | * own legacy resources you don't decode unless I have a bug | 
|  | 232 | * in this code... | 
|  | 233 | */ | 
|  | 234 | WARN_ON(conflict->owns & ~conflict->decodes); | 
|  | 235 | match = lwants & conflict->owns; | 
|  | 236 | if (!match) | 
|  | 237 | continue; | 
|  | 238 |  | 
|  | 239 | /* looks like he doesn't have a lock, we can steal | 
|  | 240 | * them from him | 
|  | 241 | */ | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 242 |  | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 243 | flags = 0; | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 244 | pci_bits = 0; | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 245 |  | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 246 | if (!conflict->bridge_has_one_vga) { | 
|  | 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); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 259 | conflict->owns &= ~lwants; | 
|  | 260 | /* If he also owned non-legacy, that is no longer the case */ | 
|  | 261 | if (lwants & VGA_RSRC_LEGACY_MEM) | 
|  | 262 | conflict->owns &= ~VGA_RSRC_NORMAL_MEM; | 
|  | 263 | if (lwants & VGA_RSRC_LEGACY_IO) | 
|  | 264 | conflict->owns &= ~VGA_RSRC_NORMAL_IO; | 
|  | 265 | } | 
|  | 266 |  | 
|  | 267 | enable_them: | 
|  | 268 | /* ok dude, we got it, everybody conflicting has been disabled, let's | 
|  | 269 | * enable us. Make sure we don't mark a bit in "owns" that we don't | 
|  | 270 | * also have in "decodes". We can lock resources we don't decode but | 
|  | 271 | * not own them. | 
|  | 272 | */ | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 273 | flags = 0; | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 274 | pci_bits = 0; | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 275 |  | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 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 | } | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 291 | vgadev->owns |= (wants & vgadev->decodes); | 
|  | 292 | lock_them: | 
|  | 293 | vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK); | 
|  | 294 | if (rsrc & VGA_RSRC_LEGACY_IO) | 
|  | 295 | vgadev->io_lock_cnt++; | 
|  | 296 | if (rsrc & VGA_RSRC_LEGACY_MEM) | 
|  | 297 | vgadev->mem_lock_cnt++; | 
|  | 298 | if (rsrc & VGA_RSRC_NORMAL_IO) | 
|  | 299 | vgadev->io_norm_cnt++; | 
|  | 300 | if (rsrc & VGA_RSRC_NORMAL_MEM) | 
|  | 301 | vgadev->mem_norm_cnt++; | 
|  | 302 |  | 
|  | 303 | return NULL; | 
|  | 304 | } | 
|  | 305 |  | 
|  | 306 | static void __vga_put(struct vga_device *vgadev, unsigned int rsrc) | 
|  | 307 | { | 
|  | 308 | unsigned int old_locks = vgadev->locks; | 
|  | 309 |  | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 310 | pr_debug("%s\n", __func__); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 311 |  | 
|  | 312 | /* Update our counters, and account for equivalent legacy resources | 
|  | 313 | * if we decode them | 
|  | 314 | */ | 
|  | 315 | if ((rsrc & VGA_RSRC_NORMAL_IO) && vgadev->io_norm_cnt > 0) { | 
|  | 316 | vgadev->io_norm_cnt--; | 
|  | 317 | if (vgadev->decodes & VGA_RSRC_LEGACY_IO) | 
|  | 318 | rsrc |= VGA_RSRC_LEGACY_IO; | 
|  | 319 | } | 
|  | 320 | if ((rsrc & VGA_RSRC_NORMAL_MEM) && vgadev->mem_norm_cnt > 0) { | 
|  | 321 | vgadev->mem_norm_cnt--; | 
|  | 322 | if (vgadev->decodes & VGA_RSRC_LEGACY_MEM) | 
|  | 323 | rsrc |= VGA_RSRC_LEGACY_MEM; | 
|  | 324 | } | 
|  | 325 | if ((rsrc & VGA_RSRC_LEGACY_IO) && vgadev->io_lock_cnt > 0) | 
|  | 326 | vgadev->io_lock_cnt--; | 
|  | 327 | if ((rsrc & VGA_RSRC_LEGACY_MEM) && vgadev->mem_lock_cnt > 0) | 
|  | 328 | vgadev->mem_lock_cnt--; | 
|  | 329 |  | 
|  | 330 | /* Just clear lock bits, we do lazy operations so we don't really | 
|  | 331 | * have to bother about anything else at this point | 
|  | 332 | */ | 
|  | 333 | if (vgadev->io_lock_cnt == 0) | 
|  | 334 | vgadev->locks &= ~VGA_RSRC_LEGACY_IO; | 
|  | 335 | if (vgadev->mem_lock_cnt == 0) | 
|  | 336 | vgadev->locks &= ~VGA_RSRC_LEGACY_MEM; | 
|  | 337 |  | 
|  | 338 | /* Kick the wait queue in case somebody was waiting if we actually | 
|  | 339 | * released something | 
|  | 340 | */ | 
|  | 341 | if (old_locks != vgadev->locks) | 
|  | 342 | wake_up_all(&vga_wait_queue); | 
|  | 343 | } | 
|  | 344 |  | 
|  | 345 | int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) | 
|  | 346 | { | 
|  | 347 | struct vga_device *vgadev, *conflict; | 
|  | 348 | unsigned long flags; | 
|  | 349 | wait_queue_t wait; | 
|  | 350 | int rc = 0; | 
|  | 351 |  | 
|  | 352 | vga_check_first_use(); | 
|  | 353 | /* The one who calls us should check for this, but lets be sure... */ | 
|  | 354 | if (pdev == NULL) | 
|  | 355 | pdev = vga_default_device(); | 
|  | 356 | if (pdev == NULL) | 
|  | 357 | return 0; | 
|  | 358 |  | 
|  | 359 | for (;;) { | 
|  | 360 | spin_lock_irqsave(&vga_lock, flags); | 
|  | 361 | vgadev = vgadev_find(pdev); | 
|  | 362 | if (vgadev == NULL) { | 
|  | 363 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 364 | rc = -ENODEV; | 
|  | 365 | break; | 
|  | 366 | } | 
|  | 367 | conflict = __vga_tryget(vgadev, rsrc); | 
|  | 368 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 369 | if (conflict == NULL) | 
|  | 370 | break; | 
|  | 371 |  | 
|  | 372 |  | 
|  | 373 | /* We have a conflict, we wait until somebody kicks the | 
|  | 374 | * work queue. Currently we have one work queue that we | 
|  | 375 | * kick each time some resources are released, but it would | 
|  | 376 | * be fairly easy to have a per device one so that we only | 
|  | 377 | * need to attach to the conflicting device | 
|  | 378 | */ | 
|  | 379 | init_waitqueue_entry(&wait, current); | 
|  | 380 | add_wait_queue(&vga_wait_queue, &wait); | 
|  | 381 | set_current_state(interruptible ? | 
|  | 382 | TASK_INTERRUPTIBLE : | 
|  | 383 | TASK_UNINTERRUPTIBLE); | 
|  | 384 | if (signal_pending(current)) { | 
|  | 385 | rc = -EINTR; | 
|  | 386 | break; | 
|  | 387 | } | 
|  | 388 | schedule(); | 
|  | 389 | remove_wait_queue(&vga_wait_queue, &wait); | 
|  | 390 | set_current_state(TASK_RUNNING); | 
|  | 391 | } | 
|  | 392 | return rc; | 
|  | 393 | } | 
|  | 394 | EXPORT_SYMBOL(vga_get); | 
|  | 395 |  | 
|  | 396 | int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) | 
|  | 397 | { | 
|  | 398 | struct vga_device *vgadev; | 
|  | 399 | unsigned long flags; | 
|  | 400 | int rc = 0; | 
|  | 401 |  | 
|  | 402 | vga_check_first_use(); | 
|  | 403 |  | 
|  | 404 | /* The one who calls us should check for this, but lets be sure... */ | 
|  | 405 | if (pdev == NULL) | 
|  | 406 | pdev = vga_default_device(); | 
|  | 407 | if (pdev == NULL) | 
|  | 408 | return 0; | 
|  | 409 | spin_lock_irqsave(&vga_lock, flags); | 
|  | 410 | vgadev = vgadev_find(pdev); | 
|  | 411 | if (vgadev == NULL) { | 
|  | 412 | rc = -ENODEV; | 
|  | 413 | goto bail; | 
|  | 414 | } | 
|  | 415 | if (__vga_tryget(vgadev, rsrc)) | 
|  | 416 | rc = -EBUSY; | 
|  | 417 | bail: | 
|  | 418 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 419 | return rc; | 
|  | 420 | } | 
|  | 421 | EXPORT_SYMBOL(vga_tryget); | 
|  | 422 |  | 
|  | 423 | void vga_put(struct pci_dev *pdev, unsigned int rsrc) | 
|  | 424 | { | 
|  | 425 | struct vga_device *vgadev; | 
|  | 426 | unsigned long flags; | 
|  | 427 |  | 
|  | 428 | /* The one who calls us should check for this, but lets be sure... */ | 
|  | 429 | if (pdev == NULL) | 
|  | 430 | pdev = vga_default_device(); | 
|  | 431 | if (pdev == NULL) | 
|  | 432 | return; | 
|  | 433 | spin_lock_irqsave(&vga_lock, flags); | 
|  | 434 | vgadev = vgadev_find(pdev); | 
|  | 435 | if (vgadev == NULL) | 
|  | 436 | goto bail; | 
|  | 437 | __vga_put(vgadev, rsrc); | 
|  | 438 | bail: | 
|  | 439 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 440 | } | 
|  | 441 | EXPORT_SYMBOL(vga_put); | 
|  | 442 |  | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 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 |  | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 499 | /* | 
|  | 500 | * Currently, we assume that the "initial" setup of the system is | 
|  | 501 | * not sane, that is we come up with conflicting devices and let | 
|  | 502 | * the arbiter's client decides if devices decodes or not legacy | 
|  | 503 | * things. | 
|  | 504 | */ | 
|  | 505 | static bool vga_arbiter_add_pci_device(struct pci_dev *pdev) | 
|  | 506 | { | 
|  | 507 | struct vga_device *vgadev; | 
|  | 508 | unsigned long flags; | 
|  | 509 | struct pci_bus *bus; | 
|  | 510 | struct pci_dev *bridge; | 
|  | 511 | u16 cmd; | 
|  | 512 |  | 
|  | 513 | /* Only deal with VGA class devices */ | 
|  | 514 | if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) | 
|  | 515 | return false; | 
|  | 516 |  | 
|  | 517 | /* Allocate structure */ | 
|  | 518 | vgadev = kmalloc(sizeof(struct vga_device), GFP_KERNEL); | 
|  | 519 | if (vgadev == NULL) { | 
|  | 520 | pr_err("vgaarb: failed to allocate pci device\n"); | 
|  | 521 | /* What to do on allocation failure ? For now, let's | 
|  | 522 | * just do nothing, I'm not sure there is anything saner | 
|  | 523 | * to be done | 
|  | 524 | */ | 
|  | 525 | return false; | 
|  | 526 | } | 
|  | 527 |  | 
|  | 528 | memset(vgadev, 0, sizeof(*vgadev)); | 
|  | 529 |  | 
|  | 530 | /* Take lock & check for duplicates */ | 
|  | 531 | spin_lock_irqsave(&vga_lock, flags); | 
|  | 532 | if (vgadev_find(pdev) != NULL) { | 
|  | 533 | BUG_ON(1); | 
|  | 534 | goto fail; | 
|  | 535 | } | 
|  | 536 | vgadev->pdev = pdev; | 
|  | 537 |  | 
|  | 538 | /* By default, assume we decode everything */ | 
|  | 539 | vgadev->decodes = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | | 
|  | 540 | VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; | 
|  | 541 |  | 
|  | 542 | /* by default mark it as decoding */ | 
|  | 543 | vga_decode_count++; | 
|  | 544 | /* Mark that we "own" resources based on our enables, we will | 
|  | 545 | * clear that below if the bridge isn't forwarding | 
|  | 546 | */ | 
|  | 547 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | 
|  | 548 | if (cmd & PCI_COMMAND_IO) | 
|  | 549 | vgadev->owns |= VGA_RSRC_LEGACY_IO; | 
|  | 550 | if (cmd & PCI_COMMAND_MEMORY) | 
|  | 551 | vgadev->owns |= VGA_RSRC_LEGACY_MEM; | 
|  | 552 |  | 
|  | 553 | /* Check if VGA cycles can get down to us */ | 
|  | 554 | bus = pdev->bus; | 
|  | 555 | while (bus) { | 
|  | 556 | bridge = bus->self; | 
|  | 557 | if (bridge) { | 
|  | 558 | u16 l; | 
|  | 559 | pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, | 
|  | 560 | &l); | 
|  | 561 | if (!(l & PCI_BRIDGE_CTL_VGA)) { | 
|  | 562 | vgadev->owns = 0; | 
|  | 563 | break; | 
|  | 564 | } | 
|  | 565 | } | 
|  | 566 | bus = bus->parent; | 
|  | 567 | } | 
|  | 568 |  | 
|  | 569 | /* Deal with VGA default device. Use first enabled one | 
|  | 570 | * by default if arch doesn't have it's own hook | 
|  | 571 | */ | 
|  | 572 | #ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE | 
|  | 573 | if (vga_default == NULL && | 
|  | 574 | ((vgadev->owns & VGA_RSRC_LEGACY_MASK) == VGA_RSRC_LEGACY_MASK)) | 
|  | 575 | vga_default = pci_dev_get(pdev); | 
|  | 576 | #endif | 
|  | 577 |  | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 578 | vga_arbiter_check_bridge_sharing(vgadev); | 
|  | 579 |  | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 580 | /* Add to the list */ | 
|  | 581 | list_add(&vgadev->list, &vga_list); | 
|  | 582 | vga_count++; | 
|  | 583 | pr_info("vgaarb: device added: PCI:%s,decodes=%s,owns=%s,locks=%s\n", | 
|  | 584 | pci_name(pdev), | 
|  | 585 | vga_iostate_to_str(vgadev->decodes), | 
|  | 586 | vga_iostate_to_str(vgadev->owns), | 
|  | 587 | vga_iostate_to_str(vgadev->locks)); | 
|  | 588 |  | 
|  | 589 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 590 | return true; | 
|  | 591 | fail: | 
|  | 592 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 593 | kfree(vgadev); | 
|  | 594 | return false; | 
|  | 595 | } | 
|  | 596 |  | 
|  | 597 | static bool vga_arbiter_del_pci_device(struct pci_dev *pdev) | 
|  | 598 | { | 
|  | 599 | struct vga_device *vgadev; | 
|  | 600 | unsigned long flags; | 
|  | 601 | bool ret = true; | 
|  | 602 |  | 
|  | 603 | spin_lock_irqsave(&vga_lock, flags); | 
|  | 604 | vgadev = vgadev_find(pdev); | 
|  | 605 | if (vgadev == NULL) { | 
|  | 606 | ret = false; | 
|  | 607 | goto bail; | 
|  | 608 | } | 
|  | 609 |  | 
|  | 610 | if (vga_default == pdev) { | 
|  | 611 | pci_dev_put(vga_default); | 
|  | 612 | vga_default = NULL; | 
|  | 613 | } | 
|  | 614 |  | 
|  | 615 | if (vgadev->decodes & (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM)) | 
|  | 616 | vga_decode_count--; | 
|  | 617 |  | 
|  | 618 | /* Remove entry from list */ | 
|  | 619 | list_del(&vgadev->list); | 
|  | 620 | vga_count--; | 
|  | 621 | /* Notify userland driver that the device is gone so it discards | 
|  | 622 | * it's copies of the pci_dev pointer | 
|  | 623 | */ | 
|  | 624 | vga_arb_device_card_gone(pdev); | 
|  | 625 |  | 
|  | 626 | /* Wake up all possible waiters */ | 
|  | 627 | wake_up_all(&vga_wait_queue); | 
|  | 628 | bail: | 
|  | 629 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 630 | kfree(vgadev); | 
|  | 631 | return ret; | 
|  | 632 | } | 
|  | 633 |  | 
|  | 634 | /* this is called with the lock */ | 
|  | 635 | static inline void vga_update_device_decodes(struct vga_device *vgadev, | 
|  | 636 | int new_decodes) | 
|  | 637 | { | 
|  | 638 | int old_decodes; | 
|  | 639 | struct vga_device *new_vgadev, *conflict; | 
|  | 640 |  | 
|  | 641 | old_decodes = vgadev->decodes; | 
|  | 642 | vgadev->decodes = new_decodes; | 
|  | 643 |  | 
|  | 644 | pr_info("vgaarb: device changed decodes: PCI:%s,olddecodes=%s,decodes=%s:owns=%s\n", | 
|  | 645 | pci_name(vgadev->pdev), | 
|  | 646 | vga_iostate_to_str(old_decodes), | 
|  | 647 | vga_iostate_to_str(vgadev->decodes), | 
|  | 648 | vga_iostate_to_str(vgadev->owns)); | 
|  | 649 |  | 
|  | 650 |  | 
|  | 651 | /* if we own the decodes we should move them along to | 
|  | 652 | another card */ | 
|  | 653 | if ((vgadev->owns & old_decodes) && (vga_count > 1)) { | 
|  | 654 | /* set us to own nothing */ | 
|  | 655 | vgadev->owns &= ~old_decodes; | 
|  | 656 | list_for_each_entry(new_vgadev, &vga_list, list) { | 
|  | 657 | if ((new_vgadev != vgadev) && | 
|  | 658 | (new_vgadev->decodes & VGA_RSRC_LEGACY_MASK)) { | 
|  | 659 | pr_info("vgaarb: transferring owner from PCI:%s to PCI:%s\n", pci_name(vgadev->pdev), pci_name(new_vgadev->pdev)); | 
|  | 660 | conflict = __vga_tryget(new_vgadev, VGA_RSRC_LEGACY_MASK); | 
|  | 661 | if (!conflict) | 
|  | 662 | __vga_put(new_vgadev, VGA_RSRC_LEGACY_MASK); | 
|  | 663 | break; | 
|  | 664 | } | 
|  | 665 | } | 
|  | 666 | } | 
|  | 667 |  | 
|  | 668 | /* change decodes counter */ | 
|  | 669 | if (old_decodes != new_decodes) { | 
|  | 670 | if (new_decodes & (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM)) | 
|  | 671 | vga_decode_count++; | 
|  | 672 | else | 
|  | 673 | vga_decode_count--; | 
|  | 674 | } | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 675 | pr_debug("vgaarb: decoding count now is: %d\n", vga_decode_count); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 676 | } | 
|  | 677 |  | 
| Daniel J Blueman | 201ba4c | 2010-09-22 18:05:35 +0100 | [diff] [blame] | 678 | static void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace) | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 679 | { | 
|  | 680 | struct vga_device *vgadev; | 
|  | 681 | unsigned long flags; | 
|  | 682 |  | 
|  | 683 | decodes &= VGA_RSRC_LEGACY_MASK; | 
|  | 684 |  | 
|  | 685 | spin_lock_irqsave(&vga_lock, flags); | 
|  | 686 | vgadev = vgadev_find(pdev); | 
|  | 687 | if (vgadev == NULL) | 
|  | 688 | goto bail; | 
|  | 689 |  | 
|  | 690 | /* don't let userspace futz with kernel driver decodes */ | 
|  | 691 | if (userspace && vgadev->set_vga_decode) | 
|  | 692 | goto bail; | 
|  | 693 |  | 
|  | 694 | /* update the device decodes + counter */ | 
|  | 695 | vga_update_device_decodes(vgadev, decodes); | 
|  | 696 |  | 
|  | 697 | /* XXX if somebody is going from "doesn't decode" to "decodes" state | 
|  | 698 | * here, additional care must be taken as we may have pending owner | 
|  | 699 | * ship of non-legacy region ... | 
|  | 700 | */ | 
|  | 701 | bail: | 
|  | 702 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 703 | } | 
|  | 704 |  | 
|  | 705 | void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes) | 
|  | 706 | { | 
|  | 707 | __vga_set_legacy_decoding(pdev, decodes, false); | 
|  | 708 | } | 
|  | 709 | EXPORT_SYMBOL(vga_set_legacy_decoding); | 
|  | 710 |  | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 711 | /* call with NULL to unregister */ | 
|  | 712 | int vga_client_register(struct pci_dev *pdev, void *cookie, | 
|  | 713 | void (*irq_set_state)(void *cookie, bool state), | 
|  | 714 | unsigned int (*set_vga_decode)(void *cookie, bool decode)) | 
|  | 715 | { | 
| Chris Wilson | 934f992 | 2011-01-20 13:09:12 +0000 | [diff] [blame] | 716 | int ret = -ENODEV; | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 717 | struct vga_device *vgadev; | 
|  | 718 | unsigned long flags; | 
|  | 719 |  | 
|  | 720 | spin_lock_irqsave(&vga_lock, flags); | 
|  | 721 | vgadev = vgadev_find(pdev); | 
|  | 722 | if (!vgadev) | 
|  | 723 | goto bail; | 
|  | 724 |  | 
|  | 725 | vgadev->irq_set_state = irq_set_state; | 
|  | 726 | vgadev->set_vga_decode = set_vga_decode; | 
|  | 727 | vgadev->cookie = cookie; | 
|  | 728 | ret = 0; | 
|  | 729 |  | 
|  | 730 | bail: | 
|  | 731 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 732 | return ret; | 
|  | 733 |  | 
|  | 734 | } | 
|  | 735 | EXPORT_SYMBOL(vga_client_register); | 
|  | 736 |  | 
|  | 737 | /* | 
|  | 738 | * Char driver implementation | 
|  | 739 | * | 
|  | 740 | * Semantics is: | 
|  | 741 | * | 
|  | 742 | *  open       : open user instance of the arbitrer. by default, it's | 
|  | 743 | *                attached to the default VGA device of the system. | 
|  | 744 | * | 
|  | 745 | *  close      : close user instance, release locks | 
|  | 746 | * | 
|  | 747 | *  read       : return a string indicating the status of the target. | 
|  | 748 | *                an IO state string is of the form {io,mem,io+mem,none}, | 
|  | 749 | *                mc and ic are respectively mem and io lock counts (for | 
|  | 750 | *                debugging/diagnostic only). "decodes" indicate what the | 
|  | 751 | *                card currently decodes, "owns" indicates what is currently | 
|  | 752 | *                enabled on it, and "locks" indicates what is locked by this | 
|  | 753 | *                card. If the card is unplugged, we get "invalid" then for | 
|  | 754 | *                card_ID and an -ENODEV error is returned for any command | 
|  | 755 | *                until a new card is targeted | 
|  | 756 | * | 
|  | 757 | *   "<card_ID>,decodes=<io_state>,owns=<io_state>,locks=<io_state> (ic,mc)" | 
|  | 758 | * | 
|  | 759 | * write       : write a command to the arbiter. List of commands is: | 
|  | 760 | * | 
|  | 761 | *   target <card_ID>   : switch target to card <card_ID> (see below) | 
|  | 762 | *   lock <io_state>    : acquires locks on target ("none" is invalid io_state) | 
|  | 763 | *   trylock <io_state> : non-blocking acquire locks on target | 
|  | 764 | *   unlock <io_state>  : release locks on target | 
|  | 765 | *   unlock all         : release all locks on target held by this user | 
|  | 766 | *   decodes <io_state> : set the legacy decoding attributes for the card | 
|  | 767 | * | 
|  | 768 | * poll         : event if something change on any card (not just the target) | 
|  | 769 | * | 
|  | 770 | * card_ID is of the form "PCI:domain:bus:dev.fn". It can be set to "default" | 
|  | 771 | * to go back to the system default card (TODO: not implemented yet). | 
|  | 772 | * Currently, only PCI is supported as a prefix, but the userland API may | 
|  | 773 | * support other bus types in the future, even if the current kernel | 
|  | 774 | * implementation doesn't. | 
|  | 775 | * | 
|  | 776 | * Note about locks: | 
|  | 777 | * | 
|  | 778 | * The driver keeps track of which user has what locks on which card. It | 
|  | 779 | * supports stacking, like the kernel one. This complexifies the implementation | 
|  | 780 | * a bit, but makes the arbiter more tolerant to userspace problems and able | 
|  | 781 | * to properly cleanup in all cases when a process dies. | 
|  | 782 | * Currently, a max of 16 cards simultaneously can have locks issued from | 
|  | 783 | * userspace for a given user (file descriptor instance) of the arbiter. | 
|  | 784 | * | 
|  | 785 | * If the device is hot-unplugged, there is a hook inside the module to notify | 
|  | 786 | * they being added/removed in the system and automatically added/removed in | 
|  | 787 | * the arbiter. | 
|  | 788 | */ | 
|  | 789 |  | 
| Mike Travis | 36028f3 | 2010-02-02 17:45:01 -0800 | [diff] [blame] | 790 | #define MAX_USER_CARDS         CONFIG_VGA_ARB_MAX_GPUS | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 791 | #define PCI_INVALID_CARD       ((struct pci_dev *)-1UL) | 
|  | 792 |  | 
|  | 793 | /* | 
|  | 794 | * Each user has an array of these, tracking which cards have locks | 
|  | 795 | */ | 
|  | 796 | struct vga_arb_user_card { | 
|  | 797 | struct pci_dev *pdev; | 
|  | 798 | unsigned int mem_cnt; | 
|  | 799 | unsigned int io_cnt; | 
|  | 800 | }; | 
|  | 801 |  | 
|  | 802 | struct vga_arb_private { | 
|  | 803 | struct list_head list; | 
|  | 804 | struct pci_dev *target; | 
|  | 805 | struct vga_arb_user_card cards[MAX_USER_CARDS]; | 
|  | 806 | spinlock_t lock; | 
|  | 807 | }; | 
|  | 808 |  | 
|  | 809 | static LIST_HEAD(vga_user_list); | 
|  | 810 | static DEFINE_SPINLOCK(vga_user_lock); | 
|  | 811 |  | 
|  | 812 |  | 
|  | 813 | /* | 
|  | 814 | * This function gets a string in the format: "PCI:domain:bus:dev.fn" and | 
|  | 815 | * returns the respective values. If the string is not in this format, | 
|  | 816 | * it returns 0. | 
|  | 817 | */ | 
|  | 818 | static int vga_pci_str_to_vars(char *buf, int count, unsigned int *domain, | 
|  | 819 | unsigned int *bus, unsigned int *devfn) | 
|  | 820 | { | 
|  | 821 | int n; | 
|  | 822 | unsigned int slot, func; | 
|  | 823 |  | 
|  | 824 |  | 
|  | 825 | n = sscanf(buf, "PCI:%x:%x:%x.%x", domain, bus, &slot, &func); | 
|  | 826 | if (n != 4) | 
|  | 827 | return 0; | 
|  | 828 |  | 
|  | 829 | *devfn = PCI_DEVFN(slot, func); | 
|  | 830 |  | 
|  | 831 | return 1; | 
|  | 832 | } | 
|  | 833 |  | 
|  | 834 | static ssize_t vga_arb_read(struct file *file, char __user * buf, | 
|  | 835 | size_t count, loff_t *ppos) | 
|  | 836 | { | 
|  | 837 | struct vga_arb_private *priv = file->private_data; | 
|  | 838 | struct vga_device *vgadev; | 
|  | 839 | struct pci_dev *pdev; | 
|  | 840 | unsigned long flags; | 
|  | 841 | size_t len; | 
|  | 842 | int rc; | 
|  | 843 | char *lbuf; | 
|  | 844 |  | 
|  | 845 | lbuf = kmalloc(1024, GFP_KERNEL); | 
|  | 846 | if (lbuf == NULL) | 
|  | 847 | return -ENOMEM; | 
|  | 848 |  | 
|  | 849 | /* Shields against vga_arb_device_card_gone (pci_dev going | 
|  | 850 | * away), and allows access to vga list | 
|  | 851 | */ | 
|  | 852 | spin_lock_irqsave(&vga_lock, flags); | 
|  | 853 |  | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 854 | /* If we are targeting the default, use it */ | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 855 | pdev = priv->target; | 
|  | 856 | if (pdev == NULL || pdev == PCI_INVALID_CARD) { | 
|  | 857 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 858 | len = sprintf(lbuf, "invalid"); | 
|  | 859 | goto done; | 
|  | 860 | } | 
|  | 861 |  | 
|  | 862 | /* Find card vgadev structure */ | 
|  | 863 | vgadev = vgadev_find(pdev); | 
|  | 864 | if (vgadev == NULL) { | 
|  | 865 | /* Wow, it's not in the list, that shouldn't happen, | 
|  | 866 | * let's fix us up and return invalid card | 
|  | 867 | */ | 
|  | 868 | if (pdev == priv->target) | 
|  | 869 | vga_arb_device_card_gone(pdev); | 
|  | 870 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 871 | len = sprintf(lbuf, "invalid"); | 
|  | 872 | goto done; | 
|  | 873 | } | 
|  | 874 |  | 
|  | 875 | /* Fill the buffer with infos */ | 
|  | 876 | len = snprintf(lbuf, 1024, | 
|  | 877 | "count:%d,PCI:%s,decodes=%s,owns=%s,locks=%s(%d:%d)\n", | 
|  | 878 | vga_decode_count, pci_name(pdev), | 
|  | 879 | vga_iostate_to_str(vgadev->decodes), | 
|  | 880 | vga_iostate_to_str(vgadev->owns), | 
|  | 881 | vga_iostate_to_str(vgadev->locks), | 
|  | 882 | vgadev->io_lock_cnt, vgadev->mem_lock_cnt); | 
|  | 883 |  | 
|  | 884 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 885 | done: | 
|  | 886 |  | 
|  | 887 | /* Copy that to user */ | 
|  | 888 | if (len > count) | 
|  | 889 | len = count; | 
|  | 890 | rc = copy_to_user(buf, lbuf, len); | 
|  | 891 | kfree(lbuf); | 
|  | 892 | if (rc) | 
|  | 893 | return -EFAULT; | 
|  | 894 | return len; | 
|  | 895 | } | 
|  | 896 |  | 
|  | 897 | /* | 
|  | 898 | * TODO: To avoid parsing inside kernel and to improve the speed we may | 
|  | 899 | * consider use ioctl here | 
|  | 900 | */ | 
|  | 901 | static ssize_t vga_arb_write(struct file *file, const char __user * buf, | 
|  | 902 | size_t count, loff_t *ppos) | 
|  | 903 | { | 
|  | 904 | struct vga_arb_private *priv = file->private_data; | 
|  | 905 | struct vga_arb_user_card *uc = NULL; | 
|  | 906 | struct pci_dev *pdev; | 
|  | 907 |  | 
|  | 908 | unsigned int io_state; | 
|  | 909 |  | 
|  | 910 | char *kbuf, *curr_pos; | 
|  | 911 | size_t remaining = count; | 
|  | 912 |  | 
|  | 913 | int ret_val; | 
|  | 914 | int i; | 
|  | 915 |  | 
|  | 916 |  | 
|  | 917 | kbuf = kmalloc(count + 1, GFP_KERNEL); | 
|  | 918 | if (!kbuf) | 
|  | 919 | return -ENOMEM; | 
|  | 920 |  | 
|  | 921 | if (copy_from_user(kbuf, buf, count)) { | 
|  | 922 | kfree(kbuf); | 
|  | 923 | return -EFAULT; | 
|  | 924 | } | 
|  | 925 | curr_pos = kbuf; | 
|  | 926 | kbuf[count] = '\0';	/* Just to make sure... */ | 
|  | 927 |  | 
|  | 928 | if (strncmp(curr_pos, "lock ", 5) == 0) { | 
|  | 929 | curr_pos += 5; | 
|  | 930 | remaining -= 5; | 
|  | 931 |  | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 932 | pr_debug("client 0x%p called 'lock'\n", priv); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 933 |  | 
|  | 934 | if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { | 
|  | 935 | ret_val = -EPROTO; | 
|  | 936 | goto done; | 
|  | 937 | } | 
|  | 938 | if (io_state == VGA_RSRC_NONE) { | 
|  | 939 | ret_val = -EPROTO; | 
|  | 940 | goto done; | 
|  | 941 | } | 
|  | 942 |  | 
|  | 943 | pdev = priv->target; | 
|  | 944 | if (priv->target == NULL) { | 
|  | 945 | ret_val = -ENODEV; | 
|  | 946 | goto done; | 
|  | 947 | } | 
|  | 948 |  | 
|  | 949 | vga_get_uninterruptible(pdev, io_state); | 
|  | 950 |  | 
|  | 951 | /* Update the client's locks lists... */ | 
|  | 952 | for (i = 0; i < MAX_USER_CARDS; i++) { | 
|  | 953 | if (priv->cards[i].pdev == pdev) { | 
|  | 954 | if (io_state & VGA_RSRC_LEGACY_IO) | 
|  | 955 | priv->cards[i].io_cnt++; | 
|  | 956 | if (io_state & VGA_RSRC_LEGACY_MEM) | 
|  | 957 | priv->cards[i].mem_cnt++; | 
|  | 958 | break; | 
|  | 959 | } | 
|  | 960 | } | 
|  | 961 |  | 
|  | 962 | ret_val = count; | 
|  | 963 | goto done; | 
|  | 964 | } else if (strncmp(curr_pos, "unlock ", 7) == 0) { | 
|  | 965 | curr_pos += 7; | 
|  | 966 | remaining -= 7; | 
|  | 967 |  | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 968 | pr_debug("client 0x%p called 'unlock'\n", priv); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 969 |  | 
|  | 970 | if (strncmp(curr_pos, "all", 3) == 0) | 
|  | 971 | io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; | 
|  | 972 | else { | 
|  | 973 | if (!vga_str_to_iostate | 
|  | 974 | (curr_pos, remaining, &io_state)) { | 
|  | 975 | ret_val = -EPROTO; | 
|  | 976 | goto done; | 
|  | 977 | } | 
|  | 978 | /* TODO: Add this? | 
|  | 979 | if (io_state == VGA_RSRC_NONE) { | 
|  | 980 | ret_val = -EPROTO; | 
|  | 981 | goto done; | 
|  | 982 | } | 
|  | 983 | */ | 
|  | 984 | } | 
|  | 985 |  | 
|  | 986 | pdev = priv->target; | 
|  | 987 | if (priv->target == NULL) { | 
|  | 988 | ret_val = -ENODEV; | 
|  | 989 | goto done; | 
|  | 990 | } | 
|  | 991 | for (i = 0; i < MAX_USER_CARDS; i++) { | 
|  | 992 | if (priv->cards[i].pdev == pdev) | 
|  | 993 | uc = &priv->cards[i]; | 
|  | 994 | } | 
|  | 995 |  | 
|  | 996 | if (!uc) | 
|  | 997 | return -EINVAL; | 
|  | 998 |  | 
|  | 999 | if (io_state & VGA_RSRC_LEGACY_IO && uc->io_cnt == 0) | 
|  | 1000 | return -EINVAL; | 
|  | 1001 |  | 
|  | 1002 | if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_cnt == 0) | 
|  | 1003 | return -EINVAL; | 
|  | 1004 |  | 
|  | 1005 | vga_put(pdev, io_state); | 
|  | 1006 |  | 
|  | 1007 | if (io_state & VGA_RSRC_LEGACY_IO) | 
|  | 1008 | uc->io_cnt--; | 
|  | 1009 | if (io_state & VGA_RSRC_LEGACY_MEM) | 
|  | 1010 | uc->mem_cnt--; | 
|  | 1011 |  | 
|  | 1012 | ret_val = count; | 
|  | 1013 | goto done; | 
|  | 1014 | } else if (strncmp(curr_pos, "trylock ", 8) == 0) { | 
|  | 1015 | curr_pos += 8; | 
|  | 1016 | remaining -= 8; | 
|  | 1017 |  | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1018 | pr_debug("client 0x%p called 'trylock'\n", priv); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1019 |  | 
|  | 1020 | if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { | 
|  | 1021 | ret_val = -EPROTO; | 
|  | 1022 | goto done; | 
|  | 1023 | } | 
|  | 1024 | /* TODO: Add this? | 
|  | 1025 | if (io_state == VGA_RSRC_NONE) { | 
|  | 1026 | ret_val = -EPROTO; | 
|  | 1027 | goto done; | 
|  | 1028 | } | 
|  | 1029 | */ | 
|  | 1030 |  | 
|  | 1031 | pdev = priv->target; | 
|  | 1032 | if (priv->target == NULL) { | 
|  | 1033 | ret_val = -ENODEV; | 
|  | 1034 | goto done; | 
|  | 1035 | } | 
|  | 1036 |  | 
|  | 1037 | if (vga_tryget(pdev, io_state)) { | 
|  | 1038 | /* Update the client's locks lists... */ | 
|  | 1039 | for (i = 0; i < MAX_USER_CARDS; i++) { | 
|  | 1040 | if (priv->cards[i].pdev == pdev) { | 
|  | 1041 | if (io_state & VGA_RSRC_LEGACY_IO) | 
|  | 1042 | priv->cards[i].io_cnt++; | 
|  | 1043 | if (io_state & VGA_RSRC_LEGACY_MEM) | 
|  | 1044 | priv->cards[i].mem_cnt++; | 
|  | 1045 | break; | 
|  | 1046 | } | 
|  | 1047 | } | 
|  | 1048 | ret_val = count; | 
|  | 1049 | goto done; | 
|  | 1050 | } else { | 
|  | 1051 | ret_val = -EBUSY; | 
|  | 1052 | goto done; | 
|  | 1053 | } | 
|  | 1054 |  | 
|  | 1055 | } else if (strncmp(curr_pos, "target ", 7) == 0) { | 
| Mike Travis | 773a38d | 2010-02-02 14:38:15 -0800 | [diff] [blame] | 1056 | struct pci_bus *pbus; | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1057 | unsigned int domain, bus, devfn; | 
|  | 1058 | struct vga_device *vgadev; | 
|  | 1059 |  | 
|  | 1060 | curr_pos += 7; | 
|  | 1061 | remaining -= 7; | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1062 | pr_debug("client 0x%p called 'target'\n", priv); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1063 | /* if target is default */ | 
| Kyle McMartin | 2cc9116 | 2010-02-16 16:18:37 -0500 | [diff] [blame] | 1064 | if (!strncmp(curr_pos, "default", 7)) | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1065 | pdev = pci_dev_get(vga_default_device()); | 
|  | 1066 | else { | 
|  | 1067 | if (!vga_pci_str_to_vars(curr_pos, remaining, | 
|  | 1068 | &domain, &bus, &devfn)) { | 
|  | 1069 | ret_val = -EPROTO; | 
|  | 1070 | goto done; | 
|  | 1071 | } | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1072 | pr_debug("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos, | 
| Mike Travis | 773a38d | 2010-02-02 14:38:15 -0800 | [diff] [blame] | 1073 | domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1074 |  | 
| Mike Travis | 773a38d | 2010-02-02 14:38:15 -0800 | [diff] [blame] | 1075 | pbus = pci_find_bus(domain, bus); | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1076 | pr_debug("vgaarb: pbus %p\n", pbus); | 
| Mike Travis | 773a38d | 2010-02-02 14:38:15 -0800 | [diff] [blame] | 1077 | if (pbus == NULL) { | 
|  | 1078 | pr_err("vgaarb: invalid PCI domain and/or bus address %x:%x\n", | 
|  | 1079 | domain, bus); | 
|  | 1080 | ret_val = -ENODEV; | 
|  | 1081 | goto done; | 
|  | 1082 | } | 
|  | 1083 | pdev = pci_get_slot(pbus, devfn); | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1084 | pr_debug("vgaarb: pdev %p\n", pdev); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1085 | if (!pdev) { | 
| Mike Travis | 773a38d | 2010-02-02 14:38:15 -0800 | [diff] [blame] | 1086 | pr_err("vgaarb: invalid PCI address %x:%x\n", | 
|  | 1087 | bus, devfn); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1088 | ret_val = -ENODEV; | 
|  | 1089 | goto done; | 
|  | 1090 | } | 
|  | 1091 | } | 
|  | 1092 |  | 
|  | 1093 | vgadev = vgadev_find(pdev); | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1094 | pr_debug("vgaarb: vgadev %p\n", vgadev); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1095 | if (vgadev == NULL) { | 
| Mike Travis | 773a38d | 2010-02-02 14:38:15 -0800 | [diff] [blame] | 1096 | pr_err("vgaarb: this pci device is not a vga device\n"); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1097 | pci_dev_put(pdev); | 
|  | 1098 | ret_val = -ENODEV; | 
|  | 1099 | goto done; | 
|  | 1100 | } | 
|  | 1101 |  | 
|  | 1102 | priv->target = pdev; | 
|  | 1103 | for (i = 0; i < MAX_USER_CARDS; i++) { | 
|  | 1104 | if (priv->cards[i].pdev == pdev) | 
|  | 1105 | break; | 
|  | 1106 | if (priv->cards[i].pdev == NULL) { | 
|  | 1107 | priv->cards[i].pdev = pdev; | 
|  | 1108 | priv->cards[i].io_cnt = 0; | 
|  | 1109 | priv->cards[i].mem_cnt = 0; | 
|  | 1110 | break; | 
|  | 1111 | } | 
|  | 1112 | } | 
|  | 1113 | if (i == MAX_USER_CARDS) { | 
| Mike Travis | 773a38d | 2010-02-02 14:38:15 -0800 | [diff] [blame] | 1114 | pr_err("vgaarb: maximum user cards (%d) number reached!\n", | 
|  | 1115 | MAX_USER_CARDS); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1116 | pci_dev_put(pdev); | 
|  | 1117 | /* XXX: which value to return? */ | 
|  | 1118 | ret_val =  -ENOMEM; | 
|  | 1119 | goto done; | 
|  | 1120 | } | 
|  | 1121 |  | 
|  | 1122 | ret_val = count; | 
|  | 1123 | pci_dev_put(pdev); | 
|  | 1124 | goto done; | 
|  | 1125 |  | 
|  | 1126 |  | 
|  | 1127 | } else if (strncmp(curr_pos, "decodes ", 8) == 0) { | 
|  | 1128 | curr_pos += 8; | 
|  | 1129 | remaining -= 8; | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1130 | pr_debug("vgaarb: client 0x%p called 'decodes'\n", priv); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1131 |  | 
|  | 1132 | if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) { | 
|  | 1133 | ret_val = -EPROTO; | 
|  | 1134 | goto done; | 
|  | 1135 | } | 
|  | 1136 | pdev = priv->target; | 
|  | 1137 | if (priv->target == NULL) { | 
|  | 1138 | ret_val = -ENODEV; | 
|  | 1139 | goto done; | 
|  | 1140 | } | 
|  | 1141 |  | 
|  | 1142 | __vga_set_legacy_decoding(pdev, io_state, true); | 
|  | 1143 | ret_val = count; | 
|  | 1144 | goto done; | 
|  | 1145 | } | 
|  | 1146 | /* If we got here, the message written is not part of the protocol! */ | 
|  | 1147 | kfree(kbuf); | 
|  | 1148 | return -EPROTO; | 
|  | 1149 |  | 
|  | 1150 | done: | 
|  | 1151 | kfree(kbuf); | 
|  | 1152 | return ret_val; | 
|  | 1153 | } | 
|  | 1154 |  | 
|  | 1155 | static unsigned int vga_arb_fpoll(struct file *file, poll_table * wait) | 
|  | 1156 | { | 
|  | 1157 | struct vga_arb_private *priv = file->private_data; | 
|  | 1158 |  | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1159 | pr_debug("%s\n", __func__); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1160 |  | 
|  | 1161 | if (priv == NULL) | 
|  | 1162 | return -ENODEV; | 
|  | 1163 | poll_wait(file, &vga_wait_queue, wait); | 
|  | 1164 | return POLLIN; | 
|  | 1165 | } | 
|  | 1166 |  | 
|  | 1167 | static int vga_arb_open(struct inode *inode, struct file *file) | 
|  | 1168 | { | 
|  | 1169 | struct vga_arb_private *priv; | 
|  | 1170 | unsigned long flags; | 
|  | 1171 |  | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1172 | pr_debug("%s\n", __func__); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1173 |  | 
| Rakib Mullick | f35119d | 2011-07-25 17:12:56 -0700 | [diff] [blame] | 1174 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1175 | if (priv == NULL) | 
|  | 1176 | return -ENOMEM; | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1177 | spin_lock_init(&priv->lock); | 
|  | 1178 | file->private_data = priv; | 
|  | 1179 |  | 
|  | 1180 | spin_lock_irqsave(&vga_user_lock, flags); | 
|  | 1181 | list_add(&priv->list, &vga_user_list); | 
|  | 1182 | spin_unlock_irqrestore(&vga_user_lock, flags); | 
|  | 1183 |  | 
|  | 1184 | /* Set the client' lists of locks */ | 
|  | 1185 | priv->target = vga_default_device(); /* Maybe this is still null! */ | 
|  | 1186 | priv->cards[0].pdev = priv->target; | 
|  | 1187 | priv->cards[0].io_cnt = 0; | 
|  | 1188 | priv->cards[0].mem_cnt = 0; | 
|  | 1189 |  | 
|  | 1190 |  | 
|  | 1191 | return 0; | 
|  | 1192 | } | 
|  | 1193 |  | 
|  | 1194 | static int vga_arb_release(struct inode *inode, struct file *file) | 
|  | 1195 | { | 
|  | 1196 | struct vga_arb_private *priv = file->private_data; | 
|  | 1197 | struct vga_arb_user_card *uc; | 
|  | 1198 | unsigned long flags; | 
|  | 1199 | int i; | 
|  | 1200 |  | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1201 | pr_debug("%s\n", __func__); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1202 |  | 
|  | 1203 | if (priv == NULL) | 
|  | 1204 | return -ENODEV; | 
|  | 1205 |  | 
|  | 1206 | spin_lock_irqsave(&vga_user_lock, flags); | 
|  | 1207 | list_del(&priv->list); | 
|  | 1208 | for (i = 0; i < MAX_USER_CARDS; i++) { | 
|  | 1209 | uc = &priv->cards[i]; | 
|  | 1210 | if (uc->pdev == NULL) | 
|  | 1211 | continue; | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1212 | pr_debug("uc->io_cnt == %d, uc->mem_cnt == %d\n", | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1213 | uc->io_cnt, uc->mem_cnt); | 
|  | 1214 | while (uc->io_cnt--) | 
|  | 1215 | vga_put(uc->pdev, VGA_RSRC_LEGACY_IO); | 
|  | 1216 | while (uc->mem_cnt--) | 
|  | 1217 | vga_put(uc->pdev, VGA_RSRC_LEGACY_MEM); | 
|  | 1218 | } | 
|  | 1219 | spin_unlock_irqrestore(&vga_user_lock, flags); | 
|  | 1220 |  | 
|  | 1221 | kfree(priv); | 
|  | 1222 |  | 
|  | 1223 | return 0; | 
|  | 1224 | } | 
|  | 1225 |  | 
|  | 1226 | static void vga_arb_device_card_gone(struct pci_dev *pdev) | 
|  | 1227 | { | 
|  | 1228 | } | 
|  | 1229 |  | 
|  | 1230 | /* | 
|  | 1231 | * callback any registered clients to let them know we have a | 
|  | 1232 | * change in VGA cards | 
|  | 1233 | */ | 
|  | 1234 | static void vga_arbiter_notify_clients(void) | 
|  | 1235 | { | 
|  | 1236 | struct vga_device *vgadev; | 
|  | 1237 | unsigned long flags; | 
|  | 1238 | uint32_t new_decodes; | 
|  | 1239 | bool new_state; | 
|  | 1240 |  | 
|  | 1241 | if (!vga_arbiter_used) | 
|  | 1242 | return; | 
|  | 1243 |  | 
|  | 1244 | spin_lock_irqsave(&vga_lock, flags); | 
|  | 1245 | list_for_each_entry(vgadev, &vga_list, list) { | 
|  | 1246 | if (vga_count > 1) | 
|  | 1247 | new_state = false; | 
|  | 1248 | else | 
|  | 1249 | new_state = true; | 
|  | 1250 | if (vgadev->set_vga_decode) { | 
|  | 1251 | new_decodes = vgadev->set_vga_decode(vgadev->cookie, new_state); | 
|  | 1252 | vga_update_device_decodes(vgadev, new_decodes); | 
|  | 1253 | } | 
|  | 1254 | } | 
|  | 1255 | spin_unlock_irqrestore(&vga_lock, flags); | 
|  | 1256 | } | 
|  | 1257 |  | 
|  | 1258 | static int pci_notify(struct notifier_block *nb, unsigned long action, | 
|  | 1259 | void *data) | 
|  | 1260 | { | 
|  | 1261 | struct device *dev = data; | 
|  | 1262 | struct pci_dev *pdev = to_pci_dev(dev); | 
|  | 1263 | bool notify = false; | 
|  | 1264 |  | 
| Tiago Vignatti | 2d6e9b9 | 2010-05-24 18:24:30 +0300 | [diff] [blame] | 1265 | pr_debug("%s\n", __func__); | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1266 |  | 
|  | 1267 | /* For now we're only intereted in devices added and removed. I didn't | 
|  | 1268 | * test this thing here, so someone needs to double check for the | 
|  | 1269 | * cases of hotplugable vga cards. */ | 
|  | 1270 | if (action == BUS_NOTIFY_ADD_DEVICE) | 
|  | 1271 | notify = vga_arbiter_add_pci_device(pdev); | 
|  | 1272 | else if (action == BUS_NOTIFY_DEL_DEVICE) | 
|  | 1273 | notify = vga_arbiter_del_pci_device(pdev); | 
|  | 1274 |  | 
|  | 1275 | if (notify) | 
|  | 1276 | vga_arbiter_notify_clients(); | 
|  | 1277 | return 0; | 
|  | 1278 | } | 
|  | 1279 |  | 
|  | 1280 | static struct notifier_block pci_notifier = { | 
|  | 1281 | .notifier_call = pci_notify, | 
|  | 1282 | }; | 
|  | 1283 |  | 
|  | 1284 | static const struct file_operations vga_arb_device_fops = { | 
|  | 1285 | .read = vga_arb_read, | 
|  | 1286 | .write = vga_arb_write, | 
|  | 1287 | .poll = vga_arb_fpoll, | 
|  | 1288 | .open = vga_arb_open, | 
|  | 1289 | .release = vga_arb_release, | 
| Arnd Bergmann | 6038f37 | 2010-08-15 18:52:59 +0200 | [diff] [blame] | 1290 | .llseek = noop_llseek, | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1291 | }; | 
|  | 1292 |  | 
|  | 1293 | static struct miscdevice vga_arb_device = { | 
|  | 1294 | MISC_DYNAMIC_MINOR, "vga_arbiter", &vga_arb_device_fops | 
|  | 1295 | }; | 
|  | 1296 |  | 
|  | 1297 | static int __init vga_arb_device_init(void) | 
|  | 1298 | { | 
|  | 1299 | int rc; | 
|  | 1300 | struct pci_dev *pdev; | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 1301 | struct vga_device *vgadev; | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1302 |  | 
|  | 1303 | rc = misc_register(&vga_arb_device); | 
|  | 1304 | if (rc < 0) | 
|  | 1305 | pr_err("vgaarb: error %d registering device\n", rc); | 
|  | 1306 |  | 
|  | 1307 | bus_register_notifier(&pci_bus_type, &pci_notifier); | 
|  | 1308 |  | 
|  | 1309 | /* We add all pci devices satisfying vga class in the arbiter by | 
|  | 1310 | * default */ | 
|  | 1311 | pdev = NULL; | 
|  | 1312 | while ((pdev = | 
|  | 1313 | pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, | 
|  | 1314 | PCI_ANY_ID, pdev)) != NULL) | 
|  | 1315 | vga_arbiter_add_pci_device(pdev); | 
|  | 1316 |  | 
|  | 1317 | pr_info("vgaarb: loaded\n"); | 
| Dave Airlie | 3448a19 | 2010-06-01 15:32:24 +1000 | [diff] [blame] | 1318 |  | 
|  | 1319 | list_for_each_entry(vgadev, &vga_list, list) { | 
|  | 1320 | if (vgadev->bridge_has_one_vga) | 
|  | 1321 | pr_info("vgaarb: bridge control possible %s\n", pci_name(vgadev->pdev)); | 
|  | 1322 | else | 
|  | 1323 | pr_info("vgaarb: no bridge control possible %s\n", pci_name(vgadev->pdev)); | 
|  | 1324 | } | 
| Benjamin Herrenschmidt | deb2d2e | 2009-08-11 15:52:06 +1000 | [diff] [blame] | 1325 | return rc; | 
|  | 1326 | } | 
|  | 1327 | subsys_initcall(vga_arb_device_init); |