From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: multipart/mixed; boundary="===============8002710326185714129==" MIME-Version: 1.0 From: kelvin.cao@microchip.com To: kbuild-all@lists.01.org Subject: [PATCH 1/5] PCI/switchtec: Error out MRPC execution when no GAS access Date: Fri, 24 Sep 2021 10:24:40 +0000 Message-ID: <20210924102444.4684-2-kelvin.cao@microchip.com> In-Reply-To: <20210924102444.4684-1-kelvin.cao@microchip.com> List-Id: --===============8002710326185714129== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Kelvin Cao After a firmware hard reset, MRPC command executions, which are based on the PCI BAR (which Microchip refers to as GAS) read/write, will hang indefinitely. This is because after a reset, the host will fail all GAS reads (get all 1s), in which case the driver won't get a valid MRPC status. Add a read check to GAS access when a MRPC command execution doesn't response timely, error out if the check fails. Signed-off-by: Kelvin Cao --- drivers/pci/switch/switchtec.c | 59 ++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 0b301f8be9ed..092653487021 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -45,6 +45,7 @@ enum mrpc_state { MRPC_QUEUED, MRPC_RUNNING, MRPC_DONE, + MRPC_IO_ERROR, }; = struct switchtec_user { @@ -66,6 +67,13 @@ struct switchtec_user { int event_cnt; }; = +static int check_access(struct switchtec_dev *stdev) +{ + u32 device =3D ioread32(&stdev->mmio_sys_info->device_id); + + return stdev->pdev->device =3D=3D device; +} + static struct switchtec_user *stuser_create(struct switchtec_dev *stdev) { struct switchtec_user *stuser; @@ -113,6 +121,7 @@ static void stuser_set_state(struct switchtec_user *stu= ser, [MRPC_QUEUED] =3D "QUEUED", [MRPC_RUNNING] =3D "RUNNING", [MRPC_DONE] =3D "DONE", + [MRPC_IO_ERROR] =3D "IO_ERROR", }; = stuser->state =3D state; @@ -184,6 +193,21 @@ static int mrpc_queue_cmd(struct switchtec_user *stuse= r) return 0; } = +static void mrpc_cleanup_cmd(struct switchtec_dev *stdev) +{ + /* requires the mrpc_mutex to already be held when called */ + struct switchtec_user *stuser =3D list_entry(stdev->mrpc_queue.next, + struct switchtec_user, list); + + stuser->cmd_done =3D true; + wake_up_interruptible(&stuser->cmd_comp); + list_del_init(&stuser->list); + stuser_put(stuser); + stdev->mrpc_busy =3D 0; + + mrpc_cmd_submit(stdev); +} + static void mrpc_complete_cmd(struct switchtec_dev *stdev) { /* requires the mrpc_mutex to already be held when called */ @@ -223,13 +247,7 @@ static void mrpc_complete_cmd(struct switchtec_dev *st= dev) memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data, stuser->read_len); out: - stuser->cmd_done =3D true; - wake_up_interruptible(&stuser->cmd_comp); - list_del_init(&stuser->list); - stuser_put(stuser); - stdev->mrpc_busy =3D 0; - - mrpc_cmd_submit(stdev); + mrpc_cleanup_cmd(stdev); } = static void mrpc_event_work(struct work_struct *work) @@ -246,6 +264,23 @@ static void mrpc_event_work(struct work_struct *work) mutex_unlock(&stdev->mrpc_mutex); } = +static void mrpc_error_complete_cmd(struct switchtec_dev *stdev) +{ + /* requires the mrpc_mutex to already be held when called */ + + struct switchtec_user *stuser; + + if (list_empty(&stdev->mrpc_queue)) + return; + + stuser =3D list_entry(stdev->mrpc_queue.next, + struct switchtec_user, list); + + stuser_set_state(stuser, MRPC_IO_ERROR); + + mrpc_cleanup_cmd(stdev); +} + static void mrpc_timeout_work(struct work_struct *work) { struct switchtec_dev *stdev; @@ -257,6 +292,11 @@ static void mrpc_timeout_work(struct work_struct *work) = mutex_lock(&stdev->mrpc_mutex); = + if (!check_access(stdev)) { + mrpc_error_complete_cmd(stdev); + goto out; + } + if (stdev->dma_mrpc) status =3D stdev->dma_mrpc->status; else @@ -544,6 +584,11 @@ static ssize_t switchtec_dev_read(struct file *filp, c= har __user *data, if (rc) return rc; = + if (stuser->state =3D=3D MRPC_IO_ERROR) { + mutex_unlock(&stdev->mrpc_mutex); + return -EIO; + } + if (stuser->state !=3D MRPC_DONE) { mutex_unlock(&stdev->mrpc_mutex); return -EBADE; -- = 2.25.1 --===============8002710326185714129==--