On Tue, Feb 9, 2016 at 8:40 AM, Mathieu Poirier <mathieu.poirier@xxxxxxxxxx> wrote: > On 8 February 2016 at 15:04, Duc Dang <dhdang@xxxxxxx> wrote: >> X-Gene mailbox controller provides 8 mailbox channels, with >> each channel has a dedicated interrupt line. >> >> Signed-off-by: Feng Kan <fkan@xxxxxxx> >> Signed-off-by: Duc Dang <dhdang@xxxxxxx> >> --- >> Changes since v4: >> - Rebase over v4.5-rc1 >> - Fix section mistmatch warning by removing >> __init in slimpro_mbox_probe declaration >> - Correctly print channel number when >> there is no IRQ for that channel >> >> Changes since v3: >> - Rebase over v4.4 >> - Remove 'id' in slimpro_mbox_chan structure >> - Remove small functions that are only called once >> and fold them into the other callers >> - Remove void* pointer type cast >> - Relax the number of mailbox IRQs condition >> - Use subsys_initcall to guarantee mailbox driver >> will be registered before any other dependent driver >> is loaded. >> >> drivers/mailbox/Kconfig | 9 ++ >> drivers/mailbox/Makefile | 2 + >> drivers/mailbox/mailbox-xgene-slimpro.c | 264 ++++++++++++++++++++++++++++++++ >> 3 files changed, 275 insertions(+) >> create mode 100644 drivers/mailbox/mailbox-xgene-slimpro.c >> >> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig >> index 546d05f..678e434 100644 >> --- a/drivers/mailbox/Kconfig >> +++ b/drivers/mailbox/Kconfig >> @@ -85,4 +85,13 @@ config MAILBOX_TEST >> Test client to help with testing new Controller driver >> implementations. >> >> +config XGENE_SLIMPRO_MBOX >> + tristate "APM SoC X-Gene SLIMpro Mailbox Controller" >> + depends on ARCH_XGENE >> + help >> + An implementation of the APM X-Gene Interprocessor Communication >> + Mailbox (IPCM) between the ARM 64-bit cores and SLIMpro controller. >> + It is used to send short messages between ARM64-bit cores and >> + the SLIMpro Management Engine, primarily for PM. Say Y here if you >> + want to use the APM X-Gene SLIMpro IPCM support. >> endif >> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile >> index 92435ef..b602ef8 100644 >> --- a/drivers/mailbox/Makefile >> +++ b/drivers/mailbox/Makefile >> @@ -17,3 +17,5 @@ obj-$(CONFIG_ALTERA_MBOX) += mailbox-altera.o >> obj-$(CONFIG_BCM2835_MBOX) += bcm2835-mailbox.o >> >> obj-$(CONFIG_STI_MBOX) += mailbox-sti.o >> + >> +obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o >> diff --git a/drivers/mailbox/mailbox-xgene-slimpro.c b/drivers/mailbox/mailbox-xgene-slimpro.c >> new file mode 100644 >> index 0000000..0ea1eb8 >> --- /dev/null >> +++ b/drivers/mailbox/mailbox-xgene-slimpro.c >> @@ -0,0 +1,264 @@ >> +/* >> + * APM X-Gene SLIMpro MailBox Driver >> + * >> + * Copyright (c) 2015, Applied Micro Circuits Corporation >> + * Author: Feng Kan fkan@xxxxxxx >> + * >> + * This program is free software; you can redistribute it and/or >> + * modify it under the terms of the GNU General Public License as >> + * published by the Free Software Foundation; either version 2 of >> + * the License, or (at your option) any later version. >> + * >> + * This program is distributed in the hope that 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. >> + * >> + * You should have received a copy of the GNU General Public License >> + * along with this program; if not, see <http://www.gnu.org/licenses/>. >> + * >> + */ >> +#include <linux/acpi.h> >> +#include <linux/delay.h> >> +#include <linux/interrupt.h> >> +#include <linux/io.h> >> +#include <linux/mailbox_controller.h> >> +#include <linux/module.h> >> +#include <linux/of.h> >> +#include <linux/platform_device.h> >> +#include <linux/spinlock.h> >> + >> +#define MBOX_CON_NAME "slimpro-mbox" >> +#define MBOX_REG_SET_OFFSET 0x1000 >> +#define MBOX_CNT 8 >> +#define MBOX_STATUS_AVAIL_MASK BIT(16) >> +#define MBOX_STATUS_ACK_MASK BIT(0) >> + >> +/* Configuration and Status Registers */ >> +#define REG_DB_IN 0x00 >> +#define REG_DB_DIN0 0x04 >> +#define REG_DB_DIN1 0x08 >> +#define REG_DB_OUT 0x10 >> +#define REG_DB_DOUT0 0x14 >> +#define REG_DB_DOUT1 0x18 >> +#define REG_DB_STAT 0x20 >> +#define REG_DB_STATMASK 0x24 >> + >> +struct slimpro_mbox_chan { >> + struct device *dev; >> + struct mbox_chan *chan; >> + void __iomem *reg; >> + int irq; >> + u32 rx_msg[3]; >> +}; >> + >> +struct slimpro_mbox { >> + struct mbox_controller mb_ctrl; >> + struct slimpro_mbox_chan mc[MBOX_CNT]; >> + struct mbox_chan chans[MBOX_CNT]; >> +}; > > The above two structure declaration could use kernel style documentation. Can you please clarify or give an example? I looked into several files in drivers/mailbox/ and drivers/irqchip but could not find what I need to tweak. > >> + >> +static void mb_chan_send_msg(struct slimpro_mbox_chan *mb_chan, u32 *msg) >> +{ >> + writel(msg[1], mb_chan->reg + REG_DB_DOUT0); >> + writel(msg[2], mb_chan->reg + REG_DB_DOUT1); >> + writel(msg[0], mb_chan->reg + REG_DB_OUT); >> +} >> + >> +static void mb_chan_recv_msg(struct slimpro_mbox_chan *mb_chan) >> +{ >> + mb_chan->rx_msg[1] = readl(mb_chan->reg + REG_DB_DIN0); >> + mb_chan->rx_msg[2] = readl(mb_chan->reg + REG_DB_DIN1); >> + mb_chan->rx_msg[0] = readl(mb_chan->reg + REG_DB_IN); >> +} > > Is there a requirement that operations in the above two functions be > ordered? If not significant gains could be achieved by using > writel/readl_relaxed(). Same comment for the rest of this driver. The 'writes' need to be in order as writing to REG_DB_OUT will trigger interrupt, so I want the other 2 'writes' complete before it. After the receiver get the message, it will clear door bell available interrupt request, this will also trigger a door bell acknowledge interrupt. So the 'read' to get the message and the 'write' to clear the door bell available interrupt must be in order as well. Regards, Duc Dang. > > Thanks, > Mathieu > >> + >> +static int mb_chan_status_ack(struct slimpro_mbox_chan *mb_chan) >> +{ >> + u32 val = readl(mb_chan->reg + REG_DB_STAT); >> + >> + if (val & MBOX_STATUS_ACK_MASK) { >> + writel(MBOX_STATUS_ACK_MASK, mb_chan->reg + REG_DB_STAT); >> + return 1; >> + } >> + return 0; >> +} >> + >> +static int mb_chan_status_avail(struct slimpro_mbox_chan *mb_chan) >> +{ >> + u32 val = readl(mb_chan->reg + REG_DB_STAT); >> + >> + if (val & MBOX_STATUS_AVAIL_MASK) { >> + mb_chan_recv_msg(mb_chan); >> + writel(MBOX_STATUS_AVAIL_MASK, mb_chan->reg + REG_DB_STAT); >> + return 1; >> + } >> + return 0; >> +} >> + >> +static irqreturn_t slimpro_mbox_irq(int irq, void *id) >> +{ >> + struct slimpro_mbox_chan *mb_chan = id; >> + >> + if (mb_chan_status_ack(mb_chan)) >> + mbox_chan_txdone(mb_chan->chan, 0); >> + >> + if (mb_chan_status_avail(mb_chan)) >> + mbox_chan_received_data(mb_chan->chan, mb_chan->rx_msg); >> + >> + return IRQ_HANDLED; >> +} >> + >> +static int slimpro_mbox_send_data(struct mbox_chan *chan, void *msg) >> +{ >> + struct slimpro_mbox_chan *mb_chan = chan->con_priv; >> + >> + mb_chan_send_msg(mb_chan, msg); >> + return 0; >> +} >> + >> +static int slimpro_mbox_startup(struct mbox_chan *chan) >> +{ >> + struct slimpro_mbox_chan *mb_chan = chan->con_priv; >> + int rc; >> + u32 val; >> + >> + rc = devm_request_irq(mb_chan->dev, mb_chan->irq, slimpro_mbox_irq, 0, >> + MBOX_CON_NAME, mb_chan); >> + if (unlikely(rc)) { >> + dev_err(mb_chan->dev, "failed to register mailbox interrupt %d\n", >> + mb_chan->irq); >> + return rc; >> + } >> + >> + /* Enable HW interrupt */ >> + writel(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK, >> + mb_chan->reg + REG_DB_STAT); >> + /* Unmask doorbell status interrupt */ >> + val = readl(mb_chan->reg + REG_DB_STATMASK); >> + val &= ~(MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK); >> + writel(val, mb_chan->reg + REG_DB_STATMASK); >> + >> + return 0; >> +} >> + >> +static void slimpro_mbox_shutdown(struct mbox_chan *chan) >> +{ >> + struct slimpro_mbox_chan *mb_chan = chan->con_priv; >> + u32 val; >> + >> + /* Mask doorbell status interrupt */ >> + val = readl(mb_chan->reg + REG_DB_STATMASK); >> + val |= (MBOX_STATUS_ACK_MASK | MBOX_STATUS_AVAIL_MASK); >> + writel(val, mb_chan->reg + REG_DB_STATMASK); >> + >> + devm_free_irq(mb_chan->dev, mb_chan->irq, mb_chan); >> +} >> + >> +static struct mbox_chan_ops slimpro_mbox_ops = { >> + .send_data = slimpro_mbox_send_data, >> + .startup = slimpro_mbox_startup, >> + .shutdown = slimpro_mbox_shutdown, >> +}; >> + >> +static int slimpro_mbox_probe(struct platform_device *pdev) >> +{ >> + struct slimpro_mbox *ctx; >> + struct resource *regs; >> + void __iomem *mb_base; >> + int rc; >> + int i; >> + >> + ctx = devm_kzalloc(&pdev->dev, sizeof(struct slimpro_mbox), GFP_KERNEL); >> + if (IS_ERR(ctx)) >> + return PTR_ERR(ctx); >> + >> + platform_set_drvdata(pdev, ctx); >> + >> + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> + mb_base = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); >> + if (IS_ERR(mb_base)) >> + return PTR_ERR(mb_base); >> + >> + /* Setup mailbox links */ >> + for (i = 0; i < MBOX_CNT; i++) { >> + ctx->mc[i].irq = platform_get_irq(pdev, i); >> + if (ctx->mc[i].irq < 0) { >> + if (i == 0) { >> + dev_err(&pdev->dev, "no available IRQ\n"); >> + return -EINVAL; >> + } >> + dev_info(&pdev->dev, "no IRQ for channel %d\n", i); >> + break; >> + } >> + >> + ctx->mc[i].dev = &pdev->dev; >> + ctx->mc[i].reg = mb_base + i * MBOX_REG_SET_OFFSET; >> + ctx->mc[i].chan = &ctx->chans[i]; >> + ctx->chans[i].con_priv = &ctx->mc[i]; >> + } >> + >> + /* Setup mailbox controller */ >> + ctx->mb_ctrl.dev = &pdev->dev; >> + ctx->mb_ctrl.chans = ctx->chans; >> + ctx->mb_ctrl.txdone_irq = true; >> + ctx->mb_ctrl.ops = &slimpro_mbox_ops; >> + ctx->mb_ctrl.num_chans = i; >> + >> + rc = mbox_controller_register(&ctx->mb_ctrl); >> + if (rc) { >> + dev_err(&pdev->dev, >> + "APM X-Gene SLIMpro MailBox register failed:%d\n", rc); >> + return rc; >> + } >> + >> + dev_info(&pdev->dev, "APM X-Gene SLIMpro MailBox registered\n"); >> + return 0; >> +} >> + >> +static int slimpro_mbox_remove(struct platform_device *pdev) >> +{ >> + struct slimpro_mbox *smb = platform_get_drvdata(pdev); >> + >> + mbox_controller_unregister(&smb->mb_ctrl); >> + return 0; >> +} >> + >> +static const struct of_device_id slimpro_of_match[] = { >> + {.compatible = "apm,xgene-slimpro-mbox" }, >> + { }, >> +}; >> +MODULE_DEVICE_TABLE(of, slimpro_of_match); >> + >> +#ifdef CONFIG_ACPI >> +static const struct acpi_device_id slimpro_acpi_ids[] = { >> + {"APMC0D01", 0}, >> + {} >> +}; >> +MODULE_DEVICE_TABLE(acpi, slimpro_acpi_ids); >> +#endif >> + >> +static struct platform_driver slimpro_mbox_driver = { >> + .probe = slimpro_mbox_probe, >> + .remove = slimpro_mbox_remove, >> + .driver = { >> + .name = "xgene-slimpro-mbox", >> + .of_match_table = of_match_ptr(slimpro_of_match), >> + .acpi_match_table = ACPI_PTR(slimpro_acpi_ids) >> + }, >> +}; >> + >> +static int __init slimpro_mbox_init(void) >> +{ >> + return platform_driver_register(&slimpro_mbox_driver); >> +} >> + >> +static void __exit slimpro_mbox_exit(void) >> +{ >> + platform_driver_unregister(&slimpro_mbox_driver); >> +} >> + >> +subsys_initcall(slimpro_mbox_init); >> +module_exit(slimpro_mbox_exit); >> + >> +MODULE_DESCRIPTION("APM X-Gene SLIMpro Mailbox Driver"); >> +MODULE_LICENSE("GPL"); >> -- >> 1.9.1 >> -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html