in hw/idt/ntb_hw_idt.c [1287:1343]
static int idt_ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
u64 addr, resource_size_t size)
{
struct idt_ntb_dev *ndev = to_ndev_ntb(ntb);
struct idt_mw_cfg *mw_cfg;
u32 data = 0, lutoff = 0;
if (pidx < 0 || ndev->peer_cnt <= pidx)
return -EINVAL;
if (widx < 0 || ndev->mw_cnt <= widx)
return -EINVAL;
/*
* Retrieve the memory window config to make sure the passed arguments
* fit it restrictions
*/
mw_cfg = &ndev->mws[widx];
if (!IS_ALIGNED(addr, mw_cfg->addr_align))
return -EINVAL;
if (!IS_ALIGNED(size, mw_cfg->size_align) || size > mw_cfg->size_max)
return -EINVAL;
/* DIR and LUT based translations are initialized differently */
if (mw_cfg->type == IDT_MW_DIR) {
const struct idt_ntb_bar *bar = &ntdata_tbl.bars[mw_cfg->bar];
u64 limit;
/* Set destination partition of translation */
data = idt_nt_read(ndev, bar->setup);
data = SET_FIELD(BARSETUP_TPART, data, ndev->peers[pidx].part);
idt_nt_write(ndev, bar->setup, data);
/* Set translation base address */
idt_nt_write(ndev, bar->ltbase, (u32)addr);
idt_nt_write(ndev, bar->utbase, (u32)(addr >> 32));
/* Set the custom BAR aperture limit */
limit = pci_bus_address(ntb->pdev, mw_cfg->bar) + size;
idt_nt_write(ndev, bar->limit, (u32)limit);
if (IS_FLD_SET(BARSETUP_TYPE, data, 64))
idt_nt_write(ndev, (bar + 1)->limit, (limit >> 32));
} else {
unsigned long irqflags;
/* Initialize corresponding LUT entry */
lutoff = SET_FIELD(LUTOFFSET_INDEX, 0, mw_cfg->idx) |
SET_FIELD(LUTOFFSET_BAR, 0, mw_cfg->bar);
data = SET_FIELD(LUTUDATA_PART, 0, ndev->peers[pidx].part) |
IDT_LUTUDATA_VALID;
spin_lock_irqsave(&ndev->lut_lock, irqflags);
idt_nt_write(ndev, IDT_NT_LUTOFFSET, lutoff);
idt_nt_write(ndev, IDT_NT_LUTLDATA, (u32)addr);
idt_nt_write(ndev, IDT_NT_LUTMDATA, (u32)(addr >> 32));
idt_nt_write(ndev, IDT_NT_LUTUDATA, data);
spin_unlock_irqrestore(&ndev->lut_lock, irqflags);
/* Limit address isn't specified since size is fixed for LUT */
}
return 0;
}