/*
*
* Intel Management Engine Interface (Intel MEI) Linux driver
* Copyright (c) 2003-2012, Intel Corporation.
*
* 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.
*
*/
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/jiffies.h>
#include "mei_dev.h"
#include <linux/mei.h>
#include "hw.h"
#include "interface.h"
/**
* mei_interrupt_quick_handler - The ISR of the MEI device
*
* @irq: The irq number
* @dev_id: pointer to the device structure
*
* returns irqreturn_t
*/
irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
{
struct mei_device *dev = (struct mei_device *) dev_id;
u32 csr_reg = mei_hcsr_read(dev);
if ((csr_reg & H_IS) != H_IS)
return IRQ_NONE;
/* clear H_IS bit in H_CSR */
mei_reg_write(dev, H_CSR, csr_reg);
return IRQ_WAKE_THREAD;
}
/**
* _mei_cmpl - processes completed operation.
*
* @cl: private data of the file object.
* @cb_pos: callback block.
*/
static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
{
if (cb_pos->fop_type == MEI_FOP_WRITE) {
mei_io_cb_free(cb_pos);
cb_pos = NULL;
cl->writing_state = MEI_WRITE_COMPLETE;
if (waitqueue_active(&cl->tx_wait))
wake_up_interruptible(&cl->tx_wait);
} else if (cb_pos->fop_type == MEI_FOP_READ &&
MEI_READING == cl->reading_state) {
cl->reading_state = MEI_READ_COMPLETE;
if (waitqueue_active(&cl->rx_wait))
wake_up_interruptible(&cl->rx_wait);
}
}
/**
* _mei_irq_thread_state_ok - checks if mei header matches file private data
*
* @cl: private data of the file object
* @mei_hdr: header of mei client message
*
* returns !=0 if matches, 0 if no match.
*/
static int _mei_irq_thread_state_ok(struct mei_cl *cl,
struct mei_msg_hdr *mei_hdr)
{
return (cl->host_client_id == mei_hdr->host_addr &&
cl->me_client_id == mei_hdr->me_addr &&
cl->state == MEI_FILE_CONNECTED &&
MEI_READ_COMPLETE != cl->reading_state);
}
/**
* mei_irq_thread_read_client_message - bottom half read routine after ISR to
* handle the read mei client message data processing.
*
* @complete_list: An instance of our list structure
* @dev: the device structure
* @mei_hdr: header of mei client message
*
* returns 0 on success, <0 on failure.
*/
static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list,
struct mei_device *dev,
struct mei_msg_hdr *mei_hdr)
{
struct mei_cl *cl;
struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
unsigned char *buffer = NULL;
dev_dbg(&dev->pdev->dev, "start client msg\n");
if (list_empty(&dev->read_list.list))
goto quit;
list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) {
cl = cb_pos->cl;
if (cl && <