Staging: heci: fix setting h_is bit in h_csr register
Host software could issue interrupts to ME firmware, using H_IG bit. While Setting H_IG bit, host software should preserve all the other bits in H_CSR unchanged. In the original function which sets H_CSR register, they first read the register, then set some bits, and write the whole 32bits back to the register. And that the special behavior of H_IS (write-one-to-zero) causes problem. This patch fixes the issue in the following ways: - Modify heci_set_csr_register() function so that it doesn't change H_IS bit. - Add interface heci_csr_clear_his() to clear H_IS bit. This function is called after H_IS checking (dev->host_hw_state & H_IS == H_IS). - In original heci_csr_disable_interrupts() function, it not only clears H_IE bit, sometimes it also clears H_IS bit. This patch separates the two parts. - Avoid calling write_heci_register() function to set H_CSR register directly, and instead using heci_set_csr_register() function Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
52b855600c
commit
ad914a3ec5
|
@ -249,7 +249,7 @@ int heci_hw_init(struct iamt_heci_device *dev)
|
|||
|
||||
if ((dev->host_hw_state & H_IS) == H_IS) {
|
||||
/* acknowledge interrupt and stop interupts */
|
||||
heci_set_csr_register(dev);
|
||||
heci_csr_clear_his(dev);
|
||||
}
|
||||
dev->recvd_msg = 0;
|
||||
DBG("reset in start the heci device.\n");
|
||||
|
@ -354,7 +354,7 @@ void heci_reset(struct iamt_heci_device *dev, int interrupts)
|
|||
dev->host_hw_state &= ~H_RST;
|
||||
dev->host_hw_state |= H_IG;
|
||||
|
||||
write_heci_register(dev, H_CSR, dev->host_hw_state);
|
||||
heci_set_csr_register(dev);
|
||||
|
||||
DBG("currently saved host_hw_state = 0x%08x.\n",
|
||||
dev->host_hw_state);
|
||||
|
|
|
@ -44,12 +44,15 @@
|
|||
|
||||
|
||||
/**
|
||||
* heci_set_csr_register - write H_CSR register to the heci device
|
||||
* heci_set_csr_register - write H_CSR register to the heci device,
|
||||
* and ignore the H_IS bit for it is write-one-to-zero.
|
||||
*
|
||||
* @dev: device object for our driver
|
||||
*/
|
||||
void heci_set_csr_register(struct iamt_heci_device *dev)
|
||||
{
|
||||
if ((dev->host_hw_state & H_IS) == H_IS)
|
||||
dev->host_hw_state &= ~H_IS;
|
||||
write_heci_register(dev, H_CSR, dev->host_hw_state);
|
||||
dev->host_hw_state = read_heci_register(dev, H_CSR);
|
||||
}
|
||||
|
@ -76,6 +79,16 @@ void heci_csr_disable_interrupts(struct iamt_heci_device *dev)
|
|||
heci_set_csr_register(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* heci_csr_clear_his - clear H_IS bit in H_CSR
|
||||
*
|
||||
* @dev: device object for our driver
|
||||
*/
|
||||
void heci_csr_clear_his(struct iamt_heci_device *dev)
|
||||
{
|
||||
write_heci_register(dev, H_CSR, dev->host_hw_state);
|
||||
dev->host_hw_state = read_heci_register(dev, H_CSR);
|
||||
}
|
||||
|
||||
/**
|
||||
* _host_get_filled_slots - get number of device filled buffer slots
|
||||
|
@ -185,7 +198,7 @@ int heci_write_message(struct iamt_heci_device *dev,
|
|||
}
|
||||
|
||||
dev->host_hw_state |= H_IG;
|
||||
write_heci_register(dev, H_CSR, dev->host_hw_state);
|
||||
heci_set_csr_register(dev);
|
||||
dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
|
||||
if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
|
||||
return 0;
|
||||
|
|
|
@ -133,6 +133,7 @@ enum client_disconnect_status_types{
|
|||
void heci_set_csr_register(struct iamt_heci_device *dev);
|
||||
void heci_csr_enable_interrupts(struct iamt_heci_device *dev);
|
||||
void heci_csr_disable_interrupts(struct iamt_heci_device *dev);
|
||||
void heci_csr_clear_his(struct iamt_heci_device *dev);
|
||||
|
||||
void heci_read_slots(struct iamt_heci_device *dev,
|
||||
unsigned char *buffer, unsigned long buffer_length);
|
||||
|
|
|
@ -92,6 +92,9 @@ irqreturn_t heci_isr_interrupt(int irq, void *dev_id)
|
|||
/* disable interrupts */
|
||||
heci_csr_disable_interrupts(dev);
|
||||
|
||||
/* clear H_IS bit in H_CSR */
|
||||
heci_csr_clear_his(dev);
|
||||
|
||||
/*
|
||||
* Our device interrupted, schedule work the heci_bh_handler
|
||||
* to handle the interrupt processing. This needs to be a
|
||||
|
@ -251,6 +254,9 @@ end:
|
|||
/* acknowledge interrupt and disable interrupts */
|
||||
heci_csr_disable_interrupts(dev);
|
||||
|
||||
/* clear H_IS bit in H_CSR */
|
||||
heci_csr_clear_his(dev);
|
||||
|
||||
PREPARE_WORK(&dev->work, heci_bh_handler);
|
||||
DBG("schedule work the heci_bh_handler.\n");
|
||||
rets = schedule_work(&dev->work);
|
||||
|
|
Loading…
Reference in New Issue