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