diff options
| author | Neil Leeder <nleeder@codeaurora.org> | 2019-03-26 11:17:50 -0400 |
|---|---|---|
| committer | Will Deacon <will.deacon@arm.com> | 2019-04-04 08:44:05 -0400 |
| commit | 24e516049360eda85cf3fe9903221d43886c2689 (patch) | |
| tree | 91dc7a7b7bc59c29cff016cb922bee5cbc021989 | |
| parent | 79a3aaa7b82e3106be97842dedfd8429248896e6 (diff) | |
ACPI/IORT: Add support for PMCG
Add support for the SMMU Performance Monitor Counter Group
information from ACPI. This is in preparation for its use
in the SMMUv3 PMU driver.
Signed-off-by: Neil Leeder <nleeder@codeaurora.org>
Signed-off-by: Hanjun Guo <guohanjun@huawei.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
| -rw-r--r-- | drivers/acpi/arm64/iort.c | 117 | ||||
| -rw-r--r-- | include/linux/acpi_iort.h | 7 |
2 files changed, 100 insertions, 24 deletions
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index e48894e002ba..e2c9b26bbee6 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c | |||
| @@ -356,7 +356,8 @@ static struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node, | |||
| 356 | if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) { | 356 | if (map->flags & ACPI_IORT_ID_SINGLE_MAPPING) { |
| 357 | if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT || | 357 | if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT || |
| 358 | node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX || | 358 | node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX || |
| 359 | node->type == ACPI_IORT_NODE_SMMU_V3) { | 359 | node->type == ACPI_IORT_NODE_SMMU_V3 || |
| 360 | node->type == ACPI_IORT_NODE_PMCG) { | ||
| 360 | *id_out = map->output_base; | 361 | *id_out = map->output_base; |
| 361 | return parent; | 362 | return parent; |
| 362 | } | 363 | } |
| @@ -394,6 +395,8 @@ static int iort_get_id_mapping_index(struct acpi_iort_node *node) | |||
| 394 | } | 395 | } |
| 395 | 396 | ||
| 396 | return smmu->id_mapping_index; | 397 | return smmu->id_mapping_index; |
| 398 | case ACPI_IORT_NODE_PMCG: | ||
| 399 | return 0; | ||
| 397 | default: | 400 | default: |
| 398 | return -EINVAL; | 401 | return -EINVAL; |
| 399 | } | 402 | } |
| @@ -1218,14 +1221,23 @@ static void __init arm_smmu_v3_init_resources(struct resource *res, | |||
| 1218 | } | 1221 | } |
| 1219 | } | 1222 | } |
| 1220 | 1223 | ||
| 1221 | static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node) | 1224 | static void __init arm_smmu_v3_dma_configure(struct device *dev, |
| 1225 | struct acpi_iort_node *node) | ||
| 1222 | { | 1226 | { |
| 1223 | struct acpi_iort_smmu_v3 *smmu; | 1227 | struct acpi_iort_smmu_v3 *smmu; |
| 1228 | enum dev_dma_attr attr; | ||
| 1224 | 1229 | ||
| 1225 | /* Retrieve SMMUv3 specific data */ | 1230 | /* Retrieve SMMUv3 specific data */ |
| 1226 | smmu = (struct acpi_iort_smmu_v3 *)node->node_data; | 1231 | smmu = (struct acpi_iort_smmu_v3 *)node->node_data; |
| 1227 | 1232 | ||
| 1228 | return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE; | 1233 | attr = (smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE) ? |
| 1234 | DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT; | ||
| 1235 | |||
| 1236 | /* We expect the dma masks to be equivalent for all SMMUv3 set-ups */ | ||
| 1237 | dev->dma_mask = &dev->coherent_dma_mask; | ||
| 1238 | |||
| 1239 | /* Configure DMA for the page table walker */ | ||
| 1240 | acpi_dma_configure(dev, attr); | ||
| 1229 | } | 1241 | } |
| 1230 | 1242 | ||
| 1231 | #if defined(CONFIG_ACPI_NUMA) | 1243 | #if defined(CONFIG_ACPI_NUMA) |
| @@ -1301,30 +1313,82 @@ static void __init arm_smmu_init_resources(struct resource *res, | |||
| 1301 | } | 1313 | } |
| 1302 | } | 1314 | } |
| 1303 | 1315 | ||
| 1304 | static bool __init arm_smmu_is_coherent(struct acpi_iort_node *node) | 1316 | static void __init arm_smmu_dma_configure(struct device *dev, |
| 1317 | struct acpi_iort_node *node) | ||
| 1305 | { | 1318 | { |
| 1306 | struct acpi_iort_smmu *smmu; | 1319 | struct acpi_iort_smmu *smmu; |
| 1320 | enum dev_dma_attr attr; | ||
| 1307 | 1321 | ||
| 1308 | /* Retrieve SMMU specific data */ | 1322 | /* Retrieve SMMU specific data */ |
| 1309 | smmu = (struct acpi_iort_smmu *)node->node_data; | 1323 | smmu = (struct acpi_iort_smmu *)node->node_data; |
| 1310 | 1324 | ||
| 1311 | return smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK; | 1325 | attr = (smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK) ? |
| 1326 | DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT; | ||
| 1327 | |||
| 1328 | /* We expect the dma masks to be equivalent for SMMU set-ups */ | ||
| 1329 | dev->dma_mask = &dev->coherent_dma_mask; | ||
| 1330 | |||
| 1331 | /* Configure DMA for the page table walker */ | ||
| 1332 | acpi_dma_configure(dev, attr); | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | static int __init arm_smmu_v3_pmcg_count_resources(struct acpi_iort_node *node) | ||
| 1336 | { | ||
| 1337 | struct acpi_iort_pmcg *pmcg; | ||
| 1338 | |||
| 1339 | /* Retrieve PMCG specific data */ | ||
| 1340 | pmcg = (struct acpi_iort_pmcg *)node->node_data; | ||
| 1341 | |||
| 1342 | /* | ||
| 1343 | * There are always 2 memory resources. | ||
| 1344 | * If the overflow_gsiv is present then add that for a total of 3. | ||
| 1345 | */ | ||
| 1346 | return pmcg->overflow_gsiv ? 3 : 2; | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | static void __init arm_smmu_v3_pmcg_init_resources(struct resource *res, | ||
| 1350 | struct acpi_iort_node *node) | ||
| 1351 | { | ||
| 1352 | struct acpi_iort_pmcg *pmcg; | ||
| 1353 | |||
| 1354 | /* Retrieve PMCG specific data */ | ||
| 1355 | pmcg = (struct acpi_iort_pmcg *)node->node_data; | ||
| 1356 | |||
| 1357 | res[0].start = pmcg->page0_base_address; | ||
| 1358 | res[0].end = pmcg->page0_base_address + SZ_4K - 1; | ||
| 1359 | res[0].flags = IORESOURCE_MEM; | ||
| 1360 | res[1].start = pmcg->page1_base_address; | ||
| 1361 | res[1].end = pmcg->page1_base_address + SZ_4K - 1; | ||
| 1362 | res[1].flags = IORESOURCE_MEM; | ||
| 1363 | |||
| 1364 | if (pmcg->overflow_gsiv) | ||
| 1365 | acpi_iort_register_irq(pmcg->overflow_gsiv, "overflow", | ||
| 1366 | ACPI_EDGE_SENSITIVE, &res[2]); | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | static int __init arm_smmu_v3_pmcg_add_platdata(struct platform_device *pdev) | ||
| 1370 | { | ||
| 1371 | u32 model = IORT_SMMU_V3_PMCG_GENERIC; | ||
| 1372 | |||
| 1373 | return platform_device_add_data(pdev, &model, sizeof(model)); | ||
| 1312 | } | 1374 | } |
| 1313 | 1375 | ||
| 1314 | struct iort_dev_config { | 1376 | struct iort_dev_config { |
| 1315 | const char *name; | 1377 | const char *name; |
| 1316 | int (*dev_init)(struct acpi_iort_node *node); | 1378 | int (*dev_init)(struct acpi_iort_node *node); |
| 1317 | bool (*dev_is_coherent)(struct acpi_iort_node *node); | 1379 | void (*dev_dma_configure)(struct device *dev, |
| 1380 | struct acpi_iort_node *node); | ||
| 1318 | int (*dev_count_resources)(struct acpi_iort_node *node); | 1381 | int (*dev_count_resources)(struct acpi_iort_node *node); |
| 1319 | void (*dev_init_resources)(struct resource *res, | 1382 | void (*dev_init_resources)(struct resource *res, |
| 1320 | struct acpi_iort_node *node); | 1383 | struct acpi_iort_node *node); |
| 1321 | void (*dev_set_proximity)(struct device *dev, | 1384 | void (*dev_set_proximity)(struct device *dev, |
| 1322 | struct acpi_iort_node *node); | 1385 | struct acpi_iort_node *node); |
| 1386 | int (*dev_add_platdata)(struct platform_device *pdev); | ||
| 1323 | }; | 1387 | }; |
| 1324 | 1388 | ||
| 1325 | static const struct iort_dev_config iort_arm_smmu_v3_cfg __initconst = { | 1389 | static const struct iort_dev_config iort_arm_smmu_v3_cfg __initconst = { |
| 1326 | .name = "arm-smmu-v3", | 1390 | .name = "arm-smmu-v3", |
| 1327 | .dev_is_coherent = arm_smmu_v3_is_coherent, | 1391 | .dev_dma_configure = arm_smmu_v3_dma_configure, |
| 1328 | .dev_count_resources = arm_smmu_v3_count_resources, | 1392 | .dev_count_resources = arm_smmu_v3_count_resources, |
| 1329 | .dev_init_resources = arm_smmu_v3_init_resources, | 1393 | .dev_init_resources = arm_smmu_v3_init_resources, |
| 1330 | .dev_set_proximity = arm_smmu_v3_set_proximity, | 1394 | .dev_set_proximity = arm_smmu_v3_set_proximity, |
| @@ -1332,9 +1396,16 @@ static const struct iort_dev_config iort_arm_smmu_v3_cfg __initconst = { | |||
| 1332 | 1396 | ||
| 1333 | static const struct iort_dev_config iort_arm_smmu_cfg __initconst = { | 1397 | static const struct iort_dev_config iort_arm_smmu_cfg __initconst = { |
| 1334 | .name = "arm-smmu", | 1398 | .name = "arm-smmu", |
| 1335 | .dev_is_coherent = arm_smmu_is_coherent, | 1399 | .dev_dma_configure = arm_smmu_dma_configure, |
| 1336 | .dev_count_resources = arm_smmu_count_resources, | 1400 | .dev_count_resources = arm_smmu_count_resources, |
| 1337 | .dev_init_resources = arm_smmu_init_resources | 1401 | .dev_init_resources = arm_smmu_init_resources, |
| 1402 | }; | ||
| 1403 | |||
| 1404 | static const struct iort_dev_config iort_arm_smmu_v3_pmcg_cfg __initconst = { | ||
| 1405 | .name = "arm-smmu-v3-pmcg", | ||
| 1406 | .dev_count_resources = arm_smmu_v3_pmcg_count_resources, | ||
| 1407 | .dev_init_resources = arm_smmu_v3_pmcg_init_resources, | ||
| 1408 | .dev_add_platdata = arm_smmu_v3_pmcg_add_platdata, | ||
| 1338 | }; | 1409 | }; |
| 1339 | 1410 | ||
| 1340 | static __init const struct iort_dev_config *iort_get_dev_cfg( | 1411 | static __init const struct iort_dev_config *iort_get_dev_cfg( |
| @@ -1345,6 +1416,8 @@ static __init const struct iort_dev_config *iort_get_dev_cfg( | |||
| 1345 | return &iort_arm_smmu_v3_cfg; | 1416 | return &iort_arm_smmu_v3_cfg; |
| 1346 | case ACPI_IORT_NODE_SMMU: | 1417 | case ACPI_IORT_NODE_SMMU: |
| 1347 | return &iort_arm_smmu_cfg; | 1418 | return &iort_arm_smmu_cfg; |
| 1419 | case ACPI_IORT_NODE_PMCG: | ||
| 1420 | return &iort_arm_smmu_v3_pmcg_cfg; | ||
| 1348 | default: | 1421 | default: |
| 1349 | return NULL; | 1422 | return NULL; |
| 1350 | } | 1423 | } |
| @@ -1362,7 +1435,6 @@ static int __init iort_add_platform_device(struct acpi_iort_node *node, | |||
| 1362 | struct fwnode_handle *fwnode; | 1435 | struct fwnode_handle *fwnode; |
| 1363 | struct platform_device *pdev; | 1436 | struct platform_device *pdev; |
| 1364 | struct resource *r; | 1437 | struct resource *r; |
| 1365 | enum dev_dma_attr attr; | ||
| 1366 | int ret, count; | 1438 | int ret, count; |
| 1367 | 1439 | ||
| 1368 | pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO); | 1440 | pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO); |
| @@ -1393,19 +1465,19 @@ static int __init iort_add_platform_device(struct acpi_iort_node *node, | |||
| 1393 | goto dev_put; | 1465 | goto dev_put; |
| 1394 | 1466 | ||
| 1395 | /* | 1467 | /* |
| 1396 | * Add a copy of IORT node pointer to platform_data to | 1468 | * Platform devices based on PMCG nodes uses platform_data to |
| 1397 | * be used to retrieve IORT data information. | 1469 | * pass the hardware model info to the driver. For others, add |
| 1470 | * a copy of IORT node pointer to platform_data to be used to | ||
| 1471 | * retrieve IORT data information. | ||
| 1398 | */ | 1472 | */ |
| 1399 | ret = platform_device_add_data(pdev, &node, sizeof(node)); | 1473 | if (ops->dev_add_platdata) |
| 1474 | ret = ops->dev_add_platdata(pdev); | ||
| 1475 | else | ||
| 1476 | ret = platform_device_add_data(pdev, &node, sizeof(node)); | ||
| 1477 | |||
| 1400 | if (ret) | 1478 | if (ret) |
| 1401 | goto dev_put; | 1479 | goto dev_put; |
| 1402 | 1480 | ||
| 1403 | /* | ||
| 1404 | * We expect the dma masks to be equivalent for | ||
| 1405 | * all SMMUs set-ups | ||
| 1406 | */ | ||
| 1407 | pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; | ||
| 1408 | |||
| 1409 | fwnode = iort_get_fwnode(node); | 1481 | fwnode = iort_get_fwnode(node); |
| 1410 | 1482 | ||
| 1411 | if (!fwnode) { | 1483 | if (!fwnode) { |
| @@ -1415,11 +1487,8 @@ static int __init iort_add_platform_device(struct acpi_iort_node *node, | |||
| 1415 | 1487 | ||
| 1416 | pdev->dev.fwnode = fwnode; | 1488 | pdev->dev.fwnode = fwnode; |
| 1417 | 1489 | ||
| 1418 | attr = ops->dev_is_coherent && ops->dev_is_coherent(node) ? | 1490 | if (ops->dev_dma_configure) |
| 1419 | DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT; | 1491 | ops->dev_dma_configure(&pdev->dev, node); |
| 1420 | |||
| 1421 | /* Configure DMA for the page table walker */ | ||
| 1422 | acpi_dma_configure(&pdev->dev, attr); | ||
| 1423 | 1492 | ||
| 1424 | iort_set_device_domain(&pdev->dev, node); | 1493 | iort_set_device_domain(&pdev->dev, node); |
| 1425 | 1494 | ||
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 38cd77b39a64..052ef7b9f985 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h | |||
| @@ -26,6 +26,13 @@ | |||
| 26 | #define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL) | 26 | #define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL) |
| 27 | #define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL) | 27 | #define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL) |
| 28 | 28 | ||
| 29 | /* | ||
| 30 | * PMCG model identifiers for use in smmu pmu driver. Please note | ||
| 31 | * that this is purely for the use of software and has nothing to | ||
| 32 | * do with hardware or with IORT specification. | ||
| 33 | */ | ||
| 34 | #define IORT_SMMU_V3_PMCG_GENERIC 0x00000000 /* Generic SMMUv3 PMCG */ | ||
| 35 | |||
| 29 | int iort_register_domain_token(int trans_id, phys_addr_t base, | 36 | int iort_register_domain_token(int trans_id, phys_addr_t base, |
| 30 | struct fwnode_handle *fw_node); | 37 | struct fwnode_handle *fw_node); |
| 31 | void iort_deregister_domain_token(int trans_id); | 38 | void iort_deregister_domain_token(int trans_id); |
