[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