Skip to content

Commit 2be225f

Browse files
author
Fox Snowpatch
committed
1 parent 960c1fd commit 2be225f

File tree

7 files changed

+190
-13
lines changed

7 files changed

+190
-13
lines changed

arch/powerpc/include/asm/iommu.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct iommu_table_ops {
4646
long index, long npages,
4747
unsigned long uaddr,
4848
enum dma_data_direction direction,
49-
unsigned long attrs);
49+
unsigned long attrs, bool is_phys);
5050
#ifdef CONFIG_IOMMU_API
5151
/*
5252
* Exchanges existing TCE with new TCE plus direction bits;

arch/powerpc/kernel/iommu.c

Lines changed: 179 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
365365
/* Put the TCEs in the HW table */
366366
build_fail = tbl->it_ops->set(tbl, entry, npages,
367367
(unsigned long)page &
368-
IOMMU_PAGE_MASK(tbl), direction, attrs);
368+
IOMMU_PAGE_MASK(tbl), direction, attrs, false);
369369

370370
/* tbl->it_ops->set() only returns non-zero for transient errors.
371371
* Clean up the table bitmap in this case and return
@@ -539,7 +539,7 @@ int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
539539
/* Insert into HW table */
540540
build_fail = tbl->it_ops->set(tbl, entry, npages,
541541
vaddr & IOMMU_PAGE_MASK(tbl),
542-
direction, attrs);
542+
direction, attrs, false);
543543
if(unlikely(build_fail))
544544
goto failure;
545545

@@ -1201,7 +1201,15 @@ spapr_tce_blocked_iommu_attach_dev(struct iommu_domain *platform_domain,
12011201
* also sets the dma_api ops
12021202
*/
12031203
table_group = iommu_group_get_iommudata(grp);
1204+
1205+
if (old && old->type == IOMMU_DOMAIN_DMA) {
1206+
ret = table_group->ops->unset_window(table_group, 0);
1207+
if (ret)
1208+
goto exit;
1209+
}
1210+
12041211
ret = table_group->ops->take_ownership(table_group, dev);
1212+
exit:
12051213
iommu_group_put(grp);
12061214

12071215
return ret;
@@ -1260,13 +1268,182 @@ static struct iommu_group *spapr_tce_iommu_device_group(struct device *dev)
12601268
return hose->controller_ops.device_group(hose, pdev);
12611269
}
12621270

1271+
struct ppc64_domain {
1272+
struct iommu_domain domain;
1273+
struct device *device; /* Make it a list */
1274+
struct iommu_table *table;
1275+
spinlock_t list_lock;
1276+
struct rcu_head rcu;
1277+
};
1278+
1279+
static struct ppc64_domain *to_ppc64_domain(struct iommu_domain *dom)
1280+
{
1281+
return container_of(dom, struct ppc64_domain, domain);
1282+
}
1283+
1284+
static void spapr_tce_domain_free(struct iommu_domain *domain)
1285+
{
1286+
struct ppc64_domain *ppc64_domain = to_ppc64_domain(domain);
1287+
1288+
kfree(ppc64_domain);
1289+
}
1290+
1291+
static const struct iommu_ops spapr_tce_iommu_ops;
1292+
static struct iommu_domain *spapr_tce_domain_alloc_paging(struct device *dev)
1293+
{
1294+
struct iommu_group *grp = iommu_group_get(dev);
1295+
struct iommu_table_group *table_group;
1296+
struct ppc64_domain *ppc64_domain;
1297+
struct iommu_table *ptbl;
1298+
int ret = -1;
1299+
1300+
table_group = iommu_group_get_iommudata(grp);
1301+
ppc64_domain = kzalloc(sizeof(*ppc64_domain), GFP_KERNEL);
1302+
if (!ppc64_domain)
1303+
return NULL;
1304+
1305+
/* Just the default window hardcode for now */
1306+
ret = table_group->ops->create_table(table_group, 0, 0xc, 0x40000000, 1, &ptbl);
1307+
iommu_tce_table_get(ptbl);
1308+
ppc64_domain->table = ptbl; /* REVISIT: Single device for now */
1309+
if (!ppc64_domain->table) {
1310+
kfree(ppc64_domain);
1311+
iommu_tce_table_put(ptbl);
1312+
iommu_group_put(grp);
1313+
return NULL;
1314+
}
1315+
1316+
table_group->ops->set_window(table_group, 0, ptbl);
1317+
iommu_group_put(grp);
1318+
1319+
ppc64_domain->domain.pgsize_bitmap = SZ_4K;
1320+
ppc64_domain->domain.geometry.force_aperture = true;
1321+
ppc64_domain->domain.geometry.aperture_start = 0;
1322+
ppc64_domain->domain.geometry.aperture_end = 0x40000000; /*default window */
1323+
ppc64_domain->domain.ops = spapr_tce_iommu_ops.default_domain_ops;
1324+
1325+
spin_lock_init(&ppc64_domain->list_lock);
1326+
1327+
return &ppc64_domain->domain;
1328+
}
1329+
1330+
static size_t spapr_tce_iommu_unmap_pages(struct iommu_domain *domain,
1331+
unsigned long iova,
1332+
size_t pgsize, size_t pgcount,
1333+
struct iommu_iotlb_gather *gather)
1334+
{
1335+
struct ppc64_domain *ppc64_domain = to_ppc64_domain(domain);
1336+
struct iommu_table *tbl = ppc64_domain->table;
1337+
unsigned long pgshift = __ffs(pgsize);
1338+
size_t size = pgcount << pgshift;
1339+
size_t mapped = 0;
1340+
unsigned int tcenum;
1341+
int mask;
1342+
1343+
if (pgsize != SZ_4K)
1344+
return -EINVAL;
1345+
1346+
size = PAGE_ALIGN(size);
1347+
1348+
mask = IOMMU_PAGE_MASK(tbl);
1349+
tcenum = iova >> tbl->it_page_shift;
1350+
1351+
tbl->it_ops->clear(tbl, tcenum, pgcount);
1352+
1353+
mapped = pgsize * pgcount;
1354+
1355+
return mapped;
1356+
}
1357+
1358+
static phys_addr_t spapr_tce_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
1359+
{
1360+
struct ppc64_domain *ppc64_domain = to_ppc64_domain(domain);
1361+
struct iommu_table *tbl = ppc64_domain->table;
1362+
phys_addr_t paddr, rpn, tceval;
1363+
unsigned int tcenum;
1364+
1365+
tcenum = iova >> tbl->it_page_shift;
1366+
tceval = tbl->it_ops->get(tbl, tcenum);
1367+
1368+
/* Ignore the direction bits */
1369+
rpn = tceval >> tbl->it_page_shift;
1370+
paddr = rpn << tbl->it_page_shift;
1371+
1372+
return paddr;
1373+
}
1374+
1375+
static int spapr_tce_iommu_map_pages(struct iommu_domain *domain,
1376+
unsigned long iova, phys_addr_t paddr,
1377+
size_t pgsize, size_t pgcount,
1378+
int prot, gfp_t gfp, size_t *mapped)
1379+
{
1380+
struct ppc64_domain *ppc64_domain = to_ppc64_domain(domain);
1381+
enum dma_data_direction direction = DMA_BIDIRECTIONAL;
1382+
struct iommu_table *tbl = ppc64_domain->table;
1383+
unsigned long pgshift = __ffs(pgsize);
1384+
size_t size = pgcount << pgshift;
1385+
unsigned int tcenum;
1386+
int ret;
1387+
1388+
if (pgsize != SZ_4K)
1389+
return -EINVAL;
1390+
1391+
if (iova < ppc64_domain->domain.geometry.aperture_start ||
1392+
(iova + size - 1) > ppc64_domain->domain.geometry.aperture_end)
1393+
return -EINVAL;
1394+
1395+
if (!IS_ALIGNED(iova | paddr, pgsize))
1396+
return -EINVAL;
1397+
1398+
if (!(prot & IOMMU_WRITE))
1399+
direction = DMA_FROM_DEVICE;
1400+
1401+
if (!(prot & IOMMU_READ))
1402+
direction = DMA_TO_DEVICE;
1403+
1404+
size = PAGE_ALIGN(size);
1405+
tcenum = iova >> tbl->it_page_shift;
1406+
1407+
/* Put the TCEs in the HW table */
1408+
ret = tbl->it_ops->set(tbl, tcenum, pgcount,
1409+
paddr, direction, 0, true);
1410+
if (!ret && mapped)
1411+
*mapped = pgsize;
1412+
1413+
return 0;
1414+
}
1415+
1416+
static int spapr_tce_iommu_attach_device(struct iommu_domain *domain,
1417+
struct device *dev, struct iommu_domain *old)
1418+
{
1419+
struct ppc64_domain *ppc64_domain = to_ppc64_domain(domain);
1420+
1421+
/* REVISIT */
1422+
if (!domain)
1423+
return 0;
1424+
1425+
/* REVISIT: Check table group, list handling */
1426+
ppc64_domain->device = dev;
1427+
1428+
return 0;
1429+
}
1430+
1431+
12631432
static const struct iommu_ops spapr_tce_iommu_ops = {
12641433
.default_domain = &spapr_tce_platform_domain,
12651434
.blocked_domain = &spapr_tce_blocked_domain,
12661435
.capable = spapr_tce_iommu_capable,
12671436
.probe_device = spapr_tce_iommu_probe_device,
12681437
.release_device = spapr_tce_iommu_release_device,
12691438
.device_group = spapr_tce_iommu_device_group,
1439+
.domain_alloc_paging = spapr_tce_domain_alloc_paging,
1440+
.default_domain_ops = &(const struct iommu_domain_ops) {
1441+
.attach_dev = spapr_tce_iommu_attach_device,
1442+
.map_pages = spapr_tce_iommu_map_pages,
1443+
.unmap_pages = spapr_tce_iommu_unmap_pages,
1444+
.iova_to_phys = spapr_tce_iommu_iova_to_phys,
1445+
.free = spapr_tce_domain_free,
1446+
}
12701447
};
12711448

12721449
static struct attribute *spapr_tce_iommu_attrs[] = {

arch/powerpc/platforms/powernv/pci-ioda-tce.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ static __be64 *pnv_tce(struct iommu_table *tbl, bool user, long idx, bool alloc)
123123

124124
int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
125125
unsigned long uaddr, enum dma_data_direction direction,
126-
unsigned long attrs)
126+
unsigned long attrs, bool is_phys)
127127
{
128128
u64 proto_tce = iommu_direction_to_tce_perm(direction);
129-
u64 rpn = __pa(uaddr) >> tbl->it_page_shift;
129+
u64 rpn = !is_phys ? __pa(uaddr) >> tbl->it_page_shift : uaddr >> tbl->it_page_shift;
130130
long i;
131131

132132
if (proto_tce & TCE_PCI_WRITE)

arch/powerpc/platforms/powernv/pci-ioda.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,10 +1241,10 @@ static void pnv_pci_ioda2_tce_invalidate(struct iommu_table *tbl,
12411241
static int pnv_ioda2_tce_build(struct iommu_table *tbl, long index,
12421242
long npages, unsigned long uaddr,
12431243
enum dma_data_direction direction,
1244-
unsigned long attrs)
1244+
unsigned long attrs, bool is_phys)
12451245
{
12461246
int ret = pnv_tce_build(tbl, index, npages, uaddr, direction,
1247-
attrs);
1247+
attrs, is_phys);
12481248

12491249
if (!ret)
12501250
pnv_pci_ioda2_tce_invalidate(tbl, index, npages);

arch/powerpc/platforms/powernv/pci.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ extern void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,
300300

301301
extern int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
302302
unsigned long uaddr, enum dma_data_direction direction,
303-
unsigned long attrs);
303+
unsigned long attrs, bool is_phys);
304304
extern void pnv_tce_free(struct iommu_table *tbl, long index, long npages);
305305
extern int pnv_tce_xchg(struct iommu_table *tbl, long index,
306306
unsigned long *hpa, enum dma_data_direction *direction);

arch/powerpc/platforms/pseries/iommu.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ static void iommu_pseries_free_group(struct iommu_table_group *table_group,
122122
static int tce_build_pSeries(struct iommu_table *tbl, long index,
123123
long npages, unsigned long uaddr,
124124
enum dma_data_direction direction,
125-
unsigned long attrs)
125+
unsigned long attrs, bool false)
126126
{
127127
u64 proto_tce;
128128
__be64 *tcep;
@@ -250,7 +250,7 @@ static DEFINE_PER_CPU(__be64 *, tce_page);
250250
static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
251251
long npages, unsigned long uaddr,
252252
enum dma_data_direction direction,
253-
unsigned long attrs)
253+
unsigned long attrs, bool is_phys)
254254
{
255255
u64 rc = 0;
256256
u64 proto_tce;
@@ -287,7 +287,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
287287
__this_cpu_write(tce_page, tcep);
288288
}
289289

290-
rpn = __pa(uaddr) >> tceshift;
290+
rpn = !is_phys ? __pa(uaddr) >> tceshift : uaddr >> tceshift;
291291
proto_tce = TCE_PCI_READ;
292292
if (direction != DMA_TO_DEVICE)
293293
proto_tce |= TCE_PCI_WRITE;

drivers/vfio/Kconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ menuconfig VFIO
44
select IOMMU_API
55
depends on IOMMUFD || !IOMMUFD
66
select INTERVAL_TREE
7-
select VFIO_GROUP if SPAPR_TCE_IOMMU || IOMMUFD=n
7+
select VFIO_GROUP if IOMMUFD=n
88
select VFIO_DEVICE_CDEV if !VFIO_GROUP
99
select VFIO_CONTAINER if IOMMUFD=n
1010
help
@@ -16,7 +16,7 @@ menuconfig VFIO
1616
if VFIO
1717
config VFIO_DEVICE_CDEV
1818
bool "Support for the VFIO cdev /dev/vfio/devices/vfioX"
19-
depends on IOMMUFD && !SPAPR_TCE_IOMMU
19+
depends on IOMMUFD
2020
default !VFIO_GROUP
2121
help
2222
The VFIO device cdev is another way for userspace to get device

0 commit comments

Comments
 (0)