[PATCH] vgaarb: Introduce non-legacy access lock ("norm_locks")

Henry Zhao henry.zhao at oracle.com
Fri Jul 16 15:46:25 PDT 2010


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 <henry.zhao at oracle.com>
---
 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



More information about the xorg-devel mailing list