mirror of
https://github.com/torvalds/linux.git
synced 2024-11-05 03:21:32 +00:00
mei: expose hardware power gating state to mei layer
Since the runtime pm and the internal power gating cannot be in complete sync in regards to I/O operations, we need to expose the device hardware internal power gating state to mei layer 2. We add pg_state handler that translate the hw internal pg state to mei layer 2. We add power gating event variable to keep power track of power gating transitions Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Reviewed-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ee7e5afd2c
commit
964a2331e9
@ -113,6 +113,19 @@ static void mei_me_hw_config(struct mei_device *dev)
|
|||||||
/* Doesn't change in runtime */
|
/* Doesn't change in runtime */
|
||||||
dev->hbuf_depth = (hcsr & H_CBD) >> 24;
|
dev->hbuf_depth = (hcsr & H_CBD) >> 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mei_me_pg_state - translate internal pg state
|
||||||
|
* to the mei power gating state
|
||||||
|
*
|
||||||
|
* @hw - me hardware
|
||||||
|
* returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
|
||||||
|
*/
|
||||||
|
static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev)
|
||||||
|
{
|
||||||
|
return MEI_PG_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mei_clear_interrupts - clear and stop interrupts
|
* mei_clear_interrupts - clear and stop interrupts
|
||||||
*
|
*
|
||||||
@ -601,6 +614,8 @@ end:
|
|||||||
}
|
}
|
||||||
static const struct mei_hw_ops mei_me_hw_ops = {
|
static const struct mei_hw_ops mei_me_hw_ops = {
|
||||||
|
|
||||||
|
.pg_state = mei_me_pg_state,
|
||||||
|
|
||||||
.host_is_ready = mei_me_host_is_ready,
|
.host_is_ready = mei_me_host_is_ready,
|
||||||
|
|
||||||
.hw_is_ready = mei_me_hw_is_ready,
|
.hw_is_ready = mei_me_hw_is_ready,
|
||||||
|
@ -158,7 +158,7 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req)
|
|||||||
dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
|
dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n",
|
||||||
hw->aliveness, req);
|
hw->aliveness, req);
|
||||||
if (do_req) {
|
if (do_req) {
|
||||||
hw->recvd_aliveness = false;
|
dev->pg_event = MEI_PG_EVENT_WAIT;
|
||||||
mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req);
|
mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req);
|
||||||
}
|
}
|
||||||
return do_req;
|
return do_req;
|
||||||
@ -213,6 +213,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
|
|||||||
do {
|
do {
|
||||||
hw->aliveness = mei_txe_aliveness_get(dev);
|
hw->aliveness = mei_txe_aliveness_get(dev);
|
||||||
if (hw->aliveness == expected) {
|
if (hw->aliveness == expected) {
|
||||||
|
dev->pg_event = MEI_PG_EVENT_IDLE;
|
||||||
dev_dbg(&dev->pdev->dev,
|
dev_dbg(&dev->pdev->dev,
|
||||||
"aliveness settled after %d msecs\n", t);
|
"aliveness settled after %d msecs\n", t);
|
||||||
return t;
|
return t;
|
||||||
@ -223,6 +224,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected)
|
|||||||
t += MSEC_PER_SEC / 5;
|
t += MSEC_PER_SEC / 5;
|
||||||
} while (t < SEC_ALIVENESS_WAIT_TIMEOUT);
|
} while (t < SEC_ALIVENESS_WAIT_TIMEOUT);
|
||||||
|
|
||||||
|
dev->pg_event = MEI_PG_EVENT_IDLE;
|
||||||
dev_err(&dev->pdev->dev, "aliveness timed out\n");
|
dev_err(&dev->pdev->dev, "aliveness timed out\n");
|
||||||
return -ETIME;
|
return -ETIME;
|
||||||
}
|
}
|
||||||
@ -249,19 +251,22 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
err = wait_event_timeout(hw->wait_aliveness,
|
err = wait_event_timeout(hw->wait_aliveness_resp,
|
||||||
hw->recvd_aliveness, timeout);
|
dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout);
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
|
|
||||||
hw->aliveness = mei_txe_aliveness_get(dev);
|
hw->aliveness = mei_txe_aliveness_get(dev);
|
||||||
ret = hw->aliveness == expected ? 0 : -ETIME;
|
ret = hw->aliveness == expected ? 0 : -ETIME;
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_err(&dev->pdev->dev, "aliveness timed out");
|
dev_warn(&dev->pdev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n",
|
||||||
|
err, hw->aliveness, dev->pg_event);
|
||||||
else
|
else
|
||||||
dev_dbg(&dev->pdev->dev, "aliveness settled after %d msecs\n",
|
dev_dbg(&dev->pdev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n",
|
||||||
jiffies_to_msecs(timeout - err));
|
jiffies_to_msecs(timeout - err),
|
||||||
hw->recvd_aliveness = false;
|
hw->aliveness, dev->pg_event);
|
||||||
|
|
||||||
|
dev->pg_event = MEI_PG_EVENT_IDLE;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +296,20 @@ static bool mei_txe_pg_is_enabled(struct mei_device *dev)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mei_txe_pg_state - translate aliveness register value
|
||||||
|
* to the mei power gating state
|
||||||
|
*
|
||||||
|
* @dev: the device structure
|
||||||
|
*
|
||||||
|
* returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise
|
||||||
|
*/
|
||||||
|
static inline enum mei_pg_state mei_txe_pg_state(struct mei_device *dev)
|
||||||
|
{
|
||||||
|
struct mei_txe_hw *hw = to_txe_hw(dev);
|
||||||
|
return hw->aliveness ? MEI_PG_OFF : MEI_PG_ON;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt
|
* mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt
|
||||||
*
|
*
|
||||||
@ -972,9 +991,9 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
|
|||||||
/* Clear the interrupt cause */
|
/* Clear the interrupt cause */
|
||||||
dev_dbg(&dev->pdev->dev,
|
dev_dbg(&dev->pdev->dev,
|
||||||
"Aliveness Interrupt: Status: %d\n", hw->aliveness);
|
"Aliveness Interrupt: Status: %d\n", hw->aliveness);
|
||||||
hw->recvd_aliveness = true;
|
dev->pg_event = MEI_PG_EVENT_RECEIVED;
|
||||||
if (waitqueue_active(&hw->wait_aliveness))
|
if (waitqueue_active(&hw->wait_aliveness_resp))
|
||||||
wake_up(&hw->wait_aliveness);
|
wake_up(&hw->wait_aliveness_resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1024,6 +1043,8 @@ static const struct mei_hw_ops mei_txe_hw_ops = {
|
|||||||
|
|
||||||
.host_is_ready = mei_txe_host_is_ready,
|
.host_is_ready = mei_txe_host_is_ready,
|
||||||
|
|
||||||
|
.pg_state = mei_txe_pg_state,
|
||||||
|
|
||||||
.hw_is_ready = mei_txe_hw_is_ready,
|
.hw_is_ready = mei_txe_hw_is_ready,
|
||||||
.hw_reset = mei_txe_hw_reset,
|
.hw_reset = mei_txe_hw_reset,
|
||||||
.hw_config = mei_txe_hw_config,
|
.hw_config = mei_txe_hw_config,
|
||||||
@ -1069,7 +1090,7 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev)
|
|||||||
|
|
||||||
hw = to_txe_hw(dev);
|
hw = to_txe_hw(dev);
|
||||||
|
|
||||||
init_waitqueue_head(&hw->wait_aliveness);
|
init_waitqueue_head(&hw->wait_aliveness_resp);
|
||||||
|
|
||||||
dev->ops = &mei_txe_hw_ops;
|
dev->ops = &mei_txe_hw_ops;
|
||||||
|
|
||||||
|
@ -35,12 +35,11 @@
|
|||||||
/**
|
/**
|
||||||
* struct mei_txe_hw - txe hardware specifics
|
* struct mei_txe_hw - txe hardware specifics
|
||||||
*
|
*
|
||||||
* @mem_addr: SeC and BRIDGE bars
|
* @mem_addr: SeC and BRIDGE bars
|
||||||
* @aliveness: aliveness (power gating) state of the hardware
|
* @aliveness: aliveness (power gating) state of the hardware
|
||||||
* @readiness: readiness state of the hardware
|
* @readiness: readiness state of the hardware
|
||||||
* @wait_aliveness: aliveness wait queue
|
* @wait_aliveness_resp: aliveness wait queue
|
||||||
* @recvd_aliveness: aliveness interrupt was recived
|
* @intr_cause: translated interrupt cause
|
||||||
* @intr_cause: translated interrupt cause
|
|
||||||
*/
|
*/
|
||||||
struct mei_txe_hw {
|
struct mei_txe_hw {
|
||||||
void __iomem *mem_addr[NUM_OF_MEM_BARS];
|
void __iomem *mem_addr[NUM_OF_MEM_BARS];
|
||||||
@ -48,8 +47,7 @@ struct mei_txe_hw {
|
|||||||
u32 readiness;
|
u32 readiness;
|
||||||
u32 slots;
|
u32 slots;
|
||||||
|
|
||||||
wait_queue_head_t wait_aliveness;
|
wait_queue_head_t wait_aliveness_resp;
|
||||||
bool recvd_aliveness;
|
|
||||||
|
|
||||||
unsigned long intr_cause;
|
unsigned long intr_cause;
|
||||||
};
|
};
|
||||||
|
@ -341,6 +341,8 @@ void mei_device_init(struct mei_device *dev)
|
|||||||
* 0: Reserved for MEI Bus Message communications
|
* 0: Reserved for MEI Bus Message communications
|
||||||
*/
|
*/
|
||||||
bitmap_set(dev->host_clients_map, 0, 1);
|
bitmap_set(dev->host_clients_map, 0, 1);
|
||||||
|
|
||||||
|
dev->pg_event = MEI_PG_EVENT_IDLE;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mei_device_init);
|
EXPORT_SYMBOL_GPL(mei_device_init);
|
||||||
|
|
||||||
|
@ -220,6 +220,7 @@ struct mei_cl {
|
|||||||
* @hw_start - start hw after reset
|
* @hw_start - start hw after reset
|
||||||
* @hw_config - configure hw
|
* @hw_config - configure hw
|
||||||
|
|
||||||
|
* @pg_state - power gating state of the device
|
||||||
* @pg_is_enabled - is power gating enabled
|
* @pg_is_enabled - is power gating enabled
|
||||||
|
|
||||||
* @intr_clear - clear pending interrupts
|
* @intr_clear - clear pending interrupts
|
||||||
@ -246,6 +247,7 @@ struct mei_hw_ops {
|
|||||||
int (*hw_start)(struct mei_device *dev);
|
int (*hw_start)(struct mei_device *dev);
|
||||||
void (*hw_config)(struct mei_device *dev);
|
void (*hw_config)(struct mei_device *dev);
|
||||||
|
|
||||||
|
enum mei_pg_state (*pg_state)(struct mei_device *dev);
|
||||||
bool (*pg_is_enabled)(struct mei_device *dev);
|
bool (*pg_is_enabled)(struct mei_device *dev);
|
||||||
|
|
||||||
void (*intr_clear)(struct mei_device *dev);
|
void (*intr_clear)(struct mei_device *dev);
|
||||||
@ -335,11 +337,37 @@ struct mei_cl_device {
|
|||||||
void *priv_data;
|
void *priv_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum mei_pg_event - power gating transition events
|
||||||
|
*
|
||||||
|
* @MEI_PG_EVENT_IDLE: the driver is not in power gating transition
|
||||||
|
* @MEI_PG_EVENT_WAIT: the driver is waiting for a pg event to complete
|
||||||
|
* @MEI_PG_EVENT_RECEIVED: the driver received pg event
|
||||||
|
*/
|
||||||
|
enum mei_pg_event {
|
||||||
|
MEI_PG_EVENT_IDLE,
|
||||||
|
MEI_PG_EVENT_WAIT,
|
||||||
|
MEI_PG_EVENT_RECEIVED,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum mei_pg_state - device internal power gating state
|
||||||
|
*
|
||||||
|
* @MEI_PG_OFF: device is not power gated - it is active
|
||||||
|
* @MEI_PG_ON: device is power gated - it is in lower power state
|
||||||
|
*/
|
||||||
|
enum mei_pg_state {
|
||||||
|
MEI_PG_OFF = 0,
|
||||||
|
MEI_PG_ON = 1,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct mei_device - MEI private device struct
|
* struct mei_device - MEI private device struct
|
||||||
|
|
||||||
* @reset_count - limits the number of consecutive resets
|
* @reset_count - limits the number of consecutive resets
|
||||||
* @hbm_state - state of host bus message protocol
|
* @hbm_state - state of host bus message protocol
|
||||||
|
* @pg_event - power gating event
|
||||||
* @mem_addr - mem mapped base register address
|
* @mem_addr - mem mapped base register address
|
||||||
|
|
||||||
* @hbuf_depth - depth of hardware host/write buffer is slots
|
* @hbuf_depth - depth of hardware host/write buffer is slots
|
||||||
@ -387,6 +415,11 @@ struct mei_device {
|
|||||||
enum mei_hbm_state hbm_state;
|
enum mei_hbm_state hbm_state;
|
||||||
u16 init_clients_timer;
|
u16 init_clients_timer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Power Gating support
|
||||||
|
*/
|
||||||
|
enum mei_pg_event pg_event;
|
||||||
|
|
||||||
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */
|
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */
|
||||||
u32 rd_msg_hdr;
|
u32 rd_msg_hdr;
|
||||||
|
|
||||||
@ -563,6 +596,11 @@ static inline void mei_hw_config(struct mei_device *dev)
|
|||||||
dev->ops->hw_config(dev);
|
dev->ops->hw_config(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline enum mei_pg_state mei_pg_state(struct mei_device *dev)
|
||||||
|
{
|
||||||
|
return dev->ops->pg_state(dev);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool mei_pg_is_enabled(struct mei_device *dev)
|
static inline bool mei_pg_is_enabled(struct mei_device *dev)
|
||||||
{
|
{
|
||||||
return dev->ops->pg_is_enabled(dev);
|
return dev->ops->pg_is_enabled(dev);
|
||||||
|
Loading…
Reference in New Issue
Block a user