aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorKent Yoder <key@linux.vnet.ibm.com>2012-04-12 01:08:22 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-05-13 20:49:09 -0400
commitf2ab6219969fcb79dca6792a484b0bdc95ab1f81 (patch)
treeb3ce8198d1d0fa36f68544278a16cacda1e103c0 /arch/powerpc
parent4726b7b5e5a0a3d11a3c80ae8e2d5395003c51af (diff)
powerpc/pseries: Add PFO support to the VIO bus
Add support for the Platform Facilities Option (PFO) to the VIO bus. These devices have a separate root node in OpenFirmware which requires additional parsing to map into the existing VIO device structure fields. This adds the interface for PFO device drivers to make synchronous hypervisor calls. Signed-off-by: Robert Jennings <rcj@linux.vnet.ibm.com> Signed-off-by: Kent Yoder <key@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/vio.h46
-rw-r--r--arch/powerpc/kernel/vio.c273
2 files changed, 280 insertions, 39 deletions
diff --git a/arch/powerpc/include/asm/vio.h b/arch/powerpc/include/asm/vio.h
index 6bfd5ffe1d4f..b19adf751dd9 100644
--- a/arch/powerpc/include/asm/vio.h
+++ b/arch/powerpc/include/asm/vio.h
@@ -46,6 +46,48 @@
46 46
47struct iommu_table; 47struct iommu_table;
48 48
49/*
50 * Platform Facilities Option (PFO)-specific data
51 */
52
53/* Starting unit address for PFO devices on the VIO BUS */
54#define VIO_BASE_PFO_UA 0x50000000
55
56/**
57 * vio_pfo_op - PFO operation parameters
58 *
59 * @flags: h_call subfunctions and modifiers
60 * @in: Input data block logical real address
61 * @inlen: If non-negative, the length of the input data block. If negative,
62 * the length of the input data descriptor list in bytes.
63 * @out: Output data block logical real address
64 * @outlen: If non-negative, the length of the input data block. If negative,
65 * the length of the input data descriptor list in bytes.
66 * @csbcpb: Logical real address of the 4k naturally-aligned storage block
67 * containing the CSB & optional FC field specific CPB
68 * @timeout: # of milliseconds to retry h_call, 0 for no timeout.
69 * @hcall_err: pointer to return the h_call return value, else NULL
70 */
71struct vio_pfo_op {
72 u64 flags;
73 s64 in;
74 s64 inlen;
75 s64 out;
76 s64 outlen;
77 u64 csbcpb;
78 void *done;
79 unsigned long handle;
80 unsigned int timeout;
81 long hcall_err;
82};
83
84/* End PFO specific data */
85
86enum vio_dev_family {
87 VDEVICE, /* The OF node is a child of /vdevice */
88 PFO, /* The OF node is a child of /ibm,platform-facilities */
89};
90
49/** 91/**
50 * vio_dev - This structure is used to describe virtual I/O devices. 92 * vio_dev - This structure is used to describe virtual I/O devices.
51 * 93 *
@@ -58,6 +100,7 @@ struct vio_dev {
58 const char *name; 100 const char *name;
59 const char *type; 101 const char *type;
60 uint32_t unit_address; 102 uint32_t unit_address;
103 uint32_t resource_id;
61 unsigned int irq; 104 unsigned int irq;
62 struct { 105 struct {
63 size_t desired; 106 size_t desired;
@@ -65,6 +108,7 @@ struct vio_dev {
65 size_t allocated; 108 size_t allocated;
66 atomic_t allocs_failed; 109 atomic_t allocs_failed;
67 } cmo; 110 } cmo;
111 enum vio_dev_family family;
68 struct device dev; 112 struct device dev;
69}; 113};
70 114
@@ -95,6 +139,8 @@ extern void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired);
95 139
96extern void __devinit vio_unregister_device(struct vio_dev *dev); 140extern void __devinit vio_unregister_device(struct vio_dev *dev);
97 141
142extern int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op);
143
98struct device_node; 144struct device_node;
99 145
100extern struct vio_dev *vio_register_device_node( 146extern struct vio_dev *vio_register_device_node(
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index a3a99901c8ec..cb87301ccd55 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -14,7 +14,9 @@
14 * 2 of the License, or (at your option) any later version. 14 * 2 of the License, or (at your option) any later version.
15 */ 15 */
16 16
17#include <linux/cpu.h>
17#include <linux/types.h> 18#include <linux/types.h>
19#include <linux/delay.h>
18#include <linux/stat.h> 20#include <linux/stat.h>
19#include <linux/device.h> 21#include <linux/device.h>
20#include <linux/init.h> 22#include <linux/init.h>
@@ -709,13 +711,26 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev)
709 struct vio_driver *viodrv = to_vio_driver(dev->driver); 711 struct vio_driver *viodrv = to_vio_driver(dev->driver);
710 unsigned long flags; 712 unsigned long flags;
711 size_t size; 713 size_t size;
714 bool dma_capable = false;
715
716 /* A device requires entitlement if it has a DMA window property */
717 switch (viodev->family) {
718 case VDEVICE:
719 if (of_get_property(viodev->dev.of_node,
720 "ibm,my-dma-window", NULL))
721 dma_capable = true;
722 break;
723 case PFO:
724 dma_capable = false;
725 break;
726 default:
727 dev_warn(dev, "unknown device family: %d\n", viodev->family);
728 BUG();
729 break;
730 }
712 731
713 /* 732 /* Configure entitlement for the device. */
714 * Check to see that device has a DMA window and configure 733 if (dma_capable) {
715 * entitlement for the device.
716 */
717 if (of_get_property(viodev->dev.of_node,
718 "ibm,my-dma-window", NULL)) {
719 /* Check that the driver is CMO enabled and get desired DMA */ 734 /* Check that the driver is CMO enabled and get desired DMA */
720 if (!viodrv->get_desired_dma) { 735 if (!viodrv->get_desired_dma) {
721 dev_err(dev, "%s: device driver does not support CMO\n", 736 dev_err(dev, "%s: device driver does not support CMO\n",
@@ -1050,6 +1065,94 @@ static void vio_cmo_sysfs_init(void) { }
1050EXPORT_SYMBOL(vio_cmo_entitlement_update); 1065EXPORT_SYMBOL(vio_cmo_entitlement_update);
1051EXPORT_SYMBOL(vio_cmo_set_dev_desired); 1066EXPORT_SYMBOL(vio_cmo_set_dev_desired);
1052 1067
1068
1069/*
1070 * Platform Facilities Option (PFO) support
1071 */
1072
1073/**
1074 * vio_h_cop_sync - Perform a synchronous PFO co-processor operation
1075 *
1076 * @vdev - Pointer to a struct vio_dev for device
1077 * @op - Pointer to a struct vio_pfo_op for the operation parameters
1078 *
1079 * Calls the hypervisor to synchronously perform the PFO operation
1080 * described in @op. In the case of a busy response from the hypervisor,
1081 * the operation will be re-submitted indefinitely unless a non-zero timeout
1082 * is specified or an error occurs. The timeout places a limit on when to
1083 * stop re-submitting a operation, the total time can be exceeded if an
1084 * operation is in progress.
1085 *
1086 * If op->hcall_ret is not NULL, this will be set to the return from the
1087 * last h_cop_op call or it will be 0 if an error not involving the h_call
1088 * was encountered.
1089 *
1090 * Returns:
1091 * 0 on success,
1092 * -EINVAL if the h_call fails due to an invalid parameter,
1093 * -E2BIG if the h_call can not be performed synchronously,
1094 * -EBUSY if a timeout is specified and has elapsed,
1095 * -EACCES if the memory area for data/status has been rescinded, or
1096 * -EPERM if a hardware fault has been indicated
1097 */
1098int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op)
1099{
1100 struct device *dev = &vdev->dev;
1101 unsigned long deadline = 0;
1102 long hret = 0;
1103 int ret = 0;
1104
1105 if (op->timeout)
1106 deadline = jiffies + msecs_to_jiffies(op->timeout);
1107
1108 while (true) {
1109 hret = plpar_hcall_norets(H_COP, op->flags,
1110 vdev->resource_id,
1111 op->in, op->inlen, op->out,
1112 op->outlen, op->csbcpb);
1113
1114 if (hret == H_SUCCESS ||
1115 (hret != H_NOT_ENOUGH_RESOURCES &&
1116 hret != H_BUSY && hret != H_RESOURCE) ||
1117 (op->timeout && time_after(deadline, jiffies)))
1118 break;
1119
1120 dev_dbg(dev, "%s: hcall ret(%ld), retrying.\n", __func__, hret);
1121 }
1122
1123 switch (hret) {
1124 case H_SUCCESS:
1125 ret = 0;
1126 break;
1127 case H_OP_MODE:
1128 case H_TOO_BIG:
1129 ret = -E2BIG;
1130 break;
1131 case H_RESCINDED:
1132 ret = -EACCES;
1133 break;
1134 case H_HARDWARE:
1135 ret = -EPERM;
1136 break;
1137 case H_NOT_ENOUGH_RESOURCES:
1138 case H_RESOURCE:
1139 case H_BUSY:
1140 ret = -EBUSY;
1141 break;
1142 default:
1143 ret = -EINVAL;
1144 break;
1145 }
1146
1147 if (ret)
1148 dev_dbg(dev, "%s: Sync h_cop_op failure (ret:%d) (hret:%ld)\n",
1149 __func__, ret, hret);
1150
1151 op->hcall_err = hret;
1152 return ret;
1153}
1154EXPORT_SYMBOL(vio_h_cop_sync);
1155
1053static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) 1156static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
1054{ 1157{
1055 const unsigned char *dma_window; 1158 const unsigned char *dma_window;
@@ -1211,35 +1314,87 @@ static void __devinit vio_dev_release(struct device *dev)
1211struct vio_dev *vio_register_device_node(struct device_node *of_node) 1314struct vio_dev *vio_register_device_node(struct device_node *of_node)
1212{ 1315{
1213 struct vio_dev *viodev; 1316 struct vio_dev *viodev;
1317 struct device_node *parent_node;
1214 const unsigned int *unit_address; 1318 const unsigned int *unit_address;
1319 const unsigned int *pfo_resid = NULL;
1320 enum vio_dev_family family;
1321 const char *of_node_name = of_node->name ? of_node->name : "<unknown>";
1215 1322
1216 /* we need the 'device_type' property, in order to match with drivers */ 1323 /*
1217 if (of_node->type == NULL) { 1324 * Determine if this node is a under the /vdevice node or under the
1218 printk(KERN_WARNING "%s: node %s missing 'device_type'\n", 1325 * /ibm,platform-facilities node. This decides the device's family.
1219 __func__, 1326 */
1220 of_node->name ? of_node->name : "<unknown>"); 1327 parent_node = of_get_parent(of_node);
1328 if (parent_node) {
1329 if (!strcmp(parent_node->full_name, "/ibm,platform-facilities"))
1330 family = PFO;
1331 else if (!strcmp(parent_node->full_name, "/vdevice"))
1332 family = VDEVICE;
1333 else {
1334 pr_warn("%s: parent(%s) of %s not recognized.\n",
1335 __func__,
1336 parent_node->full_name,
1337 of_node_name);
1338 of_node_put(parent_node);
1339 return NULL;
1340 }
1341 of_node_put(parent_node);
1342 } else {
1343 pr_warn("%s: could not determine the parent of node %s.\n",
1344 __func__, of_node_name);
1221 return NULL; 1345 return NULL;
1222 } 1346 }
1223 1347
1224 unit_address = of_get_property(of_node, "reg", NULL); 1348 if (family == PFO) {
1225 if (unit_address == NULL) { 1349 if (of_get_property(of_node, "interrupt-controller", NULL)) {
1226 printk(KERN_WARNING "%s: node %s missing 'reg'\n", 1350 pr_debug("%s: Skipping the interrupt controller %s.\n",
1227 __func__, 1351 __func__, of_node_name);
1228 of_node->name ? of_node->name : "<unknown>"); 1352 return NULL;
1229 return NULL; 1353 }
1230 } 1354 }
1231 1355
1232 /* allocate a vio_dev for this node */ 1356 /* allocate a vio_dev for this node */
1233 viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL); 1357 viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL);
1234 if (viodev == NULL) 1358 if (viodev == NULL) {
1359 pr_warn("%s: allocation failure for VIO device.\n", __func__);
1235 return NULL; 1360 return NULL;
1361 }
1236 1362
1237 viodev->irq = irq_of_parse_and_map(of_node, 0); 1363 /* we need the 'device_type' property, in order to match with drivers */
1364 viodev->family = family;
1365 if (viodev->family == VDEVICE) {
1366 if (of_node->type != NULL)
1367 viodev->type = of_node->type;
1368 else {
1369 pr_warn("%s: node %s is missing the 'device_type' "
1370 "property.\n", __func__, of_node_name);
1371 goto out;
1372 }
1373
1374 unit_address = of_get_property(of_node, "reg", NULL);
1375 if (unit_address == NULL) {
1376 pr_warn("%s: node %s missing 'reg'\n",
1377 __func__, of_node_name);
1378 goto out;
1379 }
1380 dev_set_name(&viodev->dev, "%x", *unit_address);
1381 viodev->irq = irq_of_parse_and_map(of_node, 0);
1382 viodev->unit_address = *unit_address;
1383 } else {
1384 /* PFO devices need their resource_id for submitting COP_OPs
1385 * This is an optional field for devices, but is required when
1386 * performing synchronous ops */
1387 pfo_resid = of_get_property(of_node, "ibm,resource-id", NULL);
1388 if (pfo_resid != NULL)
1389 viodev->resource_id = *pfo_resid;
1390
1391 unit_address = NULL;
1392 dev_set_name(&viodev->dev, "%s", of_node_name);
1393 viodev->type = of_node_name;
1394 viodev->irq = 0;
1395 }
1238 1396
1239 dev_set_name(&viodev->dev, "%x", *unit_address);
1240 viodev->name = of_node->name; 1397 viodev->name = of_node->name;
1241 viodev->type = of_node->type;
1242 viodev->unit_address = *unit_address;
1243 viodev->dev.of_node = of_node_get(of_node); 1398 viodev->dev.of_node = of_node_get(of_node);
1244 1399
1245 if (firmware_has_feature(FW_FEATURE_CMO)) 1400 if (firmware_has_feature(FW_FEATURE_CMO))
@@ -1267,16 +1422,51 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
1267 } 1422 }
1268 1423
1269 return viodev; 1424 return viodev;
1425
1426out: /* Use this exit point for any return prior to device_register */
1427 kfree(viodev);
1428
1429 return NULL;
1270} 1430}
1271EXPORT_SYMBOL(vio_register_device_node); 1431EXPORT_SYMBOL(vio_register_device_node);
1272 1432
1433/*
1434 * vio_bus_scan_for_devices - Scan OF and register each child device
1435 * @root_name - OF node name for the root of the subtree to search.
1436 * This must be non-NULL
1437 *
1438 * Starting from the root node provide, register the device node for
1439 * each child beneath the root.
1440 */
1441static void vio_bus_scan_register_devices(char *root_name)
1442{
1443 struct device_node *node_root, *node_child;
1444
1445 if (!root_name)
1446 return;
1447
1448 node_root = of_find_node_by_name(NULL, root_name);
1449 if (node_root) {
1450
1451 /*
1452 * Create struct vio_devices for each virtual device in
1453 * the device tree. Drivers will associate with them later.
1454 */
1455 node_child = of_get_next_child(node_root, NULL);
1456 while (node_child) {
1457 vio_register_device_node(node_child);
1458 node_child = of_get_next_child(node_root, node_child);
1459 }
1460 of_node_put(node_root);
1461 }
1462}
1463
1273/** 1464/**
1274 * vio_bus_init: - Initialize the virtual IO bus 1465 * vio_bus_init: - Initialize the virtual IO bus
1275 */ 1466 */
1276static int __init vio_bus_init(void) 1467static int __init vio_bus_init(void)
1277{ 1468{
1278 int err; 1469 int err;
1279 struct device_node *node_vroot;
1280 1470
1281 if (firmware_has_feature(FW_FEATURE_CMO)) 1471 if (firmware_has_feature(FW_FEATURE_CMO))
1282 vio_cmo_sysfs_init(); 1472 vio_cmo_sysfs_init();
@@ -1301,19 +1491,8 @@ static int __init vio_bus_init(void)
1301 if (firmware_has_feature(FW_FEATURE_CMO)) 1491 if (firmware_has_feature(FW_FEATURE_CMO))
1302 vio_cmo_bus_init(); 1492 vio_cmo_bus_init();
1303 1493
1304 node_vroot = of_find_node_by_name(NULL, "vdevice"); 1494 vio_bus_scan_register_devices("vdevice");
1305 if (node_vroot) { 1495 vio_bus_scan_register_devices("ibm,platform-facilities");
1306 struct device_node *of_node;
1307
1308 /*
1309 * Create struct vio_devices for each virtual device in
1310 * the device tree. Drivers will associate with them later.
1311 */
1312 for (of_node = node_vroot->child; of_node != NULL;
1313 of_node = of_node->sibling)
1314 vio_register_device_node(of_node);
1315 of_node_put(node_vroot);
1316 }
1317 1496
1318 return 0; 1497 return 0;
1319} 1498}
@@ -1436,12 +1615,28 @@ struct vio_dev *vio_find_node(struct device_node *vnode)
1436{ 1615{
1437 const uint32_t *unit_address; 1616 const uint32_t *unit_address;
1438 char kobj_name[20]; 1617 char kobj_name[20];
1618 struct device_node *vnode_parent;
1619 const char *dev_type;
1620
1621 vnode_parent = of_get_parent(vnode);
1622 if (!vnode_parent)
1623 return NULL;
1624
1625 dev_type = of_get_property(vnode_parent, "device_type", NULL);
1626 of_node_put(vnode_parent);
1627 if (!dev_type)
1628 return NULL;
1439 1629
1440 /* construct the kobject name from the device node */ 1630 /* construct the kobject name from the device node */
1441 unit_address = of_get_property(vnode, "reg", NULL); 1631 if (!strcmp(dev_type, "vdevice")) {
1442 if (!unit_address) 1632 unit_address = of_get_property(vnode, "reg", NULL);
1633 if (!unit_address)
1634 return NULL;
1635 snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address);
1636 } else if (!strcmp(dev_type, "ibm,platform-facilities"))
1637 snprintf(kobj_name, sizeof(kobj_name), "%s", vnode->name);
1638 else
1443 return NULL; 1639 return NULL;
1444 snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address);
1445 1640
1446 return vio_find_name(kobj_name); 1641 return vio_find_name(kobj_name);
1447} 1642}