ipi: rename to ipm

To many people, IPI connotes inter-processor interrupts on SMP
systems. Rename this to IPM, or Inter-Processor Mailboxes.

Change-Id: I032815e23c69a8297c0a43992132441c240fb71e
Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2015-11-12 14:00:47 -08:00 committed by Anas Nashif
commit 3589695508
38 changed files with 614 additions and 596 deletions

24
drivers/ipm/Kconfig Normal file
View file

@ -0,0 +1,24 @@
menuconfig IPM
bool
prompt "IPM drivers"
default n
help
Include interrupt-based inter-processor mailboxes
drivers in system configuration
config IPM_QUARK_SE
bool "Quark SE IPM driver"
default n
depends on IPM
help
Driver for Quark SE mailboxes
config IPM_QUARK_SE_MASTER
bool "Quark SE IPM master controller"
default n
depends on IPM_QUARK_SE
help
Enable this for the first CPU that initializes IPM.
Sets up the initial interrupt mask and clears out all
channels. Should be turned on for one CPU only.

4
drivers/ipm/Makefile Normal file
View file

@ -0,0 +1,4 @@
ccflags-y += -I$(srctree/drivers)
obj-$(CONFIG_IPM_QUARK_SE) += ipm_quark_se.o ipm_static_irq_stubs.o

243
drivers/ipm/ipm_quark_se.c Normal file
View file

@ -0,0 +1,243 @@
/* ipm_quark_se.c - Quark SE mailbox driver */
/*
* Copyright (c) 2015 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <nanokernel.h>
#include <stdint.h>
#include <string.h>
#include <device.h>
#include <init.h>
#include <ipm.h>
#include <arch/cpu.h>
#include <misc/printk.h>
#include <misc/__assert.h>
#include <errno.h>
#include "ipm_quark_se.h"
/* We have a single ISR for all channels, so in order to properly handle
* messages we need to figure out which device object corresponds to
* in incoming channel
*/
static struct device *device_by_channel[QUARK_SE_IPM_CHANNELS];
static uint32_t inbound_channels;
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;
int bit = channel + QUARK_SE_IPM_MASK_START_BIT;
if (enable) {
sys_clear_bit(addr, bit);
} else {
sys_set_bit(addr, bit);
}
}
/* Interrupt handler, gets messages on all incoming enabled mailboxes */
void quark_se_ipm_isr(void *param)
{
int channel;
int sts;
struct device *d;
ARG_UNUSED(param);
/* Find out which mailbox channel has an incoming message */
while (1) {
sts = quark_se_ipm_sts_get();
/* FIXME: for every message sent, there are two interrupts
* generated, the second has empty sts. Probably an IRQ
* triggering issue
*/
if (!sts) {
break;
}
channel = (find_msb_set(sts) - 1) / 2;
d = device_by_channel[channel];
if (d) {
mailbox_handle(d);
}
}
}
static int quark_se_ipm_send(struct device *d, int wait, uint32_t id,
const void *data, int size)
{
struct quark_se_ipm_config_info *config = d->config->config_info;
volatile struct quark_se_ipm *ipm = config->ipm;
const uint8_t *data8;
int i;
int flags;
if (id > QUARK_SE_IPM_MAX_ID_VAL) {
return -EINVAL;
}
if (config->direction != QUARK_SE_IPM_OUTBOUND) {
return -EINVAL;
}
if (size > QUARK_SE_IPM_DATA_BYTES) {
return -EMSGSIZE;
}
flags = irq_lock();
if (ipm->sts.sts != 0) {
irq_unlock(flags);
return -EBUSY;
}
/* Populate the data, memcpy doesn't take volatiles */
data8 = (const uint8_t *)data;
for (i = 0; i < size; ++i) {
ipm->data[i] = data8[i];
}
ipm->ctrl.ctrl = id;
/* Cause the interrupt to assert on the remote side */
ipm->ctrl.irq = 1;
/* Wait for HW to set the sts bit */
while (ipm->sts.sts == 0) {
}
if (wait) {
/* Loop until remote clears the status bit */
while (ipm->sts.sts != 0) {
}
}
irq_unlock(flags);
return 0;
}
static int quark_se_ipm_max_data_size_get(struct device *d)
{
ARG_UNUSED(d);
return QUARK_SE_IPM_DATA_BYTES;
}
static uint32_t quark_se_ipm_max_id_val_get(struct device *d)
{
ARG_UNUSED(d);
return QUARK_SE_IPM_MAX_ID_VAL;
}
static void quark_se_ipm_register_callback(struct device *d, ipm_callback_t cb,
void *context)
{
struct quark_se_ipm_driver_data *driver_data = d->driver_data;
driver_data->callback = cb;
driver_data->callback_ctx = context;
}
static int quark_se_ipm_set_enabled(struct device *d, int enable)
{
struct quark_se_ipm_config_info *config_info = d->config->config_info;
if (config_info->direction != QUARK_SE_IPM_INBOUND) {
return -EINVAL;
}
set_channel_irq_state(config_info->channel, enable);
return 0;
}
static struct ipm_driver_api api_funcs = {
.send = quark_se_ipm_send,
.register_callback = quark_se_ipm_register_callback,
.max_data_size_get = quark_se_ipm_max_data_size_get,
.max_id_val_get = quark_se_ipm_max_id_val_get,
.set_enabled = quark_se_ipm_set_enabled
};
int quark_se_ipm_controller_initialize(struct device *d)
{
struct quark_se_ipm_controller_config_info *config = d->config->config_info;
#if CONFIG_IPM_QUARK_SE_MASTER
int i;
/* Mask all mailbox interrupts, we'll enable them
* individually later. Clear out any pending messages
*/
sys_write32(0xFFFFFFFF, QUARK_SE_IPM_MASK);
for (i = 0; i < QUARK_SE_IPM_CHANNELS; ++i) {
volatile struct quark_se_ipm *ipm = QUARK_SE_IPM(i);
ipm->sts.sts = 0;
ipm->sts.irq = 0;
}
#endif
if (config->controller_init) {
return config->controller_init();
}
return DEV_OK;
}
int quark_se_ipm_initialize(struct device *d)
{
struct quark_se_ipm_config_info *config = d->config->config_info;
device_by_channel[config->channel] = d;
d->driver_api = &api_funcs;
if (config->direction == QUARK_SE_IPM_INBOUND) {
inbound_channels |= (0x3 << (config->channel * 2));
}
return DEV_OK;
}

143
drivers/ipm/ipm_quark_se.h Normal file
View file

@ -0,0 +1,143 @@
/* ipm_quark_se.h - Quark SE mailbox driver */
/*
* Copyright (c) 2015 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __INCquark_se_mailboxh
#define __INCquark_se_mailboxh
#include <nanokernel.h>
#include <board.h> /* for SCSS_REGISTER_BASE */
#include <ipm.h>
#include <device.h>
#include <init.h>
#define QUARK_SE_IPM_OUTBOUND 0
#define QUARK_SE_IPM_INBOUND 1
#if defined(CONFIG_PLATFORM_QUARK_SE)
/* First byte of the QUARK_SE_IPM_MASK register is for the Lakemont */
#define QUARK_SE_IPM_MASK_START_BIT 0
#define QUARK_SE_IPM_INTERRUPT 21
#define QUARK_SE_IPM_ARC_LMT_DIR QUARK_SE_IPM_INBOUND
#define QUARK_SE_IPM_LMT_ARC_DIR QUARK_SE_IPM_OUTBOUND
#elif defined(CONFIG_PLATFORM_QUARK_SE_SS)
/* Second byte is for ARC */
#define QUARK_SE_IPM_MASK_START_BIT 8
#define QUARK_SE_IPM_INTERRUPT 57
#define QUARK_SE_IPM_ARC_LMT_DIR QUARK_SE_IPM_OUTBOUND
#define QUARK_SE_IPM_LMT_ARC_DIR QUARK_SE_IPM_INBOUND
#else
#error "Unsupported platform for ipm_quark_se driver"
#endif
#define QUARK_SE_IPM_CHANNELS 8
#define QUARK_SE_IPM_DATA_BYTES (4 * sizeof(uint32_t))
#define QUARK_SE_IPM_MAX_ID_VAL 0x7FFFFFFF
/* QUARK_SE EAS section 28.5.1.123 */
struct __packed quark_se_ipm_ch_ctrl {
uint32_t ctrl : 31;
uint32_t irq : 1;
};
struct __packed quark_se_ipm_ch_sts {
uint32_t sts : 1;
uint32_t irq : 1;
uint32_t reserved : 30;
};
struct __packed quark_se_ipm {
struct quark_se_ipm_ch_ctrl ctrl;
uint8_t data[QUARK_SE_IPM_DATA_BYTES]; /* contiguous 32-bit registers */
struct quark_se_ipm_ch_sts sts;
};
/* Base address for mailboxes
*
* Layout:
*
* quark_se_ipm[8]
* QUARK_SE_IPM_CHALL_STS
*/
#define QUARK_SE_IPM_BASE (SCSS_REGISTER_BASE + 0xa00)
/* 28.5.1.73 Host processor Interrupt routing mask 21
*
* Bits Description
* 31:24 Mailbox SS Halt interrupt maskIUL
* 23:16 Mailbox Host Halt interrupt mask
* 15:8 Mailbox SS interrupt mask
* 7:0 Mailbox Host interrupt mask
*/
#define QUARK_SE_IPM_MASK (SCSS_REGISTER_BASE + 0x4a0)
/* All status bits of the mailboxes
*
* Bits Description
* 31:16 Reserved
* 15:0 CHn_STS bits (sts/irq) for all channels
*/
#define QUARK_SE_IPM_CHALL_STS (SCSS_REGISTER_BASE + 0x0AC0)
#define QUARK_SE_IPM(channel) ((volatile struct quark_se_ipm *)(QUARK_SE_IPM_BASE + \
((channel) * sizeof(struct quark_se_ipm))))
/* XXX I pulled this number out of thin air -- how to choose
* the right priority?
*/
#define QUARK_SE_IPM_INTERRUPT_PRI 2
struct quark_se_ipm_controller_config_info {
int (*controller_init)(void);
};
struct quark_se_ipm_config_info {
int channel;
int direction;
volatile struct quark_se_ipm *ipm;
};
struct quark_se_ipm_driver_data {
ipm_callback_t callback;
void *callback_ctx;
};
void quark_se_ipm_isr(void *param);
int quark_se_ipm_initialize(struct device *d);
int quark_se_ipm_controller_initialize(struct device *d);
#define QUARK_SE_IPM_DEFINE(name, ch, dir) \
struct quark_se_ipm_config_info quark_se_ipm_config_##name = { \
.ipm = QUARK_SE_IPM(ch), \
.channel = ch, \
.direction = dir \
}; \
struct quark_se_ipm_driver_data quark_se_ipm_runtime_##name; \
DECLARE_DEVICE_INIT_CONFIG(name, _STRINGIFY(name), \
quark_se_ipm_initialize, \
&quark_se_ipm_config_##name); \
SYS_DEFINE_DEVICE(name, &quark_se_ipm_runtime_##name, SECONDARY, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT)
#endif /* __INCquark_se_mailboxh */

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2015, Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _ASMLANGUAGE
#ifdef CONFIG_X86
#include <arch/x86/asm.h>
#include <drivers/ioapic.h>
#endif
#if defined(CONFIG_IPM_QUARK_SE)
#if defined(CONFIG_IOAPIC)
ioapic_mkstub quark_se_ipm quark_se_ipm_isr 0
#endif
#endif