Non-legacy access lock is introduced, in addition to current
legacy access lock ("lega_locks"), for performance improvement
as most graphics operations after session starts do non-legacy
accesses which do not need to block themselves.

Legacy accesses are represented by "io" and "mem". Non-legacy
accesses are represented by "IO" and "MEM".

Arbitration rules:
"lega_locks" conflicts with "lega_locks" and "norm_locks";
"norm_locks" conflicts with "lega_locks";
"norm_locks" does not conflict with "norm_locks".

Potential deadlock may occur when a program holds "norm_locks"
while requesting "lega_locks". The problem is prevented by
releasing "norm_locks" resources the same program has acquired
before going to sleep, and restore them after wakeup when the
requesting "lega_locks" is acquired.

Signed-off-by: Henry Zhao <[email protected]>
---
 drivers/gpu/vga/vgaarb.c |  387 +++++++++++++++++++++++++++++-----------------
 include/linux/vgaarb.h   |   22 ++--
 2 files changed, 258 insertions(+), 151 deletions(-)

diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index b87569e..e214b6d 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -56,11 +56,12 @@ struct vga_device {
        struct pci_dev *pdev;
        unsigned int decodes;   /* what does it decodes */
        unsigned int owns;      /* what does it owns */
-       unsigned int locks;     /* what does it locks */
-       unsigned int io_lock_cnt;       /* legacy IO lock count */
-       unsigned int mem_lock_cnt;      /* legacy MEM lock count */
-       unsigned int io_norm_cnt;       /* normal IO count */
-       unsigned int mem_norm_cnt;      /* normal MEM count */
+       unsigned int lega_locks;        /* what does it locks for legacy access 
*/
+       unsigned int norm_locks;        /* what does it locks for non-legacy 
(normal) access */
+       unsigned int io_lega_lock_cnt;  /* legacy IO lock count */
+       unsigned int mem_lega_lock_cnt; /* legacy MEM lock count */
+       unsigned int io_norm_lock_cnt;  /* normal IO count */
+       unsigned int mem_norm_lock_cnt; /* normal MEM count */
 
        /* allow IRQ enable/disable hook */
        void *cookie;
@@ -74,24 +75,30 @@ static bool vga_arbiter_used;
 static DEFINE_SPINLOCK(vga_lock);
 static DECLARE_WAIT_QUEUE_HEAD(vga_wait_queue);
 
-
-static const char *vga_iostate_to_str(unsigned int iostate)
-{
-       /* Ignore VGA_RSRC_IO and VGA_RSRC_MEM */
-       iostate &= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
-       switch (iostate) {
-       case VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM:
-               return "io+mem";
-       case VGA_RSRC_LEGACY_IO:
-               return "io";
-       case VGA_RSRC_LEGACY_MEM:
-               return "mem";
-       }
-       return "none";
-}
+static char *vga_iostate_to_str[] = {
+       "none",
+       "io",
+       "mem",
+       "io+mem",
+       "IO",
+       "io+IO",
+       "mem+IO",
+       "io+mem+IO",
+       "MEM",
+       "io+MEM",
+       "mem+MEM",
+       "io+mem+MEM",
+       "IO+MEM",
+       "io+IO+MEM",
+       "mem+IO+MEM",
+       "io+mem+IO+MEM"
+};
 
 static int vga_str_to_iostate(char *buf, int str_size, int *io_state)
 {
+       unsigned int state = 0;
+       char *bptr;
+
        /* we could in theory hand out locks on IO and mem
         * separately to userspace but it can cause deadlocks */
        if (strncmp(buf, "none", 4) == 0) {
@@ -99,16 +106,35 @@ static int vga_str_to_iostate(char *buf, int str_size, int 
*io_state)
                return 1;
        }
 
-       /* XXX We're not chekcing the str_size! */
-       if (strncmp(buf, "io+mem", 6) == 0)
-               goto both;
-       else if (strncmp(buf, "io", 2) == 0)
-               goto both;
-       else if (strncmp(buf, "mem", 3) == 0)
-               goto both;
-       return 0;
-both:
-       *io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
+       for (bptr = buf; *bptr != 0; bptr++) {
+               if (strncmp (bptr, "io", 2) == 0) {
+                       state |= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
+                       bptr += 2;
+               } else if (strncmp (bptr, "mem", 3) == 0) {
+                       state |= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
+                       bptr += 3;
+               } else if (strncmp (bptr, "IO", 2) == 0) {
+                       state |= VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+                       bptr += 2;
+               } else if (strncmp (bptr, "MEM", 3) == 0) {
+                       state |= VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+                       bptr += 3;
+               } else if (strncmp (bptr, "all", 3) == 0) {
+                       state |= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
+                               VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+                       break;
+               } else
+                       break;
+
+               if (*bptr != '+')
+                       break;
+       };
+
+       if (!state)
+               return 0;
+
+       *io_state = state;
+
        return 1;
 }
 
@@ -162,18 +188,9 @@ static void vga_check_first_use(void)
 static struct vga_device *__vga_tryget(struct vga_device *vgadev,
                                       unsigned int rsrc)
 {
-       unsigned int wants, legacy_wants, match;
+       unsigned int wants, lega_wants, norm_wants, match;
        struct vga_device *conflict;
        unsigned int pci_bits;
-       /* Account for "normal" resources to lock. If we decode the legacy,
-        * counterpart, we need to request it as well
-        */
-       if ((rsrc & VGA_RSRC_NORMAL_IO) &&
-           (vgadev->decodes & VGA_RSRC_LEGACY_IO))
-               rsrc |= VGA_RSRC_LEGACY_IO;
-       if ((rsrc & VGA_RSRC_NORMAL_MEM) &&
-           (vgadev->decodes & VGA_RSRC_LEGACY_MEM))
-               rsrc |= VGA_RSRC_LEGACY_MEM;
 
        pr_debug("%s: %d\n", __func__, rsrc);
        pr_debug("%s: owns: %d\n", __func__, vgadev->owns);
@@ -181,20 +198,21 @@ static struct vga_device *__vga_tryget(struct vga_device 
*vgadev,
        /* Check what resources we need to acquire */
        wants = rsrc & ~vgadev->owns;
 
-       /* We already own everything, just mark locked & bye bye */
-       if (wants == 0)
-               goto lock_them;
-
        /* We don't need to request a legacy resource, we just enable
         * appropriate decoding and go
         */
-       legacy_wants = wants & VGA_RSRC_LEGACY_MASK;
-       if (legacy_wants == 0)
-               goto enable_them;
+       lega_wants = rsrc & VGA_RSRC_LEGACY_MASK;
+
+       /* already own everything: legal wants still need to grab other 
devices' owns */
+        if ((wants == 0) && (lega_wants == 0))
+               goto lock_them;
+
+       norm_wants = wants & VGA_RSRC_NORMAL_MASK;
 
        /* Ok, we don't, let's find out how we need to kick off */
        list_for_each_entry(conflict, &vga_list, list) {
-               unsigned int lwants = legacy_wants;
+               unsigned int lwants = lega_wants;
+               unsigned int nwants = norm_wants;
                unsigned int change_bridge = 0;
 
                /* Don't conflict with myself */
@@ -215,13 +233,25 @@ static struct vga_device *__vga_tryget(struct vga_device 
*vgadev,
                 */
                if (vgadev->pdev->bus != conflict->pdev->bus) {
                        change_bridge = 1;
-                       lwants = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
+                       if (lwants)
+                               lwants = VGA_RSRC_LEGACY_IO|VGA_RSRC_LEGACY_MEM;
+                       if (nwants)
+                               nwants = VGA_RSRC_NORMAL_IO|VGA_RSRC_NORMAL_MEM;
                }
 
                /* Check if the guy has a lock on the resource. If he does,
                 * return the conflicting entry
                 */
-               if (conflict->locks & lwants)
+               /* legacy request: check conflict with legacy lock */
+               if (lwants & conflict->lega_locks)
+                       return conflict;
+
+               /* legacy request: check conflict with non-legacy lock */
+               if (lwants & (conflict->norm_locks >> 
VGA_RSRC_LEGACY_TO_NORMAL_SHIFT))
+                       return conflict;
+
+               /* non-legacy request: check conflict with legacy lock */
+               if (nwants & (conflict->lega_locks << 
VGA_RSRC_LEGACY_TO_NORMAL_SHIFT))
                        return conflict;
 
                /* Ok, now check if he owns the resource we want. We don't need
@@ -240,95 +270,104 @@ static struct vga_device *__vga_tryget(struct vga_device 
*vgadev,
                vga_irq_set_state(conflict, false);
 
                pci_bits = 0;
-               if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+               if (lwants & VGA_RSRC_LEGACY_MEM) {
                        pci_bits |= PCI_COMMAND_MEMORY;
-               if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+                       conflict->owns &= 
~(VGA_RSRC_NORMAL_MEM|VGA_RSRC_LEGACY_MEM);
+               }
+               if (lwants & VGA_RSRC_LEGACY_IO) {
                        pci_bits |= PCI_COMMAND_IO;
+                       conflict->owns &= 
~(VGA_RSRC_NORMAL_IO|VGA_RSRC_LEGACY_IO);
+               }
 
                pci_set_vga_state(conflict->pdev, false, pci_bits,
                                  change_bridge);
-               conflict->owns &= ~lwants;
-               /* If he also owned non-legacy, that is no longer the case */
-               if (lwants & VGA_RSRC_LEGACY_MEM)
-                       conflict->owns &= ~VGA_RSRC_NORMAL_MEM;
-               if (lwants & VGA_RSRC_LEGACY_IO)
-                       conflict->owns &= ~VGA_RSRC_NORMAL_IO;
        }
 
-enable_them:
        /* ok dude, we got it, everybody conflicting has been disabled, let's
         * enable us. Make sure we don't mark a bit in "owns" that we don't
         * also have in "decodes". We can lock resources we don't decode but
         * not own them.
         */
-       pci_bits = 0;
-       if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
-               pci_bits |= PCI_COMMAND_MEMORY;
-       if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
-               pci_bits |= PCI_COMMAND_IO;
-       pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(wants & 
VGA_RSRC_LEGACY_MASK));
+       if (wants) {
+               pci_bits = 0;
+               if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM)) {
+                       vgadev->owns |= VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM;
+                       pci_bits |= PCI_COMMAND_MEMORY;
+               }
+               if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) {
+                       vgadev->owns |= VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO;
+                       pci_bits |= PCI_COMMAND_IO;
+               }
+
+               pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(lega_wants));
+       }
 
        vga_irq_set_state(vgadev, true);
-       vgadev->owns |= (wants & vgadev->decodes);
 lock_them:
-       vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
-       if (rsrc & VGA_RSRC_LEGACY_IO)
-               vgadev->io_lock_cnt++;
-       if (rsrc & VGA_RSRC_LEGACY_MEM)
-               vgadev->mem_lock_cnt++;
-       if (rsrc & VGA_RSRC_NORMAL_IO)
-               vgadev->io_norm_cnt++;
-       if (rsrc & VGA_RSRC_NORMAL_MEM)
-               vgadev->mem_norm_cnt++;
+       if (rsrc & VGA_RSRC_LEGACY_MASK) {
+               vgadev->lega_locks |= rsrc & VGA_RSRC_LEGACY_MASK;
+               if (rsrc & VGA_RSRC_LEGACY_IO)
+                       vgadev->io_lega_lock_cnt++;
+               if (rsrc & VGA_RSRC_LEGACY_MEM)
+                       vgadev->mem_lega_lock_cnt++;
+       }
+       if (rsrc & VGA_RSRC_NORMAL_MASK) {
+               vgadev->norm_locks |= rsrc & VGA_RSRC_NORMAL_MASK;
+               if (rsrc & VGA_RSRC_NORMAL_IO)
+                       vgadev->io_norm_lock_cnt++;
+               if (rsrc & VGA_RSRC_NORMAL_MEM)
+                       vgadev->mem_norm_lock_cnt++;
+       }
 
        return NULL;
 }
 
 static void __vga_put(struct vga_device *vgadev, unsigned int rsrc)
 {
-       unsigned int old_locks = vgadev->locks;
+       unsigned int old_lega_locks = vgadev->lega_locks;
+       unsigned int old_norm_locks = vgadev->norm_locks;
 
        pr_debug("%s\n", __func__);
 
        /* Update our counters, and account for equivalent legacy resources
         * if we decode them
         */
-       if ((rsrc & VGA_RSRC_NORMAL_IO) && vgadev->io_norm_cnt > 0) {
-               vgadev->io_norm_cnt--;
-               if (vgadev->decodes & VGA_RSRC_LEGACY_IO)
-                       rsrc |= VGA_RSRC_LEGACY_IO;
-       }
-       if ((rsrc & VGA_RSRC_NORMAL_MEM) && vgadev->mem_norm_cnt > 0) {
-               vgadev->mem_norm_cnt--;
-               if (vgadev->decodes & VGA_RSRC_LEGACY_MEM)
-                       rsrc |= VGA_RSRC_LEGACY_MEM;
-       }
-       if ((rsrc & VGA_RSRC_LEGACY_IO) && vgadev->io_lock_cnt > 0)
-               vgadev->io_lock_cnt--;
-       if ((rsrc & VGA_RSRC_LEGACY_MEM) && vgadev->mem_lock_cnt > 0)
-               vgadev->mem_lock_cnt--;
+       if ((rsrc & VGA_RSRC_NORMAL_IO) && vgadev->io_norm_lock_cnt > 0)
+               vgadev->io_norm_lock_cnt--;
+       if ((rsrc & VGA_RSRC_NORMAL_MEM) && vgadev->mem_norm_lock_cnt > 0)
+               vgadev->mem_norm_lock_cnt--;
+       if ((rsrc & VGA_RSRC_LEGACY_IO) && vgadev->io_lega_lock_cnt > 0)
+               vgadev->io_lega_lock_cnt--;
+       if ((rsrc & VGA_RSRC_LEGACY_MEM) && vgadev->mem_lega_lock_cnt > 0)
+               vgadev->mem_lega_lock_cnt--;
 
        /* Just clear lock bits, we do lazy operations so we don't really
         * have to bother about anything else at this point
         */
-       if (vgadev->io_lock_cnt == 0)
-               vgadev->locks &= ~VGA_RSRC_LEGACY_IO;
-       if (vgadev->mem_lock_cnt == 0)
-               vgadev->locks &= ~VGA_RSRC_LEGACY_MEM;
+       if (vgadev->io_lega_lock_cnt == 0)
+               vgadev->lega_locks &= ~VGA_RSRC_LEGACY_IO;
+       if (vgadev->mem_lega_lock_cnt == 0)
+               vgadev->lega_locks &= ~VGA_RSRC_LEGACY_MEM;
+       if (vgadev->io_norm_lock_cnt == 0)
+               vgadev->norm_locks &= ~VGA_RSRC_NORMAL_IO;
+       if (vgadev->mem_norm_lock_cnt == 0)
+               vgadev->norm_locks &= ~VGA_RSRC_NORMAL_MEM;
 
        /* Kick the wait queue in case somebody was waiting if we actually
         * released something
         */
-       if (old_locks != vgadev->locks)
+       if ((old_lega_locks != vgadev->lega_locks) || (old_norm_locks != 
vgadev->norm_locks))
                wake_up_all(&vga_wait_queue);
 }
 
-int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible)
+int vga_get(struct pci_dev *pdev, unsigned int rsrc, unsigned int io_norm_cnt, 
unsigned int mem_norm_cnt,
+                                               int interruptible)
 {
        struct vga_device *vgadev, *conflict;
        unsigned long flags;
        wait_queue_t wait;
        int rc = 0;
+       bool released = false;
 
        vga_check_first_use();
        /* The one who calls us should check for this, but lets be sure... */
@@ -346,6 +385,27 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int 
interruptible)
                        break;
                }
                conflict = __vga_tryget(vgadev, rsrc);
+               if (conflict && (mem_norm_cnt || io_norm_cnt) && !released) {
+                       /* Release normal lock resources the same process has 
acquired
+                          before going to sleep. Note here rsrc must have 
legacy requests.
+                          If it doesn't (i.e. it has only normal requests), 
since it
+                          already had normal locks, there wouldn't be any 
conflict  */
+                       if (!(vgadev->io_norm_lock_cnt -= io_norm_cnt))
+                               vgadev->norm_locks &= ~VGA_RSRC_NORMAL_IO;
+                       if (!(vgadev->mem_norm_lock_cnt -= mem_norm_cnt))
+                               vgadev->norm_locks &= ~VGA_RSRC_NORMAL_MEM;
+                       released = true;
+               }
+               if (!conflict && released) {
+                       /* Restore released normal lock resources before 
proceeding.
+                          Note since legay requests are granted now, there 
shouldn't
+                          be any problem of restoring normal lock resources 
without
+                          arbitration  */
+                       if (vgadev->io_norm_lock_cnt += io_norm_cnt)
+                               vgadev->norm_locks |= VGA_RSRC_NORMAL_IO;
+                       if (vgadev->mem_norm_lock_cnt += mem_norm_cnt)
+                               vgadev->norm_locks |= VGA_RSRC_NORMAL_MEM;
+               }
                spin_unlock_irqrestore(&vga_lock, flags);
                if (conflict == NULL)
                        break;
@@ -471,9 +531,9 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
         */
        pci_read_config_word(pdev, PCI_COMMAND, &cmd);
        if (cmd & PCI_COMMAND_IO)
-               vgadev->owns |= VGA_RSRC_LEGACY_IO;
+               vgadev->owns |= VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO;
        if (cmd & PCI_COMMAND_MEMORY)
-               vgadev->owns |= VGA_RSRC_LEGACY_MEM;
+               vgadev->owns |= VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM;
 
        /* Check if VGA cycles can get down to us */
        bus = pdev->bus;
@@ -503,11 +563,12 @@ static bool vga_arbiter_add_pci_device(struct pci_dev 
*pdev)
        /* Add to the list */
        list_add(&vgadev->list, &vga_list);
        vga_count++;
-       pr_info("vgaarb: device added: PCI:%s,decodes=%s,owns=%s,locks=%s\n",
+       pr_info("vgaarb: device added: 
PCI:%s,decodes=%s,owns=%s,legalocks=%s,normlocks=%s\n",
                pci_name(pdev),
-               vga_iostate_to_str(vgadev->decodes),
-               vga_iostate_to_str(vgadev->owns),
-               vga_iostate_to_str(vgadev->locks));
+               vga_iostate_to_str[vgadev->decodes],
+               vga_iostate_to_str[vgadev->owns],
+               vga_iostate_to_str[vgadev->lega_locks],
+               vga_iostate_to_str[vgadev->norm_locks]);
 
        spin_unlock_irqrestore(&vga_lock, flags);
        return true;
@@ -566,10 +627,9 @@ static inline void vga_update_device_decodes(struct 
vga_device *vgadev,
 
        pr_info("vgaarb: device changed decodes: 
PCI:%s,olddecodes=%s,decodes=%s:owns=%s\n",
                pci_name(vgadev->pdev),
-               vga_iostate_to_str(old_decodes),
-               vga_iostate_to_str(vgadev->decodes),
-               vga_iostate_to_str(vgadev->owns));
-
+               vga_iostate_to_str[old_decodes],
+               vga_iostate_to_str[vgadev->decodes],
+               vga_iostate_to_str[vgadev->owns]);
 
        /* if we own the decodes we should move them along to
           another card */
@@ -718,8 +778,10 @@ EXPORT_SYMBOL(vga_client_register);
  */
 struct vga_arb_user_card {
        struct pci_dev *pdev;
-       unsigned int mem_cnt;
-       unsigned int io_cnt;
+       unsigned int mem_lega_cnt;
+       unsigned int io_lega_cnt;
+       unsigned int mem_norm_cnt;
+       unsigned int io_norm_cnt;
 };
 
 struct vga_arb_private {
@@ -797,12 +859,14 @@ static ssize_t vga_arb_read(struct file *file, char 
__user * buf,
 
        /* Fill the buffer with infos */
        len = snprintf(lbuf, 1024,
-                      "count:%d,PCI:%s,decodes=%s,owns=%s,locks=%s(%d:%d)\n",
+                      
"count:%d,PCI:%s,decodes=%s,owns=%s,legalocks=%s(%d:%d),normlocks=%s(%d:%d)\n",
                       vga_decode_count, pci_name(pdev),
-                      vga_iostate_to_str(vgadev->decodes),
-                      vga_iostate_to_str(vgadev->owns),
-                      vga_iostate_to_str(vgadev->locks),
-                      vgadev->io_lock_cnt, vgadev->mem_lock_cnt);
+                      vga_iostate_to_str[vgadev->decodes],
+                      vga_iostate_to_str[vgadev->owns],
+                      vga_iostate_to_str[vgadev->lega_locks],
+                      vgadev->io_lega_lock_cnt, vgadev->mem_lega_lock_cnt,
+                      vga_iostate_to_str[vgadev->norm_locks],
+                      vgadev->io_norm_lock_cnt, vgadev->mem_norm_lock_cnt);
 
        spin_unlock_irqrestore(&vga_lock, flags);
 done:
@@ -825,7 +889,7 @@ static ssize_t vga_arb_write(struct file *file, const char 
__user * buf,
                             size_t count, loff_t *ppos)
 {
        struct vga_arb_private *priv = file->private_data;
-       struct vga_arb_user_card *uc = NULL;
+       struct vga_arb_user_card *uc = NULL, *card = NULL;
        struct pci_dev *pdev;
 
        unsigned int io_state;
@@ -869,19 +933,27 @@ static ssize_t vga_arb_write(struct file *file, const 
char __user * buf,
                        goto done;
                }
 
-               vga_get_uninterruptible(pdev, io_state);
-
-               /* Update the client's locks lists... */
                for (i = 0; i < MAX_USER_CARDS; i++) {
                        if (priv->cards[i].pdev == pdev) {
-                               if (io_state & VGA_RSRC_LEGACY_IO)
-                                       priv->cards[i].io_cnt++;
-                               if (io_state & VGA_RSRC_LEGACY_MEM)
-                                       priv->cards[i].mem_cnt++;
+                               card = &priv->cards[i];
                                break;
                        }
                }
 
+               /* card->io_norm_cnt and card->mem_norm_cnt are non-legacy 
access lock
+                  resource the user has acquired. */
+               vga_get_uninterruptible(pdev, io_state, card->io_norm_cnt, 
card->mem_norm_cnt);
+
+               /* Update the client's locks lists... */
+               if (io_state & VGA_RSRC_LEGACY_IO)
+                       card->io_lega_cnt++;
+               if (io_state & VGA_RSRC_LEGACY_MEM)
+                       card->mem_lega_cnt++;
+               if (io_state & VGA_RSRC_NORMAL_IO)
+                       card->io_norm_cnt++;
+               if (io_state & VGA_RSRC_NORMAL_MEM)
+                       card->mem_norm_cnt++;
+
                ret_val = count;
                goto done;
        } else if (strncmp(curr_pos, "unlock ", 7) == 0) {
@@ -891,7 +963,8 @@ static ssize_t vga_arb_write(struct file *file, const char 
__user * buf,
                pr_debug("client 0x%p called 'unlock'\n", priv);
 
                if (strncmp(curr_pos, "all", 3) == 0)
-                       io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
+                       io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
+                               VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
                else {
                        if (!vga_str_to_iostate
                            (curr_pos, remaining, &io_state)) {
@@ -916,21 +989,41 @@ static ssize_t vga_arb_write(struct file *file, const 
char __user * buf,
                                uc = &priv->cards[i];
                }
 
-               if (!uc)
-                       return -EINVAL;
+               if (!uc) {
+                       ret_val = -ENODEV;
+                       goto done;
+               }
 
-               if (io_state & VGA_RSRC_LEGACY_IO && uc->io_cnt == 0)
-                       return -EINVAL;
+               if (io_state & VGA_RSRC_LEGACY_IO && uc->io_lega_cnt == 0) {
+                       ret_val = -EINVAL;
+                       goto done;
+               }
 
-               if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_cnt == 0)
-                       return -EINVAL;
+               if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_lega_cnt == 0) {
+                       ret_val = -EINVAL;
+                       goto done;
+               }
+
+               if (io_state & VGA_RSRC_NORMAL_IO && uc->io_norm_cnt == 0) {
+                       ret_val = -EINVAL;
+                       goto done;
+               }
+
+               if (io_state & VGA_RSRC_NORMAL_MEM && uc->mem_norm_cnt == 0) {
+                       ret_val = -EINVAL;
+                       goto done;
+               }
 
                vga_put(pdev, io_state);
 
                if (io_state & VGA_RSRC_LEGACY_IO)
-                       uc->io_cnt--;
+                       uc->io_lega_cnt--;
                if (io_state & VGA_RSRC_LEGACY_MEM)
-                       uc->mem_cnt--;
+                       uc->mem_lega_cnt--;
+               if (io_state & VGA_RSRC_NORMAL_IO)
+                       uc->io_norm_cnt--;
+               if (io_state & VGA_RSRC_NORMAL_MEM)
+                       uc->mem_norm_cnt--;
 
                ret_val = count;
                goto done;
@@ -957,14 +1050,18 @@ static ssize_t vga_arb_write(struct file *file, const 
char __user * buf,
                        goto done;
                }
 
-               if (vga_tryget(pdev, io_state)) {
+               if (!vga_tryget(pdev, io_state)) {
                        /* Update the client's locks lists... */
                        for (i = 0; i < MAX_USER_CARDS; i++) {
                                if (priv->cards[i].pdev == pdev) {
                                        if (io_state & VGA_RSRC_LEGACY_IO)
-                                               priv->cards[i].io_cnt++;
+                                               priv->cards[i].io_lega_cnt++;
                                        if (io_state & VGA_RSRC_LEGACY_MEM)
-                                               priv->cards[i].mem_cnt++;
+                                               priv->cards[i].mem_lega_cnt++;
+                                       if (io_state & VGA_RSRC_NORMAL_IO)
+                                               priv->cards[i].io_norm_cnt++;
+                                       if (io_state & VGA_RSRC_NORMAL_MEM)
+                                               priv->cards[i].mem_norm_cnt++;
                                        break;
                                }
                        }
@@ -1028,8 +1125,10 @@ static ssize_t vga_arb_write(struct file *file, const 
char __user * buf,
                                break;
                        if (priv->cards[i].pdev == NULL) {
                                priv->cards[i].pdev = pdev;
-                               priv->cards[i].io_cnt = 0;
-                               priv->cards[i].mem_cnt = 0;
+                               priv->cards[i].io_lega_cnt = 0;
+                               priv->cards[i].mem_lega_cnt = 0;
+                               priv->cards[i].io_norm_cnt = 0;
+                               priv->cards[i].mem_norm_cnt = 0;
                                break;
                        }
                }
@@ -1108,8 +1207,10 @@ static int vga_arb_open(struct inode *inode, struct file 
*file)
        /* Set the client' lists of locks */
        priv->target = vga_default_device(); /* Maybe this is still null! */
        priv->cards[0].pdev = priv->target;
-       priv->cards[0].io_cnt = 0;
-       priv->cards[0].mem_cnt = 0;
+       priv->cards[0].io_lega_cnt = 0;
+       priv->cards[0].mem_lega_cnt = 0;
+       priv->cards[0].io_norm_cnt = 0;
+       priv->cards[0].mem_norm_cnt = 0;
 
 
        return 0;
@@ -1133,12 +1234,16 @@ static int vga_arb_release(struct inode *inode, struct 
file *file)
                uc = &priv->cards[i];
                if (uc->pdev == NULL)
                        continue;
-               pr_debug("uc->io_cnt == %d, uc->mem_cnt == %d\n",
-                        uc->io_cnt, uc->mem_cnt);
-               while (uc->io_cnt--)
+               pr_debug("uc->io_lega_cnt == %d, uc->mem_lega_cnt == %d, 
uc->io_norm_cnt == %d, uc->mem_norm_cnt == %d\n",
+                        uc->io_lega_cnt, uc->mem_lega_cnt, uc->io_norm_cnt, 
uc->mem_norm_cnt);
+               while (uc->io_lega_cnt--)
                        vga_put(uc->pdev, VGA_RSRC_LEGACY_IO);
-               while (uc->mem_cnt--)
+               while (uc->mem_lega_cnt--)
                        vga_put(uc->pdev, VGA_RSRC_LEGACY_MEM);
+               while (uc->io_norm_cnt--)
+                       vga_put(uc->pdev, VGA_RSRC_NORMAL_IO);
+               while (uc->mem_norm_cnt--)
+                       vga_put(uc->pdev, VGA_RSRC_NORMAL_MEM);
        }
        spin_unlock_irqrestore(&vga_user_lock, flags);
 
diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h
index c9a9759..fed8905 100644
--- a/include/linux/vgaarb.h
+++ b/include/linux/vgaarb.h
@@ -38,8 +38,10 @@
 #define VGA_RSRC_LEGACY_MEM    0x02
 #define VGA_RSRC_LEGACY_MASK   (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM)
 /* Non-legacy access */
-#define VGA_RSRC_NORMAL_IO     0x04
-#define VGA_RSRC_NORMAL_MEM    0x08
+#define VGA_RSRC_LEGACY_TO_NORMAL_SHIFT 2
+#define VGA_RSRC_NORMAL_IO     (VGA_RSRC_LEGACY_IO << 
VGA_RSRC_LEGACY_TO_NORMAL_SHIFT)
+#define VGA_RSRC_NORMAL_MEM    (VGA_RSRC_LEGACY_MEM << 
VGA_RSRC_LEGACY_TO_NORMAL_SHIFT)
+#define VGA_RSRC_NORMAL_MASK   (VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)
 
 /* Passing that instead of a pci_dev to use the system "default"
  * device, that is the one used by vgacon. Archs will probably
@@ -93,8 +95,8 @@ extern void vga_set_legacy_decoding(struct pci_dev *pdev,
  *     Nested calls are supported (a per-resource counter is maintained)
  */
 
-extern int vga_get(struct pci_dev *pdev, unsigned int rsrc,
-                                                                               
        int interruptible);
+extern int vga_get(struct pci_dev *pdev, unsigned int rsrc, unsigned int 
io_norm_cnt,
+                               unsigned int mem_norm_cnt, int interruptible);
 
 /**
  *     vga_get_interruptible
@@ -102,10 +104,10 @@ extern int vga_get(struct pci_dev *pdev, unsigned int 
rsrc,
  *     Shortcut to vga_get
  */
 
-static inline int vga_get_interruptible(struct pci_dev *pdev,
-                                       unsigned int rsrc)
+static inline int vga_get_interruptible(struct pci_dev *pdev, unsigned int 
rsrc,
+                               unsigned int io_norm_cnt, unsigned int 
mem_norm_cnt)
 {
-       return vga_get(pdev, rsrc, 1);
+       return vga_get(pdev, rsrc, io_norm_cnt, mem_norm_cnt, 1);
 }
 
 /**
@@ -114,10 +116,10 @@ static inline int vga_get_interruptible(struct pci_dev 
*pdev,
  *     Shortcut to vga_get
  */
 
-static inline int vga_get_uninterruptible(struct pci_dev *pdev,
-                                         unsigned int rsrc)
+static inline int vga_get_uninterruptible(struct pci_dev *pdev, unsigned int 
rsrc,
+                               unsigned int io_norm_cnt, unsigned int 
mem_norm_cnt)
 {
-       return vga_get(pdev, rsrc, 0);
+       return vga_get(pdev, rsrc, io_norm_cnt, mem_norm_cnt, 0);
 }
 
 /**
-- 
1.5.6.5

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to