3039 lines · 70.7 KB · C
RawDownload
// 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.