ipm: quark_se: fix dropped/repeating characters
The while loop on the status bit was unnecessary as we will get a separate invocation of the ISR for every message. We also ensure that the global status register bits for the channel being serviced are cleared before exiting. Fixes an issue where some messages would be dropped or repeated. Some runtime checks that shouldn't happen in practice have been moved to assertions. Change-Id: Iedd28ae15522c7b9f59ef34fa9fa8b4e24e6be14 Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
4d3e120109
commit
08d3cd7bfd
1 changed files with 26 additions and 31 deletions
|
@ -41,26 +41,6 @@ static uint32_t quark_se_ipm_sts_get(void)
|
|||
return sys_read32(QUARK_SE_IPM_CHALL_STS) & inbound_channels;
|
||||
}
|
||||
|
||||
static void mailbox_handle(struct device *d)
|
||||
{
|
||||
struct quark_se_ipm_config_info *config;
|
||||
struct quark_se_ipm_driver_data *driver_data;
|
||||
volatile struct quark_se_ipm *ipm;
|
||||
|
||||
config = d->config->config_info;
|
||||
driver_data = d->driver_data;
|
||||
ipm = config->ipm;
|
||||
|
||||
if (driver_data->callback) {
|
||||
driver_data->callback(driver_data->callback_ctx,
|
||||
ipm->ctrl.ctrl, &ipm->data);
|
||||
}
|
||||
|
||||
ipm->sts.irq = 1; /* Clear the interrupt bit */
|
||||
ipm->sts.sts = 1; /* Clear channel status bit */
|
||||
}
|
||||
|
||||
|
||||
static void set_channel_irq_state(int channel, int enable)
|
||||
{
|
||||
mem_addr_t addr = QUARK_SE_IPM_MASK;
|
||||
|
@ -80,21 +60,36 @@ void quark_se_ipm_isr(void *param)
|
|||
int channel;
|
||||
int sts, bit;
|
||||
struct device *d;
|
||||
struct quark_se_ipm_config_info *config;
|
||||
struct quark_se_ipm_driver_data *driver_data;
|
||||
volatile struct quark_se_ipm *ipm;
|
||||
|
||||
ARG_UNUSED(param);
|
||||
sts = quark_se_ipm_sts_get();
|
||||
do {
|
||||
bit = find_msb_set(sts) - 1 ;
|
||||
channel = bit / 2;
|
||||
if (sts) {
|
||||
d = device_by_channel[channel];
|
||||
if (d) {
|
||||
mailbox_handle(d);
|
||||
}
|
||||
sts &= ~(0x1 << (bit));
|
||||
}
|
||||
} while (sts);
|
||||
|
||||
__ASSERT(sts, "spurious IPM interrupt");
|
||||
bit = find_msb_set(sts) - 1;
|
||||
channel = bit / 2;
|
||||
d = device_by_channel[channel];
|
||||
|
||||
__ASSERT(d, "got IRQ on channel with no IPM device");
|
||||
config = d->config->config_info;
|
||||
driver_data = d->driver_data;
|
||||
ipm = config->ipm;
|
||||
|
||||
__ASSERT(driver_data->callback, "enabled IPM channel with no callback");
|
||||
driver_data->callback(driver_data->callback_ctx, ipm->ctrl.ctrl,
|
||||
&ipm->data);
|
||||
|
||||
ipm->sts.irq = 1; /* Clear the interrupt bit */
|
||||
ipm->sts.sts = 1; /* Clear channel status bit */
|
||||
|
||||
/* Wait for the above register writes to clear the channel
|
||||
* to propagate to the global channel status register
|
||||
*/
|
||||
while (quark_se_ipm_sts_get() & (0x3 << (channel * 2))) {
|
||||
/* Busy-wait */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue