13703f53bSSrinivas Pandruvada /*
23703f53bSSrinivas Pandruvada  * ISHTP bus driver
33703f53bSSrinivas Pandruvada  *
43703f53bSSrinivas Pandruvada  * Copyright (c) 2012-2016, Intel Corporation.
53703f53bSSrinivas Pandruvada  *
63703f53bSSrinivas Pandruvada  * This program is free software; you can redistribute it and/or modify it
73703f53bSSrinivas Pandruvada  * under the terms and conditions of the GNU General Public License,
83703f53bSSrinivas Pandruvada  * version 2, as published by the Free Software Foundation.
93703f53bSSrinivas Pandruvada  *
103703f53bSSrinivas Pandruvada  * This program is distributed in the hope it will be useful, but WITHOUT
113703f53bSSrinivas Pandruvada  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
123703f53bSSrinivas Pandruvada  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
133703f53bSSrinivas Pandruvada  * more details.
143703f53bSSrinivas Pandruvada  */
153703f53bSSrinivas Pandruvada 
163703f53bSSrinivas Pandruvada #include <linux/module.h>
173703f53bSSrinivas Pandruvada #include <linux/init.h>
183703f53bSSrinivas Pandruvada #include <linux/kernel.h>
193703f53bSSrinivas Pandruvada #include <linux/device.h>
203703f53bSSrinivas Pandruvada #include <linux/sched.h>
213703f53bSSrinivas Pandruvada #include <linux/slab.h>
223703f53bSSrinivas Pandruvada #include "bus.h"
233703f53bSSrinivas Pandruvada #include "ishtp-dev.h"
243703f53bSSrinivas Pandruvada #include "client.h"
253703f53bSSrinivas Pandruvada #include "hbm.h"
263703f53bSSrinivas Pandruvada 
273703f53bSSrinivas Pandruvada static int ishtp_use_dma;
283703f53bSSrinivas Pandruvada module_param_named(ishtp_use_dma, ishtp_use_dma, int, 0600);
293703f53bSSrinivas Pandruvada MODULE_PARM_DESC(ishtp_use_dma, "Use DMA to send messages");
303703f53bSSrinivas Pandruvada 
313703f53bSSrinivas Pandruvada #define to_ishtp_cl_driver(d) container_of(d, struct ishtp_cl_driver, driver)
323703f53bSSrinivas Pandruvada #define to_ishtp_cl_device(d) container_of(d, struct ishtp_cl_device, dev)
333703f53bSSrinivas Pandruvada static bool ishtp_device_ready;
343703f53bSSrinivas Pandruvada 
353703f53bSSrinivas Pandruvada /**
363703f53bSSrinivas Pandruvada  * ishtp_recv() - process ishtp message
373703f53bSSrinivas Pandruvada  * @dev: ishtp device
383703f53bSSrinivas Pandruvada  *
393703f53bSSrinivas Pandruvada  * If a message with valid header and size is received, then
403703f53bSSrinivas Pandruvada  * this function calls appropriate handler. The host or firmware
413703f53bSSrinivas Pandruvada  * address is zero, then they are host bus management message,
423703f53bSSrinivas Pandruvada  * otherwise they are message fo clients.
433703f53bSSrinivas Pandruvada  */
443703f53bSSrinivas Pandruvada void ishtp_recv(struct ishtp_device *dev)
453703f53bSSrinivas Pandruvada {
463703f53bSSrinivas Pandruvada 	uint32_t	msg_hdr;
473703f53bSSrinivas Pandruvada 	struct ishtp_msg_hdr	*ishtp_hdr;
483703f53bSSrinivas Pandruvada 
493703f53bSSrinivas Pandruvada 	/* Read ISHTP header dword */
503703f53bSSrinivas Pandruvada 	msg_hdr = dev->ops->ishtp_read_hdr(dev);
513703f53bSSrinivas Pandruvada 	if (!msg_hdr)
523703f53bSSrinivas Pandruvada 		return;
533703f53bSSrinivas Pandruvada 
543703f53bSSrinivas Pandruvada 	dev->ops->sync_fw_clock(dev);
553703f53bSSrinivas Pandruvada 
563703f53bSSrinivas Pandruvada 	ishtp_hdr = (struct ishtp_msg_hdr *)&msg_hdr;
573703f53bSSrinivas Pandruvada 	dev->ishtp_msg_hdr = msg_hdr;
583703f53bSSrinivas Pandruvada 
593703f53bSSrinivas Pandruvada 	/* Sanity check: ISHTP frag. length in header */
603703f53bSSrinivas Pandruvada 	if (ishtp_hdr->length > dev->mtu) {
613703f53bSSrinivas Pandruvada 		dev_err(dev->devc,
623703f53bSSrinivas Pandruvada 			"ISHTP hdr - bad length: %u; dropped [%08X]\n",
633703f53bSSrinivas Pandruvada 			(unsigned int)ishtp_hdr->length, msg_hdr);
643703f53bSSrinivas Pandruvada 		return;
653703f53bSSrinivas Pandruvada 	}
663703f53bSSrinivas Pandruvada 
673703f53bSSrinivas Pandruvada 	/* ISHTP bus message */
683703f53bSSrinivas Pandruvada 	if (!ishtp_hdr->host_addr && !ishtp_hdr->fw_addr)
693703f53bSSrinivas Pandruvada 		recv_hbm(dev, ishtp_hdr);
703703f53bSSrinivas Pandruvada 	/* ISHTP fixed-client message */
713703f53bSSrinivas Pandruvada 	else if (!ishtp_hdr->host_addr)
723703f53bSSrinivas Pandruvada 		recv_fixed_cl_msg(dev, ishtp_hdr);
733703f53bSSrinivas Pandruvada 	else
743703f53bSSrinivas Pandruvada 		/* ISHTP client message */
753703f53bSSrinivas Pandruvada 		recv_ishtp_cl_msg(dev, ishtp_hdr);
763703f53bSSrinivas Pandruvada }
773703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_recv);
783703f53bSSrinivas Pandruvada 
793703f53bSSrinivas Pandruvada /**
803703f53bSSrinivas Pandruvada  * ishtp_send_msg() - Send ishtp message
813703f53bSSrinivas Pandruvada  * @dev: ishtp device
823703f53bSSrinivas Pandruvada  * @hdr: Message header
833703f53bSSrinivas Pandruvada  * @msg: Message contents
843703f53bSSrinivas Pandruvada  * @ipc_send_compl: completion callback
853703f53bSSrinivas Pandruvada  * @ipc_send_compl_prm: completion callback parameter
863703f53bSSrinivas Pandruvada  *
873703f53bSSrinivas Pandruvada  * Send a multi fragment message via IPC. After sending the first fragment
883703f53bSSrinivas Pandruvada  * the completion callback is called to schedule transmit of next fragment.
893703f53bSSrinivas Pandruvada  *
903703f53bSSrinivas Pandruvada  * Return: This returns IPC send message status.
913703f53bSSrinivas Pandruvada  */
923703f53bSSrinivas Pandruvada int ishtp_send_msg(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
933703f53bSSrinivas Pandruvada 		       void *msg, void(*ipc_send_compl)(void *),
943703f53bSSrinivas Pandruvada 		       void *ipc_send_compl_prm)
953703f53bSSrinivas Pandruvada {
963703f53bSSrinivas Pandruvada 	unsigned char	ipc_msg[IPC_FULL_MSG_SIZE];
973703f53bSSrinivas Pandruvada 	uint32_t	drbl_val;
983703f53bSSrinivas Pandruvada 
993703f53bSSrinivas Pandruvada 	drbl_val = dev->ops->ipc_get_header(dev, hdr->length +
1003703f53bSSrinivas Pandruvada 					    sizeof(struct ishtp_msg_hdr),
1013703f53bSSrinivas Pandruvada 					    1);
1023703f53bSSrinivas Pandruvada 
1033703f53bSSrinivas Pandruvada 	memcpy(ipc_msg, &drbl_val, sizeof(uint32_t));
1043703f53bSSrinivas Pandruvada 	memcpy(ipc_msg + sizeof(uint32_t), hdr, sizeof(uint32_t));
1053703f53bSSrinivas Pandruvada 	memcpy(ipc_msg + 2 * sizeof(uint32_t), msg, hdr->length);
1063703f53bSSrinivas Pandruvada 	return	dev->ops->write(dev, ipc_send_compl, ipc_send_compl_prm,
1073703f53bSSrinivas Pandruvada 				ipc_msg, 2 * sizeof(uint32_t) + hdr->length);
1083703f53bSSrinivas Pandruvada }
1093703f53bSSrinivas Pandruvada 
1103703f53bSSrinivas Pandruvada /**
1113703f53bSSrinivas Pandruvada  * ishtp_write_message() - Send ishtp single fragment message
1123703f53bSSrinivas Pandruvada  * @dev: ishtp device
1133703f53bSSrinivas Pandruvada  * @hdr: Message header
1143703f53bSSrinivas Pandruvada  * @buf: message data
1153703f53bSSrinivas Pandruvada  *
1163703f53bSSrinivas Pandruvada  * Send a single fragment message via IPC.  This returns IPC send message
1173703f53bSSrinivas Pandruvada  * status.
1183703f53bSSrinivas Pandruvada  *
1193703f53bSSrinivas Pandruvada  * Return: This returns IPC send message status.
1203703f53bSSrinivas Pandruvada  */
1213703f53bSSrinivas Pandruvada int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
12209cc8b36SHong Liu 			void *buf)
1233703f53bSSrinivas Pandruvada {
1243703f53bSSrinivas Pandruvada 	return ishtp_send_msg(dev, hdr, buf, NULL, NULL);
1253703f53bSSrinivas Pandruvada }
1263703f53bSSrinivas Pandruvada 
1273703f53bSSrinivas Pandruvada /**
1283703f53bSSrinivas Pandruvada  * ishtp_fw_cl_by_uuid() - locate index of fw client
1293703f53bSSrinivas Pandruvada  * @dev: ishtp device
1303703f53bSSrinivas Pandruvada  * @uuid: uuid of the client to search
1313703f53bSSrinivas Pandruvada  *
1323703f53bSSrinivas Pandruvada  * Search firmware client using UUID.
1333703f53bSSrinivas Pandruvada  *
1343703f53bSSrinivas Pandruvada  * Return: fw client index or -ENOENT if not found
1353703f53bSSrinivas Pandruvada  */
13614106501SAndy Shevchenko int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const guid_t *uuid)
1373703f53bSSrinivas Pandruvada {
13814106501SAndy Shevchenko 	unsigned int i;
1393703f53bSSrinivas Pandruvada 
1403703f53bSSrinivas Pandruvada 	for (i = 0; i < dev->fw_clients_num; ++i) {
14114106501SAndy Shevchenko 		if (guid_equal(uuid, &dev->fw_clients[i].props.protocol_name))
14214106501SAndy Shevchenko 			return i;
1433703f53bSSrinivas Pandruvada 	}
14414106501SAndy Shevchenko 	return -ENOENT;
1453703f53bSSrinivas Pandruvada }
1463703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
1473703f53bSSrinivas Pandruvada 
1483703f53bSSrinivas Pandruvada /**
149e625020bSEven Xu  * ishtp_fw_cl_get_client() - return client information to client
150e625020bSEven Xu  * @dev: the ishtp device structure
151e625020bSEven Xu  * @uuid: uuid of the client to search
152e625020bSEven Xu  *
153e625020bSEven Xu  * Search firmware client using UUID and reture related client information.
154e625020bSEven Xu  *
155e625020bSEven Xu  * Return: pointer of client information on success, NULL on failure.
156e625020bSEven Xu  */
157e625020bSEven Xu struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
15814106501SAndy Shevchenko 					       const guid_t *uuid)
159e625020bSEven Xu {
160e625020bSEven Xu 	int i;
161e625020bSEven Xu 	unsigned long flags;
162e625020bSEven Xu 
163e625020bSEven Xu 	spin_lock_irqsave(&dev->fw_clients_lock, flags);
164e625020bSEven Xu 	i = ishtp_fw_cl_by_uuid(dev, uuid);
165e625020bSEven Xu 	spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
166e625020bSEven Xu 	if (i < 0 || dev->fw_clients[i].props.fixed_address)
167e625020bSEven Xu 		return NULL;
168e625020bSEven Xu 
169e625020bSEven Xu 	return &dev->fw_clients[i];
170e625020bSEven Xu }
171e625020bSEven Xu EXPORT_SYMBOL(ishtp_fw_cl_get_client);
172e625020bSEven Xu 
173e625020bSEven Xu /**
1745f7224cfSSrinivas Pandruvada  * ishtp_get_fw_client_id() - Get fw client id
1755f7224cfSSrinivas Pandruvada  *
1765f7224cfSSrinivas Pandruvada  * This interface is used to reset HW get FW client id.
1775f7224cfSSrinivas Pandruvada  *
1785f7224cfSSrinivas Pandruvada  * Return: firmware client id.
1795f7224cfSSrinivas Pandruvada  */
1805f7224cfSSrinivas Pandruvada int ishtp_get_fw_client_id(struct ishtp_fw_client *fw_client)
1815f7224cfSSrinivas Pandruvada {
1825f7224cfSSrinivas Pandruvada 	return fw_client->client_id;
1835f7224cfSSrinivas Pandruvada }
1845f7224cfSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_get_fw_client_id);
1855f7224cfSSrinivas Pandruvada 
1865f7224cfSSrinivas Pandruvada /**
1873703f53bSSrinivas Pandruvada  * ishtp_fw_cl_by_id() - return index to fw_clients for client_id
1883703f53bSSrinivas Pandruvada  * @dev: the ishtp device structure
1893703f53bSSrinivas Pandruvada  * @client_id: fw client id to search
1903703f53bSSrinivas Pandruvada  *
1913703f53bSSrinivas Pandruvada  * Search firmware client using client id.
1923703f53bSSrinivas Pandruvada  *
1933703f53bSSrinivas Pandruvada  * Return: index on success, -ENOENT on failure.
1943703f53bSSrinivas Pandruvada  */
1953703f53bSSrinivas Pandruvada int ishtp_fw_cl_by_id(struct ishtp_device *dev, uint8_t client_id)
1963703f53bSSrinivas Pandruvada {
1973703f53bSSrinivas Pandruvada 	int i, res = -ENOENT;
1983703f53bSSrinivas Pandruvada 	unsigned long	flags;
1993703f53bSSrinivas Pandruvada 
2003703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&dev->fw_clients_lock, flags);
2013703f53bSSrinivas Pandruvada 	for (i = 0; i < dev->fw_clients_num; i++) {
2023703f53bSSrinivas Pandruvada 		if (dev->fw_clients[i].client_id == client_id) {
2033703f53bSSrinivas Pandruvada 			res = i;
2043703f53bSSrinivas Pandruvada 			break;
2053703f53bSSrinivas Pandruvada 		}
2063703f53bSSrinivas Pandruvada 	}
2073703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
2083703f53bSSrinivas Pandruvada 
2093703f53bSSrinivas Pandruvada 	return res;
2103703f53bSSrinivas Pandruvada }
2113703f53bSSrinivas Pandruvada 
2123703f53bSSrinivas Pandruvada /**
2133703f53bSSrinivas Pandruvada  * ishtp_cl_device_probe() - Bus probe() callback
2143703f53bSSrinivas Pandruvada  * @dev: the device structure
2153703f53bSSrinivas Pandruvada  *
2163703f53bSSrinivas Pandruvada  * This is a bus probe callback and calls the drive probe function.
2173703f53bSSrinivas Pandruvada  *
2183703f53bSSrinivas Pandruvada  * Return: Return value from driver probe() call.
2193703f53bSSrinivas Pandruvada  */
2203703f53bSSrinivas Pandruvada static int ishtp_cl_device_probe(struct device *dev)
2213703f53bSSrinivas Pandruvada {
2223703f53bSSrinivas Pandruvada 	struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
2233703f53bSSrinivas Pandruvada 	struct ishtp_cl_driver *driver;
2243703f53bSSrinivas Pandruvada 
2253703f53bSSrinivas Pandruvada 	if (!device)
2263703f53bSSrinivas Pandruvada 		return 0;
2273703f53bSSrinivas Pandruvada 
2283703f53bSSrinivas Pandruvada 	driver = to_ishtp_cl_driver(dev->driver);
2293703f53bSSrinivas Pandruvada 	if (!driver || !driver->probe)
2303703f53bSSrinivas Pandruvada 		return -ENODEV;
2313703f53bSSrinivas Pandruvada 
2323703f53bSSrinivas Pandruvada 	return driver->probe(device);
2333703f53bSSrinivas Pandruvada }
2343703f53bSSrinivas Pandruvada 
2353703f53bSSrinivas Pandruvada /**
2366b3f75f7SHong Liu  * ishtp_cl_bus_match() - Bus match() callback
2376b3f75f7SHong Liu  * @dev: the device structure
2386b3f75f7SHong Liu  * @drv: the driver structure
2396b3f75f7SHong Liu  *
2406b3f75f7SHong Liu  * This is a bus match callback, called when a new ishtp_cl_device is
2416b3f75f7SHong Liu  * registered during ishtp bus client enumeration. Use the guid_t in
2426b3f75f7SHong Liu  * drv and dev to decide whether they match or not.
2436b3f75f7SHong Liu  *
2446b3f75f7SHong Liu  * Return: 1 if dev & drv matches, 0 otherwise.
2456b3f75f7SHong Liu  */
2466b3f75f7SHong Liu static int ishtp_cl_bus_match(struct device *dev, struct device_driver *drv)
2476b3f75f7SHong Liu {
2486b3f75f7SHong Liu 	struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
2496b3f75f7SHong Liu 	struct ishtp_cl_driver *driver = to_ishtp_cl_driver(drv);
2506b3f75f7SHong Liu 
2516b3f75f7SHong Liu 	return guid_equal(driver->guid,
2526b3f75f7SHong Liu 			  &device->fw_client->props.protocol_name);
2536b3f75f7SHong Liu }
2546b3f75f7SHong Liu 
2556b3f75f7SHong Liu /**
2563703f53bSSrinivas Pandruvada  * ishtp_cl_device_remove() - Bus remove() callback
2573703f53bSSrinivas Pandruvada  * @dev: the device structure
2583703f53bSSrinivas Pandruvada  *
2593703f53bSSrinivas Pandruvada  * This is a bus remove callback and calls the drive remove function.
2603703f53bSSrinivas Pandruvada  * Since the ISH driver model supports only built in, this is
2613703f53bSSrinivas Pandruvada  * primarily can be called during pci driver init failure.
2623703f53bSSrinivas Pandruvada  *
2633703f53bSSrinivas Pandruvada  * Return: Return value from driver remove() call.
2643703f53bSSrinivas Pandruvada  */
2653703f53bSSrinivas Pandruvada static int ishtp_cl_device_remove(struct device *dev)
2663703f53bSSrinivas Pandruvada {
2673703f53bSSrinivas Pandruvada 	struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
2683703f53bSSrinivas Pandruvada 	struct ishtp_cl_driver *driver;
2693703f53bSSrinivas Pandruvada 
2703703f53bSSrinivas Pandruvada 	if (!device || !dev->driver)
2713703f53bSSrinivas Pandruvada 		return 0;
2723703f53bSSrinivas Pandruvada 
2733703f53bSSrinivas Pandruvada 	if (device->event_cb) {
2743703f53bSSrinivas Pandruvada 		device->event_cb = NULL;
2753703f53bSSrinivas Pandruvada 		cancel_work_sync(&device->event_work);
2763703f53bSSrinivas Pandruvada 	}
2773703f53bSSrinivas Pandruvada 
2783703f53bSSrinivas Pandruvada 	driver = to_ishtp_cl_driver(dev->driver);
2793703f53bSSrinivas Pandruvada 	if (!driver->remove) {
2803703f53bSSrinivas Pandruvada 		dev->driver = NULL;
2813703f53bSSrinivas Pandruvada 
2823703f53bSSrinivas Pandruvada 		return 0;
2833703f53bSSrinivas Pandruvada 	}
2843703f53bSSrinivas Pandruvada 
2853703f53bSSrinivas Pandruvada 	return driver->remove(device);
2863703f53bSSrinivas Pandruvada }
2873703f53bSSrinivas Pandruvada 
2883703f53bSSrinivas Pandruvada /**
2893703f53bSSrinivas Pandruvada  * ishtp_cl_device_suspend() - Bus suspend callback
2903703f53bSSrinivas Pandruvada  * @dev:	device
2913703f53bSSrinivas Pandruvada  *
2923703f53bSSrinivas Pandruvada  * Called during device suspend process.
2933703f53bSSrinivas Pandruvada  *
2943703f53bSSrinivas Pandruvada  * Return: Return value from driver suspend() call.
2953703f53bSSrinivas Pandruvada  */
2963703f53bSSrinivas Pandruvada static int ishtp_cl_device_suspend(struct device *dev)
2973703f53bSSrinivas Pandruvada {
2983703f53bSSrinivas Pandruvada 	struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
2993703f53bSSrinivas Pandruvada 	struct ishtp_cl_driver *driver;
3003703f53bSSrinivas Pandruvada 	int ret = 0;
3013703f53bSSrinivas Pandruvada 
3023703f53bSSrinivas Pandruvada 	if (!device)
3033703f53bSSrinivas Pandruvada 		return 0;
3043703f53bSSrinivas Pandruvada 
3053703f53bSSrinivas Pandruvada 	driver = to_ishtp_cl_driver(dev->driver);
3063703f53bSSrinivas Pandruvada 	if (driver && driver->driver.pm) {
3073703f53bSSrinivas Pandruvada 		if (driver->driver.pm->suspend)
3083703f53bSSrinivas Pandruvada 			ret = driver->driver.pm->suspend(dev);
3093703f53bSSrinivas Pandruvada 	}
3103703f53bSSrinivas Pandruvada 
3113703f53bSSrinivas Pandruvada 	return ret;
3123703f53bSSrinivas Pandruvada }
3133703f53bSSrinivas Pandruvada 
3143703f53bSSrinivas Pandruvada /**
3153703f53bSSrinivas Pandruvada  * ishtp_cl_device_resume() - Bus resume callback
3163703f53bSSrinivas Pandruvada  * @dev:	device
3173703f53bSSrinivas Pandruvada  *
3183703f53bSSrinivas Pandruvada  * Called during device resume process.
3193703f53bSSrinivas Pandruvada  *
3203703f53bSSrinivas Pandruvada  * Return: Return value from driver resume() call.
3213703f53bSSrinivas Pandruvada  */
3223703f53bSSrinivas Pandruvada static int ishtp_cl_device_resume(struct device *dev)
3233703f53bSSrinivas Pandruvada {
3243703f53bSSrinivas Pandruvada 	struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
3253703f53bSSrinivas Pandruvada 	struct ishtp_cl_driver *driver;
3263703f53bSSrinivas Pandruvada 	int ret = 0;
3273703f53bSSrinivas Pandruvada 
3283703f53bSSrinivas Pandruvada 	if (!device)
3293703f53bSSrinivas Pandruvada 		return 0;
3303703f53bSSrinivas Pandruvada 
3313703f53bSSrinivas Pandruvada 	/*
3323703f53bSSrinivas Pandruvada 	 * When ISH needs hard reset, it is done asynchrnously, hence bus
3333703f53bSSrinivas Pandruvada 	 * resume will  be called before full ISH resume
3343703f53bSSrinivas Pandruvada 	 */
3353703f53bSSrinivas Pandruvada 	if (device->ishtp_dev->resume_flag)
3363703f53bSSrinivas Pandruvada 		return 0;
3373703f53bSSrinivas Pandruvada 
3383703f53bSSrinivas Pandruvada 	driver = to_ishtp_cl_driver(dev->driver);
3393703f53bSSrinivas Pandruvada 	if (driver && driver->driver.pm) {
3403703f53bSSrinivas Pandruvada 		if (driver->driver.pm->resume)
3413703f53bSSrinivas Pandruvada 			ret = driver->driver.pm->resume(dev);
3423703f53bSSrinivas Pandruvada 	}
3433703f53bSSrinivas Pandruvada 
3443703f53bSSrinivas Pandruvada 	return ret;
3453703f53bSSrinivas Pandruvada }
3463703f53bSSrinivas Pandruvada 
3473703f53bSSrinivas Pandruvada /**
3483703f53bSSrinivas Pandruvada  * ishtp_cl_device_reset() - Reset callback
3493703f53bSSrinivas Pandruvada  * @device:	ishtp client device instance
3503703f53bSSrinivas Pandruvada  *
3513703f53bSSrinivas Pandruvada  * This is a callback when HW reset is done and the device need
3523703f53bSSrinivas Pandruvada  * reinit.
3533703f53bSSrinivas Pandruvada  *
3543703f53bSSrinivas Pandruvada  * Return: Return value from driver reset() call.
3553703f53bSSrinivas Pandruvada  */
3563703f53bSSrinivas Pandruvada static int ishtp_cl_device_reset(struct ishtp_cl_device *device)
3573703f53bSSrinivas Pandruvada {
3583703f53bSSrinivas Pandruvada 	struct ishtp_cl_driver *driver;
3593703f53bSSrinivas Pandruvada 	int ret = 0;
3603703f53bSSrinivas Pandruvada 
3613703f53bSSrinivas Pandruvada 	device->event_cb = NULL;
3623703f53bSSrinivas Pandruvada 	cancel_work_sync(&device->event_work);
3633703f53bSSrinivas Pandruvada 
3643703f53bSSrinivas Pandruvada 	driver = to_ishtp_cl_driver(device->dev.driver);
3653703f53bSSrinivas Pandruvada 	if (driver && driver->reset)
3663703f53bSSrinivas Pandruvada 		ret = driver->reset(device);
3673703f53bSSrinivas Pandruvada 
3683703f53bSSrinivas Pandruvada 	return ret;
3693703f53bSSrinivas Pandruvada }
3703703f53bSSrinivas Pandruvada 
3713703f53bSSrinivas Pandruvada static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
3723703f53bSSrinivas Pandruvada 	char *buf)
3733703f53bSSrinivas Pandruvada {
3743703f53bSSrinivas Pandruvada 	int len;
3753703f53bSSrinivas Pandruvada 
3763703f53bSSrinivas Pandruvada 	len = snprintf(buf, PAGE_SIZE, "ishtp:%s\n", dev_name(dev));
3773703f53bSSrinivas Pandruvada 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
3783703f53bSSrinivas Pandruvada }
379480104b7SGreg Kroah-Hartman static DEVICE_ATTR_RO(modalias);
3803703f53bSSrinivas Pandruvada 
381480104b7SGreg Kroah-Hartman static struct attribute *ishtp_cl_dev_attrs[] = {
382480104b7SGreg Kroah-Hartman 	&dev_attr_modalias.attr,
383480104b7SGreg Kroah-Hartman 	NULL,
3843703f53bSSrinivas Pandruvada };
385480104b7SGreg Kroah-Hartman ATTRIBUTE_GROUPS(ishtp_cl_dev);
3863703f53bSSrinivas Pandruvada 
3873703f53bSSrinivas Pandruvada static int ishtp_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
3883703f53bSSrinivas Pandruvada {
3893703f53bSSrinivas Pandruvada 	if (add_uevent_var(env, "MODALIAS=ishtp:%s", dev_name(dev)))
3903703f53bSSrinivas Pandruvada 		return -ENOMEM;
3913703f53bSSrinivas Pandruvada 	return 0;
3923703f53bSSrinivas Pandruvada }
3933703f53bSSrinivas Pandruvada 
3943703f53bSSrinivas Pandruvada static const struct dev_pm_ops ishtp_cl_bus_dev_pm_ops = {
3953703f53bSSrinivas Pandruvada 	/* Suspend callbacks */
3963703f53bSSrinivas Pandruvada 	.suspend = ishtp_cl_device_suspend,
3973703f53bSSrinivas Pandruvada 	.resume = ishtp_cl_device_resume,
3983703f53bSSrinivas Pandruvada 	/* Hibernate callbacks */
3993703f53bSSrinivas Pandruvada 	.freeze = ishtp_cl_device_suspend,
4003703f53bSSrinivas Pandruvada 	.thaw = ishtp_cl_device_resume,
4013703f53bSSrinivas Pandruvada 	.restore = ishtp_cl_device_resume,
4023703f53bSSrinivas Pandruvada };
4033703f53bSSrinivas Pandruvada 
4043703f53bSSrinivas Pandruvada static struct bus_type ishtp_cl_bus_type = {
4053703f53bSSrinivas Pandruvada 	.name		= "ishtp",
406480104b7SGreg Kroah-Hartman 	.dev_groups	= ishtp_cl_dev_groups,
4073703f53bSSrinivas Pandruvada 	.probe		= ishtp_cl_device_probe,
4086b3f75f7SHong Liu 	.match		= ishtp_cl_bus_match,
4093703f53bSSrinivas Pandruvada 	.remove		= ishtp_cl_device_remove,
4103703f53bSSrinivas Pandruvada 	.pm		= &ishtp_cl_bus_dev_pm_ops,
4113703f53bSSrinivas Pandruvada 	.uevent		= ishtp_cl_uevent,
4123703f53bSSrinivas Pandruvada };
4133703f53bSSrinivas Pandruvada 
4143703f53bSSrinivas Pandruvada static void ishtp_cl_dev_release(struct device *dev)
4153703f53bSSrinivas Pandruvada {
4163703f53bSSrinivas Pandruvada 	kfree(to_ishtp_cl_device(dev));
4173703f53bSSrinivas Pandruvada }
4183703f53bSSrinivas Pandruvada 
41912be9f7bSBhumika Goyal static const struct device_type ishtp_cl_device_type = {
4203703f53bSSrinivas Pandruvada 	.release	= ishtp_cl_dev_release,
4213703f53bSSrinivas Pandruvada };
4223703f53bSSrinivas Pandruvada 
4233703f53bSSrinivas Pandruvada /**
4243703f53bSSrinivas Pandruvada  * ishtp_bus_add_device() - Function to create device on bus
4253703f53bSSrinivas Pandruvada  * @dev:	ishtp device
4263703f53bSSrinivas Pandruvada  * @uuid:	uuid of the client
4273703f53bSSrinivas Pandruvada  * @name:	Name of the client
4283703f53bSSrinivas Pandruvada  *
4293703f53bSSrinivas Pandruvada  * Allocate ISHTP bus client device, attach it to uuid
4303703f53bSSrinivas Pandruvada  * and register with ISHTP bus.
4313703f53bSSrinivas Pandruvada  *
4323703f53bSSrinivas Pandruvada  * Return: ishtp_cl_device pointer or NULL on failure
4333703f53bSSrinivas Pandruvada  */
4343703f53bSSrinivas Pandruvada static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
43514106501SAndy Shevchenko 						    guid_t uuid, char *name)
4363703f53bSSrinivas Pandruvada {
4373703f53bSSrinivas Pandruvada 	struct ishtp_cl_device *device;
4383703f53bSSrinivas Pandruvada 	int status;
4393703f53bSSrinivas Pandruvada 	unsigned long flags;
4403703f53bSSrinivas Pandruvada 
4413703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&dev->device_list_lock, flags);
442e8c61135SWei Yongjun 	list_for_each_entry(device, &dev->device_list, device_link) {
4433703f53bSSrinivas Pandruvada 		if (!strcmp(name, dev_name(&device->dev))) {
4443703f53bSSrinivas Pandruvada 			device->fw_client = &dev->fw_clients[
4453703f53bSSrinivas Pandruvada 				dev->fw_client_presentation_num - 1];
4463703f53bSSrinivas Pandruvada 			spin_unlock_irqrestore(&dev->device_list_lock, flags);
4473703f53bSSrinivas Pandruvada 			ishtp_cl_device_reset(device);
4483703f53bSSrinivas Pandruvada 			return device;
4493703f53bSSrinivas Pandruvada 		}
4503703f53bSSrinivas Pandruvada 	}
4513703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&dev->device_list_lock, flags);
4523703f53bSSrinivas Pandruvada 
4533703f53bSSrinivas Pandruvada 	device = kzalloc(sizeof(struct ishtp_cl_device), GFP_KERNEL);
4543703f53bSSrinivas Pandruvada 	if (!device)
4553703f53bSSrinivas Pandruvada 		return NULL;
4563703f53bSSrinivas Pandruvada 
4573703f53bSSrinivas Pandruvada 	device->dev.parent = dev->devc;
4583703f53bSSrinivas Pandruvada 	device->dev.bus = &ishtp_cl_bus_type;
4593703f53bSSrinivas Pandruvada 	device->dev.type = &ishtp_cl_device_type;
4603703f53bSSrinivas Pandruvada 	device->ishtp_dev = dev;
4613703f53bSSrinivas Pandruvada 
4623703f53bSSrinivas Pandruvada 	device->fw_client =
4633703f53bSSrinivas Pandruvada 		&dev->fw_clients[dev->fw_client_presentation_num - 1];
4643703f53bSSrinivas Pandruvada 
4653703f53bSSrinivas Pandruvada 	dev_set_name(&device->dev, "%s", name);
4663703f53bSSrinivas Pandruvada 
4673703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&dev->device_list_lock, flags);
4683703f53bSSrinivas Pandruvada 	list_add_tail(&device->device_link, &dev->device_list);
4693703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&dev->device_list_lock, flags);
4703703f53bSSrinivas Pandruvada 
4713703f53bSSrinivas Pandruvada 	status = device_register(&device->dev);
4723703f53bSSrinivas Pandruvada 	if (status) {
4733703f53bSSrinivas Pandruvada 		spin_lock_irqsave(&dev->device_list_lock, flags);
4743703f53bSSrinivas Pandruvada 		list_del(&device->device_link);
4753703f53bSSrinivas Pandruvada 		spin_unlock_irqrestore(&dev->device_list_lock, flags);
4763703f53bSSrinivas Pandruvada 		dev_err(dev->devc, "Failed to register ISHTP client device\n");
477a4eb490aSArvind Yadav 		put_device(&device->dev);
4783703f53bSSrinivas Pandruvada 		return NULL;
4793703f53bSSrinivas Pandruvada 	}
4803703f53bSSrinivas Pandruvada 
4813703f53bSSrinivas Pandruvada 	ishtp_device_ready = true;
4829a0bc1a6SSrinivas Pandruvada 	dev_set_drvdata(&device->dev, device);
4833703f53bSSrinivas Pandruvada 
4843703f53bSSrinivas Pandruvada 	return device;
4853703f53bSSrinivas Pandruvada }
4863703f53bSSrinivas Pandruvada 
4873703f53bSSrinivas Pandruvada /**
4883703f53bSSrinivas Pandruvada  * ishtp_bus_remove_device() - Function to relase device on bus
4893703f53bSSrinivas Pandruvada  * @device:	client device instance
4903703f53bSSrinivas Pandruvada  *
4913703f53bSSrinivas Pandruvada  * This is a counterpart of ishtp_bus_add_device.
4923703f53bSSrinivas Pandruvada  * Device is unregistered.
4933703f53bSSrinivas Pandruvada  * the device structure is freed in 'ishtp_cl_dev_release' function
4943703f53bSSrinivas Pandruvada  * Called only during error in pci driver init path.
4953703f53bSSrinivas Pandruvada  */
4963703f53bSSrinivas Pandruvada static void ishtp_bus_remove_device(struct ishtp_cl_device *device)
4973703f53bSSrinivas Pandruvada {
4983703f53bSSrinivas Pandruvada 	device_unregister(&device->dev);
4993703f53bSSrinivas Pandruvada }
5003703f53bSSrinivas Pandruvada 
5013703f53bSSrinivas Pandruvada /**
502e00a864fSSrinivas Pandruvada  * ishtp_cl_driver_register() - Client driver register
5033703f53bSSrinivas Pandruvada  * @driver:	the client driver instance
5043703f53bSSrinivas Pandruvada  * @owner:	Owner of this driver module
5053703f53bSSrinivas Pandruvada  *
5063703f53bSSrinivas Pandruvada  * Once a client driver is probed, it created a client
5073703f53bSSrinivas Pandruvada  * instance and registers with the bus.
5083703f53bSSrinivas Pandruvada  *
5093703f53bSSrinivas Pandruvada  * Return: Return value of driver_register or -ENODEV if not ready
5103703f53bSSrinivas Pandruvada  */
511e00a864fSSrinivas Pandruvada int ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
5123703f53bSSrinivas Pandruvada 			     struct module *owner)
5133703f53bSSrinivas Pandruvada {
5143703f53bSSrinivas Pandruvada 	int err;
5153703f53bSSrinivas Pandruvada 
5163703f53bSSrinivas Pandruvada 	if (!ishtp_device_ready)
5173703f53bSSrinivas Pandruvada 		return -ENODEV;
5183703f53bSSrinivas Pandruvada 
5193703f53bSSrinivas Pandruvada 	driver->driver.name = driver->name;
5203703f53bSSrinivas Pandruvada 	driver->driver.owner = owner;
5213703f53bSSrinivas Pandruvada 	driver->driver.bus = &ishtp_cl_bus_type;
5223703f53bSSrinivas Pandruvada 
5233703f53bSSrinivas Pandruvada 	err = driver_register(&driver->driver);
5243703f53bSSrinivas Pandruvada 	if (err)
5253703f53bSSrinivas Pandruvada 		return err;
5263703f53bSSrinivas Pandruvada 
5273703f53bSSrinivas Pandruvada 	return 0;
5283703f53bSSrinivas Pandruvada }
529e00a864fSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_driver_register);
5303703f53bSSrinivas Pandruvada 
5313703f53bSSrinivas Pandruvada /**
5323703f53bSSrinivas Pandruvada  * ishtp_cl_driver_unregister() - Client driver unregister
5333703f53bSSrinivas Pandruvada  * @driver:	the client driver instance
5343703f53bSSrinivas Pandruvada  *
5353703f53bSSrinivas Pandruvada  * Unregister client during device removal process.
5363703f53bSSrinivas Pandruvada  */
5373703f53bSSrinivas Pandruvada void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver)
5383703f53bSSrinivas Pandruvada {
5393703f53bSSrinivas Pandruvada 	driver_unregister(&driver->driver);
5403703f53bSSrinivas Pandruvada }
5413703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_driver_unregister);
5423703f53bSSrinivas Pandruvada 
5433703f53bSSrinivas Pandruvada /**
5443703f53bSSrinivas Pandruvada  * ishtp_bus_event_work() - event work function
5453703f53bSSrinivas Pandruvada  * @work:	work struct pointer
5463703f53bSSrinivas Pandruvada  *
5473703f53bSSrinivas Pandruvada  * Once an event is received for a client this work
5483703f53bSSrinivas Pandruvada  * function is called. If the device has registered a
5493703f53bSSrinivas Pandruvada  * callback then the callback is called.
5503703f53bSSrinivas Pandruvada  */
5513703f53bSSrinivas Pandruvada static void ishtp_bus_event_work(struct work_struct *work)
5523703f53bSSrinivas Pandruvada {
5533703f53bSSrinivas Pandruvada 	struct ishtp_cl_device *device;
5543703f53bSSrinivas Pandruvada 
5553703f53bSSrinivas Pandruvada 	device = container_of(work, struct ishtp_cl_device, event_work);
5563703f53bSSrinivas Pandruvada 
5573703f53bSSrinivas Pandruvada 	if (device->event_cb)
5583703f53bSSrinivas Pandruvada 		device->event_cb(device);
5593703f53bSSrinivas Pandruvada }
5603703f53bSSrinivas Pandruvada 
5613703f53bSSrinivas Pandruvada /**
5623703f53bSSrinivas Pandruvada  * ishtp_cl_bus_rx_event() - schedule event work
5633703f53bSSrinivas Pandruvada  * @device:	client device instance
5643703f53bSSrinivas Pandruvada  *
5653703f53bSSrinivas Pandruvada  * Once an event is received for a client this schedules
5663703f53bSSrinivas Pandruvada  * a work function to process.
5673703f53bSSrinivas Pandruvada  */
5683703f53bSSrinivas Pandruvada void ishtp_cl_bus_rx_event(struct ishtp_cl_device *device)
5693703f53bSSrinivas Pandruvada {
5703703f53bSSrinivas Pandruvada 	if (!device || !device->event_cb)
5713703f53bSSrinivas Pandruvada 		return;
5723703f53bSSrinivas Pandruvada 
5733703f53bSSrinivas Pandruvada 	if (device->event_cb)
5743703f53bSSrinivas Pandruvada 		schedule_work(&device->event_work);
5753703f53bSSrinivas Pandruvada }
5763703f53bSSrinivas Pandruvada 
5773703f53bSSrinivas Pandruvada /**
5783703f53bSSrinivas Pandruvada  * ishtp_register_event_cb() - Register callback
5793703f53bSSrinivas Pandruvada  * @device:	client device instance
5803703f53bSSrinivas Pandruvada  * @event_cb:	Event processor for an client
5813703f53bSSrinivas Pandruvada  *
5823703f53bSSrinivas Pandruvada  * Register a callback for events, called from client driver
5833703f53bSSrinivas Pandruvada  *
5843703f53bSSrinivas Pandruvada  * Return: Return 0 or -EALREADY if already registered
5853703f53bSSrinivas Pandruvada  */
5863703f53bSSrinivas Pandruvada int ishtp_register_event_cb(struct ishtp_cl_device *device,
5873703f53bSSrinivas Pandruvada 	void (*event_cb)(struct ishtp_cl_device *))
5883703f53bSSrinivas Pandruvada {
5893703f53bSSrinivas Pandruvada 	if (device->event_cb)
5903703f53bSSrinivas Pandruvada 		return -EALREADY;
5913703f53bSSrinivas Pandruvada 
5923703f53bSSrinivas Pandruvada 	device->event_cb = event_cb;
5933703f53bSSrinivas Pandruvada 	INIT_WORK(&device->event_work, ishtp_bus_event_work);
5943703f53bSSrinivas Pandruvada 
5953703f53bSSrinivas Pandruvada 	return 0;
5963703f53bSSrinivas Pandruvada }
5973703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_register_event_cb);
5983703f53bSSrinivas Pandruvada 
5993703f53bSSrinivas Pandruvada /**
6003703f53bSSrinivas Pandruvada  * ishtp_get_device() - update usage count for the device
6013703f53bSSrinivas Pandruvada  * @cl_device:	client device instance
6023703f53bSSrinivas Pandruvada  *
6033703f53bSSrinivas Pandruvada  * Increment the usage count. The device can't be deleted
6043703f53bSSrinivas Pandruvada  */
6053703f53bSSrinivas Pandruvada void ishtp_get_device(struct ishtp_cl_device *cl_device)
6063703f53bSSrinivas Pandruvada {
6073703f53bSSrinivas Pandruvada 	cl_device->reference_count++;
6083703f53bSSrinivas Pandruvada }
6093703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_get_device);
6103703f53bSSrinivas Pandruvada 
6113703f53bSSrinivas Pandruvada /**
6123703f53bSSrinivas Pandruvada  * ishtp_put_device() - decrement usage count for the device
6133703f53bSSrinivas Pandruvada  * @cl_device:	client device instance
6143703f53bSSrinivas Pandruvada  *
6153703f53bSSrinivas Pandruvada  * Decrement the usage count. The device can be deleted is count = 0
6163703f53bSSrinivas Pandruvada  */
6173703f53bSSrinivas Pandruvada void ishtp_put_device(struct ishtp_cl_device *cl_device)
6183703f53bSSrinivas Pandruvada {
6193703f53bSSrinivas Pandruvada 	cl_device->reference_count--;
6203703f53bSSrinivas Pandruvada }
6213703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_put_device);
6223703f53bSSrinivas Pandruvada 
6233703f53bSSrinivas Pandruvada /**
624d0b41230SEven Xu  * ishtp_set_drvdata() - set client driver data
625d0b41230SEven Xu  * @cl_device:	client device instance
626d0b41230SEven Xu  * @data:	driver data need to be set
627d0b41230SEven Xu  *
628d0b41230SEven Xu  * Set client driver data to cl_device->driver_data.
629d0b41230SEven Xu  */
630d0b41230SEven Xu void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data)
631d0b41230SEven Xu {
632d0b41230SEven Xu 	cl_device->driver_data = data;
633d0b41230SEven Xu }
634d0b41230SEven Xu EXPORT_SYMBOL(ishtp_set_drvdata);
635d0b41230SEven Xu 
636d0b41230SEven Xu /**
637d0b41230SEven Xu  * ishtp_get_drvdata() - get client driver data
638d0b41230SEven Xu  * @cl_device:	client device instance
639d0b41230SEven Xu  *
640d0b41230SEven Xu  * Get client driver data from cl_device->driver_data.
641d0b41230SEven Xu  *
642d0b41230SEven Xu  * Return: pointer of driver data
643d0b41230SEven Xu  */
644d0b41230SEven Xu void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device)
645d0b41230SEven Xu {
646d0b41230SEven Xu 	return cl_device->driver_data;
647d0b41230SEven Xu }
648d0b41230SEven Xu EXPORT_SYMBOL(ishtp_get_drvdata);
649d0b41230SEven Xu 
650d0b41230SEven Xu /**
6513703f53bSSrinivas Pandruvada  * ishtp_bus_new_client() - Create a new client
6523703f53bSSrinivas Pandruvada  * @dev:	ISHTP device instance
6533703f53bSSrinivas Pandruvada  *
6543703f53bSSrinivas Pandruvada  * Once bus protocol enumerates a client, this is called
6553703f53bSSrinivas Pandruvada  * to add a device for the client.
6563703f53bSSrinivas Pandruvada  *
6573703f53bSSrinivas Pandruvada  * Return: 0 on success or error code on failure
6583703f53bSSrinivas Pandruvada  */
6593703f53bSSrinivas Pandruvada int ishtp_bus_new_client(struct ishtp_device *dev)
6603703f53bSSrinivas Pandruvada {
6613703f53bSSrinivas Pandruvada 	int	i;
6623703f53bSSrinivas Pandruvada 	char	*dev_name;
6633703f53bSSrinivas Pandruvada 	struct ishtp_cl_device	*cl_device;
66414106501SAndy Shevchenko 	guid_t	device_uuid;
6653703f53bSSrinivas Pandruvada 
6663703f53bSSrinivas Pandruvada 	/*
6673703f53bSSrinivas Pandruvada 	 * For all reported clients, create an unconnected client and add its
6683703f53bSSrinivas Pandruvada 	 * device to ISHTP bus.
6693703f53bSSrinivas Pandruvada 	 * If appropriate driver has loaded, this will trigger its probe().
6703703f53bSSrinivas Pandruvada 	 * Otherwise, probe() will be called when driver is loaded
6713703f53bSSrinivas Pandruvada 	 */
6723703f53bSSrinivas Pandruvada 	i = dev->fw_client_presentation_num - 1;
6733703f53bSSrinivas Pandruvada 	device_uuid = dev->fw_clients[i].props.protocol_name;
67414106501SAndy Shevchenko 	dev_name = kasprintf(GFP_KERNEL, "{%pUL}", &device_uuid);
6753703f53bSSrinivas Pandruvada 	if (!dev_name)
6763703f53bSSrinivas Pandruvada 		return	-ENOMEM;
6773703f53bSSrinivas Pandruvada 
6783703f53bSSrinivas Pandruvada 	cl_device = ishtp_bus_add_device(dev, device_uuid, dev_name);
6793703f53bSSrinivas Pandruvada 	if (!cl_device) {
6803703f53bSSrinivas Pandruvada 		kfree(dev_name);
6813703f53bSSrinivas Pandruvada 		return	-ENOENT;
6823703f53bSSrinivas Pandruvada 	}
6833703f53bSSrinivas Pandruvada 
6843703f53bSSrinivas Pandruvada 	kfree(dev_name);
6853703f53bSSrinivas Pandruvada 
6863703f53bSSrinivas Pandruvada 	return	0;
6873703f53bSSrinivas Pandruvada }
6883703f53bSSrinivas Pandruvada 
6893703f53bSSrinivas Pandruvada /**
6903703f53bSSrinivas Pandruvada  * ishtp_cl_device_bind() - bind a device
6913703f53bSSrinivas Pandruvada  * @cl:		ishtp client device
6923703f53bSSrinivas Pandruvada  *
6933703f53bSSrinivas Pandruvada  * Binds connected ishtp_cl to ISHTP bus device
6943703f53bSSrinivas Pandruvada  *
6953703f53bSSrinivas Pandruvada  * Return: 0 on success or fault code
6963703f53bSSrinivas Pandruvada  */
6973703f53bSSrinivas Pandruvada int ishtp_cl_device_bind(struct ishtp_cl *cl)
6983703f53bSSrinivas Pandruvada {
6993703f53bSSrinivas Pandruvada 	struct ishtp_cl_device	*cl_device;
7003703f53bSSrinivas Pandruvada 	unsigned long flags;
7013703f53bSSrinivas Pandruvada 	int	rv;
7023703f53bSSrinivas Pandruvada 
7033703f53bSSrinivas Pandruvada 	if (!cl->fw_client_id || cl->state != ISHTP_CL_CONNECTED)
7043703f53bSSrinivas Pandruvada 		return	-EFAULT;
7053703f53bSSrinivas Pandruvada 
7063703f53bSSrinivas Pandruvada 	rv = -ENOENT;
7073703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&cl->dev->device_list_lock, flags);
7083703f53bSSrinivas Pandruvada 	list_for_each_entry(cl_device, &cl->dev->device_list,
7093703f53bSSrinivas Pandruvada 			device_link) {
7100d28f494SHong Liu 		if (cl_device->fw_client &&
7110d28f494SHong Liu 		    cl_device->fw_client->client_id == cl->fw_client_id) {
7123703f53bSSrinivas Pandruvada 			cl->device = cl_device;
7133703f53bSSrinivas Pandruvada 			rv = 0;
7143703f53bSSrinivas Pandruvada 			break;
7153703f53bSSrinivas Pandruvada 		}
7163703f53bSSrinivas Pandruvada 	}
7173703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&cl->dev->device_list_lock, flags);
7183703f53bSSrinivas Pandruvada 	return	rv;
7193703f53bSSrinivas Pandruvada }
7203703f53bSSrinivas Pandruvada 
7213703f53bSSrinivas Pandruvada /**
7223703f53bSSrinivas Pandruvada  * ishtp_bus_remove_all_clients() - Remove all clients
7233703f53bSSrinivas Pandruvada  * @ishtp_dev:		ishtp device
7243703f53bSSrinivas Pandruvada  * @warm_reset:		Reset due to FW reset dure to errors or S3 suspend
7253703f53bSSrinivas Pandruvada  *
7263703f53bSSrinivas Pandruvada  * This is part of reset/remove flow. This function the main processing
7273703f53bSSrinivas Pandruvada  * only targets error processing, if the FW has forced reset or
7283703f53bSSrinivas Pandruvada  * error to remove connected clients. When warm reset the client devices are
7293703f53bSSrinivas Pandruvada  * not removed.
7303703f53bSSrinivas Pandruvada  */
7313703f53bSSrinivas Pandruvada void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,
7323703f53bSSrinivas Pandruvada 				  bool warm_reset)
7333703f53bSSrinivas Pandruvada {
7343703f53bSSrinivas Pandruvada 	struct ishtp_cl_device	*cl_device, *n;
7353703f53bSSrinivas Pandruvada 	struct ishtp_cl	*cl;
7363703f53bSSrinivas Pandruvada 	unsigned long	flags;
7373703f53bSSrinivas Pandruvada 
7383703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags);
7393703f53bSSrinivas Pandruvada 	list_for_each_entry(cl, &ishtp_dev->cl_list, link) {
7403703f53bSSrinivas Pandruvada 		cl->state = ISHTP_CL_DISCONNECTED;
7413703f53bSSrinivas Pandruvada 
7423703f53bSSrinivas Pandruvada 		/*
7433703f53bSSrinivas Pandruvada 		 * Wake any pending process. The waiter would check dev->state
7443703f53bSSrinivas Pandruvada 		 * and determine that it's not enabled already,
7453703f53bSSrinivas Pandruvada 		 * and will return error to its caller
7463703f53bSSrinivas Pandruvada 		 */
7473703f53bSSrinivas Pandruvada 		wake_up_interruptible(&cl->wait_ctrl_res);
7483703f53bSSrinivas Pandruvada 
7493703f53bSSrinivas Pandruvada 		/* Disband any pending read/write requests and free rb */
7503703f53bSSrinivas Pandruvada 		ishtp_cl_flush_queues(cl);
7513703f53bSSrinivas Pandruvada 
7523703f53bSSrinivas Pandruvada 		/* Remove all free and in_process rings, both Rx and Tx */
7533703f53bSSrinivas Pandruvada 		ishtp_cl_free_rx_ring(cl);
7543703f53bSSrinivas Pandruvada 		ishtp_cl_free_tx_ring(cl);
7553703f53bSSrinivas Pandruvada 
7563703f53bSSrinivas Pandruvada 		/*
7573703f53bSSrinivas Pandruvada 		 * Free client and ISHTP bus client device structures
7583703f53bSSrinivas Pandruvada 		 * don't free host client because it is part of the OS fd
7593703f53bSSrinivas Pandruvada 		 * structure
7603703f53bSSrinivas Pandruvada 		 */
7613703f53bSSrinivas Pandruvada 	}
7623703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&ishtp_dev->cl_list_lock, flags);
7633703f53bSSrinivas Pandruvada 
7643703f53bSSrinivas Pandruvada 	/* Release DMA buffers for client messages */
7653703f53bSSrinivas Pandruvada 	ishtp_cl_free_dma_buf(ishtp_dev);
7663703f53bSSrinivas Pandruvada 
7673703f53bSSrinivas Pandruvada 	/* remove bus clients */
7683703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&ishtp_dev->device_list_lock, flags);
7693703f53bSSrinivas Pandruvada 	list_for_each_entry_safe(cl_device, n, &ishtp_dev->device_list,
7703703f53bSSrinivas Pandruvada 				 device_link) {
7710d28f494SHong Liu 		cl_device->fw_client = NULL;
7723703f53bSSrinivas Pandruvada 		if (warm_reset && cl_device->reference_count)
7733703f53bSSrinivas Pandruvada 			continue;
7743703f53bSSrinivas Pandruvada 
7753703f53bSSrinivas Pandruvada 		list_del(&cl_device->device_link);
7763703f53bSSrinivas Pandruvada 		spin_unlock_irqrestore(&ishtp_dev->device_list_lock, flags);
7773703f53bSSrinivas Pandruvada 		ishtp_bus_remove_device(cl_device);
7783703f53bSSrinivas Pandruvada 		spin_lock_irqsave(&ishtp_dev->device_list_lock, flags);
7793703f53bSSrinivas Pandruvada 	}
7803703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&ishtp_dev->device_list_lock, flags);
7813703f53bSSrinivas Pandruvada 
7823703f53bSSrinivas Pandruvada 	/* Free all client structures */
7833703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&ishtp_dev->fw_clients_lock, flags);
7843703f53bSSrinivas Pandruvada 	kfree(ishtp_dev->fw_clients);
7853703f53bSSrinivas Pandruvada 	ishtp_dev->fw_clients = NULL;
7863703f53bSSrinivas Pandruvada 	ishtp_dev->fw_clients_num = 0;
7873703f53bSSrinivas Pandruvada 	ishtp_dev->fw_client_presentation_num = 0;
7883703f53bSSrinivas Pandruvada 	ishtp_dev->fw_client_index = 0;
7893703f53bSSrinivas Pandruvada 	bitmap_zero(ishtp_dev->fw_clients_map, ISHTP_CLIENTS_MAX);
7903703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&ishtp_dev->fw_clients_lock, flags);
7913703f53bSSrinivas Pandruvada }
7923703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_bus_remove_all_clients);
7933703f53bSSrinivas Pandruvada 
7943703f53bSSrinivas Pandruvada /**
7953703f53bSSrinivas Pandruvada  * ishtp_reset_handler() - IPC reset handler
7963703f53bSSrinivas Pandruvada  * @dev:	ishtp device
7973703f53bSSrinivas Pandruvada  *
7983703f53bSSrinivas Pandruvada  * ISHTP Handler for IPC_RESET notification
7993703f53bSSrinivas Pandruvada  */
8003703f53bSSrinivas Pandruvada void ishtp_reset_handler(struct ishtp_device *dev)
8013703f53bSSrinivas Pandruvada {
8023703f53bSSrinivas Pandruvada 	unsigned long	flags;
8033703f53bSSrinivas Pandruvada 
8043703f53bSSrinivas Pandruvada 	/* Handle FW-initiated reset */
8053703f53bSSrinivas Pandruvada 	dev->dev_state = ISHTP_DEV_RESETTING;
8063703f53bSSrinivas Pandruvada 
8073703f53bSSrinivas Pandruvada 	/* Clear BH processing queue - no further HBMs */
8083703f53bSSrinivas Pandruvada 	spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
8093703f53bSSrinivas Pandruvada 	dev->rd_msg_fifo_head = dev->rd_msg_fifo_tail = 0;
8103703f53bSSrinivas Pandruvada 	spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
8113703f53bSSrinivas Pandruvada 
8123703f53bSSrinivas Pandruvada 	/* Handle ISH FW reset against upper layers */
8133703f53bSSrinivas Pandruvada 	ishtp_bus_remove_all_clients(dev, true);
8143703f53bSSrinivas Pandruvada }
8153703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_reset_handler);
8163703f53bSSrinivas Pandruvada 
8173703f53bSSrinivas Pandruvada /**
8183703f53bSSrinivas Pandruvada  * ishtp_reset_compl_handler() - Reset completion handler
8193703f53bSSrinivas Pandruvada  * @dev:	ishtp device
8203703f53bSSrinivas Pandruvada  *
8213703f53bSSrinivas Pandruvada  * ISHTP handler for IPC_RESET sequence completion to start
8223703f53bSSrinivas Pandruvada  * host message bus start protocol sequence.
8233703f53bSSrinivas Pandruvada  */
8243703f53bSSrinivas Pandruvada void ishtp_reset_compl_handler(struct ishtp_device *dev)
8253703f53bSSrinivas Pandruvada {
8263703f53bSSrinivas Pandruvada 	dev->dev_state = ISHTP_DEV_INIT_CLIENTS;
8273703f53bSSrinivas Pandruvada 	dev->hbm_state = ISHTP_HBM_START;
8283703f53bSSrinivas Pandruvada 	ishtp_hbm_start_req(dev);
8293703f53bSSrinivas Pandruvada }
8303703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_reset_compl_handler);
8313703f53bSSrinivas Pandruvada 
8323703f53bSSrinivas Pandruvada /**
8333703f53bSSrinivas Pandruvada  * ishtp_use_dma_transfer() - Function to use DMA
8343703f53bSSrinivas Pandruvada  *
8353703f53bSSrinivas Pandruvada  * This interface is used to enable usage of DMA
8363703f53bSSrinivas Pandruvada  *
8373703f53bSSrinivas Pandruvada  * Return non zero if DMA can be enabled
8383703f53bSSrinivas Pandruvada  */
8393703f53bSSrinivas Pandruvada int ishtp_use_dma_transfer(void)
8403703f53bSSrinivas Pandruvada {
8413703f53bSSrinivas Pandruvada 	return ishtp_use_dma;
8423703f53bSSrinivas Pandruvada }
8433703f53bSSrinivas Pandruvada 
8443703f53bSSrinivas Pandruvada /**
8457ab21842SSrinivas Pandruvada  * ishtp_device() - Return device pointer
8467ab21842SSrinivas Pandruvada  *
8477ab21842SSrinivas Pandruvada  * This interface is used to return device pointer from ishtp_cl_device
8487ab21842SSrinivas Pandruvada  * instance.
8497ab21842SSrinivas Pandruvada  *
8507ab21842SSrinivas Pandruvada  * Return: device *.
8517ab21842SSrinivas Pandruvada  */
8527ab21842SSrinivas Pandruvada struct device *ishtp_device(struct ishtp_cl_device *device)
8537ab21842SSrinivas Pandruvada {
8547ab21842SSrinivas Pandruvada 	return &device->dev;
8557ab21842SSrinivas Pandruvada }
8567ab21842SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_device);
8577ab21842SSrinivas Pandruvada 
8587ab21842SSrinivas Pandruvada /**
8597ab21842SSrinivas Pandruvada  * ishtp_trace_callback() - Return trace callback
8607ab21842SSrinivas Pandruvada  *
8617ab21842SSrinivas Pandruvada  * This interface is used to return trace callback function pointer.
8627ab21842SSrinivas Pandruvada  *
8637ab21842SSrinivas Pandruvada  * Return: void *.
8647ab21842SSrinivas Pandruvada  */
8657ab21842SSrinivas Pandruvada void *ishtp_trace_callback(struct ishtp_cl_device *cl_device)
8667ab21842SSrinivas Pandruvada {
8677ab21842SSrinivas Pandruvada 	return cl_device->ishtp_dev->print_log;
8687ab21842SSrinivas Pandruvada }
8697ab21842SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_trace_callback);
8707ab21842SSrinivas Pandruvada 
8717ab21842SSrinivas Pandruvada /**
8725f7224cfSSrinivas Pandruvada  * ish_hw_reset() - Call HW reset IPC callback
8735f7224cfSSrinivas Pandruvada  *
8745f7224cfSSrinivas Pandruvada  * This interface is used to reset HW in case of error.
8755f7224cfSSrinivas Pandruvada  *
8765f7224cfSSrinivas Pandruvada  * Return: value from IPC hw_reset callback
8775f7224cfSSrinivas Pandruvada  */
8785f7224cfSSrinivas Pandruvada int ish_hw_reset(struct ishtp_device *dev)
8795f7224cfSSrinivas Pandruvada {
8805f7224cfSSrinivas Pandruvada 	return dev->ops->hw_reset(dev);
8815f7224cfSSrinivas Pandruvada }
8825f7224cfSSrinivas Pandruvada EXPORT_SYMBOL(ish_hw_reset);
8835f7224cfSSrinivas Pandruvada 
8845f7224cfSSrinivas Pandruvada /**
8853703f53bSSrinivas Pandruvada  * ishtp_bus_register() - Function to register bus
8863703f53bSSrinivas Pandruvada  *
8873703f53bSSrinivas Pandruvada  * This register ishtp bus
8883703f53bSSrinivas Pandruvada  *
8893703f53bSSrinivas Pandruvada  * Return: Return output of bus_register
8903703f53bSSrinivas Pandruvada  */
8913703f53bSSrinivas Pandruvada static int  __init ishtp_bus_register(void)
8923703f53bSSrinivas Pandruvada {
8933703f53bSSrinivas Pandruvada 	return bus_register(&ishtp_cl_bus_type);
8943703f53bSSrinivas Pandruvada }
8953703f53bSSrinivas Pandruvada 
8963703f53bSSrinivas Pandruvada /**
8973703f53bSSrinivas Pandruvada  * ishtp_bus_unregister() - Function to unregister bus
8983703f53bSSrinivas Pandruvada  *
8993703f53bSSrinivas Pandruvada  * This unregister ishtp bus
9003703f53bSSrinivas Pandruvada  */
9013703f53bSSrinivas Pandruvada static void __exit ishtp_bus_unregister(void)
9023703f53bSSrinivas Pandruvada {
9033703f53bSSrinivas Pandruvada 	bus_unregister(&ishtp_cl_bus_type);
9043703f53bSSrinivas Pandruvada }
9053703f53bSSrinivas Pandruvada 
9063703f53bSSrinivas Pandruvada module_init(ishtp_bus_register);
9073703f53bSSrinivas Pandruvada module_exit(ishtp_bus_unregister);
9083703f53bSSrinivas Pandruvada 
9093703f53bSSrinivas Pandruvada MODULE_LICENSE("GPL");
910