Read interrupt and port values from the device tree, setup IRQ mapping and register IRQ for each VAS instance. Set port value for each NX window. When NX sees a fault on CRB, kernel gets an interrupt and handles the fault. IRQ setup and fault handling is needed only for user space send windows. So for kernel requests, ignore if interrupts property is not available. Signed-off-by: Sukadev Bhattiprolu <sukadev@xxxxxxxxxxxxxxxxxx> Signed-off-by: Haren Myneni <haren@xxxxxxxxxx> --- arch/powerpc/platforms/powernv/vas-window.c | 14 ++++++ arch/powerpc/platforms/powernv/vas.c | 68 ++++++++++++++++++++++++++--- arch/powerpc/platforms/powernv/vas.h | 2 + 3 files changed, 78 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/powernv/vas-window.c b/arch/powerpc/platforms/powernv/vas-window.c index ea5ca02..ad6be91 100644 --- a/arch/powerpc/platforms/powernv/vas-window.c +++ b/arch/powerpc/platforms/powernv/vas-window.c @@ -758,6 +758,8 @@ static void init_winctx_for_rxwin(struct vas_window *rxwin, winctx->min_scope = VAS_SCOPE_LOCAL; winctx->max_scope = VAS_SCOPE_VECTORED_GROUP; + if (rxwin->vinst->virq) + winctx->irq_port = rxwin->vinst->irq_port; } static bool rx_win_args_valid(enum vas_cop_type cop, @@ -959,6 +961,8 @@ static void init_winctx_for_txwin(struct vas_window *txwin, winctx->tc_mode = txattr->tc_mode; winctx->min_scope = VAS_SCOPE_LOCAL; winctx->max_scope = VAS_SCOPE_VECTORED_GROUP; + if (txwin->vinst->virq) + winctx->irq_port = txwin->vinst->irq_port; winctx->pswid = 0; } @@ -1050,6 +1054,16 @@ struct vas_window *vas_tx_win_open(int vasid, enum vas_cop_type cop, } } else { /* + * Interrupt hanlder setup failed. Means NX can not generate + * fault for page fault. So not opening for user space tx + * window. + */ + if (!vinst->virq) { + rc = -ENODEV; + goto free_window; + } + + /* * A user mapping must ensure that context switch issues * CP_ABORT for this thread. */ diff --git a/arch/powerpc/platforms/powernv/vas.c b/arch/powerpc/platforms/powernv/vas.c index ed9cc6d..71bddaa 100644 --- a/arch/powerpc/platforms/powernv/vas.c +++ b/arch/powerpc/platforms/powernv/vas.c @@ -14,6 +14,8 @@ #include <linux/of_platform.h> #include <linux/of_address.h> #include <linux/of.h> +#include <linux/irqdomain.h> +#include <linux/interrupt.h> #include <asm/prom.h> #include "vas.h" @@ -23,9 +25,33 @@ static DEFINE_PER_CPU(int, cpu_vas_id); +static irqreturn_t vas_irq_handler(int virq, void *data) +{ + struct vas_instance *vinst = data; + + pr_devel("VAS %d: virq %d\n", vinst->vas_id, virq); + + return IRQ_HANDLED; +} + +static void vas_irq_fault_handle_setup(struct vas_instance *vinst) +{ + int rc; + char devname[64]; + + snprintf(devname, sizeof(devname), "vas-inst-%d", vinst->vas_id); + rc = request_irq(vinst->virq, vas_irq_handler, 0, devname, vinst); + if (rc) { + pr_err("VAS[%d]: Request IRQ(%d) failed with %d\n", + vinst->vas_id, vinst->virq, rc); + vinst->virq = 0; + } +} + static int init_vas_instance(struct platform_device *pdev) { - int rc, cpu, vasid; + int rc, cpu, vasid, nresources = 5; + uint64_t port; struct resource *res; struct vas_instance *vinst; struct device_node *dn = pdev->dev.of_node; @@ -36,7 +62,18 @@ static int init_vas_instance(struct platform_device *pdev) return -ENODEV; } - if (pdev->num_resources != 4) { + rc = of_property_read_u64(dn, "ibm,vas-port", &port); + if (rc) { + pr_err("No ibm,vas-port property for %s?\n", pdev->name); + /* No interrupts property */ + nresources = 4; + } + + /* + * interrupts property is available with 'ibm,vas-port' property. + * 4 Resources and 1 IRQ if interrupts property is available. + */ + if (pdev->num_resources != nresources) { pr_err("Unexpected DT configuration for [%s, %d]\n", pdev->name, vasid); return -ENODEV; @@ -51,6 +88,7 @@ static int init_vas_instance(struct platform_device *pdev) mutex_init(&vinst->mutex); vinst->vas_id = vasid; vinst->pdev = pdev; + vinst->irq_port = port; res = &pdev->resource[0]; vinst->hvwc_bar_start = res->start; @@ -66,12 +104,23 @@ static int init_vas_instance(struct platform_device *pdev) pr_err("Bad 'paste_win_id_shift' in DT, %llx\n", res->end); goto free_vinst; } - vinst->paste_win_id_shift = 63 - res->end; - pr_devel("Initialized instance [%s, %d], paste_base 0x%llx, " - "paste_win_id_shift 0x%llx\n", pdev->name, vasid, - vinst->paste_base_addr, vinst->paste_win_id_shift); + /* interrupts property */ + if (pdev->num_resources == 5) { + res = &pdev->resource[4]; + vinst->virq = res->start; + if (vinst->virq <= 0) { + pr_err("IRQ resource is not available for [%s, %d]\n", + pdev->name, vasid); + vinst->virq = 0; + } + } + + pr_devel("Initialized instance [%s, %d] paste_base 0x%llx paste_win_id_shift 0x%llx IRQ %d Port 0x%llx\n", + pdev->name, vasid, vinst->paste_base_addr, + vinst->paste_win_id_shift, vinst->virq, + vinst->irq_port); for_each_possible_cpu(cpu) { if (cpu_to_chip_id(cpu) == of_get_ibm_chip_id(dn)) @@ -82,6 +131,13 @@ static int init_vas_instance(struct platform_device *pdev) list_add(&vinst->node, &vas_instances); mutex_unlock(&vas_mutex); + /* + * IRQ and fault handling setup is needed only for user space + * send windows. + */ + if (vinst->virq) + vas_irq_fault_handle_setup(vinst); + vas_instance_init_dbgdir(vinst); dev_set_drvdata(&pdev->dev, vinst); diff --git a/arch/powerpc/platforms/powernv/vas.h b/arch/powerpc/platforms/powernv/vas.h index 9cc5251..bf7d3db 100644 --- a/arch/powerpc/platforms/powernv/vas.h +++ b/arch/powerpc/platforms/powernv/vas.h @@ -313,6 +313,8 @@ struct vas_instance { u64 paste_base_addr; u64 paste_win_id_shift; + u64 irq_port; + int virq; struct mutex mutex; struct vas_window *rxwin[VAS_COP_TYPE_MAX]; struct vas_window *windows[VAS_WINDOWS_PER_CHIP]; -- 1.8.3.1