diff --git a/patches.drivers/dmaengine-dw-dmac-implement-dma-protection-control-s.patch b/patches.drivers/dmaengine-dw-dmac-implement-dma-protection-control-s.patch new file mode 100644 index 0000000..d17ad0d --- /dev/null +++ b/patches.drivers/dmaengine-dw-dmac-implement-dma-protection-control-s.patch @@ -0,0 +1,145 @@ +From 7b0c03ecc42fb223baf015877fee9d517c2c8af1 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Sat, 17 Nov 2018 17:17:21 +0100 +Subject: [PATCH] dmaengine: dw-dmac: implement dma protection control setting +Git-commit: 7b0c03ecc42fb223baf015877fee9d517c2c8af1 +Patch-mainline: v5.0-rc1 +References: bsc#1111666 + +This patch adds a new device-tree property that allows to +specify the dma protection control bits for the all of the +DMA controller's channel uniformly. + +Setting the "correct" bits can have a huge impact on the +PPC460EX and APM82181 that use this DMA engine in combination +with a DesignWare' SATA-II core (sata_dwc_460ex driver). + +In the OpenWrt Forum, the user takimata reported that: +|It seems your patch unleashed the full power of the SATA port. +|Where I was previously hitting a really hard limit at around +|82 MB/s for reading and 27 MB/s for writing, I am now getting this: +| +|root@OpenWrt:/mnt# time dd if=/dev/zero of=tempfile bs=1M count=1024 +|1024+0 records in +|1024+0 records out +|real 0m 13.65s +|user 0m 0.01s +|sys 0m 11.89s +| +|root@OpenWrt:/mnt# time dd if=tempfile of=/dev/null bs=1M count=1024 +|1024+0 records in +|1024+0 records out +|real 0m 8.41s +|user 0m 0.01s +|sys 0m 4.70s +| +|This means: 121 MB/s reading and 75 MB/s writing! +| +|The drive is a WD Green WD10EARX taken from an older MBL Single. +|I repeated the test a few times with even larger files to rule out +|any caching, I'm still seeing the same great performance. OpenWrt is +|now completely on par with the original MBL firmware's performance. + +Another user And.short reported: +|I can report that your fix worked! Boots up fine with two +|drives even with more partitions, and no more reboot on +|concurrent disk access! + +A closer look into the sata_dwc_460ex code revealed that +the driver did initally set the correct protection control +bits. However, this feature was lost when the sata_dwc_460ex +driver was converted to the generic DMA driver framework. + +Buglink: https://forum.openwrt.org/t/wd-mybook-live-duo-two-disks/16195/55 +Buglink: https://forum.openwrt.org/t/wd-mybook-live-duo-two-disks/16195/50 +Fixes: 8b3444852a2b ("sata_dwc_460ex: move to generic DMA driver") +Reviewed-by: Andy Shevchenko +Signed-off-by: Christian Lamparter +Signed-off-by: Vinod Koul +Acked-by: Takashi Iwai + +--- + drivers/dma/dw/core.c | 2 ++ + drivers/dma/dw/platform.c | 6 ++++++ + drivers/dma/dw/regs.h | 4 ++++ + include/linux/platform_data/dma-dw.h | 6 ++++++ + 4 files changed, 18 insertions(+) + +diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c +index d0c3e50b39fb..2c5ca1961256 100644 +--- a/drivers/dma/dw/core.c ++++ b/drivers/dma/dw/core.c +@@ -160,12 +160,14 @@ static void dwc_initialize_chan_idma32(struct dw_dma_chan *dwc) + + static void dwc_initialize_chan_dw(struct dw_dma_chan *dwc) + { ++ struct dw_dma *dw = to_dw_dma(dwc->chan.device); + u32 cfghi = DWC_CFGH_FIFO_MODE; + u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); + bool hs_polarity = dwc->dws.hs_polarity; + + cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id); + cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id); ++ cfghi |= DWC_CFGH_PROTCTL(dw->pdata->protctl); + + /* Set polarity of handshake interface */ + cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0; +diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c +index f01b2c173fa6..31ff8113c3de 100644 +--- a/drivers/dma/dw/platform.c ++++ b/drivers/dma/dw/platform.c +@@ -162,6 +162,12 @@ dw_dma_parse_dt(struct platform_device *pdev) + pdata->multi_block[tmp] = 1; + } + ++ if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) { ++ if (tmp > CHAN_PROTCTL_MASK) ++ return NULL; ++ pdata->protctl = tmp; ++ } ++ + return pdata; + } + #else +diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h +index 09e7dfdbb790..646c9c960c07 100644 +--- a/drivers/dma/dw/regs.h ++++ b/drivers/dma/dw/regs.h +@@ -200,6 +200,10 @@ enum dw_dma_msize { + #define DWC_CFGH_FCMODE (1 << 0) + #define DWC_CFGH_FIFO_MODE (1 << 1) + #define DWC_CFGH_PROTCTL(x) ((x) << 2) ++#define DWC_CFGH_PROTCTL_DATA (0 << 2) /* data access - always set */ ++#define DWC_CFGH_PROTCTL_PRIV (1 << 2) /* privileged -> AHB HPROT[1] */ ++#define DWC_CFGH_PROTCTL_BUFFER (2 << 2) /* bufferable -> AHB HPROT[2] */ ++#define DWC_CFGH_PROTCTL_CACHE (4 << 2) /* cacheable -> AHB HPROT[3] */ + #define DWC_CFGH_DS_UPD_EN (1 << 5) + #define DWC_CFGH_SS_UPD_EN (1 << 6) + #define DWC_CFGH_SRC_PER(x) ((x) << 7) +diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h +index 896cb71a382c..1a1d58ebffbf 100644 +--- a/include/linux/platform_data/dma-dw.h ++++ b/include/linux/platform_data/dma-dw.h +@@ -49,6 +49,7 @@ struct dw_dma_slave { + * @data_width: Maximum data width supported by hardware per AHB master + * (in bytes, power of 2) + * @multi_block: Multi block transfers supported by hardware per channel. ++ * @protctl: Protection control signals setting per channel. + */ + struct dw_dma_platform_data { + unsigned int nr_channels; +@@ -65,6 +66,11 @@ struct dw_dma_platform_data { + unsigned char nr_masters; + unsigned char data_width[DW_DMA_MAX_NR_MASTERS]; + unsigned char multi_block[DW_DMA_MAX_NR_CHANNELS]; ++#define CHAN_PROTCTL_PRIVILEGED BIT(0) ++#define CHAN_PROTCTL_BUFFERABLE BIT(1) ++#define CHAN_PROTCTL_CACHEABLE BIT(2) ++#define CHAN_PROTCTL_MASK GENMASK(2, 0) ++ unsigned char protctl; + }; + + #endif /* _PLATFORM_DATA_DMA_DW_H */ +-- +2.16.4 + diff --git a/patches.drivers/iio-hid-sensors-Fix-IIO_CHAN_INFO_RAW-returning-wron.patch b/patches.drivers/iio-hid-sensors-Fix-IIO_CHAN_INFO_RAW-returning-wron.patch new file mode 100644 index 0000000..139742c --- /dev/null +++ b/patches.drivers/iio-hid-sensors-Fix-IIO_CHAN_INFO_RAW-returning-wron.patch @@ -0,0 +1,342 @@ +From 0145b50566e7de5637e80ecba96c7f0e6fff1aad Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 31 Oct 2018 15:20:05 +0100 +Subject: [PATCH] iio/hid-sensors: Fix IIO_CHAN_INFO_RAW returning wrong values for signed numbers +Git-commit: 0145b50566e7de5637e80ecba96c7f0e6fff1aad +Patch-mainline: v4.20-rc5 +References: bsc#1111666 + +Before this commit sensor_hub_input_attr_get_raw_value() failed to take +the signedness of 16 and 8 bit values into account, returning e.g. +65436 instead of -100 for the z-axis reading of an accelerometer. + +This commit adds a new is_signed parameter to the function and makes all +callers pass the appropriate value for this. + +While at it, this commit also fixes up some neighboring lines where +statements were needlessly split over 2 lines to improve readability. + +Signed-off-by: Hans de Goede +Acked-by: Srinivas Pandruvada +Acked-by: Benjamin Tissoires +Cc: +Signed-off-by: Jonathan Cameron +Acked-by: Takashi Iwai + +--- + drivers/hid/hid-sensor-custom.c | 2 +- + drivers/hid/hid-sensor-hub.c | 13 ++++++++++--- + drivers/iio/accel/hid-sensor-accel-3d.c | 5 ++++- + drivers/iio/gyro/hid-sensor-gyro-3d.c | 5 ++++- + drivers/iio/humidity/hid-sensor-humidity.c | 3 ++- + drivers/iio/light/hid-sensor-als.c | 8 +++++--- + drivers/iio/light/hid-sensor-prox.c | 8 +++++--- + drivers/iio/magnetometer/hid-sensor-magn-3d.c | 8 +++++--- + drivers/iio/orientation/hid-sensor-incl-3d.c | 8 +++++--- + drivers/iio/pressure/hid-sensor-press.c | 8 +++++--- + drivers/iio/temperature/hid-sensor-temperature.c | 3 ++- + drivers/rtc/rtc-hid-sensor-time.c | 2 +- + include/linux/hid-sensor-hub.h | 4 +++- + 13 files changed, 52 insertions(+), 25 deletions(-) + +--- a/drivers/hid/hid-sensor-custom.c ++++ b/drivers/hid/hid-sensor-custom.c +@@ -358,7 +358,7 @@ static ssize_t show_value(struct device + sensor_inst->hsdev, + sensor_inst->hsdev->usage, + usage, report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, false); + } else if (!strncmp(name, "units", strlen("units"))) + value = sensor_inst->fields[field_index].attribute.units; + else if (!strncmp(name, "unit-expo", strlen("unit-expo"))) +--- a/drivers/hid/hid-sensor-hub.c ++++ b/drivers/hid/hid-sensor-hub.c +@@ -299,7 +299,8 @@ EXPORT_SYMBOL_GPL(sensor_hub_get_feature + int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + u32 attr_usage_id, u32 report_id, +- enum sensor_hub_read_flags flag) ++ enum sensor_hub_read_flags flag, ++ bool is_signed) + { + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + unsigned long flags; +@@ -331,10 +332,16 @@ int sensor_hub_input_attr_get_raw_value( + &hsdev->pending.ready, HZ*5); + switch (hsdev->pending.raw_size) { + case 1: +- ret_val = *(u8 *)hsdev->pending.raw_data; ++ if (is_signed) ++ ret_val = *(s8 *)hsdev->pending.raw_data; ++ else ++ ret_val = *(u8 *)hsdev->pending.raw_data; + break; + case 2: +- ret_val = *(u16 *)hsdev->pending.raw_data; ++ if (is_signed) ++ ret_val = *(s16 *)hsdev->pending.raw_data; ++ else ++ ret_val = *(u16 *)hsdev->pending.raw_data; + break; + case 4: + ret_val = *(u32 *)hsdev->pending.raw_data; +--- a/drivers/iio/accel/hid-sensor-accel-3d.c ++++ b/drivers/iio/accel/hid-sensor-accel-3d.c +@@ -149,6 +149,7 @@ static int accel_3d_read_raw(struct iio_ + int report_id = -1; + u32 address; + int ret_type; ++ s32 min; + struct hid_sensor_hub_device *hsdev = + accel_state->common_attributes.hsdev; + +@@ -158,12 +159,14 @@ static int accel_3d_read_raw(struct iio_ + case 0: + hid_sensor_power_state(&accel_state->common_attributes, true); + report_id = accel_state->accel[chan->scan_index].report_id; ++ min = accel_state->accel[chan->scan_index].logical_minimum; + address = accel_3d_addresses[chan->scan_index]; + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + accel_state->common_attributes.hsdev, + hsdev->usage, address, report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, ++ min < 0); + else { + *val = 0; + hid_sensor_power_state(&accel_state->common_attributes, +--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c ++++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c +@@ -111,6 +111,7 @@ static int gyro_3d_read_raw(struct iio_d + int report_id = -1; + u32 address; + int ret_type; ++ s32 min; + + *val = 0; + *val2 = 0; +@@ -118,13 +119,15 @@ static int gyro_3d_read_raw(struct iio_d + case 0: + hid_sensor_power_state(&gyro_state->common_attributes, true); + report_id = gyro_state->gyro[chan->scan_index].report_id; ++ min = gyro_state->gyro[chan->scan_index].logical_minimum; + address = gyro_3d_addresses[chan->scan_index]; + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + gyro_state->common_attributes.hsdev, + HID_USAGE_SENSOR_GYRO_3D, address, + report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, ++ min < 0); + else { + *val = 0; + hid_sensor_power_state(&gyro_state->common_attributes, +--- a/drivers/iio/humidity/hid-sensor-humidity.c ++++ b/drivers/iio/humidity/hid-sensor-humidity.c +@@ -75,7 +75,8 @@ static int humidity_read_raw(struct iio_ + HID_USAGE_SENSOR_HUMIDITY, + HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY, + humid_st->humidity_attr.report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, ++ humid_st->humidity_attr.logical_minimum < 0); + hid_sensor_power_state(&humid_st->common_attributes, false); + + return IIO_VAL_INT; +--- a/drivers/iio/light/hid-sensor-als.c ++++ b/drivers/iio/light/hid-sensor-als.c +@@ -93,6 +93,7 @@ static int als_read_raw(struct iio_dev * + int report_id = -1; + u32 address; + int ret_type; ++ s32 min; + + *val = 0; + *val2 = 0; +@@ -102,8 +103,8 @@ static int als_read_raw(struct iio_dev * + case CHANNEL_SCAN_INDEX_INTENSITY: + case CHANNEL_SCAN_INDEX_ILLUM: + report_id = als_state->als_illum.report_id; +- address = +- HID_USAGE_SENSOR_LIGHT_ILLUM; ++ min = als_state->als_illum.logical_minimum; ++ address = HID_USAGE_SENSOR_LIGHT_ILLUM; + break; + default: + report_id = -1; +@@ -116,7 +117,8 @@ static int als_read_raw(struct iio_dev * + als_state->common_attributes.hsdev, + HID_USAGE_SENSOR_ALS, address, + report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, ++ min < 0); + hid_sensor_power_state(&als_state->common_attributes, + false); + } else { +--- a/drivers/iio/light/hid-sensor-prox.c ++++ b/drivers/iio/light/hid-sensor-prox.c +@@ -73,6 +73,7 @@ static int prox_read_raw(struct iio_dev + int report_id = -1; + u32 address; + int ret_type; ++ s32 min; + + *val = 0; + *val2 = 0; +@@ -81,8 +82,8 @@ static int prox_read_raw(struct iio_dev + switch (chan->scan_index) { + case CHANNEL_SCAN_INDEX_PRESENCE: + report_id = prox_state->prox_attr.report_id; +- address = +- HID_USAGE_SENSOR_HUMAN_PRESENCE; ++ min = prox_state->prox_attr.logical_minimum; ++ address = HID_USAGE_SENSOR_HUMAN_PRESENCE; + break; + default: + report_id = -1; +@@ -95,7 +96,8 @@ static int prox_read_raw(struct iio_dev + prox_state->common_attributes.hsdev, + HID_USAGE_SENSOR_PROX, address, + report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, ++ min < 0); + hid_sensor_power_state(&prox_state->common_attributes, + false); + } else { +--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c ++++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c +@@ -163,21 +163,23 @@ static int magn_3d_read_raw(struct iio_d + int report_id = -1; + u32 address; + int ret_type; ++ s32 min; + + *val = 0; + *val2 = 0; + switch (mask) { + case 0: + hid_sensor_power_state(&magn_state->magn_flux_attributes, true); +- report_id = +- magn_state->magn[chan->address].report_id; ++ report_id = magn_state->magn[chan->address].report_id; ++ min = magn_state->magn[chan->address].logical_minimum; + address = magn_3d_addresses[chan->address]; + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + magn_state->magn_flux_attributes.hsdev, + HID_USAGE_SENSOR_COMPASS_3D, address, + report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, ++ min < 0); + else { + *val = 0; + hid_sensor_power_state( +--- a/drivers/iio/orientation/hid-sensor-incl-3d.c ++++ b/drivers/iio/orientation/hid-sensor-incl-3d.c +@@ -111,21 +111,23 @@ static int incl_3d_read_raw(struct iio_d + int report_id = -1; + u32 address; + int ret_type; ++ s32 min; + + *val = 0; + *val2 = 0; + switch (mask) { + case IIO_CHAN_INFO_RAW: + hid_sensor_power_state(&incl_state->common_attributes, true); +- report_id = +- incl_state->incl[chan->scan_index].report_id; ++ report_id = incl_state->incl[chan->scan_index].report_id; ++ min = incl_state->incl[chan->scan_index].logical_minimum; + address = incl_3d_addresses[chan->scan_index]; + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + incl_state->common_attributes.hsdev, + HID_USAGE_SENSOR_INCLINOMETER_3D, address, + report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, ++ min < 0); + else { + hid_sensor_power_state(&incl_state->common_attributes, + false); +--- a/drivers/iio/pressure/hid-sensor-press.c ++++ b/drivers/iio/pressure/hid-sensor-press.c +@@ -77,6 +77,7 @@ static int press_read_raw(struct iio_dev + int report_id = -1; + u32 address; + int ret_type; ++ s32 min; + + *val = 0; + *val2 = 0; +@@ -85,8 +86,8 @@ static int press_read_raw(struct iio_dev + switch (chan->scan_index) { + case CHANNEL_SCAN_INDEX_PRESSURE: + report_id = press_state->press_attr.report_id; +- address = +- HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE; ++ min = press_state->press_attr.logical_minimum; ++ address = HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE; + break; + default: + report_id = -1; +@@ -99,7 +100,8 @@ static int press_read_raw(struct iio_dev + press_state->common_attributes.hsdev, + HID_USAGE_SENSOR_PRESSURE, address, + report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, ++ min < 0); + hid_sensor_power_state(&press_state->common_attributes, + false); + } else { +--- a/drivers/iio/temperature/hid-sensor-temperature.c ++++ b/drivers/iio/temperature/hid-sensor-temperature.c +@@ -76,7 +76,8 @@ static int temperature_read_raw(struct i + HID_USAGE_SENSOR_TEMPERATURE, + HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE, + temp_st->temperature_attr.report_id, +- SENSOR_HUB_SYNC); ++ SENSOR_HUB_SYNC, ++ temp_st->temperature_attr.logical_minimum < 0); + hid_sensor_power_state( + &temp_st->common_attributes, + false); +--- a/drivers/rtc/rtc-hid-sensor-time.c ++++ b/drivers/rtc/rtc-hid-sensor-time.c +@@ -213,7 +213,7 @@ static int hid_rtc_read_time(struct devi + /* get a report with all values through requesting one value */ + sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev, + HID_USAGE_SENSOR_TIME, hid_time_addresses[0], +- time_state->info[0].report_id, SENSOR_HUB_SYNC); ++ time_state->info[0].report_id, SENSOR_HUB_SYNC, false); + /* wait for all values (event) */ + ret = wait_for_completion_killable_timeout( + &time_state->comp_last_time, HZ*6); +--- a/include/linux/hid-sensor-hub.h ++++ b/include/linux/hid-sensor-hub.h +@@ -177,6 +177,7 @@ int sensor_hub_input_get_attribute_info( + * @attr_usage_id: Attribute usage id as per spec + * @report_id: Report id to look for + * @flag: Synchronous or asynchronous read ++* @is_signed: If true then fields < 32 bits will be sign-extended + * + * Issues a synchronous or asynchronous read request for an input attribute. + * Returns data upto 32 bits. +@@ -190,7 +191,8 @@ enum sensor_hub_read_flags { + int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + u32 attr_usage_id, u32 report_id, +- enum sensor_hub_read_flags flag ++ enum sensor_hub_read_flags flag, ++ bool is_signed + ); + + /** diff --git a/patches.fixes/irqchip-gic-v3-its-Plug-allocation-race-for-devices-.patch b/patches.fixes/irqchip-gic-v3-its-Plug-allocation-race-for-devices-.patch new file mode 100644 index 0000000..8594e32 --- /dev/null +++ b/patches.fixes/irqchip-gic-v3-its-Plug-allocation-race-for-devices-.patch @@ -0,0 +1,149 @@ +From 9791ec7df0e7b4d80706ccea8f24b6542f6059e9 Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Tue, 29 Jan 2019 10:02:33 +0000 +Subject: [PATCH] irqchip/gic-v3-its: Plug allocation race for devices sharing a DevID +Git-commit: 9791ec7df0e7b4d80706ccea8f24b6542f6059e9 +Patch-mainline: v5.0-rc6 +References: bsc#1111666 + +On systems or VMs where multiple devices share a single DevID +(because they sit behind a PCI bridge, or because the HW is +broken in funky ways), we reuse the save its_device structure +in order to reflect this. + +It turns out that there is a distinct lack of locking when looking +up the its_device, and two device being probed concurrently can result +in double allocations. That's obviously not nice. + +A solution for this is to have a per-ITS mutex that serializes device +allocation. + +A similar issue exists on the freeing side, which can run concurrently +with the allocation. On top of now taking the appropriate lock, we +also make sure that a shared device is never freed, as we have no way +to currently track the life cycle of such object. + +Reported-by: Zheng Xiang +Tested-by: Zheng Xiang +Cc: stable@vger.kernel.org +Signed-off-by: Marc Zyngier +Acked-by: Takashi Iwai + +--- + drivers/irqchip/irq-gic-v3-its.c | 32 +++++++++++++++++++++++++++----- + 1 file changed, 27 insertions(+), 5 deletions(-) + +diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c +index 36181197d5e0..f25ec92f23ee 100644 +--- a/drivers/irqchip/irq-gic-v3-its.c ++++ b/drivers/irqchip/irq-gic-v3-its.c +@@ -97,9 +97,14 @@ struct its_device; + * The ITS structure - contains most of the infrastructure, with the + * top-level MSI domain, the command queue, the collections, and the + * list of devices writing to it. ++ * ++ * dev_alloc_lock has to be taken for device allocations, while the ++ * spinlock must be taken to parse data structures such as the device ++ * list. + */ + struct its_node { + raw_spinlock_t lock; ++ struct mutex dev_alloc_lock; + struct list_head entry; + void __iomem *base; + phys_addr_t phys_base; +@@ -156,6 +161,7 @@ struct its_device { + void *itt; + u32 nr_ites; + u32 device_id; ++ bool shared; + }; + + static struct { +@@ -2469,6 +2475,7 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev, + struct its_device *its_dev; + struct msi_domain_info *msi_info; + u32 dev_id; ++ int err = 0; + + /* + * We ignore "dev" entierely, and rely on the dev_id that has +@@ -2491,6 +2498,7 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev, + return -EINVAL; + } + ++ mutex_lock(&its->dev_alloc_lock); + its_dev = its_find_device(its, dev_id); + if (its_dev) { + /* +@@ -2498,18 +2506,22 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev, + * another alias (PCI bridge of some sort). No need to + * create the device. + */ ++ its_dev->shared = true; + pr_debug("Reusing ITT for devID %x\n", dev_id); + goto out; + } + + its_dev = its_create_device(its, dev_id, nvec, true); +- if (!its_dev) +- return -ENOMEM; ++ if (!its_dev) { ++ err = -ENOMEM; ++ goto out; ++ } + + pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec)); + out: ++ mutex_unlock(&its->dev_alloc_lock); + info->scratchpad[0].ptr = its_dev; +- return 0; ++ return err; + } + + static struct msi_domain_ops its_msi_domain_ops = { +@@ -2613,6 +2625,7 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, + { + struct irq_data *d = irq_domain_get_irq_data(domain, virq); + struct its_device *its_dev = irq_data_get_irq_chip_data(d); ++ struct its_node *its = its_dev->its; + int i; + + for (i = 0; i < nr_irqs; i++) { +@@ -2627,8 +2640,14 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, + irq_domain_reset_irq_data(data); + } + +- /* If all interrupts have been freed, start mopping the floor */ +- if (bitmap_empty(its_dev->event_map.lpi_map, ++ mutex_lock(&its->dev_alloc_lock); ++ ++ /* ++ * If all interrupts have been freed, start mopping the ++ * floor. This is conditionned on the device not being shared. ++ */ ++ if (!its_dev->shared && ++ bitmap_empty(its_dev->event_map.lpi_map, + its_dev->event_map.nr_lpis)) { + its_lpi_free(its_dev->event_map.lpi_map, + its_dev->event_map.lpi_base, +@@ -2640,6 +2659,8 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, + its_free_device(its_dev); + } + ++ mutex_unlock(&its->dev_alloc_lock); ++ + irq_domain_free_irqs_parent(domain, virq, nr_irqs); + } + +@@ -3549,6 +3570,7 @@ static int __init its_probe_one(struct resource *res, + } + + raw_spin_lock_init(&its->lock); ++ mutex_init(&its->dev_alloc_lock); + INIT_LIST_HEAD(&its->entry); + INIT_LIST_HEAD(&its->its_device_list); + typer = gic_read_typer(its_base + GITS_TYPER); +-- +2.16.4 + diff --git a/series.conf b/series.conf index 7f9889c..127ab32 100644 --- a/series.conf +++ b/series.conf @@ -42135,6 +42135,7 @@ patches.drivers/staging-rtl8723bs-Add-missing-return-for-cfg80211_rt.patch patches.drivers/staging-vchiq_arm-fix-compat-VCHIQ_IOC_AWAIT_COMPLET.patch patches.drivers/iio-st_magn-Fix-enable-device-after-trigger.patch + patches.drivers/iio-hid-sensors-Fix-IIO_CHAN_INFO_RAW-returning-wron.patch patches.suse/msft-hv-1801-Drivers-hv-vmbus-check-the-creation_status-in-vmbus_.patch patches.drivers/misc-mic-scif-fix-copy-paste-error-in-scif_create_re.patch patches.fixes/unifdef-use-memcpy-instead-of-strncpy.patch @@ -43267,6 +43268,7 @@ patches.drivers/pinctrl-sh-pfc-sh7734-Fix-shifted-values-in-IPSR10.patch patches.drivers/pinctrl-freescale-break-dependency-on-soc_imx8mq-for-i-mx8mq.patch patches.drivers/rtc-m41t80-Correct-alarm-month-range-with-RTC-reads.patch + patches.drivers/dmaengine-dw-dmac-implement-dma-protection-control-s.patch patches.drivers/dmaengine-xilinx_dma-Remove-__aligned-attribute-on-z.patch patches.drivers/revert-iommu-io-pgtable-arm-check-for-v7s-incapable-systems patches.drivers/iommu-vt-d-handle-domain-agaw-being-less-than-iommu-agaw @@ -43601,6 +43603,7 @@ patches.arch/powerpc-papr_scm-Use-the-correct-bind-address.patch patches.drivers/dt-bindings-imx8mq-number-clocks-consecutively.patch patches.fixes/nvme-llock-NS-list-changes-while-handling-command-ef.patch + patches.fixes/irqchip-gic-v3-its-Plug-allocation-race-for-devices-.patch patches.fixes/irqchip-gic-v3-its-Gracefully-fail-on-LPI-exhaustion.patch patches.fixes/irqchip-gic-v3-its-Fix-ITT_entry_size-accessor.patch patches.arch/x86-mce-initialize-mce-bank-in-the-case-of-a-fatal-error-in-mce_no_way_out.patch