Staging: vme: Add ca91cx42 rmw support

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

Signed-off-by: Martyn Welch <martyn.welch@ge.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Martyn Welch 2010-02-18 15:13:38 +00:00 committed by Greg Kroah-Hartman
parent 21e0cf6d2e
commit 04e10e15f9
3 changed files with 64 additions and 85 deletions

View File

@ -56,7 +56,6 @@ Tempe (tsi148)
Universe II (ca91c142) Universe II (ca91c142)
---------------------- ----------------------
- RMW transactions unsupported.
- Mailboxes unsupported. - Mailboxes unsupported.
- Error Detection. - Error Detection.
- Control of prefetch size, threshold. - Control of prefetch size, threshold.

View File

@ -904,6 +904,60 @@ ssize_t ca91cx42_master_write(struct vme_master_resource *image, void *buf,
return retval; 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, int ca91cx42_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
struct vme_dma_attr *dest, size_t count) 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_set = ca91cx42_master_set;
ca91cx42_bridge->master_read = ca91cx42_master_read; ca91cx42_bridge->master_read = ca91cx42_master_read;
ca91cx42_bridge->master_write = ca91cx42_master_write; ca91cx42_bridge->master_write = ca91cx42_master_write;
#if 0
ca91cx42_bridge->master_rmw = ca91cx42_master_rmw; ca91cx42_bridge->master_rmw = ca91cx42_master_rmw;
#endif
ca91cx42_bridge->dma_list_add = ca91cx42_dma_list_add; ca91cx42_bridge->dma_list_add = ca91cx42_dma_list_add;
ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec; ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec;
ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty; ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty;
@ -1832,88 +1884,6 @@ module_exit(ca91cx42_exit);
#if 0 #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 ca91cx42_set_arbiter(vmeArbiterCfg_t *vmeArb)
{ {
int temp_ctl = 0; int temp_ctl = 0;

View File

@ -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_VCT_MBLT (1<<8)
#define CA91CX42_LSI_CTL_LAS (1<<0) #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 * LMISC Register