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
