Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc: qcom: smd: Represent smd edges as devices

By representing each edge as its own device the channels are no longer
tied to being parented by the same smd device and as such an edge can
live as children of e.g. remoteproc instances.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Andy Gross <andy.gross@linaro.org>

authored by

Bjorn Andersson and committed by
Andy Gross
da057302 381a0b4c

+141 -76
+123 -76
drivers/soc/qcom/smd.c
··· 95 95 96 96 /** 97 97 * struct qcom_smd_edge - representing a remote processor 98 - * @smd: handle to qcom_smd 98 + * @dev: device for this edge 99 99 * @of_node: of_node handle for information related to this edge 100 100 * @edge_id: identifier of this edge 101 101 * @remote_pid: identifier of remote processor ··· 111 111 * @state_work: work item for edge state changes 112 112 */ 113 113 struct qcom_smd_edge { 114 - struct qcom_smd *smd; 114 + struct device dev; 115 + 115 116 struct device_node *of_node; 116 117 unsigned edge_id; 117 118 unsigned remote_pid; ··· 135 134 struct work_struct scan_work; 136 135 struct work_struct state_work; 137 136 }; 137 + 138 + #define to_smd_edge(d) container_of(d, struct qcom_smd_edge, dev) 138 139 139 140 /* 140 141 * SMD channel states. ··· 200 197 void *drvdata; 201 198 202 199 struct list_head list; 203 - }; 204 - 205 - /** 206 - * struct qcom_smd - smd struct 207 - * @dev: device struct 208 - * @num_edges: number of entries in @edges 209 - * @edges: array of edges to be handled 210 - */ 211 - struct qcom_smd { 212 - struct device *dev; 213 - 214 - unsigned num_edges; 215 - struct qcom_smd_edge edges[0]; 216 200 }; 217 201 218 202 /* ··· 410 420 if (channel->state == state) 411 421 return; 412 422 413 - dev_dbg(edge->smd->dev, "set_state(%s, %d)\n", channel->name, state); 423 + dev_dbg(&edge->dev, "set_state(%s, %d)\n", channel->name, state); 414 424 415 425 SET_TX_CHANNEL_FLAG(channel, fDSR, is_open); 416 426 SET_TX_CHANNEL_FLAG(channel, fCTS, is_open); ··· 954 964 struct qcom_smd_device *qsdev; 955 965 struct qcom_smd_edge *edge = channel->edge; 956 966 struct device_node *node; 957 - struct qcom_smd *smd = edge->smd; 958 967 int ret; 959 968 960 969 if (channel->qsdev) 961 970 return -EEXIST; 962 971 963 - dev_dbg(smd->dev, "registering '%s'\n", channel->name); 972 + dev_dbg(&edge->dev, "registering '%s'\n", channel->name); 964 973 965 974 qsdev = kzalloc(sizeof(*qsdev), GFP_KERNEL); 966 975 if (!qsdev) ··· 970 981 edge->of_node->name, 971 982 node ? node->name : channel->name); 972 983 973 - qsdev->dev.parent = smd->dev; 984 + qsdev->dev.parent = &edge->dev; 974 985 qsdev->dev.bus = &qcom_smd_bus; 975 986 qsdev->dev.release = qcom_smd_release_device; 976 987 qsdev->dev.of_node = node; ··· 981 992 982 993 ret = device_register(&qsdev->dev); 983 994 if (ret) { 984 - dev_err(smd->dev, "device_register failed: %d\n", ret); 995 + dev_err(&edge->dev, "device_register failed: %d\n", ret); 985 996 put_device(&qsdev->dev); 986 997 } 987 998 ··· 1127 1138 char *name) 1128 1139 { 1129 1140 struct qcom_smd_channel *channel; 1130 - struct qcom_smd *smd = edge->smd; 1131 1141 size_t fifo_size; 1132 1142 size_t info_size; 1133 1143 void *fifo_base; 1134 1144 void *info; 1135 1145 int ret; 1136 1146 1137 - channel = devm_kzalloc(smd->dev, sizeof(*channel), GFP_KERNEL); 1147 + channel = devm_kzalloc(&edge->dev, sizeof(*channel), GFP_KERNEL); 1138 1148 if (!channel) 1139 1149 return ERR_PTR(-ENOMEM); 1140 1150 1141 1151 channel->edge = edge; 1142 - channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL); 1152 + channel->name = devm_kstrdup(&edge->dev, name, GFP_KERNEL); 1143 1153 if (!channel->name) 1144 1154 return ERR_PTR(-ENOMEM); 1145 1155 ··· 1161 1173 } else if (info_size == 2 * sizeof(struct smd_channel_info)) { 1162 1174 channel->info = info; 1163 1175 } else { 1164 - dev_err(smd->dev, 1176 + dev_err(&edge->dev, 1165 1177 "channel info of size %zu not supported\n", info_size); 1166 1178 ret = -EINVAL; 1167 1179 goto free_name_and_channel; ··· 1176 1188 /* The channel consist of a rx and tx fifo of equal size */ 1177 1189 fifo_size /= 2; 1178 1190 1179 - dev_dbg(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n", 1191 + dev_dbg(&edge->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n", 1180 1192 name, info_size, fifo_size); 1181 1193 1182 1194 channel->tx_fifo = fifo_base; ··· 1188 1200 return channel; 1189 1201 1190 1202 free_name_and_channel: 1191 - devm_kfree(smd->dev, channel->name); 1192 - devm_kfree(smd->dev, channel); 1203 + devm_kfree(&edge->dev, channel->name); 1204 + devm_kfree(&edge->dev, channel); 1193 1205 1194 1206 return ERR_PTR(ret); 1195 1207 } ··· 1205 1217 struct qcom_smd_alloc_entry *alloc_tbl; 1206 1218 struct qcom_smd_alloc_entry *entry; 1207 1219 struct qcom_smd_channel *channel; 1208 - struct qcom_smd *smd = edge->smd; 1209 1220 unsigned long flags; 1210 1221 unsigned fifo_id; 1211 1222 unsigned info_id; ··· 1248 1261 list_add(&channel->list, &edge->channels); 1249 1262 spin_unlock_irqrestore(&edge->channels_lock, flags); 1250 1263 1251 - dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name); 1264 + dev_dbg(&edge->dev, "new channel found: '%s'\n", channel->name); 1252 1265 set_bit(i, edge->allocated[tbl]); 1253 1266 1254 1267 wake_up_interruptible(&edge->new_channel_event); ··· 1388 1401 return 0; 1389 1402 } 1390 1403 1391 - static int qcom_smd_probe(struct platform_device *pdev) 1404 + /* 1405 + * Release function for an edge. 1406 + * Reset the state of each associated channel and free the edge context. 1407 + */ 1408 + static void qcom_smd_edge_release(struct device *dev) 1409 + { 1410 + struct qcom_smd_channel *channel; 1411 + struct qcom_smd_edge *edge = to_smd_edge(dev); 1412 + 1413 + list_for_each_entry(channel, &edge->channels, list) { 1414 + SET_RX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED); 1415 + SET_RX_CHANNEL_INFO(channel, head, 0); 1416 + SET_RX_CHANNEL_INFO(channel, tail, 0); 1417 + } 1418 + 1419 + kfree(edge); 1420 + } 1421 + 1422 + /** 1423 + * qcom_smd_register_edge() - register an edge based on an device_node 1424 + * @parent: parent device for the edge 1425 + * @node: device_node describing the edge 1426 + * 1427 + * Returns an edge reference, or negative ERR_PTR() on failure. 1428 + */ 1429 + struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent, 1430 + struct device_node *node) 1392 1431 { 1393 1432 struct qcom_smd_edge *edge; 1394 - struct device_node *node; 1395 - struct qcom_smd *smd; 1396 - size_t array_size; 1397 - int num_edges; 1398 1433 int ret; 1399 - int i = 0; 1434 + 1435 + edge = kzalloc(sizeof(*edge), GFP_KERNEL); 1436 + if (!edge) 1437 + return ERR_PTR(-ENOMEM); 1438 + 1439 + init_waitqueue_head(&edge->new_channel_event); 1440 + 1441 + edge->dev.parent = parent; 1442 + edge->dev.release = qcom_smd_edge_release; 1443 + dev_set_name(&edge->dev, "%s:%s", dev_name(parent), node->name); 1444 + ret = device_register(&edge->dev); 1445 + if (ret) { 1446 + pr_err("failed to register smd edge\n"); 1447 + return ERR_PTR(ret); 1448 + } 1449 + 1450 + ret = qcom_smd_parse_edge(&edge->dev, node, edge); 1451 + if (ret) { 1452 + dev_err(&edge->dev, "failed to parse smd edge\n"); 1453 + goto unregister_dev; 1454 + } 1455 + 1456 + schedule_work(&edge->scan_work); 1457 + 1458 + return edge; 1459 + 1460 + unregister_dev: 1461 + put_device(&edge->dev); 1462 + return ERR_PTR(ret); 1463 + } 1464 + EXPORT_SYMBOL(qcom_smd_register_edge); 1465 + 1466 + static int qcom_smd_remove_device(struct device *dev, void *data) 1467 + { 1468 + device_unregister(dev); 1469 + of_node_put(dev->of_node); 1470 + put_device(dev); 1471 + 1472 + return 0; 1473 + } 1474 + 1475 + /** 1476 + * qcom_smd_unregister_edge() - release an edge and its children 1477 + * @edge: edge reference acquired from qcom_smd_register_edge 1478 + */ 1479 + int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) 1480 + { 1481 + int ret; 1482 + 1483 + disable_irq(edge->irq); 1484 + cancel_work_sync(&edge->scan_work); 1485 + cancel_work_sync(&edge->state_work); 1486 + 1487 + ret = device_for_each_child(&edge->dev, NULL, qcom_smd_remove_device); 1488 + if (ret) 1489 + dev_warn(&edge->dev, "can't remove smd device: %d\n", ret); 1490 + 1491 + device_unregister(&edge->dev); 1492 + 1493 + return 0; 1494 + } 1495 + EXPORT_SYMBOL(qcom_smd_unregister_edge); 1496 + 1497 + static int qcom_smd_probe(struct platform_device *pdev) 1498 + { 1499 + struct device_node *node; 1400 1500 void *p; 1401 1501 1402 1502 /* Wait for smem */ ··· 1491 1417 if (PTR_ERR(p) == -EPROBE_DEFER) 1492 1418 return PTR_ERR(p); 1493 1419 1494 - num_edges = of_get_available_child_count(pdev->dev.of_node); 1495 - array_size = sizeof(*smd) + num_edges * sizeof(struct qcom_smd_edge); 1496 - smd = devm_kzalloc(&pdev->dev, array_size, GFP_KERNEL); 1497 - if (!smd) 1498 - return -ENOMEM; 1499 - smd->dev = &pdev->dev; 1500 - 1501 - smd->num_edges = num_edges; 1502 - for_each_available_child_of_node(pdev->dev.of_node, node) { 1503 - edge = &smd->edges[i++]; 1504 - edge->smd = smd; 1505 - init_waitqueue_head(&edge->new_channel_event); 1506 - 1507 - ret = qcom_smd_parse_edge(&pdev->dev, node, edge); 1508 - if (ret) 1509 - continue; 1510 - 1511 - schedule_work(&edge->scan_work); 1512 - } 1513 - 1514 - platform_set_drvdata(pdev, smd); 1420 + for_each_available_child_of_node(pdev->dev.of_node, node) 1421 + qcom_smd_register_edge(&pdev->dev, node); 1515 1422 1516 1423 return 0; 1424 + } 1425 + 1426 + static int qcom_smd_remove_edge(struct device *dev, void *data) 1427 + { 1428 + struct qcom_smd_edge *edge = to_smd_edge(dev); 1429 + 1430 + return qcom_smd_unregister_edge(edge); 1517 1431 } 1518 1432 1519 1433 /* ··· 1510 1448 */ 1511 1449 static int qcom_smd_remove(struct platform_device *pdev) 1512 1450 { 1513 - struct qcom_smd_channel *channel; 1514 - struct qcom_smd_edge *edge; 1515 - struct qcom_smd *smd = platform_get_drvdata(pdev); 1516 - int i; 1451 + int ret; 1517 1452 1518 - for (i = 0; i < smd->num_edges; i++) { 1519 - edge = &smd->edges[i]; 1453 + ret = device_for_each_child(&pdev->dev, NULL, qcom_smd_remove_edge); 1454 + if (ret) 1455 + dev_warn(&pdev->dev, "can't remove smd device: %d\n", ret); 1520 1456 1521 - disable_irq(edge->irq); 1522 - cancel_work_sync(&edge->scan_work); 1523 - cancel_work_sync(&edge->state_work); 1524 - 1525 - /* No need to lock here, because the writer is gone */ 1526 - list_for_each_entry(channel, &edge->channels, list) { 1527 - if (!channel->qsdev) 1528 - continue; 1529 - 1530 - qcom_smd_destroy_device(channel); 1531 - } 1532 - } 1533 - 1534 - return 0; 1457 + return ret; 1535 1458 } 1536 1459 1537 1460 static const struct of_device_id qcom_smd_of_match[] = {
+18
include/linux/soc/qcom/smd.h
··· 61 61 int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len); 62 62 63 63 64 + struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent, 65 + struct device_node *node); 66 + int qcom_smd_unregister_edge(struct qcom_smd_edge *edge); 67 + 64 68 #else 65 69 66 70 static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv) ··· 109 105 110 106 static inline int qcom_smd_send(struct qcom_smd_channel *channel, 111 107 const void *data, int len) 108 + { 109 + /* This shouldn't be possible */ 110 + WARN_ON(1); 111 + return -ENXIO; 112 + } 113 + 114 + static inline struct qcom_smd_edge * 115 + qcom_smd_register_edge(struct device *parent, 116 + struct device_node *node) 117 + { 118 + return ERR_PTR(-ENXIO); 119 + } 120 + 121 + static inline int qcom_smd_unregister_edge(struct qcom_smd_edge *edge) 112 122 { 113 123 /* This shouldn't be possible */ 114 124 WARN_ON(1);