Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 04e10e15 authored by Martyn Welch's avatar Martyn Welch Committed by Greg Kroah-Hartman
Browse files

Staging: vme: Add ca91cx42 rmw support



Add support for Master Read-Modify-Write cycles on the ca91cx42.

Signed-off-by: default avatarMartyn Welch <martyn.welch@ge.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 21e0cf6d
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ Tempe (tsi148)
Universe II (ca91c142)
----------------------

- RMW transactions unsupported.
- Mailboxes unsupported.
- Error Detection.
- Control of prefetch size, threshold.
+54 −84
Original line number Diff line number Diff line
@@ -904,6 +904,60 @@ ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf,
	return retval;
}

unsigned int ca91cx42_master_rmw(struct vme_master_resource *image,
	unsigned int mask, unsigned int compare, unsigned int swap,
	loff_t offset)
{
	u32 pci_addr, result;
	int i;
	struct ca91cx42_driver *bridge;
	struct device *dev;

	bridge = image->parent->driver_priv;
	dev = image->parent->parent;

	/* Find the PCI address that maps to the desired VME address */
	i = image->number;

	/* Locking as we can only do one of these at a time */
	mutex_lock(&(bridge->vme_rmw));

	/* Lock image */
	spin_lock(&(image->lock));

	pci_addr = (u32)image->kern_base + offset;

	/* Address must be 4-byte aligned */
	if (pci_addr & 0x3) {
		dev_err(dev, "RMW Address not 4-byte aligned\n");
		return -EINVAL;
	}

	/* Ensure RMW Disabled whilst configuring */
	iowrite32(0, bridge->base + SCYC_CTL);

	/* Configure registers */
	iowrite32(mask, bridge->base + SCYC_EN);
	iowrite32(compare, bridge->base + SCYC_CMP);
	iowrite32(swap, bridge->base + SCYC_SWP);
	iowrite32(pci_addr, bridge->base + SCYC_ADDR);

	/* Enable RMW */
	iowrite32(CA91CX42_SCYC_CTL_CYC_RMW, bridge->base + SCYC_CTL);

	/* Kick process off with a read to the required address. */
	result = ioread32(image->kern_base + offset);

	/* Disable RMW */
	iowrite32(0, bridge->base + SCYC_CTL);

	spin_unlock(&(image->lock));

	mutex_unlock(&(bridge->vme_rmw));

	return result;
}

int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
	struct vme_dma_attr *dest, size_t count)
{
@@ -1640,9 +1694,7 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	ca91cx42_bridge->master_set = ca91cx42_master_set;
	ca91cx42_bridge->master_read = ca91cx42_master_read;
	ca91cx42_bridge->master_write = ca91cx42_master_write;
#if 0
	ca91cx42_bridge->master_rmw = ca91cx42_master_rmw;
#endif
	ca91cx42_bridge->dma_list_add = ca91cx42_dma_list_add;
	ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec;
	ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty;
@@ -1832,88 +1884,6 @@ module_exit(ca91cx42_exit);

#if 0

int ca91cx42_master_rmw(vmeRmwCfg_t *vmeRmw)
{
	int temp_ctl = 0;
	int tempBS = 0;
	int tempBD = 0;
	int tempTO = 0;
	int vmeBS = 0;
	int vmeBD = 0;
	int *rmw_pci_data_ptr = NULL;
	int *vaDataPtr = NULL;
	int i;
	vmeOutWindowCfg_t vmeOut;
	if (vmeRmw->maxAttempts < 1) {
		return -EINVAL;
	}
	if (vmeRmw->targetAddrU) {
		return -EINVAL;
	}
	/* Find the PCI address that maps to the desired VME address */
	for (i = 0; i < 8; i++) {
		temp_ctl = ioread32(bridge->base +
			CA91CX42_LSI_CTL[i]);
		if ((temp_ctl & 0x80000000) == 0) {
			continue;
		}
		memset(&vmeOut, 0, sizeof(vmeOut));
		vmeOut.windowNbr = i;
		ca91cx42_get_out_bound(&vmeOut);
		if (vmeOut.addrSpace != vmeRmw->addrSpace) {
			continue;
		}
		tempBS = ioread32(bridge->base + CA91CX42_LSI_BS[i]);
		tempBD = ioread32(bridge->base + CA91CX42_LSI_BD[i]);
		tempTO = ioread32(bridge->base + CA91CX42_LSI_TO[i]);
		vmeBS = tempBS + tempTO;
		vmeBD = tempBD + tempTO;
		if ((vmeRmw->targetAddr >= vmeBS) &&
		    (vmeRmw->targetAddr < vmeBD)) {
			rmw_pci_data_ptr =
			    (int *)(tempBS + (vmeRmw->targetAddr - vmeBS));
			vaDataPtr =
			    (int *)(out_image_va[i] +
				    (vmeRmw->targetAddr - vmeBS));
			break;
		}
	}

	/* If no window - fail. */
	if (rmw_pci_data_ptr == NULL) {
		return -EINVAL;
	}
	/* Setup the RMW registers. */
	iowrite32(0, bridge->base + SCYC_CTL);
	iowrite32(SWIZZLE(vmeRmw->enableMask), bridge->base + SCYC_EN);
	iowrite32(SWIZZLE(vmeRmw->compareData), bridge->base +
		SCYC_CMP);
	iowrite32(SWIZZLE(vmeRmw->swapData), bridge->base + SCYC_SWP);
	iowrite32((int)rmw_pci_data_ptr, bridge->base + SCYC_ADDR);
	iowrite32(1, bridge->base + SCYC_CTL);

	/* Run the RMW cycle until either success or max attempts. */
	vmeRmw->numAttempts = 1;
	while (vmeRmw->numAttempts <= vmeRmw->maxAttempts) {

		if ((ioread32(vaDataPtr) & vmeRmw->enableMask) ==
		    (vmeRmw->swapData & vmeRmw->enableMask)) {

			iowrite32(0, bridge->base + SCYC_CTL);
			break;

		}
		vmeRmw->numAttempts++;
	}

	/* If no success, set num Attempts to be greater than max attempts */
	if (vmeRmw->numAttempts > vmeRmw->maxAttempts) {
		vmeRmw->numAttempts = vmeRmw->maxAttempts + 1;
	}

	return 0;
}

int ca91cx42_set_arbiter(vmeArbiterCfg_t *vmeArb)
{
	int temp_ctl = 0;
+10 −0
Original line number Diff line number Diff line
@@ -316,6 +316,16 @@ static const int CA91CX42_VSI_TO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO,
#define CA91CX42_LSI_CTL_VCT_MBLT	(1<<8)
#define CA91CX42_LSI_CTL_LAS		(1<<0)

/*
 * SCYC_CTL Register
 * offset 178
 */
#define CA91CX42_SCYC_CTL_LAS_PCIMEM	0
#define CA91CX42_SCYC_CTL_LAS_PCIIO	(1<<2)

#define CA91CX42_SCYC_CTL_CYC_M		(3<<0)
#define CA91CX42_SCYC_CTL_CYC_RMW	(1<<0)
#define CA91CX42_SCYC_CTL_CYC_ADOH	(1<<1)

/*
 * LMISC Register