From 5ec97ba0713d118a1cd03ccc7677a13769253bbd Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 29 Apr 2016 14:42:33 +0300 Subject: iio: bmi160: Fix output data rate for accel Format is INT_PLUS_MICRO and micro odr part of ODR should be parts of a micro. Also s/8000/800 this is obviously a typo. Fixes: 77c4ad2d6a9 ("iio: imu: Add initial support for Bosch BMI160") Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/imu/bmi160/bmi160_core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 0bf92b06d7d8..cd9b75eeccd7 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -209,11 +209,11 @@ static const struct bmi160_scale_item bmi160_scale_table[] = { }; static const struct bmi160_odr bmi160_accel_odr[] = { - {0x01, 0, 78125}, - {0x02, 1, 5625}, - {0x03, 3, 125}, - {0x04, 6, 25}, - {0x05, 12, 5}, + {0x01, 0, 781250}, + {0x02, 1, 562500}, + {0x03, 3, 125000}, + {0x04, 6, 250000}, + {0x05, 12, 500000}, {0x06, 25, 0}, {0x07, 50, 0}, {0x08, 100, 0}, @@ -229,7 +229,7 @@ static const struct bmi160_odr bmi160_gyro_odr[] = { {0x08, 100, 0}, {0x09, 200, 0}, {0x0A, 400, 0}, - {0x0B, 8000, 0}, + {0x0B, 800, 0}, {0x0C, 1600, 0}, {0x0D, 3200, 0}, }; -- cgit v1.2.3 From c25d3f37be016b301f446a5257645c4845daf53c Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 29 Apr 2016 14:42:34 +0300 Subject: iio: bmi160: Fix ODR setting mask and val parameters of regmap_update_bits were reveresed. Fixes: 77c4ad2d6a9 ("iio: imu: Add initial support for Bosch BMI160") Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/imu/bmi160/bmi160_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index cd9b75eeccd7..b8a290ec984e 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -364,8 +364,8 @@ int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t, return regmap_update_bits(data->regmap, bmi160_regs[t].config, - bmi160_odr_table[t].tbl[i].bits, - bmi160_regs[t].config_odr_mask); + bmi160_regs[t].config_odr_mask, + bmi160_odr_table[t].tbl[i].bits); } static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, -- cgit v1.2.3 From 04bf02175fe9577875fb8285cc2d08169fef613a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 29 Apr 2016 12:03:31 +0300 Subject: iio: dac: ad5592r: Off by one bug in ad5592r_alloc_channels() The > here should be >= or we go beyond the end for the array. Signed-off-by: Dan Carpenter Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5592r-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c index 948f600e7059..69bde5909854 100644 --- a/drivers/iio/dac/ad5592r-base.c +++ b/drivers/iio/dac/ad5592r-base.c @@ -525,7 +525,7 @@ static int ad5592r_alloc_channels(struct ad5592r_state *st) device_for_each_child_node(st->dev, child) { ret = fwnode_property_read_u32(child, "reg", ®); - if (ret || reg > ARRAY_SIZE(st->channel_modes)) + if (ret || reg >= ARRAY_SIZE(st->channel_modes)) continue; ret = fwnode_property_read_u32(child, "adi,mode", &tmp); -- cgit v1.2.3 From 53dfc3b9e6c54d077f578f9016b6c8ab5f891e10 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 28 Apr 2016 14:02:41 +0200 Subject: iio: light: bh1780: return after write When writing a value using direct reg access from debugfs we need to return and not fall through to reading the value, lest we'll dereference a NULL pointer. Cc: Dan Carpenter Reported-by: Dan Carpenter Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/light/bh1780.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index 72b364e4aa72..f83595334ff1 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -84,7 +84,7 @@ static int bh1780_debugfs_reg_access(struct iio_dev *indio_dev, int ret; if (!readval) - bh1780_write(bh1780, (u8)reg, (u8)writeval); + return bh1780_write(bh1780, (u8)reg, (u8)writeval); ret = bh1780_read(bh1780, (u8)reg); if (ret < 0) -- cgit v1.2.3 From a3e5afe491bf7462013aa9f0bb3b55e3d05b784d Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 28 Apr 2016 23:39:53 +0900 Subject: iio: pressure: bmp280: fix error message for wrong chip id The bmp280 driver also supports BMP180 which has a different chip id with BMP280. The probe routine verifies that the device reports the correct chip id but the error message is confusing as if BMP280's chip id is always expected. Reported-by: Matt Ranostay Signed-off-by: Akinobu Mita Cc: Matt Ranostay Cc: Vlad Dogaru Cc: Christoph Mair Cc: Jonathan Cameron Cc: Hartmut Knaack Cc: Lars-Peter Clausen Cc: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/bmp280.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c index 2f1498e12bb2..724452d61846 100644 --- a/drivers/iio/pressure/bmp280.c +++ b/drivers/iio/pressure/bmp280.c @@ -879,8 +879,8 @@ static int bmp280_probe(struct i2c_client *client, if (ret < 0) return ret; if (chip_id != id->driver_data) { - dev_err(&client->dev, "bad chip id. expected %x got %x\n", - BMP280_CHIP_ID, chip_id); + dev_err(&client->dev, "bad chip id. expected %lx got %x\n", + id->driver_data, chip_id); return -EINVAL; } -- cgit v1.2.3 From d462e32259810aaaf13440b033b99e1aad33eccd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 18 May 2016 13:39:05 +0300 Subject: crypto: omap-sham - potential Oops on error in probe This if statement is reversed so we end up either leaking or Oopsing on error. Fixes: dbe246209bc1 ('crypto: omap-sham - Use dma_request_chan() for requesting DMA channel') Signed-off-by: Dan Carpenter Acked-by: Peter Ujfalusi Signed-off-by: Herbert Xu --- drivers/crypto/omap-sham.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 6eefaa2fe58f..63464e86f2b1 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -1986,7 +1986,7 @@ err_algs: &dd->pdata->algs_info[i].algs_list[j]); err_pm: pm_runtime_disable(dev); - if (dd->polling_mode) + if (!dd->polling_mode) dma_release_channel(dd->dma_lch); data_err: dev_err(dev, "initialization failed.\n"); -- cgit v1.2.3 From 0e35cf5ce00d873d6e529d2b2cd7598d52438051 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Fri, 20 May 2016 10:06:41 -0700 Subject: iio: humidity: hdc100x: correct humidity integration time mask Apply the correct mask to enable all available humidity integration times. Currently, the driver defaults to 6500 and all is okay with that. However, if 3850 is selected we get a stuck bit and can't change back to 6500 or select 2500. (Verified with HDC1008) Signed-off-by: Alison Schofield Cc: Daniel Baluta Reviewed-by: Matt Ranostay Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/hdc100x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index fa4767613173..59aa1cbdc2fd 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -55,7 +55,7 @@ static const struct { }, { /* IIO_HUMIDITYRELATIVE channel */ .shift = 8, - .mask = 2, + .mask = 3, }, }; -- cgit v1.2.3 From 1cb0d06a00f2ec0ed8f926ec62f53bc9e12ea55e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 17 May 2016 11:02:56 +0300 Subject: iio: humidity: am2315: Remove a stray unlock We haven't taken the lock yet so we don't need to unlock here. Fixes: 0d96d5ead3f7 ('iio: humidity: Add triggered buffer support for AM2315') Signed-off-by: Dan Carpenter Acked-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/am2315.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/am2315.c b/drivers/iio/humidity/am2315.c index 3be6d209a159..11535911a5c6 100644 --- a/drivers/iio/humidity/am2315.c +++ b/drivers/iio/humidity/am2315.c @@ -165,10 +165,8 @@ static irqreturn_t am2315_trigger_handler(int irq, void *p) struct am2315_sensor_data sensor_data; ret = am2315_read_data(data, &sensor_data); - if (ret < 0) { - mutex_unlock(&data->lock); + if (ret < 0) goto err; - } mutex_lock(&data->lock); if (*(indio_dev->active_scan_mask) == AM2315_ALL_CHANNEL_MASK) { -- cgit v1.2.3 From 14f2461b822dffb116256ee9155f7eca96064f7a Mon Sep 17 00:00:00 2001 From: Crestez Dan Leonard Date: Fri, 20 May 2016 17:44:36 +0300 Subject: max44000: Remove scale from proximity This is not implemented and doesn't really make sense because IIO proximity is unit-less. Remove IIO_CHAN_INFO_SCALE from info_mask because so that the _scale sysfs entry won't appear. This fixes userspace tools like generic_buffer which abort when reads returns an error. Signed-off-by: Crestez Dan Leonard Signed-off-by: Jonathan Cameron --- drivers/iio/light/max44000.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index e01e58a9bd14..f17cb2ea18f5 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -147,7 +147,6 @@ static const struct iio_chan_spec max44000_channels[] = { { .type = IIO_PROXIMITY, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), .scan_index = MAX44000_SCAN_INDEX_PRX, .scan_type = { .sign = 'u', -- cgit v1.2.3 From a621bac3044ed6f7ec5fa0326491b2d4838bfa93 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 13 May 2016 12:04:06 -0700 Subject: scsi_lib: correctly retry failed zero length REQ_TYPE_FS commands When SCSI was written, all commands coming from the filesystem (REQ_TYPE_FS commands) had data. This meant that our signal for needing to complete the command was the number of bytes completed being equal to the number of bytes in the request. Unfortunately, with the advent of flush barriers, we can now get zero length REQ_TYPE_FS commands, which confuse this logic because they satisfy the condition every time. This means they never get retried even for retryable conditions, like UNIT ATTENTION because we complete them early assuming they're done. Fix this by special casing the early completion condition to recognise zero length commands with errors and let them drop through to the retry code. Cc: stable@vger.kernel.org Reported-by: Sebastian Parschauer Signed-off-by: James E.J. Bottomley Tested-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index b2e332af0f51..c71344aebdbb 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -821,9 +821,12 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } /* - * If we finished all bytes in the request we are done now. + * special case: failed zero length commands always need to + * drop down into the retry code. Otherwise, if we finished + * all bytes in the request we are done now. */ - if (!scsi_end_request(req, error, good_bytes, 0)) + if (!(blk_rq_bytes(req) == 0 && error) && + !scsi_end_request(req, error, good_bytes, 0)) return; /* -- cgit v1.2.3 From eb72d0bb84eee5d0dc3044fd17b75e7101dabb57 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 26 Apr 2016 08:06:58 +0200 Subject: sd: get disk reference in sd_check_events() sd_check_events() is called asynchronously, and might race with device removal. So always take a disk reference when processing the event to avoid the device being removed while the event is processed. Signed-off-by: Hannes Reinecke Reviewed-by: Ewan D. Milne Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 428c03ef02b2..f459dff30512 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1398,11 +1398,15 @@ static int media_not_present(struct scsi_disk *sdkp, **/ static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) { - struct scsi_disk *sdkp = scsi_disk(disk); - struct scsi_device *sdp = sdkp->device; + struct scsi_disk *sdkp = scsi_disk_get(disk); + struct scsi_device *sdp; struct scsi_sense_hdr *sshdr = NULL; int retval; + if (!sdkp) + return 0; + + sdp = sdkp->device; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n")); /* @@ -1459,6 +1463,7 @@ out: kfree(sshdr); retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0; sdp->changed = 0; + scsi_disk_put(sdkp); return retval; } -- cgit v1.2.3 From 7ebd67e0dece0ec53e5541fc600eda4e050fab72 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 12 May 2016 23:37:38 +0300 Subject: mpt3sas: add missing curly braces There are some missing curly braces on this if statement, so we end up printing when we shouldn't. Fixes: a470a51cd648 ('mpt3sas: Handle active cable exception event') Signed-off-by: Dan Carpenter Acked-by: Chaitra P B Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 6a4df5a315e9..6bff13e7afc7 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -7975,13 +7975,14 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, ActiveCableEventData = (Mpi26EventDataActiveCableExcept_t *) mpi_reply->EventData; if (ActiveCableEventData->ReasonCode == - MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER) + MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER) { pr_info(MPT3SAS_FMT "Currently an active cable with ReceptacleID %d", ioc->name, ActiveCableEventData->ReceptacleID); pr_info("cannot be powered and devices connected to this active cable"); pr_info("will not be seen. This active cable"); pr_info("requires %d mW of power", ActiveCableEventData->ActiveCablePowerRequirement); + } break; default: /* ignore the rest */ -- cgit v1.2.3 From 787ab6e97024926f38773287d9f98a9b330bce23 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 18 May 2016 10:16:51 +0200 Subject: aacraid: do not activate events on non-SRC adapters Only SRC-based adapters support the AifReqEvent function, so there is no point in trying to activate it on older, non-SRC based adapters. Doing so lead to crashes on older adapters. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Reviewed-by: Raghava Aditya Renukunta Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/aacraid.h | 5 +++++ drivers/scsi/aacraid/linit.c | 11 ++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 8f90d9e77104..969c312de1be 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -620,6 +620,11 @@ struct aac_driver_ident */ #define AAC_QUIRK_SCSI_32 0x0020 +/* + * SRC based adapters support the AifReqEvent functions + */ +#define AAC_QUIRK_SRC 0x0040 + /* * The adapter interface specs all queues to be located in the same * physically contiguous block. The host structure that defines the diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index a943bd230bc2..79871f3519ff 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -236,10 +236,10 @@ static struct aac_driver_ident aac_drivers[] = { { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */ { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec NEMER/ARK Catch All */ - { aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec PMC Series 6 (Tupelo) */ - { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec PMC Series 7 (Denali) */ - { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec PMC Series 8 */ - { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec PMC Series 9 */ + { aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 6 (Tupelo) */ + { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 7 (Denali) */ + { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 8 */ + { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC } /* Adaptec PMC Series 9 */ }; /** @@ -1299,7 +1299,8 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) else shost->this_id = shost->max_id; - aac_intr_normal(aac, 0, 2, 0, NULL); + if (aac_drivers[index].quirks & AAC_QUIRK_SRC) + aac_intr_normal(aac, 0, 2, 0, NULL); /* * dmb - we may need to move the setting of these parms somewhere else once -- cgit v1.2.3 From 5138806f16c74c7cb8ac3e408a859c79eb7c9567 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 21 May 2016 20:01:01 -0700 Subject: iio: proximity: as3935: correct IIO_CHAN_INFO_RAW output IIO_CHAN_INFO_RAW was returning processed data which was incorrect. This also adds the IIO_CHAN_INFO_SCALE value to convert to a processed value. Signed-off-by: Matt Ranostay Cc: Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 | 2 +- drivers/iio/proximity/as3935.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 index 6708c5e264aa..33e96f740639 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 +++ b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 @@ -1,4 +1,4 @@ -What /sys/bus/iio/devices/iio:deviceX/in_proximity_raw +What /sys/bus/iio/devices/iio:deviceX/in_proximity_input Date: March 2014 KernelVersion: 3.15 Contact: Matt Ranostay diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index f4d29d5dbd5f..f0a0defb68a4 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -72,7 +72,8 @@ static const struct iio_chan_spec as3935_channels[] = { .type = IIO_PROXIMITY, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_PROCESSED), + BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_SCALE), .scan_index = 0, .scan_type = { .sign = 'u', @@ -181,7 +182,12 @@ static int as3935_read_raw(struct iio_dev *indio_dev, /* storm out of range */ if (*val == AS3935_DATA_MASK) return -EINVAL; - *val *= 1000; + + if (m == IIO_CHAN_INFO_PROCESSED) + *val *= 1000; + break; + case IIO_CHAN_INFO_SCALE: + *val = 1000; break; default: return -EINVAL; -- cgit v1.2.3 From 7d0643634ea567969bf3f3ed6193a9d6fc75653b Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 21 May 2016 20:01:02 -0700 Subject: iio: proximity: as3935: remove triggered buffer processing Triggered buffers shouldn't return processed data, and the respective conversion was overflowing the defined .realbits for the channel. Cc: george.mccollister@gmail.com Signed-off-by: Matt Ranostay Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/as3935.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index f0a0defb68a4..6aed02437efc 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -213,7 +213,6 @@ static irqreturn_t as3935_trigger_handler(int irq, void *private) if (ret) goto err_read; val &= AS3935_DATA_MASK; - val *= 1000; iio_push_to_buffers_with_timestamp(indio_dev, &val, pf->timestamp); err_read: -- cgit v1.2.3 From 37b1ba2c68cfbe37f5f45bb91bcfaf2b016ae6a1 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 21 May 2016 20:01:03 -0700 Subject: iio: proximity: as3935: fix buffer stack trashing Buffer wasn't of a valid size to allow the timestamp, and correct padding. This patchset also moves the buffer off the stack, and onto the heap. Cc: george.mccollister@gmail.com Signed-off-by: Matt Ranostay Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/as3935.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index 6aed02437efc..e2f926cdcad2 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -64,6 +64,7 @@ struct as3935_state { struct delayed_work work; u32 tune_cap; + u8 buffer[16]; /* 8-bit data + 56-bit padding + 64-bit timestamp */ u8 buf[2] ____cacheline_aligned; }; @@ -212,9 +213,10 @@ static irqreturn_t as3935_trigger_handler(int irq, void *private) ret = as3935_read(st, AS3935_DATA, &val); if (ret) goto err_read; - val &= AS3935_DATA_MASK; - iio_push_to_buffers_with_timestamp(indio_dev, &val, pf->timestamp); + st->buffer[0] = val & AS3935_DATA_MASK; + iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer, + pf->timestamp); err_read: iio_trigger_notify_done(indio_dev->trig); -- cgit v1.2.3 From bbf178e0a0a323d896611905718db112b1ab1807 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Wed, 18 May 2016 20:40:51 +0200 Subject: net: pegasus: simplify logical constraint If !count is true, count < 4 is also true. Signed-off-by: Heinrich Schuchardt Signed-off-by: David S. Miller --- drivers/net/usb/pegasus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 36cd7f016a8d..9bbe0161a2f4 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -473,7 +473,7 @@ static void read_bulk_callback(struct urb *urb) goto goon; } - if (!count || count < 4) + if (count < 4) goto goon; rx_status = buf[count - 2]; -- cgit v1.2.3 From 8da07a393f48864a87c61bb1dfbee640d9b97fd6 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Thu, 19 May 2016 21:20:55 +0200 Subject: net: hns: avoid null pointer dereference In the statement assert(priv || priv->ae_handle); the right side of || is only evaluated if priv is null. v2: As suggested by David Leight and David Miller the assert statements are removed. Signed-off-by: Heinrich Schuchardt Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index 3d746c887873..67a648c7d3a9 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -46,7 +46,6 @@ static u32 hns_nic_get_link(struct net_device *net_dev) u32 link_stat = priv->link; struct hnae_handle *h; - assert(priv && priv->ae_handle); h = priv->ae_handle; if (priv->phy) { @@ -646,8 +645,6 @@ static void hns_nic_get_drvinfo(struct net_device *net_dev, { struct hns_nic_priv *priv = netdev_priv(net_dev); - assert(priv); - strncpy(drvinfo->version, HNAE_DRIVER_VERSION, sizeof(drvinfo->version)); drvinfo->version[sizeof(drvinfo->version) - 1] = '\0'; @@ -720,8 +717,6 @@ static int hns_set_pauseparam(struct net_device *net_dev, struct hnae_handle *h; struct hnae_ae_ops *ops; - assert(priv || priv->ae_handle); - h = priv->ae_handle; ops = h->dev->ops; @@ -780,8 +775,6 @@ static int hns_set_coalesce(struct net_device *net_dev, struct hnae_ae_ops *ops; int ret; - assert(priv || priv->ae_handle); - ops = priv->ae_handle->dev->ops; if (ec->tx_coalesce_usecs != ec->rx_coalesce_usecs) @@ -1111,8 +1104,6 @@ void hns_get_regs(struct net_device *net_dev, struct ethtool_regs *cmd, struct hns_nic_priv *priv = netdev_priv(net_dev); struct hnae_ae_ops *ops; - assert(priv || priv->ae_handle); - ops = priv->ae_handle->dev->ops; cmd->version = HNS_CHIP_VERSION; @@ -1135,8 +1126,6 @@ static int hns_get_regs_len(struct net_device *net_dev) struct hns_nic_priv *priv = netdev_priv(net_dev); struct hnae_ae_ops *ops; - assert(priv || priv->ae_handle); - ops = priv->ae_handle->dev->ops; if (!ops->get_regs_len) { netdev_err(net_dev, "ops->get_regs_len is null!\n"); -- cgit v1.2.3 From 2ece068e1b1d6e76ecd07e04b027013e931287ff Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Fri, 20 May 2016 17:51:02 +0530 Subject: ptp: use memdup_user(). Use memdup_user to duplicate a memory region from user-space to kernel-space, instead of open coding using kmalloc & copy_from_user. Signed-off-by: Muhammad Falak R Wani Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/ptp/ptp_chardev.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 579fd65299a0..0b1ac6be69ce 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -208,14 +208,9 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) break; case PTP_SYS_OFFSET: - sysoff = kmalloc(sizeof(*sysoff), GFP_KERNEL); - if (!sysoff) { - err = -ENOMEM; - break; - } - if (copy_from_user(sysoff, (void __user *)arg, - sizeof(*sysoff))) { - err = -EFAULT; + sysoff = memdup_user((void __user *)arg, sizeof(*sysoff)); + if (IS_ERR(sysoff)) { + err = PTR_ERR(sysoff); break; } if (sysoff->n_samples > PTP_MAX_SAMPLES) { -- cgit v1.2.3 From 54b9430f04b0be3beb7f2711152c61e7d39c58e5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 23 May 2016 13:19:35 +0300 Subject: qed: signedness bug in qed_dcbx_process_tlv() "priority" needs to be signed for the error handling to work. Fixes: 39651abd2814 ('qed: add support for dcbx.') Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index cbf58e1f9333..a06d19a698b2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -192,9 +192,10 @@ qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, struct dcbx_app_priority_entry *p_tbl, u32 pri_tc_tbl, int count, bool dcbx_enabled) { - u8 tc, priority, priority_map; + u8 tc, priority_map; enum dcbx_protocol_type type; u16 protocol_id; + int priority; bool enable; int i; -- cgit v1.2.3 From 3275c0c6c522ab04afa14f80efdac6213c3883d6 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 23 May 2016 11:58:28 +1000 Subject: net/qlge: Avoids recursive EEH error One timer, whose handler keeps reading on MMIO register for EEH core to detect error in time, is started when the PCI device driver is loaded. MMIO register can't be accessed during PE reset in EEH recovery. Otherwise, the unexpected recursive error is triggered. The timer isn't closed that time if the interface isn't brought up. So the unexpected recursive error is seen during EEH recovery when the interface is down. This avoids the unexpected recursive EEH error by closing the timer in qlge_io_error_detected() before EEH PE reset unconditionally. The timer is started unconditionally after EEH PE reset in qlge_io_resume(). Also, the timer should be closed unconditionally when the device is removed from the system permanently in qlge_io_error_detected(). Reported-by: Shriya R. Kulkarni Signed-off-by: Gavin Shan Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlge/qlge_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 83d72106471c..fd5d1c93b55b 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -4846,7 +4846,6 @@ static void ql_eeh_close(struct net_device *ndev) } /* Disabling the timer */ - del_timer_sync(&qdev->timer); ql_cancel_all_work_sync(qdev); for (i = 0; i < qdev->rss_ring_count; i++) @@ -4873,6 +4872,7 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: netif_device_detach(ndev); + del_timer_sync(&qdev->timer); if (netif_running(ndev)) ql_eeh_close(ndev); pci_disable_device(pdev); @@ -4880,6 +4880,7 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev, case pci_channel_io_perm_failure: dev_err(&pdev->dev, "%s: pci_channel_io_perm_failure.\n", __func__); + del_timer_sync(&qdev->timer); ql_eeh_close(ndev); set_bit(QL_EEH_FATAL, &qdev->flags); return PCI_ERS_RESULT_DISCONNECT; -- cgit v1.2.3 From ab6a11a7c8ef47f996974dd3c648c2c0b1a36ab1 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Fri, 20 May 2016 17:33:03 -0500 Subject: crypto: ccp - Fix AES XTS error for request sizes above 4096 The ccp-crypto module for AES XTS support has a bug that can allow requests greater than 4096 bytes in size to be passed to the CCP hardware. The CCP hardware does not support request sizes larger than 4096, resulting in incorrect output. The request should actually be handled by the fallback mechanism instantiated by the ccp-crypto module. Add a check to insure the request size is less than or equal to the maximum supported size and use the fallback mechanism if it is not. Cc: # 3.14.x- Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-crypto-aes-xts.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-crypto-aes-xts.c b/drivers/crypto/ccp/ccp-crypto-aes-xts.c index 52c7395cb8d8..0d0d4529ee36 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c +++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c @@ -122,6 +122,7 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req, struct ccp_ctx *ctx = crypto_tfm_ctx(req->base.tfm); struct ccp_aes_req_ctx *rctx = ablkcipher_request_ctx(req); unsigned int unit; + u32 unit_size; int ret; if (!ctx->u.aes.key_len) @@ -133,11 +134,17 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req, if (!req->info) return -EINVAL; - for (unit = 0; unit < ARRAY_SIZE(unit_size_map); unit++) - if (!(req->nbytes & (unit_size_map[unit].size - 1))) - break; + unit_size = CCP_XTS_AES_UNIT_SIZE__LAST; + if (req->nbytes <= unit_size_map[0].size) { + for (unit = 0; unit < ARRAY_SIZE(unit_size_map); unit++) { + if (!(req->nbytes & (unit_size_map[unit].size - 1))) { + unit_size = unit_size_map[unit].value; + break; + } + } + } - if ((unit_size_map[unit].value == CCP_XTS_AES_UNIT_SIZE__LAST) || + if ((unit_size == CCP_XTS_AES_UNIT_SIZE__LAST) || (ctx->u.aes.key_len != AES_KEYSIZE_128)) { /* Use the fallback to process the request for any * unsupported unit sizes or key sizes @@ -158,7 +165,7 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req, rctx->cmd.engine = CCP_ENGINE_XTS_AES_128; rctx->cmd.u.xts.action = (encrypt) ? CCP_AES_ACTION_ENCRYPT : CCP_AES_ACTION_DECRYPT; - rctx->cmd.u.xts.unit_size = unit_size_map[unit].value; + rctx->cmd.u.xts.unit_size = unit_size; rctx->cmd.u.xts.key = &ctx->u.aes.key_sg; rctx->cmd.u.xts.key_len = ctx->u.aes.key_len; rctx->cmd.u.xts.iv = &rctx->iv_sg; -- cgit v1.2.3 From ec7c7f5cafdaeea509ad4e7e6f71c2312062c4c6 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Tue, 24 May 2016 05:25:23 -0400 Subject: qed: Reset the enable flag for eth protocol. This patch fixes the coding error in determining the enable flag for the application/protocol. The enable flag should be set for all protocols but the eth. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index a06d19a698b2..21ec1c2df2c7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -222,7 +222,7 @@ qed_dcbx_process_tlv(struct qed_hwfn *p_hwfn, * indication, but we only got here if there was an * app tlv for the protocol, so dcbx must be enabled. */ - enable = !!(type == DCBX_PROTOCOL_ETH); + enable = !(type == DCBX_PROTOCOL_ETH); qed_dcbx_update_app_info(p_data, p_hwfn, enable, true, priority, tc, type); -- cgit v1.2.3 From 91c45e38b9478ff507e05f10151d64cd0d1aad7b Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Tue, 24 May 2016 18:03:25 +0200 Subject: net: mvneta: Fix lacking spinlock initialization The spinlock used by the hwbm functions must be initialized by the network driver. This commit fixes this lack and the following erros when lockdep is enabled: INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0xb4/0xe0) [] (dump_stack) from [] (__lock_acquire+0x1f58/0x2060) [] (__lock_acquire) from [] (lock_acquire+0xa4/0xd0) [] (lock_acquire) from [] (_raw_spin_lock_irqsave+0x54/0x68) [] (_raw_spin_lock_irqsave) from [] (hwbm_pool_add+0x1c/0xdc) [] (hwbm_pool_add) from [] (mvneta_bm_pool_use+0x338/0x490) [] (mvneta_bm_pool_use) from [] (mvneta_probe+0x654/0x1284) [] (mvneta_probe) from [] (platform_drv_probe+0x4c/0xb0) [] (platform_drv_probe) from [] (driver_probe_device+0x214/0x2c0) [] (driver_probe_device) from [] (__driver_attach+0xc0/0xc4) [] (__driver_attach) from [] (bus_for_each_dev+0x68/0x9c) [] (bus_for_each_dev) from [] (bus_add_driver+0x1a0/0x218) [] (bus_add_driver) from [] (driver_register+0x78/0xf8) [] (driver_register) from [] (do_one_initcall+0x90/0x1dc) [] (do_one_initcall) from [] (kernel_init_freeable+0x15c/0x1fc) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) Fixes: baa11ebc0c76 ("net: mvneta: Use the new hwbm framework") Reported-by: Russell King Cc: Signed-off-by: Gregory CLEMENT Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta_bm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvneta_bm.c b/drivers/net/ethernet/marvell/mvneta_bm.c index 01fccec632ec..466939f8f0cf 100644 --- a/drivers/net/ethernet/marvell/mvneta_bm.c +++ b/drivers/net/ethernet/marvell/mvneta_bm.c @@ -189,6 +189,7 @@ struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id, SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); hwbm_pool->construct = mvneta_bm_construct; hwbm_pool->priv = new_pool; + spin_lock_init(&hwbm_pool->lock); /* Create new pool */ err = mvneta_bm_pool_create(priv, new_pool); -- cgit v1.2.3 From c0795bf64cba4d1b796fdc5b74b33772841ed1bb Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Tue, 24 May 2016 18:53:36 +0100 Subject: sfc: on MC reset, clear PIO buffer linkage in TXQs Otherwise, if we fail to allocate new PIO buffers, our TXQs will try to use the old ones, which aren't there any more. Fixes: 183233bec810 "sfc: Allocate and link PIO buffers; map them with write-combining" Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 1681084cc96f..1f309127457d 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -619,6 +619,17 @@ fail: return rc; } +static void efx_ef10_forget_old_piobufs(struct efx_nic *efx) +{ + struct efx_channel *channel; + struct efx_tx_queue *tx_queue; + + /* All our existing PIO buffers went away */ + efx_for_each_channel(channel, efx) + efx_for_each_channel_tx_queue(tx_queue, channel) + tx_queue->piobuf = NULL; +} + #else /* !EFX_USE_PIO */ static int efx_ef10_alloc_piobufs(struct efx_nic *efx, unsigned int n) @@ -635,6 +646,10 @@ static void efx_ef10_free_piobufs(struct efx_nic *efx) { } +static void efx_ef10_forget_old_piobufs(struct efx_nic *efx) +{ +} + #endif /* EFX_USE_PIO */ static void efx_ef10_remove(struct efx_nic *efx) @@ -1018,6 +1033,7 @@ static void efx_ef10_reset_mc_allocations(struct efx_nic *efx) nic_data->must_realloc_vis = true; nic_data->must_restore_filters = true; nic_data->must_restore_piobufs = true; + efx_ef10_forget_old_piobufs(efx); nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID; /* Driver-created vswitches and vports must be re-created */ -- cgit v1.2.3 From f6988cb63a4e698d8a62a1d085d263d1fcc351ea Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Wed, 25 May 2016 21:21:52 +0200 Subject: team: don't call netdev_change_features under team->lock The team_device_event() notifier calls team_compute_features() to fix vlan_features under team->lock to protect team->port_list. The problem is that subsequent __team_compute_features() calls netdev_change_features() to propagate vlan_features to upper vlan devices while team->lock is still taken. This can lead to deadlock when NETIF_F_LRO is modified on lower devices or team device itself. Example: The team0 as active backup with eth0 and eth1 NICs. Both eth0 & eth1 are LRO capable and LRO is enabled. Thus LRO is also enabled on team0. The command 'ethtool -K team0 lro off' now hangs due to this deadlock: dev_ethtool() -> ethtool_set_features() -> __netdev_update_features(team) -> netdev_sync_lower_features() -> netdev_update_features(lower_1) -> __netdev_update_features(lower_1) -> netdev_features_change(lower_1) -> call_netdevice_notifiers(...) -> team_device_event(lower_1) -> team_compute_features(team) [TAKES team->lock] -> netdev_change_features(team) -> __netdev_update_features(team) -> netdev_sync_lower_features() -> netdev_update_features(lower_2) -> __netdev_update_features(lower_2) -> netdev_features_change(lower_2) -> call_netdevice_notifiers(...) -> team_device_event(lower_2) -> team_compute_features(team) [DEADLOCK] The bug is present in team from the beginning but it appeared after the commit fd867d5 (net/core: generic support for disabling netdev features down stack) that adds synchronization of features with lower devices. Fixes: fd867d5 (net/core: generic support for disabling netdev features down stack) Cc: Jiri Pirko Signed-off-by: Ivan Vecera Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/team/team.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index a0f64cba86ba..2ace126533cd 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -990,7 +990,7 @@ static void team_port_disable(struct team *team, #define TEAM_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ NETIF_F_RXCSUM | NETIF_F_ALL_TSO) -static void __team_compute_features(struct team *team) +static void ___team_compute_features(struct team *team) { struct team_port *port; u32 vlan_features = TEAM_VLAN_FEATURES & NETIF_F_ALL_FOR_ALL; @@ -1021,15 +1021,20 @@ static void __team_compute_features(struct team *team) team->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; if (dst_release_flag == (IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM)) team->dev->priv_flags |= IFF_XMIT_DST_RELEASE; +} +static void __team_compute_features(struct team *team) +{ + ___team_compute_features(team); netdev_change_features(team->dev); } static void team_compute_features(struct team *team) { mutex_lock(&team->lock); - __team_compute_features(team); + ___team_compute_features(team); mutex_unlock(&team->lock); + netdev_change_features(team->dev); } static int team_port_enter(struct team *team, struct team_port *port) -- cgit v1.2.3 From 26c5f03b2ae8018418ceb25b2e6a48560e8c2f5b Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 25 May 2016 14:49:54 +0800 Subject: net: alx: use custom skb allocator This patch follows Eric Dumazet's commit 7b70176421 for Atheros atl1c driver to fix one exactly same bug in alx driver, that the network link will be lost in 1-5 minutes after the device is up. My laptop Lenovo Y580 with Atheros AR8161 ethernet device hit the same problem with kernel 4.4, and it will be cured by Jarod Wilson's commit c406700c for alx driver which get merged in 4.5. But there are still some alx devices can't function well even with Jarod's patch, while this patch could make them work fine. More details on https://bugzilla.kernel.org/show_bug.cgi?id=70761 The debug shows the issue is very likely to be related with the RX DMA address, specifically 0x...f80, if RX buffer get 0x...f80 several times, their will be RX overflow error and device will stop working. For kernel 4.5.0 with Jarod's patch which works fine with my AR8161/Lennov Y580, if I made some change to the __netdev_alloc_skb --> __alloc_page_frag() to make the allocated buffer can get an address with 0x...f80, then the same error happens. If I make it to 0x...f40 or 0x....fc0, everything will be still fine. So I tend to believe that the 0x..f80 address cause the silicon to behave abnormally. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=70761 Cc: Eric Dumazet Cc: Johannes Berg Cc: Jarod Wilson Signed-off-by: Feng Tang Tested-by: Ole Lukoie Signed-off-by: David S. Miller --- drivers/net/ethernet/atheros/alx/alx.h | 4 +++ drivers/net/ethernet/atheros/alx/main.c | 48 ++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h index 8fc93c5f6abc..d02c4240b7df 100644 --- a/drivers/net/ethernet/atheros/alx/alx.h +++ b/drivers/net/ethernet/atheros/alx/alx.h @@ -96,6 +96,10 @@ struct alx_priv { unsigned int rx_ringsz; unsigned int rxbuf_size; + struct page *rx_page; + unsigned int rx_page_offset; + unsigned int rx_frag_size; + struct napi_struct napi; struct alx_tx_queue txq; struct alx_rx_queue rxq; diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index 9fe8b5e310d1..c98acdc0d14f 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -70,6 +70,35 @@ static void alx_free_txbuf(struct alx_priv *alx, int entry) } } +static struct sk_buff *alx_alloc_skb(struct alx_priv *alx, gfp_t gfp) +{ + struct sk_buff *skb; + struct page *page; + + if (alx->rx_frag_size > PAGE_SIZE) + return __netdev_alloc_skb(alx->dev, alx->rxbuf_size, gfp); + + page = alx->rx_page; + if (!page) { + alx->rx_page = page = alloc_page(gfp); + if (unlikely(!page)) + return NULL; + alx->rx_page_offset = 0; + } + + skb = build_skb(page_address(page) + alx->rx_page_offset, + alx->rx_frag_size); + if (likely(skb)) { + alx->rx_page_offset += alx->rx_frag_size; + if (alx->rx_page_offset >= PAGE_SIZE) + alx->rx_page = NULL; + else + get_page(page); + } + return skb; +} + + static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) { struct alx_rx_queue *rxq = &alx->rxq; @@ -86,7 +115,7 @@ static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) while (!cur_buf->skb && next != rxq->read_idx) { struct alx_rfd *rfd = &rxq->rfd[cur]; - skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size, gfp); + skb = alx_alloc_skb(alx, gfp); if (!skb) break; dma = dma_map_single(&alx->hw.pdev->dev, @@ -124,6 +153,7 @@ static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur); } + return count; } @@ -592,6 +622,11 @@ static void alx_free_rings(struct alx_priv *alx) kfree(alx->txq.bufs); kfree(alx->rxq.bufs); + if (alx->rx_page) { + put_page(alx->rx_page); + alx->rx_page = NULL; + } + dma_free_coherent(&alx->hw.pdev->dev, alx->descmem.size, alx->descmem.virt, @@ -646,6 +681,7 @@ static int alx_request_irq(struct alx_priv *alx) alx->dev->name, alx); if (!err) goto out; + /* fall back to legacy interrupt */ pci_disable_msi(alx->hw.pdev); } @@ -689,6 +725,7 @@ static int alx_init_sw(struct alx_priv *alx) struct pci_dev *pdev = alx->hw.pdev; struct alx_hw *hw = &alx->hw; int err; + unsigned int head_size; err = alx_identify_hw(alx); if (err) { @@ -704,7 +741,12 @@ static int alx_init_sw(struct alx_priv *alx) hw->smb_timer = 400; hw->mtu = alx->dev->mtu; + alx->rxbuf_size = ALX_MAX_FRAME_LEN(hw->mtu); + head_size = SKB_DATA_ALIGN(alx->rxbuf_size + NET_SKB_PAD) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + alx->rx_frag_size = roundup_pow_of_two(head_size); + alx->tx_ringsz = 256; alx->rx_ringsz = 512; hw->imt = 200; @@ -806,6 +848,7 @@ static int alx_change_mtu(struct net_device *netdev, int mtu) { struct alx_priv *alx = netdev_priv(netdev); int max_frame = ALX_MAX_FRAME_LEN(mtu); + unsigned int head_size; if ((max_frame < ALX_MIN_FRAME_SIZE) || (max_frame > ALX_MAX_FRAME_SIZE)) @@ -817,6 +860,9 @@ static int alx_change_mtu(struct net_device *netdev, int mtu) netdev->mtu = mtu; alx->hw.mtu = mtu; alx->rxbuf_size = max(max_frame, ALX_DEF_RXBUF_SIZE); + head_size = SKB_DATA_ALIGN(alx->rxbuf_size + NET_SKB_PAD) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + alx->rx_frag_size = roundup_pow_of_two(head_size); netdev_update_features(netdev); if (netif_running(netdev)) alx_reinit(alx); -- cgit v1.2.3 From 643d60bf575daaba93c1ac0d0e1c4b1d4ded1f75 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 26 May 2016 00:40:23 +0200 Subject: net: stmmac: Fix incorrect memcpy source memory The memcpy() currently copies mdio_bus_data into new_bus->irq, which makes no sense, since the mdio_bus_data structure contains more than just irqs. The code was likely supposed to copy mdio_bus_data->irqs into the new_bus->irq instead, so fix this. Fixes: e7f4dc3536a4 ("mdio: Move allocation of interrupts into core") Signed-off-by: Marek Vasut Cc: David S. Miller Cc: Giuseppe Cavallaro Cc: Alexandre Torgue Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 3f83c369f56c..ec295851812b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -297,7 +297,7 @@ int stmmac_mdio_register(struct net_device *ndev) return -ENOMEM; if (mdio_bus_data->irqs) - memcpy(new_bus->irq, mdio_bus_data, sizeof(new_bus->irq)); + memcpy(new_bus->irq, mdio_bus_data->irqs, sizeof(new_bus->irq)); #ifdef CONFIG_OF if (priv->device->of_node) -- cgit v1.2.3 From 3424d9be8f09649e6290d066c5c3cccff1c0ce77 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 26 May 2016 00:40:05 +0200 Subject: net: arc: trivial: Replace comma with a semicolon Fix a typo in the driver, replace comma with a semicolon at the end of statement. While using comma is a legal C here and probably does not even generate compiler warning, it was unlikely the intention. Signed-off-by: Marek Vasut Cc: David S. Miller Cc: Caesar Wang Cc: Heiko Stuebner Signed-off-by: David S. Miller --- drivers/net/ethernet/arc/emac_mdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/arc/emac_mdio.c b/drivers/net/ethernet/arc/emac_mdio.c index 16419f550eff..058460bdd5a6 100644 --- a/drivers/net/ethernet/arc/emac_mdio.c +++ b/drivers/net/ethernet/arc/emac_mdio.c @@ -141,7 +141,7 @@ int arc_mdio_probe(struct arc_emac_priv *priv) priv->bus = bus; bus->priv = priv; bus->parent = priv->dev; - bus->name = "Synopsys MII Bus", + bus->name = "Synopsys MII Bus"; bus->read = &arc_mdio_read; bus->write = &arc_mdio_write; bus->reset = &arc_mdio_reset; -- cgit v1.2.3 From 63a664b7e92b14aaa1e1c3e9ae362aa70cf4cefb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 25 May 2016 09:50:36 -0700 Subject: net/mlx4_en: fix tx_dropped bug 1) mlx4_en_xmit() can increment priv->stats.tx_dropped, but this variable is overwritten in mlx4_en_DUMP_ETH_STATS(). 2) This increment was not SMP safe, as a port might have many TX queues. Add a per TX ring tx_dropped to fix these issues. This is u32 as mlx4_en_DUMP_ETH_STATS() will add a 32bit field. So lets avoid bugs with SNMP agents having to cope with partial overwraps. (One of these agents being bond_fold_stats()) Signed-off-by: Eric Dumazet Reported-by: Willem de Bruijn Cc: Eugenia Emantayev Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 1 + drivers/net/ethernet/mellanox/mlx4/en_port.c | 4 +++- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 8 ++++---- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 + 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 92e0624f4cf0..cfd50206f7c3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1892,6 +1892,7 @@ static void mlx4_en_clear_stats(struct net_device *dev) priv->tx_ring[i]->bytes = 0; priv->tx_ring[i]->packets = 0; priv->tx_ring[i]->tx_csum = 0; + priv->tx_ring[i]->tx_dropped = 0; } for (i = 0; i < priv->rx_ring_num; i++) { priv->rx_ring[i]->bytes = 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c index 20b6c2e678b8..3df8690154b1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_port.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c @@ -188,6 +188,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) } stats->tx_packets = 0; stats->tx_bytes = 0; + stats->tx_dropped = 0; priv->port_stats.tx_chksum_offload = 0; priv->port_stats.queue_stopped = 0; priv->port_stats.wake_queue = 0; @@ -199,6 +200,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) stats->tx_packets += ring->packets; stats->tx_bytes += ring->bytes; + stats->tx_dropped += ring->tx_dropped; priv->port_stats.tx_chksum_offload += ring->tx_csum; priv->port_stats.queue_stopped += ring->queue_stopped; priv->port_stats.wake_queue += ring->wake_queue; @@ -251,7 +253,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) stats->tx_fifo_errors = 0; stats->tx_heartbeat_errors = 0; stats->tx_window_errors = 0; - stats->tx_dropped = be32_to_cpu(mlx4_en_stats->TDROP); + stats->tx_dropped += be32_to_cpu(mlx4_en_stats->TDROP); /* RX stats */ priv->pkstats.rx_multicast_packets = stats->multicast; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index f6e61570cb2c..76aa4d27183c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -726,12 +726,12 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) bool inline_ok; u32 ring_cons; - if (!priv->port_up) - goto tx_drop; - tx_ind = skb_get_queue_mapping(skb); ring = priv->tx_ring[tx_ind]; + if (!priv->port_up) + goto tx_drop; + /* fetch ring->cons far ahead before needing it to avoid stall */ ring_cons = ACCESS_ONCE(ring->cons); @@ -1030,7 +1030,7 @@ tx_drop_unmap: tx_drop: dev_kfree_skb_any(skb); - priv->stats.tx_dropped++; + ring->tx_dropped++; return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index cc84e09f324a..9a9124031fc7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -270,6 +270,7 @@ struct mlx4_en_tx_ring { unsigned long tx_csum; unsigned long tso_packets; unsigned long xmit_more; + unsigned int tx_dropped; struct mlx4_bf bf; unsigned long queue_stopped; -- cgit v1.2.3 From 45acbac609e73991dd9c3c9b7ffd03ddb8c939ef Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 25 May 2016 09:50:37 -0700 Subject: net/mlx4_en: clear some TX ring stats in mlx4_en_clear_stats() mlx4_en_clear_stats() clears about everything but few TX ring fields are missing : - queue_stopped, wake_queue, tso_packets, xmit_more Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Cc: Eugenia Emantayev Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index cfd50206f7c3..bd637c4eff13 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1893,6 +1893,10 @@ static void mlx4_en_clear_stats(struct net_device *dev) priv->tx_ring[i]->packets = 0; priv->tx_ring[i]->tx_csum = 0; priv->tx_ring[i]->tx_dropped = 0; + priv->tx_ring[i]->queue_stopped = 0; + priv->tx_ring[i]->wake_queue = 0; + priv->tx_ring[i]->tso_packets = 0; + priv->tx_ring[i]->xmit_more = 0; } for (i = 0; i < priv->rx_ring_num; i++) { priv->rx_ring[i]->bytes = 0; -- cgit v1.2.3 From 9ed17db17fb01a7be5b84558b768c091bdf8bb41 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 25 May 2016 09:50:38 -0700 Subject: net/mlx4_en: get rid of ret_stats mlx4 uses a private struct net_device_stats in a vain attempt to avoid races. This is buggy because multiple cpus could call mlx4_en_get_stats() at the same time, so ret_stats can not guarantee stable results. To fix this, we need to switch to ndo_get_stats64() as this method provides per-thread storage. This allows to reduce mlx4_en_priv bloat. Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Cc: Eugenia Emantayev Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 11 ++++++----- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index bd637c4eff13..a4fc6e966505 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1296,15 +1296,16 @@ static void mlx4_en_tx_timeout(struct net_device *dev) } -static struct net_device_stats *mlx4_en_get_stats(struct net_device *dev) +static struct rtnl_link_stats64 * +mlx4_en_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { struct mlx4_en_priv *priv = netdev_priv(dev); spin_lock_bh(&priv->stats_lock); - memcpy(&priv->ret_stats, &priv->stats, sizeof(priv->stats)); + netdev_stats_to_stats64(stats, &priv->stats); spin_unlock_bh(&priv->stats_lock); - return &priv->ret_stats; + return stats; } static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) @@ -2487,7 +2488,7 @@ static const struct net_device_ops mlx4_netdev_ops = { .ndo_stop = mlx4_en_close, .ndo_start_xmit = mlx4_en_xmit, .ndo_select_queue = mlx4_en_select_queue, - .ndo_get_stats = mlx4_en_get_stats, + .ndo_get_stats64 = mlx4_en_get_stats64, .ndo_set_rx_mode = mlx4_en_set_rx_mode, .ndo_set_mac_address = mlx4_en_set_mac, .ndo_validate_addr = eth_validate_addr, @@ -2519,7 +2520,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = { .ndo_stop = mlx4_en_close, .ndo_start_xmit = mlx4_en_xmit, .ndo_select_queue = mlx4_en_select_queue, - .ndo_get_stats = mlx4_en_get_stats, + .ndo_get_stats64 = mlx4_en_get_stats64, .ndo_set_rx_mode = mlx4_en_set_rx_mode, .ndo_set_mac_address = mlx4_en_set_mac, .ndo_validate_addr = eth_validate_addr, diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 9a9124031fc7..bfda84df8aae 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -484,7 +484,6 @@ struct mlx4_en_priv { struct net_device *dev; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; struct net_device_stats stats; - struct net_device_stats ret_stats; struct mlx4_en_port_state port_state; spinlock_t stats_lock; struct ethtool_flow_id ethtool_rules[MAX_NUM_OF_FS_RULES]; -- cgit v1.2.3 From f73a6f439fca0e14f228726e5647d5afe141bc32 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 25 May 2016 09:50:39 -0700 Subject: net/mlx4_en: get rid of private net_device_stats We simply can use the standard net_device stats. We do not need to clear fields that are already 0. Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Cc: Eugenia Emantayev Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 3 +-- drivers/net/ethernet/mellanox/mlx4/en_port.c | 14 +++----------- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 - 4 files changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index c761194bb323..fc95affaf76b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -362,7 +362,7 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev, for (i = 0; i < NUM_MAIN_STATS; i++, bitmap_iterator_inc(&it)) if (bitmap_iterator_test(&it)) - data[index++] = ((unsigned long *)&priv->stats)[i]; + data[index++] = ((unsigned long *)&dev->stats)[i]; for (i = 0; i < NUM_PORT_STATS; i++, bitmap_iterator_inc(&it)) if (bitmap_iterator_test(&it)) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index a4fc6e966505..19ceced6736c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1302,7 +1302,7 @@ mlx4_en_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) struct mlx4_en_priv *priv = netdev_priv(dev); spin_lock_bh(&priv->stats_lock); - netdev_stats_to_stats64(stats, &priv->stats); + netdev_stats_to_stats64(stats, &dev->stats); spin_unlock_bh(&priv->stats_lock); return stats; @@ -1877,7 +1877,6 @@ static void mlx4_en_clear_stats(struct net_device *dev) if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) en_dbg(HW, priv, "Failed dumping statistics\n"); - memset(&priv->stats, 0, sizeof(priv->stats)); memset(&priv->pstats, 0, sizeof(priv->pstats)); memset(&priv->pkstats, 0, sizeof(priv->pkstats)); memset(&priv->port_stats, 0, sizeof(priv->port_stats)); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c index 3df8690154b1..5aa8b751f417 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_port.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c @@ -152,8 +152,9 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) struct mlx4_counter tmp_counter_stats; struct mlx4_en_stat_out_mbox *mlx4_en_stats; struct mlx4_en_stat_out_flow_control_mbox *flowstats; - struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]); - struct net_device_stats *stats = &priv->stats; + struct net_device *dev = mdev->pndev[port]; + struct mlx4_en_priv *priv = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; struct mlx4_cmd_mailbox *mailbox; u64 in_mod = reset << 8 | port; int err; @@ -239,20 +240,11 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) stats->multicast = en_stats_adder(&mlx4_en_stats->MCAST_prio_0, &mlx4_en_stats->MCAST_prio_1, NUM_PRIORITIES); - stats->collisions = 0; stats->rx_dropped = be32_to_cpu(mlx4_en_stats->RDROP) + sw_rx_dropped; stats->rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength); - stats->rx_over_errors = 0; stats->rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC); - stats->rx_frame_errors = 0; stats->rx_fifo_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw); - stats->rx_missed_errors = 0; - stats->tx_aborted_errors = 0; - stats->tx_carrier_errors = 0; - stats->tx_fifo_errors = 0; - stats->tx_heartbeat_errors = 0; - stats->tx_window_errors = 0; stats->tx_dropped += be32_to_cpu(mlx4_en_stats->TDROP); /* RX stats */ diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index bfda84df8aae..467d47ed2c39 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -483,7 +483,6 @@ struct mlx4_en_priv { struct mlx4_en_port_profile *prof; struct net_device *dev; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; - struct net_device_stats stats; struct mlx4_en_port_state port_state; spinlock_t stats_lock; struct ethtool_flow_id ethtool_rules[MAX_NUM_OF_FS_RULES]; -- cgit v1.2.3 From be7b6d64c0f2f31ea03746edaabb22f57234cb49 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 26 May 2016 11:01:17 +0300 Subject: qede: Fix VF minimum BW setting VF is currently ignoring the minimum provided by the API, mistakenly using the maximum for minimum as well. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 337e839ca586..3bb1428e81b7 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1824,7 +1824,7 @@ static int qede_set_vf_rate(struct net_device *dev, int vfidx, { struct qede_dev *edev = netdev_priv(dev); - return edev->ops->iov->set_rate(edev->cdev, vfidx, max_tx_rate, + return edev->ops->iov->set_rate(edev->cdev, vfidx, min_tx_rate, max_tx_rate); } -- cgit v1.2.3 From ce2b885cc5014d1cbcbe519c45f00f6a59e5ab70 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 26 May 2016 11:01:18 +0300 Subject: qede: Reload on GRO changes Since driver is using a FW-based GRO implementation, this has some effects on its ability to cope with GRO enablement/disablement. As a result, driver must perform an inner-reload as a result of a state change in the offload configuration of said feature. [Failure to do so means network stack would continue to receive aggregated packets even though user requested the feature to be disabled]. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_main.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 3bb1428e81b7..5d00d1404bfc 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -2091,6 +2091,29 @@ static void qede_vlan_mark_nonconfigured(struct qede_dev *edev) edev->accept_any_vlan = false; } +int qede_set_features(struct net_device *dev, netdev_features_t features) +{ + struct qede_dev *edev = netdev_priv(dev); + netdev_features_t changes = features ^ dev->features; + bool need_reload = false; + + /* No action needed if hardware GRO is disabled during driver load */ + if (changes & NETIF_F_GRO) { + if (dev->features & NETIF_F_GRO) + need_reload = !edev->gro_disable; + else + need_reload = edev->gro_disable; + } + + if (need_reload && netif_running(edev->ndev)) { + dev->features = features; + qede_reload(edev, NULL, NULL); + return 1; + } + + return 0; +} + #ifdef CONFIG_QEDE_VXLAN static void qede_add_vxlan_port(struct net_device *dev, sa_family_t sa_family, __be16 port) @@ -2175,6 +2198,7 @@ static const struct net_device_ops qede_netdev_ops = { #endif .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, + .ndo_set_features = qede_set_features, .ndo_get_stats64 = qede_get_stats64, #ifdef CONFIG_QED_SRIOV .ndo_set_vf_link_state = qede_set_vf_link_state, -- cgit v1.2.3 From 6ecb0a0c0d9539fac1497d1d218e60a393a1070c Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 26 May 2016 11:01:19 +0300 Subject: qede: Don't expose self-test for VFs PFs and VFs differ in their registered ethtool operations, but they're using a common function for get_sset_count(). As a result, `ethtool -i' for a VF would indicate it supports selftest, although that's not the case. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 1bc75358cbc4..ad3cae3b7243 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -230,7 +230,10 @@ static int qede_get_sset_count(struct net_device *dev, int stringset) case ETH_SS_PRIV_FLAGS: return QEDE_PRI_FLAG_LEN; case ETH_SS_TEST: - return QEDE_ETHTOOL_TEST_MAX; + if (!IS_VF(edev)) + return QEDE_ETHTOOL_TEST_MAX; + else + return 0; default: DP_VERBOSE(edev, QED_MSG_DEBUG, "Unsupported stringset 0x%08x\n", stringset); -- cgit v1.2.3 From 795292916cf9d8c47c53b692bcb36b02953101cf Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Thu, 26 May 2016 11:01:20 +0300 Subject: qed: Fix allocation in interrupt context Commit 39651abd2814 ("qed: add support for dcbx") is re-configuring the QM hw-block as part of its sequence. This is done in attention handling context which is non-sleepable, yet memory is allocated in this flow using GFP_KERNEL. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 089016f46f26..7aeed2fa2b18 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -155,7 +155,7 @@ void qed_resc_free(struct qed_dev *cdev) } } -static int qed_init_qm_info(struct qed_hwfn *p_hwfn) +static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable) { u8 num_vports, vf_offset = 0, i, vport_id, num_ports, curr_queue = 0; struct qed_qm_info *qm_info = &p_hwfn->qm_info; @@ -182,23 +182,28 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn) /* PQs will be arranged as follows: First per-TC PQ then pure-LB quete. */ - qm_info->qm_pq_params = kzalloc(sizeof(*qm_info->qm_pq_params) * - num_pqs, GFP_KERNEL); + qm_info->qm_pq_params = kcalloc(num_pqs, + sizeof(struct init_qm_pq_params), + b_sleepable ? GFP_KERNEL : GFP_ATOMIC); if (!qm_info->qm_pq_params) goto alloc_err; - qm_info->qm_vport_params = kzalloc(sizeof(*qm_info->qm_vport_params) * - num_vports, GFP_KERNEL); + qm_info->qm_vport_params = kcalloc(num_vports, + sizeof(struct init_qm_vport_params), + b_sleepable ? GFP_KERNEL + : GFP_ATOMIC); if (!qm_info->qm_vport_params) goto alloc_err; - qm_info->qm_port_params = kzalloc(sizeof(*qm_info->qm_port_params) * - MAX_NUM_PORTS, GFP_KERNEL); + qm_info->qm_port_params = kcalloc(MAX_NUM_PORTS, + sizeof(struct init_qm_port_params), + b_sleepable ? GFP_KERNEL + : GFP_ATOMIC); if (!qm_info->qm_port_params) goto alloc_err; - qm_info->wfq_data = kcalloc(num_vports, sizeof(*qm_info->wfq_data), - GFP_KERNEL); + qm_info->wfq_data = kcalloc(num_vports, sizeof(struct qed_wfq_data), + b_sleepable ? GFP_KERNEL : GFP_ATOMIC); if (!qm_info->wfq_data) goto alloc_err; @@ -299,7 +304,7 @@ int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) qed_qm_info_free(p_hwfn); /* initialize qed's qm data structure */ - rc = qed_init_qm_info(p_hwfn); + rc = qed_init_qm_info(p_hwfn, false); if (rc) return rc; @@ -388,7 +393,7 @@ int qed_resc_alloc(struct qed_dev *cdev) goto alloc_err; /* Prepare and process QM requirements */ - rc = qed_init_qm_info(p_hwfn); + rc = qed_init_qm_info(p_hwfn, true); if (rc) goto alloc_err; -- cgit v1.2.3 From cc3d5eb09111a471f942c76e9610ee962e1d4c31 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 26 May 2016 11:01:21 +0300 Subject: qed: Save min/max accross dcbx-change When DCBx re-negotiation is occurring, the PF's configurations for maximum and minimum bandwidth guarantees are currently lost. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 7aeed2fa2b18..920eadd6417c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -161,6 +161,8 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable) struct qed_qm_info *qm_info = &p_hwfn->qm_info; struct init_qm_port_params *p_qm_port; u16 num_pqs, multi_cos_tcs = 1; + u8 pf_wfq = qm_info->pf_wfq; + u32 pf_rl = qm_info->pf_rl; u16 num_vfs = 0; #ifdef CONFIG_QED_SRIOV @@ -269,10 +271,10 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn, bool b_sleepable) for (i = 0; i < qm_info->num_vports; i++) qm_info->qm_vport_params[i].vport_wfq = 1; - qm_info->pf_wfq = 0; - qm_info->pf_rl = 0; qm_info->vport_rl_en = 1; qm_info->vport_wfq_en = 1; + qm_info->pf_rl = pf_rl; + qm_info->pf_wfq = pf_wfq; return 0; -- cgit v1.2.3 From 1af9dcf7f90e6b75b7c42eaaf19cdd5da1354784 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 26 May 2016 11:01:22 +0300 Subject: qed: Add missing 100g init mode Some of the HW configurations are currently missing for 100g devices. This can cause various classification issues, as well as prevent device from fully reaching line-rate. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 920eadd6417c..2a7c8755eda0 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -588,7 +588,14 @@ static void qed_calc_hw_mode(struct qed_hwfn *p_hwfn) hw_mode |= 1 << MODE_ASIC; + if (p_hwfn->cdev->num_hwfns > 1) + hw_mode |= 1 << MODE_100G; + p_hwfn->hw_info.hw_mode = hw_mode; + + DP_VERBOSE(p_hwfn, (NETIF_MSG_PROBE | NETIF_MSG_IFUP), + "Configuring function for hw_mode: 0x%08x\n", + p_hwfn->hw_info.hw_mode); } /* Init run time data for all PFs on an engine. */ -- cgit v1.2.3 From bb13ace7dca5d2385847e43511acf5777da35c0e Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Thu, 26 May 2016 11:01:23 +0300 Subject: qed: Prevent 100g from working in MSI Adapter can support 100g in both MSIx and INTa, but not in MSI. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 5 +++++ drivers/net/ethernet/qlogic/qed/qed_main.c | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 2a7c8755eda0..579c6d500865 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -835,6 +835,11 @@ int qed_hw_init(struct qed_dev *cdev, u32 load_code, param; int rc, mfw_rc, i; + if ((int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { + DP_NOTICE(cdev, "MSI mode is not supported for CMT devices\n"); + return -EINVAL; + } + if (IS_PF(cdev)) { rc = qed_init_fw_data(cdev, bin_fw_data); if (rc != 0) diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 8b22f87033ce..753064679bde 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -413,15 +413,17 @@ static int qed_set_int_mode(struct qed_dev *cdev, bool force_mode) /* Fallthrough */ case QED_INT_MODE_MSI: - rc = pci_enable_msi(cdev->pdev); - if (!rc) { - int_params->out.int_mode = QED_INT_MODE_MSI; - goto out; - } + if (cdev->num_hwfns == 1) { + rc = pci_enable_msi(cdev->pdev); + if (!rc) { + int_params->out.int_mode = QED_INT_MODE_MSI; + goto out; + } - DP_NOTICE(cdev, "Failed to enable MSI\n"); - if (force_mode) - goto out; + DP_NOTICE(cdev, "Failed to enable MSI\n"); + if (force_mode) + goto out; + } /* Fallthrough */ case QED_INT_MODE_INTA: -- cgit v1.2.3 From 3e7cfce228c6c67dd31e09175eaca55fee0c7082 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 26 May 2016 11:01:24 +0300 Subject: qed: Don't config min BW on 100g on link flap Currently 100g devices don't support minimum/maximum BW configurations, yet link flaps might cause the driver to attempt to do such a configuration. Prevent this just as we do for the maximum BW. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 579c6d500865..2d89e8c16b32 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -2105,6 +2105,13 @@ void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev, u32 min_pf_rate) { int i; + if (cdev->num_hwfns > 1) { + DP_VERBOSE(cdev, + NETIF_MSG_LINK, + "WFQ configuration is not supported for this device\n"); + return; + } + for_each_hwfn(cdev, i) { struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; -- cgit v1.2.3 From 94abd778a7bb00ed5d00f56d9fbfcbf5b7c02a5c Mon Sep 17 00:00:00 2001 From: Jaap Jan Meijer Date: Thu, 12 May 2016 18:25:08 +0200 Subject: brcmfmac: add fallback for devices that do not report per-chain values If brcmf_cfg80211_get_station fails to determine the RSSI from the per-chain values get the value individually as a fallback. Fixes: 1f0dc59a6de9 ("brcmfmac: rework .get_station() callback") Signed-off-by: Jaap Jan Meijer Acked-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index d0631b6cfd53..62f475e31077 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2540,12 +2540,14 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) { struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_scb_val_le scb_val; s32 err = 0; struct brcmf_sta_info_le sta_info_le; u32 sta_flags; u32 is_tdls_peer; s32 total_rssi; s32 count_rssi; + int rssi; u32 i; brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac); @@ -2629,6 +2631,20 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); total_rssi /= count_rssi; sinfo->signal = total_rssi; + } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED, + &ifp->vif->sme_state)) { + memset(&scb_val, 0, sizeof(scb_val)); + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_RSSI, + &scb_val, sizeof(scb_val)); + if (err) { + brcmf_err("Could not get rssi (%d)\n", err); + goto done; + } else { + rssi = le32_to_cpu(scb_val.val); + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + sinfo->signal = rssi; + brcmf_dbg(CONN, "RSSI %d dBm\n", rssi); + } } } done: -- cgit v1.2.3 From de26859dcf363d520cc44e59f6dcaf20ebe0aadf Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 21 May 2016 11:50:35 -0500 Subject: rtlwifi: Fix scheduling while atomic error from commit 49f86ec21c01 Commit 49f86ec21c01 ("rtlwifi: Change long delays to sleeps") was correct for most cases; however, driver rtl8192ce calls the affected routines while in atomic context. The kernel bug output is as follows: BUG: scheduling while atomic: wpa_supplicant/627/0x00000002 [...] [] __schedule+0x899/0xad0 [] schedule+0x3c/0x90 [] schedule_hrtimeout_range_clock+0xa2/0x120 [] ? hrtimer_init+0x120/0x120 [] ? schedule_hrtimeout_range_clock+0x96/0x120 [] schedule_hrtimeout_range+0x13/0x20 [] usleep_range+0x4f/0x70 [] rtl_rfreg_delay+0x38/0x50 [rtlwifi] [] rtl92c_phy_config_rf_with_headerfile+0xc7/0xe0 [rtl8192ce] To fix this bug, three of the changes from delay to sleep are reverted. Unfortunately, one of the changes involves a delay of 50 msec. The calling code will be modified so that this long delay can be avoided; however, this change is being pushed now to fix the problem in kernel 4.6.0. Fixes: 49f86ec21c01 ("rtlwifi: Change long delays to sleeps") Reported-by: James Feeney Signed-off-by: Larry Finger Cc: James Feeney Cc: Stable [4.6+] Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 0f48048b8654..3a0faa8fe9d4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -54,7 +54,7 @@ EXPORT_SYMBOL(channel5g_80m); void rtl_addr_delay(u32 addr) { if (addr == 0xfe) - msleep(50); + mdelay(50); else if (addr == 0xfd) msleep(5); else if (addr == 0xfc) @@ -75,7 +75,7 @@ void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr, rtl_addr_delay(addr); } else { rtl_set_rfreg(hw, rfpath, addr, mask, data); - usleep_range(1, 2); + udelay(1); } } EXPORT_SYMBOL(rtl_rfreg_delay); @@ -86,7 +86,7 @@ void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data) rtl_addr_delay(addr); } else { rtl_set_bbreg(hw, addr, MASKDWORD, data); - usleep_range(1, 2); + udelay(1); } } EXPORT_SYMBOL(rtl_bb_delay); -- cgit v1.2.3 From d43a41152f8e9e4c0d19850884d1fada076dee10 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Tue, 19 Apr 2016 11:18:33 +0200 Subject: iio:st_pressure: fix sampling gains (bring inline with ABI) Temperature channels report scaled samples in Celsius although expected as milli degree Celsius in Documentation/ABI/testing/sysfs-bus-iio. Gains are not implemented at all for LPS001WP pressure and temperature channels. This patch ensures that proper offsets and scales are exposed to userpace for both pressure and temperature channels. Also fix a NULL pointer exception when userspace reads content of sysfs scale attribute when gains are not defined. Signed-off-by: Gregor Boirie Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/st_pressure_core.c | 80 ++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 9e9b72a8f18f..257b58ac6779 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -28,15 +28,21 @@ #include #include "st_pressure.h" +#define MCELSIUS_PER_CELSIUS 1000 + +/* Default pressure sensitivity */ #define ST_PRESS_LSB_PER_MBAR 4096UL #define ST_PRESS_KPASCAL_NANO_SCALE (100000000UL / \ ST_PRESS_LSB_PER_MBAR) + +/* Default temperature sensitivity */ #define ST_PRESS_LSB_PER_CELSIUS 480UL -#define ST_PRESS_CELSIUS_NANO_SCALE (1000000000UL / \ - ST_PRESS_LSB_PER_CELSIUS) +#define ST_PRESS_MILLI_CELSIUS_OFFSET 42500UL + #define ST_PRESS_NUMBER_DATA_CHANNELS 1 /* FULLSCALE */ +#define ST_PRESS_FS_AVL_1100MB 1100 #define ST_PRESS_FS_AVL_1260MB 1260 #define ST_PRESS_1_OUT_XL_ADDR 0x28 @@ -54,9 +60,6 @@ #define ST_PRESS_LPS331AP_PW_MASK 0x80 #define ST_PRESS_LPS331AP_FS_ADDR 0x23 #define ST_PRESS_LPS331AP_FS_MASK 0x30 -#define ST_PRESS_LPS331AP_FS_AVL_1260_VAL 0x00 -#define ST_PRESS_LPS331AP_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE -#define ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE #define ST_PRESS_LPS331AP_BDU_ADDR 0x20 #define ST_PRESS_LPS331AP_BDU_MASK 0x04 #define ST_PRESS_LPS331AP_DRDY_IRQ_ADDR 0x22 @@ -67,9 +70,14 @@ #define ST_PRESS_LPS331AP_OD_IRQ_ADDR 0x22 #define ST_PRESS_LPS331AP_OD_IRQ_MASK 0x40 #define ST_PRESS_LPS331AP_MULTIREAD_BIT true -#define ST_PRESS_LPS331AP_TEMP_OFFSET 42500 /* CUSTOM VALUES FOR LPS001WP SENSOR */ + +/* LPS001WP pressure resolution */ +#define ST_PRESS_LPS001WP_LSB_PER_MBAR 16UL +/* LPS001WP temperature resolution */ +#define ST_PRESS_LPS001WP_LSB_PER_CELSIUS 64UL + #define ST_PRESS_LPS001WP_WAI_EXP 0xba #define ST_PRESS_LPS001WP_ODR_ADDR 0x20 #define ST_PRESS_LPS001WP_ODR_MASK 0x30 @@ -78,6 +86,8 @@ #define ST_PRESS_LPS001WP_ODR_AVL_13HZ_VAL 0x03 #define ST_PRESS_LPS001WP_PW_ADDR 0x20 #define ST_PRESS_LPS001WP_PW_MASK 0x40 +#define ST_PRESS_LPS001WP_FS_AVL_PRESS_GAIN \ + (100000000UL / ST_PRESS_LPS001WP_LSB_PER_MBAR) #define ST_PRESS_LPS001WP_BDU_ADDR 0x20 #define ST_PRESS_LPS001WP_BDU_MASK 0x04 #define ST_PRESS_LPS001WP_MULTIREAD_BIT true @@ -94,11 +104,6 @@ #define ST_PRESS_LPS25H_ODR_AVL_25HZ_VAL 0x04 #define ST_PRESS_LPS25H_PW_ADDR 0x20 #define ST_PRESS_LPS25H_PW_MASK 0x80 -#define ST_PRESS_LPS25H_FS_ADDR 0x00 -#define ST_PRESS_LPS25H_FS_MASK 0x00 -#define ST_PRESS_LPS25H_FS_AVL_1260_VAL 0x00 -#define ST_PRESS_LPS25H_FS_AVL_1260_GAIN ST_PRESS_KPASCAL_NANO_SCALE -#define ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN ST_PRESS_CELSIUS_NANO_SCALE #define ST_PRESS_LPS25H_BDU_ADDR 0x20 #define ST_PRESS_LPS25H_BDU_MASK 0x04 #define ST_PRESS_LPS25H_DRDY_IRQ_ADDR 0x23 @@ -109,7 +114,6 @@ #define ST_PRESS_LPS25H_OD_IRQ_ADDR 0x22 #define ST_PRESS_LPS25H_OD_IRQ_MASK 0x40 #define ST_PRESS_LPS25H_MULTIREAD_BIT true -#define ST_PRESS_LPS25H_TEMP_OFFSET 42500 #define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28 #define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b @@ -161,7 +165,9 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { .storagebits = 16, .endianness = IIO_LE, }, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), .modified = 0, }, { @@ -177,7 +183,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_SCALE), .modified = 0, }, IIO_CHAN_SOFT_TIMESTAMP(1) @@ -212,11 +218,14 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .addr = ST_PRESS_LPS331AP_FS_ADDR, .mask = ST_PRESS_LPS331AP_FS_MASK, .fs_avl = { + /* + * Pressure and temperature sensitivity values + * as defined in table 3 of LPS331AP datasheet. + */ [0] = { .num = ST_PRESS_FS_AVL_1260MB, - .value = ST_PRESS_LPS331AP_FS_AVL_1260_VAL, - .gain = ST_PRESS_LPS331AP_FS_AVL_1260_GAIN, - .gain2 = ST_PRESS_LPS331AP_FS_AVL_TEMP_GAIN, + .gain = ST_PRESS_KPASCAL_NANO_SCALE, + .gain2 = ST_PRESS_LSB_PER_CELSIUS, }, }, }, @@ -261,7 +270,17 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, .fs = { - .addr = 0, + .fs_avl = { + /* + * Pressure and temperature resolution values + * as defined in table 3 of LPS001WP datasheet. + */ + [0] = { + .num = ST_PRESS_FS_AVL_1100MB, + .gain = ST_PRESS_LPS001WP_FS_AVL_PRESS_GAIN, + .gain2 = ST_PRESS_LPS001WP_LSB_PER_CELSIUS, + }, + }, }, .bdu = { .addr = ST_PRESS_LPS001WP_BDU_ADDR, @@ -298,14 +317,15 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, }, .fs = { - .addr = ST_PRESS_LPS25H_FS_ADDR, - .mask = ST_PRESS_LPS25H_FS_MASK, .fs_avl = { + /* + * Pressure and temperature sensitivity values + * as defined in table 3 of LPS25H datasheet. + */ [0] = { .num = ST_PRESS_FS_AVL_1260MB, - .value = ST_PRESS_LPS25H_FS_AVL_1260_VAL, - .gain = ST_PRESS_LPS25H_FS_AVL_1260_GAIN, - .gain2 = ST_PRESS_LPS25H_FS_AVL_TEMP_GAIN, + .gain = ST_PRESS_KPASCAL_NANO_SCALE, + .gain2 = ST_PRESS_LSB_PER_CELSIUS, }, }, }, @@ -364,26 +384,26 @@ static int st_press_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = 0; - switch (ch->type) { case IIO_PRESSURE: + *val = 0; *val2 = press_data->current_fullscale->gain; - break; + return IIO_VAL_INT_PLUS_NANO; case IIO_TEMP: + *val = MCELSIUS_PER_CELSIUS; *val2 = press_data->current_fullscale->gain2; - break; + return IIO_VAL_FRACTIONAL; default: err = -EINVAL; goto read_error; } - return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_OFFSET: switch (ch->type) { case IIO_TEMP: - *val = 425; - *val2 = 10; + *val = ST_PRESS_MILLI_CELSIUS_OFFSET * + press_data->current_fullscale->gain2; + *val2 = MCELSIUS_PER_CELSIUS; break; default: err = -EINVAL; -- cgit v1.2.3 From 09bc0ddaab6cab0fa95a67d5535ec772e2671193 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Thu, 26 May 2016 19:55:06 -0700 Subject: iio: humidity: hdc100x: fix IIO_TEMP channel reporting IIO_TEMP channel was being incorrectly reported back as Celsius when it should have been milliCelsius. This is via an incorrect scale value being returned to userspace. Signed-off-by: Matt Ranostay Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/hdc100x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index 59aa1cbdc2fd..30709838dcdc 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -211,7 +211,7 @@ static int hdc100x_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SCALE: if (chan->type == IIO_TEMP) { - *val = 165; + *val = 165000; *val2 = 65536 >> 2; return IIO_VAL_FRACTIONAL; } else { -- cgit v1.2.3 From 13c27e946ddc0e19f3d8b307b14cd8053fcb4844 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 25 May 2016 09:40:26 +0200 Subject: iio: bh1780: dereference the client properly The code in runtime_[suspend|resume] was assuming that the i2c client data was the bh1780 state container, but it contains the IIO device. So first dereference the IIO device from the i2c client, then get the state container using the iio_priv() call. Fixes: 1f0477f18306 ("iio: light: new driver for the ROHM BH1780") Signed-off-by: Linus Walleij Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/light/bh1780.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index f83595334ff1..5fd432df2c8f 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -226,7 +226,8 @@ static int bh1780_remove(struct i2c_client *client) static int bh1780_runtime_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct bh1780_data *bh1780 = i2c_get_clientdata(client); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct bh1780_data *bh1780 = iio_priv(indio_dev); int ret; ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF); @@ -241,7 +242,8 @@ static int bh1780_runtime_suspend(struct device *dev) static int bh1780_runtime_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct bh1780_data *bh1780 = i2c_get_clientdata(client); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct bh1780_data *bh1780 = iio_priv(indio_dev); int ret; ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON); -- cgit v1.2.3 From 0dd09ca419d712d315ffd864158f515e6c64261a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 25 May 2016 09:40:27 +0200 Subject: iio: light: bh1780: assign a static name Using the struct i2c_device->id field for naming the light sensor is a bad idea: when booting from the pure device tree this is NULL and that causes the device not to have the "name" property in sysfs and that in turn confuses the "lsiio" command to stop listing devices. So instead of using the device .id, use the hard string "bh1780", which works just fine. Fixes: 1f0477f18306 ("iio: light: new driver for the ROHM BH1780") Signed-off-by: Linus Walleij Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/light/bh1780.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index 5fd432df2c8f..b54dcba05a82 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -187,7 +187,7 @@ static int bh1780_probe(struct i2c_client *client, indio_dev->dev.parent = &client->dev; indio_dev->info = &bh1780_info; - indio_dev->name = id->name; + indio_dev->name = "bh1780"; indio_dev->channels = bh1780_channels; indio_dev->num_channels = ARRAY_SIZE(bh1780_channels); indio_dev->modes = INDIO_DIRECT_MODE; -- cgit v1.2.3 From 65925b65ed98ffdb277cf5ea1af45731dac0b30b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 21 May 2016 20:43:16 +0200 Subject: iio: st_sensors: switch to a threaded interrupt commit 98ad8b41f58dff6b30713d7f09ae3834b8df7ded ("iio: st_sensors: verify interrupt event to status") caused a regression when reading ST sensors from a HRTimer trigger rather than the intrinsic interrupts: the HRTimer may trigger faster than the sensor provides new values, and as the check against new values available as a cause of the interrupt trigger was done in the poll function, this would bail out of the HRTimer interrupt with IRQ_NONE. So clearly we need to only check the new values available from the proper interrupt handler and not from the poll function, which should rather just read the raw values from the registers, put them into the buffer and be happy. To achieve this: switch the ST Sensors over to using a true threaded interrupt handler. In the interrupt thread, check if new values are available, else yield to the (potential) next device on the same interrupt line to check the registers. If the interrupt was ours, proceed to poll the values. Instead of relying on iio_trigger_generic_data_rdy_poll() as a top half to wake up the thread that polls the sensor for new data, have the thread call iio_trigger_poll_chained() after determining that is is the proper source of the interrupt. This is modelled on drivers/iio/accel/mma8452.c which is already using a properly threaded interrupt handler. In order to get the same precision in timestamps as previously, where samples would be timestamped in the poll function pf->timestamp when calling iio_trigger_generic_data_rdy_poll() we introduce a local timestamp in the sensor data, set it in the top half (fastpath) of the interrupt handler and provide that to the core when calling iio_push_to_buffers_with_timestamp(). Additionally: if the active scanmask is not set for the sensor no IRQs should be enabled and we need to bail out with IRQ_NONE. This can happen if spurious IRQs fire when installing the threaded interrupt handler. Tested with hard interrupt triggers on LIS331DL, then also tested with hrtimers on the same sensor by creating a 75Hz HRTimer and using it to poll the sensor. Signed-off-by: Linus Walleij Cc: Giuseppe Barba Cc: Denis Ciocca Reported-by: Crestez Dan Leonard Tested-by: Crestez Dan Leonard Tested-by: Jonathan Cameron Fixes: 97865fe41322 ("iio: st_sensors: verify interrupt event to status") Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_buffer.c | 2 +- drivers/iio/accel/st_accel_core.c | 1 + drivers/iio/common/st_sensors/st_sensors_buffer.c | 25 ++---- drivers/iio/common/st_sensors/st_sensors_core.c | 3 + drivers/iio/common/st_sensors/st_sensors_trigger.c | 88 +++++++++++++++++++++- drivers/iio/gyro/st_gyro_buffer.c | 2 +- drivers/iio/gyro/st_gyro_core.c | 1 + drivers/iio/magnetometer/st_magn_buffer.c | 2 +- drivers/iio/magnetometer/st_magn_core.c | 1 + drivers/iio/pressure/st_pressure_buffer.c | 2 +- drivers/iio/pressure/st_pressure_core.c | 1 + include/linux/iio/common/st_sensors.h | 9 ++- 12 files changed, 111 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c index a1e642ee13d6..7fddc137e91e 100644 --- a/drivers/iio/accel/st_accel_buffer.c +++ b/drivers/iio/accel/st_accel_buffer.c @@ -91,7 +91,7 @@ static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = { int st_accel_allocate_ring(struct iio_dev *indio_dev) { - return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + return iio_triggered_buffer_setup(indio_dev, NULL, &st_sensors_trigger_handler, &st_accel_buffer_setup_ops); } diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index dc73f2d85e6d..4d95bfc4786c 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -741,6 +741,7 @@ static const struct iio_info accel_info = { static const struct iio_trigger_ops st_accel_trigger_ops = { .owner = THIS_MODULE, .set_trigger_state = ST_ACCEL_TRIGGER_SET_STATE, + .validate_device = st_sensors_validate_device, }; #define ST_ACCEL_TRIGGER_OPS (&st_accel_trigger_ops) #else diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index c55898543a47..f1693dbebb8a 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -57,31 +57,20 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct st_sensor_data *sdata = iio_priv(indio_dev); + s64 timestamp; - /* If we have a status register, check if this IRQ came from us */ - if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) { - u8 status; - - len = sdata->tf->read_byte(&sdata->tb, sdata->dev, - sdata->sensor_settings->drdy_irq.addr_stat_drdy, - &status); - if (len < 0) - dev_err(sdata->dev, "could not read channel status\n"); - - /* - * If this was not caused by any channels on this sensor, - * return IRQ_NONE - */ - if (!(status & (u8)indio_dev->active_scan_mask[0])) - return IRQ_NONE; - } + /* If we do timetamping here, do it before reading the values */ + if (sdata->hw_irq_trigger) + timestamp = sdata->hw_timestamp; + else + timestamp = iio_get_time_ns(); len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data); if (len < 0) goto st_sensors_get_buffer_element_error; iio_push_to_buffers_with_timestamp(indio_dev, sdata->buffer_data, - pf->timestamp); + timestamp); st_sensors_get_buffer_element_error: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index dffe00692169..928ee68fcc5f 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -424,6 +424,9 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) else drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2; + /* Flag to the poll function that the hardware trigger is in use */ + sdata->hw_irq_trigger = enable; + /* Enable/Disable the interrupt generator for data ready. */ err = st_sensors_write_data_with_mask(indio_dev, sdata->sensor_settings->drdy_irq.addr, diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index da72279fcf99..1f59bcc0f143 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -17,6 +17,73 @@ #include #include "st_sensors_core.h" +/** + * st_sensors_irq_handler() - top half of the IRQ-based triggers + * @irq: irq number + * @p: private handler data + */ +irqreturn_t st_sensors_irq_handler(int irq, void *p) +{ + struct iio_trigger *trig = p; + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct st_sensor_data *sdata = iio_priv(indio_dev); + + /* Get the time stamp as close in time as possible */ + sdata->hw_timestamp = iio_get_time_ns(); + return IRQ_WAKE_THREAD; +} + +/** + * st_sensors_irq_thread() - bottom half of the IRQ-based triggers + * @irq: irq number + * @p: private handler data + */ +irqreturn_t st_sensors_irq_thread(int irq, void *p) +{ + struct iio_trigger *trig = p; + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct st_sensor_data *sdata = iio_priv(indio_dev); + int ret; + + /* + * If this trigger is backed by a hardware interrupt and we have a + * status register, check if this IRQ came from us + */ + if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) { + u8 status; + + ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, + sdata->sensor_settings->drdy_irq.addr_stat_drdy, + &status); + if (ret < 0) { + dev_err(sdata->dev, "could not read channel status\n"); + goto out_poll; + } + /* + * the lower bits of .active_scan_mask[0] is directly mapped + * to the channels on the sensor: either bit 0 for + * one-dimensional sensors, or e.g. x,y,z for accelerometers, + * gyroscopes or magnetometers. No sensor use more than 3 + * channels, so cut the other status bits here. + */ + status &= 0x07; + + /* + * If this was not caused by any channels on this sensor, + * return IRQ_NONE + */ + if (!indio_dev->active_scan_mask) + return IRQ_NONE; + if (!(status & (u8)indio_dev->active_scan_mask[0])) + return IRQ_NONE; + } + +out_poll: + /* It's our IRQ: proceed to handle the register polling */ + iio_trigger_poll_chained(p); + return IRQ_HANDLED; +} + int st_sensors_allocate_trigger(struct iio_dev *indio_dev, const struct iio_trigger_ops *trigger_ops) { @@ -77,9 +144,12 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, sdata->sensor_settings->drdy_irq.addr_stat_drdy) irq_trig |= IRQF_SHARED; - err = request_threaded_irq(irq, - iio_trigger_generic_data_rdy_poll, - NULL, + /* Let's create an interrupt thread masking the hard IRQ here */ + irq_trig |= IRQF_ONESHOT; + + err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev), + st_sensors_irq_handler, + st_sensors_irq_thread, irq_trig, sdata->trig->name, sdata->trig); @@ -119,6 +189,18 @@ void st_sensors_deallocate_trigger(struct iio_dev *indio_dev) } EXPORT_SYMBOL(st_sensors_deallocate_trigger); +int st_sensors_validate_device(struct iio_trigger *trig, + struct iio_dev *indio_dev) +{ + struct iio_dev *indio = iio_trigger_get_drvdata(trig); + + if (indio != indio_dev) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(st_sensors_validate_device); + MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c index d67b17b6a7aa..a5377044e42f 100644 --- a/drivers/iio/gyro/st_gyro_buffer.c +++ b/drivers/iio/gyro/st_gyro_buffer.c @@ -91,7 +91,7 @@ static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = { int st_gyro_allocate_ring(struct iio_dev *indio_dev) { - return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + return iio_triggered_buffer_setup(indio_dev, NULL, &st_sensors_trigger_handler, &st_gyro_buffer_setup_ops); } diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 52a3c87c375c..a8012955a1f6 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -409,6 +409,7 @@ static const struct iio_info gyro_info = { static const struct iio_trigger_ops st_gyro_trigger_ops = { .owner = THIS_MODULE, .set_trigger_state = ST_GYRO_TRIGGER_SET_STATE, + .validate_device = st_sensors_validate_device, }; #define ST_GYRO_TRIGGER_OPS (&st_gyro_trigger_ops) #else diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index ecd3bd0a9769..0a9e8fadfa9d 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -82,7 +82,7 @@ static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = { int st_magn_allocate_ring(struct iio_dev *indio_dev) { - return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + return iio_triggered_buffer_setup(indio_dev, NULL, &st_sensors_trigger_handler, &st_magn_buffer_setup_ops); } diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 62036d2a9956..8250fc322c56 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -572,6 +572,7 @@ static const struct iio_info magn_info = { static const struct iio_trigger_ops st_magn_trigger_ops = { .owner = THIS_MODULE, .set_trigger_state = ST_MAGN_TRIGGER_SET_STATE, + .validate_device = st_sensors_validate_device, }; #define ST_MAGN_TRIGGER_OPS (&st_magn_trigger_ops) #else diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c index 2ff53f222352..99468d0a64e7 100644 --- a/drivers/iio/pressure/st_pressure_buffer.c +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -82,7 +82,7 @@ static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { int st_press_allocate_ring(struct iio_dev *indio_dev) { - return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + return iio_triggered_buffer_setup(indio_dev, NULL, &st_sensors_trigger_handler, &st_press_buffer_setup_ops); } diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 257b58ac6779..92a118c3c4ac 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -445,6 +445,7 @@ static const struct iio_info press_info = { static const struct iio_trigger_ops st_press_trigger_ops = { .owner = THIS_MODULE, .set_trigger_state = ST_PRESS_TRIGGER_SET_STATE, + .validate_device = st_sensors_validate_device, }; #define ST_PRESS_TRIGGER_OPS (&st_press_trigger_ops) #else diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index d029ffac0d69..99403b19092f 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -223,6 +223,8 @@ struct st_sensor_settings { * @get_irq_data_ready: Function to get the IRQ used for data ready signal. * @tf: Transfer function structure used by I/O operations. * @tb: Transfer buffers and mutex used by I/O operations. + * @hw_irq_trigger: if we're using the hardware interrupt on the sensor. + * @hw_timestamp: Latest timestamp from the interrupt handler, when in use. */ struct st_sensor_data { struct device *dev; @@ -247,6 +249,9 @@ struct st_sensor_data { const struct st_sensor_transfer_function *tf; struct st_sensor_transfer_buffer tb; + + bool hw_irq_trigger; + s64 hw_timestamp; }; #ifdef CONFIG_IIO_BUFFER @@ -260,7 +265,8 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, const struct iio_trigger_ops *trigger_ops); void st_sensors_deallocate_trigger(struct iio_dev *indio_dev); - +int st_sensors_validate_device(struct iio_trigger *trig, + struct iio_dev *indio_dev); #else static inline int st_sensors_allocate_trigger(struct iio_dev *indio_dev, const struct iio_trigger_ops *trigger_ops) @@ -271,6 +277,7 @@ static inline void st_sensors_deallocate_trigger(struct iio_dev *indio_dev) { return; } +#define st_sensors_validate_device NULL #endif int st_sensors_init_sensor(struct iio_dev *indio_dev, -- cgit v1.2.3 From ff05916f94f912b25e8efcf9b02c10d481977bab Mon Sep 17 00:00:00 2001 From: Crestez Dan Leonard Date: Fri, 13 May 2016 21:43:33 +0300 Subject: iio: st_sensors: Init trigger before irq request This fixes a possible race where an interrupt arrives before complete initialization and crashes because iio_trigger_get_drvdata returns NULL. Cc: Giuseppe Barba Cc: Denis Ciocca Signed-off-by: Crestez Dan Leonard Reviewed-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_trigger.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index 1f59bcc0f143..296e4ff19ae8 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -97,6 +97,10 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, return -ENOMEM; } + iio_trigger_set_drvdata(sdata->trig, indio_dev); + sdata->trig->ops = trigger_ops; + sdata->trig->dev.parent = sdata->dev; + irq = sdata->get_irq_data_ready(indio_dev); irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); /* @@ -158,10 +162,6 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, goto iio_trigger_free; } - iio_trigger_set_drvdata(sdata->trig, indio_dev); - sdata->trig->ops = trigger_ops; - sdata->trig->dev.parent = sdata->dev; - err = iio_trigger_register(sdata->trig); if (err < 0) { dev_err(&indio_dev->dev, "failed to register iio trigger.\n"); -- cgit v1.2.3 From 99147606155f09feccac67c65387dc62260b749b Mon Sep 17 00:00:00 2001 From: Crestez Dan Leonard Date: Fri, 13 May 2016 21:43:34 +0300 Subject: iio: st_sensors: Disable DRDY at init time This fixes odd behavior after reboot. The fact that we set the device to powerdown mode is not sufficient to prevent DRDY being active because we might still have an unread sample. Even if powerdown was sufficient keeping DRDY disabled while trigger is not active is a good idea. Cc: Giuseppe Barba Cc: Denis Ciocca Signed-off-by: Crestez Dan Leonard Reviewed-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 928ee68fcc5f..9e59c90f6a8d 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -363,6 +363,11 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev, if (err < 0) return err; + /* Disable DRDY, this might be still be enabled after reboot. */ + err = st_sensors_set_dataready_irq(indio_dev, false); + if (err < 0) + return err; + if (sdata->current_fullscale) { err = st_sensors_set_fullscale(indio_dev, sdata->current_fullscale->num); -- cgit v1.2.3 From 4a9723e8df68cfce4048517ee32e37f78854b6fb Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 12 May 2016 16:54:08 +0200 Subject: dmaengine: at_xdmac: align descriptors on 64 bits Having descriptors aligned on 64 bits allows update CNDA and CUBC in an atomic way. Signed-off-by: Ludovic Desroches Fixes: e1f7c9eee707 ("dmaengine: at_xdmac: creation of the atmel eXtended DMA Controller driver") Cc: stable@vger.kernel.org #v4.1 and later Reviewed-by: Nicolas Ferre Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 8e304b1befc5..ba9b0b73fa47 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -242,7 +242,7 @@ struct at_xdmac_lld { u32 mbr_dus; /* Destination Microblock Stride Register */ }; - +/* 64-bit alignment needed to update CNDA and CUBC registers in an atomic way. */ struct at_xdmac_desc { struct at_xdmac_lld lld; enum dma_transfer_direction direction; @@ -253,7 +253,7 @@ struct at_xdmac_desc { unsigned int xfer_size; struct list_head descs_list; struct list_head xfer_node; -}; +} __aligned(sizeof(u64)); static inline void __iomem *at_xdmac_chan_reg_base(struct at_xdmac *atxdmac, unsigned int chan_nb) { -- cgit v1.2.3 From 53398f488821c2b5b15291e3debec6ad33f75d3d Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 12 May 2016 16:54:09 +0200 Subject: dmaengine: at_xdmac: fix residue corruption An unexpected value of CUBC can lead to a corrupted residue. A more complex sequence is needed to detect an inaccurate value for NCA or CUBC. Signed-off-by: Ludovic Desroches Fixes: e1f7c9eee707 ("dmaengine: at_xdmac: creation of the atmel eXtended DMA Controller driver") Cc: stable@vger.kernel.org #v4.1 and later Reviewed-by: Nicolas Ferre Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 54 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index ba9b0b73fa47..b02494e115fe 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1400,6 +1400,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, u32 cur_nda, check_nda, cur_ubc, mask, value; u8 dwidth = 0; unsigned long flags; + bool initd; ret = dma_cookie_status(chan, cookie, txstate); if (ret == DMA_COMPLETE) @@ -1435,34 +1436,43 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, } /* - * When processing the residue, we need to read two registers but we - * can't do it in an atomic way. AT_XDMAC_CNDA is used to find where - * we stand in the descriptor list and AT_XDMAC_CUBC is used - * to know how many data are remaining for the current descriptor. - * Since the dma channel is not paused to not loose data, between the - * AT_XDMAC_CNDA and AT_XDMAC_CUBC read, we may have change of - * descriptor. - * For that reason, after reading AT_XDMAC_CUBC, we check if we are - * still using the same descriptor by reading a second time - * AT_XDMAC_CNDA. If AT_XDMAC_CNDA has changed, it means we have to - * read again AT_XDMAC_CUBC. + * The easiest way to compute the residue should be to pause the DMA + * but doing this can lead to miss some data as some devices don't + * have FIFO. + * We need to read several registers because: + * - DMA is running therefore a descriptor change is possible while + * reading these registers + * - When the block transfer is done, the value of the CUBC register + * is set to its initial value until the fetch of the next descriptor. + * This value will corrupt the residue calculation so we have to skip + * it. + * + * INITD -------- ------------ + * |____________________| + * _______________________ _______________ + * NDA @desc2 \/ @desc3 + * _______________________/\_______________ + * __________ ___________ _______________ + * CUBC 0 \/ MAX desc1 \/ MAX desc2 + * __________/\___________/\_______________ + * + * Since descriptors are aligned on 64 bits, we can assume that + * the update of NDA and CUBC is atomic. * Memory barriers are used to ensure the read order of the registers. - * A max number of retries is set because unlikely it can never ends if - * we are transferring a lot of data with small buffers. + * A max number of retries is set because unlikely it could never ends. */ - cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; - rmb(); - cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) { - rmb(); check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; - - if (likely(cur_nda == check_nda)) - break; - - cur_nda = check_nda; + rmb(); + initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD); rmb(); cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); + rmb(); + cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; + rmb(); + + if ((check_nda == cur_nda) && initd) + break; } if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) { -- cgit v1.2.3 From 9295c41d77ca93aac79cfca6fa09fa1ca5cab66f Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 12 May 2016 16:54:10 +0200 Subject: dmaengine: at_xdmac: double FIFO flush needed to compute residue Due to the way CUBC register is updated, a double flush is needed to compute an accurate residue. First flush aim is to get data from the DMA FIFO and second one ensures that we won't report data which are not in memory. Signed-off-by: Ludovic Desroches Fixes: e1f7c9eee707 ("dmaengine: at_xdmac: creation of the atmel eXtended DMA Controller driver") Cc: stable@vger.kernel.org #v4.1 and later Reviewed-by: Nicolas Ferre Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index b02494e115fe..75bd6621dc5d 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1425,7 +1425,16 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, residue = desc->xfer_size; /* * Flush FIFO: only relevant when the transfer is source peripheral - * synchronized. + * synchronized. Flush is needed before reading CUBC because data in + * the FIFO are not reported by CUBC. Reporting a residue of the + * transfer length while we have data in FIFO can cause issue. + * Usecase: atmel USART has a timeout which means I have received + * characters but there is no more character received for a while. On + * timeout, it requests the residue. If the data are in the DMA FIFO, + * we will return a residue of the transfer length. It means no data + * received. If an application is waiting for these data, it will hang + * since we won't have another USART timeout without receiving new + * data. */ mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC; value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM; @@ -1480,6 +1489,19 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, goto spin_unlock; } + /* + * Flush FIFO: only relevant when the transfer is source peripheral + * synchronized. Another flush is needed here because CUBC is updated + * when the controller sends the data write command. It can lead to + * report data that are not written in the memory or the device. The + * FIFO flush ensures that data are really written. + */ + if ((desc->lld.mbr_cfg & mask) == value) { + at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask); + while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS)) + cpu_relax(); + } + /* * Remove size of all microblocks already transferred and the current * one. Then add the remaining size to transfer of the current -- cgit v1.2.3 From 6756325a9a1e2d36b6210f4a42f77501c917ebb9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 26 May 2016 09:46:22 +0300 Subject: ptp: oops in ptp_ioctl() If we pass ERR_PTR(-EFAULT) to kfree() then it's going to oops. Fixes: 2ece068e1b1d ('ptp: use memdup_user().') Signed-off-by: Dan Carpenter Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/ptp/ptp_chardev.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 0b1ac6be69ce..d637c933c8a9 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -211,6 +211,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) sysoff = memdup_user((void __user *)arg, sizeof(*sysoff)); if (IS_ERR(sysoff)) { err = PTR_ERR(sysoff); + sysoff = NULL; break; } if (sysoff->n_samples > PTP_MAX_SAMPLES) { -- cgit v1.2.3 From 86651650d16a359e4142c6a8b0467c87e48c4c94 Mon Sep 17 00:00:00 2001 From: Elad Kanfi Date: Thu, 26 May 2016 15:00:06 +0300 Subject: net: nps_enet: Disable interrupts before napi reschedule Since NAPI works by shutting down event interrupts when theres work and turning them on when theres none, the net driver must make sure that interrupts are disabled when it reschedules polling. By calling napi_reschedule, the driver switches to polling mode, therefor there should be no interrupt interference. Any received packets will be handled in nps_enet_poll by polling the HW indication of received packet until all packets are handled. Signed-off-by: Elad Kanfi Acked-by: Noam Camus Tested-by: Alexey Brodkin Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 085f9125cf42..06f031715b57 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -205,8 +205,10 @@ static int nps_enet_poll(struct napi_struct *napi, int budget) * re-adding ourselves to the poll list. */ - if (priv->tx_skb && !tx_ctrl_ct) + if (priv->tx_skb && !tx_ctrl_ct) { + nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); napi_reschedule(napi); + } } return work_done; -- cgit v1.2.3 From 68bb399e656f244d3d173a20a8280c167632fca8 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 26 May 2016 21:46:05 +0100 Subject: sfc: use flow dissector helpers for aRFS Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/rx.c | 75 ++++++++++++------------------------------- 1 file changed, 21 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 8956995b2fe7..9d6cc8b92ba0 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -842,33 +842,15 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, struct efx_nic *efx = netdev_priv(net_dev); struct efx_channel *channel; struct efx_filter_spec spec; - const __be16 *ports; - __be16 ether_type; - int nhoff; + struct flow_keys fk; int rc; - /* The core RPS/RFS code has already parsed and validated - * VLAN, IP and transport headers. We assume they are in the - * header area. - */ - - if (skb->protocol == htons(ETH_P_8021Q)) { - const struct vlan_hdr *vh = - (const struct vlan_hdr *)skb->data; - - /* We can't filter on the IP 5-tuple and the vlan - * together, so just strip the vlan header and filter - * on the IP part. - */ - EFX_BUG_ON_PARANOID(skb_headlen(skb) < sizeof(*vh)); - ether_type = vh->h_vlan_encapsulated_proto; - nhoff = sizeof(struct vlan_hdr); - } else { - ether_type = skb->protocol; - nhoff = 0; - } + if (!skb_flow_dissect_flow_keys(skb, &fk, 0)) + return -EPROTONOSUPPORT; - if (ether_type != htons(ETH_P_IP) && ether_type != htons(ETH_P_IPV6)) + if (fk.basic.n_proto != htons(ETH_P_IP) && fk.basic.n_proto != htons(ETH_P_IPV6)) + return -EPROTONOSUPPORT; + if (fk.control.flags & FLOW_DIS_IS_FRAGMENT) return -EPROTONOSUPPORT; efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, @@ -878,34 +860,19 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; - spec.ether_type = ether_type; - - if (ether_type == htons(ETH_P_IP)) { - const struct iphdr *ip = - (const struct iphdr *)(skb->data + nhoff); - - EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + sizeof(*ip)); - if (ip_is_fragment(ip)) - return -EPROTONOSUPPORT; - spec.ip_proto = ip->protocol; - spec.rem_host[0] = ip->saddr; - spec.loc_host[0] = ip->daddr; - EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + 4 * ip->ihl + 4); - ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); + spec.ether_type = fk.basic.n_proto; + spec.ip_proto = fk.basic.ip_proto; + + if (fk.basic.n_proto == htons(ETH_P_IP)) { + spec.rem_host[0] = fk.addrs.v4addrs.src; + spec.loc_host[0] = fk.addrs.v4addrs.dst; } else { - const struct ipv6hdr *ip6 = - (const struct ipv6hdr *)(skb->data + nhoff); - - EFX_BUG_ON_PARANOID(skb_headlen(skb) < - nhoff + sizeof(*ip6) + 4); - spec.ip_proto = ip6->nexthdr; - memcpy(spec.rem_host, &ip6->saddr, sizeof(ip6->saddr)); - memcpy(spec.loc_host, &ip6->daddr, sizeof(ip6->daddr)); - ports = (const __be16 *)(ip6 + 1); + memcpy(spec.rem_host, &fk.addrs.v6addrs.src, sizeof(struct in6_addr)); + memcpy(spec.loc_host, &fk.addrs.v6addrs.dst, sizeof(struct in6_addr)); } - spec.rem_port = ports[0]; - spec.loc_port = ports[1]; + spec.rem_port = fk.ports.src; + spec.loc_port = fk.ports.dst; rc = efx->type->filter_rfs_insert(efx, &spec); if (rc < 0) @@ -916,18 +883,18 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, channel = efx_get_channel(efx, skb_get_rx_queue(skb)); ++channel->rfs_filters_added; - if (ether_type == htons(ETH_P_IP)) + if (spec.ether_type == htons(ETH_P_IP)) netif_info(efx, rx_status, efx->net_dev, "steering %s %pI4:%u:%pI4:%u to queue %u [flow %u filter %d]\n", (spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP", - spec.rem_host, ntohs(ports[0]), spec.loc_host, - ntohs(ports[1]), rxq_index, flow_id, rc); + spec.rem_host, ntohs(spec.rem_port), spec.loc_host, + ntohs(spec.loc_port), rxq_index, flow_id, rc); else netif_info(efx, rx_status, efx->net_dev, "steering %s [%pI6]:%u:[%pI6]:%u to queue %u [flow %u filter %d]\n", (spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP", - spec.rem_host, ntohs(ports[0]), spec.loc_host, - ntohs(ports[1]), rxq_index, flow_id, rc); + spec.rem_host, ntohs(spec.rem_port), spec.loc_host, + ntohs(spec.loc_port), rxq_index, flow_id, rc); return rc; } -- cgit v1.2.3 From bebef39842c8615180e711c0ff3e8c9c40c397da Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 2 May 2016 12:59:48 +0200 Subject: drm/sun4i: add COMMON_CLK dependency The sun4i drm driver uses the clk-provider interfaces, which are not available when CONFIG_COMMON_CLK is disabled: drivers/gpu/drm/sun4i/sun4i_dotclock.c:19:16: error: field 'hw' has incomplete type struct clk_hw hw; In file included from ../include/asm-generic/bug.h:13:0, from ../arch/arm/include/asm/bug.h:59, from ../include/linux/bug.h:4, from ../include/linux/io.h:23, from ../include/linux/clk-provider.h:14, from ../drivers/gpu/drm/sun4i/sun4i_dotclock.c:13: drivers/gpu/drm/sun4i/sun4i_dotclock.c: In function 'hw_to_dclk': include/linux/kernel.h:831:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types] ... This adds a Kconfig dependency to prevent the driver from being enabled in this case. Signed-off-by: Arnd Bergmann Fixes: 9026e0d122ac ("drm: Add Allwinner A10 Display Engine support") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig index 99510e64e91a..a4b357db8856 100644 --- a/drivers/gpu/drm/sun4i/Kconfig +++ b/drivers/gpu/drm/sun4i/Kconfig @@ -1,6 +1,6 @@ config DRM_SUN4I tristate "DRM Support for Allwinner A10 Display Engine" - depends on DRM && ARM + depends on DRM && ARM && COMMON_CLK depends on ARCH_SUNXI || COMPILE_TEST select DRM_GEM_CMA_HELPER select DRM_KMS_HELPER -- cgit v1.2.3 From f1b78f0e759b174ec4f5e3b0dd27a079a2416b66 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 3 May 2016 17:23:28 +0200 Subject: drm: sun4i: print DMA address correctly The newly added sun4i drm driver prints a dma address using the %x format string, which cannot work when dma_addr_t is 64 bit, and gcc warns about this configuration: drm/sun4i/sun4i_backend.c: In function 'sun4i_backend_update_layer_buffer': drm/sun4i/sun4i_backend.c:193:84: error: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'dma_addr_t {aka long long unsigned int}' [-Werror=format=] DRM_DEBUG_DRIVER("Using GEM @ 0x%x\n", gem->paddr); drm/sun4i/sun4i_backend.c:201:84: error: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'dma_addr_t {aka long long unsigned int}' [-Werror=format=] DRM_DEBUG_DRIVER("Setting buffer address to 0x%x\n", paddr); This changes the code to use the explicit %pad format string, which always prints the right length. Signed-off-by: Arnd Bergmann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index f7a15c1a93bf..3ab560450a82 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -190,7 +190,7 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, /* Get the physical address of the buffer in memory */ gem = drm_fb_cma_get_gem_obj(fb, 0); - DRM_DEBUG_DRIVER("Using GEM @ 0x%x\n", gem->paddr); + DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr); /* Compute the start of the displayed memory */ bpp = drm_format_plane_cpp(fb->pixel_format, 0); @@ -198,7 +198,7 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, paddr += (state->src_x >> 16) * bpp; paddr += (state->src_y >> 16) * fb->pitches[0]; - DRM_DEBUG_DRIVER("Setting buffer address to 0x%x\n", paddr); + DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); /* Write the 32 lower bits of the address (in bits) */ lo_paddr = paddr << 3; -- cgit v1.2.3 From 9fa2568d9fe0c6dbf3253af6840de9389f4e89cb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 5 May 2016 22:10:52 +0200 Subject: drm: sun4i: fix probe error handling gcc points out a possible uninitialized variable use in sun4i_dclk_create(): drivers/gpu/drm/sun4i/sun4i_dotclock.c: In function 'sun4i_dclk_create': drivers/gpu/drm/sun4i/sun4i_dotclock.c:139:12: error: 'clk_name' may be used uninitialized in this function [-Werror=maybe-uninitialized] init.name = clk_name; The warning only shows up when CONFIG_OF is disabled, and the property is never filled, but the same bug can show up even when CONFIG_OF is enabled but of_property_read_string_index returns another error. To fix it, this ensures that sun4i_dclk_create propagates any error from of_property_read_string_index. Signed-off-by: Arnd Bergmann Fixes: 9026e0d122ac ("drm: Add Allwinner A10 Display Engine support") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_dotclock.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index 3ff668cb463c..6c9c090a8006 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c @@ -127,10 +127,14 @@ int sun4i_dclk_create(struct device *dev, struct sun4i_tcon *tcon) const char *clk_name, *parent_name; struct clk_init_data init; struct sun4i_dclk *dclk; + int ret; parent_name = __clk_get_name(tcon->sclk0); - of_property_read_string_index(dev->of_node, "clock-output-names", 0, - &clk_name); + ret = of_property_read_string_index(dev->of_node, + "clock-output-names", 0, + &clk_name); + if (ret) + return ret; dclk = devm_kzalloc(dev, sizeof(*dclk), GFP_KERNEL); if (!dclk) -- cgit v1.2.3 From 4731a72df273bdbd225445424057c15dbb8d3495 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sat, 2 Apr 2016 12:30:11 +0200 Subject: drm/sun4i: request exact rates to our parents Our pixel clock currently only tries to deal with the current parent rate. While that works when the resolution is the same than the one already program, or when we can compute directly the rate from the current parent rate, it cannot work in most situation when we want to change the frequency, and we end up with an improper pixel clock rate, which obviously doesn't work as expected. Ask our parent for all the possible dividers if it can reach that frequency, and return the best parent rate to the clock framework so that we can use it. Fixes: 9026e0d122ac ("drm: Add Allwinner A10 Display Engine support") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_dotclock.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index 6c9c090a8006..5b3463197c48 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c @@ -72,14 +72,40 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw, static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - return *parent_rate / DIV_ROUND_CLOSEST(*parent_rate, rate); + unsigned long best_parent = 0; + u8 best_div = 1; + int i; + + for (i = 6; i < 127; i++) { + unsigned long ideal = rate * i; + unsigned long rounded; + + rounded = clk_hw_round_rate(clk_hw_get_parent(hw), + ideal); + + if (rounded == ideal) { + best_parent = rounded; + best_div = i; + goto out; + } + + if ((rounded < ideal) && (rounded > best_parent)) { + best_parent = rounded; + best_div = i; + } + } + +out: + *parent_rate = best_parent; + + return best_parent / best_div; } static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct sun4i_dclk *dclk = hw_to_dclk(hw); - int div = DIV_ROUND_CLOSEST(parent_rate, rate); + u8 div = parent_rate / rate; return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG, GENMASK(6, 0), div); @@ -144,6 +170,7 @@ int sun4i_dclk_create(struct device *dev, struct sun4i_tcon *tcon) init.ops = &sun4i_dclk_ops; init.parent_names = &parent_name; init.num_parents = 1; + init.flags = CLK_SET_RATE_PARENT; dclk->regmap = tcon->regs; dclk->hw.init = &init; -- cgit v1.2.3 From bb43d40d7c830da5f623e3938fef908b003b7523 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 21 Apr 2016 11:25:26 +0200 Subject: drm/sun4i: rgb: Validate the clock rate Our pixel clock cannot reach a high enough rate for some rather high while common resolutions (like 1080p60). Make sure we filter the resolutions we cannot reach in our mode_valid function. Fixes: 29e57fab97fc ("drm: sun4i: Add RGB output") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_rgb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index ab6494818050..fe7ef52a9346 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -54,8 +54,13 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector) static int sun4i_rgb_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector); + struct sun4i_drv *drv = rgb->drv; + struct sun4i_tcon *tcon = drv->tcon; u32 hsync = mode->hsync_end - mode->hsync_start; u32 vsync = mode->vsync_end - mode->vsync_start; + unsigned long rate = mode->clock * 1000; + long rounded_rate; DRM_DEBUG_DRIVER("Validating modes...\n"); @@ -87,6 +92,15 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector, DRM_DEBUG_DRIVER("Vertical parameters OK\n"); + rounded_rate = clk_round_rate(tcon->dclk, rate); + if (rounded_rate < rate) + return MODE_CLOCK_LOW; + + if (rounded_rate > rate) + return MODE_CLOCK_HIGH; + + DRM_DEBUG_DRIVER("Clock rate OK\n"); + return MODE_OK; } -- cgit v1.2.3 From 0bbbb00bda57e6f091275b0103445596322b9277 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 4 May 2016 17:38:32 +0200 Subject: drm/sun4i: defer only if we didn't find our panel Our code currently defers our probe on any error, even if we were not expecting to have one at all. Make sure we return -EPROBE_DEFER only when we were supposed to have a panel, but it's not probed yet. Also fix a typo while we're at it. Fixes: 29e57fab97fc ("drm: sun4i: Add RGB output") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 9f19b0e08560..16ab426ffa34 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -425,11 +425,11 @@ static struct drm_panel *sun4i_tcon_find_panel(struct device_node *node) remote = of_graph_get_remote_port_parent(end_node); if (!remote) { - DRM_DEBUG_DRIVER("Enable to parse remote node\n"); + DRM_DEBUG_DRIVER("Unable to parse remote node\n"); return ERR_PTR(-EINVAL); } - return of_drm_find_panel(remote); + return of_drm_find_panel(remote) ?: ERR_PTR(-EPROBE_DEFER); } static int sun4i_tcon_bind(struct device *dev, struct device *master, @@ -522,12 +522,13 @@ static int sun4i_tcon_probe(struct platform_device *pdev) * Defer the probe. */ panel = sun4i_tcon_find_panel(node); - if (IS_ERR(panel)) { - /* - * If we don't have a panel endpoint, just go on - */ - if (PTR_ERR(panel) != -ENODEV) - return -EPROBE_DEFER; + + /* + * If we don't have a panel endpoint, just go on + */ + if (PTR_ERR(panel) == -EPROBE_DEFER) { + DRM_DEBUG_DRIVER("Still waiting for our panel. Deferring...\n"); + return -EPROBE_DEFER; } return component_add(&pdev->dev, &sun4i_tcon_ops); -- cgit v1.2.3 From 0de6e914a035076b1241f5738c06c9d3820abd6e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 4 May 2016 17:37:58 +0200 Subject: drm/sun4i: rgb: panel is an error pointer In case of an error, our pointer to the drm_panel structure attached to our encoder will hold an error pointer, not a NULL pointer. Make sure we check the right thing. Fixes: 29e57fab97fc ("drm: sun4i: Add RGB output") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_rgb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index fe7ef52a9346..aaffe9e64ffb 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -217,7 +217,7 @@ int sun4i_rgb_init(struct drm_device *drm) int ret; /* If we don't have a panel, there's no point in going on */ - if (!tcon->panel) + if (IS_ERR(tcon->panel)) return -ENODEV; rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL); -- cgit v1.2.3 From 3d6bd9065b7acf8499d414d70bdb4b4955856299 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 11 May 2016 16:52:50 +0200 Subject: drm/sun4i: remove simplefb at probe If simplefb was setup by our bootloader and enabled in the DT, we will have a first framebuffer loaded in our system. However, as soon as our DRM driver will load, it will reset the controller, initialise it and, if the framebuffer emulation is enabled, register a second framebuffer device. This is obviously pretty bad, since the first framebuffer will be some kind of a black hole, with memory still reserved that we can write to safely, but not displayed anywhere. Make sure we remove that framebuffer when we probe so we don't end up in that situation. Fixes: 9026e0d122ac ("drm: Add Allwinner A10 Display Engine support") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_drv.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 76e922bb60e5..af62b24c39b1 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -125,6 +125,22 @@ static struct drm_driver sun4i_drv_driver = { .disable_vblank = sun4i_drv_disable_vblank, }; +static void sun4i_remove_framebuffers(void) +{ + struct apertures_struct *ap; + + ap = alloc_apertures(1); + if (!ap) + return; + + /* The framebuffer can be located anywhere in RAM */ + ap->ranges[0].base = 0; + ap->ranges[0].size = ~0; + + remove_conflicting_framebuffers(ap, "sun4i-drm-fb", false); + kfree(ap); +} + static int sun4i_drv_bind(struct device *dev) { struct drm_device *drm; @@ -172,6 +188,9 @@ static int sun4i_drv_bind(struct device *dev) } drm->irq_enabled = true; + /* Remove early framebuffers (ie. simplefb) */ + sun4i_remove_framebuffers(); + /* Create our framebuffer */ drv->fbdev = sun4i_framebuffer_init(drm); if (IS_ERR(drv->fbdev)) { -- cgit v1.2.3 From 7aa2e2b731b337a7bc74cd076bbcd6b8b4b95fbf Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 11 May 2016 19:04:18 +0200 Subject: drm/sun4i: Convert to connector register helpers Now that connector register helpers have been created, switch to them. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_drv.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index af62b24c39b1..257d2b4f3645 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -24,34 +24,6 @@ #include "sun4i_layer.h" #include "sun4i_tcon.h" -static int sun4i_drv_connector_plug_all(struct drm_device *drm) -{ - struct drm_connector *connector, *failed; - int ret; - - mutex_lock(&drm->mode_config.mutex); - list_for_each_entry(connector, &drm->mode_config.connector_list, head) { - ret = drm_connector_register(connector); - if (ret) { - failed = connector; - goto err; - } - } - mutex_unlock(&drm->mode_config.mutex); - return 0; - -err: - list_for_each_entry(connector, &drm->mode_config.connector_list, head) { - if (failed == connector) - break; - - drm_connector_unregister(connector); - } - mutex_unlock(&drm->mode_config.mutex); - - return ret; -} - static int sun4i_drv_enable_vblank(struct drm_device *drm, unsigned int pipe) { struct sun4i_drv *drv = drm->dev_private; @@ -206,7 +178,7 @@ static int sun4i_drv_bind(struct device *dev) if (ret) goto free_drm; - ret = sun4i_drv_connector_plug_all(drm); + ret = drm_connector_register_all(drm); if (ret) goto unregister_drm; @@ -223,6 +195,7 @@ static void sun4i_drv_unbind(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); + drm_connector_unregister_all(drm); drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); sun4i_framebuffer_free(drm); -- cgit v1.2.3 From 13fef095bde04228316046f997eb963285d8532e Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 17 May 2016 23:56:06 +0800 Subject: drm: sun4i: do cleanup if RGB output init fails sun4i_rgb_init() can fail, which results in TCON failing to bind. In this case we need to do cleanup, specificly unregistering the dotclock, which is regmap based, and the regmap is registered as part of the sun4i_tcon_bind(). Failing to do so results in a NULL pointer reference when the CCF tries to turn off unused clocks. Fixes: 29e57fab97fc ("drm: sun4i: Add RGB output") Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 16ab426ffa34..652385f09735 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -490,7 +490,11 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, return 0; } - return sun4i_rgb_init(drm); + ret = sun4i_rgb_init(drm); + if (ret < 0) + goto err_free_clocks; + + return 0; err_free_clocks: sun4i_tcon_free_clocks(tcon); -- cgit v1.2.3 From a6d206e28abe468aac5bb589669c6beb855b1a66 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 27 Apr 2016 16:23:33 -0400 Subject: drm/imx: imx-ldb: Add DDC support Add support for reading EDID over Display Data Channel. If no DDC adapter is available, falls back to hardcoded EDID or display-timings node as before. Signed-off-by: Steve Longerbeam Signed-off-by: Akshay Bhat Acked-by: Philipp Zabel Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/imx-ldb.c | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index a58eee59550a..f506e8dd76cb 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -59,6 +59,7 @@ struct imx_ldb_channel { struct drm_encoder encoder; struct drm_panel *panel; struct device_node *child; + struct i2c_adapter *ddc; int chno; void *edid; int edid_len; @@ -107,6 +108,9 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) return num_modes; } + if (!imx_ldb_ch->edid && imx_ldb_ch->ddc) + imx_ldb_ch->edid = drm_get_edid(connector, imx_ldb_ch->ddc); + if (imx_ldb_ch->edid) { drm_mode_connector_update_edid_property(connector, imx_ldb_ch->edid); @@ -553,6 +557,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) for_each_child_of_node(np, child) { struct imx_ldb_channel *channel; + struct device_node *ddc_node; struct device_node *port; ret = of_property_read_u32(child, "reg", &i); @@ -595,14 +600,34 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) } } - edidp = of_get_property(child, "edid", &channel->edid_len); - if (edidp) { - channel->edid = kmemdup(edidp, channel->edid_len, - GFP_KERNEL); - } else if (!channel->panel) { - ret = of_get_drm_display_mode(child, &channel->mode, 0); - if (!ret) - channel->mode_valid = 1; + ddc_node = of_parse_phandle(child, "ddc-i2c-bus", 0); + if (ddc_node) { + channel->ddc = of_find_i2c_adapter_by_node(ddc_node); + of_node_put(ddc_node); + if (!channel->ddc) { + dev_warn(dev, "failed to get ddc i2c adapter\n"); + return -EPROBE_DEFER; + } + } + + if (!channel->ddc) { + /* if no DDC available, fallback to hardcoded EDID */ + dev_dbg(dev, "no ddc available\n"); + + edidp = of_get_property(child, "edid", + &channel->edid_len); + if (edidp) { + channel->edid = kmemdup(edidp, + channel->edid_len, + GFP_KERNEL); + } else if (!channel->panel) { + /* fallback to display-timings node */ + ret = of_get_drm_display_mode(child, + &channel->mode, + 0); + if (!ret) + channel->mode_valid = 1; + } } channel->bus_format = of_get_bus_format(dev, child); @@ -647,6 +672,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master, channel->encoder.funcs->destroy(&channel->encoder); kfree(channel->edid); + i2c_put_adapter(channel->ddc); } } -- cgit v1.2.3 From 620011e0477e485fc6112ace3c0a772130e8fd4f Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 3 May 2016 14:37:13 +0200 Subject: drm/imx: imx-ldb: use of_graph_get_endpoint_by_regs helper Instead of using of_graph_get_port_by_id() to get the port and then of_get_child_by_name() to get the first endpoint, get to the endpoint in a single step. Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/imx-ldb.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index f506e8dd76cb..5f8f0bf45a62 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -558,7 +558,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) for_each_child_of_node(np, child) { struct imx_ldb_channel *channel; struct device_node *ddc_node; - struct device_node *port; + struct device_node *ep; ret = of_property_read_u32(child, "reg", &i); if (ret || i < 0 || i > 1) @@ -581,22 +581,23 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) * The output port is port@4 with an external 4-port mux or * port@2 with the internal 2-port mux. */ - port = of_graph_get_port_by_id(child, imx_ldb->lvds_mux ? 4 : 2); - if (port) { - struct device_node *endpoint, *remote; - - endpoint = of_get_child_by_name(port, "endpoint"); - if (endpoint) { - remote = of_graph_get_remote_port_parent(endpoint); - if (remote) - channel->panel = of_drm_find_panel(remote); - else - return -EPROBE_DEFER; - if (!channel->panel) { - dev_err(dev, "panel not found: %s\n", - remote->full_name); - return -EPROBE_DEFER; - } + ep = of_graph_get_endpoint_by_regs(child, + imx_ldb->lvds_mux ? 4 : 2, + -1); + if (ep) { + struct device_node *remote; + + remote = of_graph_get_remote_port_parent(ep); + of_node_put(ep); + if (remote) + channel->panel = of_drm_find_panel(remote); + else + return -EPROBE_DEFER; + of_node_put(remote); + if (!channel->panel) { + dev_err(dev, "panel not found: %s\n", + remote->full_name); + return -EPROBE_DEFER; } } -- cgit v1.2.3 From 3a1c117f8bf13435f6db78f294d5754b2eb6185b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 3 May 2016 14:39:29 +0200 Subject: drm/imx: parallel-display: use of_graph_get_endpoint_by_regs helper Instead of using of_graph_get_port_by_id() to get the port and then of_get_child_by_name() to get the first endpoint, get to the endpoint in a single step. Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/parallel-display.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 363e2c7741e2..27755ecbf516 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -203,7 +203,7 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm = data; struct device_node *np = dev->of_node; - struct device_node *port; + struct device_node *ep; const u8 *edidp; struct imx_parallel_display *imxpd; int ret; @@ -230,18 +230,18 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) } /* port@1 is the output port */ - port = of_graph_get_port_by_id(np, 1); - if (port) { - struct device_node *endpoint, *remote; - - endpoint = of_get_child_by_name(port, "endpoint"); - if (endpoint) { - remote = of_graph_get_remote_port_parent(endpoint); - if (remote) - imxpd->panel = of_drm_find_panel(remote); - if (!imxpd->panel) - return -EPROBE_DEFER; + ep = of_graph_get_endpoint_by_regs(np, 1, -1); + if (ep) { + struct device_node *remote; + + remote = of_graph_get_remote_port_parent(ep); + of_node_put(ep); + if (remote) { + imxpd->panel = of_drm_find_panel(remote); + of_node_put(remote); } + if (!imxpd->panel) + return -EPROBE_DEFER; } imxpd->dev = dev; -- cgit v1.2.3 From 7932131f6381e5d2d4a78d9134f5f6bf45900ae5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Feb 2016 14:35:55 +0100 Subject: drm/imx: ipuv3-plane: enable UYVY and VYUY formats Advertise the DRM_FORMAT_UYVY and DRM_FORMAT_VYUY formats to userspace. Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/ipuv3-plane.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 681ec6eb77d9..8c24df787884 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -38,6 +38,8 @@ static const uint32_t ipu_plane_formats[] = { DRM_FORMAT_RGBX8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_BGRA8888, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, DRM_FORMAT_YUV420, -- cgit v1.2.3 From 4ed094fd73a7c0b8534685d2ed0f0f3ccdb96bdf Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 9 May 2016 17:02:13 +0200 Subject: drm/imx: use bus_flags for pixel clock polarity This patch allows panels to set pixel clock and data enable pin polarity other than the default of driving data at the falling pixel clock edge and active high display enable. Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/imx-drm-core.c | 13 ++++++++----- drivers/gpu/drm/imx/imx-drm.h | 7 ++++--- drivers/gpu/drm/imx/imx-tve.c | 6 ++++-- drivers/gpu/drm/imx/ipuv3-crtc.c | 10 +++++++--- drivers/gpu/drm/imx/parallel-display.c | 4 ++-- 5 files changed, 25 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 1f14b602882b..82656654fb21 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -97,8 +97,8 @@ static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) return NULL; } -int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format, - int hsync_pin, int vsync_pin) +int imx_drm_set_bus_config(struct drm_encoder *encoder, u32 bus_format, + int hsync_pin, int vsync_pin, u32 bus_flags) { struct imx_drm_crtc_helper_funcs *helper; struct imx_drm_crtc *imx_crtc; @@ -110,14 +110,17 @@ int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, u32 bus_format, helper = &imx_crtc->imx_drm_helper_funcs; if (helper->set_interface_pix_fmt) return helper->set_interface_pix_fmt(encoder->crtc, - bus_format, hsync_pin, vsync_pin); + bus_format, hsync_pin, vsync_pin, + bus_flags); return 0; } -EXPORT_SYMBOL_GPL(imx_drm_set_bus_format_pins); +EXPORT_SYMBOL_GPL(imx_drm_set_bus_config); int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format) { - return imx_drm_set_bus_format_pins(encoder, bus_format, 2, 3); + return imx_drm_set_bus_config(encoder, bus_format, 2, 3, + DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_NEGEDGE); } EXPORT_SYMBOL_GPL(imx_drm_set_bus_format); diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h index b0241b9d1334..74320a1723b7 100644 --- a/drivers/gpu/drm/imx/imx-drm.h +++ b/drivers/gpu/drm/imx/imx-drm.h @@ -19,7 +19,8 @@ struct imx_drm_crtc_helper_funcs { int (*enable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc); int (*set_interface_pix_fmt)(struct drm_crtc *crtc, - u32 bus_format, int hsync_pin, int vsync_pin); + u32 bus_format, int hsync_pin, int vsync_pin, + u32 bus_flags); const struct drm_crtc_helper_funcs *crtc_helper_funcs; const struct drm_crtc_funcs *crtc_funcs; }; @@ -41,8 +42,8 @@ void imx_drm_mode_config_init(struct drm_device *drm); struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); -int imx_drm_set_bus_format_pins(struct drm_encoder *encoder, - u32 bus_format, int hsync_pin, int vsync_pin); +int imx_drm_set_bus_config(struct drm_encoder *encoder, u32 bus_format, + int hsync_pin, int vsync_pin, u32 bus_flags); int imx_drm_set_bus_format(struct drm_encoder *encoder, u32 bus_format); diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c index ae7a9fb3b8a2..baf788121287 100644 --- a/drivers/gpu/drm/imx/imx-tve.c +++ b/drivers/gpu/drm/imx/imx-tve.c @@ -294,8 +294,10 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder) switch (tve->mode) { case TVE_MODE_VGA: - imx_drm_set_bus_format_pins(encoder, MEDIA_BUS_FMT_GBR888_1X24, - tve->hsync_pin, tve->vsync_pin); + imx_drm_set_bus_config(encoder, MEDIA_BUS_FMT_GBR888_1X24, + tve->hsync_pin, tve->vsync_pin, + DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_NEGEDGE); break; case TVE_MODE_TVOUT: imx_drm_set_bus_format(encoder, MEDIA_BUS_FMT_YUV8_1X24); diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c index b2c30b8d9816..fc040417e1e8 100644 --- a/drivers/gpu/drm/imx/ipuv3-crtc.c +++ b/drivers/gpu/drm/imx/ipuv3-crtc.c @@ -66,6 +66,7 @@ struct ipu_crtc { struct ipu_flip_work *flip_work; int irq; u32 bus_format; + u32 bus_flags; int di_hsync_pin; int di_vsync_pin; }; @@ -271,8 +272,10 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, else sig_cfg.clkflags = 0; - sig_cfg.enable_pol = 1; - sig_cfg.clk_pol = 0; + sig_cfg.enable_pol = !(ipu_crtc->bus_flags & DRM_BUS_FLAG_DE_LOW); + /* Default to driving pixel data on negative clock edges */ + sig_cfg.clk_pol = !!(ipu_crtc->bus_flags & + DRM_BUS_FLAG_PIXDATA_POSEDGE); sig_cfg.bus_format = ipu_crtc->bus_format; sig_cfg.v_to_h_sync = 0; sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin; @@ -396,11 +399,12 @@ static void ipu_disable_vblank(struct drm_crtc *crtc) } static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, - u32 bus_format, int hsync_pin, int vsync_pin) + u32 bus_format, int hsync_pin, int vsync_pin, u32 bus_flags) { struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); ipu_crtc->bus_format = bus_format; + ipu_crtc->bus_flags = bus_flags; ipu_crtc->di_hsync_pin = hsync_pin; ipu_crtc->di_vsync_pin = vsync_pin; diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 27755ecbf516..2c442516d4c7 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -115,8 +115,8 @@ static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode) static void imx_pd_encoder_prepare(struct drm_encoder *encoder) { struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); - - imx_drm_set_bus_format(encoder, imxpd->bus_format); + imx_drm_set_bus_config(encoder, imxpd->bus_format, 2, 3, + imxpd->connector.display_info.bus_flags); } static void imx_pd_encoder_commit(struct drm_encoder *encoder) -- cgit v1.2.3 From 97a6075d7cfabd0d45f8667a89da2a5fd13b4e70 Mon Sep 17 00:00:00 2001 From: Lothar Waßmann Date: Tue, 24 May 2016 08:31:51 +0200 Subject: drm/imx: parallel-display: remove dead code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'mode_valid' flag is never set in this driver. Remove it and the code that depends on it. Signed-off-by: Lothar Waßmann Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/parallel-display.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 2c442516d4c7..2d1fd02cd3d6 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -35,7 +35,6 @@ struct imx_parallel_display { void *edid; int edid_len; u32 bus_format; - int mode_valid; struct drm_display_mode mode; struct drm_panel *panel; }; @@ -68,17 +67,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) num_modes = drm_add_edid_modes(connector, imxpd->edid); } - if (imxpd->mode_valid) { - struct drm_display_mode *mode = drm_mode_create(connector->dev); - - if (!mode) - return -EINVAL; - drm_mode_copy(mode, &imxpd->mode); - mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, - drm_mode_probed_add(connector, mode); - num_modes++; - } - if (np) { struct drm_display_mode *mode = drm_mode_create(connector->dev); -- cgit v1.2.3 From c82b4d73e2cd32fff41be0cd6e75ea83d32943b3 Mon Sep 17 00:00:00 2001 From: Lothar Waßmann Date: Tue, 24 May 2016 08:31:49 +0200 Subject: drm/imx: imx-ldb: honor 'native-mode' property when selecting video mode from DT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch allows to select a specific video mode from a list of modes defined in DT by setting the 'native-mode' property appropriately. This change does not affect the behaviour of existing platforms, since they either: - have just one display-timings subnode - have the native-mode property pointing to the first entry - let the bootloader select the appropriate timing Signed-off-by: Lothar Waßmann Signed-off-by: Philipp Zabel --- drivers/gpu/drm/imx/imx-ldb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 5f8f0bf45a62..beff793bb717 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -25,6 +25,7 @@ #include #include #include +#include