diff options
Diffstat (limited to 'drivers/thunderbolt/icm.c')
-rw-r--r-- | drivers/thunderbolt/icm.c | 119 |
1 files changed, 105 insertions, 14 deletions
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index e0930dbbcf47..e1e264a9a4c7 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
18 | #include <linux/pm_runtime.h> | ||
18 | #include <linux/platform_data/x86/apple.h> | 19 | #include <linux/platform_data/x86/apple.h> |
19 | #include <linux/sizes.h> | 20 | #include <linux/sizes.h> |
20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
@@ -57,6 +58,7 @@ | |||
57 | * (only set when @upstream_port is not %NULL) | 58 | * (only set when @upstream_port is not %NULL) |
58 | * @safe_mode: ICM is in safe mode | 59 | * @safe_mode: ICM is in safe mode |
59 | * @max_boot_acl: Maximum number of preboot ACL entries (%0 if not supported) | 60 | * @max_boot_acl: Maximum number of preboot ACL entries (%0 if not supported) |
61 | * @rpm: Does the controller support runtime PM (RTD3) | ||
60 | * @is_supported: Checks if we can support ICM on this controller | 62 | * @is_supported: Checks if we can support ICM on this controller |
61 | * @get_mode: Read and return the ICM firmware mode (optional) | 63 | * @get_mode: Read and return the ICM firmware mode (optional) |
62 | * @get_route: Find a route string for given switch | 64 | * @get_route: Find a route string for given switch |
@@ -74,13 +76,14 @@ struct icm { | |||
74 | size_t max_boot_acl; | 76 | size_t max_boot_acl; |
75 | int vnd_cap; | 77 | int vnd_cap; |
76 | bool safe_mode; | 78 | bool safe_mode; |
79 | bool rpm; | ||
77 | bool (*is_supported)(struct tb *tb); | 80 | bool (*is_supported)(struct tb *tb); |
78 | int (*get_mode)(struct tb *tb); | 81 | int (*get_mode)(struct tb *tb); |
79 | int (*get_route)(struct tb *tb, u8 link, u8 depth, u64 *route); | 82 | int (*get_route)(struct tb *tb, u8 link, u8 depth, u64 *route); |
80 | void (*save_devices)(struct tb *tb); | 83 | void (*save_devices)(struct tb *tb); |
81 | int (*driver_ready)(struct tb *tb, | 84 | int (*driver_ready)(struct tb *tb, |
82 | enum tb_security_level *security_level, | 85 | enum tb_security_level *security_level, |
83 | size_t *nboot_acl); | 86 | size_t *nboot_acl, bool *rpm); |
84 | void (*device_connected)(struct tb *tb, | 87 | void (*device_connected)(struct tb *tb, |
85 | const struct icm_pkg_header *hdr); | 88 | const struct icm_pkg_header *hdr); |
86 | void (*device_disconnected)(struct tb *tb, | 89 | void (*device_disconnected)(struct tb *tb, |
@@ -97,6 +100,47 @@ struct icm_notification { | |||
97 | struct tb *tb; | 100 | struct tb *tb; |
98 | }; | 101 | }; |
99 | 102 | ||
103 | struct ep_name_entry { | ||
104 | u8 len; | ||
105 | u8 type; | ||
106 | u8 data[0]; | ||
107 | }; | ||
108 | |||
109 | #define EP_NAME_INTEL_VSS 0x10 | ||
110 | |||
111 | /* Intel Vendor specific structure */ | ||
112 | struct intel_vss { | ||
113 | u16 vendor; | ||
114 | u16 model; | ||
115 | u8 mc; | ||
116 | u8 flags; | ||
117 | u16 pci_devid; | ||
118 | u32 nvm_version; | ||
119 | }; | ||
120 | |||
121 | #define INTEL_VSS_FLAGS_RTD3 BIT(0) | ||
122 | |||
123 | static const struct intel_vss *parse_intel_vss(const void *ep_name, size_t size) | ||
124 | { | ||
125 | const void *end = ep_name + size; | ||
126 | |||
127 | while (ep_name < end) { | ||
128 | const struct ep_name_entry *ep = ep_name; | ||
129 | |||
130 | if (!ep->len) | ||
131 | break; | ||
132 | if (ep_name + ep->len > end) | ||
133 | break; | ||
134 | |||
135 | if (ep->type == EP_NAME_INTEL_VSS) | ||
136 | return (const struct intel_vss *)ep->data; | ||
137 | |||
138 | ep_name += ep->len; | ||
139 | } | ||
140 | |||
141 | return NULL; | ||
142 | } | ||
143 | |||
100 | static inline struct tb *icm_to_tb(struct icm *icm) | 144 | static inline struct tb *icm_to_tb(struct icm *icm) |
101 | { | 145 | { |
102 | return ((void *)icm - sizeof(struct tb)); | 146 | return ((void *)icm - sizeof(struct tb)); |
@@ -267,7 +311,7 @@ static void icm_fr_save_devices(struct tb *tb) | |||
267 | 311 | ||
268 | static int | 312 | static int |
269 | icm_fr_driver_ready(struct tb *tb, enum tb_security_level *security_level, | 313 | icm_fr_driver_ready(struct tb *tb, enum tb_security_level *security_level, |
270 | size_t *nboot_acl) | 314 | size_t *nboot_acl, bool *rpm) |
271 | { | 315 | { |
272 | struct icm_fr_pkg_driver_ready_response reply; | 316 | struct icm_fr_pkg_driver_ready_response reply; |
273 | struct icm_pkg_driver_ready request = { | 317 | struct icm_pkg_driver_ready request = { |
@@ -417,15 +461,19 @@ static int icm_fr_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd) | |||
417 | } | 461 | } |
418 | 462 | ||
419 | static void add_switch(struct tb_switch *parent_sw, u64 route, | 463 | static void add_switch(struct tb_switch *parent_sw, u64 route, |
420 | const uuid_t *uuid, u8 connection_id, u8 connection_key, | 464 | const uuid_t *uuid, const u8 *ep_name, |
465 | size_t ep_name_size, u8 connection_id, u8 connection_key, | ||
421 | u8 link, u8 depth, enum tb_security_level security_level, | 466 | u8 link, u8 depth, enum tb_security_level security_level, |
422 | bool authorized, bool boot) | 467 | bool authorized, bool boot) |
423 | { | 468 | { |
469 | const struct intel_vss *vss; | ||
424 | struct tb_switch *sw; | 470 | struct tb_switch *sw; |
425 | 471 | ||
472 | pm_runtime_get_sync(&parent_sw->dev); | ||
473 | |||
426 | sw = tb_switch_alloc(parent_sw->tb, &parent_sw->dev, route); | 474 | sw = tb_switch_alloc(parent_sw->tb, &parent_sw->dev, route); |
427 | if (!sw) | 475 | if (!sw) |
428 | return; | 476 | goto out; |
429 | 477 | ||
430 | sw->uuid = kmemdup(uuid, sizeof(*uuid), GFP_KERNEL); | 478 | sw->uuid = kmemdup(uuid, sizeof(*uuid), GFP_KERNEL); |
431 | sw->connection_id = connection_id; | 479 | sw->connection_id = connection_id; |
@@ -436,6 +484,10 @@ static void add_switch(struct tb_switch *parent_sw, u64 route, | |||
436 | sw->security_level = security_level; | 484 | sw->security_level = security_level; |
437 | sw->boot = boot; | 485 | sw->boot = boot; |
438 | 486 | ||
487 | vss = parse_intel_vss(ep_name, ep_name_size); | ||
488 | if (vss) | ||
489 | sw->rpm = !!(vss->flags & INTEL_VSS_FLAGS_RTD3); | ||
490 | |||
439 | /* Link the two switches now */ | 491 | /* Link the two switches now */ |
440 | tb_port_at(route, parent_sw)->remote = tb_upstream_port(sw); | 492 | tb_port_at(route, parent_sw)->remote = tb_upstream_port(sw); |
441 | tb_upstream_port(sw)->remote = tb_port_at(route, parent_sw); | 493 | tb_upstream_port(sw)->remote = tb_port_at(route, parent_sw); |
@@ -443,8 +495,11 @@ static void add_switch(struct tb_switch *parent_sw, u64 route, | |||
443 | if (tb_switch_add(sw)) { | 495 | if (tb_switch_add(sw)) { |
444 | tb_port_at(tb_route(sw), parent_sw)->remote = NULL; | 496 | tb_port_at(tb_route(sw), parent_sw)->remote = NULL; |
445 | tb_switch_put(sw); | 497 | tb_switch_put(sw); |
446 | return; | ||
447 | } | 498 | } |
499 | |||
500 | out: | ||
501 | pm_runtime_mark_last_busy(&parent_sw->dev); | ||
502 | pm_runtime_put_autosuspend(&parent_sw->dev); | ||
448 | } | 503 | } |
449 | 504 | ||
450 | static void update_switch(struct tb_switch *parent_sw, struct tb_switch *sw, | 505 | static void update_switch(struct tb_switch *parent_sw, struct tb_switch *sw, |
@@ -484,9 +539,11 @@ static void add_xdomain(struct tb_switch *sw, u64 route, | |||
484 | { | 539 | { |
485 | struct tb_xdomain *xd; | 540 | struct tb_xdomain *xd; |
486 | 541 | ||
542 | pm_runtime_get_sync(&sw->dev); | ||
543 | |||
487 | xd = tb_xdomain_alloc(sw->tb, &sw->dev, route, local_uuid, remote_uuid); | 544 | xd = tb_xdomain_alloc(sw->tb, &sw->dev, route, local_uuid, remote_uuid); |
488 | if (!xd) | 545 | if (!xd) |
489 | return; | 546 | goto out; |
490 | 547 | ||
491 | xd->link = link; | 548 | xd->link = link; |
492 | xd->depth = depth; | 549 | xd->depth = depth; |
@@ -494,6 +551,10 @@ static void add_xdomain(struct tb_switch *sw, u64 route, | |||
494 | tb_port_at(route, sw)->xdomain = xd; | 551 | tb_port_at(route, sw)->xdomain = xd; |
495 | 552 | ||
496 | tb_xdomain_add(xd); | 553 | tb_xdomain_add(xd); |
554 | |||
555 | out: | ||
556 | pm_runtime_mark_last_busy(&sw->dev); | ||
557 | pm_runtime_put_autosuspend(&sw->dev); | ||
497 | } | 558 | } |
498 | 559 | ||
499 | static void update_xdomain(struct tb_xdomain *xd, u64 route, u8 link) | 560 | static void update_xdomain(struct tb_xdomain *xd, u64 route, u8 link) |
@@ -631,7 +692,8 @@ icm_fr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr) | |||
631 | return; | 692 | return; |
632 | } | 693 | } |
633 | 694 | ||
634 | add_switch(parent_sw, route, &pkg->ep_uuid, pkg->connection_id, | 695 | add_switch(parent_sw, route, &pkg->ep_uuid, (const u8 *)pkg->ep_name, |
696 | sizeof(pkg->ep_name), pkg->connection_id, | ||
635 | pkg->connection_key, link, depth, security_level, | 697 | pkg->connection_key, link, depth, security_level, |
636 | authorized, boot); | 698 | authorized, boot); |
637 | 699 | ||
@@ -779,7 +841,7 @@ icm_fr_xdomain_disconnected(struct tb *tb, const struct icm_pkg_header *hdr) | |||
779 | 841 | ||
780 | static int | 842 | static int |
781 | icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level, | 843 | icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level, |
782 | size_t *nboot_acl) | 844 | size_t *nboot_acl, bool *rpm) |
783 | { | 845 | { |
784 | struct icm_tr_pkg_driver_ready_response reply; | 846 | struct icm_tr_pkg_driver_ready_response reply; |
785 | struct icm_pkg_driver_ready request = { | 847 | struct icm_pkg_driver_ready request = { |
@@ -798,6 +860,9 @@ icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level, | |||
798 | if (nboot_acl) | 860 | if (nboot_acl) |
799 | *nboot_acl = (reply.info & ICM_TR_INFO_BOOT_ACL_MASK) >> | 861 | *nboot_acl = (reply.info & ICM_TR_INFO_BOOT_ACL_MASK) >> |
800 | ICM_TR_INFO_BOOT_ACL_SHIFT; | 862 | ICM_TR_INFO_BOOT_ACL_SHIFT; |
863 | if (rpm) | ||
864 | *rpm = !!(reply.hdr.flags & ICM_TR_FLAGS_RTD3); | ||
865 | |||
801 | return 0; | 866 | return 0; |
802 | } | 867 | } |
803 | 868 | ||
@@ -1027,7 +1092,8 @@ icm_tr_device_connected(struct tb *tb, const struct icm_pkg_header *hdr) | |||
1027 | return; | 1092 | return; |
1028 | } | 1093 | } |
1029 | 1094 | ||
1030 | add_switch(parent_sw, route, &pkg->ep_uuid, pkg->connection_id, | 1095 | add_switch(parent_sw, route, &pkg->ep_uuid, (const u8 *)pkg->ep_name, |
1096 | sizeof(pkg->ep_name), pkg->connection_id, | ||
1031 | 0, 0, 0, security_level, authorized, boot); | 1097 | 0, 0, 0, security_level, authorized, boot); |
1032 | 1098 | ||
1033 | tb_switch_put(parent_sw); | 1099 | tb_switch_put(parent_sw); |
@@ -1206,7 +1272,7 @@ static int icm_ar_get_mode(struct tb *tb) | |||
1206 | 1272 | ||
1207 | static int | 1273 | static int |
1208 | icm_ar_driver_ready(struct tb *tb, enum tb_security_level *security_level, | 1274 | icm_ar_driver_ready(struct tb *tb, enum tb_security_level *security_level, |
1209 | size_t *nboot_acl) | 1275 | size_t *nboot_acl, bool *rpm) |
1210 | { | 1276 | { |
1211 | struct icm_ar_pkg_driver_ready_response reply; | 1277 | struct icm_ar_pkg_driver_ready_response reply; |
1212 | struct icm_pkg_driver_ready request = { | 1278 | struct icm_pkg_driver_ready request = { |
@@ -1225,6 +1291,9 @@ icm_ar_driver_ready(struct tb *tb, enum tb_security_level *security_level, | |||
1225 | if (nboot_acl && (reply.info & ICM_AR_INFO_BOOT_ACL_SUPPORTED)) | 1291 | if (nboot_acl && (reply.info & ICM_AR_INFO_BOOT_ACL_SUPPORTED)) |
1226 | *nboot_acl = (reply.info & ICM_AR_INFO_BOOT_ACL_MASK) >> | 1292 | *nboot_acl = (reply.info & ICM_AR_INFO_BOOT_ACL_MASK) >> |
1227 | ICM_AR_INFO_BOOT_ACL_SHIFT; | 1293 | ICM_AR_INFO_BOOT_ACL_SHIFT; |
1294 | if (rpm) | ||
1295 | *rpm = !!(reply.hdr.flags & ICM_AR_FLAGS_RTD3); | ||
1296 | |||
1228 | return 0; | 1297 | return 0; |
1229 | } | 1298 | } |
1230 | 1299 | ||
@@ -1378,13 +1447,13 @@ static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type, | |||
1378 | 1447 | ||
1379 | static int | 1448 | static int |
1380 | __icm_driver_ready(struct tb *tb, enum tb_security_level *security_level, | 1449 | __icm_driver_ready(struct tb *tb, enum tb_security_level *security_level, |
1381 | size_t *nboot_acl) | 1450 | size_t *nboot_acl, bool *rpm) |
1382 | { | 1451 | { |
1383 | struct icm *icm = tb_priv(tb); | 1452 | struct icm *icm = tb_priv(tb); |
1384 | unsigned int retries = 50; | 1453 | unsigned int retries = 50; |
1385 | int ret; | 1454 | int ret; |
1386 | 1455 | ||
1387 | ret = icm->driver_ready(tb, security_level, nboot_acl); | 1456 | ret = icm->driver_ready(tb, security_level, nboot_acl, rpm); |
1388 | if (ret) { | 1457 | if (ret) { |
1389 | tb_err(tb, "failed to send driver ready to ICM\n"); | 1458 | tb_err(tb, "failed to send driver ready to ICM\n"); |
1390 | return ret; | 1459 | return ret; |
@@ -1654,7 +1723,8 @@ static int icm_driver_ready(struct tb *tb) | |||
1654 | return 0; | 1723 | return 0; |
1655 | } | 1724 | } |
1656 | 1725 | ||
1657 | ret = __icm_driver_ready(tb, &tb->security_level, &tb->nboot_acl); | 1726 | ret = __icm_driver_ready(tb, &tb->security_level, &tb->nboot_acl, |
1727 | &icm->rpm); | ||
1658 | if (ret) | 1728 | if (ret) |
1659 | return ret; | 1729 | return ret; |
1660 | 1730 | ||
@@ -1760,7 +1830,7 @@ static void icm_complete(struct tb *tb) | |||
1760 | * Now all existing children should be resumed, start events | 1830 | * Now all existing children should be resumed, start events |
1761 | * from ICM to get updated status. | 1831 | * from ICM to get updated status. |
1762 | */ | 1832 | */ |
1763 | __icm_driver_ready(tb, NULL, NULL); | 1833 | __icm_driver_ready(tb, NULL, NULL, NULL); |
1764 | 1834 | ||
1765 | /* | 1835 | /* |
1766 | * We do not get notifications of devices that have been | 1836 | * We do not get notifications of devices that have been |
@@ -1770,6 +1840,22 @@ static void icm_complete(struct tb *tb) | |||
1770 | queue_delayed_work(tb->wq, &icm->rescan_work, msecs_to_jiffies(500)); | 1840 | queue_delayed_work(tb->wq, &icm->rescan_work, msecs_to_jiffies(500)); |
1771 | } | 1841 | } |
1772 | 1842 | ||
1843 | static int icm_runtime_suspend(struct tb *tb) | ||
1844 | { | ||
1845 | nhi_mailbox_cmd(tb->nhi, NHI_MAILBOX_DRV_UNLOADS, 0); | ||
1846 | return 0; | ||
1847 | } | ||
1848 | |||
1849 | static int icm_runtime_resume(struct tb *tb) | ||
1850 | { | ||
1851 | /* | ||
1852 | * We can reuse the same resume functionality than with system | ||
1853 | * suspend. | ||
1854 | */ | ||
1855 | icm_complete(tb); | ||
1856 | return 0; | ||
1857 | } | ||
1858 | |||
1773 | static int icm_start(struct tb *tb) | 1859 | static int icm_start(struct tb *tb) |
1774 | { | 1860 | { |
1775 | struct icm *icm = tb_priv(tb); | 1861 | struct icm *icm = tb_priv(tb); |
@@ -1788,6 +1874,7 @@ static int icm_start(struct tb *tb) | |||
1788 | * prevent root switch NVM upgrade on Macs for now. | 1874 | * prevent root switch NVM upgrade on Macs for now. |
1789 | */ | 1875 | */ |
1790 | tb->root_switch->no_nvm_upgrade = x86_apple_machine; | 1876 | tb->root_switch->no_nvm_upgrade = x86_apple_machine; |
1877 | tb->root_switch->rpm = icm->rpm; | ||
1791 | 1878 | ||
1792 | ret = tb_switch_add(tb->root_switch); | 1879 | ret = tb_switch_add(tb->root_switch); |
1793 | if (ret) { | 1880 | if (ret) { |
@@ -1836,6 +1923,8 @@ static const struct tb_cm_ops icm_ar_ops = { | |||
1836 | .stop = icm_stop, | 1923 | .stop = icm_stop, |
1837 | .suspend = icm_suspend, | 1924 | .suspend = icm_suspend, |
1838 | .complete = icm_complete, | 1925 | .complete = icm_complete, |
1926 | .runtime_suspend = icm_runtime_suspend, | ||
1927 | .runtime_resume = icm_runtime_resume, | ||
1839 | .handle_event = icm_handle_event, | 1928 | .handle_event = icm_handle_event, |
1840 | .get_boot_acl = icm_ar_get_boot_acl, | 1929 | .get_boot_acl = icm_ar_get_boot_acl, |
1841 | .set_boot_acl = icm_ar_set_boot_acl, | 1930 | .set_boot_acl = icm_ar_set_boot_acl, |
@@ -1854,6 +1943,8 @@ static const struct tb_cm_ops icm_tr_ops = { | |||
1854 | .stop = icm_stop, | 1943 | .stop = icm_stop, |
1855 | .suspend = icm_suspend, | 1944 | .suspend = icm_suspend, |
1856 | .complete = icm_complete, | 1945 | .complete = icm_complete, |
1946 | .runtime_suspend = icm_runtime_suspend, | ||
1947 | .runtime_resume = icm_runtime_resume, | ||
1857 | .handle_event = icm_handle_event, | 1948 | .handle_event = icm_handle_event, |
1858 | .get_boot_acl = icm_ar_get_boot_acl, | 1949 | .get_boot_acl = icm_ar_get_boot_acl, |
1859 | .set_boot_acl = icm_ar_set_boot_acl, | 1950 | .set_boot_acl = icm_ar_set_boot_acl, |