// SPDX-License-Identifier: GPL-2.0/* * Thunderbolt driver - switch/port utility functions * * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com> * Copyright (C) 2018, Intel Corporation */ #include <linux/delay.h>#include <linux/idr.h>#include <linux/nvmem-provider.h>#include <linux/pm_runtime.h>#include <linux/sched/signal.h>#include <linux/sizes.h>#include <linux/slab.h> #include "tb.h" /* Switch NVM support */ #define NVM_CSS 0x10 struct nvm_auth_status { struct list_head list; uuid_t uuid; u32 status;}; enum nvm_write_ops { WRITE_AND_AUTHENTICATE = 1, WRITE_ONLY = 2,}; /* * Hold NVM authentication failure status per switch This information * needs to stay around even when the switch gets power cycled so we * keep it separately. */static LIST_HEAD(nvm_auth_status_cache);static DEFINE_MUTEX(nvm_auth_status_lock); static struct nvm_auth_status *__nvm_get_auth_status(const struct tb_switch *sw){ struct nvm_auth_status *st; list_for_each_entry(st, &nvm_auth_status_cache, list) { if (uuid_equal(&st->uuid, sw->uuid)) return st; } return NULL;} static void nvm_get_auth_status(const struct tb_switch *sw, u32 *status){ struct nvm_auth_status *st; mutex_lock(&nvm_auth_status_lock); st = __nvm_get_auth_status(sw); mutex_unlock(&nvm_auth_status_lock); *status = st ? st->status : 0;} static void nvm_set_auth_status(const struct tb_switch *sw, u32 status){ struct nvm_auth_status *st; if (WARN_ON(!sw->uuid)) return; mutex_lock(&nvm_auth_status_lock); st = __nvm_get_auth_status(sw); if (!st) { st = kzalloc(sizeof(*st), GFP_KERNEL); if (!st) goto unlock; memcpy(&st->uuid, sw->uuid, sizeof(st->uuid)); INIT_LIST_HEAD(&st->list); list_add_tail(&st->list, &nvm_auth_status_cache); } st->status = status;unlock: mutex_unlock(&nvm_auth_status_lock);} static void nvm_clear_auth_status(const struct tb_switch *sw){ struct nvm_auth_status *st; mutex_lock(&nvm_auth_status_lock); st = __nvm_get_auth_status(sw); if (st) { list_del(&st->list); kfree(st); } mutex_unlock(&nvm_auth_status_lock);} static int nvm_validate_and_write(struct tb_switch *sw){ unsigned int image_size, hdr_size; const u8 *buf = sw->nvm->buf; u16 ds_size; int ret; if (!buf) return -EINVAL; image_size = sw->nvm->buf_data_size; if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE) return -EINVAL; /* * FARB pointer must point inside the image and must at least * contain parts of the digital section we will be reading here. */ hdr_size = (*(u32 *)buf) & 0xffffff; if (hdr_size + NVM_DEVID + 2 >= image_size) return -EINVAL; /* Digital section start should be aligned to 4k page */ if (!IS_ALIGNED(hdr_size, SZ_4K)) return -EINVAL; /* * Read digital section size and check that it also fits inside * the image. */ ds_size = *(u16 *)(buf + hdr_size); if (ds_size >= image_size) return -EINVAL; if (!sw->safe_mode) { u16 device_id; /* * Make sure the device ID in the image matches the one * we read from the switch config space. */ device_id = *(u16 *)(buf + hdr_size + NVM_DEVID); if (device_id != sw->config.device_id) return -EINVAL; if (sw->generation < 3) { /* Write CSS headers first */ ret = dma_port_flash_write(sw->dma_port, DMA_PORT_CSS_ADDRESS, buf + NVM_CSS, DMA_PORT_CSS_MAX_SIZE); if (ret) return ret; } /* Skip headers in the image */ buf += hdr_size; image_size -= hdr_size; } if (tb_switch_is_usb4(sw)) ret = usb4_switch_nvm_write(sw, 0, buf, image_size); else ret = dma_port_flash_write(sw->dma_port, 0, buf, image_size); if (!ret) sw->nvm->flushed = true; return ret;} static int nvm_authenticate_host_dma_port(struct tb_switch *sw){ int ret = 0; /* * Root switch NVM upgrade requires that we disconnect the * existing paths first (in case it is not in safe mode * already). */ if (!sw->safe_mode) { u32 status; ret = tb_domain_disconnect_all_paths(sw->tb); if (ret) return ret; /* * The host controller goes away pretty soon after this if * everything goes well so getting timeout is expected. */ ret = dma_port_flash_update_auth(sw->dma_port); if (!ret || ret == -ETIMEDOUT) return 0; /* * Any error from update auth operation requires power * cycling of the host router. */ tb_sw_warn(sw, "failed to authenticate NVM, power cycling\n"); if (dma_port_flash_update_auth_status(sw->dma_port, &status) > 0) nvm_set_auth_status(sw, status); } /* * From safe mode we can get out by just power cycling the * switch. */ dma_port_power_cycle(sw->dma_port); return ret;} static int nvm_authenticate_device_dma_port(struct tb_switch *sw){ int ret, retries = 10; ret = dma_port_flash_update_auth(sw->dma_port); switch (ret) { case 0: case -ETIMEDOUT: case -EACCES: case -EINVAL: /* Power cycle is required */ break; default: return ret; } /* * Poll here for the authentication status. It takes some time * for the device to respond (we get timeout for a while). Once * we get response the device needs to be power cycled in order * to the new NVM to be taken into use. */ do { u32 status; ret = dma_port_flash_update_auth_status(sw->dma_port, &status); if (ret < 0 && ret != -ETIMEDOUT) return ret; if (ret > 0) { if (status) { tb_sw_warn(sw, "failed to authenticate NVM\n"); nvm_set_auth_status(sw, status); } tb_sw_info(sw, "power cycling the switch now\n"); dma_port_power_cycle(sw->dma_port); return 0; } msleep(500); } while (--retries); return -ETIMEDOUT;} static void nvm_authenticate_start_dma_port(struct tb_switch *sw){ struct pci_dev *root_port; /* * During host router NVM upgrade we should not allow root port to * go into D3cold because some root ports cannot trigger PME * itself. To be on the safe side keep the root port in D0 during * the whole upgrade process. */ root_port = pcie_find_root_port(sw->tb->nhi->pdev); if (root_port) pm_runtime_get_noresume(&root_port->dev);} static void nvm_authenticate_complete_dma_port(struct tb_switch *sw){ struct pci_dev *root_port; root_port = pcie_find_root_port(sw->tb->nhi->pdev); if (root_port) pm_runtime_put(&root_port->dev);} static inline bool nvm_readable(struct tb_switch *sw){ if (tb_switch_is_usb4(sw)) { /* * USB4 devices must support NVM operations but it is * optional for hosts. Therefore we query the NVM sector * size here and if it is supported assume NVM * operations are implemented. */ return usb4_switch_nvm_sector_size(sw) > 0; } /* Thunderbolt 2 and 3 devices support NVM through DMA port */ return !!sw->dma_port;} static inline bool nvm_upgradeable(struct tb_switch *sw){ if (sw->no_nvm_upgrade) return false; return nvm_readable(sw);} static inline int nvm_read(struct tb_switch *sw, unsigned int address, void *buf, size_t size){ if (tb_switch_is_usb4(sw)) return usb4_switch_nvm_read(sw, address, buf, size); return dma_port_flash_read(sw->dma_port, address, buf, size);} static int nvm_authenticate(struct tb_switch *sw){ int ret; if (tb_switch_is_usb4(sw)) return usb4_switch_nvm_authenticate(sw); if (!tb_route(sw)) { nvm_authenticate_start_dma_port(sw); ret = nvm_authenticate_host_dma_port(sw); } else { ret = nvm_authenticate_device_dma_port(sw); } return ret;} static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val, size_t bytes){ struct tb_nvm *nvm = priv; struct tb_switch *sw = tb_to_switch(nvm->dev); int ret; pm_runtime_get_sync(&sw->dev); if (!mutex_trylock(&sw->tb->lock)) { ret = restart_syscall(); goto out; } ret = nvm_read(sw, offset, val, bytes); mutex_unlock(&sw->tb->lock); out: pm_runtime_mark_last_busy(&sw->dev); pm_runtime_put_autosuspend(&sw->dev); return ret;} static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val, size_t bytes){ struct tb_nvm *nvm = priv; struct tb_switch *sw = tb_to_switch(nvm->dev); int ret; if (!mutex_trylock(&sw->tb->lock)) return restart_syscall(); /* * Since writing the NVM image might require some special steps, * for example when CSS headers are written, we cache the image * locally here and handle the special cases when the user asks * us to authenticate the image. */ ret = tb_nvm_write_buf(nvm, offset, val, bytes); mutex_unlock(&sw->tb->lock); return ret;} static int tb_switch_nvm_add(struct tb_switch *sw){ struct tb_nvm *nvm; u32 val; int ret; if (!nvm_readable(sw)) return 0; /* * The NVM format of non-Intel hardware is not known so * currently restrict NVM upgrade for Intel hardware. We may * relax this in the future when we learn other NVM formats. */ if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL && sw->config.vendor_id != 0x8087) { dev_info(&sw->dev, "NVM format of vendor %#x is not known, disabling NVM upgrade\n", sw->config.vendor_id); return 0; } nvm = tb_nvm_alloc(&sw->dev); if (IS_ERR(nvm)) return PTR_ERR(nvm); /* * If the switch is in safe-mode the only accessible portion of * the NVM is the non-active one where userspace is expected to * write new functional NVM. */ if (!sw->safe_mode) { u32 nvm_size, hdr_size; ret = nvm_read(sw, NVM_FLASH_SIZE, &val, sizeof(val)); if (ret) goto err_nvm; hdr_size = sw->generation < 3 ? SZ_8K : SZ_16K; nvm_size = (SZ_1M << (val & 7)) / 8; nvm_size = (nvm_size - hdr_size) / 2; ret = nvm_read(sw, NVM_VERSION, &val, sizeof(val)); if (ret) goto err_nvm; nvm->major = val >> 16; nvm->minor = val >> 8; ret = tb_nvm_add_active(nvm, nvm_size, tb_switch_nvm_read); if (ret) goto err_nvm; } if (!sw->no_nvm_upgrade) { ret = tb_nvm_add_non_active(nvm, NVM_MAX_SIZE, tb_switch_nvm_write); if (ret) goto err_nvm; } sw->nvm = nvm; return 0; err_nvm: tb_nvm_free(nvm); return ret;} static void tb_switch_nvm_remove(struct tb_switch *sw){ struct tb_nvm *nvm; nvm = sw->nvm; sw->nvm = NULL; if (!nvm) return; /* Remove authentication status in case the switch is unplugged */ if (!nvm->authenticating) nvm_clear_auth_status(sw); tb_nvm_free(nvm);} /* port utility functions */ static const char *tb_port_type(struct tb_regs_port_header *port){ switch (port->type >> 16) { case 0: switch ((u8) port->type) { case 0: return "Inactive"; case 1: return "Port"; case 2: return "NHI"; default: return "unknown"; } case 0x2: return "Ethernet"; case 0x8: return "SATA"; case 0xe: return "DP/HDMI"; case 0x10: return "PCIe"; case 0x20: return "USB"; default: return "unknown"; }} static void tb_dump_port(struct tb *tb, struct tb_regs_port_header *port){ tb_dbg(tb, " Port %d: %x:%x (Revision: %d, TB Version: %d, Type: %s (%#x))\n", port->port_number, port->vendor_id, port->device_id, port->revision, port->thunderbolt_version, tb_port_type(port), port->type); tb_dbg(tb, " Max hop id (in/out): %d/%d\n", port->max_in_hop_id, port->max_out_hop_id); tb_dbg(tb, " Max counters: %d\n", port->max_counters);Lines 1–500 of 3039. Load more
// SPDX-License-Identifier: GPL-2.0 /* * Thunderbolt driver - switch/port utility functions * * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com> * Copyright (C) 2018, Intel Corporation */ #include <linux/delay.h> #include <linux/idr.h> #include <linux/nvmem-provider.h> #include <linux/pm_runtime.h> #include <linux/sched/signal.h> #include <linux/sizes.h> #include <linux/slab.h> #include "tb.h" /* Switch NVM support */ #define NVM_CSS 0x10 struct nvm_auth_status { struct list_head list; uuid_t uuid; u32 status; }; enum nvm_write_ops { WRITE_AND_AUTHENTICATE = 1, WRITE_ONLY = 2, }; /* * Hold NVM authentication failure status per switch This information * needs to stay around even when the switch gets power cycled so we * keep it separately. */ static LIST_HEAD(nvm_auth_status_cache); static DEFINE_MUTEX(nvm_auth_status_lock); static struct nvm_auth_status *__nvm_get_auth_status(const struct tb_switch *sw) { struct nvm_auth_status *st; list_for_each_entry(st, &nvm_auth_status_cache, list) { if (uuid_equal(&st->uuid, sw->uuid)) return st; } return NULL; } static void nvm_get_auth_status(const struct tb_switch *sw, u32 *status) { struct nvm_auth_status *st; mutex_lock(&nvm_auth_status_lock); st = __nvm_get_auth_status(sw); mutex_unlock(&nvm_auth_status_lock); *status = st ? st->status : 0; } static void nvm_set_auth_status(const struct tb_switch *sw, u32 status) { struct nvm_auth_status *st; if (WARN_ON(!sw->uuid)) return; mutex_lock(&nvm_auth_status_lock); st = __nvm_get_auth_status(sw); if (!st) { st = kzalloc(sizeof(*st), GFP_KERNEL); if (!st) goto unlock; memcpy(&st->uuid, sw->uuid, sizeof(st->uuid)); INIT_LIST_HEAD(&st->list); list_add_tail(&st->list, &nvm_auth_status_cache); } st->status = status; unlock: mutex_unlock(&nvm_auth_status_lock); } static void nvm_clear_auth_status(const struct tb_switch *sw) { struct nvm_auth_status *st; mutex_lock(&nvm_auth_status_lock); st = __nvm_get_auth_status(sw); if (st) { list_del(&st->list); kfree(st); } mutex_unlock(&nvm_auth_status_lock); } static int nvm_validate_and_write(struct tb_switch *sw) { unsigned int image_size, hdr_size; const u8 *buf = sw->nvm->buf; u16 ds_size; int ret; if (!buf) return -EINVAL; image_size = sw->nvm->buf_data_size; if (image_size < NVM_MIN_SIZE || image_size > NVM_MAX_SIZE) return -EINVAL; /* * FARB pointer must point inside the image and must at least * contain parts of the digital section we will be reading here. */ hdr_size = (*(u32 *)buf) & 0xffffff; if (hdr_size + NVM_DEVID + 2 >= image_size) return -EINVAL; /* Digital section start should be aligned to 4k page */ if (!IS_ALIGNED(hdr_size, SZ_4K)) return -EINVAL; /* * Read digital section size and check that it also fits inside * the image. */ ds_size = *(u16 *)(buf + hdr_size); if (ds_size >= image_size) return -EINVAL; if (!sw->safe_mode) { u16 device_id; /* * Make sure the device ID in the image matches the one * we read from the switch config space. */ device_id = *(u16 *)(buf + hdr_size + NVM_DEVID); if (device_id != sw->config.device_id) return -EINVAL; if (sw->generation < 3) { /* Write CSS headers first */ ret = dma_port_flash_write(sw->dma_port, DMA_PORT_CSS_ADDRESS, buf + NVM_CSS, DMA_PORT_CSS_MAX_SIZE); if (ret) return ret; } /* Skip headers in the image */ buf += hdr_size; image_size -= hdr_size; } if (tb_switch_is_usb4(sw)) ret = usb4_switch_nvm_write(sw, 0, buf, image_size); else ret = dma_port_flash_write(sw->dma_port, 0, buf, image_size); if (!ret) sw->nvm->flushed = true; return ret; } static int nvm_authenticate_host_dma_port(struct tb_switch *sw) { int ret = 0; /* * Root switch NVM upgrade requires that we disconnect the * existing paths first (in case it is not in safe mode * already). */ if (!sw->safe_mode) { u32 status; ret = tb_domain_disconnect_all_paths(sw->tb); if (ret) return ret; /* * The host controller goes away pretty soon after this if * everything goes well so getting timeout is expected. */ ret = dma_port_flash_update_auth(sw->dma_port); if (!ret || ret == -ETIMEDOUT) return 0; /* * Any error from update auth operation requires power * cycling of the host router. */ tb_sw_warn(sw, "failed to authenticate NVM, power cycling\n"); if (dma_port_flash_update_auth_status(sw->dma_port, &status) > 0) nvm_set_auth_status(sw, status); } /* * From safe mode we can get out by just power cycling the * switch. */ dma_port_power_cycle(sw->dma_port); return ret; } static int nvm_authenticate_device_dma_port(struct tb_switch *sw) { int ret, retries = 10; ret = dma_port_flash_update_auth(sw->dma_port); switch (ret) { case 0: case -ETIMEDOUT: case -EACCES: case -EINVAL: /* Power cycle is required */ break; default: return ret; } /* * Poll here for the authentication status. It takes some time * for the device to respond (we get timeout for a while). Once * we get response the device needs to be power cycled in order * to the new NVM to be taken into use. */ do { u32 status; ret = dma_port_flash_update_auth_status(sw->dma_port, &status); if (ret < 0 && ret != -ETIMEDOUT) return ret; if (ret > 0) { if (status) { tb_sw_warn(sw, "failed to authenticate NVM\n"); nvm_set_auth_status(sw, status); } tb_sw_info(sw, "power cycling the switch now\n"); dma_port_power_cycle(sw->dma_port); return 0; } msleep(500); } while (--retries); return -ETIMEDOUT; } static void nvm_authenticate_start_dma_port(struct tb_switch *sw) { struct pci_dev *root_port; /* * During host router NVM upgrade we should not allow root port to * go into D3cold because some root ports cannot trigger PME * itself. To be on the safe side keep the root port in D0 during * the whole upgrade process. */ root_port = pcie_find_root_port(sw->tb->nhi->pdev); if (root_port) pm_runtime_get_noresume(&root_port->dev); } static void nvm_authenticate_complete_dma_port(struct tb_switch *sw) { struct pci_dev *root_port; root_port = pcie_find_root_port(sw->tb->nhi->pdev); if (root_port) pm_runtime_put(&root_port->dev); } static inline bool nvm_readable(struct tb_switch *sw) { if (tb_switch_is_usb4(sw)) { /* * USB4 devices must support NVM operations but it is * optional for hosts. Therefore we query the NVM sector * size here and if it is supported assume NVM * operations are implemented. */ return usb4_switch_nvm_sector_size(sw) > 0; } /* Thunderbolt 2 and 3 devices support NVM through DMA port */ return !!sw->dma_port; } static inline bool nvm_upgradeable(struct tb_switch *sw) { if (sw->no_nvm_upgrade) return false; return nvm_readable(sw); } static inline int nvm_read(struct tb_switch *sw, unsigned int address, void *buf, size_t size) { if (tb_switch_is_usb4(sw)) return usb4_switch_nvm_read(sw, address, buf, size); return dma_port_flash_read(sw->dma_port, address, buf, size); } static int nvm_authenticate(struct tb_switch *sw) { int ret; if (tb_switch_is_usb4(sw)) return usb4_switch_nvm_authenticate(sw); if (!tb_route(sw)) { nvm_authenticate_start_dma_port(sw); ret = nvm_authenticate_host_dma_port(sw); } else { ret = nvm_authenticate_device_dma_port(sw); } return ret; } static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val, size_t bytes) { struct tb_nvm *nvm = priv; struct tb_switch *sw = tb_to_switch(nvm->dev); int ret; pm_runtime_get_sync(&sw->dev); if (!mutex_trylock(&sw->tb->lock)) { ret = restart_syscall(); goto out; } ret = nvm_read(sw, offset, val, bytes); mutex_unlock(&sw->tb->lock); out: pm_runtime_mark_last_busy(&sw->dev); pm_runtime_put_autosuspend(&sw->dev); return ret; } static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val, size_t bytes) { struct tb_nvm *nvm = priv; struct tb_switch *sw = tb_to_switch(nvm->dev); int ret; if (!mutex_trylock(&sw->tb->lock)) return restart_syscall(); /* * Since writing the NVM image might require some special steps, * for example when CSS headers are written, we cache the image * locally here and handle the special cases when the user asks * us to authenticate the image. */ ret = tb_nvm_write_buf(nvm, offset, val, bytes); mutex_unlock(&sw->tb->lock); return ret; } static int tb_switch_nvm_add(struct tb_switch *sw) { struct tb_nvm *nvm; u32 val; int ret; if (!nvm_readable(sw)) return 0; /* * The NVM format of non-Intel hardware is not known so * currently restrict NVM upgrade for Intel hardware. We may * relax this in the future when we learn other NVM formats. */ if (sw->config.vendor_id != PCI_VENDOR_ID_INTEL && sw->config.vendor_id != 0x8087) { dev_info(&sw->dev, "NVM format of vendor %#x is not known, disabling NVM upgrade\n", sw->config.vendor_id); return 0; } nvm = tb_nvm_alloc(&sw->dev); if (IS_ERR(nvm)) return PTR_ERR(nvm); /* * If the switch is in safe-mode the only accessible portion of * the NVM is the non-active one where userspace is expected to * write new functional NVM. */ if (!sw->safe_mode) { u32 nvm_size, hdr_size; ret = nvm_read(sw, NVM_FLASH_SIZE, &val, sizeof(val)); if (ret) goto err_nvm; hdr_size = sw->generation < 3 ? SZ_8K : SZ_16K; nvm_size = (SZ_1M << (val & 7)) / 8; nvm_size = (nvm_size - hdr_size) / 2; ret = nvm_read(sw, NVM_VERSION, &val, sizeof(val)); if (ret) goto err_nvm; nvm->major = val >> 16; nvm->minor = val >> 8; ret = tb_nvm_add_active(nvm, nvm_size, tb_switch_nvm_read); if (ret) goto err_nvm; } if (!sw->no_nvm_upgrade) { ret = tb_nvm_add_non_active(nvm, NVM_MAX_SIZE, tb_switch_nvm_write); if (ret) goto err_nvm; } sw->nvm = nvm; return 0; err_nvm: tb_nvm_free(nvm); return ret; } static void tb_switch_nvm_remove(struct tb_switch *sw) { struct tb_nvm *nvm; nvm = sw->nvm; sw->nvm = NULL; if (!nvm) return; /* Remove authentication status in case the switch is unplugged */ if (!nvm->authenticating) nvm_clear_auth_status(sw); tb_nvm_free(nvm); } /* port utility functions */ static const char *tb_port_type(struct tb_regs_port_header *port) { switch (port->type >> 16) { case 0: switch ((u8) port->type) { case 0: return "Inactive"; case 1: return "Port"; case 2: return "NHI"; default: return "unknown"; } case 0x2: return "Ethernet"; case 0x8: return "SATA"; case 0xe: return "DP/HDMI"; case 0x10: return "PCIe"; case 0x20: return "USB"; default: return "unknown"; } } static void tb_dump_port(struct tb *tb, struct tb_regs_port_header *port) { tb_dbg(tb, " Port %d: %x:%x (Revision: %d, TB Version: %d, Type: %s (%#x))\n", port->port_number, port->vendor_id, port->device_id, port->revision, port->thunderbolt_version, tb_port_type(port), port->type); tb_dbg(tb, " Max hop id (in/out): %d/%d\n", port->max_in_hop_id, port->max_out_hop_id); tb_dbg(tb, " Max counters: %d\n", port->max_counters);