Staging: vme: Add location monitor support for ca91cx42
authorMartyn Welch <martyn.welch@ge.com>
Thu, 18 Feb 2010 15:13:19 +0000 (15:13 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 4 Mar 2010 00:43:01 +0000 (16:43 -0800)
Signed-off-by: Martyn Welch <martyn.welch@ge.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/vme/TODO
drivers/staging/vme/bridges/vme_ca91cx42.c
drivers/staging/vme/bridges/vme_ca91cx42.h

index 00c0ddc..723b67b 100644 (file)
@@ -58,7 +58,6 @@ Universe II (ca91c142)
 
 - DMA unsupported.
 - RMW transactions unsupported.
-- Location Monitors unsupported.
 - Mailboxes unsupported.
 - Error Detection.
 - Control of prefetch size, threshold.
index ae2f69c..aeb11d5 100644 (file)
@@ -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;
-}
 
 
 
index df10502..b9b6308 100644 (file)
@@ -491,6 +491,19 @@ static const int CA91CX42_LINT_LM[] = { CA91CX42_LINT_LM0, CA91CX42_LINT_LM1,
 #define CA91CX42_VSI_CTL_LAS_PCI_IO    (1<<0)
 #define CA91CX42_VSI_CTL_LAS_PCI_CONF  (1<<1)
 
+/* LM_CTL Register
+ * offset  F64
+ */
+#define CA91CX42_LM_CTL_EN             (1<<31)
+#define CA91CX42_LM_CTL_PGM            (1<<23)
+#define CA91CX42_LM_CTL_DATA           (1<<22)
+#define CA91CX42_LM_CTL_SUPR           (1<<21)
+#define CA91CX42_LM_CTL_NPRIV          (1<<20)
+#define CA91CX42_LM_CTL_AS_M           (5<<16)
+#define CA91CX42_LM_CTL_AS_A16         0
+#define CA91CX42_LM_CTL_AS_A24         (1<<16)
+#define CA91CX42_LM_CTL_AS_A32         (1<<17)
+
 /*
  * VRAI_CTL Register
  * offset  F70