2011-05-15 14:43:42 +04:00
/*
*
* Intel Management Engine Interface ( Intel MEI ) Linux driver
2012-02-09 21:25:53 +04:00
* Copyright ( c ) 2003 - 2012 , Intel Corporation .
2011-05-15 14:43:42 +04:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
*/
2013-03-27 18:58:30 +04:00
# include <linux/export.h>
2011-05-15 14:43:42 +04:00
# include <linux/pci.h>
# include <linux/kthread.h>
# include <linux/interrupt.h>
# include <linux/fs.h>
# include <linux/jiffies.h>
2012-05-09 17:38:59 +04:00
# include <linux/mei.h>
2012-12-25 21:06:03 +04:00
# include "mei_dev.h"
2013-01-09 01:07:12 +04:00
# include "hbm.h"
2013-01-09 01:07:17 +04:00
# include "hw-me.h"
2013-01-09 01:07:14 +04:00
# include "client.h"
2011-05-15 14:43:42 +04:00
2013-03-17 13:41:20 +04:00
/**
* mei_irq_compl_handler - dispatch complete handelers
* for the completed callbacks
*
* @ dev - mei device
* @ compl_list - list of completed cbs
*/
void mei_irq_compl_handler ( struct mei_device * dev , struct mei_cl_cb * compl_list )
{
struct mei_cl_cb * cb , * next ;
struct mei_cl * cl ;
list_for_each_entry_safe ( cb , next , & compl_list - > list , list ) {
cl = cb - > cl ;
list_del ( & cb - > list ) ;
if ( ! cl )
continue ;
dev_dbg ( & dev - > pdev - > dev , " completing call back. \n " ) ;
if ( cl = = & dev - > iamthif_cl )
mei_amthif_complete ( dev , cb ) ;
else
2013-05-12 16:34:45 +04:00
mei_cl_complete ( cl , cb ) ;
2013-03-17 13:41:20 +04:00
}
}
2013-03-27 18:58:30 +04:00
EXPORT_SYMBOL_GPL ( mei_irq_compl_handler ) ;
2013-04-19 23:01:34 +04:00
2011-05-15 14:43:42 +04:00
/**
2013-04-19 23:01:34 +04:00
* mei_cl_hbm_equal - check if hbm is addressed to the client
2011-05-15 14:43:42 +04:00
*
2013-04-19 23:01:34 +04:00
* @ cl : host client
2011-05-15 14:43:42 +04:00
* @ mei_hdr : header of mei client message
*
2013-04-19 23:01:34 +04:00
* returns true if matches , false otherwise
2011-05-15 14:43:42 +04:00
*/
2013-04-19 23:01:34 +04:00
static inline int mei_cl_hbm_equal ( struct mei_cl * cl ,
struct mei_msg_hdr * mei_hdr )
2011-05-15 14:43:42 +04:00
{
2013-04-19 23:01:34 +04:00
return cl - > host_client_id = = mei_hdr - > host_addr & &
cl - > me_client_id = = mei_hdr - > me_addr ;
}
/**
* mei_cl_is_reading - checks if the client
is the one to read this message
*
* @ cl : mei client
* @ mei_hdr : header of mei message
*
* returns true on match and false otherwise
*/
static bool mei_cl_is_reading ( struct mei_cl * cl , struct mei_msg_hdr * mei_hdr )
{
return mei_cl_hbm_equal ( cl , mei_hdr ) & &
2011-05-15 14:43:42 +04:00
cl - > state = = MEI_FILE_CONNECTED & &
2013-04-19 23:01:34 +04:00
cl - > reading_state ! = MEI_READ_COMPLETE ;
2011-05-15 14:43:42 +04:00
}
/**
2013-04-19 23:01:34 +04:00
* mei_irq_read_client_message - process client message
2011-05-15 14:43:42 +04:00
*
* @ dev : the device structure
* @ mei_hdr : header of mei client message
2013-04-19 23:01:34 +04:00
* @ complete_list : An instance of our list structure
2011-05-15 14:43:42 +04:00
*
* returns 0 on success , < 0 on failure .
*/
2013-04-19 23:01:34 +04:00
static int mei_cl_irq_read_msg ( struct mei_device * dev ,
struct mei_msg_hdr * mei_hdr ,
struct mei_cl_cb * complete_list )
2011-05-15 14:43:42 +04:00
{
struct mei_cl * cl ;
2013-04-19 23:01:34 +04:00
struct mei_cl_cb * cb , * next ;
2011-06-16 01:46:03 +04:00
unsigned char * buffer = NULL ;
2011-05-15 14:43:42 +04:00
2013-04-19 23:01:34 +04:00
list_for_each_entry_safe ( cb , next , & dev - > read_list . list , list ) {
cl = cb - > cl ;
if ( ! cl | | ! mei_cl_is_reading ( cl , mei_hdr ) )
continue ;
cl - > reading_state = MEI_READING ;
if ( cb - > response_buffer . size = = 0 | |
cb - > response_buffer . data = = NULL ) {
2013-09-15 19:11:07 +04:00
cl_err ( dev , cl , " response buffer is not allocated. \n " ) ;
2013-04-19 23:01:34 +04:00
list_del ( & cb - > list ) ;
return - ENOMEM ;
}
if ( cb - > response_buffer . size < mei_hdr - > length + cb - > buf_idx ) {
2013-09-15 19:11:07 +04:00
cl_dbg ( dev , cl , " message overflow. size %d len %d idx %ld \n " ,
2013-04-19 23:01:35 +04:00
cb - > response_buffer . size ,
mei_hdr - > length , cb - > buf_idx ) ;
2013-04-23 06:44:35 +04:00
buffer = krealloc ( cb - > response_buffer . data ,
mei_hdr - > length + cb - > buf_idx ,
GFP_KERNEL ) ;
2013-04-19 23:01:35 +04:00
2013-04-23 06:44:35 +04:00
if ( ! buffer ) {
2013-09-15 19:11:07 +04:00
cl_err ( dev , cl , " allocation failed. \n " ) ;
2013-04-19 23:01:35 +04:00
list_del ( & cb - > list ) ;
return - ENOMEM ;
}
2013-04-23 06:44:35 +04:00
cb - > response_buffer . data = buffer ;
2013-04-19 23:01:35 +04:00
cb - > response_buffer . size =
mei_hdr - > length + cb - > buf_idx ;
2011-05-15 14:43:42 +04:00
}
2013-04-19 23:01:34 +04:00
buffer = cb - > response_buffer . data + cb - > buf_idx ;
mei_read_slots ( dev , buffer , mei_hdr - > length ) ;
cb - > buf_idx + = mei_hdr - > length ;
if ( mei_hdr - > msg_complete ) {
cl - > status = 0 ;
list_del ( & cb - > list ) ;
2013-09-15 19:11:07 +04:00
cl_dbg ( dev , cl , " completed read length = %lu \n " ,
2013-04-19 23:01:34 +04:00
cb - > buf_idx ) ;
list_add_tail ( & cb - > list , & complete_list - > list ) ;
}
break ;
2011-05-15 14:43:42 +04:00
}
dev_dbg ( & dev - > pdev - > dev , " message read \n " ) ;
if ( ! buffer ) {
2012-02-09 21:25:54 +04:00
mei_read_slots ( dev , dev - > rd_msg_buf , mei_hdr - > length ) ;
2012-12-25 21:06:00 +04:00
dev_dbg ( & dev - > pdev - > dev , " discarding message " MEI_HDR_FMT " \n " ,
MEI_HDR_PRM ( mei_hdr ) ) ;
2011-05-15 14:43:42 +04:00
}
return 0 ;
}
/**
2013-05-12 16:34:46 +04:00
* mei_cl_irq_close - processes close related operation from
* interrupt thread context - send disconnect request
2011-05-15 14:43:42 +04:00
*
2013-05-12 16:34:46 +04:00
* @ cl : client
* @ cb : callback block .
2011-05-15 14:43:42 +04:00
* @ slots : free slots .
* @ cmpl_list : complete list .
*
* returns 0 , OK ; otherwise , error .
*/
2013-05-12 16:34:46 +04:00
static int mei_cl_irq_close ( struct mei_cl * cl , struct mei_cl_cb * cb ,
s32 * slots , struct mei_cl_cb * cmpl_list )
2011-05-15 14:43:42 +04:00
{
2013-05-12 16:34:46 +04:00
struct mei_device * dev = cl - > dev ;
2013-03-11 20:27:02 +04:00
u32 msg_slots =
mei_data2slots ( sizeof ( struct hbm_client_connect_request ) ) ;
2011-05-15 14:43:42 +04:00
2013-03-11 20:27:02 +04:00
if ( * slots < msg_slots )
return - EMSGSIZE ;
* slots - = msg_slots ;
2012-07-04 20:24:53 +04:00
2012-12-25 21:06:11 +04:00
if ( mei_hbm_cl_disconnect_req ( dev , cl ) ) {
2012-07-04 20:24:53 +04:00
cl - > status = 0 ;
2013-05-12 16:34:46 +04:00
cb - > buf_idx = 0 ;
list_move_tail ( & cb - > list , & cmpl_list - > list ) ;
2013-03-11 20:27:02 +04:00
return - EIO ;
2011-05-15 14:43:42 +04:00
}
2013-03-11 20:27:02 +04:00
cl - > state = MEI_FILE_DISCONNECTING ;
cl - > status = 0 ;
2013-05-12 16:34:46 +04:00
cb - > buf_idx = 0 ;
list_move_tail ( & cb - > list , & dev - > ctrl_rd_list . list ) ;
2013-03-11 20:27:02 +04:00
cl - > timer_count = MEI_CONNECT_TIMEOUT ;
2011-05-15 14:43:42 +04:00
return 0 ;
}
/**
2013-05-12 16:34:46 +04:00
* mei_cl_irq_close - processes client read related operation from the
* interrupt thread context - request for flow control credits
2011-05-15 14:43:42 +04:00
*
2013-05-12 16:34:46 +04:00
* @ cl : client
* @ cb : callback block .
2011-05-15 14:43:42 +04:00
* @ slots : free slots .
* @ cmpl_list : complete list .
*
* returns 0 , OK ; otherwise , error .
*/
2013-05-12 16:34:46 +04:00
static int mei_cl_irq_read ( struct mei_cl * cl , struct mei_cl_cb * cb ,
s32 * slots , struct mei_cl_cb * cmpl_list )
2011-05-15 14:43:42 +04:00
{
2013-05-12 16:34:46 +04:00
struct mei_device * dev = cl - > dev ;
2013-03-11 20:27:02 +04:00
u32 msg_slots = mei_data2slots ( sizeof ( struct hbm_flow_control ) ) ;
2013-09-17 00:44:43 +04:00
int ret ;
2013-03-11 20:27:02 +04:00
if ( * slots < msg_slots ) {
2011-05-15 14:43:42 +04:00
/* return the cancel routine */
2013-05-12 16:34:46 +04:00
list_del ( & cb - > list ) ;
2013-03-11 20:27:02 +04:00
return - EMSGSIZE ;
2011-05-15 14:43:42 +04:00
}
2013-03-11 20:27:02 +04:00
* slots - = msg_slots ;
2012-07-04 20:24:52 +04:00
2013-09-17 00:44:43 +04:00
ret = mei_hbm_cl_flow_control_req ( dev , cl ) ;
if ( ret ) {
cl - > status = ret ;
2013-05-12 16:34:46 +04:00
cb - > buf_idx = 0 ;
list_move_tail ( & cb - > list , & cmpl_list - > list ) ;
2013-09-17 00:44:43 +04:00
return ret ;
2012-03-14 16:39:42 +04:00
}
2013-09-17 00:44:43 +04:00
2013-05-12 16:34:46 +04:00
list_move_tail ( & cb - > list , & dev - > read_list . list ) ;
2012-03-14 16:39:42 +04:00
2011-05-15 14:43:42 +04:00
return 0 ;
}
/**
2013-05-12 16:34:46 +04:00
* mei_cl_irq_ioctl - processes client ioctl related operation from the
* interrupt thread context - send connection request
2011-05-15 14:43:42 +04:00
*
2013-05-12 16:34:46 +04:00
* @ cl : client
* @ cb : callback block .
2011-05-15 14:43:42 +04:00
* @ slots : free slots .
* @ cmpl_list : complete list .
*
* returns 0 , OK ; otherwise , error .
*/
2013-05-12 16:34:46 +04:00
static int mei_cl_irq_ioctl ( struct mei_cl * cl , struct mei_cl_cb * cb ,
s32 * slots , struct mei_cl_cb * cmpl_list )
2011-05-15 14:43:42 +04:00
{
2013-05-12 16:34:46 +04:00
struct mei_device * dev = cl - > dev ;
2013-09-17 00:44:43 +04:00
int ret ;
2013-05-12 16:34:46 +04:00
2013-03-11 20:27:02 +04:00
u32 msg_slots =
mei_data2slots ( sizeof ( struct hbm_client_connect_request ) ) ;
if ( * slots < msg_slots ) {
2011-05-15 14:43:42 +04:00
/* return the cancel routine */
2013-05-12 16:34:46 +04:00
list_del ( & cb - > list ) ;
2013-03-11 20:27:02 +04:00
return - EMSGSIZE ;
2011-05-15 14:43:42 +04:00
}
2013-03-11 20:27:02 +04:00
* slots - = msg_slots ;
2012-07-04 20:24:53 +04:00
cl - > state = MEI_FILE_CONNECTING ;
2013-03-11 20:27:02 +04:00
2013-09-17 00:44:43 +04:00
ret = mei_hbm_cl_connect_req ( dev , cl ) ;
if ( ret ) {
cl - > status = ret ;
2013-05-12 16:34:46 +04:00
cb - > buf_idx = 0 ;
list_del ( & cb - > list ) ;
2013-09-17 00:44:43 +04:00
return ret ;
2012-07-04 20:24:53 +04:00
}
2013-05-12 16:34:46 +04:00
list_move_tail ( & cb - > list , & dev - > ctrl_rd_list . list ) ;
cl - > timer_count = MEI_CONNECT_TIMEOUT ;
2011-05-15 14:43:42 +04:00
return 0 ;
}
/**
2013-04-04 20:05:05 +04:00
* mei_irq_read_handler - bottom half read routine after ISR to
2011-05-15 14:43:42 +04:00
* handle the read processing .
*
* @ dev : the device structure
2013-02-06 16:06:42 +04:00
* @ cmpl_list : An instance of our list structure
2011-05-15 14:43:42 +04:00
* @ slots : slots to read .
*
* returns 0 on success , < 0 on failure .
*/
2013-02-06 16:06:42 +04:00
int mei_irq_read_handler ( struct mei_device * dev ,
struct mei_cl_cb * cmpl_list , s32 * slots )
2011-05-15 14:43:42 +04:00
{
struct mei_msg_hdr * mei_hdr ;
2013-11-11 15:26:08 +04:00
struct mei_cl * cl ;
int ret ;
2011-05-15 14:43:42 +04:00
if ( ! dev - > rd_msg_hdr ) {
2013-02-06 16:06:41 +04:00
dev - > rd_msg_hdr = mei_read_hdr ( dev ) ;
2011-05-15 14:43:42 +04:00
( * slots ) - - ;
dev_dbg ( & dev - > pdev - > dev , " slots =%08x. \n " , * slots ) ;
}
mei_hdr = ( struct mei_msg_hdr * ) & dev - > rd_msg_hdr ;
2012-12-25 21:06:00 +04:00
dev_dbg ( & dev - > pdev - > dev , MEI_HDR_FMT , MEI_HDR_PRM ( mei_hdr ) ) ;
2011-05-15 14:43:42 +04:00
if ( mei_hdr - > reserved | | ! dev - > rd_msg_hdr ) {
2013-11-11 15:26:08 +04:00
dev_err ( & dev - > pdev - > dev , " corrupted message header 0x%08X \n " ,
dev - > rd_msg_hdr ) ;
2011-05-15 14:43:42 +04:00
ret = - EBADMSG ;
goto end ;
}
2013-11-11 15:26:08 +04:00
if ( mei_slots2data ( * slots ) < mei_hdr - > length ) {
dev_err ( & dev - > pdev - > dev , " less data available than length=%08x. \n " ,
2011-05-15 14:43:42 +04:00
* slots ) ;
/* we can't read the message */
ret = - ERANGE ;
goto end ;
}
2013-11-11 15:26:08 +04:00
/* HBM message */
if ( mei_hdr - > host_addr = = 0 & & mei_hdr - > me_addr = = 0 ) {
2014-01-08 22:19:21 +04:00
ret = mei_hbm_dispatch ( dev , mei_hdr ) ;
if ( ret ) {
dev_dbg ( & dev - > pdev - > dev , " mei_hbm_dispatch failed ret = %d \n " ,
ret ) ;
goto end ;
}
2013-11-11 15:26:08 +04:00
goto reset_slots ;
}
2012-12-25 21:06:00 +04:00
2013-11-11 15:26:08 +04:00
/* find recepient cl */
list_for_each_entry ( cl , & dev - > file_list , link ) {
if ( mei_cl_hbm_equal ( cl , mei_hdr ) ) {
cl_dbg ( dev , cl , " got a message \n " ) ;
break ;
}
}
/* if no recepient cl was found we assume corrupted header\n */
if ( & cl - > link = = & dev - > file_list ) {
dev_err ( & dev - > pdev - > dev , " no destination client found 0x%08X \n " ,
dev - > rd_msg_hdr ) ;
ret = - EBADMSG ;
goto end ;
}
if ( mei_hdr - > host_addr = = dev - > iamthif_cl . host_client_id & &
MEI_FILE_CONNECTED = = dev - > iamthif_cl . state & &
dev - > iamthif_state = = MEI_IAMTHIF_READING ) {
2012-11-01 23:17:15 +04:00
2013-04-19 22:16:53 +04:00
ret = mei_amthif_irq_read_msg ( dev , mei_hdr , cmpl_list ) ;
2013-11-11 15:26:08 +04:00
if ( ret ) {
dev_err ( & dev - > pdev - > dev , " mei_amthif_irq_read_msg failed = %d \n " ,
ret ) ;
2011-05-15 14:43:42 +04:00
goto end ;
2013-11-11 15:26:08 +04:00
}
2011-05-15 14:43:42 +04:00
} else {
2013-04-19 23:01:34 +04:00
ret = mei_cl_irq_read_msg ( dev , mei_hdr , cmpl_list ) ;
2013-11-11 15:26:08 +04:00
if ( ret ) {
dev_err ( & dev - > pdev - > dev , " mei_cl_irq_read_msg failed = %d \n " ,
ret ) ;
2011-05-15 14:43:42 +04:00
goto end ;
2013-11-11 15:26:08 +04:00
}
2011-05-15 14:43:42 +04:00
}
2013-11-11 15:26:08 +04:00
reset_slots :
2011-05-15 14:43:42 +04:00
/* reset the number of slots and header */
* slots = mei_count_full_read_slots ( dev ) ;
dev - > rd_msg_hdr = 0 ;
if ( * slots = = - EOVERFLOW ) {
/* overflow - reset */
2013-04-19 23:01:34 +04:00
dev_err ( & dev - > pdev - > dev , " resetting due to slots overflow. \n " ) ;
2011-05-15 14:43:42 +04:00
/* set the event since message has been read */
ret = - ERANGE ;
goto end ;
}
end :
return ret ;
}
2013-03-27 18:58:30 +04:00
EXPORT_SYMBOL_GPL ( mei_irq_read_handler ) ;
2011-05-15 14:43:42 +04:00
/**
2013-02-06 16:06:42 +04:00
* mei_irq_write_handler - dispatch write requests
* after irq received
2011-05-15 14:43:42 +04:00
*
* @ dev : the device structure
2012-11-18 17:13:18 +04:00
* @ cmpl_list : An instance of our list structure
2011-05-15 14:43:42 +04:00
*
* returns 0 on success , < 0 on failure .
*/
2013-03-11 20:27:02 +04:00
int mei_irq_write_handler ( struct mei_device * dev , struct mei_cl_cb * cmpl_list )
2011-05-15 14:43:42 +04:00
{
struct mei_cl * cl ;
2013-05-12 16:34:46 +04:00
struct mei_cl_cb * cb , * next ;
2012-10-15 14:06:48 +04:00
struct mei_cl_cb * list ;
2012-11-18 17:13:18 +04:00
s32 slots ;
2011-05-15 14:43:42 +04:00
int ret ;
2013-02-06 16:06:41 +04:00
if ( ! mei_hbuf_is_ready ( dev ) ) {
2011-05-15 14:43:42 +04:00
dev_dbg ( & dev - > pdev - > dev , " host buffer is not empty. \n " ) ;
return 0 ;
}
2012-11-18 17:13:18 +04:00
slots = mei_hbuf_empty_slots ( dev ) ;
if ( slots < = 0 )
2012-06-19 10:13:36 +04:00
return - EMSGSIZE ;
2011-05-15 14:43:42 +04:00
/* complete all waiting for write CB */
dev_dbg ( & dev - > pdev - > dev , " complete all waiting for write cb. \n " ) ;
list = & dev - > write_waiting_list ;
2013-05-12 16:34:46 +04:00
list_for_each_entry_safe ( cb , next , & list - > list , list ) {
cl = cb - > cl ;
2011-11-27 23:43:34 +04:00
if ( cl = = NULL )
continue ;
cl - > status = 0 ;
2013-05-12 16:34:46 +04:00
list_del ( & cb - > list ) ;
2011-11-27 23:43:34 +04:00
if ( MEI_WRITING = = cl - > writing_state & &
2013-05-12 16:34:46 +04:00
cb - > fop_type = = MEI_FOP_WRITE & &
2012-11-11 19:38:00 +04:00
cl ! = & dev - > iamthif_cl ) {
2013-09-15 19:11:07 +04:00
cl_dbg ( dev , cl , " MEI WRITE COMPLETE \n " ) ;
2011-11-27 23:43:34 +04:00
cl - > writing_state = MEI_WRITE_COMPLETE ;
2013-05-12 16:34:46 +04:00
list_add_tail ( & cb - > list , & cmpl_list - > list ) ;
2011-11-27 23:43:34 +04:00
}
if ( cl = = & dev - > iamthif_cl ) {
2013-09-15 19:11:07 +04:00
cl_dbg ( dev , cl , " check iamthif flow control. \n " ) ;
2011-11-27 23:43:34 +04:00
if ( dev - > iamthif_flow_control_pending ) {
2012-11-18 17:13:18 +04:00
ret = mei_amthif_irq_read ( dev , & slots ) ;
2011-11-27 23:43:34 +04:00
if ( ret )
return ret ;
2011-05-15 14:43:42 +04:00
}
}
}
2012-08-16 20:39:43 +04:00
if ( dev - > wd_state = = MEI_WD_STOPPING ) {
dev - > wd_state = MEI_WD_IDLE ;
2011-05-15 14:43:42 +04:00
wake_up_interruptible ( & dev - > wait_stop_wd ) ;
}
2012-11-18 17:13:15 +04:00
if ( dev - > wr_ext_msg . hdr . length ) {
mei_write_message ( dev , & dev - > wr_ext_msg . hdr ,
2012-12-25 21:05:59 +04:00
dev - > wr_ext_msg . data ) ;
2012-11-18 17:13:18 +04:00
slots - = mei_data2slots ( dev - > wr_ext_msg . hdr . length ) ;
2012-11-18 17:13:15 +04:00
dev - > wr_ext_msg . hdr . length = 0 ;
2011-05-15 14:43:42 +04:00
}
2012-08-07 01:03:56 +04:00
if ( dev - > dev_state = = MEI_DEV_ENABLED ) {
2011-05-15 14:43:42 +04:00
if ( dev - > wd_pending & &
2013-01-09 01:07:14 +04:00
mei_cl_flow_ctrl_creds ( & dev - > wd_cl ) > 0 ) {
2011-05-15 14:43:42 +04:00
if ( mei_wd_send ( dev ) )
dev_dbg ( & dev - > pdev - > dev , " wd send failed. \n " ) ;
2013-01-09 01:07:14 +04:00
else if ( mei_cl_flow_ctrl_reduce ( & dev - > wd_cl ) )
2012-07-04 20:24:54 +04:00
return - ENODEV ;
2011-05-15 14:43:42 +04:00
2011-05-25 18:28:22 +04:00
dev - > wd_pending = false ;
2011-05-15 14:43:42 +04:00
2012-08-16 20:39:43 +04:00
if ( dev - > wd_state = = MEI_WD_RUNNING )
2012-11-18 17:13:18 +04:00
slots - = mei_data2slots ( MEI_WD_START_MSG_SIZE ) ;
2012-07-04 20:24:50 +04:00
else
2012-11-18 17:13:18 +04:00
slots - = mei_data2slots ( MEI_WD_STOP_MSG_SIZE ) ;
2011-05-15 14:43:42 +04:00
}
}
/* complete control write list CB */
2011-11-27 23:43:33 +04:00
dev_dbg ( & dev - > pdev - > dev , " complete control write list cb. \n " ) ;
2013-05-12 16:34:46 +04:00
list_for_each_entry_safe ( cb , next , & dev - > ctrl_wr_list . list , list ) {
cl = cb - > cl ;
2011-11-27 23:43:33 +04:00
if ( ! cl ) {
2013-05-12 16:34:46 +04:00
list_del ( & cb - > list ) ;
2011-11-27 23:43:33 +04:00
return - ENODEV ;
}
2013-05-12 16:34:46 +04:00
switch ( cb - > fop_type ) {
2012-11-11 19:38:00 +04:00
case MEI_FOP_CLOSE :
2011-11-27 23:43:33 +04:00
/* send disconnect message */
2013-05-12 16:34:46 +04:00
ret = mei_cl_irq_close ( cl , cb , & slots , cmpl_list ) ;
2011-11-27 23:43:33 +04:00
if ( ret )
return ret ;
2011-05-15 14:43:42 +04:00
2011-11-27 23:43:33 +04:00
break ;
2012-11-11 19:38:00 +04:00
case MEI_FOP_READ :
2011-11-27 23:43:33 +04:00
/* send flow control message */
2013-05-12 16:34:46 +04:00
ret = mei_cl_irq_read ( cl , cb , & slots , cmpl_list ) ;
2011-11-27 23:43:33 +04:00
if ( ret )
return ret ;
2011-05-15 14:43:42 +04:00
2011-11-27 23:43:33 +04:00
break ;
2012-11-11 19:38:00 +04:00
case MEI_FOP_IOCTL :
2011-11-27 23:43:33 +04:00
/* connect message */
2013-01-09 01:07:14 +04:00
if ( mei_cl_is_other_connecting ( cl ) )
2011-11-27 23:43:33 +04:00
continue ;
2013-05-12 16:34:46 +04:00
ret = mei_cl_irq_ioctl ( cl , cb , & slots , cmpl_list ) ;
2011-11-27 23:43:33 +04:00
if ( ret )
return ret ;
2011-05-15 14:43:42 +04:00
2011-11-27 23:43:33 +04:00
break ;
2011-05-15 14:43:42 +04:00
2011-11-27 23:43:33 +04:00
default :
BUG ( ) ;
2011-05-15 14:43:42 +04:00
}
2011-11-27 23:43:33 +04:00
2011-05-15 14:43:42 +04:00
}
/* complete write list CB */
2011-11-27 23:43:34 +04:00
dev_dbg ( & dev - > pdev - > dev , " complete write list cb. \n " ) ;
2013-05-12 16:34:46 +04:00
list_for_each_entry_safe ( cb , next , & dev - > write_list . list , list ) {
cl = cb - > cl ;
2011-11-27 23:43:34 +04:00
if ( cl = = NULL )
continue ;
2012-11-18 17:13:19 +04:00
if ( cl = = & dev - > iamthif_cl )
2013-05-12 16:34:46 +04:00
ret = mei_amthif_irq_write_complete ( cl , cb ,
& slots , cmpl_list ) ;
2012-11-18 17:13:19 +04:00
else
2013-05-12 16:34:46 +04:00
ret = mei_cl_irq_write_complete ( cl , cb ,
& slots , cmpl_list ) ;
2012-11-18 17:13:19 +04:00
if ( ret )
return ret ;
2011-05-15 14:43:42 +04:00
}
return 0 ;
}
2013-03-27 18:58:30 +04:00
EXPORT_SYMBOL_GPL ( mei_irq_write_handler ) ;
2011-05-15 14:43:42 +04:00
/**
* mei_timer - timer function .
*
* @ work : pointer to the work_struct structure
*
* NOTE : This function is called by timer interrupt work
*/
2011-09-07 10:03:13 +04:00
void mei_timer ( struct work_struct * work )
2011-05-15 14:43:42 +04:00
{
unsigned long timeout ;
struct mei_cl * cl_pos = NULL ;
struct mei_cl * cl_next = NULL ;
struct mei_cl_cb * cb_pos = NULL ;
struct mei_cl_cb * cb_next = NULL ;
struct mei_device * dev = container_of ( work ,
2011-09-07 10:03:13 +04:00
struct mei_device , timer_work . work ) ;
2011-05-15 14:43:42 +04:00
mutex_lock ( & dev - > device_lock ) ;
2012-08-07 01:03:56 +04:00
if ( dev - > dev_state ! = MEI_DEV_ENABLED ) {
if ( dev - > dev_state = = MEI_DEV_INIT_CLIENTS ) {
2011-05-15 14:43:42 +04:00
if ( dev - > init_clients_timer ) {
if ( - - dev - > init_clients_timer = = 0 ) {
2013-04-19 00:03:48 +04:00
dev_err ( & dev - > pdev - > dev , " reset: init clients timeout hbm_state = %d. \n " ,
dev - > hbm_state ) ;
2011-05-15 14:43:42 +04:00
mei_reset ( dev , 1 ) ;
}
}
}
goto out ;
}
/*** connect/disconnect timeouts ***/
list_for_each_entry_safe ( cl_pos , cl_next , & dev - > file_list , link ) {
if ( cl_pos - > timer_count ) {
if ( - - cl_pos - > timer_count = = 0 ) {
2013-04-08 22:56:38 +04:00
dev_err ( & dev - > pdev - > dev , " reset: connect/disconnect timeout. \n " ) ;
2011-05-15 14:43:42 +04:00
mei_reset ( dev , 1 ) ;
goto out ;
}
}
}
if ( dev - > iamthif_stall_timer ) {
if ( - - dev - > iamthif_stall_timer = = 0 ) {
2013-04-08 22:56:38 +04:00
dev_err ( & dev - > pdev - > dev , " reset: amthif hanged. \n " ) ;
2011-05-15 14:43:42 +04:00
mei_reset ( dev , 1 ) ;
dev - > iamthif_msg_buf_size = 0 ;
dev - > iamthif_msg_buf_index = 0 ;
2011-05-25 18:28:22 +04:00
dev - > iamthif_canceled = false ;
dev - > iamthif_ioctl = true ;
2011-05-15 14:43:42 +04:00
dev - > iamthif_state = MEI_IAMTHIF_IDLE ;
dev - > iamthif_timer = 0 ;
2012-10-09 18:50:20 +04:00
mei_io_cb_free ( dev - > iamthif_current_cb ) ;
dev - > iamthif_current_cb = NULL ;
2011-05-15 14:43:42 +04:00
dev - > iamthif_file_object = NULL ;
2012-11-01 23:17:15 +04:00
mei_amthif_run_next_cmd ( dev ) ;
2011-05-15 14:43:42 +04:00
}
}
if ( dev - > iamthif_timer ) {
timeout = dev - > iamthif_timer +
2012-11-01 23:17:14 +04:00
mei_secs_to_jiffies ( MEI_IAMTHIF_READ_TIMER ) ;
2011-05-15 14:43:42 +04:00
dev_dbg ( & dev - > pdev - > dev , " dev->iamthif_timer = %ld \n " ,
dev - > iamthif_timer ) ;
dev_dbg ( & dev - > pdev - > dev , " timeout = %ld \n " , timeout ) ;
dev_dbg ( & dev - > pdev - > dev , " jiffies = %ld \n " , jiffies ) ;
if ( time_after ( jiffies , timeout ) ) {
/*
* User didn ' t read the AMTHI data on time ( 15 sec )
* freeing AMTHI for other requests
*/
dev_dbg ( & dev - > pdev - > dev , " freeing AMTHI for other requests \n " ) ;
2012-11-11 19:37:58 +04:00
list_for_each_entry_safe ( cb_pos , cb_next ,
& dev - > amthif_rd_complete_list . list , list ) {
2011-05-15 14:43:42 +04:00
2011-11-27 23:43:34 +04:00
cl_pos = cb_pos - > file_object - > private_data ;
2011-05-15 14:43:42 +04:00
2011-11-27 23:43:34 +04:00
/* Finding the AMTHI entry. */
if ( cl_pos = = & dev - > iamthif_cl )
2012-10-15 14:06:48 +04:00
list_del ( & cb_pos - > list ) ;
2011-05-15 14:43:42 +04:00
}
2012-10-09 18:50:20 +04:00
mei_io_cb_free ( dev - > iamthif_current_cb ) ;
dev - > iamthif_current_cb = NULL ;
2011-05-15 14:43:42 +04:00
dev - > iamthif_file_object - > private_data = NULL ;
dev - > iamthif_file_object = NULL ;
dev - > iamthif_timer = 0 ;
2012-11-01 23:17:15 +04:00
mei_amthif_run_next_cmd ( dev ) ;
2011-05-15 14:43:42 +04:00
}
}
out :
2011-12-14 01:39:34 +04:00
schedule_delayed_work ( & dev - > timer_work , 2 * HZ ) ;
mutex_unlock ( & dev - > device_lock ) ;
2011-05-15 14:43:42 +04:00
}