908 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Thunderbolt bus support4 *5 * Copyright (C) 2017, Intel Corporation6 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>7 */8 9#include <linux/device.h>10#include <linux/idr.h>11#include <linux/module.h>12#include <linux/pm_runtime.h>13#include <linux/slab.h>14#include <linux/random.h>15#include <crypto/hash.h>16 17#include "tb.h"18 19static DEFINE_IDA(tb_domain_ida);20 21static bool match_service_id(const struct tb_service_id *id,22 const struct tb_service *svc)23{24 if (id->match_flags & TBSVC_MATCH_PROTOCOL_KEY) {25 if (strcmp(id->protocol_key, svc->key))26 return false;27 }28 29 if (id->match_flags & TBSVC_MATCH_PROTOCOL_ID) {30 if (id->protocol_id != svc->prtcid)31 return false;32 }33 34 if (id->match_flags & TBSVC_MATCH_PROTOCOL_VERSION) {35 if (id->protocol_version != svc->prtcvers)36 return false;37 }38 39 if (id->match_flags & TBSVC_MATCH_PROTOCOL_VERSION) {40 if (id->protocol_revision != svc->prtcrevs)41 return false;42 }43 44 return true;45}46 47static const struct tb_service_id *__tb_service_match(struct device *dev,48 const struct device_driver *drv)49{50 const struct tb_service_driver *driver;51 const struct tb_service_id *ids;52 struct tb_service *svc;53 54 svc = tb_to_service(dev);55 if (!svc)56 return NULL;57 58 driver = container_of_const(drv, struct tb_service_driver, driver);59 if (!driver->id_table)60 return NULL;61 62 for (ids = driver->id_table; ids->match_flags != 0; ids++) {63 if (match_service_id(ids, svc))64 return ids;65 }66 67 return NULL;68}69 70static int tb_service_match(struct device *dev, const struct device_driver *drv)71{72 return !!__tb_service_match(dev, drv);73}74 75static int tb_service_probe(struct device *dev)76{77 struct tb_service *svc = tb_to_service(dev);78 struct tb_service_driver *driver;79 const struct tb_service_id *id;80 81 driver = container_of(dev->driver, struct tb_service_driver, driver);82 id = __tb_service_match(dev, &driver->driver);83 84 return driver->probe(svc, id);85}86 87static void tb_service_remove(struct device *dev)88{89 struct tb_service *svc = tb_to_service(dev);90 struct tb_service_driver *driver;91 92 driver = container_of(dev->driver, struct tb_service_driver, driver);93 if (driver->remove)94 driver->remove(svc);95}96 97static void tb_service_shutdown(struct device *dev)98{99 struct tb_service_driver *driver;100 struct tb_service *svc;101 102 svc = tb_to_service(dev);103 if (!svc || !dev->driver)104 return;105 106 driver = container_of(dev->driver, struct tb_service_driver, driver);107 if (driver->shutdown)108 driver->shutdown(svc);109}110 111static const char * const tb_security_names[] = {112 [TB_SECURITY_NONE] = "none",113 [TB_SECURITY_USER] = "user",114 [TB_SECURITY_SECURE] = "secure",115 [TB_SECURITY_DPONLY] = "dponly",116 [TB_SECURITY_USBONLY] = "usbonly",117 [TB_SECURITY_NOPCIE] = "nopcie",118};119 120static ssize_t boot_acl_show(struct device *dev, struct device_attribute *attr,121 char *buf)122{123 struct tb *tb = container_of(dev, struct tb, dev);124 uuid_t *uuids;125 ssize_t ret;126 int i;127 128 uuids = kcalloc(tb->nboot_acl, sizeof(uuid_t), GFP_KERNEL);129 if (!uuids)130 return -ENOMEM;131 132 pm_runtime_get_sync(&tb->dev);133 134 if (mutex_lock_interruptible(&tb->lock)) {135 ret = -ERESTARTSYS;136 goto out;137 }138 ret = tb->cm_ops->get_boot_acl(tb, uuids, tb->nboot_acl);139 if (ret) {140 mutex_unlock(&tb->lock);141 goto out;142 }143 mutex_unlock(&tb->lock);144 145 for (ret = 0, i = 0; i < tb->nboot_acl; i++) {146 if (!uuid_is_null(&uuids[i]))147 ret += sysfs_emit_at(buf, ret, "%pUb", &uuids[i]);148 149 ret += sysfs_emit_at(buf, ret, "%s", i < tb->nboot_acl - 1 ? "," : "\n");150 }151 152out:153 pm_runtime_mark_last_busy(&tb->dev);154 pm_runtime_put_autosuspend(&tb->dev);155 kfree(uuids);156 157 return ret;158}159 160static ssize_t boot_acl_store(struct device *dev, struct device_attribute *attr,161 const char *buf, size_t count)162{163 struct tb *tb = container_of(dev, struct tb, dev);164 char *str, *s, *uuid_str;165 ssize_t ret = 0;166 uuid_t *acl;167 int i = 0;168 169 /*170 * Make sure the value is not bigger than tb->nboot_acl * UUID171 * length + commas and optional "\n". Also the smallest allowable172 * string is tb->nboot_acl * ",".173 */174 if (count > (UUID_STRING_LEN + 1) * tb->nboot_acl + 1)175 return -EINVAL;176 if (count < tb->nboot_acl - 1)177 return -EINVAL;178 179 str = kstrdup(buf, GFP_KERNEL);180 if (!str)181 return -ENOMEM;182 183 acl = kcalloc(tb->nboot_acl, sizeof(uuid_t), GFP_KERNEL);184 if (!acl) {185 ret = -ENOMEM;186 goto err_free_str;187 }188 189 uuid_str = strim(str);190 while ((s = strsep(&uuid_str, ",")) != NULL && i < tb->nboot_acl) {191 size_t len = strlen(s);192 193 if (len) {194 if (len != UUID_STRING_LEN) {195 ret = -EINVAL;196 goto err_free_acl;197 }198 ret = uuid_parse(s, &acl[i]);199 if (ret)200 goto err_free_acl;201 }202 203 i++;204 }205 206 if (s || i < tb->nboot_acl) {207 ret = -EINVAL;208 goto err_free_acl;209 }210 211 pm_runtime_get_sync(&tb->dev);212 213 if (mutex_lock_interruptible(&tb->lock)) {214 ret = -ERESTARTSYS;215 goto err_rpm_put;216 }217 ret = tb->cm_ops->set_boot_acl(tb, acl, tb->nboot_acl);218 if (!ret) {219 /* Notify userspace about the change */220 kobject_uevent(&tb->dev.kobj, KOBJ_CHANGE);221 }222 mutex_unlock(&tb->lock);223 224err_rpm_put:225 pm_runtime_mark_last_busy(&tb->dev);226 pm_runtime_put_autosuspend(&tb->dev);227err_free_acl:228 kfree(acl);229err_free_str:230 kfree(str);231 232 return ret ?: count;233}234static DEVICE_ATTR_RW(boot_acl);235 236static ssize_t deauthorization_show(struct device *dev,237 struct device_attribute *attr,238 char *buf)239{240 const struct tb *tb = container_of(dev, struct tb, dev);241 bool deauthorization = false;242 243 /* Only meaningful if authorization is supported */244 if (tb->security_level == TB_SECURITY_USER ||245 tb->security_level == TB_SECURITY_SECURE)246 deauthorization = !!tb->cm_ops->disapprove_switch;247 248 return sysfs_emit(buf, "%d\n", deauthorization);249}250static DEVICE_ATTR_RO(deauthorization);251 252static ssize_t iommu_dma_protection_show(struct device *dev,253 struct device_attribute *attr,254 char *buf)255{256 struct tb *tb = container_of(dev, struct tb, dev);257 258 return sysfs_emit(buf, "%d\n", tb->nhi->iommu_dma_protection);259}260static DEVICE_ATTR_RO(iommu_dma_protection);261 262static ssize_t security_show(struct device *dev, struct device_attribute *attr,263 char *buf)264{265 struct tb *tb = container_of(dev, struct tb, dev);266 const char *name = "unknown";267 268 if (tb->security_level < ARRAY_SIZE(tb_security_names))269 name = tb_security_names[tb->security_level];270 271 return sysfs_emit(buf, "%s\n", name);272}273static DEVICE_ATTR_RO(security);274 275static struct attribute *domain_attrs[] = {276 &dev_attr_boot_acl.attr,277 &dev_attr_deauthorization.attr,278 &dev_attr_iommu_dma_protection.attr,279 &dev_attr_security.attr,280 NULL,281};282 283static umode_t domain_attr_is_visible(struct kobject *kobj,284 struct attribute *attr, int n)285{286 struct device *dev = kobj_to_dev(kobj);287 struct tb *tb = container_of(dev, struct tb, dev);288 289 if (attr == &dev_attr_boot_acl.attr) {290 if (tb->nboot_acl &&291 tb->cm_ops->get_boot_acl &&292 tb->cm_ops->set_boot_acl)293 return attr->mode;294 return 0;295 }296 297 return attr->mode;298}299 300static const struct attribute_group domain_attr_group = {301 .is_visible = domain_attr_is_visible,302 .attrs = domain_attrs,303};304 305static const struct attribute_group *domain_attr_groups[] = {306 &domain_attr_group,307 NULL,308};309 310const struct bus_type tb_bus_type = {311 .name = "thunderbolt",312 .match = tb_service_match,313 .probe = tb_service_probe,314 .remove = tb_service_remove,315 .shutdown = tb_service_shutdown,316};317 318static void tb_domain_release(struct device *dev)319{320 struct tb *tb = container_of(dev, struct tb, dev);321 322 tb_ctl_free(tb->ctl);323 destroy_workqueue(tb->wq);324 ida_free(&tb_domain_ida, tb->index);325 mutex_destroy(&tb->lock);326 kfree(tb);327}328 329const struct device_type tb_domain_type = {330 .name = "thunderbolt_domain",331 .release = tb_domain_release,332};333 334static bool tb_domain_event_cb(void *data, enum tb_cfg_pkg_type type,335 const void *buf, size_t size)336{337 struct tb *tb = data;338 339 if (!tb->cm_ops->handle_event) {340 tb_warn(tb, "domain does not have event handler\n");341 return true;342 }343 344 switch (type) {345 case TB_CFG_PKG_XDOMAIN_REQ:346 case TB_CFG_PKG_XDOMAIN_RESP:347 if (tb_is_xdomain_enabled())348 return tb_xdomain_handle_request(tb, type, buf, size);349 break;350 351 default:352 tb->cm_ops->handle_event(tb, type, buf, size);353 }354 355 return true;356}357 358/**359 * tb_domain_alloc() - Allocate a domain360 * @nhi: Pointer to the host controller361 * @timeout_msec: Control channel timeout for non-raw messages362 * @privsize: Size of the connection manager private data363 *364 * Allocates and initializes a new Thunderbolt domain. Connection365 * managers are expected to call this and then fill in @cm_ops366 * accordingly.367 *368 * Call tb_domain_put() to release the domain before it has been added369 * to the system.370 *371 * Return: allocated domain structure on %NULL in case of error372 */373struct tb *tb_domain_alloc(struct tb_nhi *nhi, int timeout_msec, size_t privsize)374{375 struct tb *tb;376 377 /*378 * Make sure the structure sizes map with that the hardware379 * expects because bit-fields are being used.380 */381 BUILD_BUG_ON(sizeof(struct tb_regs_switch_header) != 5 * 4);382 BUILD_BUG_ON(sizeof(struct tb_regs_port_header) != 8 * 4);383 BUILD_BUG_ON(sizeof(struct tb_regs_hop) != 2 * 4);384 385 tb = kzalloc(sizeof(*tb) + privsize, GFP_KERNEL);386 if (!tb)387 return NULL;388 389 tb->nhi = nhi;390 mutex_init(&tb->lock);391 392 tb->index = ida_alloc(&tb_domain_ida, GFP_KERNEL);393 if (tb->index < 0)394 goto err_free;395 396 tb->wq = alloc_ordered_workqueue("thunderbolt%d", 0, tb->index);397 if (!tb->wq)398 goto err_remove_ida;399 400 tb->ctl = tb_ctl_alloc(nhi, tb->index, timeout_msec, tb_domain_event_cb, tb);401 if (!tb->ctl)402 goto err_destroy_wq;403 404 tb->dev.parent = &nhi->pdev->dev;405 tb->dev.bus = &tb_bus_type;406 tb->dev.type = &tb_domain_type;407 tb->dev.groups = domain_attr_groups;408 dev_set_name(&tb->dev, "domain%d", tb->index);409 device_initialize(&tb->dev);410 411 return tb;412 413err_destroy_wq:414 destroy_workqueue(tb->wq);415err_remove_ida:416 ida_free(&tb_domain_ida, tb->index);417err_free:418 kfree(tb);419 420 return NULL;421}422 423/**424 * tb_domain_add() - Add domain to the system425 * @tb: Domain to add426 * @reset: Issue reset to the host router427 *428 * Starts the domain and adds it to the system. Hotplugging devices will429 * work after this has been returned successfully. In order to remove430 * and release the domain after this function has been called, call431 * tb_domain_remove().432 *433 * Return: %0 in case of success and negative errno in case of error434 */435int tb_domain_add(struct tb *tb, bool reset)436{437 int ret;438 439 if (WARN_ON(!tb->cm_ops))440 return -EINVAL;441 442 mutex_lock(&tb->lock);443 /*444 * tb_schedule_hotplug_handler may be called as soon as the config445 * channel is started. Thats why we have to hold the lock here.446 */447 tb_ctl_start(tb->ctl);448 449 if (tb->cm_ops->driver_ready) {450 ret = tb->cm_ops->driver_ready(tb);451 if (ret)452 goto err_ctl_stop;453 }454 455 tb_dbg(tb, "security level set to %s\n",456 tb_security_names[tb->security_level]);457 458 ret = device_add(&tb->dev);459 if (ret)460 goto err_ctl_stop;461 462 /* Start the domain */463 if (tb->cm_ops->start) {464 ret = tb->cm_ops->start(tb, reset);465 if (ret)466 goto err_domain_del;467 }468 469 /* This starts event processing */470 mutex_unlock(&tb->lock);471 472 device_init_wakeup(&tb->dev, true);473 474 pm_runtime_no_callbacks(&tb->dev);475 pm_runtime_set_active(&tb->dev);476 pm_runtime_enable(&tb->dev);477 pm_runtime_set_autosuspend_delay(&tb->dev, TB_AUTOSUSPEND_DELAY);478 pm_runtime_mark_last_busy(&tb->dev);479 pm_runtime_use_autosuspend(&tb->dev);480 481 return 0;482 483err_domain_del:484 device_del(&tb->dev);485err_ctl_stop:486 tb_ctl_stop(tb->ctl);487 mutex_unlock(&tb->lock);488 489 return ret;490}491 492/**493 * tb_domain_remove() - Removes and releases a domain494 * @tb: Domain to remove495 *496 * Stops the domain, removes it from the system and releases all497 * resources once the last reference has been released.498 */499void tb_domain_remove(struct tb *tb)500{501 mutex_lock(&tb->lock);502 if (tb->cm_ops->stop)503 tb->cm_ops->stop(tb);504 /* Stop the domain control traffic */505 tb_ctl_stop(tb->ctl);506 mutex_unlock(&tb->lock);507 508 flush_workqueue(tb->wq);509 510 if (tb->cm_ops->deinit)511 tb->cm_ops->deinit(tb);512 513 device_unregister(&tb->dev);514}515 516/**517 * tb_domain_suspend_noirq() - Suspend a domain518 * @tb: Domain to suspend519 *520 * Suspends all devices in the domain and stops the control channel.521 */522int tb_domain_suspend_noirq(struct tb *tb)523{524 int ret = 0;525 526 /*527 * The control channel interrupt is left enabled during suspend528 * and taking the lock here prevents any events happening before529 * we actually have stopped the domain and the control channel.530 */531 mutex_lock(&tb->lock);532 if (tb->cm_ops->suspend_noirq)533 ret = tb->cm_ops->suspend_noirq(tb);534 if (!ret)535 tb_ctl_stop(tb->ctl);536 mutex_unlock(&tb->lock);537 538 return ret;539}540 541/**542 * tb_domain_resume_noirq() - Resume a domain543 * @tb: Domain to resume544 *545 * Re-starts the control channel, and resumes all devices connected to546 * the domain.547 */548int tb_domain_resume_noirq(struct tb *tb)549{550 int ret = 0;551 552 mutex_lock(&tb->lock);553 tb_ctl_start(tb->ctl);554 if (tb->cm_ops->resume_noirq)555 ret = tb->cm_ops->resume_noirq(tb);556 mutex_unlock(&tb->lock);557 558 return ret;559}560 561int tb_domain_suspend(struct tb *tb)562{563 return tb->cm_ops->suspend ? tb->cm_ops->suspend(tb) : 0;564}565 566int tb_domain_freeze_noirq(struct tb *tb)567{568 int ret = 0;569 570 mutex_lock(&tb->lock);571 if (tb->cm_ops->freeze_noirq)572 ret = tb->cm_ops->freeze_noirq(tb);573 if (!ret)574 tb_ctl_stop(tb->ctl);575 mutex_unlock(&tb->lock);576 577 return ret;578}579 580int tb_domain_thaw_noirq(struct tb *tb)581{582 int ret = 0;583 584 mutex_lock(&tb->lock);585 tb_ctl_start(tb->ctl);586 if (tb->cm_ops->thaw_noirq)587 ret = tb->cm_ops->thaw_noirq(tb);588 mutex_unlock(&tb->lock);589 590 return ret;591}592 593void tb_domain_complete(struct tb *tb)594{595 if (tb->cm_ops->complete)596 tb->cm_ops->complete(tb);597}598 599int tb_domain_runtime_suspend(struct tb *tb)600{601 if (tb->cm_ops->runtime_suspend) {602 int ret = tb->cm_ops->runtime_suspend(tb);603 if (ret)604 return ret;605 }606 tb_ctl_stop(tb->ctl);607 return 0;608}609 610int tb_domain_runtime_resume(struct tb *tb)611{612 tb_ctl_start(tb->ctl);613 if (tb->cm_ops->runtime_resume) {614 int ret = tb->cm_ops->runtime_resume(tb);615 if (ret)616 return ret;617 }618 return 0;619}620 621/**622 * tb_domain_disapprove_switch() - Disapprove switch623 * @tb: Domain the switch belongs to624 * @sw: Switch to disapprove625 *626 * This will disconnect PCIe tunnel from parent to this @sw.627 *628 * Return: %0 on success and negative errno in case of failure.629 */630int tb_domain_disapprove_switch(struct tb *tb, struct tb_switch *sw)631{632 if (!tb->cm_ops->disapprove_switch)633 return -EPERM;634 635 return tb->cm_ops->disapprove_switch(tb, sw);636}637 638/**639 * tb_domain_approve_switch() - Approve switch640 * @tb: Domain the switch belongs to641 * @sw: Switch to approve642 *643 * This will approve switch by connection manager specific means. In644 * case of success the connection manager will create PCIe tunnel from645 * parent to @sw.646 */647int tb_domain_approve_switch(struct tb *tb, struct tb_switch *sw)648{649 struct tb_switch *parent_sw;650 651 if (!tb->cm_ops->approve_switch)652 return -EPERM;653 654 /* The parent switch must be authorized before this one */655 parent_sw = tb_to_switch(sw->dev.parent);656 if (!parent_sw || !parent_sw->authorized)657 return -EINVAL;658 659 return tb->cm_ops->approve_switch(tb, sw);660}661 662/**663 * tb_domain_approve_switch_key() - Approve switch and add key664 * @tb: Domain the switch belongs to665 * @sw: Switch to approve666 *667 * For switches that support secure connect, this function first adds668 * key to the switch NVM using connection manager specific means. If669 * adding the key is successful, the switch is approved and connected.670 *671 * Return: %0 on success and negative errno in case of failure.672 */673int tb_domain_approve_switch_key(struct tb *tb, struct tb_switch *sw)674{675 struct tb_switch *parent_sw;676 int ret;677 678 if (!tb->cm_ops->approve_switch || !tb->cm_ops->add_switch_key)679 return -EPERM;680 681 /* The parent switch must be authorized before this one */682 parent_sw = tb_to_switch(sw->dev.parent);683 if (!parent_sw || !parent_sw->authorized)684 return -EINVAL;685 686 ret = tb->cm_ops->add_switch_key(tb, sw);687 if (ret)688 return ret;689 690 return tb->cm_ops->approve_switch(tb, sw);691}692 693/**694 * tb_domain_challenge_switch_key() - Challenge and approve switch695 * @tb: Domain the switch belongs to696 * @sw: Switch to approve697 *698 * For switches that support secure connect, this function generates699 * random challenge and sends it to the switch. The switch responds to700 * this and if the response matches our random challenge, the switch is701 * approved and connected.702 *703 * Return: %0 on success and negative errno in case of failure.704 */705int tb_domain_challenge_switch_key(struct tb *tb, struct tb_switch *sw)706{707 u8 challenge[TB_SWITCH_KEY_SIZE];708 u8 response[TB_SWITCH_KEY_SIZE];709 u8 hmac[TB_SWITCH_KEY_SIZE];710 struct tb_switch *parent_sw;711 struct crypto_shash *tfm;712 struct shash_desc *shash;713 int ret;714 715 if (!tb->cm_ops->approve_switch || !tb->cm_ops->challenge_switch_key)716 return -EPERM;717 718 /* The parent switch must be authorized before this one */719 parent_sw = tb_to_switch(sw->dev.parent);720 if (!parent_sw || !parent_sw->authorized)721 return -EINVAL;722 723 get_random_bytes(challenge, sizeof(challenge));724 ret = tb->cm_ops->challenge_switch_key(tb, sw, challenge, response);725 if (ret)726 return ret;727 728 tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);729 if (IS_ERR(tfm))730 return PTR_ERR(tfm);731 732 ret = crypto_shash_setkey(tfm, sw->key, TB_SWITCH_KEY_SIZE);733 if (ret)734 goto err_free_tfm;735 736 shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),737 GFP_KERNEL);738 if (!shash) {739 ret = -ENOMEM;740 goto err_free_tfm;741 }742 743 shash->tfm = tfm;744 745 memset(hmac, 0, sizeof(hmac));746 ret = crypto_shash_digest(shash, challenge, sizeof(hmac), hmac);747 if (ret)748 goto err_free_shash;749 750 /* The returned HMAC must match the one we calculated */751 if (memcmp(response, hmac, sizeof(hmac))) {752 ret = -EKEYREJECTED;753 goto err_free_shash;754 }755 756 crypto_free_shash(tfm);757 kfree(shash);758 759 return tb->cm_ops->approve_switch(tb, sw);760 761err_free_shash:762 kfree(shash);763err_free_tfm:764 crypto_free_shash(tfm);765 766 return ret;767}768 769/**770 * tb_domain_disconnect_pcie_paths() - Disconnect all PCIe paths771 * @tb: Domain whose PCIe paths to disconnect772 *773 * This needs to be called in preparation for NVM upgrade of the host774 * controller. Makes sure all PCIe paths are disconnected.775 *776 * Return %0 on success and negative errno in case of error.777 */778int tb_domain_disconnect_pcie_paths(struct tb *tb)779{780 if (!tb->cm_ops->disconnect_pcie_paths)781 return -EPERM;782 783 return tb->cm_ops->disconnect_pcie_paths(tb);784}785 786/**787 * tb_domain_approve_xdomain_paths() - Enable DMA paths for XDomain788 * @tb: Domain enabling the DMA paths789 * @xd: XDomain DMA paths are created to790 * @transmit_path: HopID we are using to send out packets791 * @transmit_ring: DMA ring used to send out packets792 * @receive_path: HopID the other end is using to send packets to us793 * @receive_ring: DMA ring used to receive packets from @receive_path794 *795 * Calls connection manager specific method to enable DMA paths to the796 * XDomain in question.797 *798 * Return: 0% in case of success and negative errno otherwise. In799 * particular returns %-ENOTSUPP if the connection manager800 * implementation does not support XDomains.801 */802int tb_domain_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,803 int transmit_path, int transmit_ring,804 int receive_path, int receive_ring)805{806 if (!tb->cm_ops->approve_xdomain_paths)807 return -ENOTSUPP;808 809 return tb->cm_ops->approve_xdomain_paths(tb, xd, transmit_path,810 transmit_ring, receive_path, receive_ring);811}812 813/**814 * tb_domain_disconnect_xdomain_paths() - Disable DMA paths for XDomain815 * @tb: Domain disabling the DMA paths816 * @xd: XDomain whose DMA paths are disconnected817 * @transmit_path: HopID we are using to send out packets818 * @transmit_ring: DMA ring used to send out packets819 * @receive_path: HopID the other end is using to send packets to us820 * @receive_ring: DMA ring used to receive packets from @receive_path821 *822 * Calls connection manager specific method to disconnect DMA paths to823 * the XDomain in question.824 *825 * Return: 0% in case of success and negative errno otherwise. In826 * particular returns %-ENOTSUPP if the connection manager827 * implementation does not support XDomains.828 */829int tb_domain_disconnect_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,830 int transmit_path, int transmit_ring,831 int receive_path, int receive_ring)832{833 if (!tb->cm_ops->disconnect_xdomain_paths)834 return -ENOTSUPP;835 836 return tb->cm_ops->disconnect_xdomain_paths(tb, xd, transmit_path,837 transmit_ring, receive_path, receive_ring);838}839 840static int disconnect_xdomain(struct device *dev, void *data)841{842 struct tb_xdomain *xd;843 struct tb *tb = data;844 int ret = 0;845 846 xd = tb_to_xdomain(dev);847 if (xd && xd->tb == tb)848 ret = tb_xdomain_disable_all_paths(xd);849 850 return ret;851}852 853/**854 * tb_domain_disconnect_all_paths() - Disconnect all paths for the domain855 * @tb: Domain whose paths are disconnected856 *857 * This function can be used to disconnect all paths (PCIe, XDomain) for858 * example in preparation for host NVM firmware upgrade. After this is859 * called the paths cannot be established without resetting the switch.860 *861 * Return: %0 in case of success and negative errno otherwise.862 */863int tb_domain_disconnect_all_paths(struct tb *tb)864{865 int ret;866 867 ret = tb_domain_disconnect_pcie_paths(tb);868 if (ret)869 return ret;870 871 return bus_for_each_dev(&tb_bus_type, NULL, tb, disconnect_xdomain);872}873 874int tb_domain_init(void)875{876 int ret;877 878 tb_debugfs_init();879 tb_acpi_init();880 881 ret = tb_xdomain_init();882 if (ret)883 goto err_acpi;884 ret = bus_register(&tb_bus_type);885 if (ret)886 goto err_xdomain;887 888 return 0;889 890err_xdomain:891 tb_xdomain_exit();892err_acpi:893 tb_acpi_exit();894 tb_debugfs_exit();895 896 return ret;897}898 899void tb_domain_exit(void)900{901 bus_unregister(&tb_bus_type);902 ida_destroy(&tb_domain_ida);903 tb_nvm_exit();904 tb_xdomain_exit();905 tb_acpi_exit();906 tb_debugfs_exit();907}908