Commit ba5d141b authored by Alexandre Bounine's avatar Alexandre Bounine Committed by Linus Torvalds

rapidio/tsi721: add check for overlapped IB window mappings

Add check for attempts to request mapping of inbound RapidIO address
space that overlaps with existing active mapping windows.

Tsi721 device does not support overlapped inbound windows and SRIO
address decoding behavior is not defined in such cases.

This patch is applicable to kernel versions starting from v3.7.
Signed-off-by: default avatarAlexandre Bounine <alexandre.bounine@idt.com>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Aurelien Jacquiot <a-jacquiot@ti.com>
Cc: Andre van Herk <andre.van.herk@prodrive-technologies.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 174f1a71
...@@ -885,26 +885,52 @@ static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, ...@@ -885,26 +885,52 @@ static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
u64 rstart, u32 size, u32 flags) u64 rstart, u32 size, u32 flags)
{ {
struct tsi721_device *priv = mport->priv; struct tsi721_device *priv = mport->priv;
int i; int i, avail = -1;
u32 regval; u32 regval;
struct tsi721_ib_win *ib_win;
int ret = -EBUSY;
if (!is_power_of_2(size) || size < 0x1000 || if (!is_power_of_2(size) || size < 0x1000 ||
((u64)lstart & (size - 1)) || (rstart & (size - 1))) ((u64)lstart & (size - 1)) || (rstart & (size - 1)))
return -EINVAL; return -EINVAL;
/* Search for free inbound translation window */ spin_lock(&priv->win_lock);
/*
* Scan for overlapping with active regions and mark the first available
* IB window at the same time.
*/
for (i = 0; i < TSI721_IBWIN_NUM; i++) { for (i = 0; i < TSI721_IBWIN_NUM; i++) {
regval = ioread32(priv->regs + TSI721_IBWIN_LB(i)); ib_win = &priv->ib_win[i];
if (!(regval & TSI721_IBWIN_LB_WEN)) if (!ib_win->active) {
if (avail == -1) {
avail = i;
ret = 0;
}
} else if (rstart < (ib_win->rstart + ib_win->size) &&
(rstart + size) > ib_win->rstart) {
ret = -EFAULT;
break; break;
}
} }
if (i >= TSI721_IBWIN_NUM) { if (ret)
dev_err(&priv->pdev->dev, goto err_out;
"Unable to find free inbound window\n"); i = avail;
return -EBUSY;
/* Sanity check: available IB window must be disabled at this point */
regval = ioread32(priv->regs + TSI721_IBWIN_LB(i));
if (WARN_ON(regval & TSI721_IBWIN_LB_WEN)) {
ret = -EIO;
goto err_out;
} }
ib_win = &priv->ib_win[i];
ib_win->active = true;
ib_win->rstart = rstart;
ib_win->lstart = lstart;
ib_win->size = size;
spin_unlock(&priv->win_lock);
iowrite32(TSI721_IBWIN_SIZE(size) << 8, iowrite32(TSI721_IBWIN_SIZE(size) << 8,
priv->regs + TSI721_IBWIN_SZ(i)); priv->regs + TSI721_IBWIN_SZ(i));
...@@ -920,6 +946,9 @@ static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, ...@@ -920,6 +946,9 @@ static int tsi721_rio_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
i, rstart, (unsigned long long)lstart); i, rstart, (unsigned long long)lstart);
return 0; return 0;
err_out:
spin_unlock(&priv->win_lock);
return ret;
} }
/** /**
...@@ -931,25 +960,25 @@ static void tsi721_rio_unmap_inb_mem(struct rio_mport *mport, ...@@ -931,25 +960,25 @@ static void tsi721_rio_unmap_inb_mem(struct rio_mport *mport,
dma_addr_t lstart) dma_addr_t lstart)
{ {
struct tsi721_device *priv = mport->priv; struct tsi721_device *priv = mport->priv;
struct tsi721_ib_win *ib_win;
int i; int i;
u64 addr;
u32 regval;
/* Search for matching active inbound translation window */ /* Search for matching active inbound translation window */
spin_lock(&priv->win_lock);
for (i = 0; i < TSI721_IBWIN_NUM; i++) { for (i = 0; i < TSI721_IBWIN_NUM; i++) {
regval = ioread32(priv->regs + TSI721_IBWIN_LB(i)); ib_win = &priv->ib_win[i];
if (regval & TSI721_IBWIN_LB_WEN) { if (ib_win->active && ib_win->lstart == lstart) {
regval = ioread32(priv->regs + TSI721_IBWIN_TUA(i)); iowrite32(0, priv->regs + TSI721_IBWIN_LB(i));
addr = (u64)regval << 32; ib_win->active = false;
regval = ioread32(priv->regs + TSI721_IBWIN_TLA(i)); break;
addr |= regval & TSI721_IBWIN_TLA_ADD;
if (addr == (u64)lstart) {
iowrite32(0, priv->regs + TSI721_IBWIN_LB(i));
break;
}
} }
} }
spin_unlock(&priv->win_lock);
if (i == TSI721_IBWIN_NUM)
dev_err(&priv->pdev->dev,
"IB window mapped to %llx not found\n",
(unsigned long long)lstart);
} }
/** /**
...@@ -966,6 +995,7 @@ static void tsi721_init_sr2pc_mapping(struct tsi721_device *priv) ...@@ -966,6 +995,7 @@ static void tsi721_init_sr2pc_mapping(struct tsi721_device *priv)
/* Disable all SR2PC inbound windows */ /* Disable all SR2PC inbound windows */
for (i = 0; i < TSI721_IBWIN_NUM; i++) for (i = 0; i < TSI721_IBWIN_NUM; i++)
iowrite32(0, priv->regs + TSI721_IBWIN_LB(i)); iowrite32(0, priv->regs + TSI721_IBWIN_LB(i));
spin_lock_init(&priv->win_lock);
} }
/** /**
......
...@@ -808,6 +808,13 @@ struct msix_irq { ...@@ -808,6 +808,13 @@ struct msix_irq {
}; };
#endif /* CONFIG_PCI_MSI */ #endif /* CONFIG_PCI_MSI */
struct tsi721_ib_win {
u64 rstart;
u32 size;
dma_addr_t lstart;
bool active;
};
struct tsi721_device { struct tsi721_device {
struct pci_dev *pdev; struct pci_dev *pdev;
struct rio_mport *mport; struct rio_mport *mport;
...@@ -843,6 +850,10 @@ struct tsi721_device { ...@@ -843,6 +850,10 @@ struct tsi721_device {
/* Outbound Messaging */ /* Outbound Messaging */
int omsg_init[TSI721_OMSG_CHNUM]; int omsg_init[TSI721_OMSG_CHNUM];
struct tsi721_omsg_ring omsg_ring[TSI721_OMSG_CHNUM]; struct tsi721_omsg_ring omsg_ring[TSI721_OMSG_CHNUM];
/* Inbound Mapping Windows */
struct tsi721_ib_win ib_win[TSI721_IBWIN_NUM];
spinlock_t win_lock;
}; };
#ifdef CONFIG_RAPIDIO_DMA_ENGINE #ifdef CONFIG_RAPIDIO_DMA_ENGINE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment