/*
*
* Intel Management Engine Interface (Intel MEI) Linux driver
* Copyright (c) 2013-2014, 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/jiffies.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/irqreturn.h>
#include <linux/mei.h>
#include "mei_dev.h"
#include "hw-txe.h"
#include "client.h"
#include "hbm.h"
/**
* mei_txe_reg_read - Reads 32bit data from the device
*
* @base_addr: registers base address
* @offset: register offset
*
*/
static inline u32 mei_txe_reg_read(void __iomem *base_addr,
unsigned long offset)
{
return ioread32(base_addr + offset);
}
/**
* mei_txe_reg_write - Writes 32bit data to the device
*
* @base_addr: registers base address
* @offset: register offset
* @value: the value to write
*/
static inline void mei_txe_reg_write(void __iomem *base_addr,
unsigned long offset, u32 value)
{
iowrite32(value, base_addr + offset);
}
/**
* mei_txe_sec_reg_read_silent - Reads 32bit data from the SeC BAR
*
* @dev: the device structure
* @offset: register offset
*
* Doesn't check for aliveness while Reads 32bit data from the SeC BAR
*/
static inline u32 mei_txe_sec_reg_read_silent(struct mei_txe_hw *hw,
unsigned long offset)
{
return mei_txe_reg_read(hw->mem_addr[SEC_BAR], offset);
}
/**
* mei_txe_sec_reg_read - Reads 32bit data from the SeC BAR
*
* @dev: the device structure
* @offset: register offset
*
* Reads 32bit data from the SeC BAR and shout loud if aliveness is not set
*/
static inline u32 mei_txe_sec_reg_read(struct mei_txe_hw *hw,
unsigned long offset)
{
WARN(!hw->aliveness, "sec read: aliveness not asserted\n");
return mei_txe_sec_reg_read_silent(hw, offset);
}
/**
* mei_txe_sec_reg_write_silent - Writes 32bit data to the SeC BAR
* doesn't check for aliveness
*
* @dev: the device structure
* @offset: register offset
* @value: value to write
*
* Doesn't check for aliveness while writes 32bit data from to the SeC BAR
*/
static inline void mei_txe_sec_reg_write_silent(struct mei_txe_hw *hw,
unsigned long offset, u32 value)
{
mei_txe_reg_write(hw->mem_addr[SEC_BAR], offset, value);
}
/**
* mei_txe_sec_reg_write - Writes 32bit data to the SeC BAR
*
* @dev: the device structure
* @offset: register offset
* @value: value to write
*
* Writes 32bit data from the SeC BAR and shout loud if aliveness is not set
*/
static inline void mei_txe_sec_reg_write(struct mei_txe_hw *hw,
unsigned long offset, u32 value)
{
WARN(!hw->aliveness, "sec write: aliveness not asserted\n");
mei_txe_sec_reg_write_silent(hw, offset, value);
}
/**
* mei_txe_br_reg_read - Reads 32bit data from the Bridge BAR
*
* @hw: the device structure
* @offset: offset from which to read the data
*
*/
static inline u32 mei_txe_br_reg_read(struct mei_txe_hw *hw,
unsigned long offset)
{
return mei_txe_reg_read(hw->mem_addr[BRIDGE_BAR], offset);
}
/**
* mei_txe_br_reg_write - Writes 32bit data to the Bridge BAR
*
* @hw: the device structure
* @offset: offset from which to write the data
* @value: the byte to write
*/
static inline void mei_txe_br_reg_write(struct mei_txe_hw *hw,
unsigned long offset, u32 value)
{
mei_txe_reg_write(hw->mem_addr[BRIDGE_BAR], offset, value);
}
/**
* mei_txe_aliveness_set - request for aliveness change
*
* @dev: the device structure
* @req: requested aliveness value
*
* Request for aliveness change and returns true if the change is
* really needed and false if aliveness is already
* in the requested state
* Requires device lock to be held
*/
static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
bool do_req = hw->aliveness != req;
dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
hw->aliveness, req);
if (do_req) {
hw->recvd_aliveness = false;
mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req);
}
return do_req;
}
/**
* mei_txe_aliveness_req_get - get aliveness requested register value
*
* @dev: the device structure
*
* Extract HICR_HOST_ALIVENESS_RESP_ACK bit from
* from HICR_HOST_ALIVENESS_REQ register value
*/
static u32 mei_txe_aliveness_req_get(struct mei_device *dev)
{
struct mei_txe_hw *hw = to_txe_hw(dev);
u32 reg;
reg = mei_txe_br_reg_read(hw, SICR_HOST_ALIVENESS_REQ_REG);