diff options
| -rw-r--r-- | Documentation/ABI/testing/sysfs-bus-siox | 22 | ||||
| -rw-r--r-- | Documentation/driver-api/uio-howto.rst | 4 | ||||
| -rw-r--r-- | Documentation/fb/fbcon.txt | 2 | ||||
| -rw-r--r-- | MAINTAINERS | 3 | ||||
| -rw-r--r-- | drivers/android/binder.c | 16 | ||||
| -rw-r--r-- | drivers/misc/habanalabs/habanalabs_ioctl.c | 2 | ||||
| -rw-r--r-- | drivers/soundwire/intel.c | 4 | ||||
| -rw-r--r-- | drivers/soundwire/stream.c | 7 | ||||
| -rw-r--r-- | drivers/thunderbolt/icm.c | 188 | ||||
| -rw-r--r-- | drivers/thunderbolt/switch.c | 45 | ||||
| -rw-r--r-- | drivers/thunderbolt/tb.h | 7 | 
11 files changed, 202 insertions, 98 deletions
| diff --git a/Documentation/ABI/testing/sysfs-bus-siox b/Documentation/ABI/testing/sysfs-bus-siox index fed7c3765a4e..c2a403f20b90 100644 --- a/Documentation/ABI/testing/sysfs-bus-siox +++ b/Documentation/ABI/testing/sysfs-bus-siox @@ -1,6 +1,6 @@  What:		/sys/bus/siox/devices/siox-X/active  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		On reading represents the current state of the bus. If it  		contains a "0" the bus is stopped and connected devices are @@ -12,7 +12,7 @@ Description:  What:		/sys/bus/siox/devices/siox-X/device_add  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Write-only file. Write @@ -27,13 +27,13 @@ Description:  What:		/sys/bus/siox/devices/siox-X/device_remove  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Write-only file. A single write removes the last device in the siox chain.  What:		/sys/bus/siox/devices/siox-X/poll_interval_ns  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Defines the interval between two poll cycles in nano seconds.  		Note this is rounded to jiffies on writing. On reading the current value @@ -41,33 +41,33 @@ Description:  What:		/sys/bus/siox/devices/siox-X-Y/connected  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Read-only value. "0" means the Yth device on siox bus X isn't "connected" i.e.  		communication with it is not ensured. "1" signals a working connection.  What:		/sys/bus/siox/devices/siox-X-Y/inbytes  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Read-only value reporting the inbytes value provided to siox-X/device_add  What:		/sys/bus/siox/devices/siox-X-Y/status_errors  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Counts the number of time intervals when the read status byte doesn't yield the  		expected value.  What:		/sys/bus/siox/devices/siox-X-Y/type  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Read-only value reporting the type value provided to siox-X/device_add.  What:		/sys/bus/siox/devices/siox-X-Y/watchdog  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Read-only value reporting if the watchdog of the siox device is  		active. "0" means the watchdog is not active and the device is expected to @@ -75,13 +75,13 @@ Description:  What:		/sys/bus/siox/devices/siox-X-Y/watchdog_errors  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Read-only value reporting the number to time intervals when the  		watchdog was active.  What:		/sys/bus/siox/devices/siox-X-Y/outbytes  KernelVersion:	4.16 -Contact:	Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Contact:	Thorsten Scherer <t.scherer@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  Description:  		Read-only value reporting the outbytes value provided to siox-X/device_add. diff --git a/Documentation/driver-api/uio-howto.rst b/Documentation/driver-api/uio-howto.rst index 25f50eace28b..8fecfa11d4ff 100644 --- a/Documentation/driver-api/uio-howto.rst +++ b/Documentation/driver-api/uio-howto.rst @@ -276,8 +276,8 @@ fields of ``struct uio_mem``:  -  ``int memtype``: Required if the mapping is used. Set this to     ``UIO_MEM_PHYS`` if you you have physical memory on your card to be     mapped. Use ``UIO_MEM_LOGICAL`` for logical memory (e.g. allocated -   with :c:func:`kmalloc()`). There's also ``UIO_MEM_VIRTUAL`` for -   virtual memory. +   with :c:func:`__get_free_pages()` but not kmalloc()). There's also +   ``UIO_MEM_VIRTUAL`` for virtual memory.  -  ``phys_addr_t addr``: Required if the mapping is used. Fill in the     address of your memory block. This address is the one that appears in diff --git a/Documentation/fb/fbcon.txt b/Documentation/fb/fbcon.txt index 60a5ec04e8f0..5a865437b33f 100644 --- a/Documentation/fb/fbcon.txt +++ b/Documentation/fb/fbcon.txt @@ -79,7 +79,7 @@ C. Boot options          Select the initial font to use. The value 'name' can be any of the          compiled-in fonts: 10x18, 6x10, 7x14, Acorn8x8, MINI4x6, -        PEARL8x8, ProFont6x11, SUN12x22, SUN8x16, VGA8x16, VGA8x8. +        PEARL8x8, ProFont6x11, SUN12x22, SUN8x16, TER16x32, VGA8x16, VGA8x8.  	Note, not all drivers can handle font with widths not divisible by 8,          such as vga16fb. diff --git a/MAINTAINERS b/MAINTAINERS index 46d3497af51f..d0ed735994a5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6234,7 +6234,6 @@ F:	include/linux/ipmi-fru.h  K:	fmc_d.*register  FPGA MANAGER FRAMEWORK -M:	Alan Tull <atull@kernel.org>  M:	Moritz Fischer <mdf@kernel.org>  L:	linux-fpga@vger.kernel.org  S:	Maintained @@ -14404,7 +14403,7 @@ F:	lib/test_siphash.c  F:	include/linux/siphash.h  SIOX -M:	Gavin Schenk <g.schenk@eckelmann.de> +M:	Thorsten Scherer <t.scherer@eckelmann.de>  M:	Uwe Kleine-König <u.kleine-koenig@pengutronix.de>  R:	Pengutronix Kernel Team <kernel@pengutronix.de>  S:	Supported diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 748ac489ef7e..bc26b5511f0a 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1941,8 +1941,18 @@ static void binder_free_txn_fixups(struct binder_transaction *t)  static void binder_free_transaction(struct binder_transaction *t)  { -	if (t->buffer) -		t->buffer->transaction = NULL; +	struct binder_proc *target_proc = t->to_proc; + +	if (target_proc) { +		binder_inner_proc_lock(target_proc); +		if (t->buffer) +			t->buffer->transaction = NULL; +		binder_inner_proc_unlock(target_proc); +	} +	/* +	 * If the transaction has no target_proc, then +	 * t->buffer->transaction has already been cleared. +	 */  	binder_free_txn_fixups(t);  	kfree(t);  	binder_stats_deleted(BINDER_STAT_TRANSACTION); @@ -3551,10 +3561,12 @@ err_invalid_target_handle:  static void  binder_free_buf(struct binder_proc *proc, struct binder_buffer *buffer)  { +	binder_inner_proc_lock(proc);  	if (buffer->transaction) {  		buffer->transaction->buffer = NULL;  		buffer->transaction = NULL;  	} +	binder_inner_proc_unlock(proc);  	if (buffer->async_transaction && buffer->target_node) {  		struct binder_node *buf_node;  		struct binder_work *w; diff --git a/drivers/misc/habanalabs/habanalabs_ioctl.c b/drivers/misc/habanalabs/habanalabs_ioctl.c index eeefb22023e9..b7a0eecf6b6c 100644 --- a/drivers/misc/habanalabs/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/habanalabs_ioctl.c @@ -140,7 +140,7 @@ static int debug_coresight(struct hl_device *hdev, struct hl_debug_args *args)  	params->op = args->op;  	if (args->input_ptr && args->input_size) { -		input = memdup_user((const void __user *) args->input_ptr, +		input = memdup_user(u64_to_user_ptr(args->input_ptr),  					args->input_size);  		if (IS_ERR(input)) {  			rc = PTR_ERR(input); diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 31336b0271b0..60293a00a14e 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -715,8 +715,8 @@ static int intel_create_dai(struct sdw_cdns *cdns,  				return -ENOMEM;  			} -			dais[i].playback.channels_min = 1; -			dais[i].playback.channels_max = max_ch; +			dais[i].capture.channels_min = 1; +			dais[i].capture.channels_max = max_ch;  			dais[i].capture.rates = SNDRV_PCM_RATE_48000;  			dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;  		} diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index d01060dbee96..1d5294b8783b 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -814,7 +814,8 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)  			goto error;  		} -		mutex_unlock(&bus->msg_lock); +		if (bus->multi_link) +			mutex_unlock(&bus->msg_lock);  	}  	return ret; @@ -1406,9 +1407,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,  	}  	for (i = 0; i < num_ports; i++) { -		dpn_prop = &dpn_prop[i]; - -		if (dpn_prop->num == port_num) +		if (dpn_prop[i].num == port_num)  			return &dpn_prop[i];  	} diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index f1c10378fa3e..fbdcef56a676 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -56,6 +56,7 @@   * @max_boot_acl: Maximum number of preboot ACL entries (%0 if not supported)   * @rpm: Does the controller support runtime PM (RTD3)   * @is_supported: Checks if we can support ICM on this controller + * @cio_reset: Trigger CIO reset   * @get_mode: Read and return the ICM firmware mode (optional)   * @get_route: Find a route string for given switch   * @save_devices: Ask ICM to save devices to ACL when suspending (optional) @@ -74,6 +75,7 @@ struct icm {  	bool safe_mode;  	bool rpm;  	bool (*is_supported)(struct tb *tb); +	int (*cio_reset)(struct tb *tb);  	int (*get_mode)(struct tb *tb);  	int (*get_route)(struct tb *tb, u8 link, u8 depth, u64 *route);  	void (*save_devices)(struct tb *tb); @@ -166,6 +168,65 @@ static inline u64 get_parent_route(u64 route)  	return depth ? route & ~(0xffULL << (depth - 1) * TB_ROUTE_SHIFT) : 0;  } +static int pci2cio_wait_completion(struct icm *icm, unsigned long timeout_msec) +{ +	unsigned long end = jiffies + msecs_to_jiffies(timeout_msec); +	u32 cmd; + +	do { +		pci_read_config_dword(icm->upstream_port, +				      icm->vnd_cap + PCIE2CIO_CMD, &cmd); +		if (!(cmd & PCIE2CIO_CMD_START)) { +			if (cmd & PCIE2CIO_CMD_TIMEOUT) +				break; +			return 0; +		} + +		msleep(50); +	} while (time_before(jiffies, end)); + +	return -ETIMEDOUT; +} + +static int pcie2cio_read(struct icm *icm, enum tb_cfg_space cs, +			 unsigned int port, unsigned int index, u32 *data) +{ +	struct pci_dev *pdev = icm->upstream_port; +	int ret, vnd_cap = icm->vnd_cap; +	u32 cmd; + +	cmd = index; +	cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK; +	cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK; +	cmd |= PCIE2CIO_CMD_START; +	pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd); + +	ret = pci2cio_wait_completion(icm, 5000); +	if (ret) +		return ret; + +	pci_read_config_dword(pdev, vnd_cap + PCIE2CIO_RDDATA, data); +	return 0; +} + +static int pcie2cio_write(struct icm *icm, enum tb_cfg_space cs, +			  unsigned int port, unsigned int index, u32 data) +{ +	struct pci_dev *pdev = icm->upstream_port; +	int vnd_cap = icm->vnd_cap; +	u32 cmd; + +	pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_WRDATA, data); + +	cmd = index; +	cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK; +	cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK; +	cmd |= PCIE2CIO_CMD_WRITE | PCIE2CIO_CMD_START; +	pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd); + +	return pci2cio_wait_completion(icm, 5000); +} +  static bool icm_match(const struct tb_cfg_request *req,  		      const struct ctl_pkg *pkg)  { @@ -484,6 +545,7 @@ static void add_switch(struct tb_switch *parent_sw, u64 route,  	sw->authorized = authorized;  	sw->security_level = security_level;  	sw->boot = boot; +	init_completion(&sw->rpm_complete);  	vss = parse_intel_vss(ep_name, ep_name_size);  	if (vss) @@ -523,6 +585,9 @@ static void update_switch(struct tb_switch *parent_sw, struct tb_switch *sw,  	/* This switch still exists */  	sw->is_unplugged = false; + +	/* Runtime resume is now complete */ +	complete(&sw->rpm_complete);  }  static void remove_switch(struct tb_switch *sw) @@ -834,6 +899,11 @@ icm_fr_xdomain_disconnected(struct tb *tb, const struct icm_pkg_header *hdr)  	}  } +static int icm_tr_cio_reset(struct tb *tb) +{ +	return pcie2cio_write(tb_priv(tb), TB_CFG_SWITCH, 0, 0x777, BIT(1)); +} +  static int  icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level,  		    size_t *nboot_acl, bool *rpm) @@ -1240,6 +1310,11 @@ static bool icm_ar_is_supported(struct tb *tb)  	return false;  } +static int icm_ar_cio_reset(struct tb *tb) +{ +	return pcie2cio_write(tb_priv(tb), TB_CFG_SWITCH, 0, 0x50, BIT(9)); +} +  static int icm_ar_get_mode(struct tb *tb)  {  	struct tb_nhi *nhi = tb->nhi; @@ -1477,65 +1552,6 @@ __icm_driver_ready(struct tb *tb, enum tb_security_level *security_level,  	return -ETIMEDOUT;  } -static int pci2cio_wait_completion(struct icm *icm, unsigned long timeout_msec) -{ -	unsigned long end = jiffies + msecs_to_jiffies(timeout_msec); -	u32 cmd; - -	do { -		pci_read_config_dword(icm->upstream_port, -				      icm->vnd_cap + PCIE2CIO_CMD, &cmd); -		if (!(cmd & PCIE2CIO_CMD_START)) { -			if (cmd & PCIE2CIO_CMD_TIMEOUT) -				break; -			return 0; -		} - -		msleep(50); -	} while (time_before(jiffies, end)); - -	return -ETIMEDOUT; -} - -static int pcie2cio_read(struct icm *icm, enum tb_cfg_space cs, -			 unsigned int port, unsigned int index, u32 *data) -{ -	struct pci_dev *pdev = icm->upstream_port; -	int ret, vnd_cap = icm->vnd_cap; -	u32 cmd; - -	cmd = index; -	cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK; -	cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK; -	cmd |= PCIE2CIO_CMD_START; -	pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd); - -	ret = pci2cio_wait_completion(icm, 5000); -	if (ret) -		return ret; - -	pci_read_config_dword(pdev, vnd_cap + PCIE2CIO_RDDATA, data); -	return 0; -} - -static int pcie2cio_write(struct icm *icm, enum tb_cfg_space cs, -			  unsigned int port, unsigned int index, u32 data) -{ -	struct pci_dev *pdev = icm->upstream_port; -	int vnd_cap = icm->vnd_cap; -	u32 cmd; - -	pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_WRDATA, data); - -	cmd = index; -	cmd |= (port << PCIE2CIO_CMD_PORT_SHIFT) & PCIE2CIO_CMD_PORT_MASK; -	cmd |= (cs << PCIE2CIO_CMD_CS_SHIFT) & PCIE2CIO_CMD_CS_MASK; -	cmd |= PCIE2CIO_CMD_WRITE | PCIE2CIO_CMD_START; -	pci_write_config_dword(pdev, vnd_cap + PCIE2CIO_CMD, cmd); - -	return pci2cio_wait_completion(icm, 5000); -} -  static int icm_firmware_reset(struct tb *tb, struct tb_nhi *nhi)  {  	struct icm *icm = tb_priv(tb); @@ -1556,7 +1572,7 @@ static int icm_firmware_reset(struct tb *tb, struct tb_nhi *nhi)  	iowrite32(val, nhi->iobase + REG_FW_STS);  	/* Trigger CIO reset now */ -	return pcie2cio_write(icm, TB_CFG_SWITCH, 0, 0x50, BIT(9)); +	return icm->cio_reset(tb);  }  static int icm_firmware_start(struct tb *tb, struct tb_nhi *nhi) @@ -1770,6 +1786,32 @@ static void icm_unplug_children(struct tb_switch *sw)  	}  } +static int complete_rpm(struct device *dev, void *data) +{ +	struct tb_switch *sw = tb_to_switch(dev); + +	if (sw) +		complete(&sw->rpm_complete); +	return 0; +} + +static void remove_unplugged_switch(struct tb_switch *sw) +{ +	pm_runtime_get_sync(sw->dev.parent); + +	/* +	 * Signal this and switches below for rpm_complete because +	 * tb_switch_remove() calls pm_runtime_get_sync() that then waits +	 * for it. +	 */ +	complete_rpm(&sw->dev, NULL); +	bus_for_each_dev(&tb_bus_type, &sw->dev, NULL, complete_rpm); +	tb_switch_remove(sw); + +	pm_runtime_mark_last_busy(sw->dev.parent); +	pm_runtime_put_autosuspend(sw->dev.parent); +} +  static void icm_free_unplugged_children(struct tb_switch *sw)  {  	unsigned int i; @@ -1782,7 +1824,7 @@ static void icm_free_unplugged_children(struct tb_switch *sw)  			port->xdomain = NULL;  		} else if (tb_port_has_remote(port)) {  			if (port->remote->sw->is_unplugged) { -				tb_switch_remove(port->remote->sw); +				remove_unplugged_switch(port->remote->sw);  				port->remote = NULL;  			} else {  				icm_free_unplugged_children(port->remote->sw); @@ -1831,6 +1873,24 @@ static int icm_runtime_suspend(struct tb *tb)  	return 0;  } +static int icm_runtime_suspend_switch(struct tb_switch *sw) +{ +	if (tb_route(sw)) +		reinit_completion(&sw->rpm_complete); +	return 0; +} + +static int icm_runtime_resume_switch(struct tb_switch *sw) +{ +	if (tb_route(sw)) { +		if (!wait_for_completion_timeout(&sw->rpm_complete, +						 msecs_to_jiffies(500))) { +			dev_dbg(&sw->dev, "runtime resuming timed out\n"); +		} +	} +	return 0; +} +  static int icm_runtime_resume(struct tb *tb)  {  	/* @@ -1910,6 +1970,8 @@ static const struct tb_cm_ops icm_ar_ops = {  	.complete = icm_complete,  	.runtime_suspend = icm_runtime_suspend,  	.runtime_resume = icm_runtime_resume, +	.runtime_suspend_switch = icm_runtime_suspend_switch, +	.runtime_resume_switch = icm_runtime_resume_switch,  	.handle_event = icm_handle_event,  	.get_boot_acl = icm_ar_get_boot_acl,  	.set_boot_acl = icm_ar_set_boot_acl, @@ -1930,6 +1992,8 @@ static const struct tb_cm_ops icm_tr_ops = {  	.complete = icm_complete,  	.runtime_suspend = icm_runtime_suspend,  	.runtime_resume = icm_runtime_resume, +	.runtime_suspend_switch = icm_runtime_suspend_switch, +	.runtime_resume_switch = icm_runtime_resume_switch,  	.handle_event = icm_handle_event,  	.get_boot_acl = icm_ar_get_boot_acl,  	.set_boot_acl = icm_ar_set_boot_acl, @@ -1975,6 +2039,7 @@ struct tb *icm_probe(struct tb_nhi *nhi)  	case PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_2C_NHI:  		icm->max_boot_acl = ICM_AR_PREBOOT_ACL_ENTRIES;  		icm->is_supported = icm_ar_is_supported; +		icm->cio_reset = icm_ar_cio_reset;  		icm->get_mode = icm_ar_get_mode;  		icm->get_route = icm_ar_get_route;  		icm->save_devices = icm_fr_save_devices; @@ -1990,6 +2055,7 @@ struct tb *icm_probe(struct tb_nhi *nhi)  	case PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_NHI:  		icm->max_boot_acl = ICM_AR_PREBOOT_ACL_ENTRIES;  		icm->is_supported = icm_ar_is_supported; +		icm->cio_reset = icm_tr_cio_reset;  		icm->get_mode = icm_ar_get_mode;  		icm->driver_ready = icm_tr_driver_ready;  		icm->device_connected = icm_tr_device_connected; diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index c1b016574fb4..10b56c66fec3 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -239,7 +239,16 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val,  	int ret;  	pm_runtime_get_sync(&sw->dev); + +	if (!mutex_trylock(&sw->tb->lock)) { +		ret = restart_syscall(); +		goto out; +	} +  	ret = dma_port_flash_read(sw->dma_port, offset, val, bytes); +	mutex_unlock(&sw->tb->lock); + +out:  	pm_runtime_mark_last_busy(&sw->dev);  	pm_runtime_put_autosuspend(&sw->dev); @@ -1019,7 +1028,6 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)  	 * the new tunnel too early.  	 */  	pci_lock_rescan_remove(); -	pm_runtime_get_sync(&sw->dev);  	switch (val) {  	/* Approve switch */ @@ -1040,8 +1048,6 @@ static int tb_switch_set_authorized(struct tb_switch *sw, unsigned int val)  		break;  	} -	pm_runtime_mark_last_busy(&sw->dev); -	pm_runtime_put_autosuspend(&sw->dev);  	pci_unlock_rescan_remove();  	if (!ret) { @@ -1069,7 +1075,10 @@ static ssize_t authorized_store(struct device *dev,  	if (val > 2)  		return -EINVAL; +	pm_runtime_get_sync(&sw->dev);  	ret = tb_switch_set_authorized(sw, val); +	pm_runtime_mark_last_busy(&sw->dev); +	pm_runtime_put_autosuspend(&sw->dev);  	return ret ? ret : count;  } @@ -1195,8 +1204,12 @@ static ssize_t nvm_authenticate_store(struct device *dev,  	bool val;  	int ret; -	if (!mutex_trylock(&sw->tb->lock)) -		return restart_syscall(); +	pm_runtime_get_sync(&sw->dev); + +	if (!mutex_trylock(&sw->tb->lock)) { +		ret = restart_syscall(); +		goto exit_rpm; +	}  	/* If NVMem devices are not yet added */  	if (!sw->nvm) { @@ -1217,13 +1230,9 @@ static ssize_t nvm_authenticate_store(struct device *dev,  			goto exit_unlock;  		} -		pm_runtime_get_sync(&sw->dev);  		ret = nvm_validate_and_write(sw); -		if (ret) { -			pm_runtime_mark_last_busy(&sw->dev); -			pm_runtime_put_autosuspend(&sw->dev); +		if (ret)  			goto exit_unlock; -		}  		sw->nvm->authenticating = true; @@ -1239,12 +1248,13 @@ static ssize_t nvm_authenticate_store(struct device *dev,  		} else {  			ret = nvm_authenticate_device(sw);  		} -		pm_runtime_mark_last_busy(&sw->dev); -		pm_runtime_put_autosuspend(&sw->dev);  	}  exit_unlock:  	mutex_unlock(&sw->tb->lock); +exit_rpm: +	pm_runtime_mark_last_busy(&sw->dev); +	pm_runtime_put_autosuspend(&sw->dev);  	if (ret)  		return ret; @@ -1380,11 +1390,22 @@ static void tb_switch_release(struct device *dev)   */  static int __maybe_unused tb_switch_runtime_suspend(struct device *dev)  { +	struct tb_switch *sw = tb_to_switch(dev); +	const struct tb_cm_ops *cm_ops = sw->tb->cm_ops; + +	if (cm_ops->runtime_suspend_switch) +		return cm_ops->runtime_suspend_switch(sw); +  	return 0;  }  static int __maybe_unused tb_switch_runtime_resume(struct device *dev)  { +	struct tb_switch *sw = tb_to_switch(dev); +	const struct tb_cm_ops *cm_ops = sw->tb->cm_ops; + +	if (cm_ops->runtime_resume_switch) +		return cm_ops->runtime_resume_switch(sw);  	return 0;  } diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index b12c8f33d89c..6407d529871d 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -79,6 +79,8 @@ struct tb_switch_nvm {   * @connection_key: Connection key used with ICM messaging   * @link: Root switch link this switch is connected (ICM only)   * @depth: Depth in the chain this switch is connected (ICM only) + * @rpm_complete: Completion used to wait for runtime resume to + *		  complete (ICM only)   *   * When the switch is being added or removed to the domain (other   * switches) you need to have domain lock held. @@ -112,6 +114,7 @@ struct tb_switch {  	u8 connection_key;  	u8 link;  	u8 depth; +	struct completion rpm_complete;  };  /** @@ -250,6 +253,8 @@ struct tb_path {   * @complete: Connection manager specific complete   * @runtime_suspend: Connection manager specific runtime_suspend   * @runtime_resume: Connection manager specific runtime_resume + * @runtime_suspend_switch: Runtime suspend a switch + * @runtime_resume_switch: Runtime resume a switch   * @handle_event: Handle thunderbolt event   * @get_boot_acl: Get boot ACL list   * @set_boot_acl: Set boot ACL list @@ -270,6 +275,8 @@ struct tb_cm_ops {  	void (*complete)(struct tb *tb);  	int (*runtime_suspend)(struct tb *tb);  	int (*runtime_resume)(struct tb *tb); +	int (*runtime_suspend_switch)(struct tb_switch *sw); +	int (*runtime_resume_switch)(struct tb_switch *sw);  	void (*handle_event)(struct tb *tb, enum tb_cfg_pkg_type,  			     const void *buf, size_t size);  	int (*get_boot_acl)(struct tb *tb, uuid_t *uuids, size_t nuuids); | 

