diff options
author | Martyn Welch <martyn.welch@ge.com> | 2010-02-18 15:13:19 +0000 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-03 16:43:01 -0800 |
commit | 2b82beb8c1bc81b3dde69d16cacbc22546681acf (patch) | |
tree | 39c2e20f81bf2865fa8539629bf137e33e08d3a6 /drivers/staging/vme/bridges/vme_ca91cx42.c | |
parent | 8fafb47638012d93134d0ff38adcc5fc661beeb1 (diff) | |
download | op-kernel-dev-2b82beb8c1bc81b3dde69d16cacbc22546681acf.zip op-kernel-dev-2b82beb8c1bc81b3dde69d16cacbc22546681acf.tar.gz |
Staging: vme: Add location monitor support for ca91cx42
Signed-off-by: Martyn Welch <martyn.welch@ge.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/vme/bridges/vme_ca91cx42.c')
-rw-r--r-- | drivers/staging/vme/bridges/vme_ca91cx42.c | 272 |
1 files changed, 200 insertions, 72 deletions
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c index ae2f69c..aeb11d5 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.c +++ b/drivers/staging/vme/bridges/vme_ca91cx42.c @@ -899,6 +899,206 @@ ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf, return retval; } +/* + * All 4 location monitors reside at the same base - this is therefore a + * system wide configuration. + * + * This does not enable the LM monitor - that should be done when the first + * callback is attached and disabled when the last callback is removed. + */ +int ca91cx42_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base, + vme_address_t aspace, vme_cycle_t cycle) +{ + u32 temp_base, lm_ctl = 0; + int i; + struct ca91cx42_driver *bridge; + struct device *dev; + + bridge = lm->parent->driver_priv; + dev = lm->parent->parent; + + /* Check the alignment of the location monitor */ + temp_base = (u32)lm_base; + if (temp_base & 0xffff) { + dev_err(dev, "Location monitor must be aligned to 64KB " + "boundary"); + return -EINVAL; + } + + mutex_lock(&(lm->mtx)); + + /* If we already have a callback attached, we can't move it! */ + for (i = 0; i < lm->monitors; i++) { + if (bridge->lm_callback[i] != NULL) { + mutex_unlock(&(lm->mtx)); + dev_err(dev, "Location monitor callback attached, " + "can't reset\n"); + return -EBUSY; + } + } + + switch (aspace) { + case VME_A16: + lm_ctl |= CA91CX42_LM_CTL_AS_A16; + break; + case VME_A24: + lm_ctl |= CA91CX42_LM_CTL_AS_A24; + break; + case VME_A32: + lm_ctl |= CA91CX42_LM_CTL_AS_A32; + break; + default: + mutex_unlock(&(lm->mtx)); + dev_err(dev, "Invalid address space\n"); + return -EINVAL; + break; + } + + if (cycle & VME_SUPER) + lm_ctl |= CA91CX42_LM_CTL_SUPR; + if (cycle & VME_USER) + lm_ctl |= CA91CX42_LM_CTL_NPRIV; + if (cycle & VME_PROG) + lm_ctl |= CA91CX42_LM_CTL_PGM; + if (cycle & VME_DATA) + lm_ctl |= CA91CX42_LM_CTL_DATA; + + iowrite32(lm_base, bridge->base + LM_BS); + iowrite32(lm_ctl, bridge->base + LM_CTL); + + mutex_unlock(&(lm->mtx)); + + return 0; +} + +/* Get configuration of the callback monitor and return whether it is enabled + * or disabled. + */ +int ca91cx42_lm_get(struct vme_lm_resource *lm, unsigned long long *lm_base, + vme_address_t *aspace, vme_cycle_t *cycle) +{ + u32 lm_ctl, enabled = 0; + struct ca91cx42_driver *bridge; + + bridge = lm->parent->driver_priv; + + mutex_lock(&(lm->mtx)); + + *lm_base = (unsigned long long)ioread32(bridge->base + LM_BS); + lm_ctl = ioread32(bridge->base + LM_CTL); + + if (lm_ctl & CA91CX42_LM_CTL_EN) + enabled = 1; + + if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A16) + *aspace = VME_A16; + if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A24) + *aspace = VME_A24; + if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A32) + *aspace = VME_A32; + + *cycle = 0; + if (lm_ctl & CA91CX42_LM_CTL_SUPR) + *cycle |= VME_SUPER; + if (lm_ctl & CA91CX42_LM_CTL_NPRIV) + *cycle |= VME_USER; + if (lm_ctl & CA91CX42_LM_CTL_PGM) + *cycle |= VME_PROG; + if (lm_ctl & CA91CX42_LM_CTL_DATA) + *cycle |= VME_DATA; + + mutex_unlock(&(lm->mtx)); + + return enabled; +} + +/* + * Attach a callback to a specific location monitor. + * + * Callback will be passed the monitor triggered. + */ +int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, + void (*callback)(int)) +{ + u32 lm_ctl, tmp; + struct ca91cx42_driver *bridge; + struct device *dev; + + bridge = lm->parent->driver_priv; + dev = lm->parent->parent; + + mutex_lock(&(lm->mtx)); + + /* Ensure that the location monitor is configured - need PGM or DATA */ + lm_ctl = ioread32(bridge->base + LM_CTL); + if ((lm_ctl & (CA91CX42_LM_CTL_PGM | CA91CX42_LM_CTL_DATA)) == 0) { + mutex_unlock(&(lm->mtx)); + dev_err(dev, "Location monitor not properly configured\n"); + return -EINVAL; + } + + /* Check that a callback isn't already attached */ + if (bridge->lm_callback[monitor] != NULL) { + mutex_unlock(&(lm->mtx)); + dev_err(dev, "Existing callback attached\n"); + return -EBUSY; + } + + /* Attach callback */ + bridge->lm_callback[monitor] = callback; + + /* Enable Location Monitor interrupt */ + tmp = ioread32(bridge->base + LINT_EN); + tmp |= CA91CX42_LINT_LM[monitor]; + iowrite32(tmp, bridge->base + LINT_EN); + + /* Ensure that global Location Monitor Enable set */ + if ((lm_ctl & CA91CX42_LM_CTL_EN) == 0) { + lm_ctl |= CA91CX42_LM_CTL_EN; + iowrite32(lm_ctl, bridge->base + LM_CTL); + } + + mutex_unlock(&(lm->mtx)); + + return 0; +} + +/* + * Detach a callback function forn a specific location monitor. + */ +int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor) +{ + u32 tmp; + struct ca91cx42_driver *bridge; + + bridge = lm->parent->driver_priv; + + mutex_lock(&(lm->mtx)); + + /* Disable Location Monitor and ensure previous interrupts are clear */ + tmp = ioread32(bridge->base + LINT_EN); + tmp &= ~CA91CX42_LINT_LM[monitor]; + iowrite32(tmp, bridge->base + LINT_EN); + + iowrite32(CA91CX42_LINT_LM[monitor], + bridge->base + LINT_STAT); + + /* Detach callback */ + bridge->lm_callback[monitor] = NULL; + + /* If all location monitors disabled, disable global Location Monitor */ + if ((tmp & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 | + CA91CX42_LINT_LM3)) == 0) { + tmp = ioread32(bridge->base + LM_CTL); + tmp &= ~CA91CX42_LM_CTL_EN; + iowrite32(tmp, bridge->base + LM_CTL); + } + + mutex_unlock(&(lm->mtx)); + + return 0; +} + int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge) { u32 slot = 0; @@ -1190,12 +1390,10 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) #endif ca91cx42_bridge->irq_set = ca91cx42_irq_set; ca91cx42_bridge->irq_generate = ca91cx42_irq_generate; -#if 0 ca91cx42_bridge->lm_set = ca91cx42_lm_set; ca91cx42_bridge->lm_get = ca91cx42_lm_get; ca91cx42_bridge->lm_attach = ca91cx42_lm_attach; ca91cx42_bridge->lm_detach = ca91cx42_lm_detach; -#endif ca91cx42_bridge->slot_get = ca91cx42_slot_get; data = ioread32(ca91cx42_device->base + MISC_CTL); @@ -1786,77 +1984,7 @@ int ca91cx42_do_dma(vmeDmaPacket_t *vmeDma) return 0; } -int ca91cx42_lm_set(vmeLmCfg_t *vmeLm) -{ - int temp_ctl = 0; - if (vmeLm->addrU) - return -EINVAL; - - switch (vmeLm->addrSpace) { - case VME_A64: - case VME_USER3: - case VME_USER4: - return -EINVAL; - case VME_A16: - temp_ctl |= 0x00000; - break; - case VME_A24: - temp_ctl |= 0x10000; - break; - case VME_A32: - temp_ctl |= 0x20000; - break; - case VME_CRCSR: - temp_ctl |= 0x50000; - break; - case VME_USER1: - temp_ctl |= 0x60000; - break; - case VME_USER2: - temp_ctl |= 0x70000; - break; - } - - /* Disable while we are mucking around */ - iowrite32(0x00000000, bridge->base + LM_CTL); - - iowrite32(vmeLm->addr, bridge->base + LM_BS); - - /* Setup CTL register. */ - if (vmeLm->userAccessType & VME_SUPER) - temp_ctl |= 0x00200000; - if (vmeLm->userAccessType & VME_USER) - temp_ctl |= 0x00100000; - if (vmeLm->dataAccessType & VME_PROG) - temp_ctl |= 0x00800000; - if (vmeLm->dataAccessType & VME_DATA) - temp_ctl |= 0x00400000; - - - /* Write ctl reg and enable */ - iowrite32(0x80000000 | temp_ctl, bridge->base + LM_CTL); - temp_ctl = ioread32(bridge->base + LM_CTL); - - return 0; -} - -int ca91cx42_wait_lm(vmeLmCfg_t *vmeLm) -{ - unsigned long flags; - unsigned int tmp; - - spin_lock_irqsave(&lm_lock, flags); - spin_unlock_irqrestore(&lm_lock, flags); - if (tmp == 0) { - if (vmeLm->lmWait < 10) - vmeLm->lmWait = 10; - interruptible_sleep_on_timeout(&lm_queue, vmeLm->lmWait); - } - iowrite32(0x00000000, bridge->base + LM_CTL); - - return 0; -} |