From ddc25bdd2b7f34667111714fafc9c04f6ad97fee Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 7 Jan 2015 13:15:22 +0100 Subject: iio: dht11: Fix out-of-bounds read As we access i-1 we must not start with i=0. Signed-off-by: Richard Weinberger Acked-by: Hartmut Knaack Acked-by: Harald Geyer Reviewed-by: Sanjeev Sharma Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 623c145d8a97..f546ecae90f1 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -88,7 +88,7 @@ static int dht11_decode(struct dht11 *dht11, int offset) unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum; /* Calculate timestamp resolution */ - for (i = 0; i < dht11->num_edges; ++i) { + for (i = 1; i < dht11->num_edges; ++i) { t = dht11->edges[i].ts - dht11->edges[i-1].ts; if (t > 0 && t < timeres) timeres = t; -- cgit v1.2.3 From 004bc530341a40536494431cf665504f8ee70266 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 7 Jan 2015 13:18:23 +0100 Subject: iio: dht11: Add locking Make sure that the read function is not interrupted... Signed-off-by: Richard Weinberger Acked-by: Harald Geyer Reviewed-by: Sanjeev Sharma Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index f546ecae90f1..7717f5c3395b 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ struct dht11 { int irq; struct completion completion; + struct mutex lock; s64 timestamp; int temperature; @@ -145,6 +147,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev, struct dht11 *dht11 = iio_priv(iio_dev); int ret; + mutex_lock(&dht11->lock); if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) { reinit_completion(&dht11->completion); @@ -185,6 +188,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev, ret = -EINVAL; err: dht11->num_edges = -1; + mutex_unlock(&dht11->lock); return ret; } @@ -268,6 +272,7 @@ static int dht11_probe(struct platform_device *pdev) platform_set_drvdata(pdev, iio); init_completion(&dht11->completion); + mutex_init(&dht11->lock); iio->name = pdev->name; iio->dev.parent = &pdev->dev; iio->info = &dht11_iio_info; -- cgit v1.2.3 From 94e65519abde01cbffb9c538a4598f6a50bc86d1 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 7 Jan 2015 13:22:49 +0100 Subject: iio: dht11: IRQ fixes Since setting irq-enabled GPIOs into output state is not supported by all GPIO controllers, we need to disable the irq while requesting sensor data. As side effect we lose a tiny bit of functionality: Some wiring problems can't be concluded from log messages anymore. Signed-off-by: Richard Weinberger Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 62 +++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 7717f5c3395b..7d79a1ac5f5f 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -40,8 +40,12 @@ #define DHT11_DATA_VALID_TIME 2000000000 /* 2s in ns */ -#define DHT11_EDGES_PREAMBLE 4 +#define DHT11_EDGES_PREAMBLE 2 #define DHT11_BITS_PER_READ 40 +/* + * Note that when reading the sensor actually 84 edges are detected, but + * since the last edge is not significant, we only store 83: + */ #define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1) /* Data transmission timing (nano seconds) */ @@ -140,6 +144,27 @@ static int dht11_decode(struct dht11 *dht11, int offset) return 0; } +/* + * IRQ handler called on GPIO edges + */ +static irqreturn_t dht11_handle_irq(int irq, void *data) +{ + struct iio_dev *iio = data; + struct dht11 *dht11 = iio_priv(iio); + + /* TODO: Consider making the handler safe for IRQ sharing */ + if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) { + dht11->edges[dht11->num_edges].ts = iio_get_time_ns(); + dht11->edges[dht11->num_edges++].value = + gpio_get_value(dht11->gpio); + + if (dht11->num_edges >= DHT11_EDGES_PER_READ) + complete(&dht11->completion); + } + + return IRQ_HANDLED; +} + static int dht11_read_raw(struct iio_dev *iio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long m) @@ -160,8 +185,17 @@ static int dht11_read_raw(struct iio_dev *iio_dev, if (ret) goto err; + ret = request_irq(dht11->irq, dht11_handle_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + iio_dev->name, iio_dev); + if (ret) + goto err; + ret = wait_for_completion_killable_timeout(&dht11->completion, HZ); + + free_irq(dht11->irq, iio_dev); + if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) { dev_err(&iio_dev->dev, "Only %d signal edges detected\n", @@ -197,27 +231,6 @@ static const struct iio_info dht11_iio_info = { .read_raw = dht11_read_raw, }; -/* - * IRQ handler called on GPIO edges -*/ -static irqreturn_t dht11_handle_irq(int irq, void *data) -{ - struct iio_dev *iio = data; - struct dht11 *dht11 = iio_priv(iio); - - /* TODO: Consider making the handler safe for IRQ sharing */ - if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) { - dht11->edges[dht11->num_edges].ts = iio_get_time_ns(); - dht11->edges[dht11->num_edges++].value = - gpio_get_value(dht11->gpio); - - if (dht11->num_edges >= DHT11_EDGES_PER_READ) - complete(&dht11->completion); - } - - return IRQ_HANDLED; -} - static const struct iio_chan_spec dht11_chan_spec[] = { { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }, @@ -260,11 +273,6 @@ static int dht11_probe(struct platform_device *pdev) dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio); return -EINVAL; } - ret = devm_request_irq(dev, dht11->irq, dht11_handle_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - pdev->name, iio); - if (ret) - return ret; dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1; dht11->num_edges = -1; -- cgit v1.2.3 From f2229ab8611e6e79992b6357db3fb4faf70e74a9 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Wed, 31 Dec 2014 03:59:46 -0500 Subject: iio: iadc: wait_for_completion_timeout time in jiffies The timeout value to wait_for_completion_timeout is in jiffies but the value being passed seems like it was intended to by microseconds Note that the timeout was extremely long thus it might be too short now. In any case it probably should be passed through usecs_to_jiffies() or msecs_to_jiffies() patch is against linux-next 3.19.0-rc1 -next-20141226 patch was only compile-tested x86_64_defcofnig + CONFIG_SPMI=m CONFIG_IIO=m, CONFIG_QCOM_SPMI_IADC=m Signed-off-by: Nicholas Mc Guire Acked-by: Ivan T. Ivanov Signed-off-by: Jonathan Cameron --- drivers/iio/adc/qcom-spmi-iadc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/adc/qcom-spmi-iadc.c b/drivers/iio/adc/qcom-spmi-iadc.c index b9666f2f5e51..fabd24edc2a1 100644 --- a/drivers/iio/adc/qcom-spmi-iadc.c +++ b/drivers/iio/adc/qcom-spmi-iadc.c @@ -296,7 +296,8 @@ static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data) if (iadc->poll_eoc) { ret = iadc_poll_wait_eoc(iadc, wait); } else { - ret = wait_for_completion_timeout(&iadc->complete, wait); + ret = wait_for_completion_timeout(&iadc->complete, + usecs_to_jiffies(wait)); if (!ret) ret = -ETIMEDOUT; else -- cgit v1.2.3 From 4f33fbae555000bf73aaacbc4f5b24668afc8c7a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 9 Jan 2015 15:13:37 -0800 Subject: iio: imu: inv_mpu6050: Prevent dereferencing NULL When id is null, with ACPI enumeration, don't dereference it. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index b75519deac1a..eedd3e07d27c 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -690,7 +690,11 @@ static int inv_mpu_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); indio_dev->dev.parent = &client->dev; - indio_dev->name = id->name; + /* id will be NULL when enumerated via ACPI */ + if (id) + indio_dev->name = (char *)id->name; + else + indio_dev->name = (char *)dev_name(&client->dev); indio_dev->channels = inv_mpu_channels; indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); -- cgit v1.2.3 From fb8b7d2b9d80e1e71f379e57355936bd2b024be9 Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Wed, 21 Jan 2015 18:35:47 +0800 Subject: reservation: wait only with non-zero timeout specified (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the timeout value passed to reservation_object_wait_timeout_rcu is zero, no wait should be done if the fences are not signaled. Return '1' for idle and '0' for busy if the specified timeout is '0' to keep consistent with the case of non-zero timeout. v2: call fence_put if not signaled in the case of timeout==0 v3: switch to reservation_object_test_signaled_rcu Signed-off-by: Jammy Zhou Reviewed-by: Christian König Reviewed-by: Alex Deucher Reviewed-By: Maarten Lankhorst Signed-off-by: Sumit Semwal --- drivers/dma-buf/reservation.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 3c97c8fa8d02..807ef1555255 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -327,6 +327,9 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj, unsigned seq, shared_count, i = 0; long ret = timeout; + if (!timeout) + return reservation_object_test_signaled_rcu(obj, wait_all); + retry: fence = NULL; shared_count = 0; -- cgit v1.2.3 From 847b19a39e4c9b5e74c40f0842c48b41664cb43c Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Wed, 21 Jan 2015 18:35:48 +0800 Subject: dma-buf/fence: don't wait when specified timeout is zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When specified timeout is zero for fence_wait_timeout, just check if the fence is signaled or not without wait. Signed-off-by: Jammy Zhou Reviewed-by: Christian König Reviewed-By: Maarten Lankhorst Signed-off-by: Sumit Semwal --- drivers/dma-buf/fence.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/dma-buf/fence.c b/drivers/dma-buf/fence.c index e5541117b3e9..50ef8bd8708b 100644 --- a/drivers/dma-buf/fence.c +++ b/drivers/dma-buf/fence.c @@ -159,6 +159,9 @@ fence_wait_timeout(struct fence *fence, bool intr, signed long timeout) if (WARN_ON(timeout < 0)) return -EINVAL; + if (timeout == 0) + return fence_is_signaled(fence); + trace_fence_wait_start(fence); ret = fence->ops->wait(fence, intr, timeout); trace_fence_wait_end(fence); -- cgit v1.2.3 From 4eb2440ed60fb5793f7aa6da89b3d517cc59de43 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Thu, 22 Jan 2015 16:00:17 +0900 Subject: reservation: Remove shadowing local variable 'ret' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was causing the return value of fence_is_signaled to be ignored, making reservation objects signal too early. Cc: stable@vger.kernel.org Reviewed-by: Maarten Lankhorst Reviewed-by: Alex Deucher Signed-off-by: Michel Dänzer Signed-off-by: Sumit Semwal --- drivers/dma-buf/reservation.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c index 807ef1555255..39920d77f288 100644 --- a/drivers/dma-buf/reservation.c +++ b/drivers/dma-buf/reservation.c @@ -405,8 +405,6 @@ reservation_object_test_signaled_single(struct fence *passed_fence) int ret = 1; if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) { - int ret; - fence = fence_get_rcu(lfence); if (!fence) return -1; -- cgit v1.2.3 From f81197b8a31b8fb287ae57f597b5b6841e1ece92 Mon Sep 17 00:00:00 2001 From: Kristina Martšenko Date: Sun, 25 Jan 2015 18:28:19 +0200 Subject: iio: mxs-lradc: separate touchscreen and buffer virtual channels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The touchscreen was initially designed [1] to map all of its physical channels to one virtual channel, leaving buffered capture to use the remaining 7 virtual channels. When the touchscreen was reimplemented [2], it was made to use four virtual channels, which overlap and conflict with the channels the buffer uses. As a result, when the buffer is enabled, the touchscreen's virtual channels are remapped to whichever physical channels the buffer was configured with, causing the touchscreen to read those instead of the touch measurement channels. Effectively the touchscreen stops working. So here we separate the channels again, giving the touchscreen 2 virtual channels and the buffer 6. We can't give the touchscreen just 1 channel as before, as the current pressure calculation requires 2 channels to be read at the same time. This makes the touchscreen continue to work during buffered capture. It has been tested on i.MX28, but not on i.MX23. [1] 06ddd353f5c8 ("iio: mxs: Implement support for touchscreen") [2] dee05308f602 ("Staging/iio/adc/touchscreen/MXS: add interrupt driven touch detection") Signed-off-by: Kristina Martšenko Reviewed-by: Marek Vasut Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 166 ++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 91 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index f053535385bf..4e574b76ead0 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -214,11 +214,14 @@ struct mxs_lradc { unsigned long is_divided; /* - * Touchscreen LRADC channels receives a private slot in the CTRL4 - * register, the slot #7. Therefore only 7 slots instead of 8 in the - * CTRL4 register can be mapped to LRADC channels when using the - * touchscreen. - * + * When the touchscreen is enabled, we give it two private virtual + * channels: #6 and #7. This means that only 6 virtual channels (instead + * of 8) will be available for buffered capture. + */ +#define TOUCHSCREEN_VCHANNEL1 7 +#define TOUCHSCREEN_VCHANNEL2 6 + + /* * Furthermore, certain LRADC channels are shared between touchscreen * and/or touch-buttons and generic LRADC block. Therefore when using * either of these, these channels are not available for the regular @@ -342,6 +345,9 @@ struct mxs_lradc { #define LRADC_CTRL4 0x140 #define LRADC_CTRL4_LRADCSELECT_MASK(n) (0xf << ((n) * 4)) #define LRADC_CTRL4_LRADCSELECT_OFFSET(n) ((n) * 4) +#define LRADC_CTRL4_LRADCSELECT(n, x) \ + (((x) << LRADC_CTRL4_LRADCSELECT_OFFSET(n)) & \ + LRADC_CTRL4_LRADCSELECT_MASK(n)) #define LRADC_RESOLUTION 12 #define LRADC_SINGLE_SAMPLE_MASK ((1 << LRADC_RESOLUTION) - 1) @@ -416,6 +422,14 @@ static bool mxs_lradc_check_touch_event(struct mxs_lradc *lradc) LRADC_STATUS_TOUCH_DETECT_RAW); } +static void mxs_lradc_map_channel(struct mxs_lradc *lradc, unsigned vch, + unsigned ch) +{ + mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(vch), + LRADC_CTRL4); + mxs_lradc_reg_set(lradc, LRADC_CTRL4_LRADCSELECT(vch, ch), LRADC_CTRL4); +} + static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch) { /* @@ -443,12 +457,8 @@ static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch) LRADC_DELAY_DELAY(lradc->over_sample_delay - 1), LRADC_DELAY(3)); - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) | - LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) | - LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1); + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch), LRADC_CTRL1); - /* wake us again, when the complete conversion is done */ - mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch), LRADC_CTRL1); /* * after changing the touchscreen plates setting * the signals need some initial time to settle. Start the @@ -502,12 +512,8 @@ static void mxs_lradc_setup_ts_pressure(struct mxs_lradc *lradc, unsigned ch1, LRADC_DELAY_DELAY(lradc->over_sample_delay - 1), LRADC_DELAY(3)); - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) | - LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) | - LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1); + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch2), LRADC_CTRL1); - /* wake us again, when the conversions are done */ - mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch2), LRADC_CTRL1); /* * after changing the touchscreen plates setting * the signals need some initial time to settle. Start the @@ -573,36 +579,6 @@ static unsigned mxs_lradc_read_ts_pressure(struct mxs_lradc *lradc, #define TS_CH_XM 4 #define TS_CH_YM 5 -static int mxs_lradc_read_ts_channel(struct mxs_lradc *lradc) -{ - u32 reg; - int val; - - reg = readl(lradc->base + LRADC_CTRL1); - - /* only channels 3 to 5 are of interest here */ - if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YP)) { - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YP) | - LRADC_CTRL1_LRADC_IRQ(TS_CH_YP), LRADC_CTRL1); - val = mxs_lradc_read_raw_channel(lradc, TS_CH_YP); - } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_XM)) { - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_XM) | - LRADC_CTRL1_LRADC_IRQ(TS_CH_XM), LRADC_CTRL1); - val = mxs_lradc_read_raw_channel(lradc, TS_CH_XM); - } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YM)) { - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YM) | - LRADC_CTRL1_LRADC_IRQ(TS_CH_YM), LRADC_CTRL1); - val = mxs_lradc_read_raw_channel(lradc, TS_CH_YM); - } else { - return -EIO; - } - - mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2)); - mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3)); - - return val; -} - /* * YP(open)--+-------------+ * | |--+ @@ -646,7 +622,8 @@ static void mxs_lradc_prepare_x_pos(struct mxs_lradc *lradc) mxs_lradc_reg_set(lradc, mxs_lradc_drive_x_plate(lradc), LRADC_CTRL0); lradc->cur_plate = LRADC_SAMPLE_X; - mxs_lradc_setup_ts_channel(lradc, TS_CH_YP); + mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YP); + mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1); } /* @@ -667,7 +644,8 @@ static void mxs_lradc_prepare_y_pos(struct mxs_lradc *lradc) mxs_lradc_reg_set(lradc, mxs_lradc_drive_y_plate(lradc), LRADC_CTRL0); lradc->cur_plate = LRADC_SAMPLE_Y; - mxs_lradc_setup_ts_channel(lradc, TS_CH_XM); + mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_XM); + mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1); } /* @@ -688,7 +666,10 @@ static void mxs_lradc_prepare_pressure(struct mxs_lradc *lradc) mxs_lradc_reg_set(lradc, mxs_lradc_drive_pressure(lradc), LRADC_CTRL0); lradc->cur_plate = LRADC_SAMPLE_PRESSURE; - mxs_lradc_setup_ts_pressure(lradc, TS_CH_XP, TS_CH_YM); + mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YM); + mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL2, TS_CH_XP); + mxs_lradc_setup_ts_pressure(lradc, TOUCHSCREEN_VCHANNEL2, + TOUCHSCREEN_VCHANNEL1); } static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc) @@ -701,6 +682,19 @@ static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc) mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); } +static void mxs_lradc_start_touch_event(struct mxs_lradc *lradc) +{ + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, + LRADC_CTRL1); + mxs_lradc_reg_set(lradc, + LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1); + /* + * start with the Y-pos, because it uses nearly the same plate + * settings like the touch detection + */ + mxs_lradc_prepare_y_pos(lradc); +} + static void mxs_lradc_report_ts_event(struct mxs_lradc *lradc) { input_report_abs(lradc->ts_input, ABS_X, lradc->ts_x_pos); @@ -718,10 +712,12 @@ static void mxs_lradc_complete_touch_event(struct mxs_lradc *lradc) * start a dummy conversion to burn time to settle the signals * note: we are not interested in the conversion's value */ - mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(5)); - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1); - mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(5), LRADC_CTRL1); - mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << 5) | + mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(TOUCHSCREEN_VCHANNEL1)); + mxs_lradc_reg_clear(lradc, + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1); + mxs_lradc_reg_wrt(lradc, + LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) | LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), /* waste 5 ms */ LRADC_DELAY(2)); } @@ -753,59 +749,45 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid) /* if it is released, wait for the next touch via IRQ */ lradc->cur_plate = LRADC_TOUCH; - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1); + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2)); + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3)); + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ | + LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1); mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); } /* touchscreen's state machine */ static void mxs_lradc_handle_touch(struct mxs_lradc *lradc) { - int val; - switch (lradc->cur_plate) { case LRADC_TOUCH: - /* - * start with the Y-pos, because it uses nearly the same plate - * settings like the touch detection - */ - if (mxs_lradc_check_touch_event(lradc)) { - mxs_lradc_reg_clear(lradc, - LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, - LRADC_CTRL1); - mxs_lradc_prepare_y_pos(lradc); - } + if (mxs_lradc_check_touch_event(lradc)) + mxs_lradc_start_touch_event(lradc); mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1); return; case LRADC_SAMPLE_Y: - val = mxs_lradc_read_ts_channel(lradc); - if (val < 0) { - mxs_lradc_enable_touch_detection(lradc); /* re-start */ - return; - } - lradc->ts_y_pos = val; + lradc->ts_y_pos = mxs_lradc_read_raw_channel(lradc, + TOUCHSCREEN_VCHANNEL1); mxs_lradc_prepare_x_pos(lradc); return; case LRADC_SAMPLE_X: - val = mxs_lradc_read_ts_channel(lradc); - if (val < 0) { - mxs_lradc_enable_touch_detection(lradc); /* re-start */ - return; - } - lradc->ts_x_pos = val; + lradc->ts_x_pos = mxs_lradc_read_raw_channel(lradc, + TOUCHSCREEN_VCHANNEL1); mxs_lradc_prepare_pressure(lradc); return; case LRADC_SAMPLE_PRESSURE: - lradc->ts_pressure = - mxs_lradc_read_ts_pressure(lradc, TS_CH_XP, TS_CH_YM); + lradc->ts_pressure = mxs_lradc_read_ts_pressure(lradc, + TOUCHSCREEN_VCHANNEL2, + TOUCHSCREEN_VCHANNEL1); mxs_lradc_complete_touch_event(lradc); return; case LRADC_SAMPLE_VALID: - val = mxs_lradc_read_ts_channel(lradc); /* ignore the value */ mxs_lradc_finish_touch_event(lradc, 1); break; } @@ -1083,9 +1065,8 @@ static void mxs_lradc_disable_ts(struct mxs_lradc *lradc) { /* stop all interrupts from firing */ mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN | - LRADC_CTRL1_LRADC_IRQ_EN(2) | LRADC_CTRL1_LRADC_IRQ_EN(3) | - LRADC_CTRL1_LRADC_IRQ_EN(4) | LRADC_CTRL1_LRADC_IRQ_EN(5), - LRADC_CTRL1); + LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) | + LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1); /* Power-down touchscreen touch-detect circuitry. */ mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0); @@ -1151,26 +1132,29 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data) struct iio_dev *iio = data; struct mxs_lradc *lradc = iio_priv(iio); unsigned long reg = readl(lradc->base + LRADC_CTRL1); + uint32_t clr_irq = mxs_lradc_irq_mask(lradc); const uint32_t ts_irq_mask = LRADC_CTRL1_TOUCH_DETECT_IRQ | - LRADC_CTRL1_LRADC_IRQ(2) | - LRADC_CTRL1_LRADC_IRQ(3) | - LRADC_CTRL1_LRADC_IRQ(4) | - LRADC_CTRL1_LRADC_IRQ(5); + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2); if (!(reg & mxs_lradc_irq_mask(lradc))) return IRQ_NONE; - if (lradc->use_touchscreen && (reg & ts_irq_mask)) + if (lradc->use_touchscreen && (reg & ts_irq_mask)) { mxs_lradc_handle_touch(lradc); + /* Make sure we don't clear the next conversion's interrupt. */ + clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2)); + } + if (iio_buffer_enabled(iio)) iio_trigger_poll(iio->trig); else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) complete(&lradc->completion); - mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc), - LRADC_CTRL1); + mxs_lradc_reg_clear(lradc, reg & clr_irq, LRADC_CTRL1); return IRQ_HANDLED; } @@ -1346,7 +1330,7 @@ static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio, if (lradc->use_touchbutton) rsvd_chans++; if (lradc->use_touchscreen) - rsvd_chans++; + rsvd_chans += 2; /* Test for attempts to map channels with special mode of operation. */ if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS)) -- cgit v1.2.3 From 86bf7f3ef7e961e91e16dceb31ae0f583483b204 Mon Sep 17 00:00:00 2001 From: Kristina Martšenko Date: Sun, 25 Jan 2015 18:28:20 +0200 Subject: iio: mxs-lradc: make ADC reads not disable touchscreen interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading a channel through sysfs, or starting a buffered capture, will currently turn off the touchscreen. This is because the read_raw() and buffer preenable()/postdisable() callbacks disable interrupts for all LRADC channels, including those the touchscreen uses. So make the callbacks only disable interrupts for the channels they use. This means channel 0 for read_raw() and channels 0-5 for the buffer (if the touchscreen is enabled). Since the touchscreen uses different channels (6 and 7), it no longer gets turned off. Note that only i.MX28 is affected by this issue, i.MX23 should be fine. Signed-off-by: Kristina Martšenko Reviewed-by: Marek Vasut Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 4e574b76ead0..653af03bc69d 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -220,6 +220,9 @@ struct mxs_lradc { */ #define TOUCHSCREEN_VCHANNEL1 7 #define TOUCHSCREEN_VCHANNEL2 6 +#define BUFFER_VCHANS_LIMITED 0x3f +#define BUFFER_VCHANS_ALL 0xff + u8 buffer_vchans; /* * Furthermore, certain LRADC channels are shared between touchscreen @@ -819,7 +822,7 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val) * used if doing raw sampling. */ if (lradc->soc == IMX28_LRADC) - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK, + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0), LRADC_CTRL1); mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); @@ -1266,8 +1269,9 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) } if (lradc->soc == IMX28_LRADC) - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK, - LRADC_CTRL1); + mxs_lradc_reg_clear(lradc, + lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET, + LRADC_CTRL1); mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) { @@ -1303,8 +1307,9 @@ static int mxs_lradc_buffer_postdisable(struct iio_dev *iio) mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); if (lradc->soc == IMX28_LRADC) - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK, - LRADC_CTRL1); + mxs_lradc_reg_clear(lradc, + lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET, + LRADC_CTRL1); kfree(lradc->buffer); mutex_unlock(&lradc->lock); @@ -1542,6 +1547,11 @@ static int mxs_lradc_probe(struct platform_device *pdev) touch_ret = mxs_lradc_probe_touchscreen(lradc, node); + if (touch_ret == 0) + lradc->buffer_vchans = BUFFER_VCHANS_LIMITED; + else + lradc->buffer_vchans = BUFFER_VCHANS_ALL; + /* Grab all IRQ sources */ for (i = 0; i < of_cfg->irq_count; i++) { lradc->irq[i] = platform_get_irq(pdev, i); -- cgit v1.2.3 From 6abe0300a1d5242f4ff89257197f284679af1a06 Mon Sep 17 00:00:00 2001 From: Kristina Martšenko Date: Sun, 25 Jan 2015 18:28:21 +0200 Subject: iio: mxs-lradc: make ADC reads not unschedule touchscreen conversions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading a channel through sysfs, or starting a buffered capture, can occasionally turn off the touchscreen. This is because the read_raw() and buffer preenable()/postdisable() callbacks unschedule current conversions on all channels. If a delay channel happens to schedule a touchscreen conversion at the same time, the conversion gets cancelled and the touchscreen sequence stops. This is probably related to this note from the reference manual: "If a delay group schedules channels to be sampled and a manual write to the schedule field in CTRL0 occurs while the block is discarding samples, the LRADC will switch to the new schedule and will not sample the channels that were previously scheduled. The time window for this to happen is very small and lasts only while the LRADC is discarding samples." So make the callbacks only unschedule conversions for the channels they use. This means channel 0 for read_raw() and channels 0-5 for the buffer (if the touchscreen is enabled). Since the touchscreen uses different channels (6 and 7), it no longer gets turned off. This is tested and fixes the issue on i.MX28, but hasn't been tested on i.MX23. Signed-off-by: Kristina Martšenko Reviewed-by: Marek Vasut Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 653af03bc69d..d2e0c275bf4d 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -824,7 +824,7 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val) if (lradc->soc == IMX28_LRADC) mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(0), LRADC_CTRL1); - mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); + mxs_lradc_reg_clear(lradc, 0x1, LRADC_CTRL0); /* Enable / disable the divider per requirement */ if (test_bit(chan, &lradc->is_divided)) @@ -1272,7 +1272,7 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) mxs_lradc_reg_clear(lradc, lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET, LRADC_CTRL1); - mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); + mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0); for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) { ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs); @@ -1305,7 +1305,7 @@ static int mxs_lradc_buffer_postdisable(struct iio_dev *iio) mxs_lradc_reg_clear(lradc, LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK, LRADC_DELAY(0)); - mxs_lradc_reg_clear(lradc, 0xff, LRADC_CTRL0); + mxs_lradc_reg_clear(lradc, lradc->buffer_vchans, LRADC_CTRL0); if (lradc->soc == IMX28_LRADC) mxs_lradc_reg_clear(lradc, lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET, -- cgit v1.2.3 From 89bb35e200bee745c539a96666e0792301ca40f1 Mon Sep 17 00:00:00 2001 From: Kristina Martšenko Date: Sun, 25 Jan 2015 18:28:22 +0200 Subject: iio: mxs-lradc: only update the buffer when its conversions have finished MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the touchscreen while running buffered capture results in the buffer reporting lots of wrong values, often just zeros. This is because we push readings to the buffer every time a touchscreen interrupt arrives, including when the buffer's own conversions have not yet finished. So let's only push to the buffer when its conversions are ready. Signed-off-by: Kristina Martšenko Reviewed-by: Marek Vasut Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index d2e0c275bf4d..ebcbd12d48b9 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1152,10 +1152,12 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data) LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2)); } - if (iio_buffer_enabled(iio)) - iio_trigger_poll(iio->trig); - else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) + if (iio_buffer_enabled(iio)) { + if (reg & lradc->buffer_vchans) + iio_trigger_poll(iio->trig); + } else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) { complete(&lradc->completion); + } mxs_lradc_reg_clear(lradc, reg & clr_irq, LRADC_CTRL1); -- cgit v1.2.3 From f7067a5ad717d4dbb4faa3ec56744152f6ba97ad Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 23 Jan 2015 00:09:56 +0100 Subject: staging: iio: ad2s1200: Fix sign extension The line above makes vel a 12-bit quantity (st->rx[] is u8). The intention is to sign-extend vel using bit 11 as the sign bit. But because of C's promotion rules "vel = (vel << 4) >> 4;" is actually a no-op, since vel is promoted to int before the inner shift. sign_extend32 works equally well for 8 and 16 bits types, so use that. Signed-off-by: Rasmus Villemoes Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1200.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c index 017d2f8379b7..c17893b4918c 100644 --- a/drivers/staging/iio/resolver/ad2s1200.c +++ b/drivers/staging/iio/resolver/ad2s1200.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -68,7 +69,7 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev, break; case IIO_ANGL_VEL: vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); - vel = (vel << 4) >> 4; + vel = sign_extend32(vel, 11); *val = vel; break; default: -- cgit v1.2.3 From 19e353f2b344ad86cea6ebbc0002e5f903480a90 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 23 Jan 2015 00:34:02 +0100 Subject: iio: imu: adis16400: Fix sign extension The intention is obviously to sign-extend a 12 bit quantity. But because of C's promotion rules, the assignment is equivalent to "val16 &= 0xfff;". Use the proper API for this. Signed-off-by: Rasmus Villemoes Acked-by: Lars-Peter Clausen Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index b70873de04ea..fa795dcd5f75 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -414,7 +415,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); if (ret) return ret; - val16 = ((val16 & 0xFFF) << 4) >> 4; + val16 = sign_extend32(val16, 11); *val = val16; return IIO_VAL_INT; case IIO_CHAN_INFO_OFFSET: -- cgit v1.2.3 From 03305e535cd5cdc1079b32909bf4b2dd67d46f7f Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 3 Jan 2015 20:34:12 +0000 Subject: iio: mxs-lradc: fix iio channel map regression Since commit c8231a9af8147f8a ("iio: mxs-lradc: compute temperature from channel 8 and 9") with the removal of adc channel 9 there is no 1-1 mapping in the channel spec. All hwmon channel values above 9 are accessible via there index minus one. So add a hidden iio channel 9 to fix this issue. Signed-off-by: Stefan Wahren Acked-by: Alexandre Belloni Reviewed-by: Marek Vasut Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index ebcbd12d48b9..351339ccaad6 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1397,6 +1397,13 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { .channel = 8, .scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,}, }, + /* Hidden channel to keep indexes */ + { + .type = IIO_TEMP, + .indexed = 1, + .scan_index = -1, + .channel = 9, + }, MXS_ADC_CHAN(10, IIO_VOLTAGE), /* VDDIO */ MXS_ADC_CHAN(11, IIO_VOLTAGE), /* VTH */ MXS_ADC_CHAN(12, IIO_VOLTAGE), /* VDDA */ -- cgit v1.2.3 From 9e128ced3851d2802b6db870f6b2e93f449ce013 Mon Sep 17 00:00:00 2001 From: Angelo Compagnucci Date: Wed, 4 Feb 2015 15:14:26 +0100 Subject: iio:adc:mcp3422 Fix incorrect scales table This patch fixes uncorrect order of mcp3422_scales table, the values was erroneously transposed. It removes also an unused array and a wrong comment. Signed-off-by: Angelo Compagnucci Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/mcp3422.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index 51672256072b..b96c636470ef 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -58,20 +58,11 @@ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ } -/* LSB is in nV to eliminate floating point */ -static const u32 rates_to_lsb[] = {1000000, 250000, 62500, 15625}; - -/* - * scales calculated as: - * rates_to_lsb[sample_rate] / (1 << pga); - * pga is 1 for 0, 2 - */ - static const int mcp3422_scales[4][4] = { - { 1000000, 250000, 62500, 15625 }, - { 500000 , 125000, 31250, 7812 }, - { 250000 , 62500 , 15625, 3906 }, - { 125000 , 31250 , 7812 , 1953 } }; + { 1000000, 500000, 250000, 125000 }, + { 250000 , 125000, 62500 , 31250 }, + { 62500 , 31250 , 15625 , 7812 }, + { 15625 , 7812 , 3906 , 1953 } }; /* Constant msleep times for data acquisitions */ static const int mcp3422_read_times[4] = { -- cgit v1.2.3 From da019f59cb16570e78feaf10380ac65a3a06861e Mon Sep 17 00:00:00 2001 From: Urs Fässler Date: Mon, 2 Feb 2015 17:12:23 +0100 Subject: iio: ad5686: fix optional reference voltage declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When not using the "_optional" function, a dummy regulator is returned and the driver fails to initialize. Signed-off-by: Urs Fässler Acked-by: Lars-Peter Clausen Cc: stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5686.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index f57562aa396f..15c73e20272d 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -322,7 +322,7 @@ static int ad5686_probe(struct spi_device *spi) st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); - st->reg = devm_regulator_get(&spi->dev, "vcc"); + st->reg = devm_regulator_get_optional(&spi->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) -- cgit v1.2.3 From 49e19d5f27aaa004692a2080453b9cc4d4fb6ec4 Mon Sep 17 00:00:00 2001 From: Roberta Dobrescu Date: Thu, 12 Feb 2015 23:00:14 +0200 Subject: iio: light: jsa1212: Select REGMAP_I2C This patch adds missing 'select' statement for jsa1212 driver. Without regmap_i2c, we get the following error when loading the module: Unknown symbol devm_regmap_init_i2c. Signed-off-by: Roberta Dobrescu Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index ae68c64bdad3..e0ed374b33fd 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -126,6 +126,7 @@ config HID_SENSOR_PROX config JSA1212 tristate "JSA1212 ALS and proximity sensor driver" depends on I2C + select REGMAP_I2C help Say Y here if you want to build a IIO driver for JSA1212 proximity & ALS sensor device. -- cgit v1.2.3 From 8c3b3efb32e0fc5dc3c0a81c7f7639a14bebdb78 Mon Sep 17 00:00:00 2001 From: Roberta Dobrescu Date: Thu, 12 Feb 2015 23:00:15 +0200 Subject: iio: light: gp2ap020a00f: Select REGMAP_I2C This patch adds missing 'select' statement for gp2ap020a00f driver. Without regmap_i2c, we get the following error when loading the module: Unknown symbol devm_regmap_init_i2c. Signed-off-by: Roberta Dobrescu Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 5bea821adcae..a338089f8077 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -62,6 +62,7 @@ config CM36651 config GP2AP020A00F tristate "Sharp GP2AP020A00F Proximity/ALS sensor" depends on I2C + select REGMAP_I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER select IRQ_WORK -- cgit v1.2.3 From e765537add38cf7967efa11999bb5daf84a6517d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 14 Feb 2015 11:32:17 +0000 Subject: Revert "iio:humidity:si7020: fix pointer to i2c client" This reverts commit e0922e5e3ccb78aa0152e93dfbd1755ac39c8582. Requested by Andrey Smirnov. It incorrectly assumes that the level of indirection is not needed which is not true(probably because the driver incorrectly allocates sizeof(*client) instead of sizeof(*data) via devm_iio_device_alloc). If you look at the code of the probe function(see below) it is easy to see that what is being stored in the private memory of the IIO device instance is not a copy of a 'struct i2c_client' but a pointer to an instance passed as an argument to the probe function. struct i2c_client **data; int ret; < Some code skipped > indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*client)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); *data = client; Without reverting this change any read of a raw value of this sensor leads to a kernel oops due to a NULL pointer de-reference on my hardware setup. Signed-off-by: Jonathan Cameron Cc: Stable@vger.kernel.org --- drivers/iio/humidity/si7020.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index b54164677b89..69e49f58a455 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -45,12 +45,12 @@ static int si7020_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - struct i2c_client *client = iio_priv(indio_dev); + struct i2c_client **client = iio_priv(indio_dev); int ret; switch (mask) { case IIO_CHAN_INFO_RAW: - ret = i2c_smbus_read_word_data(client, + ret = i2c_smbus_read_word_data(*client, chan->type == IIO_TEMP ? SI7020CMD_TEMP_HOLD : SI7020CMD_RH_HOLD); -- cgit v1.2.3 From e01becbad300712a28f29b666e685536f45e83bc Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 12 Feb 2015 23:58:41 -0800 Subject: IIO: si7020: Allocate correct amount of memory in devm_iio_device_alloc Since only a pointer to struct i2c_client is stored in a private area of IIO device created by the driver there's no need to allocate sizeof(struct i2c_client) worth of storage. Pushed to stable as this is linked to the revert patch previously. Without this followup the original patch looks sensible. Signed-off-by: Andrey Smirnov Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/si7020.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index 69e49f58a455..fa3b809aff5e 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -126,7 +126,7 @@ static int si7020_probe(struct i2c_client *client, /* Wait the maximum power-up time after software reset. */ msleep(15); - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*client)); + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; -- cgit v1.2.3 From 4d9cbff5aae65880e3d1e44357924fafc8d8bea0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 17 Feb 2015 13:11:11 +0100 Subject: regulator: da9210: Mask all interrupt sources to deassert interrupt line After boot-up, some events may be set, and cause the da9210 interrupt line to be asserted. As the da9210 driver doesn't have interrupt support yet, this causes havoc on systems where the interrupt line is shared among multiple devices. This is the case on e.g. r8a7791/koelsch, where the interrupt line is shared with a da9063 regulator, and the following events are set: EVENT_A = 0x00000011 (GPI0 | GPI4) EVENT_B = 0x00000002 (NPWRGOOD) Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/regulator/da9210-regulator.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index bc6100103f7f..f0489cb9018b 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -152,6 +152,15 @@ static int da9210_i2c_probe(struct i2c_client *i2c, config.regmap = chip->regmap; config.of_node = dev->of_node; + /* Mask all interrupt sources to deassert interrupt line */ + error = regmap_write(chip->regmap, DA9210_REG_MASK_A, ~0); + if (!error) + error = regmap_write(chip->regmap, DA9210_REG_MASK_B, ~0); + if (error) { + dev_err(&i2c->dev, "Failed to write to mask reg: %d\n", error); + return error; + } + rdev = devm_regulator_register(&i2c->dev, &da9210_reg, &config); if (IS_ERR(rdev)) { dev_err(&i2c->dev, "Failed to register DA9210 regulator\n"); -- cgit v1.2.3 From de2080d41b5d584205e408d72021f0f335a046fc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 31 Jan 2015 23:42:34 -0500 Subject: gadget/function/f_fs.c: close leaks If ffs_epfile_io() fails in AIO case, we end up leaking io_data (and iovec_copy in case of AIO read). Signed-off-by: Al Viro --- drivers/usb/gadget/function/f_fs.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index af98b096af2f..3ab34a2075df 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -970,6 +970,7 @@ static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, unsigned long nr_segs, loff_t loff) { struct ffs_io_data *io_data; + ssize_t res; ENTER(); @@ -989,7 +990,10 @@ static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); - return ffs_epfile_io(kiocb->ki_filp, io_data); + res = ffs_epfile_io(kiocb->ki_filp, io_data); + if (res != -EIOCBQUEUED) + kfree(io_data); + return res; } static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, @@ -998,6 +1002,7 @@ static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, { struct ffs_io_data *io_data; struct iovec *iovec_copy; + ssize_t res; ENTER(); @@ -1025,7 +1030,12 @@ static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); - return ffs_epfile_io(kiocb->ki_filp, io_data); + res = ffs_epfile_io(kiocb->ki_filp, io_data); + if (res != -EIOCBQUEUED) { + kfree(io_data); + kfree(iovec_copy); + } + return res; } static int -- cgit v1.2.3 From c993c39b86398c627afda36b45dc92de655e213e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 31 Jan 2015 23:23:35 -0500 Subject: gadget/function/f_fs.c: use put iov_iter into io_data both on aio and non-aio sides Signed-off-by: Al Viro --- drivers/usb/gadget/function/f_fs.c | 86 +++++++++++--------------------------- 1 file changed, 25 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 3ab34a2075df..98610e4595de 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -144,10 +144,9 @@ struct ffs_io_data { bool read; struct kiocb *kiocb; - const struct iovec *iovec; - unsigned long nr_segs; - char __user *buf; - size_t len; + struct iov_iter data; + const void *to_free; + char *buf; struct mm_struct *mm; struct work_struct work; @@ -649,29 +648,10 @@ static void ffs_user_copy_worker(struct work_struct *work) io_data->req->actual; if (io_data->read && ret > 0) { - int i; - size_t pos = 0; - - /* - * Since req->length may be bigger than io_data->len (after - * being rounded up to maxpacketsize), we may end up with more - * data then user space has space for. - */ - ret = min_t(int, ret, io_data->len); - use_mm(io_data->mm); - for (i = 0; i < io_data->nr_segs; i++) { - size_t len = min_t(size_t, ret - pos, - io_data->iovec[i].iov_len); - if (!len) - break; - if (unlikely(copy_to_user(io_data->iovec[i].iov_base, - &io_data->buf[pos], len))) { - ret = -EFAULT; - break; - } - pos += len; - } + ret = copy_to_iter(io_data->buf, ret, &io_data->data); + if (iov_iter_count(&io_data->data)) + ret = -EFAULT; unuse_mm(io_data->mm); } @@ -684,7 +664,7 @@ static void ffs_user_copy_worker(struct work_struct *work) io_data->kiocb->private = NULL; if (io_data->read) - kfree(io_data->iovec); + kfree(io_data->to_free); kfree(io_data->buf); kfree(io_data); } @@ -743,6 +723,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * before the waiting completes, so do not assign to 'gadget' earlier */ struct usb_gadget *gadget = epfile->ffs->gadget; + size_t copied; spin_lock_irq(&epfile->ffs->eps_lock); /* In the meantime, endpoint got disabled or changed. */ @@ -750,34 +731,21 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) spin_unlock_irq(&epfile->ffs->eps_lock); return -ESHUTDOWN; } + data_len = iov_iter_count(&io_data->data); /* * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint. */ - data_len = io_data->read ? - usb_ep_align_maybe(gadget, ep->ep, io_data->len) : - io_data->len; + if (io_data->read) + data_len = usb_ep_align_maybe(gadget, ep->ep, data_len); spin_unlock_irq(&epfile->ffs->eps_lock); data = kmalloc(data_len, GFP_KERNEL); if (unlikely(!data)) return -ENOMEM; - if (io_data->aio && !io_data->read) { - int i; - size_t pos = 0; - for (i = 0; i < io_data->nr_segs; i++) { - if (unlikely(copy_from_user(&data[pos], - io_data->iovec[i].iov_base, - io_data->iovec[i].iov_len))) { - ret = -EFAULT; - goto error; - } - pos += io_data->iovec[i].iov_len; - } - } else { - if (!io_data->read && - unlikely(__copy_from_user(data, io_data->buf, - io_data->len))) { + if (!io_data->read) { + copied = copy_from_iter(data, data_len, &io_data->data); + if (copied != data_len) { ret = -EFAULT; goto error; } @@ -876,10 +844,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) */ ret = ep->status; if (io_data->read && ret > 0) { - ret = min_t(size_t, ret, io_data->len); - - if (unlikely(copy_to_user(io_data->buf, - data, ret))) + ret = copy_to_iter(data, ret, &io_data->data); + if (unlikely(iov_iter_count(&io_data->data))) ret = -EFAULT; } } @@ -903,13 +869,13 @@ ffs_epfile_write(struct file *file, const char __user *buf, size_t len, loff_t *ptr) { struct ffs_io_data io_data; + struct iovec iov = {.iov_base = buf, .iov_len = len}; ENTER(); io_data.aio = false; io_data.read = false; - io_data.buf = (char * __user)buf; - io_data.len = len; + iov_iter_init(&io_data.data, WRITE, &iov, 1, len); return ffs_epfile_io(file, &io_data); } @@ -918,13 +884,14 @@ static ssize_t ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) { struct ffs_io_data io_data; + struct iovec iov = {.iov_base = buf, .iov_len = len}; ENTER(); io_data.aio = false; io_data.read = true; - io_data.buf = buf; - io_data.len = len; + io_data.to_free = NULL; + iov_iter_init(&io_data.data, READ, &iov, 1, len); return ffs_epfile_io(file, &io_data); } @@ -981,9 +948,7 @@ static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, io_data->aio = true; io_data->read = false; io_data->kiocb = kiocb; - io_data->iovec = iovec; - io_data->nr_segs = nr_segs; - io_data->len = kiocb->ki_nbytes; + iov_iter_init(&io_data->data, WRITE, iovec, nr_segs, kiocb->ki_nbytes); io_data->mm = current->mm; kiocb->private = io_data; @@ -1021,9 +986,8 @@ static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, io_data->aio = true; io_data->read = true; io_data->kiocb = kiocb; - io_data->iovec = iovec_copy; - io_data->nr_segs = nr_segs; - io_data->len = kiocb->ki_nbytes; + io_data->to_free = iovec_copy; + iov_iter_init(&io_data->data, READ, iovec_copy, nr_segs, kiocb->ki_nbytes); io_data->mm = current->mm; kiocb->private = io_data; @@ -1032,8 +996,8 @@ static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, res = ffs_epfile_io(kiocb->ki_filp, io_data); if (res != -EIOCBQUEUED) { + kfree(io_data->to_free); kfree(io_data); - kfree(iovec_copy); } return res; } -- cgit v1.2.3 From 70e60d917e91fff2237095b8950810effa2b1a50 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 31 Jan 2015 23:55:39 -0500 Subject: gadget/function/f_fs.c: switch to ->{read,write}_iter() Signed-off-by: Al Viro --- drivers/usb/gadget/function/f_fs.c | 136 ++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 98610e4595de..175c9956cbe3 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -864,38 +864,6 @@ error: return ret; } -static ssize_t -ffs_epfile_write(struct file *file, const char __user *buf, size_t len, - loff_t *ptr) -{ - struct ffs_io_data io_data; - struct iovec iov = {.iov_base = buf, .iov_len = len}; - - ENTER(); - - io_data.aio = false; - io_data.read = false; - iov_iter_init(&io_data.data, WRITE, &iov, 1, len); - - return ffs_epfile_io(file, &io_data); -} - -static ssize_t -ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) -{ - struct ffs_io_data io_data; - struct iovec iov = {.iov_base = buf, .iov_len = len}; - - ENTER(); - - io_data.aio = false; - io_data.read = true; - io_data.to_free = NULL; - iov_iter_init(&io_data.data, READ, &iov, 1, len); - - return ffs_epfile_io(file, &io_data); -} - static int ffs_epfile_open(struct inode *inode, struct file *file) { @@ -932,72 +900,84 @@ static int ffs_aio_cancel(struct kiocb *kiocb) return value; } -static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, - const struct iovec *iovec, - unsigned long nr_segs, loff_t loff) +static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) { - struct ffs_io_data *io_data; + struct ffs_io_data io_data, *p = &io_data; ssize_t res; ENTER(); - io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); - if (unlikely(!io_data)) - return -ENOMEM; + if (!is_sync_kiocb(kiocb)) { + p = kmalloc(sizeof(io_data), GFP_KERNEL); + if (unlikely(!p)) + return -ENOMEM; + p->aio = true; + } else { + p->aio = false; + } - io_data->aio = true; - io_data->read = false; - io_data->kiocb = kiocb; - iov_iter_init(&io_data->data, WRITE, iovec, nr_segs, kiocb->ki_nbytes); - io_data->mm = current->mm; + p->read = false; + p->kiocb = kiocb; + p->data = *from; + p->mm = current->mm; - kiocb->private = io_data; + kiocb->private = p; kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); - res = ffs_epfile_io(kiocb->ki_filp, io_data); - if (res != -EIOCBQUEUED) - kfree(io_data); + res = ffs_epfile_io(kiocb->ki_filp, p); + if (res == -EIOCBQUEUED) + return res; + if (p->aio) + kfree(p); + else + *from = p->data; return res; } -static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, - const struct iovec *iovec, - unsigned long nr_segs, loff_t loff) +static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) { - struct ffs_io_data *io_data; - struct iovec *iovec_copy; + struct ffs_io_data io_data, *p = &io_data; ssize_t res; ENTER(); - iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL); - if (unlikely(!iovec_copy)) - return -ENOMEM; - - memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs); - - io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); - if (unlikely(!io_data)) { - kfree(iovec_copy); - return -ENOMEM; + if (!is_sync_kiocb(kiocb)) { + p = kmalloc(sizeof(io_data), GFP_KERNEL); + if (unlikely(!p)) + return -ENOMEM; + p->aio = true; + } else { + p->aio = false; } - io_data->aio = true; - io_data->read = true; - io_data->kiocb = kiocb; - io_data->to_free = iovec_copy; - iov_iter_init(&io_data->data, READ, iovec_copy, nr_segs, kiocb->ki_nbytes); - io_data->mm = current->mm; + p->read = true; + p->kiocb = kiocb; + if (p->aio) { + p->to_free = dup_iter(&p->data, to, GFP_KERNEL); + if (!p->to_free) { + kfree(p); + return -ENOMEM; + } + } else { + p->data = *to; + p->to_free = NULL; + } + p->mm = current->mm; - kiocb->private = io_data; + kiocb->private = p; kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); - res = ffs_epfile_io(kiocb->ki_filp, io_data); - if (res != -EIOCBQUEUED) { - kfree(io_data->to_free); - kfree(io_data); + res = ffs_epfile_io(kiocb->ki_filp, p); + if (res == -EIOCBQUEUED) + return res; + + if (p->aio) { + kfree(p->to_free); + kfree(p); + } else { + *to = p->data; } return res; } @@ -1079,10 +1059,10 @@ static const struct file_operations ffs_epfile_operations = { .llseek = no_llseek, .open = ffs_epfile_open, - .write = ffs_epfile_write, - .read = ffs_epfile_read, - .aio_write = ffs_epfile_aio_write, - .aio_read = ffs_epfile_aio_read, + .write = new_sync_write, + .read = new_sync_read, + .write_iter = ffs_epfile_write_iter, + .read_iter = ffs_epfile_read_iter, .release = ffs_epfile_release, .unlocked_ioctl = ffs_epfile_ioctl, }; -- cgit v1.2.3 From f01d35a15fa04162a58b95970fc01fa70ec9dacd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 6 Feb 2015 02:07:45 -0500 Subject: gadgetfs: use-after-free in ->aio_read() AIO_PREAD requests call ->aio_read() with iovec on caller's stack, so if we are going to access it asynchronously, we'd better get ourselves a copy - the one on kernel stack of aio_run_iocb() won't be there anymore. function/f_fs.c take care of doing that, legacy/inode.c doesn't... Cc: stable@vger.kernel.org Signed-off-by: Al Viro --- drivers/usb/gadget/legacy/inode.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index db49ec4c748e..9fbbaa041a31 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -566,7 +566,6 @@ static ssize_t ep_copy_to_user(struct kiocb_priv *priv) if (total == 0) break; } - return len; } @@ -585,6 +584,7 @@ static void ep_user_copy_worker(struct work_struct *work) aio_complete(iocb, ret, ret); kfree(priv->buf); + kfree(priv->iv); kfree(priv); } @@ -605,6 +605,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) */ if (priv->iv == NULL || unlikely(req->actual == 0)) { kfree(req->buf); + kfree(priv->iv); kfree(priv); iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ @@ -640,7 +641,7 @@ ep_aio_rwtail( struct usb_request *req; ssize_t value; - priv = kmalloc(sizeof *priv, GFP_KERNEL); + priv = kzalloc(sizeof *priv, GFP_KERNEL); if (!priv) { value = -ENOMEM; fail: @@ -649,7 +650,14 @@ fail: } iocb->private = priv; priv->iocb = iocb; - priv->iv = iv; + if (iv) { + priv->iv = kmemdup(iv, nr_segs * sizeof(struct iovec), + GFP_KERNEL); + if (!priv->iv) { + kfree(priv); + goto fail; + } + } priv->nr_segs = nr_segs; INIT_WORK(&priv->work, ep_user_copy_worker); @@ -689,6 +697,7 @@ fail: mutex_unlock(&epdata->lock); if (unlikely(value)) { + kfree(priv->iv); kfree(priv); put_ep(epdata); } else -- cgit v1.2.3 From 7fe3976e0f3ab26f8ffd9430d3d2a19a70f2c8d2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 7 Feb 2015 00:30:23 -0500 Subject: gadget: switch ep_io_operations to ->read_iter/->write_iter Signed-off-by: Al Viro --- drivers/usb/gadget/legacy/inode.c | 355 +++++++++++++++----------------------- 1 file changed, 141 insertions(+), 214 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 9fbbaa041a31..b825edcbf387 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -363,97 +363,6 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len) return value; } - -/* handle a synchronous OUT bulk/intr/iso transfer */ -static ssize_t -ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) -{ - struct ep_data *data = fd->private_data; - void *kbuf; - ssize_t value; - - if ((value = get_ready_ep (fd->f_flags, data)) < 0) - return value; - - /* halt any endpoint by doing a "wrong direction" i/o call */ - if (usb_endpoint_dir_in(&data->desc)) { - if (usb_endpoint_xfer_isoc(&data->desc)) { - mutex_unlock(&data->lock); - return -EINVAL; - } - DBG (data->dev, "%s halt\n", data->name); - spin_lock_irq (&data->dev->lock); - if (likely (data->ep != NULL)) - usb_ep_set_halt (data->ep); - spin_unlock_irq (&data->dev->lock); - mutex_unlock(&data->lock); - return -EBADMSG; - } - - /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */ - - value = -ENOMEM; - kbuf = kmalloc (len, GFP_KERNEL); - if (unlikely (!kbuf)) - goto free1; - - value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s read %zu OUT, status %d\n", - data->name, len, (int) value); - if (value >= 0 && copy_to_user (buf, kbuf, value)) - value = -EFAULT; - -free1: - mutex_unlock(&data->lock); - kfree (kbuf); - return value; -} - -/* handle a synchronous IN bulk/intr/iso transfer */ -static ssize_t -ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) -{ - struct ep_data *data = fd->private_data; - void *kbuf; - ssize_t value; - - if ((value = get_ready_ep (fd->f_flags, data)) < 0) - return value; - - /* halt any endpoint by doing a "wrong direction" i/o call */ - if (!usb_endpoint_dir_in(&data->desc)) { - if (usb_endpoint_xfer_isoc(&data->desc)) { - mutex_unlock(&data->lock); - return -EINVAL; - } - DBG (data->dev, "%s halt\n", data->name); - spin_lock_irq (&data->dev->lock); - if (likely (data->ep != NULL)) - usb_ep_set_halt (data->ep); - spin_unlock_irq (&data->dev->lock); - mutex_unlock(&data->lock); - return -EBADMSG; - } - - /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */ - - value = -ENOMEM; - kbuf = memdup_user(buf, len); - if (IS_ERR(kbuf)) { - value = PTR_ERR(kbuf); - kbuf = NULL; - goto free1; - } - - value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s write %zu IN, status %d\n", - data->name, len, (int) value); -free1: - mutex_unlock(&data->lock); - kfree (kbuf); - return value; -} - static int ep_release (struct inode *inode, struct file *fd) { @@ -517,8 +426,8 @@ struct kiocb_priv { struct mm_struct *mm; struct work_struct work; void *buf; - const struct iovec *iv; - unsigned long nr_segs; + struct iov_iter to; + const void *to_free; unsigned actual; }; @@ -541,34 +450,6 @@ static int ep_aio_cancel(struct kiocb *iocb) return value; } -static ssize_t ep_copy_to_user(struct kiocb_priv *priv) -{ - ssize_t len, total; - void *to_copy; - int i; - - /* copy stuff into user buffers */ - total = priv->actual; - len = 0; - to_copy = priv->buf; - for (i=0; i < priv->nr_segs; i++) { - ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); - - if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) { - if (len == 0) - len = -EFAULT; - break; - } - - total -= this; - len += this; - to_copy += this; - if (total == 0) - break; - } - return len; -} - static void ep_user_copy_worker(struct work_struct *work) { struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work); @@ -577,14 +458,16 @@ static void ep_user_copy_worker(struct work_struct *work) size_t ret; use_mm(mm); - ret = ep_copy_to_user(priv); + ret = copy_to_iter(priv->buf, priv->actual, &priv->to); unuse_mm(mm); + if (!ret) + ret = -EFAULT; /* completing the iocb can drop the ctx and mm, don't touch mm after */ aio_complete(iocb, ret, ret); kfree(priv->buf); - kfree(priv->iv); + kfree(priv->to_free); kfree(priv); } @@ -603,9 +486,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) * don't need to copy anything to userspace, so we can * complete the aio request immediately. */ - if (priv->iv == NULL || unlikely(req->actual == 0)) { + if (priv->to_free == NULL || unlikely(req->actual == 0)) { kfree(req->buf); - kfree(priv->iv); + kfree(priv->to_free); kfree(priv); iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ @@ -619,6 +502,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) priv->buf = req->buf; priv->actual = req->actual; + INIT_WORK(&priv->work, ep_user_copy_worker); schedule_work(&priv->work); } spin_unlock(&epdata->dev->lock); @@ -627,45 +511,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) put_ep(epdata); } -static ssize_t -ep_aio_rwtail( - struct kiocb *iocb, - char *buf, - size_t len, - struct ep_data *epdata, - const struct iovec *iv, - unsigned long nr_segs -) +static ssize_t ep_aio(struct kiocb *iocb, + struct kiocb_priv *priv, + struct ep_data *epdata, + char *buf, + size_t len) { - struct kiocb_priv *priv; - struct usb_request *req; - ssize_t value; + struct usb_request *req; + ssize_t value; - priv = kzalloc(sizeof *priv, GFP_KERNEL); - if (!priv) { - value = -ENOMEM; -fail: - kfree(buf); - return value; - } iocb->private = priv; priv->iocb = iocb; - if (iv) { - priv->iv = kmemdup(iv, nr_segs * sizeof(struct iovec), - GFP_KERNEL); - if (!priv->iv) { - kfree(priv); - goto fail; - } - } - priv->nr_segs = nr_segs; - INIT_WORK(&priv->work, ep_user_copy_worker); - - value = get_ready_ep(iocb->ki_filp->f_flags, epdata); - if (unlikely(value < 0)) { - kfree(priv); - goto fail; - } kiocb_set_cancel_fn(iocb, ep_aio_cancel); get_ep(epdata); @@ -677,76 +533,147 @@ fail: * allocate or submit those if the host disconnected. */ spin_lock_irq(&epdata->dev->lock); - if (likely(epdata->ep)) { - req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC); - if (likely(req)) { - priv->req = req; - req->buf = buf; - req->length = len; - req->complete = ep_aio_complete; - req->context = iocb; - value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC); - if (unlikely(0 != value)) - usb_ep_free_request(epdata->ep, req); - } else - value = -EAGAIN; - } else - value = -ENODEV; - spin_unlock_irq(&epdata->dev->lock); + value = -ENODEV; + if (unlikely(epdata->ep)) + goto fail; - mutex_unlock(&epdata->lock); + req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC); + value = -ENOMEM; + if (unlikely(!req)) + goto fail; - if (unlikely(value)) { - kfree(priv->iv); - kfree(priv); - put_ep(epdata); - } else - value = -EIOCBQUEUED; + priv->req = req; + req->buf = buf; + req->length = len; + req->complete = ep_aio_complete; + req->context = iocb; + value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC); + if (unlikely(0 != value)) { + usb_ep_free_request(epdata->ep, req); + goto fail; + } + spin_unlock_irq(&epdata->dev->lock); + return -EIOCBQUEUED; + +fail: + spin_unlock_irq(&epdata->dev->lock); + kfree(priv->to_free); + kfree(priv); + put_ep(epdata); return value; } static ssize_t -ep_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t o) +ep_read_iter(struct kiocb *iocb, struct iov_iter *to) { - struct ep_data *epdata = iocb->ki_filp->private_data; - char *buf; + struct file *file = iocb->ki_filp; + struct ep_data *epdata = file->private_data; + size_t len = iov_iter_count(to); + ssize_t value; + char *buf; - if (unlikely(usb_endpoint_dir_in(&epdata->desc))) - return -EINVAL; + if ((value = get_ready_ep(file->f_flags, epdata)) < 0) + return value; - buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL); - if (unlikely(!buf)) - return -ENOMEM; + /* halt any endpoint by doing a "wrong direction" i/o call */ + if (usb_endpoint_dir_in(&epdata->desc)) { + if (usb_endpoint_xfer_isoc(&epdata->desc) || + !is_sync_kiocb(iocb)) { + mutex_unlock(&epdata->lock); + return -EINVAL; + } + DBG (epdata->dev, "%s halt\n", epdata->name); + spin_lock_irq(&epdata->dev->lock); + if (likely(epdata->ep != NULL)) + usb_ep_set_halt(epdata->ep); + spin_unlock_irq(&epdata->dev->lock); + mutex_unlock(&epdata->lock); + return -EBADMSG; + } - return ep_aio_rwtail(iocb, buf, iocb->ki_nbytes, epdata, iov, nr_segs); + buf = kmalloc(len, GFP_KERNEL); + if (unlikely(!buf)) { + mutex_unlock(&epdata->lock); + return -ENOMEM; + } + if (is_sync_kiocb(iocb)) { + value = ep_io(epdata, buf, len); + if (value >= 0 && copy_to_iter(buf, value, to)) + value = -EFAULT; + } else { + struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL); + value = -ENOMEM; + if (!priv) + goto fail; + priv->to_free = dup_iter(&priv->to, to, GFP_KERNEL); + if (!priv->to_free) { + kfree(priv); + goto fail; + } + value = ep_aio(iocb, priv, epdata, buf, len); + if (value == -EIOCBQUEUED) + buf = NULL; + } +fail: + kfree(buf); + mutex_unlock(&epdata->lock); + return value; } static ssize_t -ep_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t o) +ep_write_iter(struct kiocb *iocb, struct iov_iter *from) { - struct ep_data *epdata = iocb->ki_filp->private_data; - char *buf; - size_t len = 0; - int i = 0; + struct file *file = iocb->ki_filp; + struct ep_data *epdata = file->private_data; + size_t len = iov_iter_count(from); + ssize_t value; + char *buf; - if (unlikely(!usb_endpoint_dir_in(&epdata->desc))) - return -EINVAL; + if ((value = get_ready_ep(file->f_flags, epdata)) < 0) + return value; - buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL); - if (unlikely(!buf)) + /* halt any endpoint by doing a "wrong direction" i/o call */ + if (!usb_endpoint_dir_in(&epdata->desc)) { + if (usb_endpoint_xfer_isoc(&epdata->desc) || + !is_sync_kiocb(iocb)) { + mutex_unlock(&epdata->lock); + return -EINVAL; + } + DBG (epdata->dev, "%s halt\n", epdata->name); + spin_lock_irq(&epdata->dev->lock); + if (likely(epdata->ep != NULL)) + usb_ep_set_halt(epdata->ep); + spin_unlock_irq(&epdata->dev->lock); + mutex_unlock(&epdata->lock); + return -EBADMSG; + } + + buf = kmalloc(len, GFP_KERNEL); + if (unlikely(!buf)) { + mutex_unlock(&epdata->lock); return -ENOMEM; + } - for (i=0; i < nr_segs; i++) { - if (unlikely(copy_from_user(&buf[len], iov[i].iov_base, - iov[i].iov_len) != 0)) { - kfree(buf); - return -EFAULT; + if (unlikely(copy_from_iter(buf, len, from) != len)) { + value = -EFAULT; + goto out; + } + + if (is_sync_kiocb(iocb)) { + value = ep_io(epdata, buf, len); + } else { + struct kiocb_priv *priv = kzalloc(sizeof *priv, GFP_KERNEL); + value = -ENOMEM; + if (priv) { + value = ep_aio(iocb, priv, epdata, buf, len); + if (value == -EIOCBQUEUED) + buf = NULL; } - len += iov[i].iov_len; } - return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0); +out: + kfree(buf); + mutex_unlock(&epdata->lock); + return value; } /*----------------------------------------------------------------------*/ @@ -756,13 +683,13 @@ static const struct file_operations ep_io_operations = { .owner = THIS_MODULE, .llseek = no_llseek, - .read = ep_read, - .write = ep_write, + .read = new_sync_read, + .write = new_sync_write, .unlocked_ioctl = ep_ioctl, .release = ep_release, - .aio_read = ep_aio_read, - .aio_write = ep_aio_write, + .read_iter = ep_read_iter, + .write_iter = ep_write_iter, }; /* ENDPOINT INITIALIZATION -- cgit v1.2.3 From ce204e9a4bd82e9e6e7479bca8057e45aaac5c42 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Wed, 18 Feb 2015 15:51:41 +0200 Subject: firmware: dmi_scan: Fix dmi scan to handle "End of Table" structure The dmi-sysfs should create "End of Table" entry, that is type 127. But after adding initial SMBIOS v3 support fc43026278b2 ("dmi: add support for SMBIOS 3.0 64-bit entry point") the 127-0 entry is not handled any more, as result it's not created in dmi sysfs for instance. This is important because the size of whole DMI table must correspond to sum of all DMI entry sizes. So move the end-of-table check after it's handled by dmi_table. Reviewed-by: Ard Biesheuvel Signed-off-by: Ivan Khoronzhuk Cc: # v3.19 Signed-off-by: Matt Fleming --- drivers/firmware/dmi_scan.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index c5f7b4e9eb6c..a44b87c7b45c 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -92,12 +92,6 @@ static void dmi_table(u8 *buf, int len, int num, while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { const struct dmi_header *dm = (const struct dmi_header *)data; - /* - * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0] - */ - if (dm->type == DMI_ENTRY_END_OF_TABLE) - break; - /* * We want to know the total length (formatted area and * strings) before decoding to make sure we won't run off the @@ -108,6 +102,13 @@ static void dmi_table(u8 *buf, int len, int num, data++; if (data - buf < len - 1) decode(dm, private_data); + + /* + * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0] + */ + if (dm->type == DMI_ENTRY_END_OF_TABLE) + break; + data += 2; i++; } -- cgit v1.2.3 From aa183323312dbd1457096b4b94ca274b35fc462b Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 15 Feb 2015 17:44:20 -0200 Subject: ehea: Register memory hotplug, reboot and crash hooks on adapter probe ehea creates memory hotplug, reboot and crash hooks even if there are no adapters in the box. Just create them when we probe our first adapter. [cascardo: use ehea_register_memory_hooks return code] Signed-off-by: Anton Blanchard Tested-by: Thadeu Lima de Souza Cascardo Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ehea/ehea_main.c | 246 +++++++++++++++++------------- 1 file changed, 141 insertions(+), 105 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index e8a1adb7a962..c05e50759621 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -3262,6 +3262,139 @@ static void ehea_remove_device_sysfs(struct platform_device *dev) device_remove_file(&dev->dev, &dev_attr_remove_port); } +static int ehea_reboot_notifier(struct notifier_block *nb, + unsigned long action, void *unused) +{ + if (action == SYS_RESTART) { + pr_info("Reboot: freeing all eHEA resources\n"); + ibmebus_unregister_driver(&ehea_driver); + } + return NOTIFY_DONE; +} + +static struct notifier_block ehea_reboot_nb = { + .notifier_call = ehea_reboot_notifier, +}; + +static int ehea_mem_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + int ret = NOTIFY_BAD; + struct memory_notify *arg = data; + + mutex_lock(&dlpar_mem_lock); + + switch (action) { + case MEM_CANCEL_OFFLINE: + pr_info("memory offlining canceled"); + /* Fall through: re-add canceled memory block */ + + case MEM_ONLINE: + pr_info("memory is going online"); + set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); + if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages)) + goto out_unlock; + ehea_rereg_mrs(); + break; + + case MEM_GOING_OFFLINE: + pr_info("memory is going offline"); + set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); + if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages)) + goto out_unlock; + ehea_rereg_mrs(); + break; + + default: + break; + } + + ehea_update_firmware_handles(); + ret = NOTIFY_OK; + +out_unlock: + mutex_unlock(&dlpar_mem_lock); + return ret; +} + +static struct notifier_block ehea_mem_nb = { + .notifier_call = ehea_mem_notifier, +}; + +static void ehea_crash_handler(void) +{ + int i; + + if (ehea_fw_handles.arr) + for (i = 0; i < ehea_fw_handles.num_entries; i++) + ehea_h_free_resource(ehea_fw_handles.arr[i].adh, + ehea_fw_handles.arr[i].fwh, + FORCE_FREE); + + if (ehea_bcmc_regs.arr) + for (i = 0; i < ehea_bcmc_regs.num_entries; i++) + ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh, + ehea_bcmc_regs.arr[i].port_id, + ehea_bcmc_regs.arr[i].reg_type, + ehea_bcmc_regs.arr[i].macaddr, + 0, H_DEREG_BCMC); +} + +static atomic_t ehea_memory_hooks_registered; + +/* Register memory hooks on probe of first adapter */ +static int ehea_register_memory_hooks(void) +{ + int ret = 0; + + if (atomic_inc_and_test(&ehea_memory_hooks_registered)) + return 0; + + ret = ehea_create_busmap(); + if (ret) { + pr_info("ehea_create_busmap failed\n"); + goto out; + } + + ret = register_reboot_notifier(&ehea_reboot_nb); + if (ret) { + pr_info("register_reboot_notifier failed\n"); + goto out; + } + + ret = register_memory_notifier(&ehea_mem_nb); + if (ret) { + pr_info("register_memory_notifier failed\n"); + goto out2; + } + + ret = crash_shutdown_register(ehea_crash_handler); + if (ret) { + pr_info("crash_shutdown_register failed\n"); + goto out3; + } + + return 0; + +out3: + unregister_memory_notifier(&ehea_mem_nb); +out2: + unregister_reboot_notifier(&ehea_reboot_nb); +out: + return ret; +} + +static void ehea_unregister_memory_hooks(void) +{ + if (atomic_read(&ehea_memory_hooks_registered)) + return; + + unregister_reboot_notifier(&ehea_reboot_nb); + if (crash_shutdown_unregister(ehea_crash_handler)) + pr_info("failed unregistering crash handler\n"); + unregister_memory_notifier(&ehea_mem_nb); +} + static int ehea_probe_adapter(struct platform_device *dev) { struct ehea_adapter *adapter; @@ -3269,6 +3402,10 @@ static int ehea_probe_adapter(struct platform_device *dev) int ret; int i; + ret = ehea_register_memory_hooks(); + if (ret) + return ret; + if (!dev || !dev->dev.of_node) { pr_err("Invalid ibmebus device probed\n"); return -EINVAL; @@ -3392,81 +3529,6 @@ static int ehea_remove(struct platform_device *dev) return 0; } -static void ehea_crash_handler(void) -{ - int i; - - if (ehea_fw_handles.arr) - for (i = 0; i < ehea_fw_handles.num_entries; i++) - ehea_h_free_resource(ehea_fw_handles.arr[i].adh, - ehea_fw_handles.arr[i].fwh, - FORCE_FREE); - - if (ehea_bcmc_regs.arr) - for (i = 0; i < ehea_bcmc_regs.num_entries; i++) - ehea_h_reg_dereg_bcmc(ehea_bcmc_regs.arr[i].adh, - ehea_bcmc_regs.arr[i].port_id, - ehea_bcmc_regs.arr[i].reg_type, - ehea_bcmc_regs.arr[i].macaddr, - 0, H_DEREG_BCMC); -} - -static int ehea_mem_notifier(struct notifier_block *nb, - unsigned long action, void *data) -{ - int ret = NOTIFY_BAD; - struct memory_notify *arg = data; - - mutex_lock(&dlpar_mem_lock); - - switch (action) { - case MEM_CANCEL_OFFLINE: - pr_info("memory offlining canceled"); - /* Readd canceled memory block */ - case MEM_ONLINE: - pr_info("memory is going online"); - set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); - if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages)) - goto out_unlock; - ehea_rereg_mrs(); - break; - case MEM_GOING_OFFLINE: - pr_info("memory is going offline"); - set_bit(__EHEA_STOP_XFER, &ehea_driver_flags); - if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages)) - goto out_unlock; - ehea_rereg_mrs(); - break; - default: - break; - } - - ehea_update_firmware_handles(); - ret = NOTIFY_OK; - -out_unlock: - mutex_unlock(&dlpar_mem_lock); - return ret; -} - -static struct notifier_block ehea_mem_nb = { - .notifier_call = ehea_mem_notifier, -}; - -static int ehea_reboot_notifier(struct notifier_block *nb, - unsigned long action, void *unused) -{ - if (action == SYS_RESTART) { - pr_info("Reboot: freeing all eHEA resources\n"); - ibmebus_unregister_driver(&ehea_driver); - } - return NOTIFY_DONE; -} - -static struct notifier_block ehea_reboot_nb = { - .notifier_call = ehea_reboot_notifier, -}; - static int check_module_parm(void) { int ret = 0; @@ -3520,26 +3582,10 @@ static int __init ehea_module_init(void) if (ret) goto out; - ret = ehea_create_busmap(); - if (ret) - goto out; - - ret = register_reboot_notifier(&ehea_reboot_nb); - if (ret) - pr_info("failed registering reboot notifier\n"); - - ret = register_memory_notifier(&ehea_mem_nb); - if (ret) - pr_info("failed registering memory remove notifier\n"); - - ret = crash_shutdown_register(ehea_crash_handler); - if (ret) - pr_info("failed registering crash handler\n"); - ret = ibmebus_register_driver(&ehea_driver); if (ret) { pr_err("failed registering eHEA device driver on ebus\n"); - goto out2; + goto out; } ret = driver_create_file(&ehea_driver.driver, @@ -3547,32 +3593,22 @@ static int __init ehea_module_init(void) if (ret) { pr_err("failed to register capabilities attribute, ret=%d\n", ret); - goto out3; + goto out2; } return ret; -out3: - ibmebus_unregister_driver(&ehea_driver); out2: - unregister_memory_notifier(&ehea_mem_nb); - unregister_reboot_notifier(&ehea_reboot_nb); - crash_shutdown_unregister(ehea_crash_handler); + ibmebus_unregister_driver(&ehea_driver); out: return ret; } static void __exit ehea_module_exit(void) { - int ret; - driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities); ibmebus_unregister_driver(&ehea_driver); - unregister_reboot_notifier(&ehea_reboot_nb); - ret = crash_shutdown_unregister(ehea_crash_handler); - if (ret) - pr_info("failed unregistering crash handler\n"); - unregister_memory_notifier(&ehea_mem_nb); + ehea_unregister_memory_hooks(); kfree(ehea_fw_handles.arr); kfree(ehea_bcmc_regs.arr); ehea_destroy_busmap(); -- cgit v1.2.3 From 42c972a1f390e3bc51ca1e434b7e28764992067f Mon Sep 17 00:00:00 2001 From: Ben Shelton Date: Mon, 16 Feb 2015 13:47:06 -0600 Subject: usb: plusb: Add support for National Instruments host-to-host cable The National Instruments USB Host-to-Host Cable is based on the Prolific PL-25A1 chipset. Add its VID/PID so the plusb driver will recognize it. Signed-off-by: Ben Shelton Signed-off-by: David S. Miller --- drivers/net/usb/plusb.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 3d18bb0eee85..1bfe0fcaccf5 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -134,6 +134,11 @@ static const struct usb_device_id products [] = { }, { USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */ .driver_info = (unsigned long) &prolific_info, +}, { + USB_DEVICE(0x3923, 0x7825), /* National Instruments USB + * Host-to-Host Cable + */ + .driver_info = (unsigned long) &prolific_info, }, { }, // END -- cgit v1.2.3 From 54da5a8be3c1e924c35480eb44c6e9b275f6444e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 17 Feb 2015 09:36:22 -0800 Subject: net: phy: Fix verification of EEE support in phy_init_eee phy_init_eee uses phy_find_setting(phydev->speed, phydev->duplex) to find a valid entry in the settings array for the given speed and duplex value. For full duplex 1000baseT, this will return the first matching entry, which is the entry for 1000baseKX_Full. If the phy eee does not support 1000baseKX_Full, this entry will not match, causing phy_init_eee to fail for no good reason. Fixes: 9a9c56cb34e6 ("net: phy: fix a bug when verify the EEE support") Fixes: 3e7077067e80c ("phy: Expand phy speed/duplex settings array") Cc: Giuseppe Cavallaro Signed-off-by: Guenter Roeck Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index cdcac6aa4260..52cd8db2c57d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -235,6 +235,25 @@ static inline unsigned int phy_find_valid(unsigned int idx, u32 features) return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; } +/** + * phy_check_valid - check if there is a valid PHY setting which matches + * speed, duplex, and feature mask + * @speed: speed to match + * @duplex: duplex to match + * @features: A mask of the valid settings + * + * Description: Returns true if there is a valid setting, false otherwise. + */ +static inline bool phy_check_valid(int speed, int duplex, u32 features) +{ + unsigned int idx; + + idx = phy_find_valid(phy_find_setting(speed, duplex), features); + + return settings[idx].speed == speed && settings[idx].duplex == duplex && + (settings[idx].setting & features); +} + /** * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex * @phydev: the target phy_device struct @@ -1045,7 +1064,6 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) int eee_lp, eee_cap, eee_adv; u32 lp, cap, adv; int status; - unsigned int idx; /* Read phy status to properly get the right settings */ status = phy_read_status(phydev); @@ -1077,8 +1095,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv); lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp); - idx = phy_find_setting(phydev->speed, phydev->duplex); - if (!(lp & adv & settings[idx].setting)) + if (!phy_check_valid(phydev->speed, phydev->duplex, lp & adv)) goto eee_exit_err; if (clk_stop_enable) { -- cgit v1.2.3 From f81edc6ac1e1e2e2cbe98bcd6ef5ebb7afb00807 Mon Sep 17 00:00:00 2001 From: Derrick Pallas Date: Wed, 18 Feb 2015 00:50:25 -0800 Subject: ethernet/ixp4xx: prevent allmulti from clobbering promisc If both promisc and allmulti are set, promisc should trump allmulti and disable the MAC filter; otherwise, the interface is not really promisc. Previously, this code checked IFF_ALLMULTI prior to and without regard for IFF_PROMISC; if both were set, only multicast and direct unicast traffic would make it through the filter. Signed-off-by: Derrick Pallas Signed-off-by: David S. Miller --- drivers/net/ethernet/xscale/ixp4xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index f7e0f0f7c2e2..9e16a2819d48 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -938,7 +938,7 @@ static void eth_set_mcast_list(struct net_device *dev) int i; static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; - if (dev->flags & IFF_ALLMULTI) { + if ((dev->flags & IFF_ALLMULTI) && !(dev->flags & IFF_PROMISC)) { for (i = 0; i < ETH_ALEN; i++) { __raw_writel(allmulti[i], &port->regs->mcast_addr[i]); __raw_writel(allmulti[i], &port->regs->mcast_mask[i]); -- cgit v1.2.3 From 15added6a5940454e225c09b78837514d35fcf70 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Feb 2015 20:47:30 +0100 Subject: net: smc91x: improve neponset hack The smc91x driver tries to support multiple platforms at compile time, but they are mutually exclusive at runtime, and not clearly defined. Trying to build for CONFIG_SA1100_ASSABET without CONFIG_ASSABET_NEPONSET results in this link error: drivers/built-in.o: In function `smc_drv_probe': :(.text+0x33310c): undefined reference to `neponset_ncr_frob' since the neponset_ncr_set function is not defined otherwise. Similarly, building for both CONFIG_SA1100_ASSABET and CONFIG_SA1100_PLEB results in a different build error: smsc/smc91x.c: In function 'smc_drv_probe': smsc/smc91x.c:2299:2: error: implicit declaration of function 'neponset_ncr_set' [-Werror=implicit-function-declaration] neponset_ncr_set(NCR_ENET_OSC_EN); ^ smsc/smc91x.c:2299:19: error: 'NCR_ENET_OSC_EN' undeclared (first use in this function) neponset_ncr_set(NCR_ENET_OSC_EN); ^ This is an attempt to fix the call site responsible for both errors, making sure we call the function exactly when the driver is actually trying to run on the assabet/neponset machine. With this patch, I no longer see randconfig build errors in this file. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/smc91x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 88a55f95fe09..fa3f193b5f4d 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -2355,7 +2355,7 @@ static int smc_drv_probe(struct platform_device *pdev) ret = smc_request_attrib(pdev, ndev); if (ret) goto out_release_io; -#if defined(CONFIG_SA1100_ASSABET) +#if defined(CONFIG_ASSABET_NEPONSET) && !defined(CONFIG_SA1100_PLEB) neponset_ncr_set(NCR_ENET_OSC_EN); #endif platform_set_drvdata(pdev, ndev); -- cgit v1.2.3 From bf60e50cb3ed50ae536f7655c8af1acda137ea5b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Feb 2015 20:48:54 +0100 Subject: net/appletalk: LTPC needs virt_to_bus The ltpc driver is rather outdated and does not get built on most platforms because it requires the ISA_DMA_API symbol. However there are some ARM platforms that have ISA_DMA_API but no virt_to_bus, and they get this build error when enabling the ltpc driver. drivers/net/appletalk/ltpc.c: In function 'handlefc': drivers/net/appletalk/ltpc.c:380:2: error: implicit declaration of function 'virt_to_bus' [-Werror=implicit-function-declaration] set_dma_addr(dma,virt_to_bus(ltdmacbuf)); ^ This adds another dependency in Kconfig to avoid that configuration. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller --- drivers/net/appletalk/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig index 4ce6ca5f3d36..dc6b78e5342f 100644 --- a/drivers/net/appletalk/Kconfig +++ b/drivers/net/appletalk/Kconfig @@ -40,7 +40,7 @@ config DEV_APPLETALK config LTPC tristate "Apple/Farallon LocalTalk PC support" - depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API + depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API && VIRT_TO_BUS help This allows you to use the AppleTalk PC card to connect to LocalTalk networks. The card is also known as the Farallon PhoneNet PC card. -- cgit v1.2.3 From f4c2b7a08170dc4e442c4566486e4597af8d72a3 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Wed, 18 Feb 2015 15:15:57 -0800 Subject: ipvlan: Fix text that talks about ip util support ipvlan was added into 3.19 release and iproute2 added support for the same in iproute2-3.19 package. Signed-off-by: Mahesh Bandewar CC: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 84673ebcf428..df51d6025a90 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -157,7 +157,7 @@ config IPVLAN making it transparent to the connected L2 switch. Ipvlan devices can be added using the "ip" command from the - iproute2 package starting with the iproute2-X.Y.ZZ release: + iproute2 package starting with the iproute2-3.19 release: "ip link add link [ NAME ] type ipvlan" -- cgit v1.2.3 From 5a8eeec468f229558322926f28c61bb0769793e9 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Wed, 18 Feb 2015 15:29:45 -0800 Subject: cxgb4: Fix incorrect 'c' suffix to %pI4, use %pISc instead Issue caught by 0-day kernel test infrastructure. Code changed to use sockaddr members so that %pISc can be used instead. Fixes: b5a02f503caa ('cxgb4 : Update ipv6 address handling api') Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c | 57 ++++++++++++++------------- drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h | 6 ++- 2 files changed, 33 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c index 9062a8434246..c308429dd9c7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c @@ -35,10 +35,10 @@ static inline unsigned int ipv6_clip_hash(struct clip_tbl *d, const u32 *key) } static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr, - int addr_len) + u8 v6) { - return addr_len == 4 ? ipv4_clip_hash(ctbl, addr) : - ipv6_clip_hash(ctbl, addr); + return v6 ? ipv6_clip_hash(ctbl, addr) : + ipv4_clip_hash(ctbl, addr); } static int clip6_get_mbox(const struct net_device *dev, @@ -78,23 +78,22 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) struct clip_entry *ce, *cte; u32 *addr = (u32 *)lip; int hash; - int addr_len; - int ret = 0; + int ret = -1; if (!ctbl) return 0; - if (v6) - addr_len = 16; - else - addr_len = 4; - - hash = clip_addr_hash(ctbl, addr, addr_len); + hash = clip_addr_hash(ctbl, addr, v6); read_lock_bh(&ctbl->lock); list_for_each_entry(cte, &ctbl->hash_list[hash], list) { - if (addr_len == cte->addr_len && - memcmp(lip, cte->addr, cte->addr_len) == 0) { + if (cte->addr6.sin6_family == AF_INET6 && v6) + ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr, + sizeof(struct in6_addr)); + else if (cte->addr.sin_family == AF_INET && !v6) + ret = memcmp(lip, (char *)(&cte->addr.sin_addr), + sizeof(struct in_addr)); + if (!ret) { ce = cte; read_unlock_bh(&ctbl->lock); goto found; @@ -111,15 +110,20 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) spin_lock_init(&ce->lock); atomic_set(&ce->refcnt, 0); atomic_dec(&ctbl->nfree); - ce->addr_len = addr_len; - memcpy(ce->addr, lip, addr_len); list_add_tail(&ce->list, &ctbl->hash_list[hash]); if (v6) { + ce->addr6.sin6_family = AF_INET6; + memcpy(ce->addr6.sin6_addr.s6_addr, + lip, sizeof(struct in6_addr)); ret = clip6_get_mbox(dev, (const struct in6_addr *)lip); if (ret) { write_unlock_bh(&ctbl->lock); return ret; } + } else { + ce->addr.sin_family = AF_INET; + memcpy((char *)(&ce->addr.sin_addr), lip, + sizeof(struct in_addr)); } } else { write_unlock_bh(&ctbl->lock); @@ -140,19 +144,19 @@ void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6) struct clip_entry *ce, *cte; u32 *addr = (u32 *)lip; int hash; - int addr_len; - - if (v6) - addr_len = 16; - else - addr_len = 4; + int ret = -1; - hash = clip_addr_hash(ctbl, addr, addr_len); + hash = clip_addr_hash(ctbl, addr, v6); read_lock_bh(&ctbl->lock); list_for_each_entry(cte, &ctbl->hash_list[hash], list) { - if (addr_len == cte->addr_len && - memcmp(lip, cte->addr, cte->addr_len) == 0) { + if (cte->addr6.sin6_family == AF_INET6 && v6) + ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr, + sizeof(struct in6_addr)); + else if (cte->addr.sin_family == AF_INET && !v6) + ret = memcmp(lip, (char *)(&cte->addr.sin_addr), + sizeof(struct in_addr)); + if (!ret) { ce = cte; read_unlock_bh(&ctbl->lock); goto found; @@ -249,10 +253,7 @@ int clip_tbl_show(struct seq_file *seq, void *v) for (i = 0 ; i < ctbl->clipt_size; ++i) { list_for_each_entry(ce, &ctbl->hash_list[i], list) { ip[0] = '\0'; - if (ce->addr_len == 16) - sprintf(ip, "%pI6c", ce->addr); - else - sprintf(ip, "%pI4c", ce->addr); + sprintf(ip, "%pISc", &ce->addr); seq_printf(seq, "%-25s %u\n", ip, atomic_read(&ce->refcnt)); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h index 2eaba0161cf8..35eb43c6bcbb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h @@ -14,8 +14,10 @@ struct clip_entry { spinlock_t lock; /* Hold while modifying clip reference */ atomic_t refcnt; struct list_head list; - u32 addr[4]; - int addr_len; + union { + struct sockaddr_in addr; + struct sockaddr_in6 addr6; + }; }; struct clip_tbl { -- cgit v1.2.3 From ddede6d536d70c4ef2193ca14208db90740fcd22 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 19 Feb 2015 11:09:27 -0800 Subject: net: dsa: bcm_sf2: fix 64-bits register reads Reading 64-bits register was not working because we inverted the steps between reading the lower 32-bits of the register and reading the upper 32-bits. Swapping these operations is how the HW guarantees that 64-bits reads are latched correctly. We only have a handful of 64-bits registers for now, mostly MIB counters, so the imapct is low. Fixes: 246d7f773c13 ("net: dsa: add Broadcom SF2 switch driver") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h index ee9f650d5026..7b7053d3c5fa 100644 --- a/drivers/net/dsa/bcm_sf2.h +++ b/drivers/net/dsa/bcm_sf2.h @@ -105,8 +105,8 @@ static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off) \ { \ u32 indir, dir; \ spin_lock(&priv->indir_lock); \ - indir = reg_readl(priv, REG_DIR_DATA_READ); \ dir = __raw_readl(priv->name + off); \ + indir = reg_readl(priv, REG_DIR_DATA_READ); \ spin_unlock(&priv->indir_lock); \ return (u64)indir << 32 | dir; \ } \ -- cgit v1.2.3 From 006110476478c69c399d0cd25888eefab0e69267 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Wed, 18 Feb 2015 00:33:51 +0530 Subject: drivers: spi: ti-qspi: wait for busy bit clear before data write/read Data corruption is seen while reading/writing large data from/to qspi device because the data register is over written or read before data is ready which is denoted by busy bit in status register. SO adding a busy bit check before writing/reading data to/from qspi device. Signed-off-by: Mugunthan V N Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 884a716e50cb..5c0616870358 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -101,6 +101,7 @@ struct ti_qspi { #define QSPI_FLEN(n) ((n - 1) << 0) /* STATUS REGISTER */ +#define BUSY 0x01 #define WC 0x02 /* INTERRUPT REGISTER */ @@ -199,6 +200,21 @@ static void ti_qspi_restore_ctx(struct ti_qspi *qspi) ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG); } +static inline u32 qspi_is_busy(struct ti_qspi *qspi) +{ + u32 stat; + unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT; + + stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); + while ((stat & BUSY) && time_after(timeout, jiffies)) { + cpu_relax(); + stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); + } + + WARN(stat & BUSY, "qspi busy\n"); + return stat & BUSY; +} + static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) { int wlen, count; @@ -211,6 +227,9 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) wlen = t->bits_per_word >> 3; /* in bytes */ while (count) { + if (qspi_is_busy(qspi)) + return -EBUSY; + switch (wlen) { case 1: dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", @@ -266,6 +285,9 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) while (count) { dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); + if (qspi_is_busy(qspi)) + return -EBUSY; + ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); if (!wait_for_completion_timeout(&qspi->transfer_complete, QSPI_COMPLETION_TIMEOUT)) { -- cgit v1.2.3 From 28249b0c2fa361cdac450a6f40242ed45408a24f Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Fri, 20 Feb 2015 16:53:38 -0800 Subject: regulator: rk808: Set the enable time for LDOs The LDOs are documented in the rk808 datasheet to have a soft start time of 400us. Add that to the driver. If this time takes longer on a certain board the device tree should be able to override with "regulator-enable-ramp-delay". This fixes some dw_mmc probing problems (together with other patches posted to the mmc maiing lists) on rk3288. Signed-off-by: Doug Anderson Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/regulator/rk808-regulator.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index c94a3e0f3b91..3f6722863bd2 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -235,6 +235,7 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_LDO_VSEL_MASK, .enable_reg = RK808_LDO_EN_REG, .enable_mask = BIT(0), + .enable_time = 400, .owner = THIS_MODULE, }, { .name = "LDO_REG2", @@ -249,6 +250,7 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_LDO_VSEL_MASK, .enable_reg = RK808_LDO_EN_REG, .enable_mask = BIT(1), + .enable_time = 400, .owner = THIS_MODULE, }, { .name = "LDO_REG3", @@ -263,6 +265,7 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_BUCK4_VSEL_MASK, .enable_reg = RK808_LDO_EN_REG, .enable_mask = BIT(2), + .enable_time = 400, .owner = THIS_MODULE, }, { .name = "LDO_REG4", @@ -277,6 +280,7 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_LDO_VSEL_MASK, .enable_reg = RK808_LDO_EN_REG, .enable_mask = BIT(3), + .enable_time = 400, .owner = THIS_MODULE, }, { .name = "LDO_REG5", @@ -291,6 +295,7 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_LDO_VSEL_MASK, .enable_reg = RK808_LDO_EN_REG, .enable_mask = BIT(4), + .enable_time = 400, .owner = THIS_MODULE, }, { .name = "LDO_REG6", @@ -305,6 +310,7 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_LDO_VSEL_MASK, .enable_reg = RK808_LDO_EN_REG, .enable_mask = BIT(5), + .enable_time = 400, .owner = THIS_MODULE, }, { .name = "LDO_REG7", @@ -319,6 +325,7 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_LDO_VSEL_MASK, .enable_reg = RK808_LDO_EN_REG, .enable_mask = BIT(6), + .enable_time = 400, .owner = THIS_MODULE, }, { .name = "LDO_REG8", @@ -333,6 +340,7 @@ static const struct regulator_desc rk808_reg[] = { .vsel_mask = RK808_LDO_VSEL_MASK, .enable_reg = RK808_LDO_EN_REG, .enable_mask = BIT(7), + .enable_time = 400, .owner = THIS_MODULE, }, { .name = "SWITCH_REG1", -- cgit v1.2.3 From b841118ee6c0917004e7e763c4f6bf8eb10a6d93 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 18 Feb 2015 12:39:46 +0100 Subject: iio: common: ssp_sensors: Protect PM-only functions to kill warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_PM_SLEEP=n: drivers/iio/common/ssp_sensors/ssp_dev.c:644: warning: ‘ssp_suspend’ defined but not used drivers/iio/common/ssp_sensors/ssp_dev.c:669: warning: ‘ssp_resume’ defined but not used Protect the unused functions by #ifdef CONFIG_PM_SLEEP to fix this. Signed-off-by: Geert Uytterhoeven Acked-by: Karol Wrona Signed-off-by: Jonathan Cameron --- drivers/iio/common/ssp_sensors/ssp_dev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index 52d70435f5a1..55a90082a29b 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -640,6 +640,7 @@ static int ssp_remove(struct spi_device *spi) return 0; } +#ifdef CONFIG_PM_SLEEP static int ssp_suspend(struct device *dev) { int ret; @@ -688,6 +689,7 @@ static int ssp_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops ssp_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume) -- cgit v1.2.3 From 45cee4f594bcb3083c2d8475462af2f2ddf29aff Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 20 Feb 2015 19:12:52 +0100 Subject: mISDN: replace current->state by set_current_state() Use helper function to access current->state. Direct assignments are prone to races and therefore buggy. Thanks to Peter Zijlstra for the exact definition of the problem. Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/hfcpci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 3c92780bda09..ff48da61c94c 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1755,7 +1755,7 @@ init_card(struct hfc_pci *hc) enable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); /* Timeout 80ms */ - current->state = TASK_UNINTERRUPTIBLE; + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((80 * HZ) / 1000); printk(KERN_INFO "HFC PCI: IRQ %d count %d\n", hc->irq, hc->irqcnt); -- cgit v1.2.3 From 50462ce0052c67b5a06f19fb7c7f308813006879 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 20 Feb 2015 19:12:55 +0100 Subject: hso: replace current->state by __set_current_state() Use helper functions to access current->state. Direct assignments are prone to races and therefore buggy. Thanks to Peter Zijlstra for the exact definition of the problem. Suggested-By: Peter Zijlstra Signed-off-by: Fabian Frederick Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 9cdfb3fe9c15..778e91531fac 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1594,7 +1594,7 @@ hso_wait_modem_status(struct hso_serial *serial, unsigned long arg) } cprev = cnow; } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&tiocmget->waitq, &wait); return ret; -- cgit v1.2.3 From 2c45015a66a171de306e23991fec998667b49acf Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 20 Feb 2015 19:12:56 +0100 Subject: wan: cosa: replace current->state by set_current_state() Use helper functions to access current->state. Direct assignments are prone to races and therefore buggy. current->state = TASK_RUNNING is replaced by __set_current_state() Thanks to Peter Zijlstra for the exact definition of the problem. Suggested-By: Peter Zijlstra Signed-off-by: Fabian Frederick Acked-By: Jan "Yenya" Kasprzak Signed-off-by: David S. Miller --- drivers/net/wan/cosa.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 83c39e2858bf..88d121d43c08 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -806,21 +806,21 @@ static ssize_t cosa_read(struct file *file, spin_lock_irqsave(&cosa->lock, flags); add_wait_queue(&chan->rxwaitq, &wait); while (!chan->rx_status) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&cosa->lock, flags); schedule(); spin_lock_irqsave(&cosa->lock, flags); if (signal_pending(current) && chan->rx_status == 0) { chan->rx_status = 1; remove_wait_queue(&chan->rxwaitq, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); spin_unlock_irqrestore(&cosa->lock, flags); mutex_unlock(&chan->rlock); return -ERESTARTSYS; } } remove_wait_queue(&chan->rxwaitq, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); kbuf = chan->rxdata; count = chan->rxsize; spin_unlock_irqrestore(&cosa->lock, flags); @@ -890,14 +890,14 @@ static ssize_t cosa_write(struct file *file, spin_lock_irqsave(&cosa->lock, flags); add_wait_queue(&chan->txwaitq, &wait); while (!chan->tx_status) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&cosa->lock, flags); schedule(); spin_lock_irqsave(&cosa->lock, flags); if (signal_pending(current) && chan->tx_status == 0) { chan->tx_status = 1; remove_wait_queue(&chan->txwaitq, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); chan->tx_status = 1; spin_unlock_irqrestore(&cosa->lock, flags); up(&chan->wsem); @@ -905,7 +905,7 @@ static ssize_t cosa_write(struct file *file, } } remove_wait_queue(&chan->txwaitq, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); up(&chan->wsem); spin_unlock_irqrestore(&cosa->lock, flags); kfree(kbuf); -- cgit v1.2.3 From 87cda7cb4380fa05b70485b0a57b07d020f5204b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 22 Feb 2015 15:54:29 -0500 Subject: r8169: Revert BQL and xmit_more support. There are certain regressions which are pointing to these two commits which we are having a hard time resolving. So revert them for now. Specifically this reverts: commit 0bec3b700d106a8b0a34227b2976d1a582f1aab7 Author: Florian Westphal Date: Wed Jan 7 10:49:49 2015 +0100 r8169: add support for xmit_more and commit 1e918876853aa85435e0f17fd8b4a92dcfff53d6 Author: Florian Westphal Date: Wed Oct 1 13:38:03 2014 +0200 r8169: add support for Byte Queue Limits There were some attempts by Eric Dumazet to address some obvious problems in the TX flow, to see if they would fix the problems, but none of them seem to help for the regression reporters. Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index ad0020af2193..b1560927abd4 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5067,8 +5067,6 @@ static void rtl_hw_reset(struct rtl8169_private *tp) RTL_W8(ChipCmd, CmdReset); rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100); - - netdev_reset_queue(tp->dev); } static void rtl_request_uncached_firmware(struct rtl8169_private *tp) @@ -7049,7 +7047,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, u32 status, len; u32 opts[2]; int frags; - bool stop_queue; if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) { netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n"); @@ -7090,8 +7087,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, txd->opts2 = cpu_to_le32(opts[1]); - netdev_sent_queue(dev, skb->len); - skb_tx_timestamp(skb); /* Force memory writes to complete before releasing descriptor */ @@ -7106,16 +7101,11 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->cur_tx += frags + 1; - stop_queue = !TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS); + RTL_W8(TxPoll, NPQ); - if (!skb->xmit_more || stop_queue || - netif_xmit_stopped(netdev_get_tx_queue(dev, 0))) { - RTL_W8(TxPoll, NPQ); - - mmiowb(); - } + mmiowb(); - if (stop_queue) { + if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) { /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must * not miss a ring update when it notices a stopped queue. */ @@ -7198,7 +7188,6 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev) static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) { unsigned int dirty_tx, tx_left; - unsigned int bytes_compl = 0, pkts_compl = 0; dirty_tx = tp->dirty_tx; smp_rmb(); @@ -7222,8 +7211,10 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb, tp->TxDescArray + entry); if (status & LastFrag) { - pkts_compl++; - bytes_compl += tx_skb->skb->len; + u64_stats_update_begin(&tp->tx_stats.syncp); + tp->tx_stats.packets++; + tp->tx_stats.bytes += tx_skb->skb->len; + u64_stats_update_end(&tp->tx_stats.syncp); dev_kfree_skb_any(tx_skb->skb); tx_skb->skb = NULL; } @@ -7232,13 +7223,6 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) } if (tp->dirty_tx != dirty_tx) { - netdev_completed_queue(tp->dev, pkts_compl, bytes_compl); - - u64_stats_update_begin(&tp->tx_stats.syncp); - tp->tx_stats.packets += pkts_compl; - tp->tx_stats.bytes += bytes_compl; - u64_stats_update_end(&tp->tx_stats.syncp); - tp->dirty_tx = dirty_tx; /* Sync with rtl8169_start_xmit: * - publish dirty_tx ring index (write barrier) -- cgit v1.2.3 From 2035772010db634ec8566b658fb1cd87ec47ac77 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Wed, 5 Mar 2014 14:01:43 +0530 Subject: usb: musb: musb_host: Enable HCD_BH flag to handle urb return in bottom half Enable HCD_BH flag for musb host controller driver. This improves the MSC/UVC through put. With this enabled even 640x480@30fps webcam streaming is also supported. Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 883a9adfdfff..c3d5fc9dfb5b 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2613,7 +2613,7 @@ static const struct hc_driver musb_hc_driver = { .description = "musb-hcd", .product_desc = "MUSB HDRC host driver", .hcd_priv_size = sizeof(struct musb *), - .flags = HCD_USB2 | HCD_MEMORY, + .flags = HCD_USB2 | HCD_MEMORY | HCD_BH, /* not using irq handler or reset hooks from usbcore, since * those must be shared with peripheral code for OTG configs -- cgit v1.2.3 From 9ec36f7fe20ef919cc15171e1da1b6739222541a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 2 Feb 2015 16:24:17 -0600 Subject: usb: gadget: function: phonet: balance usb_ep_disable calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit f_phonet's ->set_alt() method will call usb_ep_disable() potentially on an endpoint which is already disabled. That's something the gadget/function driver must guarantee that it's always balanced. In order to balance the calls, just make sure the endpoint was enabled before by means of checking the validity of driver_data. Reported-by: Pali Rohár Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_phonet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c index c89e96cfa3e4..c0c3ef272714 100644 --- a/drivers/usb/gadget/function/f_phonet.c +++ b/drivers/usb/gadget/function/f_phonet.c @@ -417,7 +417,10 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) return -EINVAL; spin_lock(&port->lock); - __pn_reset(f); + + if (fp->in_ep->driver_data) + __pn_reset(f); + if (alt == 1) { int i; -- cgit v1.2.3 From 3e43a0725637299a14369e3ef109c25a8ec5c008 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 2 Feb 2015 17:12:00 -0600 Subject: usb: musb: core: add pm_runtime_irq_safe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need a pm_runtime_get_sync() call from within musb_gadget_pullup() to make sure registers are accessible at that time. The problem is that musb_gadget_pullup() is called with IRQs disabled and, because of that, we need to tell pm_runtime that this pm_runtime_get_sync() is IRQ safe. We can simply add pm_runtime_irq_safe(), however, because we need to make our read/write accessor function pointers have been initialized before trying to use them. This means that all pm_runtime initialization for musb_core needs to be moved down so that when we call pm_runtime_irq_safe(), the pm_runtime_get_sync() that it calls on the parent, won't cause a crash due to NULL musb_read/write accessors. Reported-by: Pali Rohár Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index e6f4cbfeed97..067920f2d570 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1969,10 +1969,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) goto fail0; } - pm_runtime_use_autosuspend(musb->controller); - pm_runtime_set_autosuspend_delay(musb->controller, 200); - pm_runtime_enable(musb->controller); - spin_lock_init(&musb->lock); musb->board_set_power = plat->set_power; musb->min_power = plat->min_power; @@ -1991,6 +1987,12 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb_readl = musb_default_readl; musb_writel = musb_default_writel; + /* We need musb_read/write functions initialized for PM */ + pm_runtime_use_autosuspend(musb->controller); + pm_runtime_set_autosuspend_delay(musb->controller, 200); + pm_runtime_irq_safe(musb->controller); + pm_runtime_enable(musb->controller); + /* The musb_platform_init() call: * - adjusts musb->mregs * - sets the musb->isr -- cgit v1.2.3 From 407550fe2ccfca3fa0ac4bcdb0a412adeabf84ba Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 22 Feb 2015 15:41:18 -0800 Subject: Bluetooth: btusb: Fix issue with CSR based Intel Wireless controllers Older Wireless controllers from Intel used CSR chips to provide support for Bluetooth. The commit d0ac9eb72 (Bluetooth: btusb: Ignore unknown Intel devices with generic descriptor) disabled these older controllers. To enable them again, put them into the blacklist and mark them clearly as CSR based controllers. T: Bus=02 Lev=02 Prnt=02 Port=05 Cnt=01 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=8087 ProdID=07da Rev=78.69 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr= 0mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Reported-by: Kenneth R. Crudup Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b87688881143..8bfc4c2bba87 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -272,6 +272,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, /* Intel Bluetooth devices */ + { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW }, -- cgit v1.2.3 From 606bf4d5d630781c0e626b6811ac3aabb57fdf1b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 4 Feb 2015 06:28:49 -0800 Subject: usb: musb: Fix use for of_property_read_bool for disabled multipoint The value for the multipoint dts property is ignored when parsing with of_property_read_bool, so we currently have multipoint always set as 1 even if value 0 is specified in the dts file. Let's fix this to read the value too instead of just the property like the binding documentation says as otherwise MUSB will fail to work on devices with Mentor configuration that does not support multipoint. Cc: Brian Hutchinson Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 7 +++++-- drivers/usb/musb/omap2430.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 53bd0e71d19f..5872accb0fd3 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -687,7 +687,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, struct musb_hdrc_config *config; struct platform_device *musb; struct device_node *dn = parent->dev.of_node; - int ret; + int ret, val; memset(resources, 0, sizeof(resources)); res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc"); @@ -739,7 +739,10 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, pdata.mode = get_musb_port_mode(dev); /* DT keeps this entry in mA, musb expects it as per USB spec */ pdata.power = get_int_prop(dn, "mentor,power") / 2; - config->multipoint = of_property_read_bool(dn, "mentor,multipoint"); + + ret = of_property_read_u32(dn, "mentor,multipoint", &val); + if (!ret && val) + config->multipoint = true; ret = platform_device_add_data(musb, &pdata, sizeof(pdata)); if (ret) { diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 763649eb4987..cc752d8c7773 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -516,7 +516,7 @@ static int omap2430_probe(struct platform_device *pdev) struct omap2430_glue *glue; struct device_node *np = pdev->dev.of_node; struct musb_hdrc_config *config; - int ret = -ENOMEM; + int ret = -ENOMEM, val; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) @@ -559,7 +559,10 @@ static int omap2430_probe(struct platform_device *pdev) of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps); of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits); of_property_read_u32(np, "power", (u32 *)&pdata->power); - config->multipoint = of_property_read_bool(np, "multipoint"); + + ret = of_property_read_u32(np, "multipoint", &val); + if (!ret && val) + config->multipoint = true; pdata->board_data = data; pdata->config = config; -- cgit v1.2.3 From eed97ef39a30e3301c5a7f0c94db63130bbe785b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 18 Feb 2015 22:07:07 +0100 Subject: usb: renesas: fix extcon dependency The renesas usbhs driver calls extcon_get_edev_by_phandle(), which is defined in drivers/extcon/extcon-class.c, and that can be a loadable module. If the extcon-class support is disabled, usbhs will work correctly for all devices that do not need extcon. However, if extcon-class is a loadable module, and usbhs is built-in, the kernel fails to link. In order to solve that, we need a Kconfig dependency that allows extcon to be disabled but does not allow usbhs built-in if extcon is a module. Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig index de83b9d0cd5c..ebc99ee076ce 100644 --- a/drivers/usb/renesas_usbhs/Kconfig +++ b/drivers/usb/renesas_usbhs/Kconfig @@ -6,6 +6,7 @@ config USB_RENESAS_USBHS tristate 'Renesas USBHS controller' depends on USB_GADGET depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST + depends on EXTCON || !EXTCON # if EXTCON=m, USBHS cannot be built-in default n help Renesas USBHS is a discrete USB host and peripheral controller chip -- cgit v1.2.3 From bb90600d5cdd3a59053e0843f165e2ee49009c54 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 4 Feb 2015 06:28:49 -0800 Subject: usb: musb: Fix getting a generic phy for musb_dsps We still have a combination of legacy phys and generic phys in use so we need to support both types of phy for musb_dsps.c. Cc: Brian Hutchinson Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 5872accb0fd3..a900c9877195 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -457,12 +457,27 @@ static int dsps_musb_init(struct musb *musb) if (IS_ERR(musb->xceiv)) return PTR_ERR(musb->xceiv); + musb->phy = devm_phy_get(dev->parent, "usb2-phy"); + /* Returns zero if e.g. not clocked */ rev = dsps_readl(reg_base, wrp->revision); if (!rev) return -ENODEV; usb_phy_init(musb->xceiv); + if (IS_ERR(musb->phy)) { + musb->phy = NULL; + } else { + ret = phy_init(musb->phy); + if (ret < 0) + return ret; + ret = phy_power_on(musb->phy); + if (ret) { + phy_exit(musb->phy); + return ret; + } + } + setup_timer(&glue->timer, otg_timer, (unsigned long) musb); /* Reset the musb */ @@ -502,6 +517,8 @@ static int dsps_musb_exit(struct musb *musb) del_timer_sync(&glue->timer); usb_phy_shutdown(musb->xceiv); + phy_power_off(musb->phy); + phy_exit(musb->phy); debugfs_remove_recursive(glue->dbgfs_root); return 0; @@ -610,7 +627,7 @@ static int dsps_musb_reset(struct musb *musb) struct device *dev = musb->controller; struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; - int session_restart = 0; + int session_restart = 0, error; if (glue->sw_babble_enabled) session_restart = sw_babble_control(musb); @@ -624,8 +641,14 @@ static int dsps_musb_reset(struct musb *musb) dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); usleep_range(100, 200); usb_phy_shutdown(musb->xceiv); + error = phy_power_off(musb->phy); + if (error) + dev_err(dev, "phy shutdown failed: %i\n", error); usleep_range(100, 200); usb_phy_init(musb->xceiv); + error = phy_power_on(musb->phy); + if (error) + dev_err(dev, "phy powerup failed: %i\n", error); session_restart = 1; } -- cgit v1.2.3 From 4d3db7d78425c469d328d460e3b69dfb80dd309c Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Fri, 6 Feb 2015 05:08:53 -0500 Subject: usb: isp1760: use msecs_to_jiffies for time conversion This is only an API consolidation and should make things more readable it replaces var * HZ / 1000 by msecs_to_jiffies(var). Acked-by: Laurent Pinchart Signed-off-by: Nicholas Mc Guire Signed-off-by: Felipe Balbi --- drivers/usb/isp1760/isp1760-hcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c index eba9b82e2d70..3cb98b1d5d29 100644 --- a/drivers/usb/isp1760/isp1760-hcd.c +++ b/drivers/usb/isp1760/isp1760-hcd.c @@ -1274,7 +1274,7 @@ static void errata2_function(unsigned long data) for (slot = 0; slot < 32; slot++) if (priv->atl_slots[slot].qh && time_after(jiffies, priv->atl_slots[slot].timestamp + - SLOT_TIMEOUT * HZ / 1000)) { + msecs_to_jiffies(SLOT_TIMEOUT))) { ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); if (!FROM_DW0_VALID(ptd.dw0) && !FROM_DW3_ACTIVE(ptd.dw3)) @@ -1286,7 +1286,7 @@ static void errata2_function(unsigned long data) spin_unlock_irqrestore(&priv->lock, spinflags); - errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000; + errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD); add_timer(&errata2_timer); } @@ -1336,7 +1336,7 @@ static int isp1760_run(struct usb_hcd *hcd) return retval; setup_timer(&errata2_timer, errata2_function, (unsigned long)hcd); - errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000; + errata2_timer.expires = jiffies + msecs_to_jiffies(SLOT_CHECK_PERIOD); add_timer(&errata2_timer); chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG); -- cgit v1.2.3 From 7a3cc4618497e1c6b2f9cd4c8c20759ad8ceb2d1 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Wed, 4 Feb 2015 17:49:36 +0000 Subject: usb: gadget: function: f_hid: fix sparse warning this patch fixes following sparse warning: f_hid.c:572:30: warning: symbol 'f_hidg_fops' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 426d69a9c018..a2612fb79eff 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -569,7 +569,7 @@ fail: return status; } -const struct file_operations f_hidg_fops = { +static const struct file_operations f_hidg_fops = { .owner = THIS_MODULE, .open = f_hidg_open, .release = f_hidg_release, -- cgit v1.2.3 From ef16e7c8ba9cee07d2295de01bbdf921d20c4902 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Wed, 4 Feb 2015 18:01:11 +0000 Subject: usb: gadget: function: f_uac2: fix sparse warnings this patch fixes following sparse warnings: f_uac2.c:57:12: warning: symbol 'uac2_name' was not declared. Should it be static? f_uac2.c:637:36: warning: symbol 'in_clk_src_desc' was not declared. Should it be static? f_uac2.c:649:36: warning: symbol 'out_clk_src_desc' was not declared. Should it be static? f_uac2.c:661:39: warning: symbol 'usb_out_it_desc' was not declared. Should it be static? f_uac2.c:675:39: warning: symbol 'io_in_it_desc' was not declared. Should it be static? f_uac2.c:689:40: warning: symbol 'usb_in_ot_desc' was not declared. Should it be static? f_uac2.c:703:40: warning: symbol 'io_out_ot_desc' was not declared. Should it be static? f_uac2.c:716:34: warning: symbol 'ac_hdr_desc' was not declared. Should it be static? f_uac2.c:754:34: warning: symbol 'as_out_hdr_desc' was not declared. Should it be static? f_uac2.c:767:38: warning: symbol 'as_out_fmt1_desc' was not declared. Should it be static? f_uac2.c:775:32: warning: symbol 'fs_epout_desc' was not declared. Should it be static? f_uac2.c:785:32: warning: symbol 'hs_epout_desc' was not declared. Should it be static? f_uac2.c:831:34: warning: symbol 'as_in_hdr_desc' was not declared. Should it be static? f_uac2.c:844:38: warning: symbol 'as_in_fmt1_desc' was not declared. Should it be static? f_uac2.c:852:32: warning: symbol 'fs_epin_desc' was not declared. Should it be static? f_uac2.c:862:32: warning: symbol 'hs_epin_desc' was not declared. Should it be static? f_uac2.c:1566:21: warning: symbol 'afunc_alloc' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uac2.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 33e16658e5cf..6d3eb8b00a48 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -54,7 +54,7 @@ #define UNFLW_CTRL 8 #define OVFLW_CTRL 10 -const char *uac2_name = "snd_uac2"; +static const char *uac2_name = "snd_uac2"; struct uac2_req { struct uac2_rtd_params *pp; /* parent param */ @@ -634,7 +634,7 @@ static struct usb_interface_descriptor std_ac_if_desc = { }; /* Clock source for IN traffic */ -struct uac_clock_source_descriptor in_clk_src_desc = { +static struct uac_clock_source_descriptor in_clk_src_desc = { .bLength = sizeof in_clk_src_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -646,7 +646,7 @@ struct uac_clock_source_descriptor in_clk_src_desc = { }; /* Clock source for OUT traffic */ -struct uac_clock_source_descriptor out_clk_src_desc = { +static struct uac_clock_source_descriptor out_clk_src_desc = { .bLength = sizeof out_clk_src_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -658,7 +658,7 @@ struct uac_clock_source_descriptor out_clk_src_desc = { }; /* Input Terminal for USB_OUT */ -struct uac2_input_terminal_descriptor usb_out_it_desc = { +static struct uac2_input_terminal_descriptor usb_out_it_desc = { .bLength = sizeof usb_out_it_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -672,7 +672,7 @@ struct uac2_input_terminal_descriptor usb_out_it_desc = { }; /* Input Terminal for I/O-In */ -struct uac2_input_terminal_descriptor io_in_it_desc = { +static struct uac2_input_terminal_descriptor io_in_it_desc = { .bLength = sizeof io_in_it_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -686,7 +686,7 @@ struct uac2_input_terminal_descriptor io_in_it_desc = { }; /* Ouput Terminal for USB_IN */ -struct uac2_output_terminal_descriptor usb_in_ot_desc = { +static struct uac2_output_terminal_descriptor usb_in_ot_desc = { .bLength = sizeof usb_in_ot_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -700,7 +700,7 @@ struct uac2_output_terminal_descriptor usb_in_ot_desc = { }; /* Ouput Terminal for I/O-Out */ -struct uac2_output_terminal_descriptor io_out_ot_desc = { +static struct uac2_output_terminal_descriptor io_out_ot_desc = { .bLength = sizeof io_out_ot_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -713,7 +713,7 @@ struct uac2_output_terminal_descriptor io_out_ot_desc = { .bmControls = (CONTROL_RDWR << COPY_CTRL), }; -struct uac2_ac_header_descriptor ac_hdr_desc = { +static struct uac2_ac_header_descriptor ac_hdr_desc = { .bLength = sizeof ac_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -751,7 +751,7 @@ static struct usb_interface_descriptor std_as_out_if1_desc = { }; /* Audio Stream OUT Intface Desc */ -struct uac2_as_header_descriptor as_out_hdr_desc = { +static struct uac2_as_header_descriptor as_out_hdr_desc = { .bLength = sizeof as_out_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -764,7 +764,7 @@ struct uac2_as_header_descriptor as_out_hdr_desc = { }; /* Audio USB_OUT Format */ -struct uac2_format_type_i_descriptor as_out_fmt1_desc = { +static struct uac2_format_type_i_descriptor as_out_fmt1_desc = { .bLength = sizeof as_out_fmt1_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, @@ -772,7 +772,7 @@ struct uac2_format_type_i_descriptor as_out_fmt1_desc = { }; /* STD AS ISO OUT Endpoint */ -struct usb_endpoint_descriptor fs_epout_desc = { +static struct usb_endpoint_descriptor fs_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -782,7 +782,7 @@ struct usb_endpoint_descriptor fs_epout_desc = { .bInterval = 1, }; -struct usb_endpoint_descriptor hs_epout_desc = { +static struct usb_endpoint_descriptor hs_epout_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -828,7 +828,7 @@ static struct usb_interface_descriptor std_as_in_if1_desc = { }; /* Audio Stream IN Intface Desc */ -struct uac2_as_header_descriptor as_in_hdr_desc = { +static struct uac2_as_header_descriptor as_in_hdr_desc = { .bLength = sizeof as_in_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -841,7 +841,7 @@ struct uac2_as_header_descriptor as_in_hdr_desc = { }; /* Audio USB_IN Format */ -struct uac2_format_type_i_descriptor as_in_fmt1_desc = { +static struct uac2_format_type_i_descriptor as_in_fmt1_desc = { .bLength = sizeof as_in_fmt1_desc, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, @@ -849,7 +849,7 @@ struct uac2_format_type_i_descriptor as_in_fmt1_desc = { }; /* STD AS ISO IN Endpoint */ -struct usb_endpoint_descriptor fs_epin_desc = { +static struct usb_endpoint_descriptor fs_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -859,7 +859,7 @@ struct usb_endpoint_descriptor fs_epin_desc = { .bInterval = 1, }; -struct usb_endpoint_descriptor hs_epin_desc = { +static struct usb_endpoint_descriptor hs_epin_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -1563,7 +1563,7 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f) agdev->out_ep->driver_data = NULL; } -struct usb_function *afunc_alloc(struct usb_function_instance *fi) +static struct usb_function *afunc_alloc(struct usb_function_instance *fi) { struct audio_dev *agdev; struct f_uac2_opts *opts; -- cgit v1.2.3 From fcaddc5d7efbee24a6e324672a7f4118c2686648 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Wed, 4 Feb 2015 18:09:59 +0000 Subject: usb: gadget: function: f_sourcesink: fix sparse warning this patch fixes following sparse warnings: f_sourcesink.c:347:34: warning: symbol 'ss_int_source_comp_desc' was not declared. Should it be static? f_sourcesink.c:365:34: warning: symbol 'ss_int_sink_comp_desc' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_sourcesink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index e07c50ced64d..e3dae47baef3 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -344,7 +344,7 @@ static struct usb_endpoint_descriptor ss_int_source_desc = { .bInterval = USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL), }; -struct usb_ss_ep_comp_descriptor ss_int_source_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_int_source_comp_desc = { .bLength = USB_DT_SS_EP_COMP_SIZE, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, @@ -362,7 +362,7 @@ static struct usb_endpoint_descriptor ss_int_sink_desc = { .bInterval = USB_MS_TO_SS_INTERVAL(GZERO_INT_INTERVAL), }; -struct usb_ss_ep_comp_descriptor ss_int_sink_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_int_sink_comp_desc = { .bLength = USB_DT_SS_EP_COMP_SIZE, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, -- cgit v1.2.3 From 70685711f2fead61817785169587b8914df416bf Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 13:02:18 +0000 Subject: usb: gadget: function: uvc: fix sparse warnings this patch fixes following sparse warnings: uvc_video.c:283:5: warning: symbol 'uvcg_video_pump' was not declared. Should it be static? uvc_video.c:342:5: warning: symbol 'uvcg_video_enable' was not declared. Should it be static? uvc_video.c:381:5: warning: symbol 'uvcg_video_init' was not declared. Should it be static? Signed-off-by: Lad, Prabhakar Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/uvc_video.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 9cb86bc1a9a5..50a5e637ca35 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -21,6 +21,7 @@ #include "uvc.h" #include "uvc_queue.h" +#include "uvc_video.h" /* -------------------------------------------------------------------------- * Video codecs -- cgit v1.2.3 From 2b87cd24c3451608d728862d4d62ff27f2d82e93 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 13:11:47 +0000 Subject: usb: gadget: gadgetfs: fix sparse warnings this patch fixes following sparse warnings: g_ffs.c:136:3: warning: symbol 'gfs_configurations' was not declared. Should it be static? g_ffs.c:281:16: warning: Using plain integer as NULL pointer Signed-off-by: Lad, Prabhakar Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/g_ffs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index 06acfa55864a..b01b88e1b716 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -133,7 +133,9 @@ struct gfs_configuration { struct usb_configuration c; int (*eth)(struct usb_configuration *c); int num; -} gfs_configurations[] = { +}; + +static struct gfs_configuration gfs_configurations[] = { #ifdef CONFIG_USB_FUNCTIONFS_RNDIS { .eth = bind_rndis_config, @@ -278,7 +280,7 @@ static void *functionfs_acquire_dev(struct ffs_dev *dev) if (!try_module_get(THIS_MODULE)) return ERR_PTR(-ENOENT); - return 0; + return NULL; } static void functionfs_release_dev(struct ffs_dev *dev) -- cgit v1.2.3 From 1f754ef10350681f3dc1980d357e77487d308c52 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 5 Feb 2015 13:16:26 +0000 Subject: usb: gadget: function: uvc_v4l2.c: fix sparse warnings this patch fixes following sparse warnings: uvc_v4l2.c:264:29: warning: symbol 'uvc_v4l2_ioctl_ops' was not declared. Should it be static? uvc_v4l2.c:355:29: warning: symbol 'uvc_v4l2_fops' was not declared. Should it be static? Acked-by: Laurent Pinchart Signed-off-by: Lad, Prabhakar Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/uvc_v4l2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 5aad7fededa5..8b818fd027b3 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -27,6 +27,7 @@ #include "uvc.h" #include "uvc_queue.h" #include "uvc_video.h" +#include "uvc_v4l2.h" /* -------------------------------------------------------------------------- * Requests handling -- cgit v1.2.3 From 96e5d31244c5542f5b2ea81d76f14ba4b8a7d440 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Fri, 13 Feb 2015 10:13:24 +0530 Subject: usb: dwc3: dwc3-omap: Fix disable IRQ In the wrapper the IRQ disable should be done by writing 1's to the IRQ*_CLR register. Existing code is broken because it instead writes zeros to IRQ*_SET register. Fix this by adding functions dwc3_omap_write_irqmisc_clr() and dwc3_omap_write_irq0_clr() which do the right thing. Fixes: 72246da40f37 ("usb: Introduce DesignWare USB3 DRD Driver") Cc: # v3.2+ Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 172d64e585b6..52e0c4e5e48e 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -205,6 +205,18 @@ static void dwc3_omap_write_irq0_set(struct dwc3_omap *omap, u32 value) omap->irq0_offset, value); } +static void dwc3_omap_write_irqmisc_clr(struct dwc3_omap *omap, u32 value) +{ + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_MISC + + omap->irqmisc_offset, value); +} + +static void dwc3_omap_write_irq0_clr(struct dwc3_omap *omap, u32 value) +{ + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_CLR_0 - + omap->irq0_offset, value); +} + static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, enum omap_dwc3_vbus_id_status status) { @@ -345,9 +357,23 @@ static void dwc3_omap_enable_irqs(struct dwc3_omap *omap) static void dwc3_omap_disable_irqs(struct dwc3_omap *omap) { + u32 reg; + /* disable all IRQs */ - dwc3_omap_write_irqmisc_set(omap, 0x00); - dwc3_omap_write_irq0_set(omap, 0x00); + reg = USBOTGSS_IRQO_COREIRQ_ST; + dwc3_omap_write_irq0_clr(omap, reg); + + reg = (USBOTGSS_IRQMISC_OEVT | + USBOTGSS_IRQMISC_DRVVBUS_RISE | + USBOTGSS_IRQMISC_CHRGVBUS_RISE | + USBOTGSS_IRQMISC_DISCHRGVBUS_RISE | + USBOTGSS_IRQMISC_IDPULLUP_RISE | + USBOTGSS_IRQMISC_DRVVBUS_FALL | + USBOTGSS_IRQMISC_CHRGVBUS_FALL | + USBOTGSS_IRQMISC_DISCHRGVBUS_FALL | + USBOTGSS_IRQMISC_IDPULLUP_FALL); + + dwc3_omap_write_irqmisc_clr(omap, reg); } static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32); -- cgit v1.2.3 From a0456399fb07155637a2b597b91cc1c63bc25141 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Fri, 13 Feb 2015 12:12:53 +0100 Subject: usb: gadget: configfs: don't NUL-terminate (sub)compatible ids The "Extended Compat ID OS Feature Descriptor Specification" does not require the (sub)compatible ids to be NUL-terminated, because they are placed in a fixed-size buffer and only unused parts of it should contain NULs. If the buffer is fully utilized, there is no place for NULs. Consequently, the code which uses desc->ext_compat_id never expects the data contained to be NUL terminated. If the compatible id is stored after sub-compatible id, and the compatible id is full length (8 bytes), the (useless) NUL terminator overwrites the first byte of the sub-compatible id. If the sub-compatible id is full length (8 bytes), the (useless) NUL terminator ends up out of the buffer. The situation can happen in the RNDIS function, where the buffer is a part of struct f_rndis_opts. The next member of struct f_rndis_opts is a mutex, so its first byte gets overwritten. The said byte is a part of a mutex'es member which contains the information on whether the muext is locked or not. This can lead to a deadlock, because, in a configfs-composed gadget when a function is linked into a configuration with config_usb_cfg_link(), usb_get_function() is called, which then calls rndis_alloc(), which tries locking the same mutex and (wrongly) finds it already locked. This patch eliminates NUL terminating of the (sub)compatible id. Cc: # v3.16+ Fixes: da4243145fb1: "usb: gadget: configfs: OS Extended Compatibility descriptors support" Reported-by: Dan Carpenter Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/configfs.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 75648145dc1b..c42765b3a060 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1161,7 +1161,6 @@ static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc, if (desc->opts_mutex) mutex_lock(desc->opts_mutex); memcpy(desc->ext_compat_id, page, l); - desc->ext_compat_id[l] = '\0'; if (desc->opts_mutex) mutex_unlock(desc->opts_mutex); @@ -1192,7 +1191,6 @@ static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc, if (desc->opts_mutex) mutex_lock(desc->opts_mutex); memcpy(desc->ext_compat_id + 8, page, l); - desc->ext_compat_id[l + 8] = '\0'; if (desc->opts_mutex) mutex_unlock(desc->opts_mutex); -- cgit v1.2.3 From 89ce4b0f4e7adda75ac7eec6aaa9b3516390cef2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 8 Jan 2015 00:04:04 +0100 Subject: gpu: ipu-v3: do not divide by zero if the pixel clock is too large Even if an unsupported mode with a pixel clock larger than two times the 264 MHz IPU HSP clock is set, don't divide by zero. Signed-off-by: Philipp Zabel --- drivers/gpu/ipu-v3/ipu-di.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c index b61d6be97602..3ddfb3d0b64d 100644 --- a/drivers/gpu/ipu-v3/ipu-di.c +++ b/drivers/gpu/ipu-v3/ipu-di.c @@ -459,6 +459,8 @@ static void ipu_di_config_clock(struct ipu_di *di, clkrate = clk_get_rate(di->clk_ipu); div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock); + if (div == 0) + div = 1; rate = clkrate / div; error = rate / (sig->mode.pixelclock / 1000); -- cgit v1.2.3 From 081c80e85feabe9a0081f4db940fccb6443b81fb Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 7 Jan 2015 23:52:15 +0100 Subject: drm/imx: dw_hdmi-imx: add mode_valid callback prune unsupported modes This patch limits the pixel clock to 13.4 MHz - 266 MHz for i.MX6Q and 13.5 MHz - 270 MHz for i.MX6DL, which is the range documented in the HDMI Transmitter chapter of the respective reference manuals. Without this patch, when connected to a monitor capable of 2160p60 modes, dw_hdmi will happily report this mode and the IPU code will cause a division by zero in ipu_di_config_clock when trying to figure out how to divide the 264 MHz HSP clock down to ~600 MHz. Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/dw_hdmi-imx.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 121d30ca2d44..d25aaef3cba6 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -136,11 +136,34 @@ static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = { .destroy = drm_encoder_cleanup, }; +static enum drm_mode_status imx6q_hdmi_mode_valid(struct drm_connector *con, + struct drm_display_mode *mode) +{ + if (mode->clock < 13500) + return MODE_CLOCK_LOW; + if (mode->clock > 266000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con, + struct drm_display_mode *mode) +{ + if (mode->clock < 13500) + return MODE_CLOCK_LOW; + if (mode->clock > 270000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = { - .mpll_cfg = imx_mpll_cfg, - .cur_ctr = imx_cur_ctr, - .sym_term = imx_sym_term, - .dev_type = IMX6Q_HDMI, + .mpll_cfg = imx_mpll_cfg, + .cur_ctr = imx_cur_ctr, + .sym_term = imx_sym_term, + .dev_type = IMX6Q_HDMI, + .mode_valid = imx6q_hdmi_mode_valid, }; static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = { @@ -148,6 +171,7 @@ static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = { .cur_ctr = imx_cur_ctr, .sym_term = imx_sym_term, .dev_type = IMX6DL_HDMI, + .mode_valid = imx6dl_hdmi_mode_valid, }; static const struct of_device_id dw_hdmi_imx_dt_ids[] = { -- cgit v1.2.3 From 6e8958ec0ecfd83691e6854839f917d3eaca236b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 7 Jan 2015 23:49:41 +0100 Subject: drm/imx: dw_hdmi-imx: add end of array element to current control array The loop iterating over curr_ctrl in dw_hdmi terminates on mpixelclock == ~0UL, so there needs to be an end of list element here in case a mode with a pixel clock larger than 216 MHz is set. Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/dw_hdmi-imx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index d25aaef3cba6..87fe8ed92ebe 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c @@ -70,7 +70,9 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = { 118800000, { 0x091c, 0x091c, 0x06dc }, }, { 216000000, { 0x06dc, 0x0b5c, 0x091c }, - } + }, { + ~0UL, { 0x0000, 0x0000, 0x0000 }, + }, }; static const struct dw_hdmi_sym_term imx_sym_term[] = { -- cgit v1.2.3 From 51dac94e801fb779789fa8e38bac7df306ac4fa7 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 23 Jan 2015 17:10:01 +0100 Subject: drm/imx: imx-ldb: enable DI clock in encoder_mode_set Commit eb10d6355532 ("imx-drm: encoder prepare/mode_set must use adjusted mode") broke the first LVDS modeset by using crtc->hwmode before crtc mode_set is called. In fact, encoder prepare is not supposed to prepare the display clock at all. Rather encoder mode_set should be used to set the DI clock rate, before it is enabled by crtc commit. Reported-by: Liu Ying Tested-by: Fabio Estevam Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/imx-ldb.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 1b86aac0b341..2d6dc94e1e64 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -163,22 +163,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) { struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; - struct drm_display_mode *mode = &encoder->crtc->hwmode; u32 pixel_fmt; - unsigned long serial_clk; - unsigned long di_clk = mode->clock * 1000; - int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); - - if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { - /* dual channel LVDS mode */ - serial_clk = 3500UL * mode->clock; - imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk); - imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk); - } else { - serial_clk = 7000UL * mode->clock; - imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk, - di_clk); - } switch (imx_ldb_ch->chno) { case 0: @@ -247,6 +232,9 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; + unsigned long serial_clk; + unsigned long di_clk = mode->clock * 1000; + int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder); if (mode->clock > 170000) { dev_warn(ldb->dev, @@ -257,6 +245,16 @@ static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder, "%s: mode exceeds 85 MHz pixel clock\n", __func__); } + if (dual) { + serial_clk = 3500UL * mode->clock; + imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk); + imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk); + } else { + serial_clk = 7000UL * mode->clock; + imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk, + di_clk); + } + /* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */ if (imx_ldb_ch == &ldb->channel[0]) { if (mode->flags & DRM_MODE_FLAG_NVSYNC) -- cgit v1.2.3 From d70e96ae05928643a7b10b8a519dc27afe4750d0 Mon Sep 17 00:00:00 2001 From: Liu Ying Date: Mon, 23 Feb 2015 11:09:51 +0800 Subject: DRM: i.MX: parallel display: Support probe deferral for finding DRM panel Signed-off-by: Liu Ying Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/parallel-display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 5e83e007080f..900dda6a8e71 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -236,8 +236,11 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) } panel_node = of_parse_phandle(np, "fsl,panel", 0); - if (panel_node) + if (panel_node) { imxpd->panel = of_drm_find_panel(panel_node); + if (!imxpd->panel) + return -EPROBE_DEFER; + } imxpd->dev = dev; -- cgit v1.2.3 From 3a314f143d82603bd697d7eb6c76518afc3595bc Mon Sep 17 00:00:00 2001 From: Qiao Zhou Date: Wed, 4 Feb 2015 14:16:03 +0800 Subject: dmaenegine: mmp-pdma: fix irq handler overwrite physical chan issue Some dma channels may be reserved for other purpose in other layer, like secure driver in EL2/EL3. PDMA driver can see the interrupt status, but it should not try to handle related interrupt, since it doesn't belong to PDMA driver in kernel. These interrupts should be handled by corresponding client/module.Otherwise, it will overwrite illegal memory and cause unexpected issues, since pdma driver only requests resources for pdma channels. In PDMA driver, the reserved channels are at the end of total 32 channels. If we find interrupt bit index is not smaller than total dma channels, we should ignore it. Signed-off-by: Qiao Zhou Acked-by: Zhangfei Gao Signed-off-by: Vinod Koul --- drivers/dma/mmp_pdma.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 8926f271904e..abf1450bb25d 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -219,6 +219,9 @@ static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id) while (dint) { i = __ffs(dint); + /* only handle interrupts belonging to pdma driver*/ + if (i >= pdev->dma_channels) + break; dint &= (dint - 1); phy = &pdev->phy[i]; ret = mmp_pdma_chan_handler(irq, phy); -- cgit v1.2.3 From 57e595631904c827cfa1a0f7bbd7cc9a49da5745 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 23 Feb 2015 14:02:54 +0100 Subject: team: fix possible null pointer dereference in team_handle_frame Currently following race is possible in team: CPU0 CPU1 team_port_del team_upper_dev_unlink priv_flags &= ~IFF_TEAM_PORT team_handle_frame team_port_get_rcu team_port_exists priv_flags & IFF_TEAM_PORT == 0 return NULL (instead of port got from rx_handler_data) netdev_rx_handler_unregister The thing is that the flag is removed before rx_handler is unregistered. If team_handle_frame is called in between, team_port_exists returns 0 and team_port_get_rcu will return NULL. So do not check the flag here. It is guaranteed by netdev_rx_handler_unregister that team_handle_frame will always see valid rx_handler_data pointer. Signed-off-by: Jiri Pirko Fixes: 3d249d4ca7d0 ("net: introduce ethernet teaming device") Signed-off-by: David S. Miller --- drivers/net/team/team.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 0e62274e884a..f1ee71e22241 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -43,9 +43,7 @@ static struct team_port *team_port_get_rcu(const struct net_device *dev) { - struct team_port *port = rcu_dereference(dev->rx_handler_data); - - return team_port_exists(dev) ? port : NULL; + return rcu_dereference(dev->rx_handler_data); } static struct team_port *team_port_get_rtnl(const struct net_device *dev) -- cgit v1.2.3 From fe6e4081a626d2987b73c9b15ed520b4f22d585f Mon Sep 17 00:00:00 2001 From: Vlastimil Setka Date: Mon, 23 Feb 2015 11:27:37 -0600 Subject: altera_tse: Correct typo in obtaining tx_fifo_depth from devicetree This patch corrects a typo in the way tx_fifo_depth is read from the devicetree. This patch was submitted by Vlastimil about a week ago, and is now cleaned up and resubmitted. Signed-off-by: Vlastimil Setka Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/altera_tse_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 760c72c6e2ac..f3d784a3463d 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -1399,7 +1399,7 @@ static int altera_tse_probe(struct platform_device *pdev) } if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", - &priv->rx_fifo_depth)) { + &priv->tx_fifo_depth)) { dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n"); ret = -ENXIO; goto err_free_netdev; -- cgit v1.2.3 From 8d4ac39df09c6f8078af60cd0ddd7b2435728e72 Mon Sep 17 00:00:00 2001 From: Vlastimil Setka Date: Mon, 23 Feb 2015 11:30:29 -0600 Subject: altera_tse: Fixes in NAPI and interrupt handling paths Incorrect NAPI polling caused WARNING at net/core/dev.c net_rx_action. Some stability issues were also seen at high throughput and system load before this patch. This patch contains several changes in altera_tse_main.c: - tse_rx() is fixed to not process more than `limit` frames - tse_poll() is refactored to match NAPI logic - only received frames are counted for return value - removed bogus condition `(rxcomplete >= budget || txcomplete > 0)` - replace by: if (rxcomplete < budget) -> call __napi_complete and enable irq - altera_isr() - replace spin_lock_irqsave() by spin_lock() - we are in isr - use spinlocks just over irq manipulation, not over __napi_schedule - reset IRQ first, then disable and schedule napi This is a cleaned up resubmission from Vlastimil's recent submission. Signed-off-by: Vlastimil Setka Signed-off-by: Roman Pisl Signed-off-by: Vince Bridgers Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/altera_tse_main.c | 45 +++++++++++++-------------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index f3d784a3463d..6725dc00750b 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -376,7 +376,8 @@ static int tse_rx(struct altera_tse_private *priv, int limit) u16 pktlength; u16 pktstatus; - while ((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) { + while (((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) && + (count < limit)) { pktstatus = rxstatus >> 16; pktlength = rxstatus & 0xffff; @@ -491,28 +492,27 @@ static int tse_poll(struct napi_struct *napi, int budget) struct altera_tse_private *priv = container_of(napi, struct altera_tse_private, napi); int rxcomplete = 0; - int txcomplete = 0; unsigned long int flags; - txcomplete = tse_tx_complete(priv); + tse_tx_complete(priv); rxcomplete = tse_rx(priv, budget); - if (rxcomplete >= budget || txcomplete > 0) - return rxcomplete; + if (rxcomplete < budget) { - napi_gro_flush(napi, false); - __napi_complete(napi); + napi_gro_flush(napi, false); + __napi_complete(napi); - netdev_dbg(priv->dev, - "NAPI Complete, did %d packets with budget %d\n", - txcomplete+rxcomplete, budget); + netdev_dbg(priv->dev, + "NAPI Complete, did %d packets with budget %d\n", + rxcomplete, budget); - spin_lock_irqsave(&priv->rxdma_irq_lock, flags); - priv->dmaops->enable_rxirq(priv); - priv->dmaops->enable_txirq(priv); - spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); - return rxcomplete + txcomplete; + spin_lock_irqsave(&priv->rxdma_irq_lock, flags); + priv->dmaops->enable_rxirq(priv); + priv->dmaops->enable_txirq(priv); + spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); + } + return rxcomplete; } /* DMA TX & RX FIFO interrupt routing @@ -521,7 +521,6 @@ static irqreturn_t altera_isr(int irq, void *dev_id) { struct net_device *dev = dev_id; struct altera_tse_private *priv; - unsigned long int flags; if (unlikely(!dev)) { pr_err("%s: invalid dev pointer\n", __func__); @@ -529,20 +528,20 @@ static irqreturn_t altera_isr(int irq, void *dev_id) } priv = netdev_priv(dev); - /* turn off desc irqs and enable napi rx */ - spin_lock_irqsave(&priv->rxdma_irq_lock, flags); + spin_lock(&priv->rxdma_irq_lock); + /* reset IRQs */ + priv->dmaops->clear_rxirq(priv); + priv->dmaops->clear_txirq(priv); + spin_unlock(&priv->rxdma_irq_lock); if (likely(napi_schedule_prep(&priv->napi))) { + spin_lock(&priv->rxdma_irq_lock); priv->dmaops->disable_rxirq(priv); priv->dmaops->disable_txirq(priv); + spin_unlock(&priv->rxdma_irq_lock); __napi_schedule(&priv->napi); } - /* reset IRQs */ - priv->dmaops->clear_rxirq(priv); - priv->dmaops->clear_txirq(priv); - - spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); return IRQ_HANDLED; } -- cgit v1.2.3 From 307ed83c8c2004c9eb022e8eab326d494223e4ba Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 23 Feb 2015 17:55:54 +0200 Subject: spi: dw-pci: correct number of chip selects The commit d58cf5ff6500 brought a second controller to the list of supported devices and changed a number of the chip selects. Besides the previous number was wrong anyway the mentioned patch makes it wrong again meanwhile has a proper numbers in the commit message. Indeed, SPI1 has 5 bits and SPI2 has 2 bits, but it does not mean to have power of two of this bits as a possible number of the chip selects. So, this patch fixes it eventually. Fixes: d58cf5ff6500 (spi: dw-pci: describe Intel MID controllers better) Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-dw-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 5ba331047cbe..6d331e0db331 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -36,13 +36,13 @@ struct spi_pci_desc { static struct spi_pci_desc spi_pci_mid_desc_1 = { .setup = dw_spi_mid_init, - .num_cs = 32, + .num_cs = 5, .bus_num = 0, }; static struct spi_pci_desc spi_pci_mid_desc_2 = { .setup = dw_spi_mid_init, - .num_cs = 4, + .num_cs = 2, .bus_num = 1, }; -- cgit v1.2.3 From f2831e2007810b690f93a26128058a193eadf393 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 5 Feb 2015 08:45:43 -0500 Subject: mac80211_hwsim: fix error handling in tx_frame_nl Correct two problems with the error handling when using the netlink forwarding API: first, the netlink skb is never freed if nla_put() fails; and second, genlmsg_unicast() can fail if the netlink socket is full. In the latter case, the corresponding data skb is not counted as a drop and userspace programs like wmediumd will see TCP stalls due to lost packets. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4a4c6586a8d2..8908be6dbc48 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -946,7 +946,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, goto nla_put_failure; genlmsg_end(skb, msg_head); - genlmsg_unicast(&init_net, skb, dst_portid); + if (genlmsg_unicast(&init_net, skb, dst_portid)) + goto err_free_txskb; /* Enqueue the packet */ skb_queue_tail(&data->pending, my_skb); @@ -955,6 +956,8 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, return; nla_put_failure: + nlmsg_free(skb); +err_free_txskb: printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); ieee80211_free_txskb(hw, my_skb); data->tx_failed++; -- cgit v1.2.3 From 1e7e4fb66489cc84366656ca5318f1cb61afd4ba Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 24 Feb 2015 18:27:00 +0200 Subject: usb: XHCI: platform: Move the Marvell quirks after the enabling the clocks The commit 973747928514 ("usb: host: xhci-plat: add support for the Armada 375/38x XHCI controllers") extended the xhci-plat driver to support the Armada 375/38x SoCs, mostly by adding a quirk configuring the MBUS window. However, that quirk was run before the clock the controllers needs has been enabled. This usually worked because the clock was first enabled by the bootloader, and left as such until the driver is probe, where it tries to access the MBUS configuration registers before enabling the clock. Things get messy when EPROBE_DEFER is involved during the probe, since as part of its error path, the driver will rightfully disable the clock. When the driver will be reprobed, it will retry to access the MBUS registers, but this time with the clock disabled, which hangs forever. Fix this by running the quirks after the clock has been enabled by the driver. Signed-off-by: Maxime Ripard Cc: # v3.16+ Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 08d402b15482..0e11d61408ff 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -83,16 +83,6 @@ static int xhci_plat_probe(struct platform_device *pdev) if (irq < 0) return -ENODEV; - - if (of_device_is_compatible(pdev->dev.of_node, - "marvell,armada-375-xhci") || - of_device_is_compatible(pdev->dev.of_node, - "marvell,armada-380-xhci")) { - ret = xhci_mvebu_mbus_init_quirk(pdev); - if (ret) - return ret; - } - /* Initialize dma_mask and coherent_dma_mask to 32-bits */ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) @@ -127,6 +117,15 @@ static int xhci_plat_probe(struct platform_device *pdev) goto put_hcd; } + if (of_device_is_compatible(pdev->dev.of_node, + "marvell,armada-375-xhci") || + of_device_is_compatible(pdev->dev.of_node, + "marvell,armada-380-xhci")) { + ret = xhci_mvebu_mbus_init_quirk(pdev); + if (ret) + goto disable_clk; + } + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto disable_clk; -- cgit v1.2.3 From 6596a926b0b6c80b730a1dd2fa91908e0a539c37 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 24 Feb 2015 18:27:01 +0200 Subject: xhci: Allocate correct amount of scratchpad buffers Include the high order bit fields for Max scratchpad buffers when calculating how many scratchpad buffers are needed. I'm suprised this hasn't caused more issues, we never allocated more than 32 buffers even if xhci needed more. Either we got lucky and xhci never really used past that area, or then we got enough zeroed dma memory anyway. Should be backported as far back as possible Reported-by: Tim Chen Tested-by: Tim Chen Signed-off-by: Mathias Nyman Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 974514762a14..68956b13b8d1 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -88,9 +88,10 @@ struct xhci_cap_regs { #define HCS_IST(p) (((p) >> 0) & 0xf) /* bits 4:7, max number of Event Ring segments */ #define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) +/* bits 21:25 Hi 5 bits of Scratchpad buffers SW must allocate for the HW */ /* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ -/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ -#define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f) +/* bits 27:31 Lo 5 bits of Scratchpad buffers SW must allocate for the HW */ +#define HCS_MAX_SCRATCHPAD(p) ((((p) >> 16) & 0x3e0) | (((p) >> 27) & 0x1f)) /* HCSPARAMS3 - hcs_params3 - bitmasks */ /* bits 0:7, Max U1 to U0 latency for the roothub ports */ -- cgit v1.2.3 From 27082e2654dc148078b0abdfc3c8e5ccbde0ebfa Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 24 Feb 2015 18:27:02 +0200 Subject: xhci: Clear the host side toggle manually when endpoint is 'soft reset' Main benefit of this is to get xhci connected USB scanners to work. Some devices use a clear endpoint halt request as a 'soft reset' even if the endpoint is not halted. This will clear the toggle and sequence on the device side. xHCI however refuses to reset a non-halted endpoint, so instead we need to issue a configure endpoint command on xHCI to clear its host side toggle and sequence, and get it in sync with the device side. Tested-by: Mike Mammarella Cc: # v3.18 Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 2 +- drivers/usb/host/xhci.c | 100 +++++++++++++++++++++++++++++++++++++++---- drivers/usb/host/xhci.h | 2 + 3 files changed, 94 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 88da8d629820..b46b5b98a943 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1729,7 +1729,7 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, if (!command) return; - ep->ep_state |= EP_HALTED; + ep->ep_state |= EP_HALTED | EP_RECENTLY_HALTED; ep->stopped_stream = stream_id; xhci_queue_reset_ep(xhci, command, slot_id, ep_index); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index ec8ac1674854..b06d1a53652d 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1338,6 +1338,12 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) goto exit; } + /* Reject urb if endpoint is in soft reset, queue must stay empty */ + if (xhci->devs[slot_id]->eps[ep_index].ep_state & EP_CONFIG_PENDING) { + xhci_warn(xhci, "Can't enqueue URB while ep is in soft reset\n"); + ret = -EINVAL; + } + if (usb_endpoint_xfer_isoc(&urb->ep->desc)) size = urb->number_of_packets; else @@ -2948,23 +2954,36 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, } } -/* Called when clearing halted device. The core should have sent the control +/* Called after clearing a halted device. USB core should have sent the control * message to clear the device halt condition. The host side of the halt should - * already be cleared with a reset endpoint command issued when the STALL tx - * event was received. - * - * Context: in_interrupt + * already be cleared with a reset endpoint command issued immediately when the + * STALL tx event was received. */ void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) { struct xhci_hcd *xhci; + struct usb_device *udev; + struct xhci_virt_device *virt_dev; + struct xhci_virt_ep *virt_ep; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_command *command; + unsigned int ep_index, ep_state; + unsigned long flags; + u32 ep_flag; xhci = hcd_to_xhci(hcd); + udev = (struct usb_device *) ep->hcpriv; + if (!ep->hcpriv) + return; + virt_dev = xhci->devs[udev->slot_id]; + ep_index = xhci_get_endpoint_index(&ep->desc); + virt_ep = &virt_dev->eps[ep_index]; + ep_state = virt_ep->ep_state; /* - * We might need to implement the config ep cmd in xhci 4.8.1 note: + * Implement the config ep command in xhci 4.6.8 additional note: * The Reset Endpoint Command may only be issued to endpoints in the * Halted state. If software wishes reset the Data Toggle or Sequence * Number of an endpoint that isn't in the Halted state, then software @@ -2972,9 +2991,72 @@ void xhci_endpoint_reset(struct usb_hcd *hcd, * for the target endpoint. that is in the Stopped state. */ - /* For now just print debug to follow the situation */ - xhci_dbg(xhci, "Endpoint 0x%x ep reset callback called\n", - ep->desc.bEndpointAddress); + if (ep_state & SET_DEQ_PENDING || ep_state & EP_RECENTLY_HALTED) { + virt_ep->ep_state &= ~EP_RECENTLY_HALTED; + xhci_dbg(xhci, "ep recently halted, no toggle reset needed\n"); + return; + } + + /* Only interrupt and bulk ep's use Data toggle, USB2 spec 5.5.4-> */ + if (usb_endpoint_xfer_control(&ep->desc) || + usb_endpoint_xfer_isoc(&ep->desc)) + return; + + ep_flag = xhci_get_endpoint_flag(&ep->desc); + + if (ep_flag == SLOT_FLAG || ep_flag == EP0_FLAG) + return; + + command = xhci_alloc_command(xhci, true, true, GFP_NOWAIT); + if (!command) { + xhci_err(xhci, "Could not allocate xHCI command structure.\n"); + return; + } + + spin_lock_irqsave(&xhci->lock, flags); + + /* block ringing ep doorbell */ + virt_ep->ep_state |= EP_CONFIG_PENDING; + + /* + * Make sure endpoint ring is empty before resetting the toggle/seq. + * Driver is required to synchronously cancel all transfer request. + * + * xhci 4.6.6 says we can issue a configure endpoint command on a + * running endpoint ring as long as it's idle (queue empty) + */ + + if (!list_empty(&virt_ep->ring->td_list)) { + dev_err(&udev->dev, "EP not empty, refuse reset\n"); + spin_unlock_irqrestore(&xhci->lock, flags); + goto cleanup; + } + + xhci_dbg(xhci, "Reset toggle/seq for slot %d, ep_index: %d\n", + udev->slot_id, ep_index); + + ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx); + if (!ctrl_ctx) { + xhci_err(xhci, "Could not get input context, bad type. virt_dev: %p, in_ctx %p\n", + virt_dev, virt_dev->in_ctx); + spin_unlock_irqrestore(&xhci->lock, flags); + goto cleanup; + } + xhci_setup_input_ctx_for_config_ep(xhci, command->in_ctx, + virt_dev->out_ctx, ctrl_ctx, + ep_flag, ep_flag); + xhci_endpoint_copy(xhci, command->in_ctx, virt_dev->out_ctx, ep_index); + + xhci_queue_configure_endpoint(xhci, command, command->in_ctx->dma, + udev->slot_id, false); + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + wait_for_completion(command->completion); + +cleanup: + virt_ep->ep_state &= ~EP_CONFIG_PENDING; + xhci_free_command(xhci, command); } static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 68956b13b8d1..3b97f0582155 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -864,6 +864,8 @@ struct xhci_virt_ep { #define EP_HAS_STREAMS (1 << 4) /* Transitioning the endpoint to not using streams, don't enqueue URBs */ #define EP_GETTING_NO_STREAMS (1 << 5) +#define EP_RECENTLY_HALTED (1 << 6) +#define EP_CONFIG_PENDING (1 << 7) /* ---- Related to URB cancellation ---- */ struct list_head cancelled_td_list; struct xhci_td *stopped_td; -- cgit v1.2.3 From f0c2b68198589249afd2b1f2c4e8de8c03e19c16 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 13 Feb 2015 10:54:53 -0500 Subject: USB: usbfs: don't leak kernel data in siginfo When a signal is delivered, the information in the siginfo structure is copied to userspace. Good security practice dicatates that the unused fields in this structure should be initialized to 0 so that random kernel stack data isn't exposed to the user. This patch adds such an initialization to the two places where usbfs raises signals. Signed-off-by: Alan Stern Reported-by: Dave Mielke CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 66abdbcfbfa5..11635537c052 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -501,6 +501,7 @@ static void async_completed(struct urb *urb) as->status = urb->status; signr = as->signr; if (signr) { + memset(&sinfo, 0, sizeof(sinfo)); sinfo.si_signo = as->signr; sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; @@ -2382,6 +2383,7 @@ static void usbdev_remove(struct usb_device *udev) wake_up_all(&ps->wait); list_del_init(&ps->list); if (ps->discsignr) { + memset(&sinfo, 0, sizeof(sinfo)); sinfo.si_signo = ps->discsignr; sinfo.si_errno = EPIPE; sinfo.si_code = SI_ASYNCIO; -- cgit v1.2.3 From 59e980efafd27df83a5c85c054f906d82bcbf752 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Feb 2015 13:41:14 +0100 Subject: uas: Add US_FL_NO_REPORT_OPCODES for JMicron JMS539 Like the JMicron JMS567 enclosures with the JMS539 choke on report-opcodes, so avoid it. Tested-and-reported-by: Tom Arild Naess Cc: stable@vger.kernel.org # 3.16 Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_uas.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index dbc00e56c7f5..82570425fdfe 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -113,6 +113,13 @@ UNUSUAL_DEV(0x0bc2, 0xab2a, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_ATA_1X), +/* Reported-by: Tom Arild Naess */ +UNUSUAL_DEV(0x152d, 0x0539, 0x0000, 0x9999, + "JMicron", + "JMS539", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_REPORT_OPCODES), + /* Reported-by: Claudio Bizzarri */ UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999, "JMicron", -- cgit v1.2.3 From ec371326d47385dd3fc8e6c7e0d9e89118d94dd8 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 10 Feb 2015 09:27:59 +0100 Subject: usb-storage: support for more than 8 LUNs This is necessary to make some storage arrays work. Some storage devices have more than 8 LUNs. In addition you can hook up a WideSCSI bus to USB. In these cases even level 2 devices can have more than 8 LUNs. For them it is necessary to simply believe the class specific command and report its result back to the SCSI layer. Off by one Alan noticed is fixed. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index d468d02179f4..5600c33fcadb 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -889,6 +889,12 @@ static void usb_stor_scan_dwork(struct work_struct *work) !(us->fflags & US_FL_SCM_MULT_TARG)) { mutex_lock(&us->dev_mutex); us->max_lun = usb_stor_Bulk_max_lun(us); + /* + * Allow proper scanning of devices that present more than 8 LUNs + * While not affecting other devices that may need the previous behavior + */ + if (us->max_lun >= 8) + us_to_host(us)->max_lun = us->max_lun+1; mutex_unlock(&us->dev_mutex); } scsi_scan_host(us_to_host(us)); -- cgit v1.2.3 From b20b1618b8fca858c83e52da4aa22cd6b13b0359 Mon Sep 17 00:00:00 2001 From: Björn Gerhart Date: Wed, 18 Feb 2015 07:19:44 +0100 Subject: cdc-acm: Add support for Denso cradle CU-321 In order to support an older USB cradle by Denso, I added its vendor- and product-ID to the array of usb_device_id acm_ids. In this way cdc-acm feels responsible for this cradle. The related /dev/ttyACM node is being created properly, and the data transfer works. However, later cradle models by Denso do have proper descriptors, so the patch is not required for these. At the same time both the older and the later model have the same vendor- and product-ID, but they both work with the patched driver. Declaration of the Denso cradles I tested: - both models have the same IDs: vendorID 0x076d, productID 0x0006 - older model: Denso CU-321 (descriptors not properly set) - later model: Denso CU-821 (with proper descriptors) Signed-off-by: Bjoern Gerhart Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e78720b59d67..683617714e7c 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1650,6 +1650,8 @@ static int acm_reset_resume(struct usb_interface *intf) static const struct usb_device_id acm_ids[] = { /* quirky and broken devices */ + { USB_DEVICE(0x076d, 0x0006), /* Denso Cradle CU-321 */ + .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */ { USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */ .driver_info = NO_UNION_NORMAL, },/* has no union descriptor */ { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ -- cgit v1.2.3 From 7ed620bb343f434f8a85f830020c04988df2a140 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 19 Feb 2015 20:18:03 -0800 Subject: efi/libstub: Fix boundary checking in efi_high_alloc() While adding support loading kernel and initrd above 4G to grub2 in legacy mode, I was referring to efi_high_alloc(). That will allocate buffer for kernel and then initrd, and initrd will use kernel buffer start as limit. During testing found two buffers will be overlapped when initrd size is very big like 400M. It turns out efi_high_alloc() boundary checking is not right. end - size will be the new start, and should not compare new start with max, we need to make sure end is smaller than max. [ Basically, with the current efi_high_alloc() code it's possible to allocate memory above 'max', because efi_high_alloc() doesn't check that the tail of the allocation is below 'max'. If you have an EFI memory map with a single entry that looks like so, [0xc0000000-0xc0004000] And want to allocate 0x3000 bytes below 0xc0003000 the current code will allocate [0xc0001000-0xc0004000], not [0xc0000000-0xc0003000] like you would expect. - Matt ] Signed-off-by: Yinghai Lu Reviewed-by: Ard Biesheuvel Reviewed-by: Mark Rutland Tested-by: Mark Rutland Cc: Signed-off-by: Matt Fleming --- drivers/firmware/efi/libstub/efi-stub-helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 9bd9fbb5bea8..c927bccd92bd 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -170,12 +170,12 @@ again: start = desc->phys_addr; end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); - if ((start + size) > end || (start + size) > max) - continue; - - if (end - size > max) + if (end > max) end = max; + if ((start + size) > end) + continue; + if (round_down(end - size, align) < start) continue; -- cgit v1.2.3 From 6d9ff473317245e3e5cd9922b4520411c2296388 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Wed, 18 Feb 2015 13:33:19 +0200 Subject: firmware: dmi_scan: Fix dmi_len type According to SMBIOSv3 specification the length of DMI table can be up to 32bits wide. So use appropriate type to avoid overflow. It's obvious that dmi_num theoretically can be more than u16 also, so it's can be changed to u32 or at least it's better to use int instead of u16, but on that moment I cannot imagine dmi structure count more than 65535 and it can require changing type of vars that work with it. So I didn't correct it. Acked-by: Ard Biesheuvel Signed-off-by: Ivan Khoronzhuk Cc: Signed-off-by: Matt Fleming --- drivers/firmware/dmi_scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index a44b87c7b45c..69fac068669f 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -78,7 +78,7 @@ static const char * __init dmi_string(const struct dmi_header *dm, u8 s) * We have to be cautious here. We have seen BIOSes with DMI pointers * pointing to completely the wrong place for example */ -static void dmi_table(u8 *buf, int len, int num, +static void dmi_table(u8 *buf, u32 len, int num, void (*decode)(const struct dmi_header *, void *), void *private_data) { @@ -115,7 +115,7 @@ static void dmi_table(u8 *buf, int len, int num, } static phys_addr_t dmi_base; -static u16 dmi_len; +static u32 dmi_len; static u16 dmi_num; static int __init dmi_walk_early(void (*decode)(const struct dmi_header *, -- cgit v1.2.3 From 7fbb9d8415d4a51cf542e87cf3a717a9f7e6aedc Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Tue, 24 Feb 2015 11:17:59 +0000 Subject: xen-netback: release pending index before pushing Tx responses If the pending indexes are released /after/ pushing the Tx response then a stale pending index may be used if a new Tx request is immediately pushed by the frontend. The may cause various WARNINGs or BUGs if the stale pending index is actually still in use. Fix this by releasing the pending index before pushing the Tx response. The full barrier for the pending ring update is not required since the the Tx response push already has a suitable write barrier. Signed-off-by: David Vrabel Reviewed-by: Wei Liu Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index f7a31d2cb3f1..c4d68d768408 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -655,9 +655,15 @@ static void xenvif_tx_err(struct xenvif_queue *queue, unsigned long flags; do { + int notify; + spin_lock_irqsave(&queue->response_lock, flags); make_tx_response(queue, txp, XEN_NETIF_RSP_ERROR); + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify); spin_unlock_irqrestore(&queue->response_lock, flags); + if (notify) + notify_remote_via_irq(queue->tx_irq); + if (cons == end) break; txp = RING_GET_REQUEST(&queue->tx, cons++); @@ -1649,17 +1655,28 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx, { struct pending_tx_info *pending_tx_info; pending_ring_idx_t index; + int notify; unsigned long flags; pending_tx_info = &queue->pending_tx_info[pending_idx]; + spin_lock_irqsave(&queue->response_lock, flags); + make_tx_response(queue, &pending_tx_info->req, status); - index = pending_index(queue->pending_prod); + + /* Release the pending index before pusing the Tx response so + * its available before a new Tx request is pushed by the + * frontend. + */ + index = pending_index(queue->pending_prod++); queue->pending_ring[index] = pending_idx; - /* TX shouldn't use the index before we give it back here */ - mb(); - queue->pending_prod++; + + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify); + spin_unlock_irqrestore(&queue->response_lock, flags); + + if (notify) + notify_remote_via_irq(queue->tx_irq); } @@ -1669,7 +1686,6 @@ static void make_tx_response(struct xenvif_queue *queue, { RING_IDX i = queue->tx.rsp_prod_pvt; struct xen_netif_tx_response *resp; - int notify; resp = RING_GET_RESPONSE(&queue->tx, i); resp->id = txp->id; @@ -1679,9 +1695,6 @@ static void make_tx_response(struct xenvif_queue *queue, RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL; queue->tx.rsp_prod_pvt = ++i; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify); - if (notify) - notify_remote_via_irq(queue->tx_irq); } static struct xen_netif_rx_response *make_rx_response(struct xenvif_queue *queue, -- cgit v1.2.3 From 5c2d2b148b35a995f0c0e76a3a37902ec98f164c Mon Sep 17 00:00:00 2001 From: Yannick Guerrini Date: Tue, 24 Feb 2015 13:03:51 +0100 Subject: r8169: Fix trivial typo in rtl_check_firmware Change 'firwmare' to 'firmware' Signed-off-by: Yannick Guerrini Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index b1560927abd4..c70ab40d8698 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -2561,7 +2561,7 @@ static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw) int rc = -EINVAL; if (!rtl_fw_format_ok(tp, rtl_fw)) { - netif_err(tp, ifup, dev, "invalid firwmare\n"); + netif_err(tp, ifup, dev, "invalid firmware\n"); goto out; } -- cgit v1.2.3 From 4efe874aace57dba967624ce1c48322da2447b75 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Wed, 4 Feb 2015 17:38:15 -0500 Subject: PCI: Don't read past the end of sysfs "driver_override" buffer When printing the driver_override parameter when it is 4095 and 4094 bytes long, the printing code would access invalid memory because we need count+1 bytes for printing. Fixes: 782a985d7af2 ("PCI: Introduce new device binding path using pci_dev.driver_override") Signed-off-by: Sasha Levin Signed-off-by: Bjorn Helgaas Acked-by: Alex Williamson CC: stable@vger.kernel.org # v3.16+ CC: Konrad Rzeszutek Wilk CC: Alexander Graf CC: Greg Kroah-Hartman --- drivers/pci/pci-sysfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index aa012fb3834b..312f23a8429c 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -521,7 +521,8 @@ static ssize_t driver_override_store(struct device *dev, struct pci_dev *pdev = to_pci_dev(dev); char *driver_override, *old = pdev->driver_override, *cp; - if (count > PATH_MAX) + /* We need to keep extra room for a newline */ + if (count >= (PAGE_SIZE - 1)) return -EINVAL; driver_override = kstrndup(buf, count, GFP_KERNEL); @@ -549,7 +550,7 @@ static ssize_t driver_override_show(struct device *dev, { struct pci_dev *pdev = to_pci_dev(dev); - return sprintf(buf, "%s\n", pdev->driver_override); + return snprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override); } static DEVICE_ATTR_RW(driver_override); -- cgit v1.2.3 From 367bd978b81c2c7bcdcacdd3156645a27fab0676 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 16 Feb 2015 18:38:20 +0000 Subject: iommu/io-pgtable-arm: Fix self-test WARNs on i386 Various build/boot bots have reported WARNs being triggered by the ARM iopgtable LPAE self-tests on i386 machines. This boils down to two instances of right-shifting a 32-bit unsigned long (i.e. an iova) by more than the size of the type. On 32-bit ARM, this happens to give us zero, hence my testing didn't catch this earlier. This patch fixes the issue by using DIV_ROUND_UP and explicit case to to avoid the erroneous shifts. Reported-by: Fengguang Wu Reported-by: Huang Ying Signed-off-by: Will Deacon Signed-off-by: Joerg Roedel --- drivers/iommu/io-pgtable-arm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 5a500edf00cc..b610a8dee238 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -56,7 +56,8 @@ ((((d)->levels - ((l) - ARM_LPAE_START_LVL(d) + 1)) \ * (d)->bits_per_level) + (d)->pg_shift) -#define ARM_LPAE_PAGES_PER_PGD(d) ((d)->pgd_size >> (d)->pg_shift) +#define ARM_LPAE_PAGES_PER_PGD(d) \ + DIV_ROUND_UP((d)->pgd_size, 1UL << (d)->pg_shift) /* * Calculate the index at level l used to map virtual address a using the @@ -66,7 +67,7 @@ ((l) == ARM_LPAE_START_LVL(d) ? ilog2(ARM_LPAE_PAGES_PER_PGD(d)) : 0) #define ARM_LPAE_LVL_IDX(a,l,d) \ - (((a) >> ARM_LPAE_LVL_SHIFT(l,d)) & \ + (((u64)(a) >> ARM_LPAE_LVL_SHIFT(l,d)) & \ ((1 << ((d)->bits_per_level + ARM_LPAE_PGD_IDX(l,d))) - 1)) /* Calculate the block/page mapping size at level l for pagetable in d. */ -- cgit v1.2.3 From a7b67cd5d9afb94fdcacb71b43066b8d70d1d218 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 6 Feb 2015 11:44:05 +0100 Subject: iommu/exynos: Play nice in multi-platform builds The Exynos System MMU driver unconditionally executes code and registers a struct iommu_ops with the platform bus irrespective of whether it runs on an Exynos SoC or not. This causes problems in multi-platform kernels where drivers for other SoCs will no longer be able to register their own struct iommu_ops or even try to use a struct iommu_ops for an IOMMU that obviously isn't there. The smallest fix I could think of is to check for the existence of any Exynos System MMU devices in the device tree and skip initialization otherwise. This fixes a problem on Tegra20 where the DRM driver will try to use the obviously non-existent Exynos System MMU. Reported-by: Nicolas Chauvet Cc: Kukjin Kim Signed-off-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 7ce52737c7a1..dc14fec4ede1 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1186,8 +1186,15 @@ static const struct iommu_ops exynos_iommu_ops = { static int __init exynos_iommu_init(void) { + struct device_node *np; int ret; + np = of_find_matching_node(NULL, sysmmu_of_match); + if (!np) + return 0; + + of_node_put(np); + lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table", LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL); if (!lv2table_kmem_cache) { -- cgit v1.2.3 From f938aab2c46c906b41261629982e2a2cda9e819f Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 6 Feb 2015 11:44:06 +0100 Subject: iommu/omap: Play nice in multi-platform builds The OMAP IOMMU driver unconditionally executes code and registers a struct iommu_ops with the platform bus irrespective of whether it runs on an OMAP SoC or not. This causes problems in multi-platform kernels where drivers for other SoCs will no longer be able to register their own struct iommu_ops or even try to use a struct iommu_ops for an IOMMU that obviously isn't there. The smallest fix I could think of is to check for the existence of any OMAP IOMMU devices in the device tree and skip initialization otherwise. This fixes a problem on Tegra20 where the DRM driver will try to use the obviously non-existent OMAP IOMMU. Reported-by: Nicolas Chauvet Cc: Tony Lindgren Cc: Suman Anna Cc: Laurent Pinchart Signed-off-by: Thierry Reding Acked-by: Laurent Pinchart Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index f59f857b702e..a4ba851825c2 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1376,6 +1376,13 @@ static int __init omap_iommu_init(void) struct kmem_cache *p; const unsigned long flags = SLAB_HWCACHE_ALIGN; size_t align = 1 << 10; /* L2 pagetable alignement */ + struct device_node *np; + + np = of_find_matching_node(NULL, omap_iommu_of_match); + if (!np) + return 0; + + of_node_put(np); p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags, iopte_cachep_ctor); -- cgit v1.2.3 From 425061b0f5074c727446b6383d0880f089ede469 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 6 Feb 2015 11:44:07 +0100 Subject: iommu/rockchip: Play nice in multi-platform builds The Rockchip IOMMU driver unconditionally executes code and registers a struct iommu_ops with the platform bus irrespective of whether it runs on a Rockchip SoC or not. This causes problems in multi-platform kernels where drivers for other SoCs will no longer be able to register their own struct iommu_ops or even try to use a struct iommu_ops for an IOMMU that obviously isn't there. The smallest fix I could think of is to check for the existence of any Rockchip IOMMU devices in the device tree and skip initialization otherwise. This fixes a problem on Tegra20 where the DRM driver will try to use the obviously non-existent Rockchip IOMMU. Reported-by: Nicolas Chauvet Cc: Heiko Stuebner Cc: Daniel Kurtz Reviewed-by: Heiko Stuebner Tested-by: Heiko Stuebner Signed-off-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/rockchip-iommu.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index 6a8b1ec4a48a..9f74fddcd304 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1015,8 +1015,15 @@ static struct platform_driver rk_iommu_driver = { static int __init rk_iommu_init(void) { + struct device_node *np; int ret; + np = of_find_matching_node(NULL, rk_iommu_dt_ids); + if (!np) + return 0; + + of_node_put(np); + ret = bus_set_iommu(&platform_bus_type, &rk_iommu_ops); if (ret) return ret; -- cgit v1.2.3 From a3f447a4f19c5799bf67be622a72846ab81c5399 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 6 Feb 2015 11:44:08 +0100 Subject: iommu/msm: Mark driver BROKEN The MSM IOMMU driver unconditionally calls bus_set_iommu(), which is a very stupid thing to do on multi-platform kernels. While marking the driver BROKEN may seem a little extreme, there is no other way to make the driver skip initialization. One of the problems is that it doesn't have devicetree binding documentation and the driver doesn't contain a struct of_device_id table either, so no way to check that it is indeed valid to set up the IOMMU operations for this driver. This fixes a problem on Tegra20 where the DRM driver will try to use the obviously non-existent MSM IOMMU. Marking the driver BROKEN shouldn't do any harm, since there aren't any users currently. There is no struct of_device_id table, so the device can't be instantiated from device tree, and I couldn't find any code that would instantiate a matching platform_device either, so the driver is effectively unused. Reported-by: Nicolas Chauvet Cc: David Brown Cc: Daniel Walker Cc: Bryan Huntsman Cc: Olav Haugan Acked-by: Rob Clark Signed-off-by: Thierry Reding Signed-off-by: Joerg Roedel --- drivers/iommu/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index baa0d9786f50..2bd5b18106c8 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -63,6 +63,7 @@ config MSM_IOMMU bool "MSM IOMMU Support" depends on ARM depends on ARCH_MSM8X60 || ARCH_MSM8960 || COMPILE_TEST + depends on BROKEN select IOMMU_API help Support for the IOMMUs found on certain Qualcomm SOCs. -- cgit v1.2.3 From 03208cc69fc16a8d46de49f51f49964666e4a694 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 28 Jan 2015 09:00:49 -0800 Subject: clk: ti: Fix FAPLL parent enable bit handling Commit 163152cbbe32 ("clk: ti: Add support for FAPLL on dm816x") added basic support for the FAPLL on dm818x, but has a bug for the parent PLL enable bit. The FAPLL_MAIN_PLLEN is defined as BIT(3) but the code is doing a shift on it. This means the parent PLL won't get disabled even if all it's child synthesizers are disabled. Reported-by: Dan Carpenter Cc: Brian Hutchinson Signed-off-by: Tony Lindgren Signed-off-by: Michael Turquette --- drivers/clk/ti/fapll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c index 6ef89639a9f6..d21640634adf 100644 --- a/drivers/clk/ti/fapll.c +++ b/drivers/clk/ti/fapll.c @@ -84,7 +84,7 @@ static int ti_fapll_enable(struct clk_hw *hw) struct fapll_data *fd = to_fapll(hw); u32 v = readl_relaxed(fd->base); - v |= (1 << FAPLL_MAIN_PLLEN); + v |= FAPLL_MAIN_PLLEN; writel_relaxed(v, fd->base); return 0; @@ -95,7 +95,7 @@ static void ti_fapll_disable(struct clk_hw *hw) struct fapll_data *fd = to_fapll(hw); u32 v = readl_relaxed(fd->base); - v &= ~(1 << FAPLL_MAIN_PLLEN); + v &= ~FAPLL_MAIN_PLLEN; writel_relaxed(v, fd->base); } @@ -104,7 +104,7 @@ static int ti_fapll_is_enabled(struct clk_hw *hw) struct fapll_data *fd = to_fapll(hw); u32 v = readl_relaxed(fd->base); - return v & (1 << FAPLL_MAIN_PLLEN); + return v & FAPLL_MAIN_PLLEN; } static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw, -- cgit v1.2.3 From 7dd47b8ef54c301ecde58cecf2f3e29ff3f48d4a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 29 Jan 2015 15:38:11 -0800 Subject: clk: qcom: Fix slimbus n and m val offsets These shifts were copy/pasted from the pcm which is a different size RCG. Use the correct offsets so that slimbus rates are correct. Fixes: b82875ee07e5 "clk: qcom: Add MSM8960/APQ8064 LPASS clock controller (LCC) driver" Signed-off-by: Stephen Boyd Signed-off-by: Michael Turquette --- drivers/clk/qcom/lcc-msm8960.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c index a75a408cfccd..705e4d5bb6c7 100644 --- a/drivers/clk/qcom/lcc-msm8960.c +++ b/drivers/clk/qcom/lcc-msm8960.c @@ -417,8 +417,8 @@ static struct clk_rcg slimbus_src = { .mnctr_en_bit = 8, .mnctr_reset_bit = 7, .mnctr_mode_shift = 5, - .n_val_shift = 16, - .m_val_shift = 16, + .n_val_shift = 24, + .m_val_shift = 8, .width = 8, }, .p = { -- cgit v1.2.3 From 84b919fdb8559a8cd5432d8fa0002219df59cb32 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 29 Jan 2015 15:38:12 -0800 Subject: clk: qcom: lcc-msm8960: Fix PLL rate detection regmap_read() returns 0 on success, not the value of the register that is read. Fix it so we properly detect the frequency plan. Fixes: b82875ee07e5 "clk: qcom: Add MSM8960/APQ8064 LPASS clock controller (LCC) driver" Signed-off-by: Stephen Boyd Signed-off-by: Michael Turquette --- drivers/clk/qcom/lcc-msm8960.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c index 705e4d5bb6c7..3ecade0de9d2 100644 --- a/drivers/clk/qcom/lcc-msm8960.c +++ b/drivers/clk/qcom/lcc-msm8960.c @@ -547,7 +547,7 @@ static int lcc_msm8960_probe(struct platform_device *pdev) return PTR_ERR(regmap); /* Use the correct frequency plan depending on speed of PLL4 */ - val = regmap_read(regmap, 0x4, &val); + regmap_read(regmap, 0x4, &val); if (val == 0x12) { slimbus_src.freq_tbl = clk_tbl_aif_osr_492; mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492; -- cgit v1.2.3 From 4be8fc04700aafeb3c8a9c10ece5652e08ec0e94 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 29 Jan 2015 15:38:13 -0800 Subject: clk: qcom: Add PLL4 vote clock This clock is needed for most audio clock frequencies. Add it. Signed-off-by: Stephen Boyd Signed-off-by: Michael Turquette --- drivers/clk/qcom/gcc-msm8960.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index b0b562b9ce0e..e60feffc10a1 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -48,6 +48,17 @@ static struct clk_pll pll3 = { }, }; +static struct clk_regmap pll4_vote = { + .enable_reg = 0x34c0, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "pll4_vote", + .parent_names = (const char *[]){ "pll4" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + static struct clk_pll pll8 = { .l_reg = 0x3144, .m_reg = 0x3148, @@ -3023,6 +3034,7 @@ static struct clk_branch rpm_msg_ram_h_clk = { static struct clk_regmap *gcc_msm8960_clks[] = { [PLL3] = &pll3.clkr, + [PLL4_VOTE] = &pll4_vote, [PLL8] = &pll8.clkr, [PLL8_VOTE] = &pll8_vote, [PLL14] = &pll14.clkr, @@ -3247,6 +3259,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { static struct clk_regmap *gcc_apq8064_clks[] = { [PLL3] = &pll3.clkr, + [PLL4_VOTE] = &pll4_vote, [PLL8] = &pll8.clkr, [PLL8_VOTE] = &pll8_vote, [PLL14] = &pll14.clkr, -- cgit v1.2.3 From 3b34109a4d07e732dac6db1102a3399177333651 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 28 Jan 2015 15:00:51 +0800 Subject: clk: qcom: fix platform_no_drv_owner.cocci warnings drivers/clk/qcom/lcc-ipq806x.c:465:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Rajendra Nayak Signed-off-by: Fengguang Wu Reviewed-by: Stephen Boyd Signed-off-by: Michael Turquette --- drivers/clk/qcom/lcc-ipq806x.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c index 121ffde25dc3..c9ff27b4648b 100644 --- a/drivers/clk/qcom/lcc-ipq806x.c +++ b/drivers/clk/qcom/lcc-ipq806x.c @@ -462,7 +462,6 @@ static struct platform_driver lcc_ipq806x_driver = { .remove = lcc_ipq806x_remove, .driver = { .name = "lcc-ipq806x", - .owner = THIS_MODULE, .of_match_table = lcc_ipq806x_match_table, }, }; -- cgit v1.2.3 From a456fe3d27b1fe502fe3d5fd21cd025e5bf64c22 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 28 Jan 2015 15:11:34 +0800 Subject: clk: qcom: fix platform_no_drv_owner.cocci warnings drivers/clk/qcom/lcc-msm8960.c:577:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Fengguang Wu Reviewed-by: Stephen Boyd Signed-off-by: Michael Turquette --- drivers/clk/qcom/lcc-msm8960.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c index 3ecade0de9d2..e2c863295f00 100644 --- a/drivers/clk/qcom/lcc-msm8960.c +++ b/drivers/clk/qcom/lcc-msm8960.c @@ -574,7 +574,6 @@ static struct platform_driver lcc_msm8960_driver = { .remove = lcc_msm8960_remove, .driver = { .name = "lcc-msm8960", - .owner = THIS_MODULE, .of_match_table = lcc_msm8960_match_table, }, }; -- cgit v1.2.3 From 74ad752442d9488cf02ee2a9243d6c6b5c943efb Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Tue, 24 Feb 2015 10:47:49 -0600 Subject: amd-xgbe-phy: PHY KX/KR mode differences The PHY requires different settings for the Decision Feedback Analyzer (DFE) when running in KX mode vs. KR mode. Update the code to change these settings when changing modes in order to provide a more stable link. Additionally, adjust the 10GbE PQ skew default setting to a more sane value. Signed-off-by: Tom Lendacky Signed-off-by: David S. Miller --- .../devicetree/bindings/net/amd-xgbe-phy.txt | 4 ++ drivers/net/phy/amd-xgbe-phy.c | 82 +++++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt b/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt index 33df3932168e..8db32384a486 100644 --- a/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt +++ b/Documentation/devicetree/bindings/net/amd-xgbe-phy.txt @@ -27,6 +27,8 @@ property is used. - amd,serdes-cdr-rate: CDR rate speed selection - amd,serdes-pq-skew: PQ (data sampling) skew - amd,serdes-tx-amp: TX amplitude boost +- amd,serdes-dfe-tap-config: DFE taps available to run +- amd,serdes-dfe-tap-enable: DFE taps to enable Example: xgbe_phy@e1240800 { @@ -41,4 +43,6 @@ Example: amd,serdes-cdr-rate = <2>, <2>, <7>; amd,serdes-pq-skew = <10>, <10>, <30>; amd,serdes-tx-amp = <15>, <15>, <10>; + amd,serdes-dfe-tap-config = <3>, <3>, <1>; + amd,serdes-dfe-tap-enable = <0>, <0>, <127>; }; diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c index 9e3af54c9010..32efbd48f326 100644 --- a/drivers/net/phy/amd-xgbe-phy.c +++ b/drivers/net/phy/amd-xgbe-phy.c @@ -92,6 +92,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define XGBE_PHY_CDR_RATE_PROPERTY "amd,serdes-cdr-rate" #define XGBE_PHY_PQ_SKEW_PROPERTY "amd,serdes-pq-skew" #define XGBE_PHY_TX_AMP_PROPERTY "amd,serdes-tx-amp" +#define XGBE_PHY_DFE_CFG_PROPERTY "amd,serdes-dfe-tap-config" +#define XGBE_PHY_DFE_ENA_PROPERTY "amd,serdes-dfe-tap-enable" #define XGBE_PHY_SPEEDS 3 #define XGBE_PHY_SPEED_1000 0 @@ -177,10 +179,12 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define SPEED_10000_BLWC 0 #define SPEED_10000_CDR 0x7 #define SPEED_10000_PLL 0x1 -#define SPEED_10000_PQ 0x1e +#define SPEED_10000_PQ 0x12 #define SPEED_10000_RATE 0x0 #define SPEED_10000_TXAMP 0xa #define SPEED_10000_WORD 0x7 +#define SPEED_10000_DFE_TAP_CONFIG 0x1 +#define SPEED_10000_DFE_TAP_ENABLE 0x7f #define SPEED_2500_BLWC 1 #define SPEED_2500_CDR 0x2 @@ -189,6 +193,8 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define SPEED_2500_RATE 0x1 #define SPEED_2500_TXAMP 0xf #define SPEED_2500_WORD 0x1 +#define SPEED_2500_DFE_TAP_CONFIG 0x3 +#define SPEED_2500_DFE_TAP_ENABLE 0x0 #define SPEED_1000_BLWC 1 #define SPEED_1000_CDR 0x2 @@ -197,16 +203,25 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); #define SPEED_1000_RATE 0x3 #define SPEED_1000_TXAMP 0xf #define SPEED_1000_WORD 0x1 +#define SPEED_1000_DFE_TAP_CONFIG 0x3 +#define SPEED_1000_DFE_TAP_ENABLE 0x0 /* SerDes RxTx register offsets */ +#define RXTX_REG6 0x0018 #define RXTX_REG20 0x0050 +#define RXTX_REG22 0x0058 #define RXTX_REG114 0x01c8 +#define RXTX_REG129 0x0204 /* SerDes RxTx register entry bit positions and sizes */ +#define RXTX_REG6_RESETB_RXD_INDEX 8 +#define RXTX_REG6_RESETB_RXD_WIDTH 1 #define RXTX_REG20_BLWC_ENA_INDEX 2 #define RXTX_REG20_BLWC_ENA_WIDTH 1 #define RXTX_REG114_PQ_REG_INDEX 9 #define RXTX_REG114_PQ_REG_WIDTH 7 +#define RXTX_REG129_RXDFE_CONFIG_INDEX 14 +#define RXTX_REG129_RXDFE_CONFIG_WIDTH 2 /* Bit setting and getting macros * The get macro will extract the current bit field value from within @@ -333,6 +348,18 @@ static const u32 amd_xgbe_phy_serdes_tx_amp[] = { SPEED_10000_TXAMP, }; +static const u32 amd_xgbe_phy_serdes_dfe_tap_cfg[] = { + SPEED_1000_DFE_TAP_CONFIG, + SPEED_2500_DFE_TAP_CONFIG, + SPEED_10000_DFE_TAP_CONFIG, +}; + +static const u32 amd_xgbe_phy_serdes_dfe_tap_ena[] = { + SPEED_1000_DFE_TAP_ENABLE, + SPEED_2500_DFE_TAP_ENABLE, + SPEED_10000_DFE_TAP_ENABLE, +}; + enum amd_xgbe_phy_an { AMD_XGBE_AN_READY = 0, AMD_XGBE_AN_PAGE_RECEIVED, @@ -393,6 +420,8 @@ struct amd_xgbe_phy_priv { u32 serdes_cdr_rate[XGBE_PHY_SPEEDS]; u32 serdes_pq_skew[XGBE_PHY_SPEEDS]; u32 serdes_tx_amp[XGBE_PHY_SPEEDS]; + u32 serdes_dfe_tap_cfg[XGBE_PHY_SPEEDS]; + u32 serdes_dfe_tap_ena[XGBE_PHY_SPEEDS]; /* Auto-negotiation state machine support */ struct mutex an_mutex; @@ -481,11 +510,16 @@ static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev) status = XSIR0_IOREAD(priv, SIR0_STATUS); if (XSIR_GET_BITS(status, SIR0_STATUS, RX_READY) && XSIR_GET_BITS(status, SIR0_STATUS, TX_READY)) - return; + goto rx_reset; } netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n", status); + +rx_reset: + /* Perform Rx reset for the DFE changes */ + XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 0); + XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RESETB_RXD, 1); } static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) @@ -534,6 +568,10 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) priv->serdes_blwc[XGBE_PHY_SPEED_10000]); XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG, + priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_10000]); + XRXTX_IOWRITE(priv, RXTX_REG22, + priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_10000]); amd_xgbe_phy_serdes_complete_ratechange(phydev); @@ -586,6 +624,10 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev) priv->serdes_blwc[XGBE_PHY_SPEED_2500]); XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG, + priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_2500]); + XRXTX_IOWRITE(priv, RXTX_REG22, + priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_2500]); amd_xgbe_phy_serdes_complete_ratechange(phydev); @@ -638,6 +680,10 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev) priv->serdes_blwc[XGBE_PHY_SPEED_1000]); XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]); + XRXTX_IOWRITE_BITS(priv, RXTX_REG129, RXDFE_CONFIG, + priv->serdes_dfe_tap_cfg[XGBE_PHY_SPEED_1000]); + XRXTX_IOWRITE(priv, RXTX_REG22, + priv->serdes_dfe_tap_ena[XGBE_PHY_SPEED_1000]); amd_xgbe_phy_serdes_complete_ratechange(phydev); @@ -1668,6 +1714,38 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev) sizeof(priv->serdes_tx_amp)); } + if (device_property_present(phy_dev, XGBE_PHY_DFE_CFG_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_DFE_CFG_PROPERTY, + priv->serdes_dfe_tap_cfg, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_DFE_CFG_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_dfe_tap_cfg, + amd_xgbe_phy_serdes_dfe_tap_cfg, + sizeof(priv->serdes_dfe_tap_cfg)); + } + + if (device_property_present(phy_dev, XGBE_PHY_DFE_ENA_PROPERTY)) { + ret = device_property_read_u32_array(phy_dev, + XGBE_PHY_DFE_ENA_PROPERTY, + priv->serdes_dfe_tap_ena, + XGBE_PHY_SPEEDS); + if (ret) { + dev_err(dev, "invalid %s property\n", + XGBE_PHY_DFE_ENA_PROPERTY); + goto err_sir1; + } + } else { + memcpy(priv->serdes_dfe_tap_ena, + amd_xgbe_phy_serdes_dfe_tap_ena, + sizeof(priv->serdes_dfe_tap_ena)); + } + phydev->priv = priv; if (!priv->adev || acpi_disabled) -- cgit v1.2.3 From 71daf89476144343df5db1686759a06459292a5f Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 25 Feb 2015 17:11:04 -0800 Subject: Input: mma8450 - add parent device Add the parent device so that udev can show the full hierarchy. This avoids the device showing up under /devices/virtual/input instead of the i2c bus it is actually attached to. Signed-off-by: Stefan Sauer Signed-off-by: Dmitry Torokhov --- drivers/input/misc/mma8450.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index 59d4dcddf6de..98228773a111 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -187,6 +187,7 @@ static int mma8450_probe(struct i2c_client *c, idev->private = m; idev->input->name = MMA8450_DRV_NAME; idev->input->id.bustype = BUS_I2C; + idev->input->dev.parent = &c->dev; idev->poll = mma8450_poll; idev->poll_interval = POLL_INTERVAL; idev->poll_interval_max = POLL_INTERVAL_MAX; -- cgit v1.2.3 From 9d239d353c319f9ff884c287ce47feb7cdf60ddc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 25 Feb 2015 11:39:36 +0200 Subject: spi: dw: revisit FIFO size detection again The commit d297933cc7fc (spi: dw: Fix detecting FIFO depth) tries to fix the logic of the FIFO detection based on the description on the comments. However, there is a slight difference between numbers in TX Level and TX FIFO size. So, by specification the FIFO size would be in a range 2-256 bytes. From TX Level prospective it means we can set threshold in the range 0-(FIFO size - 1) bytes. Hence there are currently two issues: a) FIFO size 2 bytes is actually skipped since TX Level is 1 bit and could be either 0 or 1 byte; b) FIFO size is incorrectly decreased by 1 which already done by meaning of TX Level register. This patch fixes it eventually right. Fixes: d297933cc7fc (spi: dw: Fix detecting FIFO depth) Reviewed-by: Axel Lin Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-dw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 5a97a62b298a..4847afba89f4 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -621,14 +621,14 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws) if (!dws->fifo_len) { u32 fifo; - for (fifo = 2; fifo <= 256; fifo++) { + for (fifo = 1; fifo < 256; fifo++) { dw_writew(dws, DW_SPI_TXFLTR, fifo); if (fifo != dw_readw(dws, DW_SPI_TXFLTR)) break; } dw_writew(dws, DW_SPI_TXFLTR, 0); - dws->fifo_len = (fifo == 2) ? 0 : fifo - 1; + dws->fifo_len = (fifo == 1) ? 0 : fifo; dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len); } } -- cgit v1.2.3 From 76e1d14b316d6f501ebc001e7a5d86b24ce5b615 Mon Sep 17 00:00:00 2001 From: Torsten Fleischer Date: Tue, 24 Feb 2015 16:32:57 +0100 Subject: spi: atmel: Fix interrupt setup for PDC transfers Additionally to the current DMA transfer the PDC allows to set up a next DMA transfer. This is useful for larger SPI transfers. The driver currently waits for ENDRX as end of the transfer. But ENDRX is set when the current DMA transfer is done (RCR = 0), i.e. it doesn't include the next DMA transfer. Thus a subsequent SPI transfer could be started although there is currently a transfer in progress. This can cause invalid accesses to the SPI slave devices and to SPI transfer errors. This issue has been observed on a hardware with a M25P128 SPI NOR flash. So instead of ENDRX we should wait for RXBUFF. This flag is set if there is no more DMA transfer in progress (RCR = RNCR = 0). Signed-off-by: Torsten Fleischer Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-atmel.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 9af7841f2e8c..06de34001c66 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -764,17 +764,17 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master, (unsigned long long)xfer->rx_dma); } - /* REVISIT: We're waiting for ENDRX before we start the next + /* REVISIT: We're waiting for RXBUFF before we start the next * transfer because we need to handle some difficult timing - * issues otherwise. If we wait for ENDTX in one transfer and - * then starts waiting for ENDRX in the next, it's difficult - * to tell the difference between the ENDRX interrupt we're - * actually waiting for and the ENDRX interrupt of the + * issues otherwise. If we wait for TXBUFE in one transfer and + * then starts waiting for RXBUFF in the next, it's difficult + * to tell the difference between the RXBUFF interrupt we're + * actually waiting for and the RXBUFF interrupt of the * previous transfer. * * It should be doable, though. Just not now... */ - spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES)); + spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES)); spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN)); } -- cgit v1.2.3 From 11f09e53af05822d8c481edc70c08d925d8ef7dd Mon Sep 17 00:00:00 2001 From: Kiran Padwal Date: Wed, 11 Feb 2015 15:06:45 +0530 Subject: video: ARM CLCD: Add missing error check for devm_kzalloc This patch add a missing check on the return value of devm_kzalloc, which would cause a NULL pointer dereference in a OOM situation. Signed-off-by: Kiran Padwal Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/amba-clcd.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c index 32c0b6b28097..9362424c2340 100644 --- a/drivers/video/fbdev/amba-clcd.c +++ b/drivers/video/fbdev/amba-clcd.c @@ -599,6 +599,9 @@ static int clcdfb_of_get_mode(struct device *dev, struct device_node *endpoint, len = clcdfb_snprintf_mode(NULL, 0, mode); name = devm_kzalloc(dev, len + 1, GFP_KERNEL); + if (!name) + return -ENOMEM; + clcdfb_snprintf_mode(name, len + 1, mode); mode->name = name; -- cgit v1.2.3 From d746b40c64619f5064ebbe545938062481ef5183 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 12 Feb 2015 21:17:36 +0530 Subject: video: fbdev: fix possible null dereference we were dereferencing edid first and the NULL check was after accessing that. now we are using edid only if we know that it is not NULL. Signed-off-by: Sudip Mukherjee Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/core/fbmon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index 95338593ebf4..868facdec638 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -624,9 +624,6 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize, int num = 0, i, first = 1; int ver, rev; - ver = edid[EDID_STRUCT_VERSION]; - rev = edid[EDID_STRUCT_REVISION]; - mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); if (mode == NULL) return NULL; @@ -637,6 +634,9 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize, return NULL; } + ver = edid[EDID_STRUCT_VERSION]; + rev = edid[EDID_STRUCT_REVISION]; + *dbsize = 0; DPRINTK(" Detailed Timings\n"); -- cgit v1.2.3 From a38bb793eaebe1178fbd8ef6ab66ccc062bad505 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 25 Feb 2015 10:23:58 +0200 Subject: OMAPDSS: fix regression with display sysfs files omapdss's sysfs directories for displays used to have 'name' file, giving the name for the display. This file was later renamed to 'display_name' to avoid conflicts with i2c sysfs 'name' file. Looks like at least xserver-xorg-video-omap3 requires the 'name' file to be present. To fix the regression, this patch creates new kobjects for each display, allowing us to create sysfs directories for the displays. This way we have the whole directory for omapdss, and there will be no sysfs file clashes with the underlying display device's sysfs files. We can thus add the 'name' sysfs file back. Signed-off-by: Tomi Valkeinen Tested-by: NeilBrown --- drivers/video/fbdev/omap2/dss/display-sysfs.c | 179 ++++++++++++++------------ include/video/omapdss.h | 1 + 2 files changed, 96 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbdev/omap2/dss/display-sysfs.c b/drivers/video/fbdev/omap2/dss/display-sysfs.c index 5a2095a98ed8..12186557a9d4 100644 --- a/drivers/video/fbdev/omap2/dss/display-sysfs.c +++ b/drivers/video/fbdev/omap2/dss/display-sysfs.c @@ -28,44 +28,22 @@ #include