Received: by 2002:a05:6a10:22f:0:0:0:0 with SMTP id 15csp79325pxk; Wed, 30 Sep 2020 18:31:16 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxwe4aMzd4+gWjW1tdLADKoe04IdCtTSsuXaG3Jvg1S40A59ghH5uilkewRTXHFvtyVFUOP X-Received: by 2002:a05:6402:6c1:: with SMTP id n1mr5866645edy.215.1601515876432; Wed, 30 Sep 2020 18:31:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1601515876; cv=none; d=google.com; s=arc-20160816; b=rRggmj4gZBUNHLcUER7NE/sNTXyD+lI6d+p2eEkrpaleCORYjOqP5OOvQFqYPmksrE VXKblj8Ko8jU3qr7mKBw0usPvTvByU/JJHGB0bw7STgzPMhA2QO898Rv+J5I0ifKiPds L8DtEf7XJ9ewOHwXr8eUuML0XuwCKF5FeTTwtsT5lBMhsZHPYijWZ3vIukP9CYId4IN0 +HwXb8JbBBFL+XecTKxs8vXmLl2wE6LkH70H46xjH8xwHRXvpj3er9A249oalGpOyAic ZQWcQkUWrdtF5VrB8gAG4e/ETJi5FnMpMxoU5o4b/bLHdxCYUA+QhY4EFmngD+zf2Pb9 bWVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :cc:to:from:dkim-signature; bh=8fJyzCxt/GO9PtsA5BOgtWuxpP3lRsySK6PZTSGsWv0=; b=CyxQchlUh+AylmGC008OzUjUcRMOwUj13OXWdyCs42wcUNmydAyQMxAZsstgM65vV9 qbojQVTO2IxPpGL/hQSyrBW3xKQrQXvkWDIY9VLqK/+e8PuhAZDhDTucTzRidtX2Y7KR PL5ehCJDfQU2j+cwEogbA9ejh6bCdjLIIK8gqvbz/vLj9dFnXbQXXhZ3xpXXUwTQS0kT nsvEUGUt3NmltmRNUrAAsnhydKnXdaP/5u0CXvT0e2euEO0nf/xx78/REhxZffxK1ak8 Hi8THZPkVwJXoaJiK5Oc1XSvJgKA583mbbRrOZLmS18jMpNQ7nuIJddf4/FhRJepln2c 31OA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@broadcom.com header.s=google header.b=LccrfY6Q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=broadcom.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id jz17si2445168ejb.504.2020.09.30.18.30.53; Wed, 30 Sep 2020 18:31:16 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@broadcom.com header.s=google header.b=LccrfY6Q; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=broadcom.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730785AbgJAB3L (ORCPT + 99 others); Wed, 30 Sep 2020 21:29:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50846 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730211AbgJAB26 (ORCPT ); Wed, 30 Sep 2020 21:28:58 -0400 Received: from mail-vs1-xe64.google.com (mail-vs1-xe64.google.com [IPv6:2607:f8b0:4864:20::e64]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9BC53C0613D1 for ; Wed, 30 Sep 2020 18:28:58 -0700 (PDT) Received: by mail-vs1-xe64.google.com with SMTP id a16so1844066vsp.12 for ; Wed, 30 Sep 2020 18:28:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=8fJyzCxt/GO9PtsA5BOgtWuxpP3lRsySK6PZTSGsWv0=; b=LccrfY6Q6noMIJFam9tLl35hiX+egbXmb0m5kkVkXZKlFx/POLWYVvOQRDbt1afn2j eiQoFIV+vxDKlS9hWfhcf57tcVCGKYLdue4Fzp+rsAVWiv7FS1xptdz8QWbhfBZAmbI1 eNWnmqeqhoZ3rTgW7DwQoLVwcl7OAN67LpxSo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=8fJyzCxt/GO9PtsA5BOgtWuxpP3lRsySK6PZTSGsWv0=; b=SDGG5aFQEj0JhiMJlir8vaO5A9nUuSv+2tW7e3fm6EV4lDDdJcaCqEPxftiTI3DX8T +Wy1vzwLXK/wnlU0LVBrKRONOPqSxuG1AWyoGldIHJA+U+MHKD5/neBluwEcvzehQeoU /44FTX8BJ2pIexInX+eHNSNxnL7JO0bM3DzUOCtHi4z7mMtVxjsfzJ55IjOazzP8Cjq4 tiCvwDBcI2Z+27k2zad2jCKQr2s7nDPNmGddnAt4ex16t5WZ7AatGXVC/uv+vUFwtD2P EH5ejznvdmcTvFnikU5iq9i4cm9bi1ywSDWgCo+sliRuCWADOMzQPFM0tG0S0VJiRnaS tj8g== X-Gm-Message-State: AOAM533Bzy63C3qItpFBifZ2hBa0gaGRomslvMZJe1jrGrbbPbtAEn7E dltLYX20o+RG3FF5lUx5MSXR2hSMt2tyT9ixX/Km22qia0xI X-Received: by 2002:a05:6102:11b:: with SMTP id z27mr3447426vsq.6.1601515737709; Wed, 30 Sep 2020 18:28:57 -0700 (PDT) Received: from lbrmn-lnxub113.broadcom.net ([192.19.228.250]) by smtp-relay.gmail.com with ESMTPS id r25sm520472vkq.14.2020.09.30.18.28.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Sep 2020 18:28:57 -0700 (PDT) X-Relaying-Domain: broadcom.com From: Scott Branden To: Arnd Bergmann , Greg Kroah-Hartman , Scott Branden Cc: Kees Cook , linux-kernel@vger.kernel.org, bcm-kernel-feedback-list@broadcom.com, Desmond Yan Subject: [PATCH v5 10/15] misc: bcm-vk: reset_pid support Date: Wed, 30 Sep 2020 18:28:05 -0700 Message-Id: <20201001012810.4172-11-scott.branden@broadcom.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201001012810.4172-1-scott.branden@broadcom.com> References: <20201001012810.4172-1-scott.branden@broadcom.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add reset support via ioctl. Kill user processes that are open when VK card is reset. If a particular PID has issued the reset request do not kill that process as it issued the ioctl. Co-developed-by: Desmond Yan Signed-off-by: Desmond Yan Signed-off-by: Scott Branden --- drivers/misc/bcm-vk/bcm_vk.h | 1 + drivers/misc/bcm-vk/bcm_vk_dev.c | 158 +++++++++++++++++++++++++++++-- drivers/misc/bcm-vk/bcm_vk_msg.c | 40 +++++++- 3 files changed, 191 insertions(+), 8 deletions(-) diff --git a/drivers/misc/bcm-vk/bcm_vk.h b/drivers/misc/bcm-vk/bcm_vk.h index 38b2bd575b97..92251a56516f 100644 --- a/drivers/misc/bcm-vk/bcm_vk.h +++ b/drivers/misc/bcm-vk/bcm_vk.h @@ -463,6 +463,7 @@ irqreturn_t bcm_vk_msgq_irqhandler(int irq, void *dev_id); irqreturn_t bcm_vk_notf_irqhandler(int irq, void *dev_id); int bcm_vk_msg_init(struct bcm_vk *vk); void bcm_vk_msg_remove(struct bcm_vk *vk); +void bcm_vk_drain_msg_on_reset(struct bcm_vk *vk); int bcm_vk_sync_msgq(struct bcm_vk *vk, bool force_sync); void bcm_vk_blk_drv_access(struct bcm_vk *vk); s32 bcm_to_h_msg_dequeue(struct bcm_vk *vk); diff --git a/drivers/misc/bcm-vk/bcm_vk_dev.c b/drivers/misc/bcm-vk/bcm_vk_dev.c index c23bfaa71a31..7fdf245b0436 100644 --- a/drivers/misc/bcm-vk/bcm_vk_dev.c +++ b/drivers/misc/bcm-vk/bcm_vk_dev.c @@ -478,7 +478,9 @@ void bcm_vk_blk_drv_access(struct bcm_vk *vk) int i; /* - * kill all the apps + * kill all the apps except for the process that is resetting. + * If not called during reset, reset_pid will be 0, and all will be + * killed. */ spin_lock(&vk->ctx_lock); @@ -489,10 +491,12 @@ void bcm_vk_blk_drv_access(struct bcm_vk *vk) struct bcm_vk_ctx *ctx; list_for_each_entry(ctx, &vk->pid_ht[i].head, node) { - dev_dbg(&vk->pdev->dev, - "Send kill signal to pid %d\n", - ctx->pid); - kill_pid(find_vpid(ctx->pid), SIGKILL, 1); + if (ctx->pid != vk->reset_pid) { + dev_dbg(&vk->pdev->dev, + "Send kill signal to pid %d\n", + ctx->pid); + kill_pid(find_vpid(ctx->pid), SIGKILL, 1); + } } } spin_unlock(&vk->ctx_lock); @@ -975,6 +979,49 @@ static long bcm_vk_load_image(struct bcm_vk *vk, return ret; } +static int bcm_vk_reset_successful(struct bcm_vk *vk) +{ + struct device *dev = &vk->pdev->dev; + u32 fw_status, reset_reason; + int ret = -EAGAIN; + + /* + * Reset could be triggered when the card in several state: + * i) in bootROM + * ii) after boot1 + * iii) boot2 running + * + * i) & ii) - no status bits will be updated. If vkboot1 + * runs automatically after reset, it will update the reason + * to be unknown reason + * iii) - reboot reason match + deinit done. + */ + fw_status = vkread32(vk, BAR_0, VK_BAR_FWSTS); + /* immediate exit if interface goes down */ + if (BCM_VK_INTF_IS_DOWN(fw_status)) { + dev_err(dev, "PCIe Intf Down!\n"); + goto reset_exit; + } + + reset_reason = (fw_status & VK_FWSTS_RESET_REASON_MASK); + if ((reset_reason == VK_FWSTS_RESET_MBOX_DB) || + (reset_reason == VK_FWSTS_RESET_UNKNOWN)) + ret = 0; + + /* + * if some of the deinit bits are set, but done + * bit is not, this is a failure if triggered while boot2 is running + */ + if ((fw_status & VK_FWSTS_DEINIT_TRIGGERED) && + !(fw_status & VK_FWSTS_RESET_DONE)) + ret = -EAGAIN; + +reset_exit: + dev_dbg(dev, "FW status = 0x%x ret %d\n", fw_status, ret); + + return ret; +} + static void bcm_to_v_reset_doorbell(struct bcm_vk *vk, u32 db_val) { vkwrite32(vk, db_val, BAR_0, VK_BAR0_RESET_DB_BASE); @@ -984,7 +1031,11 @@ static int bcm_vk_trigger_reset(struct bcm_vk *vk) { u32 i; u32 value, boot_status; + bool is_stdalone, is_boot2; + /* clean up before pressing the door bell */ + bcm_vk_drain_msg_on_reset(vk); + vkwrite32(vk, 0, BAR_1, VK_BAR1_MSGQ_DEF_RDY); /* make tag '\0' terminated */ vkwrite32(vk, 0, BAR_1, VK_BAR1_BOOT1_VER_TAG); @@ -995,6 +1046,11 @@ static int bcm_vk_trigger_reset(struct bcm_vk *vk) for (i = 0; i < VK_BAR1_SOTP_REVID_MAX; i++) vkwrite32(vk, 0, BAR_1, VK_BAR1_SOTP_REVID_ADDR(i)); + memset(&vk->card_info, 0, sizeof(vk->card_info)); + memset(&vk->peerlog_info, 0, sizeof(vk->peerlog_info)); + memset(&vk->proc_mon_info, 0, sizeof(vk->proc_mon_info)); + memset(&vk->alert_cnts, 0, sizeof(vk->alert_cnts)); + /* * When boot request fails, the CODE_PUSH_OFFSET stays persistent. * Allowing us to debug the failure. When we call reset, @@ -1015,17 +1071,103 @@ static int bcm_vk_trigger_reset(struct bcm_vk *vk) } vkwrite32(vk, value, BAR_0, BAR_CODEPUSH_SBL); + /* special reset handling */ + is_stdalone = boot_status & BOOT_STDALONE_RUNNING; + is_boot2 = (boot_status & BOOT_STATE_MASK) == BOOT2_RUNNING; + if (vk->peer_alert.flags & ERR_LOG_RAMDUMP) { + /* + * if card is in ramdump mode, it is hitting an error. Don't + * reset the reboot reason as it will contain valid info that + * is important - simply use special reset + */ + vkwrite32(vk, VK_BAR0_RESET_RAMPDUMP, BAR_0, VK_BAR_FWSTS); + return VK_BAR0_RESET_RAMPDUMP; + } else if (is_stdalone && !is_boot2) { + dev_info(&vk->pdev->dev, "Hard reset on Standalone mode"); + bcm_to_v_reset_doorbell(vk, VK_BAR0_RESET_DB_HARD); + return VK_BAR0_RESET_DB_HARD; + } + /* reset fw_status with proper reason, and press db */ vkwrite32(vk, VK_FWSTS_RESET_MBOX_DB, BAR_0, VK_BAR_FWSTS); bcm_to_v_reset_doorbell(vk, VK_BAR0_RESET_DB_SOFT); - /* clear other necessary registers records */ + /* clear other necessary registers and alert records */ vkwrite32(vk, 0, BAR_0, BAR_OS_UPTIME); vkwrite32(vk, 0, BAR_0, BAR_INTF_VER); + memset(&vk->host_alert, 0, sizeof(vk->host_alert)); + memset(&vk->peer_alert, 0, sizeof(vk->peer_alert)); + /* clear 4096 bits of bitmap */ + bitmap_clear(vk->bmap, 0, VK_MSG_ID_BITMAP_SIZE); return 0; } +static long bcm_vk_reset(struct bcm_vk *vk, struct vk_reset __user *arg) +{ + struct device *dev = &vk->pdev->dev; + struct vk_reset reset; + int ret = 0; + u32 ramdump_reset; + int special_reset; + + if (copy_from_user(&reset, arg, sizeof(struct vk_reset))) + return -EFAULT; + + /* check if any download is in-progress, if so return error */ + if (test_and_set_bit(BCM_VK_WQ_DWNLD_PEND, vk->wq_offload) != 0) { + dev_err(dev, "Download operation pending - skip reset.\n"); + return -EPERM; + } + + ramdump_reset = vk->peer_alert.flags & ERR_LOG_RAMDUMP; + dev_info(dev, "Issue Reset %s\n", + ramdump_reset ? "in ramdump mode" : ""); + + /* + * The following is the sequence of reset: + * - send card level graceful shut down + * - wait enough time for VK to handle its business, stopping DMA etc + * - kill host apps + * - Trigger interrupt with DB + */ + bcm_vk_send_shutdown_msg(vk, VK_SHUTDOWN_GRACEFUL, 0, 0); + + spin_lock(&vk->ctx_lock); + if (!vk->reset_pid) { + vk->reset_pid = task_pid_nr(current); + } else { + dev_err(dev, "Reset already launched by process pid %d\n", + vk->reset_pid); + ret = -EACCES; + } + spin_unlock(&vk->ctx_lock); + if (ret) + goto err_exit; + + bcm_vk_blk_drv_access(vk); + special_reset = bcm_vk_trigger_reset(vk); + + /* + * Wait enough time for card os to deinit + * and populate the reset reason. + */ + msleep(BCM_VK_DEINIT_TIME_MS); + + if (special_reset) { + /* if it is special ramdump reset, return the type to user */ + reset.arg2 = special_reset; + if (copy_to_user(arg, &reset, sizeof(reset))) + ret = -EFAULT; + } else { + ret = bcm_vk_reset_successful(vk); + } + +err_exit: + clear_bit(BCM_VK_WQ_DWNLD_PEND, vk->wq_offload); + return ret; +} + static long bcm_vk_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = -EINVAL; @@ -1044,6 +1186,10 @@ static long bcm_vk_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = bcm_vk_load_image(vk, argp); break; + case VK_IOCTL_RESET: + ret = bcm_vk_reset(vk, argp); + break; + default: break; } diff --git a/drivers/misc/bcm-vk/bcm_vk_msg.c b/drivers/misc/bcm-vk/bcm_vk_msg.c index 3f2876484b7a..e31d41400199 100644 --- a/drivers/misc/bcm-vk/bcm_vk_msg.c +++ b/drivers/misc/bcm-vk/bcm_vk_msg.c @@ -204,6 +204,15 @@ static struct bcm_vk_ctx *bcm_vk_get_ctx(struct bcm_vk *vk, const pid_t pid) spin_lock(&vk->ctx_lock); + /* check if it is in reset, if so, don't allow */ + if (vk->reset_pid) { + dev_err(&vk->pdev->dev, + "No context allowed during reset by pid %d\n", + vk->reset_pid); + + goto in_reset_exit; + } + for (i = 0; i < ARRAY_SIZE(vk->ctx); i++) { if (!vk->ctx[i].in_use) { vk->ctx[i].in_use = true; @@ -232,6 +241,7 @@ static struct bcm_vk_ctx *bcm_vk_get_ctx(struct bcm_vk *vk, const pid_t pid) init_waitqueue_head(&ctx->rd_wq); all_in_use_exit: +in_reset_exit: spin_unlock(&vk->ctx_lock); return ctx; @@ -376,6 +386,12 @@ static void bcm_vk_drain_all_pend(struct device *dev, num, ctx->idx); } +void bcm_vk_drain_msg_on_reset(struct bcm_vk *vk) +{ + bcm_vk_drain_all_pend(&vk->pdev->dev, &vk->to_v_msg_chan, NULL); + bcm_vk_drain_all_pend(&vk->pdev->dev, &vk->to_h_msg_chan, NULL); +} + /* * Function to sync up the messages queue info that is provided by BAR1 */ @@ -700,13 +716,22 @@ static int bcm_vk_handle_last_sess(struct bcm_vk *vk, const pid_t pid, /* * don't send down or do anything if message queue is not initialized + * and if it is the reset session, clear it. */ - if (!bcm_vk_drv_access_ok(vk)) + if (!bcm_vk_drv_access_ok(vk)) { + if (vk->reset_pid == pid) + vk->reset_pid = 0; return -EPERM; + } dev_dbg(dev, "No more sessions, shut down pid %d\n", pid); - rc = bcm_vk_send_shutdown_msg(vk, VK_SHUTDOWN_PID, pid, q_num); + /* only need to do it if it is not the reset process */ + if (vk->reset_pid != pid) + rc = bcm_vk_send_shutdown_msg(vk, VK_SHUTDOWN_PID, pid, q_num); + else + /* put reset_pid to 0 if it is exiting last session */ + vk->reset_pid = 0; return rc; } @@ -1110,6 +1135,17 @@ ssize_t bcm_vk_write(struct file *p_file, int dir; struct _vk_data *data; + /* + * check if we are in reset, if so, no buffer transfer is + * allowed and return error. + */ + if (vk->reset_pid) { + dev_dbg(dev, "No Transfer allowed during reset, pid %d.\n", + ctx->pid); + rc = -EACCES; + goto write_free_msgid; + } + num_planes = entry->to_v_msg[0].cmd & VK_CMD_PLANES_MASK; if ((entry->to_v_msg[0].cmd & VK_CMD_MASK) == VK_CMD_DOWNLOAD) dir = DMA_FROM_DEVICE; -- 2.17.1