191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/* 291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * Intel Management Engine Interface (Intel MEI) Linux driver 4733ba91cc0d5b0a3cc012431b8c5b354697b57c1Tomas Winkler * Copyright (c) 2003-2012, Intel Corporation. 591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * This program is free software; you can redistribute it and/or modify it 791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * under the terms and conditions of the GNU General Public License, 891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * version 2, as published by the Free Software Foundation. 991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 1091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * This program is distributed in the hope it will be useful, but WITHOUT 1191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * more details. 1491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 1591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 1691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 1791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil#include <linux/pci.h> 1891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil#include <linux/sched.h> 1991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil#include <linux/wait.h> 2091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil#include <linux/delay.h> 2191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 2291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil#include "mei_dev.h" 2391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil#include "hw.h" 2491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil#include "interface.h" 2591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil#include "mei.h" 2691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 2791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilconst uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, 2891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 0xa8, 0x46, 0xe0, 0xff, 0x65, 2991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 0x81, 0x4c); 3091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 3191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 320288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler * mei_io_list_init - Sets up a queue list. 3391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 340288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler * @list: An instance io list structure 3591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 3691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 370288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winklervoid mei_io_list_init(struct mei_io_list *list) 3891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 3991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* initialize our queue list */ 4091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil INIT_LIST_HEAD(&list->mei_cb.cb_list); 4191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 4291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 4391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 440288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler * mei_io_list_flush - removes list entry belonging to cl. 4591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 4691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @list: An instance of our list structure 4791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @cl: private data of the file object 4891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 490288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winklervoid mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl) 5091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 513a5352fc9d316fe1be18daf80571e80805e06f11Tomas Winkler struct mei_cl_cb *pos; 523a5352fc9d316fe1be18daf80571e80805e06f11Tomas Winkler struct mei_cl_cb *next; 5391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 54b7cd2d9fdc0185e0f4fede78f2a040c5f7c5a179Tomas Winkler list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { 553a5352fc9d316fe1be18daf80571e80805e06f11Tomas Winkler if (pos->file_private) { 560288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler struct mei_cl *cl_tmp; 57b7cd2d9fdc0185e0f4fede78f2a040c5f7c5a179Tomas Winkler cl_tmp = (struct mei_cl *)pos->file_private; 580288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler if (mei_cl_cmp_id(cl, cl_tmp)) 59b7cd2d9fdc0185e0f4fede78f2a040c5f7c5a179Tomas Winkler list_del(&pos->cb_list); 6091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 6191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 6291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 630288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler/** 640288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler * mei_cl_flush_queues - flushes queue lists belonging to cl. 650288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler * 660288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler * @dev: the device structure 670288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler * @cl: private data of the file object 680288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler */ 690288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winklerint mei_cl_flush_queues(struct mei_cl *cl) 700288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler{ 710288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler if (!cl || !cl->dev) 720288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler return -EINVAL; 730288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler 740288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n"); 750288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_flush(&cl->dev->read_list, cl); 760288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_flush(&cl->dev->write_list, cl); 770288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_flush(&cl->dev->write_waiting_list, cl); 780288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); 790288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); 800288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_flush(&cl->dev->amthi_cmd_list, cl); 810288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl); 820288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler return 0; 830288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler} 840288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler 850288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler 8691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 8791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 8891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * mei_reset_iamthif_params - initializes mei device iamthif 8991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 9091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 9191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 9291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilstatic void mei_reset_iamthif_params(struct mei_device *dev) 9391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 9491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* reset iamthif parameters. */ 9591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_current_cb = NULL; 9691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_msg_buf_size = 0; 9791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_msg_buf_index = 0; 98eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->iamthif_canceled = false; 99eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->iamthif_ioctl = false; 10091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_state = MEI_IAMTHIF_IDLE; 10191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_timer = 0; 10291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 10391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 10491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 10591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * init_mei_device - allocates and initializes the mei device structure 10691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 10791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @pdev: The pci device structure 10891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 10991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * returns The mei_device_device pointer on success, NULL on failure. 11091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 111c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winklerstruct mei_device *mei_device_init(struct pci_dev *pdev) 11291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 11391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_device *dev; 11491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 11591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL); 11691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (!dev) 11791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return NULL; 11891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 11991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* setup our list array */ 12091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil INIT_LIST_HEAD(&dev->file_list); 12191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil INIT_LIST_HEAD(&dev->wd_cl.link); 12291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil INIT_LIST_HEAD(&dev->iamthif_cl.link); 12391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mutex_init(&dev->device_lock); 12491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil init_waitqueue_head(&dev->wait_recvd_msg); 12591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil init_waitqueue_head(&dev->wait_stop_wd); 12691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state = MEI_INITIALIZING; 12791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_state = MEI_IAMTHIF_IDLE; 1289ce178e539e0511571a9517e63980e68427b5585Oren Weil dev->wd_interface_reg = false; 1290288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler 1300288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler 1310288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_init(&dev->read_list); 1320288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_init(&dev->write_list); 1330288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_init(&dev->write_waiting_list); 1340288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_init(&dev->ctrl_wr_list); 1350288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_init(&dev->ctrl_rd_list); 1360288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_init(&dev->amthi_cmd_list); 1370288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_init(&dev->amthi_read_complete_list); 13891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->pdev = pdev; 13991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return dev; 14091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 14191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 14291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 14391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * mei_hw_init - initializes host and fw to start work. 14491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 14591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 14691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 14791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * returns 0 on success, <0 on failure. 14891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 14991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilint mei_hw_init(struct mei_device *dev) 15091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 15191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil int err = 0; 15291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil int ret; 15391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 15491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mutex_lock(&dev->device_lock); 15591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 15691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state = mei_hcsr_read(dev); 15791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->me_hw_state = mei_mecsr_read(dev); 15891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n", 15991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state, dev->me_hw_state); 16091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 16191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* acknowledge interrupt and stop interupts */ 16291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if ((dev->host_hw_state & H_IS) == H_IS) 16391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_reg_write(dev, H_CSR, dev->host_hw_state); 16491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 165eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->recvd_msg = false; 16691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); 16791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 16891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_reset(dev, 1); 16991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 17091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", 17191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state, dev->me_hw_state); 17291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 17391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* wait for ME to turn on ME_RDY */ 17491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (!dev->recvd_msg) { 17591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mutex_unlock(&dev->device_lock); 17691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil err = wait_event_interruptible_timeout(dev->wait_recvd_msg, 17791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->recvd_msg, MEI_INTEROP_TIMEOUT); 17891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mutex_lock(&dev->device_lock); 17991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 18091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 181a534bb6eea72c0d082dd2faab85450e5554ba1c8Tomas Winkler if (err <= 0 && !dev->recvd_msg) { 18291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state = MEI_DISABLED; 18391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, 18491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil "wait_event_interruptible_timeout failed" 18591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil "on wait for ME to turn on ME_RDY.\n"); 18691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil ret = -ENODEV; 18791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil goto out; 18891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 18991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 19091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (!(((dev->host_hw_state & H_RDY) == H_RDY) && 19191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) { 19291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state = MEI_DISABLED; 19391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, 19491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", 19591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state, dev->me_hw_state); 19691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 1978eb73c6c2675f708283822bd058ad1e416836ba2Dan Carpenter if (!(dev->host_hw_state & H_RDY)) 19891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n"); 19991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 2008eb73c6c2675f708283822bd058ad1e416836ba2Dan Carpenter if (!(dev->me_hw_state & ME_RDY_HRA)) 20191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n"); 20291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 20391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil printk(KERN_ERR "mei: link layer initialization failed.\n"); 20491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil ret = -ENODEV; 20591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil goto out; 20691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 20791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 20891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (dev->version.major_version != HBM_MAJOR_VERSION || 20991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->version.minor_version != HBM_MINOR_VERSION) { 21091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "MEI start failed.\n"); 21191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil ret = -ENODEV; 21291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil goto out; 21391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 21491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 215eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->recvd_msg = false; 21691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", 21791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state, dev->me_hw_state); 21891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n"); 21991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "link layer has been established.\n"); 22091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "MEI start success.\n"); 22191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil ret = 0; 22291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 22391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilout: 22491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mutex_unlock(&dev->device_lock); 22591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return ret; 22691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 22791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 22891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 22991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * mei_hw_reset - resets fw via mei csr register. 23091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 23191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 23291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @interrupts_enabled: if interrupt should be enabled after reset. 23391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 23491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilstatic void mei_hw_reset(struct mei_device *dev, int interrupts_enabled) 23591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 23691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state |= (H_RST | H_IG); 23791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 23891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (interrupts_enabled) 23991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_enable_interrupts(dev); 24091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil else 24191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_disable_interrupts(dev); 24291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 24391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 24491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 24591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * mei_reset - resets host and fw. 24691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 24791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 24891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @interrupts_enabled: if interrupt should be enabled after reset. 24991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 25091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilvoid mei_reset(struct mei_device *dev, int interrupts_enabled) 25191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 25291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_cl *cl_pos = NULL; 25391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_cl *cl_next = NULL; 25491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_cl_cb *cb_pos = NULL; 25591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_cl_cb *cb_next = NULL; 25691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil bool unexpected; 25791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 25891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (dev->mei_state == MEI_RECOVERING_FROM_RESET) { 259eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->need_reset = true; 26091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return; 26191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 26291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 26391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil unexpected = (dev->mei_state != MEI_INITIALIZING && 26491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state != MEI_DISABLED && 26591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state != MEI_POWER_DOWN && 26691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state != MEI_POWER_UP); 26791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 26891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state = mei_hcsr_read(dev); 26991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 27091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n", 27191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state); 27291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 27391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hw_reset(dev, interrupts_enabled); 27491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 27591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state &= ~H_RST; 27691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state |= H_IG; 27791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 27891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hcsr_set(dev); 27991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 28091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n", 28191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state); 28291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 283eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->need_reset = false; 28491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 28591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (dev->mei_state != MEI_INITIALIZING) { 28691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (dev->mei_state != MEI_DISABLED && 28791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state != MEI_POWER_DOWN) 28891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state = MEI_RESETING; 28991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 29091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil list_for_each_entry_safe(cl_pos, 29191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cl_next, &dev->file_list, link) { 29291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cl_pos->state = MEI_FILE_DISCONNECTED; 29391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cl_pos->mei_flow_ctrl_creds = 0; 29491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cl_pos->read_cb = NULL; 29591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cl_pos->timer_count = 0; 29691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 29791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* remove entry if already in list */ 29891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n"); 29991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_remove_client_from_file_list(dev, 30091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->wd_cl.host_client_id); 30191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 30291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_remove_client_from_file_list(dev, 30391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_cl.host_client_id); 30491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 30591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_reset_iamthif_params(dev); 30691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->wd_due_counter = 0; 30791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->extra_write_index = 0; 30891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 30991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 310cf9673dad4dd76ecdccd265809921ceed752f19eTomas Winkler dev->me_clients_num = 0; 31191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->rd_msg_hdr = 0; 312eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->stop = false; 313eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->wd_pending = false; 31491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 31591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* update the state of the registers after reset */ 31691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state = mei_hcsr_read(dev); 31791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->me_hw_state = mei_mecsr_read(dev); 31891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 31991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", 32091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->host_hw_state, dev->me_hw_state); 32191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 32291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (unexpected) 32391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_warn(&dev->pdev->dev, "unexpected reset.\n"); 32491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 32591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* Wake up all readings so they can be interrupted */ 32691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { 32791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (waitqueue_active(&cl_pos->rx_wait)) { 32891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "Waking up client!\n"); 32991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil wake_up_interruptible(&cl_pos->rx_wait); 33091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 33191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 33291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* remove all waiting requests */ 333b7cd2d9fdc0185e0f4fede78f2a040c5f7c5a179Tomas Winkler list_for_each_entry_safe(cb_pos, cb_next, 334b7cd2d9fdc0185e0f4fede78f2a040c5f7c5a179Tomas Winkler &dev->write_list.mei_cb.cb_list, cb_list) { 3353a5352fc9d316fe1be18daf80571e80805e06f11Tomas Winkler list_del(&cb_pos->cb_list); 3363a5352fc9d316fe1be18daf80571e80805e06f11Tomas Winkler mei_free_cb_private(cb_pos); 33791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 33891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 33991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 34091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 34191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 34291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 34391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * host_start_message - mei host sends start message. 34491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 34591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 34691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 34791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * returns none. 34891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 349c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winklervoid mei_host_start_message(struct mei_device *dev) 35091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 35191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_msg_hdr *mei_hdr; 35291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct hbm_host_version_request *host_start_req; 35391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 35491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* host start message */ 35591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; 35691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->host_addr = 0; 35791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->me_addr = 0; 35891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->length = sizeof(struct hbm_host_version_request); 35991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->msg_complete = 1; 36091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->reserved = 0; 36191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 36291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil host_start_req = 36391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil (struct hbm_host_version_request *) &dev->wr_msg_buf[1]; 36491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil memset(host_start_req, 0, sizeof(struct hbm_host_version_request)); 3651ca7e782864222bcdbe305e543df25df4e343963Tomas Winkler host_start_req->hbm_cmd = HOST_START_REQ_CMD; 36691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil host_start_req->host_version.major_version = HBM_MAJOR_VERSION; 36791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil host_start_req->host_version.minor_version = HBM_MINOR_VERSION; 368eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->recvd_msg = false; 3691ccb7b6249f9bc50678e2a383084ed0a34cc9239Tomas Winkler if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req, 37091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->length)) { 37191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); 37291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state = MEI_RESETING; 37391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_reset(dev, 1); 37491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 37591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->init_clients_state = MEI_START_MESSAGE; 37691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; 37791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return ; 37891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 37991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 38091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 38191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * host_enum_clients_message - host sends enumeration client request message. 38291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 38391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 38491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 38591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * returns none. 38691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 387c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winklervoid mei_host_enum_clients_message(struct mei_device *dev) 38891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 38991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_msg_hdr *mei_hdr; 39091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct hbm_host_enum_request *host_enum_req; 39191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; 39291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* enumerate clients */ 39391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->host_addr = 0; 39491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->me_addr = 0; 39591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->length = sizeof(struct hbm_host_enum_request); 39691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->msg_complete = 1; 39791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->reserved = 0; 39891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 39991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; 40091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); 4011ca7e782864222bcdbe305e543df25df4e343963Tomas Winkler host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; 4021ccb7b6249f9bc50678e2a383084ed0a34cc9239Tomas Winkler if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req, 40391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_hdr->length)) { 40491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state = MEI_RESETING; 40591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); 40691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_reset(dev, 1); 40791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 40891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; 40991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; 4101ccb7b6249f9bc50678e2a383084ed0a34cc9239Tomas Winkler return; 41191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 41291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 41391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 41491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 41591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * allocate_me_clients_storage - allocates storage for me clients 41691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 41791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 41891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 41991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * returns none. 42091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 421c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winklervoid mei_allocate_me_clients_storage(struct mei_device *dev) 42291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 42391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_me_client *clients; 42491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil int b; 42591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 42691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* count how many ME clients we have */ 42791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX) 428cf9673dad4dd76ecdccd265809921ceed752f19eTomas Winkler dev->me_clients_num++; 42991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 430cf9673dad4dd76ecdccd265809921ceed752f19eTomas Winkler if (dev->me_clients_num <= 0) 43191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return ; 43291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 43391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 43491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (dev->me_clients != NULL) { 43591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil kfree(dev->me_clients); 43691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->me_clients = NULL; 43791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 43891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n", 439cf9673dad4dd76ecdccd265809921ceed752f19eTomas Winkler dev->me_clients_num * sizeof(struct mei_me_client)); 44091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* allocate storage for ME clients representation */ 441cf9673dad4dd76ecdccd265809921ceed752f19eTomas Winkler clients = kcalloc(dev->me_clients_num, 44291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil sizeof(struct mei_me_client), GFP_KERNEL); 44391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (!clients) { 44491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n"); 44591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state = MEI_RESETING; 44691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_reset(dev, 1); 44791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return ; 44891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 44991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->me_clients = clients; 45091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return ; 45191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 45291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 45391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * host_client_properties - reads properties for client 45491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 45591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 45691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 457abc51b6de532b1071d8335918970c5d9154da73fOren Weil * returns: 458abc51b6de532b1071d8335918970c5d9154da73fOren Weil * < 0 - Error. 459abc51b6de532b1071d8335918970c5d9154da73fOren Weil * = 0 - no more clients. 460abc51b6de532b1071d8335918970c5d9154da73fOren Weil * = 1 - still have clients to send properties request. 46191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 462abc51b6de532b1071d8335918970c5d9154da73fOren Weilint mei_host_client_properties(struct mei_device *dev) 46391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 46491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_msg_hdr *mei_header; 46591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct hbm_props_request *host_cli_req; 46691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil int b; 46791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil u8 client_num = dev->me_client_presentation_num; 46891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 46991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil b = dev->me_client_index; 47091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b); 47191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (b < MEI_CLIENTS_MAX) { 47291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->me_clients[client_num].client_id = b; 47391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->me_clients[client_num].mei_flow_ctrl_creds = 0; 47491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; 47591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_header->host_addr = 0; 47691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_header->me_addr = 0; 47791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_header->length = sizeof(struct hbm_props_request); 47891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_header->msg_complete = 1; 47991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_header->reserved = 0; 48091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 48191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; 48291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 48391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil memset(host_cli_req, 0, sizeof(struct hbm_props_request)); 48491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 4851ca7e782864222bcdbe305e543df25df4e343963Tomas Winkler host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; 48691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil host_cli_req->address = b; 48791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 4881ccb7b6249f9bc50678e2a383084ed0a34cc9239Tomas Winkler if (mei_write_message(dev, mei_header, 48991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil (unsigned char *)host_cli_req, 49091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_header->length)) { 49191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->mei_state = MEI_RESETING; 49291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); 49391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_reset(dev, 1); 494abc51b6de532b1071d8335918970c5d9154da73fOren Weil return -EIO; 49591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 49691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 49791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; 49891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->me_client_index = b; 499abc51b6de532b1071d8335918970c5d9154da73fOren Weil return 1; 50091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 50191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 502abc51b6de532b1071d8335918970c5d9154da73fOren Weil return 0; 50391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 50491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 50591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 50691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * mei_init_file_private - initializes private file structure. 50791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 50891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @priv: private file structure to be initialized 50991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @file: the file structure 51091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 511c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winklervoid mei_cl_init(struct mei_cl *priv, struct mei_device *dev) 51291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 51391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil memset(priv, 0, sizeof(struct mei_cl)); 51491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil init_waitqueue_head(&priv->wait); 51591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil init_waitqueue_head(&priv->rx_wait); 51691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil init_waitqueue_head(&priv->tx_wait); 51791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil INIT_LIST_HEAD(&priv->link); 51891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil priv->reading_state = MEI_IDLE; 51991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil priv->writing_state = MEI_IDLE; 52091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil priv->dev = dev; 52191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 52291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 52391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilint mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid) 52491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 52591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil int i, res = -1; 52691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 527cf9673dad4dd76ecdccd265809921ceed752f19eTomas Winkler for (i = 0; i < dev->me_clients_num; ++i) 52891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (uuid_le_cmp(cuuid, 52991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->me_clients[i].props.protocol_name) == 0) { 53091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil res = i; 53191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil break; 53291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 53391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 53491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return res; 53591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 53691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 53791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 53891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 53991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * mei_find_me_client_update_filext - searches for ME client guid 54091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * sets client_id in mei_file_private if found 54191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 54291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @priv: private file structure to set client_id in 54391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @cguid: searched guid of ME client 54491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @client_id: id of host client to be set in file private structure 54591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 54691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * returns ME client index 54791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 54891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilu8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv, 54991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil const uuid_le *cguid, u8 client_id) 55091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 55191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil int i; 55291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 55391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (!dev || !priv || !cguid) 55491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return 0; 55591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 55691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* check for valid client id */ 55791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil i = mei_find_me_client_index(dev, *cguid); 55891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (i >= 0) { 55991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil priv->me_client_id = dev->me_clients[i].client_id; 56091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil priv->state = MEI_FILE_CONNECTING; 56191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil priv->host_client_id = client_id; 56291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 56391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil list_add_tail(&priv->link, &dev->file_list); 56491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return (u8)i; 56591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 56691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 56791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return 0; 56891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 56991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 57091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 57191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * host_init_iamthif - mei initialization iamthif client. 57291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 57391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 57491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 57591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 576c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winklervoid mei_host_init_iamthif(struct mei_device *dev) 57791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 57891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil u8 i; 57991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil unsigned char *msg_buf; 58091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 581c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winkler mei_cl_init(&dev->iamthif_cl, dev); 58291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; 58391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 58491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* find ME amthi client */ 58591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl, 58691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); 58791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) { 58891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); 58991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return; 59091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 59191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 592c9667bff9d191db5775d383d9b5efecc26eccae1Tomas Winkler /* Assign iamthif_mtu to the value received from ME */ 59391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 59491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; 595c9667bff9d191db5775d383d9b5efecc26eccae1Tomas Winkler dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", 59691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->me_clients[i].props.max_msg_length); 59791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 59891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil kfree(dev->iamthif_msg_buf); 59991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_msg_buf = NULL; 60091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 60191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil /* allocate storage for ME message buffer */ 60291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil msg_buf = kcalloc(dev->iamthif_mtu, 60391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil sizeof(unsigned char), GFP_KERNEL); 60491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (!msg_buf) { 60591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); 60691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return; 60791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 60891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 60991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_msg_buf = msg_buf; 61091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 6111ccb7b6249f9bc50678e2a383084ed0a34cc9239Tomas Winkler if (mei_connect(dev, &dev->iamthif_cl)) { 61291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); 61391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; 61491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_cl.host_client_id = 0; 61591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } else { 61691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev->iamthif_cl.timer_count = CONNECT_TIMEOUT; 61791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 61891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 61991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 62091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 62191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * mei_alloc_file_private - allocates a private file structure and sets it up. 62291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @file: the file structure 62391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 62491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * returns The allocated file or NULL on failure 62591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 626c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winklerstruct mei_cl *mei_cl_allocate(struct mei_device *dev) 62791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 628c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winkler struct mei_cl *cl; 62991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 630c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winkler cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); 631c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winkler if (!cl) 63291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return NULL; 63391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 634c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winkler mei_cl_init(cl, dev); 63591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 636c95efb741f1db9c804a582a3ba52413b9cbd8f7fTomas Winkler return cl; 63791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 63891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 63991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 64091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 64191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 64291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * mei_disconnect_host_client - sends disconnect message to fw from host client. 64391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 64491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 64591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @cl: private data of the file object 64691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 64791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * Locking: called under "dev->device_lock" lock 64891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 64991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * returns 0 on success, <0 on failure. 65091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 65191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilint mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) 65291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 65391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil int rets, err; 65491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil long timeout = 15; /* 15 seconds */ 65591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_cl_cb *cb; 65691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 65791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (!dev || !cl) 65891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return -ENODEV; 65991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 66091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (cl->state != MEI_FILE_DISCONNECTING) 66191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return 0; 66291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 66391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); 66491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (!cb) 66591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return -ENOMEM; 66691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 66791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil INIT_LIST_HEAD(&cb->cb_list); 66891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cb->file_private = cl; 66991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cb->major_file_operations = MEI_CLOSE; 67091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (dev->mei_host_buffer_is_empty) { 671eb9af0acec3858d835276935df5d5eecd62535d0Tomas Winkler dev->mei_host_buffer_is_empty = false; 67291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (mei_disconnect(dev, cl)) { 67391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil rets = -ENODEV; 67491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n"); 67591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil goto free; 67691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 6771ccb7b6249f9bc50678e2a383084ed0a34cc9239Tomas Winkler mdelay(10); /* Wait for hardware disconnection ready */ 6781ccb7b6249f9bc50678e2a383084ed0a34cc9239Tomas Winkler list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list); 67991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } else { 68091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); 68191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil list_add_tail(&cb->cb_list, 68291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil &dev->ctrl_wr_list.mei_cb.cb_list); 68391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 68491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mutex_unlock(&dev->device_lock); 68591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 68691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil err = wait_event_timeout(dev->wait_recvd_msg, 68791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil (MEI_FILE_DISCONNECTED == cl->state), 68891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil timeout * HZ); 68991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 69091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mutex_lock(&dev->device_lock); 69191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (MEI_FILE_DISCONNECTED == cl->state) { 69291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil rets = 0; 69391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); 69491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } else { 69591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil rets = -ENODEV; 69691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (MEI_FILE_DISCONNECTED != cl->state) 69791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); 69891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 69991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (err) 70091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, 70191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil "wait failed disconnect err=%08x\n", 70291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil err); 70391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 70491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); 70591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 70691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 7070288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_flush(&dev->ctrl_rd_list, cl); 7080288c7c9754d45531944992e8731d1ee9c59ecc3Tomas Winkler mei_io_list_flush(&dev->ctrl_wr_list, cl); 70991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilfree: 71091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil mei_free_cb_private(cb); 71191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil return rets; 71291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 71391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil 71491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil/** 71591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * mei_remove_client_from_file_list - 71691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * removes file private data from device file list 71791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * 71891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @dev: the device structure 71991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil * @host_client_id: host client id to be removed 72091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil */ 72191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weilvoid mei_remove_client_from_file_list(struct mei_device *dev, 72291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil u8 host_client_id) 72391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil{ 72491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_cl *cl_pos = NULL; 72591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil struct mei_cl *cl_next = NULL; 72691f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { 72791f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil if (host_client_id == cl_pos->host_client_id) { 72891f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", 72991f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cl_pos->host_client_id, 73091f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil cl_pos->me_client_id); 73191f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil list_del_init(&cl_pos->link); 73291f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil break; 73391f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 73491f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil } 73591f01c6d45e634b98dd68439afdb04b674a95eeeOren Weil} 736