12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23703f53bSSrinivas Pandruvada /*
33703f53bSSrinivas Pandruvada * ISHTP bus driver
43703f53bSSrinivas Pandruvada *
53703f53bSSrinivas Pandruvada * Copyright (c) 2012-2016, Intel Corporation.
63703f53bSSrinivas Pandruvada */
73703f53bSSrinivas Pandruvada
83703f53bSSrinivas Pandruvada #include <linux/module.h>
93703f53bSSrinivas Pandruvada #include <linux/init.h>
103703f53bSSrinivas Pandruvada #include <linux/kernel.h>
113703f53bSSrinivas Pandruvada #include <linux/device.h>
123703f53bSSrinivas Pandruvada #include <linux/sched.h>
133703f53bSSrinivas Pandruvada #include <linux/slab.h>
143703f53bSSrinivas Pandruvada #include "bus.h"
153703f53bSSrinivas Pandruvada #include "ishtp-dev.h"
163703f53bSSrinivas Pandruvada #include "client.h"
173703f53bSSrinivas Pandruvada #include "hbm.h"
183703f53bSSrinivas Pandruvada
193703f53bSSrinivas Pandruvada static int ishtp_use_dma;
203703f53bSSrinivas Pandruvada module_param_named(ishtp_use_dma, ishtp_use_dma, int, 0600);
213703f53bSSrinivas Pandruvada MODULE_PARM_DESC(ishtp_use_dma, "Use DMA to send messages");
223703f53bSSrinivas Pandruvada
233703f53bSSrinivas Pandruvada #define to_ishtp_cl_driver(d) container_of(d, struct ishtp_cl_driver, driver)
243703f53bSSrinivas Pandruvada #define to_ishtp_cl_device(d) container_of(d, struct ishtp_cl_device, dev)
253703f53bSSrinivas Pandruvada static bool ishtp_device_ready;
263703f53bSSrinivas Pandruvada
273703f53bSSrinivas Pandruvada /**
283703f53bSSrinivas Pandruvada * ishtp_recv() - process ishtp message
293703f53bSSrinivas Pandruvada * @dev: ishtp device
303703f53bSSrinivas Pandruvada *
313703f53bSSrinivas Pandruvada * If a message with valid header and size is received, then
323703f53bSSrinivas Pandruvada * this function calls appropriate handler. The host or firmware
333703f53bSSrinivas Pandruvada * address is zero, then they are host bus management message,
343703f53bSSrinivas Pandruvada * otherwise they are message fo clients.
353703f53bSSrinivas Pandruvada */
ishtp_recv(struct ishtp_device * dev)363703f53bSSrinivas Pandruvada void ishtp_recv(struct ishtp_device *dev)
373703f53bSSrinivas Pandruvada {
383703f53bSSrinivas Pandruvada uint32_t msg_hdr;
393703f53bSSrinivas Pandruvada struct ishtp_msg_hdr *ishtp_hdr;
403703f53bSSrinivas Pandruvada
413703f53bSSrinivas Pandruvada /* Read ISHTP header dword */
423703f53bSSrinivas Pandruvada msg_hdr = dev->ops->ishtp_read_hdr(dev);
433703f53bSSrinivas Pandruvada if (!msg_hdr)
443703f53bSSrinivas Pandruvada return;
453703f53bSSrinivas Pandruvada
463703f53bSSrinivas Pandruvada dev->ops->sync_fw_clock(dev);
473703f53bSSrinivas Pandruvada
483703f53bSSrinivas Pandruvada ishtp_hdr = (struct ishtp_msg_hdr *)&msg_hdr;
493703f53bSSrinivas Pandruvada dev->ishtp_msg_hdr = msg_hdr;
503703f53bSSrinivas Pandruvada
513703f53bSSrinivas Pandruvada /* Sanity check: ISHTP frag. length in header */
523703f53bSSrinivas Pandruvada if (ishtp_hdr->length > dev->mtu) {
533703f53bSSrinivas Pandruvada dev_err(dev->devc,
543703f53bSSrinivas Pandruvada "ISHTP hdr - bad length: %u; dropped [%08X]\n",
553703f53bSSrinivas Pandruvada (unsigned int)ishtp_hdr->length, msg_hdr);
563703f53bSSrinivas Pandruvada return;
573703f53bSSrinivas Pandruvada }
583703f53bSSrinivas Pandruvada
593703f53bSSrinivas Pandruvada /* ISHTP bus message */
603703f53bSSrinivas Pandruvada if (!ishtp_hdr->host_addr && !ishtp_hdr->fw_addr)
613703f53bSSrinivas Pandruvada recv_hbm(dev, ishtp_hdr);
623703f53bSSrinivas Pandruvada /* ISHTP fixed-client message */
633703f53bSSrinivas Pandruvada else if (!ishtp_hdr->host_addr)
643703f53bSSrinivas Pandruvada recv_fixed_cl_msg(dev, ishtp_hdr);
653703f53bSSrinivas Pandruvada else
663703f53bSSrinivas Pandruvada /* ISHTP client message */
673703f53bSSrinivas Pandruvada recv_ishtp_cl_msg(dev, ishtp_hdr);
683703f53bSSrinivas Pandruvada }
693703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_recv);
703703f53bSSrinivas Pandruvada
713703f53bSSrinivas Pandruvada /**
723703f53bSSrinivas Pandruvada * ishtp_send_msg() - Send ishtp message
733703f53bSSrinivas Pandruvada * @dev: ishtp device
743703f53bSSrinivas Pandruvada * @hdr: Message header
753703f53bSSrinivas Pandruvada * @msg: Message contents
763703f53bSSrinivas Pandruvada * @ipc_send_compl: completion callback
773703f53bSSrinivas Pandruvada * @ipc_send_compl_prm: completion callback parameter
783703f53bSSrinivas Pandruvada *
793703f53bSSrinivas Pandruvada * Send a multi fragment message via IPC. After sending the first fragment
803703f53bSSrinivas Pandruvada * the completion callback is called to schedule transmit of next fragment.
813703f53bSSrinivas Pandruvada *
823703f53bSSrinivas Pandruvada * Return: This returns IPC send message status.
833703f53bSSrinivas Pandruvada */
ishtp_send_msg(struct ishtp_device * dev,struct ishtp_msg_hdr * hdr,void * msg,void (* ipc_send_compl)(void *),void * ipc_send_compl_prm)843703f53bSSrinivas Pandruvada int ishtp_send_msg(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
853703f53bSSrinivas Pandruvada void *msg, void(*ipc_send_compl)(void *),
863703f53bSSrinivas Pandruvada void *ipc_send_compl_prm)
873703f53bSSrinivas Pandruvada {
883703f53bSSrinivas Pandruvada unsigned char ipc_msg[IPC_FULL_MSG_SIZE];
893703f53bSSrinivas Pandruvada uint32_t drbl_val;
903703f53bSSrinivas Pandruvada
913703f53bSSrinivas Pandruvada drbl_val = dev->ops->ipc_get_header(dev, hdr->length +
923703f53bSSrinivas Pandruvada sizeof(struct ishtp_msg_hdr),
933703f53bSSrinivas Pandruvada 1);
943703f53bSSrinivas Pandruvada
953703f53bSSrinivas Pandruvada memcpy(ipc_msg, &drbl_val, sizeof(uint32_t));
963703f53bSSrinivas Pandruvada memcpy(ipc_msg + sizeof(uint32_t), hdr, sizeof(uint32_t));
973703f53bSSrinivas Pandruvada memcpy(ipc_msg + 2 * sizeof(uint32_t), msg, hdr->length);
983703f53bSSrinivas Pandruvada return dev->ops->write(dev, ipc_send_compl, ipc_send_compl_prm,
993703f53bSSrinivas Pandruvada ipc_msg, 2 * sizeof(uint32_t) + hdr->length);
1003703f53bSSrinivas Pandruvada }
1013703f53bSSrinivas Pandruvada
1023703f53bSSrinivas Pandruvada /**
1033703f53bSSrinivas Pandruvada * ishtp_write_message() - Send ishtp single fragment message
1043703f53bSSrinivas Pandruvada * @dev: ishtp device
1053703f53bSSrinivas Pandruvada * @hdr: Message header
1063703f53bSSrinivas Pandruvada * @buf: message data
1073703f53bSSrinivas Pandruvada *
1083703f53bSSrinivas Pandruvada * Send a single fragment message via IPC. This returns IPC send message
1093703f53bSSrinivas Pandruvada * status.
1103703f53bSSrinivas Pandruvada *
1113703f53bSSrinivas Pandruvada * Return: This returns IPC send message status.
1123703f53bSSrinivas Pandruvada */
ishtp_write_message(struct ishtp_device * dev,struct ishtp_msg_hdr * hdr,void * buf)1133703f53bSSrinivas Pandruvada int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
11409cc8b36SHong Liu void *buf)
1153703f53bSSrinivas Pandruvada {
1163703f53bSSrinivas Pandruvada return ishtp_send_msg(dev, hdr, buf, NULL, NULL);
1173703f53bSSrinivas Pandruvada }
1183703f53bSSrinivas Pandruvada
1193703f53bSSrinivas Pandruvada /**
1203703f53bSSrinivas Pandruvada * ishtp_fw_cl_by_uuid() - locate index of fw client
1213703f53bSSrinivas Pandruvada * @dev: ishtp device
1223703f53bSSrinivas Pandruvada * @uuid: uuid of the client to search
1233703f53bSSrinivas Pandruvada *
1243703f53bSSrinivas Pandruvada * Search firmware client using UUID.
1253703f53bSSrinivas Pandruvada *
1263703f53bSSrinivas Pandruvada * Return: fw client index or -ENOENT if not found
1273703f53bSSrinivas Pandruvada */
ishtp_fw_cl_by_uuid(struct ishtp_device * dev,const guid_t * uuid)12814106501SAndy Shevchenko int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const guid_t *uuid)
1293703f53bSSrinivas Pandruvada {
13014106501SAndy Shevchenko unsigned int i;
1313703f53bSSrinivas Pandruvada
1323703f53bSSrinivas Pandruvada for (i = 0; i < dev->fw_clients_num; ++i) {
13314106501SAndy Shevchenko if (guid_equal(uuid, &dev->fw_clients[i].props.protocol_name))
13414106501SAndy Shevchenko return i;
1353703f53bSSrinivas Pandruvada }
13614106501SAndy Shevchenko return -ENOENT;
1373703f53bSSrinivas Pandruvada }
1383703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
1393703f53bSSrinivas Pandruvada
1403703f53bSSrinivas Pandruvada /**
141e625020bSEven Xu * ishtp_fw_cl_get_client() - return client information to client
142e625020bSEven Xu * @dev: the ishtp device structure
143e625020bSEven Xu * @uuid: uuid of the client to search
144e625020bSEven Xu *
145e625020bSEven Xu * Search firmware client using UUID and reture related client information.
146e625020bSEven Xu *
147e625020bSEven Xu * Return: pointer of client information on success, NULL on failure.
148e625020bSEven Xu */
ishtp_fw_cl_get_client(struct ishtp_device * dev,const guid_t * uuid)149e625020bSEven Xu struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
15014106501SAndy Shevchenko const guid_t *uuid)
151e625020bSEven Xu {
152e625020bSEven Xu int i;
153e625020bSEven Xu unsigned long flags;
154e625020bSEven Xu
155e625020bSEven Xu spin_lock_irqsave(&dev->fw_clients_lock, flags);
156e625020bSEven Xu i = ishtp_fw_cl_by_uuid(dev, uuid);
157e625020bSEven Xu spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
158e625020bSEven Xu if (i < 0 || dev->fw_clients[i].props.fixed_address)
159e625020bSEven Xu return NULL;
160e625020bSEven Xu
161e625020bSEven Xu return &dev->fw_clients[i];
162e625020bSEven Xu }
163e625020bSEven Xu EXPORT_SYMBOL(ishtp_fw_cl_get_client);
164e625020bSEven Xu
165e625020bSEven Xu /**
1665f7224cfSSrinivas Pandruvada * ishtp_get_fw_client_id() - Get fw client id
167d5831beeSLee Jones * @fw_client: firmware client used to fetch the ID
1685f7224cfSSrinivas Pandruvada *
1695f7224cfSSrinivas Pandruvada * This interface is used to reset HW get FW client id.
1705f7224cfSSrinivas Pandruvada *
1715f7224cfSSrinivas Pandruvada * Return: firmware client id.
1725f7224cfSSrinivas Pandruvada */
ishtp_get_fw_client_id(struct ishtp_fw_client * fw_client)1735f7224cfSSrinivas Pandruvada int ishtp_get_fw_client_id(struct ishtp_fw_client *fw_client)
1745f7224cfSSrinivas Pandruvada {
1755f7224cfSSrinivas Pandruvada return fw_client->client_id;
1765f7224cfSSrinivas Pandruvada }
1775f7224cfSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_get_fw_client_id);
1785f7224cfSSrinivas Pandruvada
1795f7224cfSSrinivas Pandruvada /**
1803703f53bSSrinivas Pandruvada * ishtp_fw_cl_by_id() - return index to fw_clients for client_id
1813703f53bSSrinivas Pandruvada * @dev: the ishtp device structure
1823703f53bSSrinivas Pandruvada * @client_id: fw client id to search
1833703f53bSSrinivas Pandruvada *
1843703f53bSSrinivas Pandruvada * Search firmware client using client id.
1853703f53bSSrinivas Pandruvada *
1863703f53bSSrinivas Pandruvada * Return: index on success, -ENOENT on failure.
1873703f53bSSrinivas Pandruvada */
ishtp_fw_cl_by_id(struct ishtp_device * dev,uint8_t client_id)1883703f53bSSrinivas Pandruvada int ishtp_fw_cl_by_id(struct ishtp_device *dev, uint8_t client_id)
1893703f53bSSrinivas Pandruvada {
1903703f53bSSrinivas Pandruvada int i, res = -ENOENT;
1913703f53bSSrinivas Pandruvada unsigned long flags;
1923703f53bSSrinivas Pandruvada
1933703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->fw_clients_lock, flags);
1943703f53bSSrinivas Pandruvada for (i = 0; i < dev->fw_clients_num; i++) {
1953703f53bSSrinivas Pandruvada if (dev->fw_clients[i].client_id == client_id) {
1963703f53bSSrinivas Pandruvada res = i;
1973703f53bSSrinivas Pandruvada break;
1983703f53bSSrinivas Pandruvada }
1993703f53bSSrinivas Pandruvada }
2003703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->fw_clients_lock, flags);
2013703f53bSSrinivas Pandruvada
2023703f53bSSrinivas Pandruvada return res;
2033703f53bSSrinivas Pandruvada }
2043703f53bSSrinivas Pandruvada
2053703f53bSSrinivas Pandruvada /**
2063703f53bSSrinivas Pandruvada * ishtp_cl_device_probe() - Bus probe() callback
2073703f53bSSrinivas Pandruvada * @dev: the device structure
2083703f53bSSrinivas Pandruvada *
2093703f53bSSrinivas Pandruvada * This is a bus probe callback and calls the drive probe function.
2103703f53bSSrinivas Pandruvada *
2113703f53bSSrinivas Pandruvada * Return: Return value from driver probe() call.
2123703f53bSSrinivas Pandruvada */
ishtp_cl_device_probe(struct device * dev)2133703f53bSSrinivas Pandruvada static int ishtp_cl_device_probe(struct device *dev)
2143703f53bSSrinivas Pandruvada {
2153703f53bSSrinivas Pandruvada struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
2163703f53bSSrinivas Pandruvada struct ishtp_cl_driver *driver;
2173703f53bSSrinivas Pandruvada
2183703f53bSSrinivas Pandruvada if (!device)
2193703f53bSSrinivas Pandruvada return 0;
2203703f53bSSrinivas Pandruvada
2213703f53bSSrinivas Pandruvada driver = to_ishtp_cl_driver(dev->driver);
2223703f53bSSrinivas Pandruvada if (!driver || !driver->probe)
2233703f53bSSrinivas Pandruvada return -ENODEV;
2243703f53bSSrinivas Pandruvada
2253703f53bSSrinivas Pandruvada return driver->probe(device);
2263703f53bSSrinivas Pandruvada }
2273703f53bSSrinivas Pandruvada
2283703f53bSSrinivas Pandruvada /**
2296b3f75f7SHong Liu * ishtp_cl_bus_match() - Bus match() callback
2306b3f75f7SHong Liu * @dev: the device structure
2316b3f75f7SHong Liu * @drv: the driver structure
2326b3f75f7SHong Liu *
2336b3f75f7SHong Liu * This is a bus match callback, called when a new ishtp_cl_device is
2346b3f75f7SHong Liu * registered during ishtp bus client enumeration. Use the guid_t in
2356b3f75f7SHong Liu * drv and dev to decide whether they match or not.
2366b3f75f7SHong Liu *
2376b3f75f7SHong Liu * Return: 1 if dev & drv matches, 0 otherwise.
2386b3f75f7SHong Liu */
ishtp_cl_bus_match(struct device * dev,struct device_driver * drv)2396b3f75f7SHong Liu static int ishtp_cl_bus_match(struct device *dev, struct device_driver *drv)
2406b3f75f7SHong Liu {
2416b3f75f7SHong Liu struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
2426b3f75f7SHong Liu struct ishtp_cl_driver *driver = to_ishtp_cl_driver(drv);
2436b3f75f7SHong Liu
244*38518593STanu Malhotra return(device->fw_client ? guid_equal(&driver->id[0].guid,
245*38518593STanu Malhotra &device->fw_client->props.protocol_name) : 0);
2466b3f75f7SHong Liu }
2476b3f75f7SHong Liu
2486b3f75f7SHong Liu /**
2493703f53bSSrinivas Pandruvada * ishtp_cl_device_remove() - Bus remove() callback
2503703f53bSSrinivas Pandruvada * @dev: the device structure
2513703f53bSSrinivas Pandruvada *
2523703f53bSSrinivas Pandruvada * This is a bus remove callback and calls the drive remove function.
2533703f53bSSrinivas Pandruvada * Since the ISH driver model supports only built in, this is
2543703f53bSSrinivas Pandruvada * primarily can be called during pci driver init failure.
2553703f53bSSrinivas Pandruvada *
2563703f53bSSrinivas Pandruvada * Return: Return value from driver remove() call.
2573703f53bSSrinivas Pandruvada */
ishtp_cl_device_remove(struct device * dev)258fc7a6209SUwe Kleine-König static void ishtp_cl_device_remove(struct device *dev)
2593703f53bSSrinivas Pandruvada {
2603703f53bSSrinivas Pandruvada struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
261464956f7SUwe Kleine-König struct ishtp_cl_driver *driver = to_ishtp_cl_driver(dev->driver);
2623703f53bSSrinivas Pandruvada
2633703f53bSSrinivas Pandruvada if (device->event_cb) {
2643703f53bSSrinivas Pandruvada device->event_cb = NULL;
2653703f53bSSrinivas Pandruvada cancel_work_sync(&device->event_work);
2663703f53bSSrinivas Pandruvada }
2673703f53bSSrinivas Pandruvada
2687c746603SUwe Kleine-König if (driver->remove)
269e71da1fdSUwe Kleine-König driver->remove(device);
2703703f53bSSrinivas Pandruvada }
2713703f53bSSrinivas Pandruvada
2723703f53bSSrinivas Pandruvada /**
2733703f53bSSrinivas Pandruvada * ishtp_cl_device_suspend() - Bus suspend callback
2743703f53bSSrinivas Pandruvada * @dev: device
2753703f53bSSrinivas Pandruvada *
2763703f53bSSrinivas Pandruvada * Called during device suspend process.
2773703f53bSSrinivas Pandruvada *
2783703f53bSSrinivas Pandruvada * Return: Return value from driver suspend() call.
2793703f53bSSrinivas Pandruvada */
ishtp_cl_device_suspend(struct device * dev)2803703f53bSSrinivas Pandruvada static int ishtp_cl_device_suspend(struct device *dev)
2813703f53bSSrinivas Pandruvada {
2823703f53bSSrinivas Pandruvada struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
2833703f53bSSrinivas Pandruvada struct ishtp_cl_driver *driver;
2843703f53bSSrinivas Pandruvada int ret = 0;
2853703f53bSSrinivas Pandruvada
2863703f53bSSrinivas Pandruvada if (!device)
2873703f53bSSrinivas Pandruvada return 0;
2883703f53bSSrinivas Pandruvada
2893703f53bSSrinivas Pandruvada driver = to_ishtp_cl_driver(dev->driver);
2903703f53bSSrinivas Pandruvada if (driver && driver->driver.pm) {
2913703f53bSSrinivas Pandruvada if (driver->driver.pm->suspend)
2923703f53bSSrinivas Pandruvada ret = driver->driver.pm->suspend(dev);
2933703f53bSSrinivas Pandruvada }
2943703f53bSSrinivas Pandruvada
2953703f53bSSrinivas Pandruvada return ret;
2963703f53bSSrinivas Pandruvada }
2973703f53bSSrinivas Pandruvada
2983703f53bSSrinivas Pandruvada /**
2993703f53bSSrinivas Pandruvada * ishtp_cl_device_resume() - Bus resume callback
3003703f53bSSrinivas Pandruvada * @dev: device
3013703f53bSSrinivas Pandruvada *
3023703f53bSSrinivas Pandruvada * Called during device resume process.
3033703f53bSSrinivas Pandruvada *
3043703f53bSSrinivas Pandruvada * Return: Return value from driver resume() call.
3053703f53bSSrinivas Pandruvada */
ishtp_cl_device_resume(struct device * dev)3063703f53bSSrinivas Pandruvada static int ishtp_cl_device_resume(struct device *dev)
3073703f53bSSrinivas Pandruvada {
3083703f53bSSrinivas Pandruvada struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
3093703f53bSSrinivas Pandruvada struct ishtp_cl_driver *driver;
3103703f53bSSrinivas Pandruvada int ret = 0;
3113703f53bSSrinivas Pandruvada
3123703f53bSSrinivas Pandruvada if (!device)
3133703f53bSSrinivas Pandruvada return 0;
3143703f53bSSrinivas Pandruvada
3153703f53bSSrinivas Pandruvada driver = to_ishtp_cl_driver(dev->driver);
3163703f53bSSrinivas Pandruvada if (driver && driver->driver.pm) {
3173703f53bSSrinivas Pandruvada if (driver->driver.pm->resume)
3183703f53bSSrinivas Pandruvada ret = driver->driver.pm->resume(dev);
3193703f53bSSrinivas Pandruvada }
3203703f53bSSrinivas Pandruvada
3213703f53bSSrinivas Pandruvada return ret;
3223703f53bSSrinivas Pandruvada }
3233703f53bSSrinivas Pandruvada
3243703f53bSSrinivas Pandruvada /**
3253703f53bSSrinivas Pandruvada * ishtp_cl_device_reset() - Reset callback
3263703f53bSSrinivas Pandruvada * @device: ishtp client device instance
3273703f53bSSrinivas Pandruvada *
3283703f53bSSrinivas Pandruvada * This is a callback when HW reset is done and the device need
3293703f53bSSrinivas Pandruvada * reinit.
3303703f53bSSrinivas Pandruvada *
3313703f53bSSrinivas Pandruvada * Return: Return value from driver reset() call.
3323703f53bSSrinivas Pandruvada */
ishtp_cl_device_reset(struct ishtp_cl_device * device)3333703f53bSSrinivas Pandruvada static int ishtp_cl_device_reset(struct ishtp_cl_device *device)
3343703f53bSSrinivas Pandruvada {
3353703f53bSSrinivas Pandruvada struct ishtp_cl_driver *driver;
3363703f53bSSrinivas Pandruvada int ret = 0;
3373703f53bSSrinivas Pandruvada
3383703f53bSSrinivas Pandruvada device->event_cb = NULL;
3393703f53bSSrinivas Pandruvada cancel_work_sync(&device->event_work);
3403703f53bSSrinivas Pandruvada
3413703f53bSSrinivas Pandruvada driver = to_ishtp_cl_driver(device->dev.driver);
3423703f53bSSrinivas Pandruvada if (driver && driver->reset)
3433703f53bSSrinivas Pandruvada ret = driver->reset(device);
3443703f53bSSrinivas Pandruvada
3453703f53bSSrinivas Pandruvada return ret;
3463703f53bSSrinivas Pandruvada }
3473703f53bSSrinivas Pandruvada
modalias_show(struct device * dev,struct device_attribute * a,char * buf)3483703f53bSSrinivas Pandruvada static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
3493703f53bSSrinivas Pandruvada char *buf)
3503703f53bSSrinivas Pandruvada {
3513703f53bSSrinivas Pandruvada int len;
3523703f53bSSrinivas Pandruvada
353cb1a2c68SThomas Weißschuh len = snprintf(buf, PAGE_SIZE, ISHTP_MODULE_PREFIX "%s\n", dev_name(dev));
3543703f53bSSrinivas Pandruvada return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
3553703f53bSSrinivas Pandruvada }
356480104b7SGreg Kroah-Hartman static DEVICE_ATTR_RO(modalias);
3573703f53bSSrinivas Pandruvada
358480104b7SGreg Kroah-Hartman static struct attribute *ishtp_cl_dev_attrs[] = {
359480104b7SGreg Kroah-Hartman &dev_attr_modalias.attr,
360480104b7SGreg Kroah-Hartman NULL,
3613703f53bSSrinivas Pandruvada };
362480104b7SGreg Kroah-Hartman ATTRIBUTE_GROUPS(ishtp_cl_dev);
3633703f53bSSrinivas Pandruvada
ishtp_cl_uevent(const struct device * dev,struct kobj_uevent_env * env)3643703f53bSSrinivas Pandruvada static int ishtp_cl_uevent(const struct device *dev, struct kobj_uevent_env *env)
3653703f53bSSrinivas Pandruvada {
366cb1a2c68SThomas Weißschuh if (add_uevent_var(env, "MODALIAS=" ISHTP_MODULE_PREFIX "%s", dev_name(dev)))
3673703f53bSSrinivas Pandruvada return -ENOMEM;
3683703f53bSSrinivas Pandruvada return 0;
3693703f53bSSrinivas Pandruvada }
3703703f53bSSrinivas Pandruvada
3713703f53bSSrinivas Pandruvada static const struct dev_pm_ops ishtp_cl_bus_dev_pm_ops = {
3723703f53bSSrinivas Pandruvada /* Suspend callbacks */
3733703f53bSSrinivas Pandruvada .suspend = ishtp_cl_device_suspend,
3743703f53bSSrinivas Pandruvada .resume = ishtp_cl_device_resume,
3753703f53bSSrinivas Pandruvada /* Hibernate callbacks */
3763703f53bSSrinivas Pandruvada .freeze = ishtp_cl_device_suspend,
3773703f53bSSrinivas Pandruvada .thaw = ishtp_cl_device_resume,
3783703f53bSSrinivas Pandruvada .restore = ishtp_cl_device_resume,
3793703f53bSSrinivas Pandruvada };
3803703f53bSSrinivas Pandruvada
3813703f53bSSrinivas Pandruvada static struct bus_type ishtp_cl_bus_type = {
3823703f53bSSrinivas Pandruvada .name = "ishtp",
383480104b7SGreg Kroah-Hartman .dev_groups = ishtp_cl_dev_groups,
3843703f53bSSrinivas Pandruvada .probe = ishtp_cl_device_probe,
3856b3f75f7SHong Liu .match = ishtp_cl_bus_match,
3863703f53bSSrinivas Pandruvada .remove = ishtp_cl_device_remove,
3873703f53bSSrinivas Pandruvada .pm = &ishtp_cl_bus_dev_pm_ops,
3883703f53bSSrinivas Pandruvada .uevent = ishtp_cl_uevent,
3893703f53bSSrinivas Pandruvada };
3903703f53bSSrinivas Pandruvada
ishtp_cl_dev_release(struct device * dev)3913703f53bSSrinivas Pandruvada static void ishtp_cl_dev_release(struct device *dev)
3923703f53bSSrinivas Pandruvada {
3933703f53bSSrinivas Pandruvada kfree(to_ishtp_cl_device(dev));
3943703f53bSSrinivas Pandruvada }
3953703f53bSSrinivas Pandruvada
39612be9f7bSBhumika Goyal static const struct device_type ishtp_cl_device_type = {
3973703f53bSSrinivas Pandruvada .release = ishtp_cl_dev_release,
3983703f53bSSrinivas Pandruvada };
3993703f53bSSrinivas Pandruvada
4003703f53bSSrinivas Pandruvada /**
4013703f53bSSrinivas Pandruvada * ishtp_bus_add_device() - Function to create device on bus
4023703f53bSSrinivas Pandruvada * @dev: ishtp device
4033703f53bSSrinivas Pandruvada * @uuid: uuid of the client
4043703f53bSSrinivas Pandruvada * @name: Name of the client
4053703f53bSSrinivas Pandruvada *
4063703f53bSSrinivas Pandruvada * Allocate ISHTP bus client device, attach it to uuid
4073703f53bSSrinivas Pandruvada * and register with ISHTP bus.
4083703f53bSSrinivas Pandruvada *
4093703f53bSSrinivas Pandruvada * Return: ishtp_cl_device pointer or NULL on failure
4103703f53bSSrinivas Pandruvada */
ishtp_bus_add_device(struct ishtp_device * dev,guid_t uuid,char * name)4113703f53bSSrinivas Pandruvada static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
41214106501SAndy Shevchenko guid_t uuid, char *name)
4133703f53bSSrinivas Pandruvada {
4143703f53bSSrinivas Pandruvada struct ishtp_cl_device *device;
4153703f53bSSrinivas Pandruvada int status;
4163703f53bSSrinivas Pandruvada unsigned long flags;
4173703f53bSSrinivas Pandruvada
4183703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->device_list_lock, flags);
419e8c61135SWei Yongjun list_for_each_entry(device, &dev->device_list, device_link) {
4203703f53bSSrinivas Pandruvada if (!strcmp(name, dev_name(&device->dev))) {
4213703f53bSSrinivas Pandruvada device->fw_client = &dev->fw_clients[
4223703f53bSSrinivas Pandruvada dev->fw_client_presentation_num - 1];
4233703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->device_list_lock, flags);
4243703f53bSSrinivas Pandruvada ishtp_cl_device_reset(device);
4253703f53bSSrinivas Pandruvada return device;
4263703f53bSSrinivas Pandruvada }
4273703f53bSSrinivas Pandruvada }
4283703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->device_list_lock, flags);
4293703f53bSSrinivas Pandruvada
4303703f53bSSrinivas Pandruvada device = kzalloc(sizeof(struct ishtp_cl_device), GFP_KERNEL);
4313703f53bSSrinivas Pandruvada if (!device)
4323703f53bSSrinivas Pandruvada return NULL;
4333703f53bSSrinivas Pandruvada
4343703f53bSSrinivas Pandruvada device->dev.parent = dev->devc;
4353703f53bSSrinivas Pandruvada device->dev.bus = &ishtp_cl_bus_type;
4363703f53bSSrinivas Pandruvada device->dev.type = &ishtp_cl_device_type;
4373703f53bSSrinivas Pandruvada device->ishtp_dev = dev;
4383703f53bSSrinivas Pandruvada
4393703f53bSSrinivas Pandruvada device->fw_client =
4403703f53bSSrinivas Pandruvada &dev->fw_clients[dev->fw_client_presentation_num - 1];
4413703f53bSSrinivas Pandruvada
4423703f53bSSrinivas Pandruvada dev_set_name(&device->dev, "%s", name);
4433703f53bSSrinivas Pandruvada
4443703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->device_list_lock, flags);
4453703f53bSSrinivas Pandruvada list_add_tail(&device->device_link, &dev->device_list);
4463703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->device_list_lock, flags);
4473703f53bSSrinivas Pandruvada
4483703f53bSSrinivas Pandruvada status = device_register(&device->dev);
4493703f53bSSrinivas Pandruvada if (status) {
4503703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->device_list_lock, flags);
4513703f53bSSrinivas Pandruvada list_del(&device->device_link);
4523703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->device_list_lock, flags);
4533703f53bSSrinivas Pandruvada dev_err(dev->devc, "Failed to register ISHTP client device\n");
454a4eb490aSArvind Yadav put_device(&device->dev);
4553703f53bSSrinivas Pandruvada return NULL;
4563703f53bSSrinivas Pandruvada }
4573703f53bSSrinivas Pandruvada
4583703f53bSSrinivas Pandruvada ishtp_device_ready = true;
4593703f53bSSrinivas Pandruvada
4603703f53bSSrinivas Pandruvada return device;
4613703f53bSSrinivas Pandruvada }
4623703f53bSSrinivas Pandruvada
4633703f53bSSrinivas Pandruvada /**
4643703f53bSSrinivas Pandruvada * ishtp_bus_remove_device() - Function to relase device on bus
4653703f53bSSrinivas Pandruvada * @device: client device instance
4663703f53bSSrinivas Pandruvada *
4673703f53bSSrinivas Pandruvada * This is a counterpart of ishtp_bus_add_device.
4683703f53bSSrinivas Pandruvada * Device is unregistered.
4693703f53bSSrinivas Pandruvada * the device structure is freed in 'ishtp_cl_dev_release' function
4703703f53bSSrinivas Pandruvada * Called only during error in pci driver init path.
4713703f53bSSrinivas Pandruvada */
ishtp_bus_remove_device(struct ishtp_cl_device * device)4723703f53bSSrinivas Pandruvada static void ishtp_bus_remove_device(struct ishtp_cl_device *device)
4733703f53bSSrinivas Pandruvada {
4743703f53bSSrinivas Pandruvada device_unregister(&device->dev);
4753703f53bSSrinivas Pandruvada }
4763703f53bSSrinivas Pandruvada
4773703f53bSSrinivas Pandruvada /**
478e00a864fSSrinivas Pandruvada * ishtp_cl_driver_register() - Client driver register
4793703f53bSSrinivas Pandruvada * @driver: the client driver instance
4803703f53bSSrinivas Pandruvada * @owner: Owner of this driver module
4813703f53bSSrinivas Pandruvada *
4823703f53bSSrinivas Pandruvada * Once a client driver is probed, it created a client
4833703f53bSSrinivas Pandruvada * instance and registers with the bus.
4843703f53bSSrinivas Pandruvada *
4853703f53bSSrinivas Pandruvada * Return: Return value of driver_register or -ENODEV if not ready
4863703f53bSSrinivas Pandruvada */
ishtp_cl_driver_register(struct ishtp_cl_driver * driver,struct module * owner)487e00a864fSSrinivas Pandruvada int ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
4883703f53bSSrinivas Pandruvada struct module *owner)
4893703f53bSSrinivas Pandruvada {
4903703f53bSSrinivas Pandruvada if (!ishtp_device_ready)
4913703f53bSSrinivas Pandruvada return -ENODEV;
4923703f53bSSrinivas Pandruvada
4933703f53bSSrinivas Pandruvada driver->driver.name = driver->name;
4943703f53bSSrinivas Pandruvada driver->driver.owner = owner;
4953703f53bSSrinivas Pandruvada driver->driver.bus = &ishtp_cl_bus_type;
4963703f53bSSrinivas Pandruvada
49736725cb0SQinglang Miao return driver_register(&driver->driver);
4983703f53bSSrinivas Pandruvada }
499e00a864fSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_driver_register);
5003703f53bSSrinivas Pandruvada
5013703f53bSSrinivas Pandruvada /**
5023703f53bSSrinivas Pandruvada * ishtp_cl_driver_unregister() - Client driver unregister
5033703f53bSSrinivas Pandruvada * @driver: the client driver instance
5043703f53bSSrinivas Pandruvada *
5053703f53bSSrinivas Pandruvada * Unregister client during device removal process.
5063703f53bSSrinivas Pandruvada */
ishtp_cl_driver_unregister(struct ishtp_cl_driver * driver)5073703f53bSSrinivas Pandruvada void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver)
5083703f53bSSrinivas Pandruvada {
5093703f53bSSrinivas Pandruvada driver_unregister(&driver->driver);
5103703f53bSSrinivas Pandruvada }
5113703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_cl_driver_unregister);
5123703f53bSSrinivas Pandruvada
5133703f53bSSrinivas Pandruvada /**
5143703f53bSSrinivas Pandruvada * ishtp_bus_event_work() - event work function
5153703f53bSSrinivas Pandruvada * @work: work struct pointer
5163703f53bSSrinivas Pandruvada *
5173703f53bSSrinivas Pandruvada * Once an event is received for a client this work
5183703f53bSSrinivas Pandruvada * function is called. If the device has registered a
5193703f53bSSrinivas Pandruvada * callback then the callback is called.
5203703f53bSSrinivas Pandruvada */
ishtp_bus_event_work(struct work_struct * work)5213703f53bSSrinivas Pandruvada static void ishtp_bus_event_work(struct work_struct *work)
5223703f53bSSrinivas Pandruvada {
5233703f53bSSrinivas Pandruvada struct ishtp_cl_device *device;
5243703f53bSSrinivas Pandruvada
5253703f53bSSrinivas Pandruvada device = container_of(work, struct ishtp_cl_device, event_work);
5263703f53bSSrinivas Pandruvada
5273703f53bSSrinivas Pandruvada if (device->event_cb)
5283703f53bSSrinivas Pandruvada device->event_cb(device);
5293703f53bSSrinivas Pandruvada }
5303703f53bSSrinivas Pandruvada
5313703f53bSSrinivas Pandruvada /**
5323703f53bSSrinivas Pandruvada * ishtp_cl_bus_rx_event() - schedule event work
5333703f53bSSrinivas Pandruvada * @device: client device instance
5343703f53bSSrinivas Pandruvada *
5353703f53bSSrinivas Pandruvada * Once an event is received for a client this schedules
5363703f53bSSrinivas Pandruvada * a work function to process.
5373703f53bSSrinivas Pandruvada */
ishtp_cl_bus_rx_event(struct ishtp_cl_device * device)5383703f53bSSrinivas Pandruvada void ishtp_cl_bus_rx_event(struct ishtp_cl_device *device)
5393703f53bSSrinivas Pandruvada {
5403703f53bSSrinivas Pandruvada if (!device || !device->event_cb)
5413703f53bSSrinivas Pandruvada return;
5423703f53bSSrinivas Pandruvada
5433703f53bSSrinivas Pandruvada if (device->event_cb)
5443703f53bSSrinivas Pandruvada schedule_work(&device->event_work);
5453703f53bSSrinivas Pandruvada }
5463703f53bSSrinivas Pandruvada
5473703f53bSSrinivas Pandruvada /**
5483703f53bSSrinivas Pandruvada * ishtp_register_event_cb() - Register callback
5493703f53bSSrinivas Pandruvada * @device: client device instance
5503703f53bSSrinivas Pandruvada * @event_cb: Event processor for an client
5513703f53bSSrinivas Pandruvada *
5523703f53bSSrinivas Pandruvada * Register a callback for events, called from client driver
5533703f53bSSrinivas Pandruvada *
5543703f53bSSrinivas Pandruvada * Return: Return 0 or -EALREADY if already registered
5553703f53bSSrinivas Pandruvada */
ishtp_register_event_cb(struct ishtp_cl_device * device,void (* event_cb)(struct ishtp_cl_device *))5563703f53bSSrinivas Pandruvada int ishtp_register_event_cb(struct ishtp_cl_device *device,
5573703f53bSSrinivas Pandruvada void (*event_cb)(struct ishtp_cl_device *))
5583703f53bSSrinivas Pandruvada {
5593703f53bSSrinivas Pandruvada if (device->event_cb)
5603703f53bSSrinivas Pandruvada return -EALREADY;
5613703f53bSSrinivas Pandruvada
5623703f53bSSrinivas Pandruvada device->event_cb = event_cb;
5633703f53bSSrinivas Pandruvada INIT_WORK(&device->event_work, ishtp_bus_event_work);
5643703f53bSSrinivas Pandruvada
5653703f53bSSrinivas Pandruvada return 0;
5663703f53bSSrinivas Pandruvada }
5673703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_register_event_cb);
5683703f53bSSrinivas Pandruvada
5693703f53bSSrinivas Pandruvada /**
5703703f53bSSrinivas Pandruvada * ishtp_get_device() - update usage count for the device
5713703f53bSSrinivas Pandruvada * @cl_device: client device instance
5723703f53bSSrinivas Pandruvada *
5733703f53bSSrinivas Pandruvada * Increment the usage count. The device can't be deleted
5743703f53bSSrinivas Pandruvada */
ishtp_get_device(struct ishtp_cl_device * cl_device)5753703f53bSSrinivas Pandruvada void ishtp_get_device(struct ishtp_cl_device *cl_device)
5763703f53bSSrinivas Pandruvada {
5773703f53bSSrinivas Pandruvada cl_device->reference_count++;
5783703f53bSSrinivas Pandruvada }
5793703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_get_device);
5803703f53bSSrinivas Pandruvada
5813703f53bSSrinivas Pandruvada /**
5823703f53bSSrinivas Pandruvada * ishtp_put_device() - decrement usage count for the device
5833703f53bSSrinivas Pandruvada * @cl_device: client device instance
5843703f53bSSrinivas Pandruvada *
5853703f53bSSrinivas Pandruvada * Decrement the usage count. The device can be deleted is count = 0
5863703f53bSSrinivas Pandruvada */
ishtp_put_device(struct ishtp_cl_device * cl_device)5873703f53bSSrinivas Pandruvada void ishtp_put_device(struct ishtp_cl_device *cl_device)
5883703f53bSSrinivas Pandruvada {
5893703f53bSSrinivas Pandruvada cl_device->reference_count--;
5903703f53bSSrinivas Pandruvada }
5913703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_put_device);
5923703f53bSSrinivas Pandruvada
5933703f53bSSrinivas Pandruvada /**
594d0b41230SEven Xu * ishtp_set_drvdata() - set client driver data
595d0b41230SEven Xu * @cl_device: client device instance
596d0b41230SEven Xu * @data: driver data need to be set
597d0b41230SEven Xu *
598d0b41230SEven Xu * Set client driver data to cl_device->driver_data.
599d0b41230SEven Xu */
ishtp_set_drvdata(struct ishtp_cl_device * cl_device,void * data)600d0b41230SEven Xu void ishtp_set_drvdata(struct ishtp_cl_device *cl_device, void *data)
601d0b41230SEven Xu {
602d0b41230SEven Xu cl_device->driver_data = data;
603d0b41230SEven Xu }
604d0b41230SEven Xu EXPORT_SYMBOL(ishtp_set_drvdata);
605d0b41230SEven Xu
606d0b41230SEven Xu /**
607d0b41230SEven Xu * ishtp_get_drvdata() - get client driver data
608d0b41230SEven Xu * @cl_device: client device instance
609d0b41230SEven Xu *
610d0b41230SEven Xu * Get client driver data from cl_device->driver_data.
611d0b41230SEven Xu *
612d0b41230SEven Xu * Return: pointer of driver data
613d0b41230SEven Xu */
ishtp_get_drvdata(struct ishtp_cl_device * cl_device)614d0b41230SEven Xu void *ishtp_get_drvdata(struct ishtp_cl_device *cl_device)
615d0b41230SEven Xu {
616d0b41230SEven Xu return cl_device->driver_data;
617d0b41230SEven Xu }
618d0b41230SEven Xu EXPORT_SYMBOL(ishtp_get_drvdata);
619d0b41230SEven Xu
620d0b41230SEven Xu /**
621b12bbdc5SHyungwoo Yang * ishtp_dev_to_cl_device() - get ishtp_cl_device instance from device instance
622b12bbdc5SHyungwoo Yang * @device: device instance
623b12bbdc5SHyungwoo Yang *
624b12bbdc5SHyungwoo Yang * Get ish_cl_device instance which embeds device instance in it.
625b12bbdc5SHyungwoo Yang *
626b12bbdc5SHyungwoo Yang * Return: pointer to ishtp_cl_device instance
627b12bbdc5SHyungwoo Yang */
ishtp_dev_to_cl_device(struct device * device)628b12bbdc5SHyungwoo Yang struct ishtp_cl_device *ishtp_dev_to_cl_device(struct device *device)
629b12bbdc5SHyungwoo Yang {
630b12bbdc5SHyungwoo Yang return to_ishtp_cl_device(device);
631b12bbdc5SHyungwoo Yang }
632b12bbdc5SHyungwoo Yang EXPORT_SYMBOL(ishtp_dev_to_cl_device);
633b12bbdc5SHyungwoo Yang
634b12bbdc5SHyungwoo Yang /**
6353703f53bSSrinivas Pandruvada * ishtp_bus_new_client() - Create a new client
6363703f53bSSrinivas Pandruvada * @dev: ISHTP device instance
6373703f53bSSrinivas Pandruvada *
6383703f53bSSrinivas Pandruvada * Once bus protocol enumerates a client, this is called
6393703f53bSSrinivas Pandruvada * to add a device for the client.
6403703f53bSSrinivas Pandruvada *
6413703f53bSSrinivas Pandruvada * Return: 0 on success or error code on failure
6423703f53bSSrinivas Pandruvada */
ishtp_bus_new_client(struct ishtp_device * dev)6433703f53bSSrinivas Pandruvada int ishtp_bus_new_client(struct ishtp_device *dev)
6443703f53bSSrinivas Pandruvada {
6453703f53bSSrinivas Pandruvada int i;
6463703f53bSSrinivas Pandruvada char *dev_name;
6473703f53bSSrinivas Pandruvada struct ishtp_cl_device *cl_device;
64814106501SAndy Shevchenko guid_t device_uuid;
6493703f53bSSrinivas Pandruvada
6503703f53bSSrinivas Pandruvada /*
6513703f53bSSrinivas Pandruvada * For all reported clients, create an unconnected client and add its
6523703f53bSSrinivas Pandruvada * device to ISHTP bus.
6533703f53bSSrinivas Pandruvada * If appropriate driver has loaded, this will trigger its probe().
6543703f53bSSrinivas Pandruvada * Otherwise, probe() will be called when driver is loaded
6553703f53bSSrinivas Pandruvada */
6563703f53bSSrinivas Pandruvada i = dev->fw_client_presentation_num - 1;
6573703f53bSSrinivas Pandruvada device_uuid = dev->fw_clients[i].props.protocol_name;
65814106501SAndy Shevchenko dev_name = kasprintf(GFP_KERNEL, "{%pUL}", &device_uuid);
6593703f53bSSrinivas Pandruvada if (!dev_name)
6603703f53bSSrinivas Pandruvada return -ENOMEM;
6613703f53bSSrinivas Pandruvada
6623703f53bSSrinivas Pandruvada cl_device = ishtp_bus_add_device(dev, device_uuid, dev_name);
6633703f53bSSrinivas Pandruvada if (!cl_device) {
6643703f53bSSrinivas Pandruvada kfree(dev_name);
6653703f53bSSrinivas Pandruvada return -ENOENT;
6663703f53bSSrinivas Pandruvada }
6673703f53bSSrinivas Pandruvada
6683703f53bSSrinivas Pandruvada kfree(dev_name);
6693703f53bSSrinivas Pandruvada
6703703f53bSSrinivas Pandruvada return 0;
6713703f53bSSrinivas Pandruvada }
6723703f53bSSrinivas Pandruvada
6733703f53bSSrinivas Pandruvada /**
6743703f53bSSrinivas Pandruvada * ishtp_cl_device_bind() - bind a device
6753703f53bSSrinivas Pandruvada * @cl: ishtp client device
6763703f53bSSrinivas Pandruvada *
6773703f53bSSrinivas Pandruvada * Binds connected ishtp_cl to ISHTP bus device
6783703f53bSSrinivas Pandruvada *
6793703f53bSSrinivas Pandruvada * Return: 0 on success or fault code
6803703f53bSSrinivas Pandruvada */
ishtp_cl_device_bind(struct ishtp_cl * cl)6813703f53bSSrinivas Pandruvada int ishtp_cl_device_bind(struct ishtp_cl *cl)
6823703f53bSSrinivas Pandruvada {
6833703f53bSSrinivas Pandruvada struct ishtp_cl_device *cl_device;
6843703f53bSSrinivas Pandruvada unsigned long flags;
6853703f53bSSrinivas Pandruvada int rv;
6863703f53bSSrinivas Pandruvada
6873703f53bSSrinivas Pandruvada if (!cl->fw_client_id || cl->state != ISHTP_CL_CONNECTED)
6883703f53bSSrinivas Pandruvada return -EFAULT;
6893703f53bSSrinivas Pandruvada
6903703f53bSSrinivas Pandruvada rv = -ENOENT;
6913703f53bSSrinivas Pandruvada spin_lock_irqsave(&cl->dev->device_list_lock, flags);
6923703f53bSSrinivas Pandruvada list_for_each_entry(cl_device, &cl->dev->device_list,
6933703f53bSSrinivas Pandruvada device_link) {
6940d28f494SHong Liu if (cl_device->fw_client &&
6950d28f494SHong Liu cl_device->fw_client->client_id == cl->fw_client_id) {
6963703f53bSSrinivas Pandruvada cl->device = cl_device;
6973703f53bSSrinivas Pandruvada rv = 0;
6983703f53bSSrinivas Pandruvada break;
6993703f53bSSrinivas Pandruvada }
7003703f53bSSrinivas Pandruvada }
7013703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&cl->dev->device_list_lock, flags);
7023703f53bSSrinivas Pandruvada return rv;
7033703f53bSSrinivas Pandruvada }
7043703f53bSSrinivas Pandruvada
7053703f53bSSrinivas Pandruvada /**
7063703f53bSSrinivas Pandruvada * ishtp_bus_remove_all_clients() - Remove all clients
7073703f53bSSrinivas Pandruvada * @ishtp_dev: ishtp device
7083703f53bSSrinivas Pandruvada * @warm_reset: Reset due to FW reset dure to errors or S3 suspend
7093703f53bSSrinivas Pandruvada *
7103703f53bSSrinivas Pandruvada * This is part of reset/remove flow. This function the main processing
7113703f53bSSrinivas Pandruvada * only targets error processing, if the FW has forced reset or
7123703f53bSSrinivas Pandruvada * error to remove connected clients. When warm reset the client devices are
7133703f53bSSrinivas Pandruvada * not removed.
7143703f53bSSrinivas Pandruvada */
ishtp_bus_remove_all_clients(struct ishtp_device * ishtp_dev,bool warm_reset)7153703f53bSSrinivas Pandruvada void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,
7163703f53bSSrinivas Pandruvada bool warm_reset)
7173703f53bSSrinivas Pandruvada {
7183703f53bSSrinivas Pandruvada struct ishtp_cl_device *cl_device, *n;
7193703f53bSSrinivas Pandruvada struct ishtp_cl *cl;
7203703f53bSSrinivas Pandruvada unsigned long flags;
7213703f53bSSrinivas Pandruvada
7223703f53bSSrinivas Pandruvada spin_lock_irqsave(&ishtp_dev->cl_list_lock, flags);
7233703f53bSSrinivas Pandruvada list_for_each_entry(cl, &ishtp_dev->cl_list, link) {
7243703f53bSSrinivas Pandruvada cl->state = ISHTP_CL_DISCONNECTED;
7253703f53bSSrinivas Pandruvada
7263703f53bSSrinivas Pandruvada /*
7273703f53bSSrinivas Pandruvada * Wake any pending process. The waiter would check dev->state
7283703f53bSSrinivas Pandruvada * and determine that it's not enabled already,
7293703f53bSSrinivas Pandruvada * and will return error to its caller
7303703f53bSSrinivas Pandruvada */
7313703f53bSSrinivas Pandruvada wake_up_interruptible(&cl->wait_ctrl_res);
7323703f53bSSrinivas Pandruvada
7333703f53bSSrinivas Pandruvada /* Disband any pending read/write requests and free rb */
7343703f53bSSrinivas Pandruvada ishtp_cl_flush_queues(cl);
7353703f53bSSrinivas Pandruvada
7363703f53bSSrinivas Pandruvada /* Remove all free and in_process rings, both Rx and Tx */
7373703f53bSSrinivas Pandruvada ishtp_cl_free_rx_ring(cl);
7383703f53bSSrinivas Pandruvada ishtp_cl_free_tx_ring(cl);
7393703f53bSSrinivas Pandruvada
7403703f53bSSrinivas Pandruvada /*
7413703f53bSSrinivas Pandruvada * Free client and ISHTP bus client device structures
7423703f53bSSrinivas Pandruvada * don't free host client because it is part of the OS fd
7433703f53bSSrinivas Pandruvada * structure
7443703f53bSSrinivas Pandruvada */
7453703f53bSSrinivas Pandruvada }
7463703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&ishtp_dev->cl_list_lock, flags);
7473703f53bSSrinivas Pandruvada
7483703f53bSSrinivas Pandruvada /* Release DMA buffers for client messages */
7493703f53bSSrinivas Pandruvada ishtp_cl_free_dma_buf(ishtp_dev);
7503703f53bSSrinivas Pandruvada
7513703f53bSSrinivas Pandruvada /* remove bus clients */
7523703f53bSSrinivas Pandruvada spin_lock_irqsave(&ishtp_dev->device_list_lock, flags);
7533703f53bSSrinivas Pandruvada list_for_each_entry_safe(cl_device, n, &ishtp_dev->device_list,
7543703f53bSSrinivas Pandruvada device_link) {
7550d28f494SHong Liu cl_device->fw_client = NULL;
7563703f53bSSrinivas Pandruvada if (warm_reset && cl_device->reference_count)
7573703f53bSSrinivas Pandruvada continue;
7583703f53bSSrinivas Pandruvada
7593703f53bSSrinivas Pandruvada list_del(&cl_device->device_link);
7603703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&ishtp_dev->device_list_lock, flags);
7613703f53bSSrinivas Pandruvada ishtp_bus_remove_device(cl_device);
7623703f53bSSrinivas Pandruvada spin_lock_irqsave(&ishtp_dev->device_list_lock, flags);
7633703f53bSSrinivas Pandruvada }
7643703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&ishtp_dev->device_list_lock, flags);
7653703f53bSSrinivas Pandruvada
7663703f53bSSrinivas Pandruvada /* Free all client structures */
7673703f53bSSrinivas Pandruvada spin_lock_irqsave(&ishtp_dev->fw_clients_lock, flags);
7683703f53bSSrinivas Pandruvada kfree(ishtp_dev->fw_clients);
7693703f53bSSrinivas Pandruvada ishtp_dev->fw_clients = NULL;
7703703f53bSSrinivas Pandruvada ishtp_dev->fw_clients_num = 0;
7713703f53bSSrinivas Pandruvada ishtp_dev->fw_client_presentation_num = 0;
7723703f53bSSrinivas Pandruvada ishtp_dev->fw_client_index = 0;
7733703f53bSSrinivas Pandruvada bitmap_zero(ishtp_dev->fw_clients_map, ISHTP_CLIENTS_MAX);
7743703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&ishtp_dev->fw_clients_lock, flags);
7753703f53bSSrinivas Pandruvada }
7763703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_bus_remove_all_clients);
7773703f53bSSrinivas Pandruvada
7783703f53bSSrinivas Pandruvada /**
7793703f53bSSrinivas Pandruvada * ishtp_reset_handler() - IPC reset handler
7803703f53bSSrinivas Pandruvada * @dev: ishtp device
7813703f53bSSrinivas Pandruvada *
7823703f53bSSrinivas Pandruvada * ISHTP Handler for IPC_RESET notification
7833703f53bSSrinivas Pandruvada */
ishtp_reset_handler(struct ishtp_device * dev)7843703f53bSSrinivas Pandruvada void ishtp_reset_handler(struct ishtp_device *dev)
7853703f53bSSrinivas Pandruvada {
7863703f53bSSrinivas Pandruvada unsigned long flags;
7873703f53bSSrinivas Pandruvada
7883703f53bSSrinivas Pandruvada /* Handle FW-initiated reset */
7893703f53bSSrinivas Pandruvada dev->dev_state = ISHTP_DEV_RESETTING;
7903703f53bSSrinivas Pandruvada
7913703f53bSSrinivas Pandruvada /* Clear BH processing queue - no further HBMs */
7923703f53bSSrinivas Pandruvada spin_lock_irqsave(&dev->rd_msg_spinlock, flags);
7933703f53bSSrinivas Pandruvada dev->rd_msg_fifo_head = dev->rd_msg_fifo_tail = 0;
7943703f53bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->rd_msg_spinlock, flags);
7953703f53bSSrinivas Pandruvada
7963703f53bSSrinivas Pandruvada /* Handle ISH FW reset against upper layers */
7973703f53bSSrinivas Pandruvada ishtp_bus_remove_all_clients(dev, true);
7983703f53bSSrinivas Pandruvada }
7993703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_reset_handler);
8003703f53bSSrinivas Pandruvada
8013703f53bSSrinivas Pandruvada /**
8023703f53bSSrinivas Pandruvada * ishtp_reset_compl_handler() - Reset completion handler
8033703f53bSSrinivas Pandruvada * @dev: ishtp device
8043703f53bSSrinivas Pandruvada *
8053703f53bSSrinivas Pandruvada * ISHTP handler for IPC_RESET sequence completion to start
8063703f53bSSrinivas Pandruvada * host message bus start protocol sequence.
8073703f53bSSrinivas Pandruvada */
ishtp_reset_compl_handler(struct ishtp_device * dev)8083703f53bSSrinivas Pandruvada void ishtp_reset_compl_handler(struct ishtp_device *dev)
8093703f53bSSrinivas Pandruvada {
8103703f53bSSrinivas Pandruvada dev->dev_state = ISHTP_DEV_INIT_CLIENTS;
8113703f53bSSrinivas Pandruvada dev->hbm_state = ISHTP_HBM_START;
8123703f53bSSrinivas Pandruvada ishtp_hbm_start_req(dev);
8133703f53bSSrinivas Pandruvada }
8143703f53bSSrinivas Pandruvada EXPORT_SYMBOL(ishtp_reset_compl_handler);
8153703f53bSSrinivas Pandruvada
8163703f53bSSrinivas Pandruvada /**
8173703f53bSSrinivas Pandruvada * ishtp_use_dma_transfer() - Function to use DMA
8183703f53bSSrinivas Pandruvada *
8193703f53bSSrinivas Pandruvada * This interface is used to enable usage of DMA
8203703f53bSSrinivas Pandruvada *
8213703f53bSSrinivas Pandruvada * Return non zero if DMA can be enabled
8223703f53bSSrinivas Pandruvada */
ishtp_use_dma_transfer(void)8233703f53bSSrinivas Pandruvada int ishtp_use_dma_transfer(void)
8243703f53bSSrinivas Pandruvada {
8253703f53bSSrinivas Pandruvada return ishtp_use_dma;
8263703f53bSSrinivas Pandruvada }
8273703f53bSSrinivas Pandruvada
8283703f53bSSrinivas Pandruvada /**
8297ab21842SSrinivas Pandruvada * ishtp_device() - Return device pointer
830d5831beeSLee Jones * @device: ISH-TP client device instance
8317ab21842SSrinivas Pandruvada *
8327ab21842SSrinivas Pandruvada * This interface is used to return device pointer from ishtp_cl_device
8337ab21842SSrinivas Pandruvada * instance.
8347ab21842SSrinivas Pandruvada *
8357ab21842SSrinivas Pandruvada * Return: device *.
8367ab21842SSrinivas Pandruvada */
ishtp_device(struct ishtp_cl_device * device)8377ab21842SSrinivas Pandruvada struct device *ishtp_device(struct ishtp_cl_device *device)
8387ab21842SSrinivas Pandruvada {
8397ab21842SSrinivas Pandruvada return &device->dev;
8407ab21842SSrinivas Pandruvada }
8417ab21842SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_device);
8427ab21842SSrinivas Pandruvada
8437ab21842SSrinivas Pandruvada /**
844e48bf29cSYe Xiang * ishtp_wait_resume() - Wait for IPC resume
845e48bf29cSYe Xiang *
846e48bf29cSYe Xiang * Wait for IPC resume
847e48bf29cSYe Xiang *
848e48bf29cSYe Xiang * Return: resume complete or not
849e48bf29cSYe Xiang */
ishtp_wait_resume(struct ishtp_device * dev)850e48bf29cSYe Xiang bool ishtp_wait_resume(struct ishtp_device *dev)
851e48bf29cSYe Xiang {
852e48bf29cSYe Xiang /* 50ms to get resume response */
853e48bf29cSYe Xiang #define WAIT_FOR_RESUME_ACK_MS 50
854e48bf29cSYe Xiang
855e48bf29cSYe Xiang /* Waiting to get resume response */
856e48bf29cSYe Xiang if (dev->resume_flag)
857e48bf29cSYe Xiang wait_event_interruptible_timeout(dev->resume_wait,
858e48bf29cSYe Xiang !dev->resume_flag,
859e48bf29cSYe Xiang msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
860e48bf29cSYe Xiang
861e48bf29cSYe Xiang return (!dev->resume_flag);
862e48bf29cSYe Xiang }
863e48bf29cSYe Xiang EXPORT_SYMBOL_GPL(ishtp_wait_resume);
864e48bf29cSYe Xiang
865e48bf29cSYe Xiang /**
8660e568a16SSrinivas Pandruvada * ishtp_get_pci_device() - Return PCI device dev pointer
8670e568a16SSrinivas Pandruvada * This interface is used to return PCI device pointer
8680e568a16SSrinivas Pandruvada * from ishtp_cl_device instance.
869d5831beeSLee Jones * @device: ISH-TP client device instance
8700e568a16SSrinivas Pandruvada *
8710e568a16SSrinivas Pandruvada * Return: device *.
8720e568a16SSrinivas Pandruvada */
ishtp_get_pci_device(struct ishtp_cl_device * device)8730e568a16SSrinivas Pandruvada struct device *ishtp_get_pci_device(struct ishtp_cl_device *device)
8740e568a16SSrinivas Pandruvada {
8750e568a16SSrinivas Pandruvada return device->ishtp_dev->devc;
8760e568a16SSrinivas Pandruvada }
8770e568a16SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_get_pci_device);
8780e568a16SSrinivas Pandruvada
8790e568a16SSrinivas Pandruvada /**
8807ab21842SSrinivas Pandruvada * ishtp_trace_callback() - Return trace callback
881d5831beeSLee Jones * @cl_device: ISH-TP client device instance
8827ab21842SSrinivas Pandruvada *
8837ab21842SSrinivas Pandruvada * This interface is used to return trace callback function pointer.
8847ab21842SSrinivas Pandruvada *
885c57179c7SLee Jones * Return: *ishtp_print_log()
8867ab21842SSrinivas Pandruvada */
ishtp_trace_callback(struct ishtp_cl_device * cl_device)887c57179c7SLee Jones ishtp_print_log ishtp_trace_callback(struct ishtp_cl_device *cl_device)
8887ab21842SSrinivas Pandruvada {
8897ab21842SSrinivas Pandruvada return cl_device->ishtp_dev->print_log;
8907ab21842SSrinivas Pandruvada }
8917ab21842SSrinivas Pandruvada EXPORT_SYMBOL(ishtp_trace_callback);
8927ab21842SSrinivas Pandruvada
8937ab21842SSrinivas Pandruvada /**
8945f7224cfSSrinivas Pandruvada * ish_hw_reset() - Call HW reset IPC callback
895d5831beeSLee Jones * @dev: ISHTP device instance
8965f7224cfSSrinivas Pandruvada *
8975f7224cfSSrinivas Pandruvada * This interface is used to reset HW in case of error.
8985f7224cfSSrinivas Pandruvada *
8995f7224cfSSrinivas Pandruvada * Return: value from IPC hw_reset callback
9005f7224cfSSrinivas Pandruvada */
ish_hw_reset(struct ishtp_device * dev)9015f7224cfSSrinivas Pandruvada int ish_hw_reset(struct ishtp_device *dev)
9025f7224cfSSrinivas Pandruvada {
9035f7224cfSSrinivas Pandruvada return dev->ops->hw_reset(dev);
9045f7224cfSSrinivas Pandruvada }
9055f7224cfSSrinivas Pandruvada EXPORT_SYMBOL(ish_hw_reset);
9065f7224cfSSrinivas Pandruvada
9075f7224cfSSrinivas Pandruvada /**
9083703f53bSSrinivas Pandruvada * ishtp_bus_register() - Function to register bus
9093703f53bSSrinivas Pandruvada *
9103703f53bSSrinivas Pandruvada * This register ishtp bus
9113703f53bSSrinivas Pandruvada *
9123703f53bSSrinivas Pandruvada * Return: Return output of bus_register
9133703f53bSSrinivas Pandruvada */
ishtp_bus_register(void)9143703f53bSSrinivas Pandruvada static int __init ishtp_bus_register(void)
9153703f53bSSrinivas Pandruvada {
9163703f53bSSrinivas Pandruvada return bus_register(&ishtp_cl_bus_type);
9173703f53bSSrinivas Pandruvada }
9183703f53bSSrinivas Pandruvada
9193703f53bSSrinivas Pandruvada /**
9203703f53bSSrinivas Pandruvada * ishtp_bus_unregister() - Function to unregister bus
9213703f53bSSrinivas Pandruvada *
9223703f53bSSrinivas Pandruvada * This unregister ishtp bus
9233703f53bSSrinivas Pandruvada */
ishtp_bus_unregister(void)9243703f53bSSrinivas Pandruvada static void __exit ishtp_bus_unregister(void)
9253703f53bSSrinivas Pandruvada {
9263703f53bSSrinivas Pandruvada bus_unregister(&ishtp_cl_bus_type);
9273703f53bSSrinivas Pandruvada }
9283703f53bSSrinivas Pandruvada
9293703f53bSSrinivas Pandruvada module_init(ishtp_bus_register);
9303703f53bSSrinivas Pandruvada module_exit(ishtp_bus_unregister);
9313703f53bSSrinivas Pandruvada
9323703f53bSSrinivas Pandruvada MODULE_LICENSE("GPL");
933