client.c revision a8605ea2c20c2b97a54d7746c16ebef5ba29632a
19ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/*
29ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
39ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * Intel Management Engine Interface (Intel MEI) Linux driver
49ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * Copyright (c) 2003-2012, Intel Corporation.
59ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
69ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * This program is free software; you can redistribute it and/or modify it
79ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * under the terms and conditions of the GNU General Public License,
89ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * version 2, as published by the Free Software Foundation.
99ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * This program is distributed in the hope it will be useful, but WITHOUT
119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * more details.
149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/sched.h>
189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/wait.h>
199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/delay.h>
201f180359f42fc6fda4600175c63f2a84f444cc92Tomas Winkler#include <linux/slab.h>
2104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler#include <linux/pm_runtime.h>
229ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
239ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include <linux/mei.h>
249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
259ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include "mei_dev.h"
269ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler#include "hbm.h"
2790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler#include "client.h"
2890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
2990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler/**
30a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * mei_me_cl_by_uuid - locate me client by uuid
3190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
3290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @dev: mei device
33a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @uuid: me client uuid
34a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin *
35a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin * Locking: called under "dev->device_lock" lock
36a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin *
37a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: me client or NULL if not found
3890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler */
39d320832f64666089a06778782e42fac29abd7bf7Tomas Winklerstruct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
40d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler					const uuid_le *uuid)
4190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler{
425ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	struct mei_me_client *me_cl;
4390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
445ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	list_for_each_entry(me_cl, &dev->me_clients, list)
455ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
465ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler			return me_cl;
4790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
48d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	return NULL;
4990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler}
5090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
5190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler/**
52a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * mei_me_cl_by_id - locate me client by client id
5390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
5490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @dev: the device structure
5590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @client_id: me client id
5690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
5790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * Locking: called under "dev->device_lock" lock
5890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
59a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: me client or NULL if not found
6090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler */
61d320832f64666089a06778782e42fac29abd7bf7Tomas Winklerstruct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
6290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler{
63a27a76d3c07de08a0d0d298b6bc280c5b820e997Alexander Usyskin
645ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	struct mei_me_client *me_cl;
6590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
665ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	list_for_each_entry(me_cl, &dev->me_clients, list)
675ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		if (me_cl->client_id == client_id)
685ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler			return me_cl;
69d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	return NULL;
7090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler}
719ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
72a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin/**
73a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * mei_me_cl_by_uuid_id - locate me client by client id and uuid
74a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *
75a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @dev: the device structure
76a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @uuid: me client uuid
77a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @client_id: me client id
78a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *
79a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Locking: called under "dev->device_lock" lock
80a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *
81a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: me client or NULL if not found
82a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin */
83d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winklerstruct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
84d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler					   const uuid_le *uuid, u8 client_id)
85d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler{
86d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler	struct mei_me_client *me_cl;
87d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler
88d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler	list_for_each_entry(me_cl, &dev->me_clients, list)
89d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
90d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler		    me_cl->client_id == client_id)
91d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler			return me_cl;
92d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler	return NULL;
93d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler}
94d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler
9525ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler/**
9625ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler * mei_me_cl_remove - remove me client matching uuid and client_id
9725ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler *
9825ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler * @dev: the device structure
9925ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler * @uuid: me client uuid
10025ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler * @client_id: me client address
10125ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler */
10225ca6472b590e87efba314892a76bd5629c8c989Tomas Winklervoid mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id)
10325ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler{
10425ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler	struct mei_me_client *me_cl, *next;
10525ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler
10625ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler	list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
10725ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler		if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
10825ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler		    me_cl->client_id == client_id) {
10925ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler			list_del(&me_cl->list);
11025ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler			kfree(me_cl);
11125ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler			break;
11225ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler		}
11325ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler	}
11425ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler}
11525ca6472b590e87efba314892a76bd5629c8c989Tomas Winkler
1169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
1179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
118cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_cl_cmp_id - tells if the clients are the same
1199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
120cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl1: host client 1
121cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl2: host client 2
122cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *
123a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: true  - if the clients has same host and me ids
124cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *         false - otherwise
125cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler */
126cc99ecfdac01215594c73907726b12f251c21e20Tomas Winklerstatic inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
127cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler				const struct mei_cl *cl2)
128cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler{
129cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	return cl1 && cl2 &&
130cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler		(cl1->host_client_id == cl2->host_client_id) &&
131cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler		(cl1->me_client_id == cl2->me_client_id);
132cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler}
133cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler
134cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler/**
135cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_io_list_flush - removes cbs belonging to cl.
136cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *
137cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @list:  an instance of our list structure
138cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl:    host client, can be NULL for flushing the whole list
139cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @free:  whether to free the cbs
1409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
141cc99ecfdac01215594c73907726b12f251c21e20Tomas Winklerstatic void __mei_io_list_flush(struct mei_cl_cb *list,
142cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler				struct mei_cl *cl, bool free)
1439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
1449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *cb;
1459ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *next;
1469ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
147cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	/* enable removing everything if no cl is specified */
1489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	list_for_each_entry_safe(cb, next, &list->list, list) {
149cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler		if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
1509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			list_del(&cb->list);
151cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler			if (free)
152cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler				mei_io_cb_free(cb);
153cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler		}
1549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
1559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
1569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
1579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
158cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_io_list_flush - removes list entry belonging to cl.
159cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *
160cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @list:  An instance of our list structure
161cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl: host client
162cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler */
1635456796b1a2aedd2d6345944b73ac41aeb8cb589Alexander Usyskinvoid mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
164cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler{
165cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	__mei_io_list_flush(list, cl, false);
166cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler}
167cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler
168cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler
169cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler/**
170cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * mei_io_list_free - removes cb belonging to cl and free them
171cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler *
172cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @list:  An instance of our list structure
173cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler * @cl: host client
174cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler */
175cc99ecfdac01215594c73907726b12f251c21e20Tomas Winklerstatic inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
176cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler{
177cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	__mei_io_list_flush(list, cl, true);
178cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler}
179cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler
180cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler/**
1819ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_io_cb_free - free mei_cb_private related memory
1829ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
1839ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cb: mei callback struct
1849ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
1859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklervoid mei_io_cb_free(struct mei_cl_cb *cb)
1869ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
1879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (cb == NULL)
1889ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return;
1899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
1909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	kfree(cb->request_buffer.data);
1919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	kfree(cb->response_buffer.data);
1929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	kfree(cb);
1939ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
1949ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
1959ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
1969ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_io_cb_init - allocate and initialize io callback
1979ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
198a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @cl: mei client
199393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @fp: pointer to file structure
2009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
201a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: mei_cl_cb pointer or NULL;
2029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
2039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerstruct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
2049ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
2059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *cb;
2069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
2089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb)
2099ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return NULL;
2109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_init(cb);
2129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->file_object = fp;
2149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->cl = cl;
2159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->buf_idx = 0;
2169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return cb;
2179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
2189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
2209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_io_cb_alloc_req_buf - allocate request buffer
2219ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
222393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cb: io callback structure
223393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @length: size of the buffer
2249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
225a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success
2269ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *         -EINVAL if cb is NULL
2279ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *         -ENOMEM if allocation failed
2289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
2299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerint mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
2309ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
2319ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb)
2329ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EINVAL;
2339ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2349ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (length == 0)
2359ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return 0;
2369ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2379ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
2389ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb->request_buffer.data)
2399ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -ENOMEM;
2409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->request_buffer.size = length;
2419ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return 0;
2429ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
2439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
24483ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_io_cb_alloc_resp_buf - allocate response buffer
2459ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
246393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cb: io callback structure
247393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @length: size of the buffer
2489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
249a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success
2509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *         -EINVAL if cb is NULL
2519ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *         -ENOMEM if allocation failed
2529ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
2539ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerint mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
2549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
2559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb)
2569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EINVAL;
2579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (length == 0)
2599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return 0;
2609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->response_buffer.data = kmalloc(length, GFP_KERNEL);
2629ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cb->response_buffer.data)
2639ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -ENOMEM;
2649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->response_buffer.size = length;
2659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return 0;
2669ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
2679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2689ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2699ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2709ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
2719ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_cl_flush_queues - flushes queue lists belonging to cl.
2729ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
2739ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: host client
2749ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
2759ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerint mei_cl_flush_queues(struct mei_cl *cl)
2769ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
277c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	struct mei_device *dev;
278c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin
27990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
2809ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EINVAL;
2819ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
282c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	dev = cl->dev;
283c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin
284c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	cl_dbg(dev, cl, "remove list entry belonging to cl\n");
2859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->read_list, cl);
286cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	mei_io_list_free(&cl->dev->write_list, cl);
287cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	mei_io_list_free(&cl->dev->write_waiting_list, cl);
2889ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
2899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
2909ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
2919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
2929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return 0;
2939ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
2949ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2959ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
2969ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
29783ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_cl_init - initializes cl.
2989ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
2999ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: host client to be initialized
3009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @dev: mei device
3019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
3029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklervoid mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
3039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
3049ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	memset(cl, 0, sizeof(struct mei_cl));
3059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	init_waitqueue_head(&cl->wait);
3069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	init_waitqueue_head(&cl->rx_wait);
3079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	init_waitqueue_head(&cl->tx_wait);
3089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	INIT_LIST_HEAD(&cl->link);
309a7b71bc043aded9da4cf51f85271e0779161fe22Samuel Ortiz	INIT_LIST_HEAD(&cl->device_link);
3109ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cl->reading_state = MEI_IDLE;
3119ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cl->writing_state = MEI_IDLE;
3129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cl->dev = dev;
3139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
3149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
3159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
3169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * mei_cl_allocate - allocates cl  structure and sets it up.
3179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
3189ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @dev: mei device
319a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return:  The allocated file or NULL on failure
3209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
3219ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerstruct mei_cl *mei_cl_allocate(struct mei_device *dev)
3229ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
3239ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl *cl;
3249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
3259ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
3269ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (!cl)
3279ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return NULL;
3289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
3299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_cl_init(cl, dev);
3309ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
3319ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return cl;
3329ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
3339ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
33490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler/**
33590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_find_read_cb - find this cl's callback in the read list
33690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *
337393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cl: host client
338393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida *
339a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: cb on success, NULL on error
34090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler */
34190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerstruct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
34290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler{
34390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev = cl->dev;
34431f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	struct mei_cl_cb *cb;
34590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
34631f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	list_for_each_entry(cb, &dev->read_list.list, list)
34790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		if (mei_cl_cmp_id(cl, cb->cl))
34890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler			return cb;
34990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	return NULL;
35090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler}
35190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
35283ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin/** mei_cl_link: allocate host id in the host map
3539ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
354781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler * @cl - host client
35583ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * @id - fixed host id or -1 for generic one
356393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida *
357a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success
3589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-EINVAL on incorrect values
3599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-ENONET if client not found
3609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
361781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winklerint mei_cl_link(struct mei_cl *cl, int id)
3629ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
36390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
36422f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	long open_handle_count;
3659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
366781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
3679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EINVAL;
3689ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
36990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
37090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
37183ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin	/* If Id is not assigned get one*/
372781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	if (id == MEI_HOST_CLIENT_ID_ANY)
373781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler		id = find_first_zero_bit(dev->host_clients_map,
374781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler					MEI_CLIENTS_MAX);
3759ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
376781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	if (id >= MEI_CLIENTS_MAX) {
3772bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
378e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler		return -EMFILE;
379e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler	}
380e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler
38122f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
38222f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
3832bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		dev_err(dev->dev, "open_handle_count exceeded %d",
384e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler			MEI_MAX_OPEN_HANDLE_COUNT);
385e036cc5727eb6d471442d2a9218990aa11215400Tomas Winkler		return -EMFILE;
3869ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
3879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
388781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	dev->open_handle_count++;
389781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
390781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	cl->host_client_id = id;
391781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	list_add_tail(&cl->link, &dev->file_list);
392781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
393781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	set_bit(id, dev->host_clients_map);
394781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
395781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	cl->state = MEI_FILE_INITIALIZING;
396781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
397c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	cl_dbg(dev, cl, "link cl\n");
398781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	return 0;
3999ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
400781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
4019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
40290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_unlink - remove me_cl from the list
4039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
404393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * @cl: host client
4059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
40690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_unlink(struct mei_cl *cl)
4079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
40890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
40990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
410781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	/* don't shout on error exit path */
411781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler	if (!cl)
412781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler		return 0;
413781d0d89224bbbc438c2c0360cfd4822bb35d280Tomas Winkler
4148e9a4a9a5c8e8765417d54ed6917c7e1e4d09f4dTomas Winkler	/* wd and amthif might not be initialized */
4158e9a4a9a5c8e8765417d54ed6917c7e1e4d09f4dTomas Winkler	if (!cl->dev)
4168e9a4a9a5c8e8765417d54ed6917c7e1e4d09f4dTomas Winkler		return 0;
41790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
41890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
41990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
420a14c44d82fcff280fd1138574d4480b2bdd40216Tomas Winkler	cl_dbg(dev, cl, "unlink client");
421a14c44d82fcff280fd1138574d4480b2bdd40216Tomas Winkler
42222f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	if (dev->open_handle_count > 0)
42322f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler		dev->open_handle_count--;
42422f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler
42522f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	/* never clear the 0 bit */
42622f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	if (cl->host_client_id)
42722f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler		clear_bit(cl->host_client_id, dev->host_clients_map);
42822f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler
42922f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	list_del_init(&cl->link);
43022f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler
43122f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler	cl->state = MEI_FILE_INITIALIZING;
43222f96a0eb6c62b570621d77dacbf2589a6de2997Tomas Winkler
43390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	return 0;
4349ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
4359ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4369ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4379ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklervoid mei_host_client_init(struct work_struct *work)
4389ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
4399ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_device *dev = container_of(work,
4409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler					      struct mei_device, init_work);
4415ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	struct mei_me_client *me_cl;
4425ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	struct mei_client_properties *props;
4439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mutex_lock(&dev->device_lock);
4459ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4465ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler	list_for_each_entry(me_cl, &dev->me_clients, list) {
4475ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		props = &me_cl->props;
4489ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4495ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		if (!uuid_le_cmp(props->protocol_name, mei_amthif_guid))
4509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			mei_amthif_host_init(dev);
4515ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		else if (!uuid_le_cmp(props->protocol_name, mei_wd_guid))
4529ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			mei_wd_host_init(dev);
4535ca2d3882d60c040285d0b45df731e11f5da7c64Tomas Winkler		else if (!uuid_le_cmp(props->protocol_name, mei_nfc_guid))
45459fcd7c63abf0340f551f487264b67ff5f7a0b86Samuel Ortiz			mei_nfc_host_init(dev);
45559fcd7c63abf0340f551f487264b67ff5f7a0b86Samuel Ortiz
4569ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
4579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4589ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	dev->dev_state = MEI_DEV_ENABLED;
4596adb8efb024a7e413b93b22848fc13395b1a438aTomas Winkler	dev->reset_count = 0;
4609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mutex_unlock(&dev->device_lock);
46204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
4632bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
4642bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	dev_dbg(dev->dev, "rpm: autosuspend\n");
4652bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_autosuspend(dev->dev);
4669ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
4679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4686aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler/**
469a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * mei_hbuf_acquire - try to acquire host buffer
4706aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler *
4716aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler * @dev: the device structure
472a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: true if host buffer was acquired
4736aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler */
4746aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winklerbool mei_hbuf_acquire(struct mei_device *dev)
4756aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler{
47604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (mei_pg_state(dev) == MEI_PG_ON ||
47704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	    dev->pg_event == MEI_PG_EVENT_WAIT) {
4782bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		dev_dbg(dev->dev, "device is in pg\n");
47904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return false;
48004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
48104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
4826aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (!dev->hbuf_is_ready) {
4832bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		dev_dbg(dev->dev, "hbuf is not ready\n");
4846aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		return false;
4856aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	}
4866aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler
4876aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	dev->hbuf_is_ready = false;
4886aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler
4896aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	return true;
4906aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler}
4919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
4929ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
49383ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_cl_disconnect - disconnect host client from the me one
4949ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
49590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @cl: host client
4969ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
4979ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * Locking: called under "dev->device_lock" lock
4989ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
499a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success, <0 on failure.
5009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
50190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_disconnect(struct mei_cl *cl)
5029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
50390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
5049ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *cb;
505fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin	int rets;
5069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
50790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
5089ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -ENODEV;
5099ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
51090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
51190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
512c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	cl_dbg(dev, cl, "disconnecting");
513c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin
5149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (cl->state != MEI_FILE_DISCONNECTING)
5159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return 0;
5169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5172bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	rets = pm_runtime_get(dev->dev);
51804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets < 0 && rets != -EINPROGRESS) {
5192bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		pm_runtime_put_noidle(dev->dev);
52004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_err(dev, cl, "rpm: get failed %d\n", rets);
52104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return rets;
52204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
52304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
5249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb = mei_io_cb_init(cl, NULL);
52504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (!cb) {
52604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		rets = -ENOMEM;
52704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		goto free;
52804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
5299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5305a8373fba0ab2cec8d206747ad60ca4a30821a37Tomas Winkler	cb->fop_type = MEI_FOP_DISCONNECT;
5315a8373fba0ab2cec8d206747ad60ca4a30821a37Tomas Winkler
5326aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (mei_hbuf_acquire(dev)) {
5339ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		if (mei_hbm_cl_disconnect_req(dev, cl)) {
5349ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			rets = -ENODEV;
535c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin			cl_err(dev, cl, "failed to disconnect.\n");
5369ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			goto free;
5379ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		}
53822b987a325701223f9a37db700c6eb20b9924c6fAlexander Usyskin		cl->timer_count = MEI_CONNECT_TIMEOUT;
5399ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		mdelay(10); /* Wait for hardware disconnection ready */
5409ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
5419ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	} else {
542c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin		cl_dbg(dev, cl, "add disconnect cb to control write list\n");
5439ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
5449ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5459ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
5469ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mutex_unlock(&dev->device_lock);
5479ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
54812f45ed414c8d2eac1a98bf2deaf4117e8c0324fTomas Winkler	wait_event_timeout(cl->wait,
5499ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			MEI_FILE_DISCONNECTED == cl->state,
5509ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
5519ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5529ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mutex_lock(&dev->device_lock);
553fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin
5549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (MEI_FILE_DISCONNECTED == cl->state) {
5559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		rets = 0;
556c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin		cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
5579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	} else {
558fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin		cl_dbg(dev, cl, "timeout on disconnect from FW client.\n");
559fe2f17eb3da38ac0d5a00c511255bf3a33d16d24Alexander Usyskin		rets = -ETIME;
5609ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
5619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5629ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&dev->ctrl_rd_list, cl);
5639ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_list_flush(&dev->ctrl_wr_list, cl);
5649ca9050b3df690d9d44e39424ab2a531120af936Tomas Winklerfree:
56504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	cl_dbg(dev, cl, "rpm: autosuspend\n");
5662bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
5672bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_put_autosuspend(dev->dev);
56804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
5699ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	mei_io_cb_free(cb);
5709ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return rets;
5719ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
5729ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5739ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5749ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
57590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_is_other_connecting - checks if other
57690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler *    client with the same me client id is connecting
5779ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
5789ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: private data of the file object
5799ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
580a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: true if other client is connected, false - otherwise.
5819ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
58290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerbool mei_cl_is_other_connecting(struct mei_cl *cl)
5839ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
58490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
58531f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	struct mei_cl *ocl; /* the other client */
5869ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
58790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
58890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		return false;
58990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
59090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
59190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
59231f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	list_for_each_entry(ocl, &dev->file_list, link) {
59331f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler		if (ocl->state == MEI_FILE_CONNECTING &&
59431f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler		    ocl != cl &&
59531f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler		    cl->me_client_id == ocl->me_client_id)
59690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler			return true;
5979ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
5989ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
59990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
60090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	return false;
6019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
6029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
6039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
60483ce07411dc2316aaaf95a0f193fa2fd76e2e739Alexander Usyskin * mei_cl_connect - connect host client to the me one
6059f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler *
6069f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * @cl: host client
607a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @file: pointer to file structure
6089f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler *
6099f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler * Locking: called under "dev->device_lock" lock
6109f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler *
611a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success, <0 on failure.
6129f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler */
6139f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winklerint mei_cl_connect(struct mei_cl *cl, struct file *file)
6149f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler{
6159f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	struct mei_device *dev;
6169f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	struct mei_cl_cb *cb;
6179f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	int rets;
6189f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6199f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	if (WARN_ON(!cl || !cl->dev))
6209f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		return -ENODEV;
6219f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6229f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	dev = cl->dev;
6239f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6242bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	rets = pm_runtime_get(dev->dev);
62504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets < 0 && rets != -EINPROGRESS) {
6262bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		pm_runtime_put_noidle(dev->dev);
62704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_err(dev, cl, "rpm: get failed %d\n", rets);
62804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return rets;
62904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
63004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
6319f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	cb = mei_io_cb_init(cl, file);
6329f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	if (!cb) {
6339f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		rets = -ENOMEM;
6349f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		goto out;
6359f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	}
6369f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
63702a7eecc6ee565f5f3af836d56fe25bafcc49c98Tomas Winkler	cb->fop_type = MEI_FOP_CONNECT;
6389f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6396aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	/* run hbuf acquire last so we don't have to undo */
6406aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
641e4d8270e604c3202131bac607969605ac397b893Alexander Usyskin		cl->state = MEI_FILE_CONNECTING;
6429f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		if (mei_hbm_cl_connect_req(dev, cl)) {
6439f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler			rets = -ENODEV;
6449f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler			goto out;
6459f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		}
6469f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		cl->timer_count = MEI_CONNECT_TIMEOUT;
6479f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
6489f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	} else {
64973ab4232388b7a08f17c8d08141ff2099fa0b161Alexander Usyskin		cl->state = MEI_FILE_INITIALIZING;
6509f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
6519f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	}
6529f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6539f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	mutex_unlock(&dev->device_lock);
65412f45ed414c8d2eac1a98bf2deaf4117e8c0324fTomas Winkler	wait_event_timeout(cl->wait,
655285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin			(cl->state == MEI_FILE_CONNECTED ||
656285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin			 cl->state == MEI_FILE_DISCONNECTED),
657285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
6589f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	mutex_lock(&dev->device_lock);
6599f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6609f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	if (cl->state != MEI_FILE_CONNECTED) {
6613e37ebb7183f0c4eb92a88c60657ac319c01b3e9Alexander Usyskin		cl->state = MEI_FILE_DISCONNECTED;
662285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin		/* something went really wrong */
663285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin		if (!cl->status)
664285e2996655b7bbfb5eb83076a7d7e6f03e2f5c2Alexander Usyskin			cl->status = -EFAULT;
6659f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6669f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		mei_io_list_flush(&dev->ctrl_rd_list, cl);
6679f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler		mei_io_list_flush(&dev->ctrl_wr_list, cl);
6689f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	}
6699f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6709f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	rets = cl->status;
6719f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6729f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winklerout:
67304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	cl_dbg(dev, cl, "rpm: autosuspend\n");
6742bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
6752bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_put_autosuspend(dev->dev);
67604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
6779f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	mei_io_cb_free(cb);
6789f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler	return rets;
6799f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler}
6809f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler
6819f81abdac3629629a246fdc9e2a7c01ffd52ce8aTomas Winkler/**
68290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
6839ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
6849ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: private data of the file object
6859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
686a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
6879ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-ENOENT if mei_cl is not present
6889ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-EINVAL if single_recv_buf == 0
6899ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
69090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_flow_ctrl_creds(struct mei_cl *cl)
6919ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
69290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
69312d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	struct mei_me_client *me_cl;
6949ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
69590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
69690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		return -EINVAL;
69790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
69890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
69990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
7009ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (cl->mei_flow_ctrl_creds > 0)
7019ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return 1;
7029ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
703d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
704d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	if (!me_cl) {
70512d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
706d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler		return -ENOENT;
7079ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
70812d0066526f386538de80b4d86d2008461b36674Alexander Usyskin
70912d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	if (me_cl->mei_flow_ctrl_creds) {
71012d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		if (WARN_ON(me_cl->props.single_recv_buf == 0))
71112d0066526f386538de80b4d86d2008461b36674Alexander Usyskin			return -EINVAL;
71212d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		return 1;
71312d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	}
71412d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	return 0;
7159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
7169ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
7179ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
71890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * mei_cl_flow_ctrl_reduce - reduces flow_control.
7199ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
7209ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler * @cl: private data of the file object
721393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida *
722a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return:
7239ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	0 on success
7249ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-ENOENT when me client is not found
7259ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *	-EINVAL when ctrl credits are <= 0
7269ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
72790e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winklerint mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
7289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
72990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
73012d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	struct mei_me_client *me_cl;
7319ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
73290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
73390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		return -EINVAL;
73490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
73590e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
73690e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
737d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
738d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	if (!me_cl) {
73912d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
740d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler		return -ENOENT;
74112d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	}
7429ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
743d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	if (me_cl->props.single_recv_buf) {
74412d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
74512d0066526f386538de80b4d86d2008461b36674Alexander Usyskin			return -EINVAL;
74612d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		me_cl->mei_flow_ctrl_creds--;
74712d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	} else {
74812d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
74912d0066526f386538de80b4d86d2008461b36674Alexander Usyskin			return -EINVAL;
75012d0066526f386538de80b4d86d2008461b36674Alexander Usyskin		cl->mei_flow_ctrl_creds--;
7519ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
75212d0066526f386538de80b4d86d2008461b36674Alexander Usyskin	return 0;
7539ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
7549ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
7559ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler/**
756393b148f9d0e70cfcb0096985bb0f0742802929eMasanari Iida * mei_cl_read_start - the start read client message function.
7579ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
75890e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler * @cl: host client
7599ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler *
760a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0 on success, <0 on failure.
7619ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler */
762fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winklerint mei_cl_read_start(struct mei_cl *cl, size_t length)
7639ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler{
76490e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	struct mei_device *dev;
7659ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	struct mei_cl_cb *cb;
766d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	struct mei_me_client *me_cl;
7679ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	int rets;
7689ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
76990e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
77090e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler		return -ENODEV;
77190e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
77290e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler	dev = cl->dev;
77390e0b5f18569bdd03c5ddd1d8c99946f42af77b8Tomas Winkler
774b950ac1dabfcbf97b99f26fa75f86087e1960aefTomas Winkler	if (!mei_cl_is_connected(cl))
7759ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -ENODEV;
7769ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
777d91aaed30a938c5daae2641e6758dfab8727862eTomas Winkler	if (cl->read_cb) {
778c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin		cl_dbg(dev, cl, "read is pending.\n");
7799ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		return -EBUSY;
7809ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
781d880f3294d0576e79dfab4e2cd5a2eb62fe188f0Tomas Winkler	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
782d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	if (!me_cl) {
783c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
7847ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		return  -ENOTTY;
7859ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
7869ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
7872bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	rets = pm_runtime_get(dev->dev);
78804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets < 0 && rets != -EINPROGRESS) {
7892bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		pm_runtime_put_noidle(dev->dev);
79004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_err(dev, cl, "rpm: get failed %d\n", rets);
79104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return rets;
79204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
79304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
7949ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb = mei_io_cb_init(cl, NULL);
79504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (!cb) {
79604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		rets = -ENOMEM;
79704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		goto out;
79804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
7999ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
800fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winkler	/* always allocate at least client max message */
801d320832f64666089a06778782e42fac29abd7bf7Tomas Winkler	length = max_t(size_t, length, me_cl->props.max_msg_length);
802fcb136e1ac5774909e0d85189f721b8dfa800e0fTomas Winkler	rets = mei_io_cb_alloc_resp_buf(cb, length);
8039ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	if (rets)
80404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		goto out;
8059ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
8069ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	cb->fop_type = MEI_FOP_READ;
8076aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (mei_hbuf_acquire(dev)) {
80886113500c060bccb0f08bdcadcecc0bd267fd25aAlexander Usyskin		rets = mei_hbm_cl_flow_control_req(dev, cl);
80986113500c060bccb0f08bdcadcecc0bd267fd25aAlexander Usyskin		if (rets < 0)
81004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler			goto out;
81104bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
8129ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		list_add_tail(&cb->list, &dev->read_list.list);
8139ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	} else {
8149ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler		list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
8159ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	}
816accb884b32e82f943340688c9cd30290531e73e0Chao Bi
817accb884b32e82f943340688c9cd30290531e73e0Chao Bi	cl->read_cb = cb;
818accb884b32e82f943340688c9cd30290531e73e0Chao Bi
81904bb139a071fef549892718f8965a7c61b1924e0Tomas Winklerout:
82004bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	cl_dbg(dev, cl, "rpm: autosuspend\n");
8212bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
8222bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_put_autosuspend(dev->dev);
82304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
82404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets)
82504bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		mei_io_cb_free(cb);
82604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
8279ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler	return rets;
8289ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler}
8299ca9050b3df690d9d44e39424ab2a531120af936Tomas Winkler
830074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler/**
8319d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler * mei_cl_irq_write - write a message to device
83221767546e955c3c1705387ca4548db812382fe08Tomas Winkler *	from the interrupt thread context
83321767546e955c3c1705387ca4548db812382fe08Tomas Winkler *
83421767546e955c3c1705387ca4548db812382fe08Tomas Winkler * @cl: client
83521767546e955c3c1705387ca4548db812382fe08Tomas Winkler * @cb: callback block.
83621767546e955c3c1705387ca4548db812382fe08Tomas Winkler * @cmpl_list: complete list.
83721767546e955c3c1705387ca4548db812382fe08Tomas Winkler *
838a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: 0, OK; otherwise error.
83921767546e955c3c1705387ca4548db812382fe08Tomas Winkler */
8409d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winklerint mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
8419d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler		     struct mei_cl_cb *cmpl_list)
84221767546e955c3c1705387ca4548db812382fe08Tomas Winkler{
843136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	struct mei_device *dev;
844136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	struct mei_msg_data *buf;
84521767546e955c3c1705387ca4548db812382fe08Tomas Winkler	struct mei_msg_hdr mei_hdr;
846136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	size_t len;
847136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	u32 msg_slots;
8489d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler	int slots;
8492ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler	int rets;
85021767546e955c3c1705387ca4548db812382fe08Tomas Winkler
851136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	if (WARN_ON(!cl || !cl->dev))
852136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler		return -ENODEV;
853136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
854136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	dev = cl->dev;
855136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
856136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	buf = &cb->request_buffer;
857136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
858136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	rets = mei_cl_flow_ctrl_creds(cl);
859136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	if (rets < 0)
860136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler		return rets;
861136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
862136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	if (rets == 0) {
86304bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
864136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler		return 0;
865136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	}
866136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
8679d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler	slots = mei_hbuf_empty_slots(dev);
868136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	len = buf->size - cb->buf_idx;
869136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	msg_slots = mei_data2slots(len);
870136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler
87121767546e955c3c1705387ca4548db812382fe08Tomas Winkler	mei_hdr.host_addr = cl->host_client_id;
87221767546e955c3c1705387ca4548db812382fe08Tomas Winkler	mei_hdr.me_addr = cl->me_client_id;
87321767546e955c3c1705387ca4548db812382fe08Tomas Winkler	mei_hdr.reserved = 0;
874479327fc42737234a1f76f20010334c99110d256Tomas Winkler	mei_hdr.internal = cb->internal;
87521767546e955c3c1705387ca4548db812382fe08Tomas Winkler
8769d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler	if (slots >= msg_slots) {
87721767546e955c3c1705387ca4548db812382fe08Tomas Winkler		mei_hdr.length = len;
87821767546e955c3c1705387ca4548db812382fe08Tomas Winkler		mei_hdr.msg_complete = 1;
87921767546e955c3c1705387ca4548db812382fe08Tomas Winkler	/* Split the message only if we can write the whole host buffer */
8809d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler	} else if (slots == dev->hbuf_depth) {
8819d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler		msg_slots = slots;
8829d098192c3d45ab6dd90ae87d649950a9ef70ccbTomas Winkler		len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
88321767546e955c3c1705387ca4548db812382fe08Tomas Winkler		mei_hdr.length = len;
88421767546e955c3c1705387ca4548db812382fe08Tomas Winkler		mei_hdr.msg_complete = 0;
88521767546e955c3c1705387ca4548db812382fe08Tomas Winkler	} else {
88621767546e955c3c1705387ca4548db812382fe08Tomas Winkler		/* wait for next time the host buffer is empty */
88721767546e955c3c1705387ca4548db812382fe08Tomas Winkler		return 0;
88821767546e955c3c1705387ca4548db812382fe08Tomas Winkler	}
88921767546e955c3c1705387ca4548db812382fe08Tomas Winkler
890c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin	cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
89121767546e955c3c1705387ca4548db812382fe08Tomas Winkler			cb->request_buffer.size, cb->buf_idx);
89221767546e955c3c1705387ca4548db812382fe08Tomas Winkler
893136698e535cd1ce59e436cc084b41370fd8f1effTomas Winkler	rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
8942ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler	if (rets) {
8952ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler		cl->status = rets;
89621767546e955c3c1705387ca4548db812382fe08Tomas Winkler		list_move_tail(&cb->list, &cmpl_list->list);
8972ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler		return rets;
89821767546e955c3c1705387ca4548db812382fe08Tomas Winkler	}
89921767546e955c3c1705387ca4548db812382fe08Tomas Winkler
90021767546e955c3c1705387ca4548db812382fe08Tomas Winkler	cl->status = 0;
9014dfaa9f7020b1ff4bf87899f4797d2efd76e80fdTomas Winkler	cl->writing_state = MEI_WRITING;
90221767546e955c3c1705387ca4548db812382fe08Tomas Winkler	cb->buf_idx += mei_hdr.length;
9034dfaa9f7020b1ff4bf87899f4797d2efd76e80fdTomas Winkler
90421767546e955c3c1705387ca4548db812382fe08Tomas Winkler	if (mei_hdr.msg_complete) {
90521767546e955c3c1705387ca4548db812382fe08Tomas Winkler		if (mei_cl_flow_ctrl_reduce(cl))
9062ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler			return -EIO;
90721767546e955c3c1705387ca4548db812382fe08Tomas Winkler		list_move_tail(&cb->list, &dev->write_waiting_list.list);
90821767546e955c3c1705387ca4548db812382fe08Tomas Winkler	}
90921767546e955c3c1705387ca4548db812382fe08Tomas Winkler
91021767546e955c3c1705387ca4548db812382fe08Tomas Winkler	return 0;
91121767546e955c3c1705387ca4548db812382fe08Tomas Winkler}
91221767546e955c3c1705387ca4548db812382fe08Tomas Winkler
91321767546e955c3c1705387ca4548db812382fe08Tomas Winkler/**
9144234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler * mei_cl_write - submit a write cb to mei device
915a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *	assumes device_lock is locked
9164234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler *
9174234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler * @cl: host client
918a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @cb: write callback with filled data
9194234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler *
920a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * Return: number of bytes sent on success, <0 on failure.
9214234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler */
9224234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winklerint mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
9234234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler{
9244234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	struct mei_device *dev;
9254234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	struct mei_msg_data *buf;
9264234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	struct mei_msg_hdr mei_hdr;
9274234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	int rets;
9284234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9294234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9304234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (WARN_ON(!cl || !cl->dev))
9314234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		return -ENODEV;
9324234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9334234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (WARN_ON(!cb))
9344234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		return -EINVAL;
9354234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9364234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	dev = cl->dev;
9374234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9384234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9394234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	buf = &cb->request_buffer;
9404234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9410a01e97432a6ee5c5b78c0425dd7518a80f87b54Alexander Usyskin	cl_dbg(dev, cl, "size=%d\n", buf->size);
9424234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9432bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	rets = pm_runtime_get(dev->dev);
94404bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	if (rets < 0 && rets != -EINPROGRESS) {
9452bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler		pm_runtime_put_noidle(dev->dev);
94604bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		cl_err(dev, cl, "rpm: get failed %d\n", rets);
94704bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler		return rets;
94804bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	}
9494234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9504234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	cb->fop_type = MEI_FOP_WRITE;
9516aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	cb->buf_idx = 0;
9526aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	cl->writing_state = MEI_IDLE;
9536aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler
9546aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.host_addr = cl->host_client_id;
9556aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.me_addr = cl->me_client_id;
9566aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.reserved = 0;
9576aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.msg_complete = 0;
9586aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	mei_hdr.internal = cb->internal;
9594234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9604234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	rets = mei_cl_flow_ctrl_creds(cl);
9614234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (rets < 0)
9624234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		goto err;
9634234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9646aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (rets == 0) {
9656aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
9666aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		rets = buf->size;
9676aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		goto out;
9686aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	}
9696aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler	if (!mei_hbuf_acquire(dev)) {
9706aae48ff18f2fcfb533d2b448ecae16d1de006c1Tomas Winkler		cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
9714234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		rets = buf->size;
9724234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		goto out;
9734234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	}
9744234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9754234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	/* Check for a maximum length */
9764234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (buf->size > mei_hbuf_max_len(dev)) {
9774234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mei_hdr.length = mei_hbuf_max_len(dev);
9784234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mei_hdr.msg_complete = 0;
9794234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	} else {
9804234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mei_hdr.length = buf->size;
9814234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mei_hdr.msg_complete = 1;
9824234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	}
9834234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9842ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler	rets = mei_write_message(dev, &mei_hdr, buf->data);
9852ebf8c94d431078d93599ba56efa58bf850078a1Tomas Winkler	if (rets)
9864234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		goto err;
9874234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9884234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	cl->writing_state = MEI_WRITING;
9894234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	cb->buf_idx = mei_hdr.length;
9904234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
9914234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winklerout:
9924234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (mei_hdr.msg_complete) {
9937ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		rets = mei_cl_flow_ctrl_reduce(cl);
9947ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		if (rets < 0)
9954234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler			goto err;
9967ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin
9974234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		list_add_tail(&cb->list, &dev->write_waiting_list.list);
9984234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	} else {
9994234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		list_add_tail(&cb->list, &dev->write_list.list);
10004234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	}
10014234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10024234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10034234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
10044234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10054234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mutex_unlock(&dev->device_lock);
10067ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		rets = wait_event_interruptible(cl->tx_wait,
10077ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin				cl->writing_state == MEI_WRITE_COMPLETE);
10084234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler		mutex_lock(&dev->device_lock);
10097ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		/* wait_event_interruptible returns -ERESTARTSYS */
10107ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		if (rets) {
10117ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin			if (signal_pending(current))
10127ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin				rets = -EINTR;
10137ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin			goto err;
10147ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin		}
10154234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	}
10167ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin
10177ca96aa278f8b9983184e318b06a0ed9ad0297b8Alexander Usyskin	rets = buf->size;
10184234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winklererr:
101904bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler	cl_dbg(dev, cl, "rpm: autosuspend\n");
10202bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_mark_last_busy(dev->dev);
10212bf94cabb199f73402a5ddefa4a7bf1a82aaeda5Tomas Winkler	pm_runtime_put_autosuspend(dev->dev);
102204bb139a071fef549892718f8965a7c61b1924e0Tomas Winkler
10234234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler	return rets;
10244234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler}
10254234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10264234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
1027db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler/**
1028db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * mei_cl_complete - processes completed operation for a client
1029db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler *
1030db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * @cl: private data of the file object.
1031db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler * @cb: callback block.
1032db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler */
1033db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winklervoid mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
1034db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler{
1035db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler	if (cb->fop_type == MEI_FOP_WRITE) {
1036db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		mei_io_cb_free(cb);
1037db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		cb = NULL;
1038db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		cl->writing_state = MEI_WRITE_COMPLETE;
1039db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		if (waitqueue_active(&cl->tx_wait))
1040db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler			wake_up_interruptible(&cl->tx_wait);
1041db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler
1042db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler	} else if (cb->fop_type == MEI_FOP_READ &&
1043db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler			MEI_READING == cl->reading_state) {
1044db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		cl->reading_state = MEI_READ_COMPLETE;
1045db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		if (waitqueue_active(&cl->rx_wait))
1046db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler			wake_up_interruptible(&cl->rx_wait);
1047db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler		else
1048db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler			mei_cl_bus_rx_event(cl);
1049db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler
1050db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler	}
1051db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler}
1052db086fa926e57e1bd70e8c41235d230b3caa5e99Tomas Winkler
10534234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler
10544234a6deb5ab04e50cfd6d72761345727bd2de21Tomas Winkler/**
1055074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * mei_cl_all_disconnect - disconnect forcefully all connected clients
1056074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler *
1057a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @dev: mei device
1058074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler */
1059074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1060074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winklervoid mei_cl_all_disconnect(struct mei_device *dev)
1061074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler{
106231f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	struct mei_cl *cl;
1063074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
106431f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	list_for_each_entry(cl, &dev->file_list, link) {
1065074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		cl->state = MEI_FILE_DISCONNECTED;
1066074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		cl->mei_flow_ctrl_creds = 0;
1067074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		cl->timer_count = 0;
1068074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler	}
1069074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler}
1070074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1071074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1072074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler/**
10735290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler * mei_cl_all_wakeup  - wake up all readers and writers they can be interrupted
1074074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler *
1075a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @dev: mei device
1076074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler */
10775290801c23231c8e192943d3beb01fdbeb536395Tomas Winklervoid mei_cl_all_wakeup(struct mei_device *dev)
1078074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler{
107931f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	struct mei_cl *cl;
108092db1555f3b9c9be257ef4070d87eb9410493cf3Tomas Winkler
108131f88f5739e966cb3c524083e2d19b423ece3585Tomas Winkler	list_for_each_entry(cl, &dev->file_list, link) {
1082074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		if (waitqueue_active(&cl->rx_wait)) {
1083c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin			cl_dbg(dev, cl, "Waking up reading client!\n");
1084074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler			wake_up_interruptible(&cl->rx_wait);
1085074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler		}
10865290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler		if (waitqueue_active(&cl->tx_wait)) {
1087c0abffbd982ccf9460187206a074e52cb23e8be3Alexander Usyskin			cl_dbg(dev, cl, "Waking up writing client!\n");
10885290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler			wake_up_interruptible(&cl->tx_wait);
10895290801c23231c8e192943d3beb01fdbeb536395Tomas Winkler		}
1090074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler	}
1091074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler}
1092074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1093074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler/**
1094074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler * mei_cl_all_write_clear - clear all pending writes
1095a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin *
1096a8605ea2c20c2b97a54d7746c16ebef5ba29632aAlexander Usyskin * @dev: mei device
1097074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler */
1098074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winklervoid mei_cl_all_write_clear(struct mei_device *dev)
1099074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler{
1100cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	mei_io_list_free(&dev->write_list, NULL);
1101cc99ecfdac01215594c73907726b12f251c21e20Tomas Winkler	mei_io_list_free(&dev->write_waiting_list, NULL);
1102074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler}
1103074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1104074b4c01abb68c6767612a01f41e9b4ed93d5fb8Tomas Winkler
1105