diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c index 042b735cbd05..cdea19e163c7 100644 --- a/drivers/coresight/coresight-tmc.c +++ b/drivers/coresight/coresight-tmc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -850,6 +850,14 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) return ret; mutex_lock(&drvdata->usb_lock); + spin_lock_irqsave(&drvdata->spinlock, flags); + if (drvdata->reading) { + ret = -EBUSY; + spin_unlock_irqrestore(&drvdata->spinlock, flags); + goto err0; + } + spin_unlock_irqrestore(&drvdata->spinlock, flags); + if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { coresight_cti_map_trigout(drvdata->cti_flush, 1, 0); coresight_cti_map_trigin(drvdata->cti_reset, 2, 0); @@ -896,10 +904,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) } spin_lock_irqsave(&drvdata->spinlock, flags); - if (drvdata->reading) { - ret = -EBUSY; - goto err1; - } if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { __tmc_etb_enable(drvdata); @@ -929,11 +933,6 @@ static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode) dev_info(drvdata->dev, "TMC enabled\n"); return 0; -err1: - spin_unlock_irqrestore(&drvdata->spinlock, flags); - if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) - if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) - usb_qdss_close(drvdata->usbch); err0: mutex_unlock(&drvdata->usb_lock); clk_disable_unprepare(drvdata->clk); @@ -1328,6 +1327,7 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) unsigned long flags; enum tmc_mode mode; + mutex_lock(&drvdata->usb_lock); spin_lock_irqsave(&drvdata->spinlock, flags); if (!drvdata->sticky_enable) { dev_err(drvdata->dev, "enable tmc once before reading\n"); @@ -1358,11 +1358,13 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) out: drvdata->reading = true; spin_unlock_irqrestore(&drvdata->spinlock, flags); + mutex_unlock(&drvdata->usb_lock); dev_info(drvdata->dev, "TMC read start\n"); return 0; err: spin_unlock_irqrestore(&drvdata->spinlock, flags); + mutex_unlock(&drvdata->usb_lock); return ret; } @@ -1544,8 +1546,12 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, { struct tmc_drvdata *drvdata = container_of(file->private_data, struct tmc_drvdata, miscdev); - char *bufp = drvdata->buf + *ppos; - char *end = (char *)(drvdata->vaddr + drvdata->size); + char *bufp, *end; + + mutex_lock(&drvdata->usb_lock); + + bufp = drvdata->buf + *ppos; + end = (char *)(drvdata->vaddr + drvdata->size); if (*ppos + len > drvdata->size) len = drvdata->size - *ppos; @@ -1572,6 +1578,7 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, if (copy_to_user(data, bufp, len)) { dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__); + mutex_unlock(&drvdata->usb_lock); return -EFAULT; } @@ -1579,6 +1586,8 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len, out: dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n", __func__, len, (int) (drvdata->size - *ppos)); + + mutex_unlock(&drvdata->usb_lock); return len; }