From a786ef152cdcfebc923a67f63c7815806eefcf81 Mon Sep 17 00:00:00 2001 From: Daniel Vacek Date: Mon, 5 Nov 2018 18:10:40 +0100 Subject: x86/tsc: Make calibration refinement more robust The threshold in tsc_read_refs() is constant which may favor slower CPUs but may not be optimal for simple reading of reference on faster ones. Hence make it proportional to tsc_khz when available to compensate for this. The threshold guards against any disturbance like IRQs, NMIs, SMIs or CPU stealing by host on guest systems so rename it accordingly and fix comments as well. Also on some systems there is noticeable DMI bus contention at some point during boot keeping the readout failing (observed with about one in ~300 boots when testing). In that case retry also the second readout instead of simply bailing out unrefined. Usually the next second the readout returns fast just fine without any issues. Signed-off-by: Daniel Vacek Signed-off-by: Thomas Gleixner Cc: Borislav Petkov Cc: "H. Peter Anvin" Link: https://lkml.kernel.org/r/1541437840-29293-1-git-send-email-neelx@redhat.com --- arch/x86/kernel/tsc.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index e9f777bfed40..3fae23834069 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -297,15 +297,16 @@ static int __init tsc_setup(char *str) __setup("tsc=", tsc_setup); -#define MAX_RETRIES 5 -#define SMI_TRESHOLD 50000 +#define MAX_RETRIES 5 +#define TSC_DEFAULT_THRESHOLD 0x20000 /* - * Read TSC and the reference counters. Take care of SMI disturbance + * Read TSC and the reference counters. Take care of any disturbances */ static u64 tsc_read_refs(u64 *p, int hpet) { u64 t1, t2; + u64 thresh = tsc_khz ? tsc_khz >> 5 : TSC_DEFAULT_THRESHOLD; int i; for (i = 0; i < MAX_RETRIES; i++) { @@ -315,7 +316,7 @@ static u64 tsc_read_refs(u64 *p, int hpet) else *p = acpi_pm_read_early(); t2 = get_cycles(); - if ((t2 - t1) < SMI_TRESHOLD) + if ((t2 - t1) < thresh) return t2; } return ULLONG_MAX; @@ -703,15 +704,15 @@ static unsigned long pit_hpet_ptimer_calibrate_cpu(void) * zero. In each wait loop iteration we read the TSC and check * the delta to the previous read. We keep track of the min * and max values of that delta. The delta is mostly defined - * by the IO time of the PIT access, so we can detect when a - * SMI/SMM disturbance happened between the two reads. If the + * by the IO time of the PIT access, so we can detect when + * any disturbance happened between the two reads. If the * maximum time is significantly larger than the minimum time, * then we discard the result and have another try. * * 2) Reference counter. If available we use the HPET or the * PMTIMER as a reference to check the sanity of that value. * We use separate TSC readouts and check inside of the - * reference read for a SMI/SMM disturbance. We dicard + * reference read for any possible disturbance. We dicard * disturbed values here as well. We do that around the PIT * calibration delay loop as we have to wait for a certain * amount of time anyway. @@ -744,7 +745,7 @@ static unsigned long pit_hpet_ptimer_calibrate_cpu(void) if (ref1 == ref2) continue; - /* Check, whether the sampling was disturbed by an SMI */ + /* Check, whether the sampling was disturbed */ if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) continue; @@ -1268,7 +1269,7 @@ static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work); */ static void tsc_refine_calibration_work(struct work_struct *work) { - static u64 tsc_start = -1, ref_start; + static u64 tsc_start = ULLONG_MAX, ref_start; static int hpet; u64 tsc_stop, ref_stop, delta; unsigned long freq; @@ -1283,14 +1284,15 @@ static void tsc_refine_calibration_work(struct work_struct *work) * delayed the first time we expire. So set the workqueue * again once we know timers are working. */ - if (tsc_start == -1) { + if (tsc_start == ULLONG_MAX) { +restart: /* * Only set hpet once, to avoid mixing hardware * if the hpet becomes enabled later. */ hpet = is_hpet_enabled(); - schedule_delayed_work(&tsc_irqwork, HZ); tsc_start = tsc_read_refs(&ref_start, hpet); + schedule_delayed_work(&tsc_irqwork, HZ); return; } @@ -1300,9 +1302,9 @@ static void tsc_refine_calibration_work(struct work_struct *work) if (ref_start == ref_stop) goto out; - /* Check, whether the sampling was disturbed by an SMI */ - if (tsc_start == ULLONG_MAX || tsc_stop == ULLONG_MAX) - goto out; + /* Check, whether the sampling was disturbed */ + if (tsc_stop == ULLONG_MAX) + goto restart; delta = tsc_stop - tsc_start; delta *= 1000000LL; -- cgit v1.2.3-58-ga151 From e4c8ae3e3d6d473bfbfbb5db234792b9f8ddab3b Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 9 Nov 2018 10:48:57 +0100 Subject: backlight: pwm_bl: Re-add driver internal enabled tracking Commit e6bcca0890b9 ("backlight: pwm_bl: Switch to using "atomic" PWM API") removed the driver internal enabled tracking in favor of simply checking the pwm state. This can lead to issues as all of gpio-, regulator- and pwm-state are used to determine the initial state and the bootloader or kernel can leave them in an inconsistent state at boot. In my case on rk3399-kevin, the pwm backlight is build as module and the kernel disables the supply regulator as unused while keeping the pwm running thus pwm_bl calling pwm_backlight_power_off() during probe and creating an unmatched regulator-disable call, as it never got enabled from the pwm-bl before. To prevent these consistency issues, reintroduce the driver-internal tracking of the enabled state. Fixes: e6bcca0890b9 ("backlight: pwm_bl: Switch to using "atomic" PWM API") Signed-off-by: Heiko Stuebner Acked-by: Thierry Reding Acked-by: Daniel Thompson Signed-off-by: Lee Jones --- drivers/video/backlight/pwm_bl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 678b27063198..bcd08b41765d 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -30,6 +30,7 @@ struct pwm_bl_data { struct device *dev; unsigned int lth_brightness; unsigned int *levels; + bool enabled; struct regulator *power_supply; struct gpio_desc *enable_gpio; unsigned int scale; @@ -50,7 +51,7 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb) int err; pwm_get_state(pb->pwm, &state); - if (state.enabled) + if (pb->enabled) return; err = regulator_enable(pb->power_supply); @@ -65,6 +66,8 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb) if (pb->enable_gpio) gpiod_set_value_cansleep(pb->enable_gpio, 1); + + pb->enabled = true; } static void pwm_backlight_power_off(struct pwm_bl_data *pb) @@ -72,7 +75,7 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) struct pwm_state state; pwm_get_state(pb->pwm, &state); - if (!state.enabled) + if (!pb->enabled) return; if (pb->enable_gpio) @@ -86,6 +89,7 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb) pwm_apply_state(pb->pwm, &state); regulator_disable(pb->power_supply); + pb->enabled = false; } static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness) @@ -483,6 +487,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->check_fb = data->check_fb; pb->exit = data->exit; pb->dev = &pdev->dev; + pb->enabled = false; pb->post_pwm_on_delay = data->post_pwm_on_delay; pb->pwm_off_delay = data->pwm_off_delay; -- cgit v1.2.3-58-ga151 From 61170ee9386888f1e6f7e9cc58e8d9a8c2a3c1dd Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 12 Nov 2018 10:02:57 +0100 Subject: backlight: pwm_bl: Fix devicetree parsing with auto-generated brightness tables Commit 88ba95bedb79 ("backlight: pwm_bl: Compute brightness of LED linearly to human eye") made the parse-dt function return early when using an auto- generated brightness-table, but didn't take into account that some more settings were handled below the brightness handling, like power-on-delays and also setting the pdata enable-gpio to -EINVAL. This surfaces for example in the case of a backlight without any enable-gpio which then tries to use gpio-0 in error. Fix this by simply moving the trailing settings above the brightness handling. Fixes: 88ba95bedb79 ("backlight: pwm_bl: Compute brightness of LED linearly to human eye") Signed-off-by: Heiko Stuebner Acked-by: Daniel Thompson Signed-off-by: Lee Jones --- drivers/video/backlight/pwm_bl.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index bcd08b41765d..b7b5b31f3824 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -272,6 +272,16 @@ static int pwm_backlight_parse_dt(struct device *dev, memset(data, 0, sizeof(*data)); + /* + * These values are optional and set as 0 by default, the out values + * are modified only if a valid u32 value can be decoded. + */ + of_property_read_u32(node, "post-pwm-on-delay-ms", + &data->post_pwm_on_delay); + of_property_read_u32(node, "pwm-off-delay-ms", &data->pwm_off_delay); + + data->enable_gpio = -EINVAL; + /* * Determine the number of brightness levels, if this property is not * set a default table of brightness levels will be used. @@ -384,15 +394,6 @@ static int pwm_backlight_parse_dt(struct device *dev, data->max_brightness--; } - /* - * These values are optional and set as 0 by default, the out values - * are modified only if a valid u32 value can be decoded. - */ - of_property_read_u32(node, "post-pwm-on-delay-ms", - &data->post_pwm_on_delay); - of_property_read_u32(node, "pwm-off-delay-ms", &data->pwm_off_delay); - - data->enable_gpio = -EINVAL; return 0; } -- cgit v1.2.3-58-ga151 From b40ee006fe6a8a25093434e5d394128c356a48f3 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Mon, 3 Dec 2018 13:31:17 +0530 Subject: mfd: ti_am335x_tscadc: Use PLATFORM_DEVID_AUTO while registering mfd cells Use PLATFORM_DEVID_AUTO to number mfd cells while registering, so that different instances are uniquely identified. This is required in order to support registering of multiple instances of same ti_am335x_tscadc IP. Signed-off-by: Vignesh R Signed-off-by: Lee Jones --- drivers/mfd/ti_am335x_tscadc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index c2d47d78705b..fd111296b959 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -264,8 +264,9 @@ static int ti_tscadc_probe(struct platform_device *pdev) cell->pdata_size = sizeof(tscadc); } - err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells, - tscadc->used_cells, NULL, 0, NULL); + err = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, + tscadc->cells, tscadc->used_cells, NULL, + 0, NULL); if (err < 0) goto err_disable_clk; -- cgit v1.2.3-58-ga151 From 4b3ab9372ffa569827c8f7b7ffc7b69ba544a3bd Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Mon, 3 Dec 2018 13:31:18 +0530 Subject: iio: adc: ti_am335x_tscadc: Improve accuracy of measurement When performing single ended measurements with TSCADC, its recommended to set negative input (SEL_INM_SWC_3_0) of ADC step to ADC's VREFN in the corresponding STEP_CONFIGx register. Also, the positive(SEL_RFP_SWC_2_0) and negative(SEL_RFM_SWC_1_0) reference voltage for ADC step needs to be set to VREFP and VREFN respectively in STEP_CONFIGx register. Without these changes, there may be variation of as much as ~2% in the ADC's digital output which is bad for precise measurement. Signed-off-by: Vignesh R Acked-by: Jonathan Cameron Signed-off-by: Lee Jones --- drivers/iio/adc/ti_am335x_adc.c | 5 ++++- include/linux/mfd/ti_am335x_tscadc.h | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index cafb1dcadc48..9d984f2a8ba7 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -142,7 +142,10 @@ static void tiadc_step_config(struct iio_dev *indio_dev) stepconfig |= STEPCONFIG_MODE_SWCNT; tiadc_writel(adc_dev, REG_STEPCONFIG(steps), - stepconfig | STEPCONFIG_INP(chan)); + stepconfig | STEPCONFIG_INP(chan) | + STEPCONFIG_INM_ADCREFM | + STEPCONFIG_RFP_VREFP | + STEPCONFIG_RFM_VREFN); if (adc_dev->open_delay[i] > STEPDELAY_OPEN_MASK) { dev_warn(dev, "chan %d open delay truncating to 0x3FFFF\n", diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index b9a53e013bff..483168403ae5 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -78,6 +78,8 @@ #define STEPCONFIG_YNN BIT(8) #define STEPCONFIG_XNP BIT(9) #define STEPCONFIG_YPN BIT(10) +#define STEPCONFIG_RFP(val) ((val) << 12) +#define STEPCONFIG_RFP_VREFP (0x3 << 12) #define STEPCONFIG_INM_MASK (0xF << 15) #define STEPCONFIG_INM(val) ((val) << 15) #define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8) @@ -86,6 +88,8 @@ #define STEPCONFIG_INP_AN4 STEPCONFIG_INP(4) #define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8) #define STEPCONFIG_FIFO1 BIT(26) +#define STEPCONFIG_RFM(val) ((val) << 23) +#define STEPCONFIG_RFM_VREFN (0x3 << 23) /* Delay register */ #define STEPDELAY_OPEN_MASK (0x3FFFF << 0) -- cgit v1.2.3-58-ga151 From d999c0ec2498e54b9328db6b2c1037710025add1 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 30 Nov 2018 13:14:50 -0800 Subject: x86/hpet: Remove unused FSEC_PER_NSEC define The FSEC_PER_NSEC macro has had zero users since commit ab0e08f15d23 ("x86: hpet: Cleanup the clockevents init and register code"). Remove it. Signed-off-by: Roland Dreier Signed-off-by: Borislav Petkov Acked-by: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: x86-ml Link: https://lkml.kernel.org/r/20181130211450.5200-1-roland@purestorage.com --- arch/x86/kernel/hpet.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index b0acb22e5a46..dfd3aca82c61 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -21,10 +21,6 @@ #define HPET_MASK CLOCKSOURCE_MASK(32) -/* FSEC = 10^-15 - NSEC = 10^-9 */ -#define FSEC_PER_NSEC 1000000L - #define HPET_DEV_USED_BIT 2 #define HPET_DEV_USED (1 << HPET_DEV_USED_BIT) #define HPET_DEV_VALID 0x8 -- cgit v1.2.3-58-ga151 From 3cee7a7d05b11038c8b5fa093e45c6f839ffc867 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 Dec 2018 13:50:44 -0600 Subject: backlight: 88pm860x_bl: Use of_node_name_eq for node name comparisons Convert string compares of DT node names to use of_node_name_eq helper instead. This removes direct access to the node name pointer. For instances using of_node_cmp, this has the side effect of now using case sensitive comparisons. This should not matter for any FDT based system which this is. Signed-off-by: Rob Herring Acked-by: Daniel Thompson Signed-off-by: Lee Jones --- drivers/video/backlight/88pm860x_bl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 6d8dc2c77520..51e0c4be08df 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -174,7 +174,7 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev, return -ENODEV; } for_each_child_of_node(nproot, np) { - if (!of_node_cmp(np->name, name)) { + if (of_node_name_eq(np, name)) { of_property_read_u32(np, "marvell,88pm860x-iset", &iset); data->iset = PM8606_WLED_CURRENT(iset); -- cgit v1.2.3-58-ga151 From 99c66bc051e7407fe0bf0607b142ec0be1a1d1dd Mon Sep 17 00:00:00 2001 From: "Kristian H. Kristensen" Date: Wed, 19 Dec 2018 08:57:41 -0800 Subject: drm/msm: Unblock writer if reader closes file Prevents deadlock when fifo is full and reader closes file. Signed-off-by: Kristian H. Kristensen Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_rd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index b5672061ae08..d990b5f5154c 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -115,7 +115,9 @@ static void rd_write(struct msm_rd_state *rd, const void *buf, int sz) char *fptr = &fifo->buf[fifo->head]; int n; - wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0); + wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0 || !rd->open); + if (!rd->open) + return; /* Note that smp_load_acquire() is not strictly required * as CIRC_SPACE_TO_END() does not access the tail more @@ -213,7 +215,10 @@ out: static int rd_release(struct inode *inode, struct file *file) { struct msm_rd_state *rd = inode->i_private; + rd->open = false; + wake_up_all(&rd->fifo_event); + return 0; } -- cgit v1.2.3-58-ga151 From 74d4b4e0f43e5ffb61b63f4e3cfcfad3d7398765 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Thu, 27 Dec 2018 10:44:43 +0200 Subject: regmap: regmap-irq: silently ignore unsupported type settings Do not return error if irq-type setting is requested for controlloer which does not support this. This is how regmap-irq has previously handled the undupported type settings and existing drivers seem to be upset if failure is now reported. Fixes: 1c2928e3e321 ("regmap: regmap-irq/gpio-max77620: add level-irq support") Signed-off-by: Matti Vaittinen Reported-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 1bd1145ad8b5..d2d0014b0d23 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -258,7 +258,7 @@ static int regmap_irq_set_type(struct irq_data *data, unsigned int type) const struct regmap_irq_type *t = &irq_data->type; if ((t->types_supported & type) != type) - return -ENOTSUPP; + return 0; reg = t->type_reg_offset / map->reg_stride; -- cgit v1.2.3-58-ga151 From 2e61069b056f7ac3cde5f84a4be8aa703b57089d Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sun, 30 Dec 2018 20:40:05 +0000 Subject: ACPI: Fix build failure when CONFIG_NLS is set to 'n' Observing link failure as follows when CONFIG_ACPI is set but both CONFIG_NLS and CONFIG_PCI are no set: drivers/acpi/device_sysfs.o: In function `description_show': device_sysfs.c:(.text+0x48a): undefined reference to `utf16s_to_utf8s' This issue was previously addressed implicitly by commit 8a226e00eeed (PCI: pci-label: Fix build failure when CONFIG_NLS is set to 'm' by allmodconfig) causing PCI_LABEL to be selected when ACPI was set which caused NLS to be selected too in that case. However, after commit 5d32a66541c46 (PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set) it is possible to build ACPI support without PCI, so make ACPI select NLS directly to cover that case. Fixes: 5d32a66541c46 (PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set) Signed-off-by: Sinan Kaya [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 7b65a807b3dd..90ff0a47c12e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -10,6 +10,7 @@ menuconfig ACPI bool "ACPI (Advanced Configuration and Power Interface) Support" depends on ARCH_SUPPORTS_ACPI select PNP + select NLS default y if X86 help Advanced Configuration and Power Interface (ACPI) support for -- cgit v1.2.3-58-ga151 From 7d7b467cb95bf29597b417d4990160d4ea6d69b9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 18:25:00 +0100 Subject: ACPI: power: Skip duplicate power resource references in _PRx Some ACPI tables contain duplicate power resource references like this: Name (_PR0, Package (0x04) // _PR0: Power Resources for D0 { P28P, P18P, P18P, CLK4 }) This causes a WARN_ON in sysfs_add_link_to_group() because we end up adding a link to the same acpi_device twice: sysfs: cannot create duplicate filename '/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/808622C1:00/OVTI2680:00/power_resources_D0/LNXPOWER:0a' CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.12-301.fc29.x86_64 #1 Hardware name: Insyde CherryTrail/Type2 - Board Product Name, BIOS jumperx.T87.KFBNEEA02 04/13/2016 Call Trace: dump_stack+0x5c/0x80 sysfs_warn_dup.cold.3+0x17/0x2a sysfs_do_create_link_sd.isra.2+0xa9/0xb0 sysfs_add_link_to_group+0x30/0x50 acpi_power_expose_list+0x74/0xa0 acpi_power_add_remove_device+0x50/0xa0 acpi_add_single_object+0x26b/0x5f0 acpi_bus_check_add+0xc4/0x250 ... To address this issue, make acpi_extract_power_resources() check for duplicates and simply skip them when found. Cc: All applicable Signed-off-by: Hans de Goede [ rjw: Subject & changelog, comments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 1b475bc1ae16..665e93ca0b40 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -131,6 +131,23 @@ void acpi_power_resources_list_free(struct list_head *list) } } +static bool acpi_power_resource_is_dup(union acpi_object *package, + unsigned int start, unsigned int i) +{ + acpi_handle rhandle, dup; + unsigned int j; + + /* The caller is expected to check the package element types */ + rhandle = package->package.elements[i].reference.handle; + for (j = start; j < i; j++) { + dup = package->package.elements[j].reference.handle; + if (dup == rhandle) + return true; + } + + return false; +} + int acpi_extract_power_resources(union acpi_object *package, unsigned int start, struct list_head *list) { @@ -150,6 +167,11 @@ int acpi_extract_power_resources(union acpi_object *package, unsigned int start, err = -ENODEV; break; } + + /* Some ACPI tables contain duplicate power resource references */ + if (acpi_power_resource_is_dup(package, start, i)) + continue; + err = acpi_add_power_resource(rhandle); if (err) break; -- cgit v1.2.3-58-ga151 From b79470b64fa9266948d1ce8d825ced94c4f63293 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Fri, 21 Dec 2018 15:06:29 -0800 Subject: pvcalls-front: read all data before closing the connection When a connection is closing in_error is set to ENOTCONN. There could still be outstanding data on the ring left by the backend. Before closing the connection on the frontend side, drain the ring. Signed-off-by: Stefano Stabellini Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky --- drivers/xen/pvcalls-front.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 77224d8f3e6f..e5d95aab2cb8 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -560,15 +560,13 @@ static int __read_ring(struct pvcalls_data_intf *intf, error = intf->in_error; /* get pointers before reading from the ring */ virt_rmb(); - if (error < 0) - return error; size = pvcalls_queued(prod, cons, array_size); masked_prod = pvcalls_mask(prod, array_size); masked_cons = pvcalls_mask(cons, array_size); if (size == 0) - return 0; + return error ?: size; if (len > size) len = size; -- cgit v1.2.3-58-ga151 From 96283f9a084e23d7cda2d3c5d1ffa6df6cf1ecec Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Fri, 21 Dec 2018 15:06:30 -0800 Subject: pvcalls-front: don't try to free unallocated rings inflight_req_id is 0 when initialized. If inflight_req_id is 0, there is no accept_map to free. Fix the check in pvcalls_front_release. Signed-off-by: Stefano Stabellini Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky --- drivers/xen/pvcalls-front.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index e5d95aab2cb8..4f3d664b3f39 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -1030,8 +1030,8 @@ int pvcalls_front_release(struct socket *sock) spin_lock(&bedata->socket_lock); list_del(&map->list); spin_unlock(&bedata->socket_lock); - if (READ_ONCE(map->passive.inflight_req_id) != - PVCALLS_INVALID_ID) { + if (READ_ONCE(map->passive.inflight_req_id) != PVCALLS_INVALID_ID && + READ_ONCE(map->passive.inflight_req_id) != 0) { pvcalls_front_free_map(bedata, map->passive.accept_map); } -- cgit v1.2.3-58-ga151 From beee1fbe8f7d57d6ebaa5188f9f4db89c2077196 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Fri, 21 Dec 2018 15:06:31 -0800 Subject: pvcalls-front: properly allocate sk Don't use kzalloc: it ends up leaving sk->sk_prot not properly initialized. Use sk_alloc instead and define our own trivial struct proto. Signed-off-by: Stefano Stabellini Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky --- drivers/xen/pvcalls-front.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 4f3d664b3f39..01588582ae66 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -31,6 +31,12 @@ #define PVCALLS_NR_RSP_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE) #define PVCALLS_FRONT_MAX_SPIN 5000 +static struct proto pvcalls_proto = { + .name = "PVCalls", + .owner = THIS_MODULE, + .obj_size = sizeof(struct sock), +}; + struct pvcalls_bedata { struct xen_pvcalls_front_ring ring; grant_ref_t ref; @@ -837,7 +843,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) received: map2->sock = newsock; - newsock->sk = kzalloc(sizeof(*newsock->sk), GFP_KERNEL); + newsock->sk = sk_alloc(sock_net(sock->sk), PF_INET, GFP_KERNEL, &pvcalls_proto, false); if (!newsock->sk) { bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; map->passive.inflight_req_id = PVCALLS_INVALID_ID; -- cgit v1.2.3-58-ga151 From d90a1ca60a1eccb4383fe203c76223ab4c0799ed Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Fri, 21 Dec 2018 15:06:32 -0800 Subject: pvcalls-front: don't return error when the ring is full When the ring is full, size == array_size. It is not an error condition, so simply return 0 instead of an error. Signed-off-by: Stefano Stabellini Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky --- drivers/xen/pvcalls-front.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 01588582ae66..1a893a164349 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -475,8 +475,10 @@ static int __write_ring(struct pvcalls_data_intf *intf, virt_mb(); size = pvcalls_queued(prod, cons, array_size); - if (size >= array_size) + if (size > array_size) return -EINVAL; + if (size == array_size) + return 0; if (len > array_size - size) len = array_size - size; -- cgit v1.2.3-58-ga151 From e6587cdbd732eacb4c7ce592ed46f7bbcefb655f Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Fri, 21 Dec 2018 15:06:33 -0800 Subject: pvcalls-back: set -ENOTCONN in pvcalls_conn_back_read When a connection is closing we receive on pvcalls_sk_state_change notification. Instead of setting the connection as closed immediately (-ENOTCONN), let's read one more time from it: pvcalls_conn_back_read will set the connection as closed when necessary. That way, we avoid races between pvcalls_sk_state_change and pvcalls_back_ioworker. Signed-off-by: Stefano Stabellini Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky --- drivers/xen/pvcalls-back.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c index 2e5d845b5091..71b628774c6f 100644 --- a/drivers/xen/pvcalls-back.c +++ b/drivers/xen/pvcalls-back.c @@ -160,9 +160,10 @@ static void pvcalls_conn_back_read(void *opaque) /* write the data, then modify the indexes */ virt_wmb(); - if (ret < 0) + if (ret < 0) { + atomic_set(&map->read, 0); intf->in_error = ret; - else + } else intf->in_prod = prod + ret; /* update the indexes, then notify the other end */ virt_wmb(); @@ -288,7 +289,7 @@ static void pvcalls_sk_state_change(struct sock *sock) return; intf = map->ring; - intf->in_error = -ENOTCONN; + atomic_inc(&map->read); notify_remote_via_irq(map->irq); } -- cgit v1.2.3-58-ga151 From 125892edfe69915a227d8d125ff0e1cd713178f4 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 1 Jan 2019 18:54:26 +0900 Subject: inotify: Fix fd refcount leak in inotify_add_watch(). Commit 4d97f7d53da7dc83 ("inotify: Add flag IN_MASK_CREATE for inotify_add_watch()") forgot to call fdput() before bailing out. Fixes: 4d97f7d53da7dc83 ("inotify: Add flag IN_MASK_CREATE for inotify_add_watch()") CC: stable@vger.kernel.org Signed-off-by: Tetsuo Handa Reviewed-by: Amir Goldstein Signed-off-by: Jan Kara --- fs/notify/inotify/inotify_user.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 105576daca4a..798f1253141a 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -724,8 +724,10 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname, return -EBADF; /* IN_MASK_ADD and IN_MASK_CREATE don't make sense together */ - if (unlikely((mask & IN_MASK_ADD) && (mask & IN_MASK_CREATE))) - return -EINVAL; + if (unlikely((mask & IN_MASK_ADD) && (mask & IN_MASK_CREATE))) { + ret = -EINVAL; + goto fput_and_out; + } /* verify that this is indeed an inotify instance */ if (unlikely(f.file->f_op != &inotify_fops)) { -- cgit v1.2.3-58-ga151 From 47bbcc1e92385b595e92e11e29076185c820a0b8 Mon Sep 17 00:00:00 2001 From: Emily Deng Date: Wed, 26 Dec 2018 18:09:33 +0800 Subject: drm/amdgpu/virtual_dce: No need to pin the fb's bo For virtual display, no need to pin the fb's bo. Signed-off-by: Emily Deng Reviewed-by: Huang Rui Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 20 ++++++++++++-------- drivers/gpu/drm/amd/amdgpu/dce_virtual.c | 17 +++-------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 15ce7e681d67..b083b219b1a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -188,10 +188,12 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, goto cleanup; } - r = amdgpu_bo_pin(new_abo, amdgpu_display_supported_domains(adev)); - if (unlikely(r != 0)) { - DRM_ERROR("failed to pin new abo buffer before flip\n"); - goto unreserve; + if (!adev->enable_virtual_display) { + r = amdgpu_bo_pin(new_abo, amdgpu_display_supported_domains(adev)); + if (unlikely(r != 0)) { + DRM_ERROR("failed to pin new abo buffer before flip\n"); + goto unreserve; + } } r = amdgpu_ttm_alloc_gart(&new_abo->tbo); @@ -211,7 +213,8 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, amdgpu_bo_get_tiling_flags(new_abo, &tiling_flags); amdgpu_bo_unreserve(new_abo); - work->base = amdgpu_bo_gpu_offset(new_abo); + if (!adev->enable_virtual_display) + work->base = amdgpu_bo_gpu_offset(new_abo); work->target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) + amdgpu_get_vblank_counter_kms(dev, work->crtc_id); @@ -242,9 +245,10 @@ pflip_cleanup: goto cleanup; } unpin: - if (unlikely(amdgpu_bo_unpin(new_abo) != 0)) { - DRM_ERROR("failed to unpin new abo in error path\n"); - } + if (!adev->enable_virtual_display) + if (unlikely(amdgpu_bo_unpin(new_abo) != 0)) + DRM_ERROR("failed to unpin new abo in error path\n"); + unreserve: amdgpu_bo_unreserve(new_abo); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index fdace004544d..e4cc1d48eaab 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -167,19 +167,6 @@ static void dce_virtual_crtc_disable(struct drm_crtc *crtc) struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - if (crtc->primary->fb) { - int r; - struct amdgpu_bo *abo; - - abo = gem_to_amdgpu_bo(crtc->primary->fb->obj[0]); - r = amdgpu_bo_reserve(abo, true); - if (unlikely(r)) - DRM_ERROR("failed to reserve abo before unpin\n"); - else { - amdgpu_bo_unpin(abo); - amdgpu_bo_unreserve(abo); - } - } amdgpu_crtc->pll_id = ATOM_PPLL_INVALID; amdgpu_crtc->encoder = NULL; @@ -692,7 +679,9 @@ static int dce_virtual_pageflip(struct amdgpu_device *adev, spin_unlock_irqrestore(&adev->ddev->event_lock, flags); drm_crtc_vblank_put(&amdgpu_crtc->base); - schedule_work(&works->unpin_work); + amdgpu_bo_unref(&works->old_abo); + kfree(works->shared); + kfree(works); return 0; } -- cgit v1.2.3-58-ga151 From baf3c982dfbf7b0742039e6fef3f1fe1ba4079ab Mon Sep 17 00:00:00 2001 From: Emily Deng Date: Wed, 26 Dec 2018 18:08:54 +0800 Subject: drm/amdgpu/virtual_dce: No need to pin the cursor bo For virtual display feature, no need to pin cursor bo. Signed-off-by: Emily Deng Reviewed-by: Huang Rui Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 8a078f4ae73d..98df8e4704eb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2798,7 +2798,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon) struct drm_framebuffer *fb = crtc->primary->fb; struct amdgpu_bo *robj; - if (amdgpu_crtc->cursor_bo) { + if (amdgpu_crtc->cursor_bo && !adev->enable_virtual_display) { struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); r = amdgpu_bo_reserve(aobj, true); if (r == 0) { @@ -2906,7 +2906,7 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - if (amdgpu_crtc->cursor_bo) { + if (amdgpu_crtc->cursor_bo && !adev->enable_virtual_display) { struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); r = amdgpu_bo_reserve(aobj, true); if (r == 0) { -- cgit v1.2.3-58-ga151 From 048b9b0f5ceefb2691834ac62f8459ebb7d3100e Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Thu, 27 Dec 2018 14:23:30 +0800 Subject: drm/amd/powerplay: support BOOTUP_DEFAULT power profile mode This can avoid unexpected profile mode change after running compute workload. Signed-off-by: Evan Quan Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/include/kgd_pp_interface.h | 13 ++++++------ drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 24 ++++++++++++---------- drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 8 +++++--- drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 12 ++++++----- drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 10 ++++++--- drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 +- 6 files changed, 40 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 1479ea1dc3e7..789c4f288485 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -127,12 +127,13 @@ enum amd_pp_task { }; enum PP_SMC_POWER_PROFILE { - PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x0, - PP_SMC_POWER_PROFILE_POWERSAVING = 0x1, - PP_SMC_POWER_PROFILE_VIDEO = 0x2, - PP_SMC_POWER_PROFILE_VR = 0x3, - PP_SMC_POWER_PROFILE_COMPUTE = 0x4, - PP_SMC_POWER_PROFILE_CUSTOM = 0x5, + PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT = 0x0, + PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x1, + PP_SMC_POWER_PROFILE_POWERSAVING = 0x2, + PP_SMC_POWER_PROFILE_VIDEO = 0x3, + PP_SMC_POWER_PROFILE_VR = 0x4, + PP_SMC_POWER_PROFILE_COMPUTE = 0x5, + PP_SMC_POWER_PROFILE_CUSTOM = 0x6, }; enum { diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index 47ac92369739..472263ab274a 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -64,17 +64,19 @@ static int ci_set_asic_special_caps(struct pp_hwmgr *hwmgr); static void hwmgr_init_workload_prority(struct pp_hwmgr *hwmgr) { - hwmgr->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 2; - hwmgr->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 0; - hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 1; - hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VR] = 3; - hwmgr->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 4; - - hwmgr->workload_setting[0] = PP_SMC_POWER_PROFILE_POWERSAVING; - hwmgr->workload_setting[1] = PP_SMC_POWER_PROFILE_VIDEO; - hwmgr->workload_setting[2] = PP_SMC_POWER_PROFILE_FULLSCREEN3D; - hwmgr->workload_setting[3] = PP_SMC_POWER_PROFILE_VR; - hwmgr->workload_setting[4] = PP_SMC_POWER_PROFILE_COMPUTE; + hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0; + hwmgr->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1; + hwmgr->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2; + hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3; + hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4; + hwmgr->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5; + + hwmgr->workload_setting[0] = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; + hwmgr->workload_setting[1] = PP_SMC_POWER_PROFILE_FULLSCREEN3D; + hwmgr->workload_setting[2] = PP_SMC_POWER_PROFILE_POWERSAVING; + hwmgr->workload_setting[3] = PP_SMC_POWER_PROFILE_VIDEO; + hwmgr->workload_setting[4] = PP_SMC_POWER_PROFILE_VR; + hwmgr->workload_setting[5] = PP_SMC_POWER_PROFILE_COMPUTE; } int hwmgr_early_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 3958729d6265..13d65fd877cf 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -77,8 +77,9 @@ #define PCIE_BUS_CLK 10000 #define TCLK (PCIE_BUS_CLK / 10) -static const struct profile_mode_setting smu7_profiling[6] = - {{1, 0, 100, 30, 1, 0, 100, 10}, +static const struct profile_mode_setting smu7_profiling[7] = + {{0, 0, 0, 0, 0, 0, 0, 0}, + {1, 0, 100, 30, 1, 0, 100, 10}, {1, 10, 0, 30, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 10, 16, 31}, {1, 0, 11, 50, 1, 0, 100, 10}, @@ -4885,7 +4886,8 @@ static int smu7_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf) uint32_t i, size = 0; uint32_t len; - static const char *profile_name[6] = {"3D_FULL_SCREEN", + static const char *profile_name[7] = {"BOOTUP_DEFAULT", + "3D_FULL_SCREEN", "POWER_SAVING", "VIDEO", "VR", diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index e2bc6e0c229f..a4221b91d3fb 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -804,9 +804,9 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->backend = data; - hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VIDEO]; - hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO; - hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO; + hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT]; + hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; + hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; vega10_set_default_registry_data(hwmgr); data->disable_dpm_mask = 0xff; @@ -4664,13 +4664,15 @@ static int vega10_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf) { struct vega10_hwmgr *data = hwmgr->backend; uint32_t i, size = 0; - static const uint8_t profile_mode_setting[5][4] = {{70, 60, 1, 3,}, + static const uint8_t profile_mode_setting[6][4] = {{70, 60, 0, 0,}, + {70, 60, 1, 3,}, {90, 60, 0, 0,}, {70, 60, 0, 0,}, {70, 90, 0, 0,}, {30, 60, 0, 6,}, }; - static const char *profile_name[6] = {"3D_FULL_SCREEN", + static const char *profile_name[7] = {"BOOTUP_DEFAULT", + "3D_FULL_SCREEN", "POWER_SAVING", "VIDEO", "VR", diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 5a93a902d3dd..ea0b52d46fe9 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -390,9 +390,9 @@ static int vega20_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->backend = data; - hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_VIDEO]; - hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO; - hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_VIDEO; + hwmgr->workload_mask = 1 << hwmgr->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT]; + hwmgr->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; + hwmgr->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; vega20_set_default_registry_data(hwmgr); @@ -3251,6 +3251,9 @@ static int conv_power_profile_to_pplib_workload(int power_profile) int pplib_workload = 0; switch (power_profile) { + case PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT: + pplib_workload = WORKLOAD_DEFAULT_BIT; + break; case PP_SMC_POWER_PROFILE_FULLSCREEN3D: pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT; break; @@ -3280,6 +3283,7 @@ static int vega20_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf) uint32_t i, size = 0; uint16_t workload_type = 0; static const char *profile_name[] = { + "BOOTUP_DEFAULT", "3D_FULL_SCREEN", "POWER_SAVING", "VIDEO", diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index 0d298a0409f5..8cb831b6a016 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -705,7 +705,7 @@ enum PP_TABLE_VERSION { /** * The main hardware manager structure. */ -#define Workload_Policy_Max 5 +#define Workload_Policy_Max 6 struct pp_hwmgr { void *adev; -- cgit v1.2.3-58-ga151 From b8cf66182eddb22e9c7539821ed6eecdb4f86d1a Mon Sep 17 00:00:00 2001 From: Emily Deng Date: Sat, 29 Dec 2018 17:46:05 +0800 Subject: drm/amdgpu/sriov:Correct pfvf exchange logic The pfvf exchange need be in exclusive mode. And add pfvf exchange in gpu reset. Signed-off-by: Emily Deng Reviewed-By: Xiangliang Yu Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 8 ++++---- drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 98df8e4704eb..7ff3a28fc903 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1701,8 +1701,10 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) amdgpu_xgmi_add_device(adev); amdgpu_amdkfd_device_init(adev); - if (amdgpu_sriov_vf(adev)) + if (amdgpu_sriov_vf(adev)) { + amdgpu_virt_init_data_exchange(adev); amdgpu_virt_release_full_gpu(adev, true); + } return 0; } @@ -2632,9 +2634,6 @@ fence_driver_init: goto failed; } - if (amdgpu_sriov_vf(adev)) - amdgpu_virt_init_data_exchange(adev); - amdgpu_fbdev_init(adev); r = amdgpu_pm_sysfs_init(adev); @@ -3226,6 +3225,7 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, r = amdgpu_ib_ring_tests(adev); error: + amdgpu_virt_init_data_exchange(adev); amdgpu_virt_release_full_gpu(adev, true); if (!r && adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST) { atomic_inc(&adev->vram_lost_counter); diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c index 8cbb4655896a..b11a1c17a7f2 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c @@ -174,7 +174,7 @@ static int xgpu_ai_send_access_requests(struct amdgpu_device *adev, return r; } /* Retrieve checksum from mailbox2 */ - if (req == IDH_REQ_GPU_INIT_ACCESS) { + if (req == IDH_REQ_GPU_INIT_ACCESS || req == IDH_REQ_GPU_RESET_ACCESS) { adev->virt.fw_reserve.checksum_key = RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_MSGBUF_RCV_DW2)); -- cgit v1.2.3-58-ga151 From e49cddcd0ab08f2a3bf3fea8554ea45ae1446d26 Mon Sep 17 00:00:00 2001 From: Tiecheng Zhou Date: Mon, 24 Dec 2018 08:55:45 +0800 Subject: drm/amdgpu/gfx_v8_0: Reorder the gfx, kiq and kcq rings test sequence The kiq ring and the very first compute ring may fail occasionally if they are tested directly following kiq_kcq_enable. Insert the gfx ring test before kiq ring test to delay the kiq and kcq ring tests will fix the issue. Acked-by: Alex Deucher Signed-off-by: Tiecheng Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 48 +++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 381f593b0cda..164ffc91b645 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -4278,9 +4278,8 @@ static int gfx_v8_0_cp_gfx_resume(struct amdgpu_device *adev) amdgpu_ring_clear_ring(ring); gfx_v8_0_cp_gfx_start(adev); ring->sched.ready = true; - r = amdgpu_ring_test_helper(ring); - return r; + return 0; } static void gfx_v8_0_cp_compute_enable(struct amdgpu_device *adev, bool enable) @@ -4369,10 +4368,9 @@ static int gfx_v8_0_kiq_kcq_enable(struct amdgpu_device *adev) amdgpu_ring_write(kiq_ring, upper_32_bits(wptr_addr)); } - r = amdgpu_ring_test_helper(kiq_ring); - if (r) - DRM_ERROR("KCQ enable failed\n"); - return r; + amdgpu_ring_commit(kiq_ring); + + return 0; } static int gfx_v8_0_deactivate_hqd(struct amdgpu_device *adev, u32 req) @@ -4709,16 +4707,32 @@ static int gfx_v8_0_kcq_resume(struct amdgpu_device *adev) if (r) goto done; - /* Test KCQs - reversing the order of rings seems to fix ring test failure - * after GPU reset - */ - for (i = adev->gfx.num_compute_rings - 1; i >= 0; i--) { +done: + return r; +} + +static int gfx_v8_0_cp_test_all_rings(struct amdgpu_device *adev) +{ + int r, i; + struct amdgpu_ring *ring; + + /* collect all the ring_tests here, gfx, kiq, compute */ + ring = &adev->gfx.gfx_ring[0]; + r = amdgpu_ring_test_helper(ring); + if (r) + return r; + + ring = &adev->gfx.kiq.ring; + r = amdgpu_ring_test_helper(ring); + if (r) + return r; + + for (i = 0; i < adev->gfx.num_compute_rings; i++) { ring = &adev->gfx.compute_ring[i]; - r = amdgpu_ring_test_helper(ring); + amdgpu_ring_test_helper(ring); } -done: - return r; + return 0; } static int gfx_v8_0_cp_resume(struct amdgpu_device *adev) @@ -4739,6 +4753,11 @@ static int gfx_v8_0_cp_resume(struct amdgpu_device *adev) r = gfx_v8_0_kcq_resume(adev); if (r) return r; + + r = gfx_v8_0_cp_test_all_rings(adev); + if (r) + return r; + gfx_v8_0_enable_gui_idle_interrupt(adev, true); return 0; @@ -5056,6 +5075,7 @@ static int gfx_v8_0_post_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 grbm_soft_reset = 0; + struct amdgpu_ring *ring; if ((!adev->gfx.grbm_soft_reset) && (!adev->gfx.srbm_soft_reset)) @@ -5086,6 +5106,8 @@ static int gfx_v8_0_post_soft_reset(void *handle) REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX)) gfx_v8_0_cp_gfx_resume(adev); + gfx_v8_0_cp_test_all_rings(adev); + adev->gfx.rlc.funcs->start(adev); return 0; -- cgit v1.2.3-58-ga151 From 6e863844ad6effecac92a67a43b8467a8c2e129f Mon Sep 17 00:00:00 2001 From: Lukasz Luba Date: Wed, 5 Dec 2018 12:05:55 +0100 Subject: PM: sleep: call devfreq suspend/resume Devfreq framework supports suspend of its devices. Call the the devfreq interface and allow devfreq devices preserve/restore their states during suspend/resume. Suggested-by: Tobias Jakobi Reviewed-by: Chanwoo Choi Signed-off-by: Lukasz Luba Signed-off-by: Rafael J. Wysocki --- drivers/base/power/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index a690fd400260..0992e67e862b 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "../base.h" @@ -1078,6 +1079,7 @@ void dpm_resume(pm_message_t state) dpm_show_time(starttime, state, 0, NULL); cpufreq_resume(); + devfreq_resume(); trace_suspend_resume(TPS("dpm_resume"), state.event, false); } @@ -1852,6 +1854,7 @@ int dpm_suspend(pm_message_t state) trace_suspend_resume(TPS("dpm_suspend"), state.event, true); might_sleep(); + devfreq_suspend(); cpufreq_suspend(); mutex_lock(&dpm_list_mtx); -- cgit v1.2.3-58-ga151 From 8838555089f0345b87f4277fe5a8dd647dc65589 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 17 Oct 2018 10:13:23 -0700 Subject: mfd: twl-core: Fix section annotations on {,un}protect_pm_master When building the kernel with Clang, the following section mismatch warning appears: WARNING: vmlinux.o(.text+0x3d84a3b): Section mismatch in reference from the function twl_probe() to the function .init.text:unprotect_pm_master() The function twl_probe() references the function __init unprotect_pm_master(). This is often because twl_probe lacks a __init annotation or the annotation of unprotect_pm_master is wrong. Remove the __init annotation on the *protect_pm_master functions so there is no more mismatch. Signed-off-by: Nathan Chancellor Signed-off-by: Lee Jones --- drivers/mfd/twl-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 4be3d239da9e..299016bc46d9 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -979,7 +979,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, * letting it generate the right frequencies for USB, MADC, and * other purposes. */ -static inline int __init protect_pm_master(void) +static inline int protect_pm_master(void) { int e = 0; @@ -988,7 +988,7 @@ static inline int __init protect_pm_master(void) return e; } -static inline int __init unprotect_pm_master(void) +static inline int unprotect_pm_master(void) { int e = 0; -- cgit v1.2.3-58-ga151 From a3888f62fe66429fad3be7f2ba962e1e08c26fd6 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 17 Oct 2018 17:56:28 -0700 Subject: mfd: db8500-prcmu: Fix some section annotations When building the kernel with Clang, the following section mismatch warnings appear: WARNING: vmlinux.o(.text+0x7239cc): Section mismatch in reference from the function db8500_prcmu_probe() to the function .init.text:init_prcm_registers() The function db8500_prcmu_probe() references the function __init init_prcm_registers(). This is often because db8500_prcmu_probe lacks a __init annotation or the annotation of init_prcm_registers is wrong. WARNING: vmlinux.o(.text+0x723e28): Section mismatch in reference from the function db8500_prcmu_probe() to the function .init.text:fw_project_name() The function db8500_prcmu_probe() references the function __init fw_project_name(). This is often because db8500_prcmu_probe lacks a __init annotation or the annotation of fw_project_name is wrong. db8500_prcmu_probe should not be marked as __init so remove the __init annotation from fw_project_name and init_prcm_registers. Signed-off-by: Nathan Chancellor Signed-off-by: Lee Jones --- drivers/mfd/db8500-prcmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 5970b8def548..aec20e1c7d3d 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -2584,7 +2584,7 @@ static struct irq_chip prcmu_irq_chip = { .irq_unmask = prcmu_irq_unmask, }; -static __init char *fw_project_name(u32 project) +static char *fw_project_name(u32 project) { switch (project) { case PRCMU_FW_PROJECT_U8500: @@ -2732,7 +2732,7 @@ void __init db8500_prcmu_early_init(u32 phy_base, u32 size) INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); } -static void __init init_prcm_registers(void) +static void init_prcm_registers(void) { u32 val; -- cgit v1.2.3-58-ga151 From a177276aa098aa47a100d51a13eaaef029604b6d Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Mon, 22 Oct 2018 10:55:06 +0800 Subject: mfd: mt6397: Do not call irq_domain_remove if PMIC unsupported If the PMIC ID is unknown, the current code would call irq_domain_remove and panic, as pmic->irq_domain is only initialized by mt6397_irq_init. Return immediately with an error, if the chip ID is unsupported. Signed-off-by: Nicolas Boichat Signed-off-by: Lee Jones --- drivers/mfd/mt6397-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index 77b64bd64df3..ab24e176ef44 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c @@ -329,8 +329,7 @@ static int mt6397_probe(struct platform_device *pdev) default: dev_err(&pdev->dev, "unsupported chip: %d\n", id); - ret = -ENODEV; - break; + return -ENODEV; } if (ret) { -- cgit v1.2.3-58-ga151 From a54e950fdec3cde98caa04bc601cbdc95d0d319c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 7 Nov 2018 14:50:01 +0100 Subject: mfd: tmio: Typo s/use use/use/ Signed-off-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Lee Jones --- include/linux/mfd/tmio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 1e70060c92ce..aa696bcb1d12 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -83,7 +83,7 @@ /* Some controllers have a CBSY bit */ #define TMIO_MMC_HAVE_CBSY BIT(11) -/* Some controllers that support HS400 use use 4 taps while others use 8. */ +/* Some controllers that support HS400 use 4 taps while others use 8. */ #define TMIO_MMC_HAVE_4TAP_HS400 BIT(13) int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base); -- cgit v1.2.3-58-ga151 From 10628e3ecf544fa2e4e24f8e112d95c37884dc98 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 25 Oct 2018 15:43:44 +0300 Subject: mfd: ab8500-core: Return zero in get_register_interruptible() This function is supposed to return zero on success or negative error codes on error. Unfortunately, there is a bug so it sometimes returns non-zero, positive numbers on success. I noticed this bug during review and I can't test it. It does appear that the return is sometimes propogated back to _regmap_read() where all non-zero returns are treated as failure so this may affect run time. Fixes: 47c1697508f2 ("mfd: Align ab8500 with the abx500 interface") Signed-off-by: Dan Carpenter Reviewed-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab8500-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 30d09d177171..11ab17f64c64 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -261,7 +261,7 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank, mutex_unlock(&ab8500->lock); dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); - return ret; + return (ret < 0) ? ret : 0; } static int ab8500_get_register(struct device *dev, u8 bank, -- cgit v1.2.3-58-ga151 From b0aff01e7aa6ad2d6998ef1323843212d1db8b04 Mon Sep 17 00:00:00 2001 From: Dien Pham Date: Wed, 3 Oct 2018 15:58:41 +0200 Subject: mfd: bd9571mwv: Add volatile register to make DVFS work Because BD9571MWV_DVFS_MONIVDAC is not defined in the volatile table, the physical register value is not updated by regmap and DVFS doesn't work as expected. Fix it! Fixes: d3ea21272094 ("mfd: Add ROHM BD9571MWV-M MFD PMIC driver") Signed-off-by: Dien Pham [wsa: rebase, add 'Fixes', reword commit message] Signed-off-by: Wolfram Sang Reviewed-by: Marek Vasut Signed-off-by: Lee Jones --- drivers/mfd/bd9571mwv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/bd9571mwv.c b/drivers/mfd/bd9571mwv.c index 503979c81dae..fab3cdc27ed6 100644 --- a/drivers/mfd/bd9571mwv.c +++ b/drivers/mfd/bd9571mwv.c @@ -59,6 +59,7 @@ static const struct regmap_access_table bd9571mwv_writable_table = { }; static const struct regmap_range bd9571mwv_volatile_yes_ranges[] = { + regmap_reg_range(BD9571MWV_DVFS_MONIVDAC, BD9571MWV_DVFS_MONIVDAC), regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN), regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT), regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ), -- cgit v1.2.3-58-ga151 From 628f3dfe4c7b35bbe63ec194ca6da857b00b0083 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 12 Nov 2018 10:49:42 +0100 Subject: mfd: at91-usart: Add platform dependency It doesn't make sense to present option MFD_AT91_USART by default if not building an AT91 kernel, as the drivers which depend on it are not available. Fixes: 7d3aa342cef7 ("mfd: at91-usart: Add MFD driver for USART") Signed-off-by: Jean Delvare Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 8c5dfdce4326..f461460a2aeb 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -102,6 +102,7 @@ config MFD_AAT2870_CORE config MFD_AT91_USART tristate "AT91 USART Driver" select MFD_CORE + depends on ARCH_AT91 || COMPILE_TEST help Select this to get support for AT91 USART IP. This is a wrapper over at91-usart-serial driver and usart-spi-driver. Only one function -- cgit v1.2.3-58-ga151 From 7f9472134a5af31bad191f074a5d416146da26f7 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 12 Nov 2018 15:28:37 +0000 Subject: mfd: madera: Add shared data for accessory detection Add variables to struct madera that will be shared by the extcon and audio codec drivers to synchronize output state during accessory detection. Also add a mutex to protect the DAPM pointer. Signed-off-by: Richard Fitzgerald Signed-off-by: Lee Jones --- drivers/mfd/madera-core.c | 3 +++ include/linux/mfd/madera/core.h | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/drivers/mfd/madera-core.c b/drivers/mfd/madera-core.c index 440030cecbbd..5b58a8aea902 100644 --- a/drivers/mfd/madera-core.c +++ b/drivers/mfd/madera-core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -357,6 +358,8 @@ int madera_dev_init(struct madera *madera) dev_set_drvdata(madera->dev, madera); BLOCKING_INIT_NOTIFIER_HEAD(&madera->notifier); + mutex_init(&madera->dapm_ptr_lock); + madera_set_micbias_info(madera); /* diff --git a/include/linux/mfd/madera/core.h b/include/linux/mfd/madera/core.h index fe69c0f4398f..4d5d51a9c8a6 100644 --- a/include/linux/mfd/madera/core.h +++ b/include/linux/mfd/madera/core.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,8 @@ enum madera_type { #define MADERA_MAX_MICBIAS 4 +#define MADERA_MAX_HP_OUTPUT 3 + /* Notifier events */ #define MADERA_NOTIFY_VOICE_TRIGGER 0x1 #define MADERA_NOTIFY_HPDET 0x2 @@ -183,6 +186,10 @@ struct madera { unsigned int num_childbias[MADERA_MAX_MICBIAS]; struct snd_soc_dapm_context *dapm; + struct mutex dapm_ptr_lock; + unsigned int hp_ena; + bool out_clamp[MADERA_MAX_HP_OUTPUT]; + bool out_shorted[MADERA_MAX_HP_OUTPUT]; struct blocking_notifier_head notifier; }; -- cgit v1.2.3-58-ga151 From ac4ca4b9f4623ba5e1ea7a582f286567c611e027 Mon Sep 17 00:00:00 2001 From: Jonathan Hunter Date: Tue, 13 Nov 2018 08:56:31 +0000 Subject: mfd: tps6586x: Handle interrupts on suspend The tps6586x driver creates an irqchip that is used by its various child devices for managing interrupts. The tps6586x-rtc device is one of its children that uses the tps6586x irqchip. When using the tps6586x-rtc as a wake-up device from suspend, the following is seen: PM: Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.001 seconds) done. OOM killer disabled. Freezing remaining freezable tasks ... (elapsed 0.000 seconds) done. Disabling non-boot CPUs ... Entering suspend state LP1 Enabling non-boot CPUs ... CPU1 is up tps6586x 3-0034: failed to read interrupt status tps6586x 3-0034: failed to read interrupt status The reason why the tps6586x interrupt status cannot be read is because the tps6586x interrupt is not masked during suspend and when the tps6586x-rtc interrupt occurs, to wake-up the device, the interrupt is seen before the i2c controller has been resumed in order to read the tps6586x interrupt status. The tps6586x-rtc driver sets it's interrupt as a wake-up source during suspend, which gets propagated to the parent tps6586x interrupt. However, the tps6586x-rtc driver cannot disable it's interrupt during suspend otherwise we would never be woken up and so the tps6586x must disable it's interrupt instead. Prevent the tps6586x interrupt handler from executing on exiting suspend before the i2c controller has been resumed by disabling the tps6586x interrupt on entering suspend and re-enabling it on resuming from suspend. Cc: stable@vger.kernel.org Signed-off-by: Jon Hunter Reviewed-by: Dmitry Osipenko Tested-by: Dmitry Osipenko Acked-by: Thierry Reding Signed-off-by: Lee Jones --- drivers/mfd/tps6586x.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index b89379782741..9c7925ca13cf 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -592,6 +592,29 @@ static int tps6586x_i2c_remove(struct i2c_client *client) return 0; } +static int __maybe_unused tps6586x_i2c_suspend(struct device *dev) +{ + struct tps6586x *tps6586x = dev_get_drvdata(dev); + + if (tps6586x->client->irq) + disable_irq(tps6586x->client->irq); + + return 0; +} + +static int __maybe_unused tps6586x_i2c_resume(struct device *dev) +{ + struct tps6586x *tps6586x = dev_get_drvdata(dev); + + if (tps6586x->client->irq) + enable_irq(tps6586x->client->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(tps6586x_pm_ops, tps6586x_i2c_suspend, + tps6586x_i2c_resume); + static const struct i2c_device_id tps6586x_id_table[] = { { "tps6586x", 0 }, { }, @@ -602,6 +625,7 @@ static struct i2c_driver tps6586x_driver = { .driver = { .name = "tps6586x", .of_match_table = of_match_ptr(tps6586x_of_match), + .pm = &tps6586x_pm_ops, }, .probe = tps6586x_i2c_probe, .remove = tps6586x_i2c_remove, -- cgit v1.2.3-58-ga151 From 504e4175829c44328773b96ad9c538e4783a8d22 Mon Sep 17 00:00:00 2001 From: Jonathan Marek Date: Mon, 19 Nov 2018 14:53:17 -0500 Subject: mfd: qcom_rpm: write fw_version to CTRL_REG This is required as part of the initialization sequence on certain SoCs. If these registers are not initialized, the hardware can be unresponsive. This fixes the driver on apq8060 (HP TouchPad device). Signed-off-by: Jonathan Marek Signed-off-by: Lee Jones --- drivers/mfd/qcom_rpm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mfd/qcom_rpm.c b/drivers/mfd/qcom_rpm.c index 52fafea06067..8d420c37b2a6 100644 --- a/drivers/mfd/qcom_rpm.c +++ b/drivers/mfd/qcom_rpm.c @@ -638,6 +638,10 @@ static int qcom_rpm_probe(struct platform_device *pdev) return -EFAULT; } + writel(fw_version[0], RPM_CTRL_REG(rpm, 0)); + writel(fw_version[1], RPM_CTRL_REG(rpm, 1)); + writel(fw_version[2], RPM_CTRL_REG(rpm, 2)); + dev_info(&pdev->dev, "RPM firmware %u.%u.%u\n", fw_version[0], fw_version[1], fw_version[2]); -- cgit v1.2.3-58-ga151 From 04c801c18ded421845324255e660147a6f58dcd6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 28 Nov 2018 10:04:22 +0000 Subject: mfd: wm5110: Add missing ASRC rate register Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm5110-tables.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 1ee68bd440fb..16c6e2accfaa 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -1618,6 +1618,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */ { 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */ { 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */ + { 0x00000EE3, 0x4000 }, /* R3811 - ASRC_RATE2 */ { 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */ { 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */ { 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */ @@ -2869,6 +2870,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_ASRC_ENABLE: case ARIZONA_ASRC_STATUS: case ARIZONA_ASRC_RATE1: + case ARIZONA_ASRC_RATE2: case ARIZONA_ISRC_1_CTRL_1: case ARIZONA_ISRC_1_CTRL_2: case ARIZONA_ISRC_1_CTRL_3: -- cgit v1.2.3-58-ga151 From 4a19f9a65375ca9781b3ca9e810ece92edfc3e78 Mon Sep 17 00:00:00 2001 From: Oskari Lemmela Date: Tue, 20 Nov 2018 19:52:10 +0200 Subject: mfd: axp20x: Add AC power supply cell for AXP813 As axp20x-ac-power-supply now supports AXP813, add a cell for it. Signed-off-by: Oskari Lemmela Reviewed-by: Quentin Schulz Reviewed-by: Chen-Yu Tsai Tested-by: Vasily Khoruzhick Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 0be511dd93d0..dfc3cff1d08b 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -778,6 +778,11 @@ static const struct mfd_cell axp813_cells[] = { }, { .name = "axp20x-battery-power-supply", .of_compatible = "x-powers,axp813-battery-power-supply", + }, { + .name = "axp20x-ac-power-supply", + .of_compatible = "x-powers,axp813-ac-power-supply", + .num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources), + .resources = axp20x_ac_power_supply_resources, }, }; -- cgit v1.2.3-58-ga151 From 753a8d083e085c6f552c7982749de4cc7c40e2ac Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 8 Dec 2018 19:58:46 +0200 Subject: mfd: axp20x: Re-align MFD cell entries In the axp20x driver, the various mfd_cell lists had varying amounts of indentation, sometimes even within the same list. For the axp288, there's no alignment at all. Re-align the right hand side of the assignments with the least amount of tabs possible. Also collapse the closing bracket and the opening bracket of the next entry onto the same line for the axp288, to be consistent with all the other mfd_cell lists. This patch is whitespace change only. No functionality is modified. Signed-off-by: Chen-Yu Tsai Signed-off-by: Oskari Lemmela Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 107 ++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 56 deletions(-) diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index dfc3cff1d08b..8037b4e01ed6 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -640,9 +640,9 @@ static const struct mfd_cell axp221_cells[] = { static const struct mfd_cell axp223_cells[] = { { - .name = "axp221-pek", - .num_resources = ARRAY_SIZE(axp22x_pek_resources), - .resources = axp22x_pek_resources, + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp22x_pek_resources), + .resources = axp22x_pek_resources, }, { .name = "axp22x-adc", .of_compatible = "x-powers,axp221-adc", @@ -650,7 +650,7 @@ static const struct mfd_cell axp223_cells[] = { .name = "axp20x-battery-power-supply", .of_compatible = "x-powers,axp221-battery-power-supply", }, { - .name = "axp20x-regulator", + .name = "axp20x-regulator", }, { .name = "axp20x-ac-power-supply", .of_compatible = "x-powers,axp221-ac-power-supply", @@ -666,9 +666,9 @@ static const struct mfd_cell axp223_cells[] = { static const struct mfd_cell axp152_cells[] = { { - .name = "axp20x-pek", - .num_resources = ARRAY_SIZE(axp152_pek_resources), - .resources = axp152_pek_resources, + .name = "axp20x-pek", + .num_resources = ARRAY_SIZE(axp152_pek_resources), + .resources = axp152_pek_resources, }, }; @@ -697,84 +697,79 @@ static const struct resource axp288_charger_resources[] = { static const struct mfd_cell axp288_cells[] = { { - .name = "axp288_adc", - .num_resources = ARRAY_SIZE(axp288_adc_resources), - .resources = axp288_adc_resources, - }, - { - .name = "axp288_extcon", - .num_resources = ARRAY_SIZE(axp288_extcon_resources), - .resources = axp288_extcon_resources, - }, - { - .name = "axp288_charger", - .num_resources = ARRAY_SIZE(axp288_charger_resources), - .resources = axp288_charger_resources, - }, - { - .name = "axp288_fuel_gauge", - .num_resources = ARRAY_SIZE(axp288_fuel_gauge_resources), - .resources = axp288_fuel_gauge_resources, - }, - { - .name = "axp221-pek", - .num_resources = ARRAY_SIZE(axp288_power_button_resources), - .resources = axp288_power_button_resources, - }, - { - .name = "axp288_pmic_acpi", + .name = "axp288_adc", + .num_resources = ARRAY_SIZE(axp288_adc_resources), + .resources = axp288_adc_resources, + }, { + .name = "axp288_extcon", + .num_resources = ARRAY_SIZE(axp288_extcon_resources), + .resources = axp288_extcon_resources, + }, { + .name = "axp288_charger", + .num_resources = ARRAY_SIZE(axp288_charger_resources), + .resources = axp288_charger_resources, + }, { + .name = "axp288_fuel_gauge", + .num_resources = ARRAY_SIZE(axp288_fuel_gauge_resources), + .resources = axp288_fuel_gauge_resources, + }, { + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp288_power_button_resources), + .resources = axp288_power_button_resources, + }, { + .name = "axp288_pmic_acpi", }, }; static const struct mfd_cell axp803_cells[] = { { - .name = "axp221-pek", - .num_resources = ARRAY_SIZE(axp803_pek_resources), - .resources = axp803_pek_resources, + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp803_pek_resources), + .resources = axp803_pek_resources, }, - { .name = "axp20x-regulator" }, + { .name = "axp20x-regulator" }, }; static const struct mfd_cell axp806_self_working_cells[] = { { - .name = "axp221-pek", - .num_resources = ARRAY_SIZE(axp806_pek_resources), - .resources = axp806_pek_resources, + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp806_pek_resources), + .resources = axp806_pek_resources, }, - { .name = "axp20x-regulator" }, + { .name = "axp20x-regulator" }, }; static const struct mfd_cell axp806_cells[] = { { - .id = 2, - .name = "axp20x-regulator", + .id = 2, + .name = "axp20x-regulator", }, }; static const struct mfd_cell axp809_cells[] = { { - .name = "axp221-pek", - .num_resources = ARRAY_SIZE(axp809_pek_resources), - .resources = axp809_pek_resources, + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp809_pek_resources), + .resources = axp809_pek_resources, }, { - .id = 1, - .name = "axp20x-regulator", + .id = 1, + .name = "axp20x-regulator", }, }; static const struct mfd_cell axp813_cells[] = { { - .name = "axp221-pek", - .num_resources = ARRAY_SIZE(axp803_pek_resources), - .resources = axp803_pek_resources, + .name = "axp221-pek", + .num_resources = ARRAY_SIZE(axp803_pek_resources), + .resources = axp803_pek_resources, }, { - .name = "axp20x-regulator", + .name = "axp20x-regulator", }, { - .name = "axp20x-gpio", - .of_compatible = "x-powers,axp813-gpio", + .name = "axp20x-gpio", + .of_compatible = "x-powers,axp813-gpio", }, { - .name = "axp813-adc", - .of_compatible = "x-powers,axp813-adc", + .name = "axp813-adc", + .of_compatible = "x-powers,axp813-adc", }, { .name = "axp20x-battery-power-supply", .of_compatible = "x-powers,axp813-battery-power-supply", -- cgit v1.2.3-58-ga151 From ea90e7b47f0a8bd2fe14e9a88f523de7c67db90a Mon Sep 17 00:00:00 2001 From: Oskari Lemmela Date: Sat, 8 Dec 2018 19:58:47 +0200 Subject: mfd: axp20x: Add supported cells for AXP803 Parts of the AXP803 are compatible with their counterparts on the AXP813. These include the GPIO, ADC, AC and battery power supplies. Signed-off-by: Oskari Lemmela Reviewed-by: Chen-Yu Tsai Tested-by: Vasily Khoruzhick Signed-off-by: Chen-Yu Tsai Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 8037b4e01ed6..f8e0fa97bb31 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -726,6 +726,20 @@ static const struct mfd_cell axp803_cells[] = { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp803_pek_resources), .resources = axp803_pek_resources, + }, { + .name = "axp20x-gpio", + .of_compatible = "x-powers,axp813-gpio", + }, { + .name = "axp813-adc", + .of_compatible = "x-powers,axp813-adc", + }, { + .name = "axp20x-battery-power-supply", + .of_compatible = "x-powers,axp813-battery-power-supply", + }, { + .name = "axp20x-ac-power-supply", + .of_compatible = "x-powers,axp813-ac-power-supply", + .num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources), + .resources = axp20x_ac_power_supply_resources, }, { .name = "axp20x-regulator" }, }; -- cgit v1.2.3-58-ga151 From 18e294ddafaeb80a1e2e10c9bd750a6cb8388d5b Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 10 Dec 2018 19:00:02 +0100 Subject: mfd: cros_ec_dev: Add missing mfd_remove_devices() call in remove The driver adds different MFD child devices via mfd_add_devices() and hence it is required to call mfd_remove_devices() to remove MFD child devices. Fixes: 5e0115581bbc ("cros_ec: Move cros_ec_dev module to drivers/mfd") Signed-off-by: Enric Balletbo i Serra Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 8f9d6964173e..ff788d3e6d5f 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -493,6 +493,7 @@ static int ec_device_remove(struct platform_device *pdev) cros_ec_debugfs_remove(ec); + mfd_remove_devices(ec->dev); cdev_del(&ec->cdev); device_unregister(&ec->class_dev); return 0; -- cgit v1.2.3-58-ga151 From 38df91cc0b82d053234accf4429eafd2f5a4d401 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 Dec 2018 13:50:31 -0600 Subject: mfd: Use of_node_name_eq() for node name comparisons Convert string compares of DT node names to use of_node_name_eq() helper instead. This removes direct access to the node name pointer. Signed-off-by: Rob Herring Signed-off-by: Lee Jones --- drivers/mfd/max77620.c | 2 +- drivers/mfd/stmpe.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c index d8217366ed36..d8ddd1a6f304 100644 --- a/drivers/mfd/max77620.c +++ b/drivers/mfd/max77620.c @@ -280,7 +280,7 @@ static int max77620_config_fps(struct max77620_chip *chip, for (fps_id = 0; fps_id < MAX77620_FPS_COUNT; fps_id++) { sprintf(fps_name, "fps%d", fps_id); - if (!strcmp(fps_np->name, fps_name)) + if (of_node_name_eq(fps_np, fps_name)) break; } diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 566caca4efd8..7569a4be0608 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1302,17 +1302,17 @@ static void stmpe_of_probe(struct stmpe_platform_data *pdata, pdata->autosleep = (pdata->autosleep_timeout) ? true : false; for_each_child_of_node(np, child) { - if (!strcmp(child->name, "stmpe_gpio")) { + if (of_node_name_eq(child, "stmpe_gpio")) { pdata->blocks |= STMPE_BLOCK_GPIO; - } else if (!strcmp(child->name, "stmpe_keypad")) { + } else if (of_node_name_eq(child, "stmpe_keypad")) { pdata->blocks |= STMPE_BLOCK_KEYPAD; - } else if (!strcmp(child->name, "stmpe_touchscreen")) { + } else if (of_node_name_eq(child, "stmpe_touchscreen")) { pdata->blocks |= STMPE_BLOCK_TOUCHSCREEN; - } else if (!strcmp(child->name, "stmpe_adc")) { + } else if (of_node_name_eq(child, "stmpe_adc")) { pdata->blocks |= STMPE_BLOCK_ADC; - } else if (!strcmp(child->name, "stmpe_pwm")) { + } else if (of_node_name_eq(child, "stmpe_pwm")) { pdata->blocks |= STMPE_BLOCK_PWM; - } else if (!strcmp(child->name, "stmpe_rotator")) { + } else if (of_node_name_eq(child, "stmpe_rotator")) { pdata->blocks |= STMPE_BLOCK_ROTATOR; } } -- cgit v1.2.3-58-ga151 From 75d4c5e03c2ae9902ab521024b10291f6fc9515b Mon Sep 17 00:00:00 2001 From: Keerthy Date: Sun, 9 Dec 2018 19:29:31 +0530 Subject: mfd: tps65218: Use devm_regmap_add_irq_chip and clean up error path in probe() Use devm_regmap_add_irq_chip and clean up error path in probe and also the remove function. Reported-by: Christian Hohnstaedt Signed-off-by: Keerthy Reviewed-by: Sebastian Reichel Signed-off-by: Lee Jones --- drivers/mfd/tps65218.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index 910f569ff77c..8bcdecf494d0 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -235,9 +235,9 @@ static int tps65218_probe(struct i2c_client *client, mutex_init(&tps->tps_lock); - ret = regmap_add_irq_chip(tps->regmap, tps->irq, - IRQF_ONESHOT, 0, &tps65218_irq_chip, - &tps->irq_data); + ret = devm_regmap_add_irq_chip(&client->dev, tps->regmap, tps->irq, + IRQF_ONESHOT, 0, &tps65218_irq_chip, + &tps->irq_data); if (ret < 0) return ret; @@ -253,26 +253,9 @@ static int tps65218_probe(struct i2c_client *client, ARRAY_SIZE(tps65218_cells), NULL, 0, regmap_irq_get_domain(tps->irq_data)); - if (ret < 0) - goto err_irq; - - return 0; - -err_irq: - regmap_del_irq_chip(tps->irq, tps->irq_data); - return ret; } -static int tps65218_remove(struct i2c_client *client) -{ - struct tps65218 *tps = i2c_get_clientdata(client); - - regmap_del_irq_chip(tps->irq, tps->irq_data); - - return 0; -} - static const struct i2c_device_id tps65218_id_table[] = { { "tps65218", TPS65218 }, { }, @@ -285,7 +268,6 @@ static struct i2c_driver tps65218_driver = { .of_match_table = of_tps65218_match_table, }, .probe = tps65218_probe, - .remove = tps65218_remove, .id_table = tps65218_id_table, }; -- cgit v1.2.3-58-ga151 From ddf5aaa8eecb6ccf51f311a513c3a5011fbe0d54 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 16 Dec 2018 15:10:44 +0100 Subject: mfd: ingenic-tcu: Fix bit field description in header The description of the bit was inverted. Signed-off-by: Paul Cercueil Signed-off-by: Lee Jones --- include/linux/mfd/ingenic-tcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mfd/ingenic-tcu.h b/include/linux/mfd/ingenic-tcu.h index ab16ad283def..2083fa20821d 100644 --- a/include/linux/mfd/ingenic-tcu.h +++ b/include/linux/mfd/ingenic-tcu.h @@ -41,7 +41,7 @@ #define TCU_TCSR_PRESCALE_LSB 3 #define TCU_TCSR_PRESCALE_MASK 0x38 -#define TCU_TCSR_PWM_SD BIT(9) /* 0: Shutdown abruptly 1: gracefully */ +#define TCU_TCSR_PWM_SD BIT(9) /* 0: Shutdown gracefully 1: abruptly */ #define TCU_TCSR_PWM_INITL_HIGH BIT(8) /* Sets the initial output level */ #define TCU_TCSR_PWM_EN BIT(7) /* PWM pin output enable */ -- cgit v1.2.3-58-ga151 From f7b1e49c670370eeb21e0d7feb7eaa2468ad7ae2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 15 Dec 2018 03:29:18 -0500 Subject: mfd: rave-sp: Fix typo in rave_sp_checksum comment Caculated -> Calculated Signed-off-by: Yangtao Li Signed-off-by: Lee Jones --- drivers/mfd/rave-sp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c index 2a8369657e38..26c7b63e008a 100644 --- a/drivers/mfd/rave-sp.c +++ b/drivers/mfd/rave-sp.c @@ -109,7 +109,7 @@ struct rave_sp_reply { /** * struct rave_sp_checksum - Variant specific checksum implementation details * - * @length: Caculated checksum length + * @length: Calculated checksum length * @subroutine: Utilized checksum algorithm implementation */ struct rave_sp_checksum { -- cgit v1.2.3-58-ga151 From 4bcb83e055033592e8672a8deb7b209eed936e11 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 14 Dec 2018 14:39:14 +0000 Subject: mfd: madera: Remove spurious semicolon in while loop Coccinelle warning of a spurious semicolon on the closing brace of a while loop. Signed-off-by: Richard Fitzgerald Signed-off-by: Lee Jones --- drivers/mfd/madera-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/madera-core.c b/drivers/mfd/madera-core.c index 5b58a8aea902..2a77988d0462 100644 --- a/drivers/mfd/madera-core.c +++ b/drivers/mfd/madera-core.c @@ -156,7 +156,7 @@ static int madera_wait_for_boot(struct madera *madera) usleep_range(MADERA_BOOT_POLL_INTERVAL_USEC / 2, MADERA_BOOT_POLL_INTERVAL_USEC); regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_1, &val); - }; + } if (!(val & MADERA_BOOT_DONE_STS1)) { dev_err(madera->dev, "Polling BOOT_DONE_STS timed out\n"); -- cgit v1.2.3-58-ga151 From c1f3375be60c562e24460d41b75e564c0a429835 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Tue, 18 Dec 2018 17:06:26 +0800 Subject: mfd: cros_ec: Add commands to control codec Add EC host commands to control codec on EC. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Lee Jones --- include/linux/mfd/cros_ec_commands.h | 94 ++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h index 9a9631f0559e..fc91082d4c35 100644 --- a/include/linux/mfd/cros_ec_commands.h +++ b/include/linux/mfd/cros_ec_commands.h @@ -2790,6 +2790,100 @@ struct ec_response_battery_vendor_param { uint32_t value; } __packed; +/*****************************************************************************/ +/* Commands for I2S recording on audio codec. */ + +#define EC_CMD_CODEC_I2S 0x00BC + +enum ec_codec_i2s_subcmd { + EC_CODEC_SET_SAMPLE_DEPTH = 0x0, + EC_CODEC_SET_GAIN = 0x1, + EC_CODEC_GET_GAIN = 0x2, + EC_CODEC_I2S_ENABLE = 0x3, + EC_CODEC_I2S_SET_CONFIG = 0x4, + EC_CODEC_I2S_SET_TDM_CONFIG = 0x5, + EC_CODEC_I2S_SET_BCLK = 0x6, +}; + +enum ec_sample_depth_value { + EC_CODEC_SAMPLE_DEPTH_16 = 0, + EC_CODEC_SAMPLE_DEPTH_24 = 1, +}; + +enum ec_i2s_config { + EC_DAI_FMT_I2S = 0, + EC_DAI_FMT_RIGHT_J = 1, + EC_DAI_FMT_LEFT_J = 2, + EC_DAI_FMT_PCM_A = 3, + EC_DAI_FMT_PCM_B = 4, + EC_DAI_FMT_PCM_TDM = 5, +}; + +struct ec_param_codec_i2s { + /* + * enum ec_codec_i2s_subcmd + */ + uint8_t cmd; + union { + /* + * EC_CODEC_SET_SAMPLE_DEPTH + * Value should be one of ec_sample_depth_value. + */ + uint8_t depth; + + /* + * EC_CODEC_SET_GAIN + * Value should be 0~43 for both channels. + */ + struct ec_param_codec_i2s_set_gain { + uint8_t left; + uint8_t right; + } __packed gain; + + /* + * EC_CODEC_I2S_ENABLE + * 1 to enable, 0 to disable. + */ + uint8_t i2s_enable; + + /* + * EC_CODEC_I2S_SET_COFNIG + * Value should be one of ec_i2s_config. + */ + uint8_t i2s_config; + + /* + * EC_CODEC_I2S_SET_TDM_CONFIG + * Value should be one of ec_i2s_config. + */ + struct ec_param_codec_i2s_tdm { + /* + * 0 to 496 + */ + int16_t ch0_delay; + /* + * -1 to 496 + */ + int16_t ch1_delay; + uint8_t adjacent_to_ch0; + uint8_t adjacent_to_ch1; + } __packed tdm_param; + + /* + * EC_CODEC_I2S_SET_BCLK + */ + uint32_t bclk; + }; +} __packed; + +/* + * For subcommand EC_CODEC_GET_GAIN. + */ +struct ec_response_codec_gain { + uint8_t left; + uint8_t right; +} __packed; + /*****************************************************************************/ /* System commands */ -- cgit v1.2.3-58-ga151 From 9e28989d41c0eab57ec0bb156617a8757406ff8a Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Thu, 20 Dec 2018 15:12:11 -0600 Subject: mfd: mc13xxx: Fix a missing check of a register-read failure When mc13xxx_reg_read() fails, "old_adc0" is uninitialized and will contain random value. Further execution uses "old_adc0" even when mc13xxx_reg_read() fails. The fix checks the return value of mc13xxx_reg_read(), and exits the execution when it fails. Signed-off-by: Kangjie Lu Signed-off-by: Lee Jones --- drivers/mfd/mc13xxx-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index f475e848252f..d0bf50e3568d 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -274,7 +274,9 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, mc13xxx->adcflags |= MC13XXX_ADC_WORKING; - mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0); + ret = mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0); + if (ret) + goto out; adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2 | MC13XXX_ADC0_CHRGRAWDIV; -- cgit v1.2.3-58-ga151 From 3f2d347e851ef4464dea49504cde85e5eef67b2d Mon Sep 17 00:00:00 2001 From: Beomho Seo Date: Fri, 21 Dec 2018 15:32:28 +0100 Subject: mfd: exynos-lpass: Enable UART module support This patch enables proper interrupts routing between UART module in Exynos Audio SubSystem and the rest of the SoC. This routing is completely transparent for UART device and CPU/GIC. UART driver requests interrupts from the respective controller and enables/masks/handles it by itself via standard methods. There are boards (for example TM2), which use UART module in Exynos Audio SubStem for communication with BlueTooth chip. Signed-off-by: Beomho Seo [mszyprow: rephrased commit message, added UART reset] Signed-off-by: Marek Szyprowski Reviewed-by: Sylwester Nawrocki Signed-off-by: Lee Jones --- drivers/mfd/exynos-lpass.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c index ca829f85672f..2713de989f05 100644 --- a/drivers/mfd/exynos-lpass.c +++ b/drivers/mfd/exynos-lpass.c @@ -82,11 +82,13 @@ static void exynos_lpass_enable(struct exynos_lpass *lpass) LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S); regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK, - LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S); + LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S | + LPASS_INTR_UART); exynos_lpass_core_sw_reset(lpass, LPASS_I2S_SW_RESET); exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET); exynos_lpass_core_sw_reset(lpass, LPASS_MEM_SW_RESET); + exynos_lpass_core_sw_reset(lpass, LPASS_UART_SW_RESET); } static void exynos_lpass_disable(struct exynos_lpass *lpass) -- cgit v1.2.3-58-ga151 From 088d923a11e683af28ad9cea9b66782fff588495 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 2 Jan 2019 12:13:52 +0100 Subject: cpufreq / Documentation: Update cpufreq MAINTAINERS entry Update the MAINTAINERS entry for cpufreq by making it clear that it is not just drivers and adding current documentation records to it. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- MAINTAINERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7808b166fdb9..2a01d1af1e26 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3909,7 +3909,7 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/ti/cpmac.c -CPU FREQUENCY DRIVERS +CPU FREQUENCY SCALING FRAMEWORK M: "Rafael J. Wysocki" M: Viresh Kumar L: linux-pm@vger.kernel.org @@ -3917,6 +3917,8 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git T: git git://git.linaro.org/people/vireshk/linux.git (For ARM Updates) B: https://bugzilla.kernel.org +F: Documentation/admin-guide/pm/cpufreq.rst +F: Documentation/admin-guide/pm/intel_pstate.rst F: Documentation/cpu-freq/ F: Documentation/devicetree/bindings/cpufreq/ F: drivers/cpufreq/ -- cgit v1.2.3-58-ga151 From b9ced18acf68dffebe6888c7ec765a2b1db7a039 Mon Sep 17 00:00:00 2001 From: Chao Fan Date: Wed, 26 Dec 2018 11:34:50 +0800 Subject: ACPI: NUMA: Use correct type for printing addresses on i386-PAE The addresses of NUMA nodes are not printed correctly on i386-PAE which is misleading. Here is a debian9-32bit with PAE in a QEMU guest having more than 4G of memory: qemu-system-i386 \ -hda /var/lib/libvirt/images/debian32.qcow2 \ -m 5G \ -enable-kvm \ -smp 10 \ -numa node,mem=512M,nodeid=0,cpus=0 \ -numa node,mem=512M,nodeid=1,cpus=1 \ -numa node,mem=512M,nodeid=2,cpus=2 \ -numa node,mem=512M,nodeid=3,cpus=3 \ -numa node,mem=512M,nodeid=4,cpus=4 \ -numa node,mem=512M,nodeid=5,cpus=5 \ -numa node,mem=512M,nodeid=6,cpus=6 \ -numa node,mem=512M,nodeid=7,cpus=7 \ -numa node,mem=512M,nodeid=8,cpus=8 \ -numa node,mem=512M,nodeid=9,cpus=9 \ -serial stdio Because of the wrong value type, it prints as below: [ 0.021049] ACPI: SRAT Memory (0x0 length 0xa0000) in proximity domain 0 enabled [ 0.021740] ACPI: SRAT Memory (0x100000 length 0x1ff00000) in proximity domain 0 enabled [ 0.022425] ACPI: SRAT Memory (0x20000000 length 0x20000000) in proximity domain 1 enabled [ 0.023092] ACPI: SRAT Memory (0x40000000 length 0x20000000) in proximity domain 2 enabled [ 0.023764] ACPI: SRAT Memory (0x60000000 length 0x20000000) in proximity domain 3 enabled [ 0.024431] ACPI: SRAT Memory (0x80000000 length 0x20000000) in proximity domain 4 enabled [ 0.025104] ACPI: SRAT Memory (0xa0000000 length 0x20000000) in proximity domain 5 enabled [ 0.025791] ACPI: SRAT Memory (0x0 length 0x20000000) in proximity domain 6 enabled [ 0.026412] ACPI: SRAT Memory (0x20000000 length 0x20000000) in proximity domain 7 enabled [ 0.027118] ACPI: SRAT Memory (0x40000000 length 0x20000000) in proximity domain 8 enabled [ 0.027802] ACPI: SRAT Memory (0x60000000 length 0x20000000) in proximity domain 9 enabled The upper half of the start address of the NUMA domains between 6 and 9 inclusive was cut, so the printed values are incorrect. Fix the value type, to get the correct values in the log as follows: [ 0.023698] ACPI: SRAT Memory (0x0 length 0xa0000) in proximity domain 0 enabled [ 0.024325] ACPI: SRAT Memory (0x100000 length 0x1ff00000) in proximity domain 0 enabled [ 0.024981] ACPI: SRAT Memory (0x20000000 length 0x20000000) in proximity domain 1 enabled [ 0.025659] ACPI: SRAT Memory (0x40000000 length 0x20000000) in proximity domain 2 enabled [ 0.026317] ACPI: SRAT Memory (0x60000000 length 0x20000000) in proximity domain 3 enabled [ 0.026980] ACPI: SRAT Memory (0x80000000 length 0x20000000) in proximity domain 4 enabled [ 0.027635] ACPI: SRAT Memory (0xa0000000 length 0x20000000) in proximity domain 5 enabled [ 0.028311] ACPI: SRAT Memory (0x100000000 length 0x20000000) in proximity domain 6 enabled [ 0.028985] ACPI: SRAT Memory (0x120000000 length 0x20000000) in proximity domain 7 enabled [ 0.029667] ACPI: SRAT Memory (0x140000000 length 0x20000000) in proximity domain 8 enabled [ 0.030334] ACPI: SRAT Memory (0x160000000 length 0x20000000) in proximity domain 9 enabled Signed-off-by: Chao Fan [ rjw: Subject & changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/numa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 274699463b4f..7bbbf8256a41 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -146,9 +146,9 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header) { struct acpi_srat_mem_affinity *p = (struct acpi_srat_mem_affinity *)header; - pr_debug("SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s%s\n", - (unsigned long)p->base_address, - (unsigned long)p->length, + pr_debug("SRAT Memory (0x%llx length 0x%llx) in proximity domain %d %s%s%s\n", + (unsigned long long)p->base_address, + (unsigned long long)p->length, p->proximity_domain, (p->flags & ACPI_SRAT_MEM_ENABLED) ? "enabled" : "disabled", -- cgit v1.2.3-58-ga151 From 8a99255a50c0b4c2a449b96fd8d45fcc8d72c701 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 3 Jan 2019 15:40:45 +0800 Subject: perf stat: Fix endless wait for child process We hit a 'perf stat' issue by using following script: #!/bin/bash sleep 1000 & exec perf stat -a -e cycles -I1000 -- sleep 5 Since "perf stat" is launched by exec, the "sleep 1000" would be the child process of "perf stat". The wait4() call will not return because it's waiting for the child process "sleep 1000" to end. So 'perf stat' doesn't return even after 5s passes. This patch lets 'perf stat' return when the specified child process ends (in this case, the specified child process is "sleep 5"). Committer testing: # cat test.sh #!/bin/bash sleep 10 & exec perf stat -a -e cycles -I1000 -- sleep 5 # Before: # time ./test.sh # time counts unit events 1.001113090 108,453,351 cycles 2.002062196 142,075,435 cycles 3.002896194 164,801,068 cycles 4.003731666 107,062,140 cycles 5.002068867 112,241,832 cycles real 0m10.066s user 0m0.016s sys 0m0.101s # After: # time ./test.sh # time counts unit events 1.001016096 91,412,027 cycles 2.002014963 124,063,708 cycles 3.002883964 125,993,929 cycles 4.003706470 120,465,734 cycles 5.002006778 163,560,355 cycles real 0m5.123s user 0m0.014s sys 0m0.105s # Signed-off-by: Jin Yao Reviewed-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1546501245-4512-1-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1410d66192f7..63a3afc7f32b 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -561,7 +561,8 @@ try_again: break; } } - wait4(child_pid, &status, 0, &stat_config.ru_data); + if (child_pid != -1) + wait4(child_pid, &status, 0, &stat_config.ru_data); if (workload_exec_errno) { const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); -- cgit v1.2.3-58-ga151 From 0f68c396f6048cf87c662aab1ef9c9aa237153a8 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 20 Dec 2018 10:36:12 +0300 Subject: ASoC: cs4341: Add driver for CS4341 DAC This patch adds Cirrus Logic CS4341. This is a very simple, playback only, stereo DAC. Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs4341.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 355 insertions(+) create mode 100644 sound/soc/codecs/cs4341.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 62bdb7e333b8..3f742753abd1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -65,6 +65,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271_SPI if SPI_MASTER select SND_SOC_CS42XX8_I2C if I2C select SND_SOC_CS43130 if I2C + select SND_SOC_CS4341 if SND_SOC_I2C_AND_SPI select SND_SOC_CS4349 if I2C select SND_SOC_CS47L24 if MFD_CS47L24 select SND_SOC_CS53L30 if I2C @@ -542,6 +543,12 @@ config SND_SOC_CS43130 tristate "Cirrus Logic CS43130 CODEC" depends on I2C +config SND_SOC_CS4341 + tristate "Cirrus Logic CS4341 CODEC" + depends on I2C || SPI_MASTER + select REGMAP_I2C if I2C + select REGMAP_SPI if SPI_MASTER + # Cirrus Logic CS4349 HiFi DAC config SND_SOC_CS4349 tristate "Cirrus Logic CS4349 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 66f55d185620..fbe36e6177b0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -60,6 +60,7 @@ snd-soc-cs4271-spi-objs := cs4271-spi.o snd-soc-cs42xx8-objs := cs42xx8.o snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o snd-soc-cs43130-objs := cs43130.o +snd-soc-cs4341-objs := cs4341.o snd-soc-cs4349-objs := cs4349.o snd-soc-cs47l24-objs := cs47l24.o snd-soc-cs53l30-objs := cs53l30.o @@ -326,6 +327,7 @@ obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o +obj-$(CONFIG_SND_SOC_CS4341) += snd-soc-cs4341.o obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c new file mode 100644 index 000000000000..d2e616a89fd4 --- /dev/null +++ b/sound/soc/codecs/cs4341.c @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Cirrus Logic CS4341A ALSA SoC Codec Driver + * Author: Alexander Shiyan + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define CS4341_REG_MODE1 0x00 +#define CS4341_REG_MODE2 0x01 +#define CS4341_REG_MIX 0x02 +#define CS4341_REG_VOLA 0x03 +#define CS4341_REG_VOLB 0x04 + +#define CS4341_MODE2_DIF (7 << 4) +#define CS4341_MODE2_DIF_I2S_24 (0 << 4) +#define CS4341_MODE2_DIF_I2S_16 (1 << 4) +#define CS4341_MODE2_DIF_LJ_24 (2 << 4) +#define CS4341_MODE2_DIF_RJ_24 (3 << 4) +#define CS4341_MODE2_DIF_RJ_16 (5 << 4) +#define CS4341_VOLX_MUTE (1 << 7) + +struct cs4341_priv { + unsigned int fmt; + struct regmap *regmap; + struct regmap_config regcfg; +}; + +static const struct reg_default cs4341_reg_defaults[] = { + { CS4341_REG_MODE1, 0x00 }, + { CS4341_REG_MODE2, 0x82 }, + { CS4341_REG_MIX, 0x49 }, + { CS4341_REG_VOLA, 0x80 }, + { CS4341_REG_VOLB, 0x80 }, +}; + +static int cs4341_set_fmt(struct snd_soc_dai *dai, unsigned int format) +{ + struct snd_soc_component *component = dai->component; + struct cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component); + + switch (format & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (format & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } + + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + cs4341->fmt = format & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs4341_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component); + unsigned int mode = 0; + int b24 = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S24_LE: + b24 = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + break; + default: + dev_err(component->dev, "Unsupported PCM format 0x%08x.\n", + params_format(params)); + return -EINVAL; + } + + switch (cs4341->fmt) { + case SND_SOC_DAIFMT_I2S: + mode = b24 ? CS4341_MODE2_DIF_I2S_24 : CS4341_MODE2_DIF_I2S_16; + break; + case SND_SOC_DAIFMT_LEFT_J: + mode = CS4341_MODE2_DIF_LJ_24; + break; + case SND_SOC_DAIFMT_RIGHT_J: + mode = b24 ? CS4341_MODE2_DIF_RJ_24 : CS4341_MODE2_DIF_RJ_16; + break; + default: + dev_err(component->dev, "Unsupported DAI format 0x%08x.\n", + cs4341->fmt); + return -EINVAL; + } + + return snd_soc_component_update_bits(component, CS4341_REG_MODE2, + CS4341_MODE2_DIF, mode); +} + +static int cs4341_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + int ret; + + ret = snd_soc_component_update_bits(component, CS4341_REG_VOLA, + CS4341_VOLX_MUTE, + mute ? CS4341_VOLX_MUTE : 0); + if (ret < 0) + return ret; + + return snd_soc_component_update_bits(component, CS4341_REG_VOLB, + CS4341_VOLX_MUTE, + mute ? CS4341_VOLX_MUTE : 0); +} + +static DECLARE_TLV_DB_SCALE(out_tlv, -9000, 100, 0); + +static const char * const deemph[] = { + "None", "44.1k", "48k", "32k", +}; + +static const struct soc_enum deemph_enum = + SOC_ENUM_SINGLE(CS4341_REG_MODE2, 2, 4, deemph); + +static const char * const srzc[] = { + "Immediate", "Zero Cross", "Soft Ramp", "SR on ZC", +}; + +static const struct soc_enum srzc_enum = + SOC_ENUM_SINGLE(CS4341_REG_MIX, 5, 4, srzc); + + +static const struct snd_soc_dapm_widget cs4341_dapm_widgets[] = { + SND_SOC_DAPM_DAC("HiFi DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("OutA"), + SND_SOC_DAPM_OUTPUT("OutB"), +}; + +static const struct snd_soc_dapm_route cs4341_routes[] = { + { "OutA", NULL, "HiFi DAC" }, + { "OutB", NULL, "HiFi DAC" }, + { "DAC Playback", NULL, "OutA" }, + { "DAC Playback", NULL, "OutB" }, +}; + +static const struct snd_kcontrol_new cs4341_controls[] = { + SOC_DOUBLE_R_TLV("Master Playback Volume", + CS4341_REG_VOLA, CS4341_REG_VOLB, 0, 90, 1, out_tlv), + SOC_ENUM("De-Emphasis Control", deemph_enum), + SOC_ENUM("Soft Ramp Zero Cross Control", srzc_enum), + SOC_SINGLE("Auto-Mute Switch", CS4341_REG_MODE2, 7, 1, 0), + SOC_SINGLE("Popguard Transient Switch", CS4341_REG_MODE2, 1, 1, 0), +}; + +static const struct snd_soc_dai_ops cs4341_dai_ops = { + .set_fmt = cs4341_set_fmt, + .hw_params = cs4341_hw_params, + .digital_mute = cs4341_digital_mute, +}; + +static struct snd_soc_dai_driver cs4341_dai = { + .name = "cs4341a-hifi", + .playback = { + .stream_name = "DAC Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &cs4341_dai_ops, + .symmetric_rates = 1, +}; + +static const struct snd_soc_component_driver soc_component_cs4341 = { + .controls = cs4341_controls, + .num_controls = ARRAY_SIZE(cs4341_controls), + .dapm_widgets = cs4341_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs4341_dapm_widgets), + .dapm_routes = cs4341_routes, + .num_dapm_routes = ARRAY_SIZE(cs4341_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static const struct of_device_id __maybe_unused cs4341_dt_ids[] = { + { .compatible = "cirrus,cs4341a", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs4341_dt_ids); + +static int cs4341_probe(struct device *dev) +{ + struct cs4341_priv *cs4341 = dev_get_drvdata(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(cs4341_reg_defaults); i++) + regmap_write(cs4341->regmap, cs4341_reg_defaults[i].reg, + cs4341_reg_defaults[i].def); + + return devm_snd_soc_register_component(dev, &soc_component_cs4341, + &cs4341_dai, 1); +} + +#if defined(CONFIG_I2C) +static int cs4341_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct cs4341_priv *cs4341; + + cs4341 = devm_kzalloc(&i2c->dev, sizeof(*cs4341), GFP_KERNEL); + if (!cs4341) + return -ENOMEM; + + i2c_set_clientdata(i2c, cs4341); + + cs4341->regcfg.reg_bits = 8; + cs4341->regcfg.val_bits = 8; + cs4341->regcfg.max_register = CS4341_REG_VOLB; + cs4341->regcfg.cache_type = REGCACHE_FLAT; + cs4341->regcfg.reg_defaults = cs4341_reg_defaults; + cs4341->regcfg.num_reg_defaults = ARRAY_SIZE(cs4341_reg_defaults); + cs4341->regmap = devm_regmap_init_i2c(i2c, &cs4341->regcfg); + if (IS_ERR(cs4341->regmap)) + return PTR_ERR(cs4341->regmap); + + return cs4341_probe(&i2c->dev); +} + +static const struct i2c_device_id cs4341_i2c_id[] = { + { "cs4341", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs4341_i2c_id); + +static struct i2c_driver cs4341_i2c_driver = { + .driver = { + .name = "cs4341-i2c", + .of_match_table = of_match_ptr(cs4341_dt_ids), + }, + .probe = cs4341_i2c_probe, + .id_table = cs4341_i2c_id, +}; +#endif + +#if defined(CONFIG_SPI_MASTER) +static bool cs4341_reg_readable(struct device *dev, unsigned int reg) +{ + return false; +} + +static int cs4341_spi_probe(struct spi_device *spi) +{ + struct cs4341_priv *cs4341; + int ret; + + cs4341 = devm_kzalloc(&spi->dev, sizeof(*cs4341), GFP_KERNEL); + if (!cs4341) + return -ENOMEM; + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + if (!spi->max_speed_hz) + spi->max_speed_hz = 6000000; + ret = spi_setup(spi); + if (ret) + return ret; + + spi_set_drvdata(spi, cs4341); + + cs4341->regcfg.reg_bits = 16; + cs4341->regcfg.val_bits = 8; + cs4341->regcfg.write_flag_mask = 0x20; + cs4341->regcfg.max_register = CS4341_REG_VOLB; + cs4341->regcfg.cache_type = REGCACHE_FLAT; + cs4341->regcfg.readable_reg = cs4341_reg_readable; + cs4341->regcfg.reg_defaults = cs4341_reg_defaults; + cs4341->regcfg.num_reg_defaults = ARRAY_SIZE(cs4341_reg_defaults); + cs4341->regmap = devm_regmap_init_spi(spi, &cs4341->regcfg); + if (IS_ERR(cs4341->regmap)) + return PTR_ERR(cs4341->regmap); + + return cs4341_probe(&spi->dev); +} + +static struct spi_driver cs4341_spi_driver = { + .driver = { + .name = "cs4341-spi", + .of_match_table = of_match_ptr(cs4341_dt_ids), + }, + .probe = cs4341_spi_probe, +}; +#endif + +static int __init cs4341_init(void) +{ + int ret = 0; + +#if defined(CONFIG_I2C) + ret = i2c_add_driver(&cs4341_i2c_driver); + if (ret) + return ret; +#endif +#if defined(CONFIG_SPI_MASTER) + ret = spi_register_driver(&cs4341_spi_driver); +#endif + + return ret; +} +module_init(cs4341_init); + +static void __exit cs4341_exit(void) +{ +#if defined(CONFIG_I2C) + i2c_del_driver(&cs4341_i2c_driver); +#endif +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&cs4341_spi_driver); +#endif +} +module_exit(cs4341_exit); + +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("Cirrus Logic CS4341 ALSA SoC Codec Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-58-ga151 From 0ddb46080a465fad99cff838682744f1f4848a4b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 20 Dec 2018 10:37:08 +0300 Subject: ASoC: cs4341: Add DT bindings documentation for CS4341 DAC This patch adds DT bindings documentation for Cirrus Logic CS4341 DAC. Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/cs4341.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cs4341.txt diff --git a/Documentation/devicetree/bindings/sound/cs4341.txt b/Documentation/devicetree/bindings/sound/cs4341.txt new file mode 100644 index 000000000000..12b4aa8ef0db --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs4341.txt @@ -0,0 +1,22 @@ +Cirrus Logic CS4341 audio DAC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + - compatible: "cirrus,cs4341a" + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +For required properties on I2C-bus, please consult +Documentation/devicetree/bindings/i2c/i2c.txt +For required properties on SPI-bus, please consult +Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + codec: cs4341@0 { + #sound-dai-cells = <0>; + compatible = "cirrus,cs4341a"; + reg = <0>; + spi-max-frequency = <6000000>; + }; -- cgit v1.2.3-58-ga151 From 2bb853f6f93775dc4dd4683a42f6934700d90d07 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Wed, 19 Dec 2018 21:11:15 +0100 Subject: ASoC: wm8904: make the driver visible in Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For platforms that use the audio-graph-card driver, the codec is not selected by SoC-platform driver. Make it available. Signed-off-by: Michał Mirosław Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3f742753abd1..d46de3e04ff6 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1218,7 +1218,8 @@ config SND_SOC_WM8903 depends on I2C config SND_SOC_WM8904 - tristate + tristate "Wolfson Microelectronics WM8904 CODEC" + depends on I2C config SND_SOC_WM8940 tristate -- cgit v1.2.3-58-ga151 From fb82c6ed31902e651cc9324108f507babfabc890 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Wed, 19 Dec 2018 21:11:16 +0100 Subject: ASoC: wm8904: save model id directly in of_device_id.data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Save 2x unsigned int of .rodata. Signed-off-by: Michał Mirosław Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 2a3e5fbd04e4..9283a2dc70aa 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2108,16 +2108,13 @@ static const struct regmap_config wm8904_regmap = { }; #ifdef CONFIG_OF -static enum wm8904_type wm8904_data = WM8904; -static enum wm8904_type wm8912_data = WM8912; - static const struct of_device_id wm8904_of_match[] = { { .compatible = "wlf,wm8904", - .data = &wm8904_data, + .data = (void *)WM8904, }, { .compatible = "wlf,wm8912", - .data = &wm8912_data, + .data = (void *)WM8912, }, { /* sentinel */ } @@ -2158,7 +2155,7 @@ static int wm8904_i2c_probe(struct i2c_client *i2c, match = of_match_node(wm8904_of_match, i2c->dev.of_node); if (match == NULL) return -EINVAL; - wm8904->devtype = *((enum wm8904_type *)match->data); + wm8904->devtype = (enum wm8904_type)match->data; } else { wm8904->devtype = id->driver_data; } -- cgit v1.2.3-58-ga151 From 5489e81f981b1fb7c2fdaba332122fff3290e9a4 Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Wed, 19 Dec 2018 21:11:16 +0100 Subject: ASoC: wm8904: enable MCLK in STANDBY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MCLK input is needed when accessing any register after enabling SYSCLK. This also fixes imbalance of clk_enable / clk_disable when transitioning between ON -> STANDBY -> ON bias levels. Signed-off-by: Michał Mirosław Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 9283a2dc70aa..9e0f96e0f8ec 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1837,9 +1837,6 @@ static int wm8904_set_bias_level(struct snd_soc_component *component, switch (level) { case SND_SOC_BIAS_ON: - ret = clk_prepare_enable(wm8904->mclk); - if (ret) - return ret; break; case SND_SOC_BIAS_PREPARE: @@ -1864,6 +1861,15 @@ static int wm8904_set_bias_level(struct snd_soc_component *component, return ret; } + ret = clk_prepare_enable(wm8904->mclk); + if (ret) { + dev_err(component->dev, + "Failed to enable MCLK: %d\n", ret); + regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), + wm8904->supplies); + return ret; + } + regcache_cache_only(wm8904->regmap, false); regcache_sync(wm8904->regmap); -- cgit v1.2.3-58-ga151 From 431b67c27c57bc6a752482727c87f6dda988aae5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:02 -0600 Subject: ASoC: Intel: Skylake: remove useless cast Detected with Coccinelle sound/soc/intel/skylake/skl-topology.c:3106:16-20: WARNING: casting value returned by memory allocation function to (char *) is useless. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index cf8848b779dc..389f1862bc43 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3103,7 +3103,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, ac->size = dfw_ac->max; if (ac->max) { - ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); + ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL); if (!ac->params) return -ENOMEM; -- cgit v1.2.3-58-ga151 From d8747d30aa7f9e7dc6123709d7ca1d8429d648b0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:03 -0600 Subject: ASoC: Intel: Skylake: simplify boolean tests Detected with Coccinelle skl-messages.c:419:5-32: WARNING: Comparison to bool skl-pcm.c:1426:6-33: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 2 +- sound/soc/intel/skylake/skl-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index b0e6fb93eaf8..28c4806b196a 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -416,7 +416,7 @@ int skl_resume_dsp(struct skl *skl) snd_hdac_ext_bus_ppcap_int_enable(bus, true); /* check if DSP 1st boot is done */ - if (skl->skl_sst->is_first_boot == true) + if (skl->skl_sst->is_first_boot) return 0; /* diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 557f80c0bfe5..8e589d698c58 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1423,7 +1423,7 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) if (!ops) return -EIO; - if (skl->skl_sst->is_first_boot == false) { + if (!skl->skl_sst->is_first_boot) { dev_err(component->dev, "DSP reports first boot done!!!\n"); return -EIO; } -- cgit v1.2.3-58-ga151 From 6c5414589721d696fe300dc0b8720e0368e3907a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:04 -0600 Subject: ASoC: Intel: Haswell: remove unneeded semicolon Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index fe2c826e710c..fb9b8608eb3b 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -544,7 +544,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, dev_err(rtd->dev, "error: invalid DAI ID %d\n", rtd->cpu_dai->id); return -EINVAL; - }; + } ret = sst_hsw_stream_format(hsw, pcm_data->stream, path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT); -- cgit v1.2.3-58-ga151 From bf88b3c3c277c8138d688a0fc3199b57fecfaf56 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:05 -0600 Subject: ASoC: Intel: Haswell: assign booleans to true/false Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/haswell/sst-haswell-ipc.c | 2 +- sound/soc/intel/haswell/sst-haswell-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index d33bdaf92c57..31fcdf12c67d 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -1216,7 +1216,7 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) return ret; } - stream->commited = 1; + stream->commited = true; trace_hsw_stream_alloc_reply(stream); return 0; diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index fb9b8608eb3b..2debcc2ed99a 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -861,7 +861,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); goto out; } - pcm_data->allocated = 0; + pcm_data->allocated = false; pcm_data->stream = NULL; out: -- cgit v1.2.3-58-ga151 From 060d35be2dfa9202d37f967fd20f133c530505d2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:06 -0600 Subject: ASoC: Intel: Baytrail: remove unneeded variable Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-ipc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 260447da32b8..2cd8f9668b50 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -278,7 +278,6 @@ static int sst_byt_process_notification(struct sst_byt *byt, struct sst_byt_stream *stream; u64 header; u8 msg_id, stream_id; - int handled = 1; header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); msg_id = sst_byt_header_msg_id(header); @@ -298,7 +297,7 @@ static int sst_byt_process_notification(struct sst_byt *byt, break; } - return handled; + return 1; } static irqreturn_t sst_byt_irq_thread(int irq, void *context) -- cgit v1.2.3-58-ga151 From e295450dd86d974861e1e9e302d67b0a23457ea8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:07 -0600 Subject: ASoC: Intel: Baytrail: simplify boolean test Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index aabb35bf6b96..498fb5346f1a 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -188,7 +188,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) sst_byt_stream_start(byt, pcm_data->stream, 0); break; case SNDRV_PCM_TRIGGER_RESUME: - if (pdata->restore_stream == true) + if (pdata->restore_stream) schedule_work(&pcm_data->work); else sst_byt_stream_resume(byt, pcm_data->stream); -- cgit v1.2.3-58-ga151 From 10583cdac237b32c0d3f6027b06c5eec8bf91211 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:08 -0600 Subject: ASoC: Intel: Atom: simplify boolean tests Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 2 +- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 2 +- sound/soc/intel/atom/sst/sst_acpi.c | 2 +- sound/soc/intel/atom/sst/sst_drv_interface.c | 2 +- sound/soc/intel/atom/sst/sst_loader.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 3672d36b4b66..d1207ea53523 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -647,7 +647,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, set_mixer = false; } - if (set_mixer == false) + if (!set_mixer) return 0; if (SND_SOC_DAPM_EVENT_ON(event) || diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index afc559866095..aefa5ce4cb59 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -190,7 +190,7 @@ int sst_fill_stream_params(void *substream, map = ctx->pdata->pdev_strm_map; map_size = ctx->pdata->strm_map_size; - if (is_compress == true) + if (is_compress) cstream = (struct snd_compr_stream *)substream; else pstream = (struct snd_pcm_substream *)substream; diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index ac542535b9d5..3a95ebbfc45d 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -334,7 +334,7 @@ static int sst_acpi_probe(struct platform_device *pdev) return ret; ret = is_byt_cr(dev, &bytcr); - if (!((ret < 0) || (bytcr == false))) { + if (!(ret < 0 || !bytcr)) { dev_info(dev, "Detected Baytrail-CR platform\n"); /* override resource info */ diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 5455d6e0ab53..a592df06aa58 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -146,7 +146,7 @@ static int sst_power_control(struct device *dev, bool state) int ret = 0; int usage_count = 0; - if (state == true) { + if (state) { ret = pm_runtime_get_sync(dev); usage_count = GET_USAGE_COUNT(dev); dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index b8c456753f01..321c783cf833 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -269,7 +269,7 @@ static void sst_do_memcpy(struct list_head *memcpy_list) struct sst_memcpy_list *listnode; list_for_each_entry(listnode, memcpy_list, memcpylist) { - if (listnode->is_io == true) + if (listnode->is_io) memcpy32_toio((void __iomem *)listnode->dstn, listnode->src, listnode->size); else -- cgit v1.2.3-58-ga151 From 4e88068ed0888549acd1cbb2f6e271b007051203 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:10 -0600 Subject: ASoC: Intel: boards: use snd_mask_set_format in all machine drivers Fix Sparse warnings with two machine drivers which weren't updated Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 2 +- sound/soc/intel/boards/kbl_da7219_max98927.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index c74c4f17316f..0739e3a75083 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -164,7 +164,7 @@ static int geminilake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, /* set SSP to 24 bit */ snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 723a4935ed76..6dd5c69671b3 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -221,7 +221,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, rate->min = rate->max = 48000; channels->min = channels->max = 2; snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); } /* @@ -229,7 +229,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, * thus changing the mask here */ if (!strcmp(be_dai_link->name, "SSP0-Codec")) - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; } -- cgit v1.2.3-58-ga151 From a0c426fe143328760c9fd565cd203a37a7b4fde8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:42 +0900 Subject: ASoC: simple-card-utils: check "reg" property on asoc_simple_card_get_dai_id() We will get DAI ID from "reg" property if it has on DT, otherwise get it by counting port/endpoint. But in below case, we need to get DAI ID = 0 via port reg = <0>, but current implementation returns ID = 1, because it can't judge ID = 0 was from "non reg" or "reg = <0>". Thus, it will count port/endpoint number as "non reg" case. of_graph_parse_endpoint() implementation itself is not a problem, but because asoc_simple_card_get_dai_id() need to count port/endpoint number when "non reg" case, it need to know ID = 0 was from "non reg" or "reg = <0>". This patch fix this issue. port { reg = <0>; xxxx: endpoint@0 { }; => xxxx: endpoint@1 { }; }; Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index b807a47515eb..336895f7fd1e 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -283,12 +283,20 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep) /* use endpoint/port reg if exist */ ret = of_graph_parse_endpoint(ep, &info); if (ret == 0) { - if (info.id) + /* + * Because it will count port/endpoint if it doesn't have "reg". + * But, we can't judge whether it has "no reg", or "reg = <0>" + * only of_graph_parse_endpoint(). + * We need to check "reg" property + */ + if (of_get_property(ep, "reg", NULL)) return info.id; - if (info.port) + + node = of_get_parent(ep); + of_node_put(node); + if (of_get_property(node, "reg", NULL)) return info.port; } - node = of_graph_get_port_parent(ep); /* -- cgit v1.2.3-58-ga151 From 40dfae169ad047535d566a4791daae3b08f71c0c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:48 +0900 Subject: ASoC: audio-graph-card: add asoc_graph_card_get_conversion() audio-graph-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= audio-graph-scu) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged audio-graph-card is completely forgeting about it. To re-support 1 CPU : 1 Codec DPCM for hw_params_fixup(), it need to judge whether it is DPCM by checking convert-rate/channel. For this purpose, this patch adds asoc_graph_card_get_conversion() as preparation Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0d6144560a1e..c3e80bc27e80 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -169,6 +169,22 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static void asoc_graph_card_get_conversion(struct device *dev, + struct device_node *ep, + struct asoc_simple_card_data *adata) +{ + struct device_node *top = dev->of_node; + struct device_node *port = of_get_parent(ep); + struct device_node *ports = of_get_parent(port); + struct device_node *node = of_graph_get_port_parent(ep); + + asoc_simple_card_parse_convert(dev, top, NULL, adata); + asoc_simple_card_parse_convert(dev, node, PREFIX, adata); + asoc_simple_card_parse_convert(dev, ports, NULL, adata); + asoc_simple_card_parse_convert(dev, port, NULL, adata); + asoc_simple_card_parse_convert(dev, ep, NULL, adata); +} + static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, struct device_node *cpu_ep, struct device_node *codec_ep, @@ -194,11 +210,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs); - asoc_simple_card_parse_convert(dev, top, NULL, &dai_props->adata); - asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata); - asoc_simple_card_parse_convert(dev, ports, NULL, &dai_props->adata); - asoc_simple_card_parse_convert(dev, port, NULL, &dai_props->adata); - asoc_simple_card_parse_convert(dev, ep, NULL, &dai_props->adata); + asoc_graph_card_get_conversion(dev, ep, &dai_props->adata); of_node_put(ports); of_node_put(port); -- cgit v1.2.3-58-ga151 From e4f4fdfc57d9c846862ea6109e356b3a4542df5b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:27 +0900 Subject: ASoC: audio-graph-scu-card: remove audio-graph-scu-card on Doc It is already merged into audio-graph-card. audio-graph-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-scu-card.txt | 123 --------------------- 1 file changed, 123 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt diff --git a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt b/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt deleted file mode 100644 index 62d42768a00b..000000000000 --- a/Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt +++ /dev/null @@ -1,123 +0,0 @@ -Audio-Graph-SCU-Card: - -Audio-Graph-SCU-Card is "Audio-Graph-Card" + "ALSA DPCM". - -It is based on common bindings for device graphs. -see ${LINUX}/Documentation/devicetree/bindings/graph.txt - -Basically, Audio-Graph-SCU-Card property is same as -Simple-Card / Simple-SCU-Card / Audio-Graph-Card. -see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt - ${LINUX}/Documentation/devicetree/bindings/sound/simple-scu-card.txt - ${LINUX}/Documentation/devicetree/bindings/sound/audio-graph-card.txt - -Below are same as Simple-Card / Audio-Graph-Card. - -- label -- dai-format -- frame-master -- bitclock-master -- bitclock-inversion -- frame-inversion -- dai-tdm-slot-num -- dai-tdm-slot-width -- clocks / system-clock-frequency - -Below are same as Simple-SCU-Card. - -- convert-rate -- convert-channels -- prefix -- routing - -Required properties: - -- compatible : "audio-graph-scu-card"; -- dais : list of CPU DAI port{s} - -Example 1. Sampling Rate Conversion - - sound_card { - compatible = "audio-graph-scu-card"; - - label = "sound-card"; - prefix = "codec"; - routing = "codec Playback", "DAI0 Playback", - "DAI0 Capture", "codec Capture"; - convert-rate = <48000>; - - dais = <&cpu_port>; - }; - - audio-codec { - ... - - port { - codec_endpoint: endpoint { - remote-endpoint = <&cpu_endpoint>; - }; - }; - }; - - dai-controller { - ... - cpu_port: port { - cpu_endpoint: endpoint { - remote-endpoint = <&codec_endpoint>; - - dai-format = "left_j"; - ... - }; - }; - }; - -Example 2. 2 CPU 1 Codec (Mixing) - - sound_card { - compatible = "audio-graph-scu-card"; - - label = "sound-card"; - routing = "codec Playback", "DAI0 Playback", - "codec Playback", "DAI1 Playback", - "DAI0 Capture", "codec Capture"; - - dais = <&cpu_port0 - &cpu_port1>; - }; - - audio-codec { - ... - - audio-graph-card,prefix = "codec"; - audio-graph-card,convert-rate = <48000>; - port { - codec_endpoint0: endpoint { - remote-endpoint = <&cpu_endpoint0>; - }; - codec_endpoint1: endpoint { - remote-endpoint = <&cpu_endpoint1>; - }; - }; - }; - - dai-controller { - ... - ports { - cpu_port0: port { - cpu_endpoint0: endpoint { - remote-endpoint = <&codec_endpoint0>; - - dai-format = "left_j"; - ... - }; - }; - cpu_port1: port { - cpu_endpoint1: endpoint { - remote-endpoint = <&codec_endpoint1>; - - dai-format = "left_j"; - ... - }; - }; - }; - }; -- cgit v1.2.3-58-ga151 From 61c263ac27a307cdf7f46aaee4810619103effad Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:32 +0900 Subject: ASoC: audio-graph-scu-card: remove audio-graph-scu-card It is already merged into audio-graph-card. audio-graph-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/Kconfig | 9 - sound/soc/generic/Makefile | 2 - sound/soc/generic/audio-graph-scu-card.c | 501 ------------------------------- 3 files changed, 512 deletions(-) delete mode 100644 sound/soc/generic/audio-graph-scu-card.c diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index 92c2cf06f40a..59190f42fc08 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -24,12 +24,3 @@ config SND_AUDIO_GRAPH_CARD This option enables generic simple sound card support with OF-graph DT bindings. It also support DPCM of multi CPU single Codec ststem. - -config SND_AUDIO_GRAPH_SCU_CARD - tristate "ASoC Audio Graph SCU sound card support" - depends on OF - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple SCU sound card support - with OF-graph DT bindings. - It supports DPCM of multi CPU single Codec ststem. diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 9dec293a4c4d..9fbfdd524b24 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -3,10 +3,8 @@ snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o snd-soc-simple-scu-card-objs := simple-scu-card.o snd-soc-audio-graph-card-objs := audio-graph-card.o -snd-soc-audio-graph-scu-card-objs := audio-graph-scu-card.o obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o -obj-$(CONFIG_SND_AUDIO_GRAPH_SCU_CARD) += snd-soc-audio-graph-scu-card.o diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c deleted file mode 100644 index e1b192ea147b..000000000000 --- a/sound/soc/generic/audio-graph-scu-card.c +++ /dev/null @@ -1,501 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ASoC audio graph SCU sound card support -// -// Copyright (C) 2017 Renesas Solutions Corp. -// Kuninori Morimoto -// -// based on -// ${LINUX}/sound/soc/generic/simple-scu-card.c -// ${LINUX}/sound/soc/generic/audio-graph-card.c - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct graph_card_data { - struct snd_soc_card snd_card; - struct graph_dai_props { - struct asoc_simple_dai *cpu_dai; - struct asoc_simple_dai *codec_dai; - struct snd_soc_dai_link_component codecs; - struct snd_soc_dai_link_component platform; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; - } *dai_props; - struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dais; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; -}; - -#define graph_priv_to_card(priv) (&(priv)->snd_card) -#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) -#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) - -#define PREFIX "audio-graph-card," - -static int asoc_graph_card_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - int ret = 0; - - ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); - if (ret) - return ret; - - ret = asoc_simple_card_clk_enable(dai_props->codec_dai); - if (ret) - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - return ret; -} - -static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - asoc_simple_card_clk_disable(dai_props->codec_dai); -} - -static const struct snd_soc_ops asoc_graph_card_ops = { - .startup = asoc_graph_card_startup, - .shutdown = asoc_graph_card_shutdown, -}; - -static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - int ret = 0; - - ret = asoc_simple_card_init_dai(rtd->codec_dai, - dai_props->codec_dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_init_dai(rtd->cpu_dai, - dai_props->cpu_dai); - if (ret < 0) - return ret; - - return 0; -} - -static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - - asoc_simple_card_convert_fixup(&dai_props->adata, params); - - /* overwrite by top level adata if exist */ - asoc_simple_card_convert_fixup(&priv->adata, params); - - return 0; -} - -static int asoc_graph_card_dai_link_of(struct device_node *cpu_ep, - struct device_node *codec_ep, - struct graph_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe) -{ - struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *ep = is_fe ? cpu_ep : codec_ep; - struct device_node *node = of_graph_get_port_parent(ep); - struct asoc_simple_dai *dai; - int ret; - - if (is_fe) { - struct snd_soc_dai_link_component *codecs; - - /* BE is dummy */ - codecs = dai_link->codecs; - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; - - /* FE settings */ - dai_link->dynamic = 1; - dai_link->dpcm_merged_format = 1; - - dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; - - ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); - if (ret) - return ret; - - ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "fe.%s", - dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - /* card->num_links includes Codec */ - asoc_simple_card_canonicalize_cpu(dai_link, - of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); - } else { - struct snd_soc_codec_conf *cconf; - - /* FE is dummy */ - dai_link->cpu_of_node = NULL; - dai_link->cpu_dai_name = "snd-soc-dummy-dai"; - dai_link->cpu_name = "snd-soc-dummy"; - - /* BE settings */ - dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; - - dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; - - cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; - - ret = asoc_simple_card_parse_graph_codec(ep, dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "be.%s", - dai_link->codecs->dai_name); - if (ret < 0) - return ret; - - /* check "prefix" from top node */ - snd_soc_of_parse_audio_prefix(card, cconf, - dai_link->codecs->of_node, - "prefix"); - /* check "prefix" from each node if top doesn't have */ - if (!cconf->of_node) - snd_soc_of_parse_node_prefix(node, cconf, - dai_link->codecs->of_node, - PREFIX "prefix"); - } - - asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata); - - ret = asoc_simple_card_of_parse_tdm(ep, dai); - if (ret) - return ret; - - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, - NULL, &dai_link->dai_fmt); - if (ret < 0) - return ret; - - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; - - return 0; -} - -static int asoc_graph_card_parse_of(struct graph_card_data *priv) -{ - struct of_phandle_iterator it; - struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - int dai_idx, link_idx, conf_idx, ret; - int rc, codec; - - if (!node) - return -EINVAL; - - /* - * we need to consider "widgets", "mclk-fs" around here - * see simple-card - */ - - ret = asoc_simple_card_of_parse_routing(card, NULL); - if (ret < 0) - return ret; - - asoc_simple_card_parse_convert(dev, node, NULL, &priv->adata); - - /* - * it supports multi CPU, single CODEC only here - * see asoc_graph_get_dais_count - */ - - link_idx = 0; - dai_idx = 0; - conf_idx = 0; - codec_port_old = NULL; - for (codec = 0; codec < 2; codec++) { - /* - * To listup valid sounds continuously, - * detect all CPU-dummy first, and - * detect all dummy-Codec second - */ - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = of_get_next_child(cpu_port, NULL); - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_graph_get_port_parent(codec_ep); - - of_node_put(cpu_ep); - of_node_put(codec_ep); - of_node_put(cpu_port); - of_node_put(codec_port); - it.node = NULL; - - if (codec) { - if (codec_port_old == codec_port) - continue; - - codec_port_old = codec_port; - } - - ret = asoc_graph_card_dai_link_of(cpu_ep, codec_ep, - priv, &dai_idx, - link_idx++, &conf_idx, - !codec); - if (ret < 0) - goto parse_of_err; - } - } - - ret = asoc_simple_card_parse_card_name(card, NULL); - if (ret) - goto parse_of_err; - - if ((card->num_links != link_idx) || - (card->num_configs != conf_idx)) { - dev_err(dev, "dai_link or codec_config wrong (%d/%d, %d/%d)\n", - card->num_links, link_idx, card->num_configs, conf_idx); - ret = -EINVAL; - goto parse_of_err; - } - - ret = 0; - -parse_of_err: - return ret; -} - -static void asoc_graph_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) -{ - struct of_phandle_iterator it; - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - struct device_node *codec_port_old2; - int rc; - - /* - * link_num : number of links. - * CPU-Codec / CPU-dummy / dummy-Codec - * dais_num : number of DAIs - * ccnf_num : number of codec_conf - * same number for dummy-Codec - * - * ex1) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 7 - * CPU2 -/ ccnf : 1 - * CPU3 --- Codec2 - * - * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec - * => 7 DAIs = 4xCPU + 3xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex2) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 6 - * CPU2 -/ ccnf : 1 - * CPU3 -/ - * - * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex3) - * CPU0 --- Codec0 link : 6 - * CPU1 -/ dais : 6 - * CPU2 --- Codec1 ccnf : 2 - * CPU3 -/ - * - * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 2 ccnf = 2xdummy-Codec - */ - codec_port_old = NULL; - codec_port_old2 = NULL; - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = of_get_next_child(cpu_port, NULL); - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_graph_get_port_parent(codec_ep); - - of_node_put(cpu_ep); - of_node_put(codec_ep); - of_node_put(codec_port); - - (*link_num)++; - (*dais_num)++; - - if (codec_port_old == codec_port) { - if (codec_port_old2 != codec_port_old) { - (*link_num)++; - (*ccnf_num)++; - } - - codec_port_old2 = codec_port_old; - continue; - } - - (*dais_num)++; - codec_port_old = codec_port; - } -} - -static int asoc_graph_card_probe(struct platform_device *pdev) -{ - struct graph_card_data *priv; - struct snd_soc_dai_link *dai_link; - struct graph_dai_props *dai_props; - struct asoc_simple_dai *dais; - struct device *dev = &pdev->dev; - struct snd_soc_card *card; - struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; - int ret, i; - - /* Allocate the private data and the DAI link array */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) - return -EINVAL; - - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); - if (!dai_props || !dai_link || !dais) - return -ENOMEM; - - /* - * Use snd_soc_dai_link_component instead of legacy style - * It is codec only. but cpu/platform will be supported in the future. - * see - * soc-core.c :: snd_soc_init_multicodec() - */ - for (i = 0; i < lnum; i++) { - dai_link[i].codecs = &dai_props[i].codecs; - dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; - } - - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; - - /* Init snd_soc_card */ - card = graph_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; - card->dai_link = priv->dai_link; - card->num_links = lnum; - card->codec_conf = cconf; - card->num_configs = cnum; - - ret = asoc_graph_card_parse_of(priv); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - asoc_simple_card_clean_reference(card); - - return ret; -} - -static int asoc_graph_card_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_card_clean_reference(card); -} - -static const struct of_device_id asoc_graph_of_match[] = { - { .compatible = "audio-graph-scu-card", }, - {}, -}; -MODULE_DEVICE_TABLE(of, asoc_graph_of_match); - -static struct platform_driver asoc_graph_card = { - .driver = { - .name = "asoc-audio-graph-scu-card", - .pm = &snd_soc_pm_ops, - .of_match_table = asoc_graph_of_match, - }, - .probe = asoc_graph_card_probe, - .remove = asoc_graph_card_remove, -}; -module_platform_driver(asoc_graph_card); - -MODULE_ALIAS("platform:asoc-audio-graph-scu-card"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ASoC Audio Graph SCU Sound Card"); -MODULE_AUTHOR("Kuninori Morimoto "); -- cgit v1.2.3-58-ga151 From bb93487b85012b2232149888d260f935e4da680d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:37 +0900 Subject: ASoC: simple-scu-card: remove simple-scu-card on Doc It is already merged into simple-card. simple-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/simple-scu-card.txt | 94 ---------------------- 1 file changed, 94 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/simple-scu-card.txt diff --git a/Documentation/devicetree/bindings/sound/simple-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-scu-card.txt deleted file mode 100644 index 3a2f71616cda..000000000000 --- a/Documentation/devicetree/bindings/sound/simple-scu-card.txt +++ /dev/null @@ -1,94 +0,0 @@ -ASoC Simple SCU Sound Card - -Simple SCU Sound Card is "Simple Sound Card" + "ALSA DPCM". -For example, you can use this driver if you want to exchange sampling rate convert, -Mixing, etc... - -Required properties: - -- compatible : "simple-scu-audio-card" - "renesas,rsrc-card" -Optional properties: - -- simple-audio-card,name : see simple-audio-card.txt -- simple-audio-card,cpu : see simple-audio-card.txt -- simple-audio-card,codec : see simple-audio-card.txt - -Optional subnode properties: - -- simple-audio-card,format : see simple-audio-card.txt -- simple-audio-card,frame-master : see simple-audio-card.txt -- simple-audio-card,bitclock-master : see simple-audio-card.txt -- simple-audio-card,bitclock-inversion : see simple-audio-card.txt -- simple-audio-card,frame-inversion : see simple-audio-card.txt -- simple-audio-card,convert-rate : platform specified sampling rate convert -- simple-audio-card,convert-channels : platform specified converted channel size (2 - 8 ch) -- simple-audio-card,prefix : see routing -- simple-audio-card,widgets : Please refer to widgets.txt. -- simple-audio-card,routing : A list of the connections between audio components. - Each entry is a pair of strings, the first being the connection's sink, - the second being the connection's source. Valid names for sources. - use audio-prefix if some components is using same sink/sources naming. - it can be used if compatible was "renesas,rsrc-card"; - -Required CPU/CODEC subnodes properties: - -- sound-dai : see simple-audio-card.txt - -Optional CPU/CODEC subnodes properties: - -- clocks / system-clock-frequency : see simple-audio-card.txt - -Example 1. Sampling Rate Conversion - -sound { - compatible = "simple-scu-audio-card"; - - simple-audio-card,name = "rsnd-ak4643"; - simple-audio-card,format = "left_j"; - simple-audio-card,bitclock-master = <&sndcodec>; - simple-audio-card,frame-master = <&sndcodec>; - - simple-audio-card,convert-rate = <48000>; - - simple-audio-card,prefix = "ak4642"; - simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", - "DAI0 Capture", "ak4642 Capture"; - - sndcpu: simple-audio-card,cpu { - sound-dai = <&rcar_sound>; - }; - - sndcodec: simple-audio-card,codec { - sound-dai = <&ak4643>; - system-clock-frequency = <11289600>; - }; -}; - -Example 2. 2 CPU 1 Codec (Mixing) - -sound { - compatible = "simple-scu-audio-card"; - - simple-audio-card,name = "rsnd-ak4643"; - simple-audio-card,format = "left_j"; - simple-audio-card,bitclock-master = <&dpcmcpu>; - simple-audio-card,frame-master = <&dpcmcpu>; - - simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", - "ak4642 Playback", "DAI1 Playback"; - - dpcmcpu: cpu@0 { - sound-dai = <&rcar_sound 0>; - }; - - cpu@1 { - sound-dai = <&rcar_sound 1>; - }; - - codec { - prefix = "ak4642"; - sound-dai = <&ak4643>; - clocks = <&audio_clock>; - }; -}; -- cgit v1.2.3-58-ga151 From c8ed6aca6b824018a39702a563f2f6591de20d64 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:42 +0900 Subject: ASoC: simple-scu-card: remove simple-scu-card It is already merged into simple-card. simple-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/Kconfig | 8 - sound/soc/generic/Makefile | 2 - sound/soc/generic/simple-scu-card.c | 474 ------------------------------------ 3 files changed, 484 deletions(-) delete mode 100644 sound/soc/generic/simple-scu-card.c diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index 59190f42fc08..83f1243145b0 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -8,14 +8,6 @@ config SND_SIMPLE_CARD This option enables generic simple sound card support It also support DPCM of multi CPU single Codec ststem. -config SND_SIMPLE_SCU_CARD - tristate "ASoC Simple SCU sound card support" - depends on OF - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple SCU sound card support. - It supports DPCM of multi CPU single Codec system. - config SND_AUDIO_GRAPH_CARD tristate "ASoC Audio Graph sound card support" depends on OF diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 9fbfdd524b24..21c29e5e0671 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -1,10 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o -snd-soc-simple-scu-card-objs := simple-scu-card.o snd-soc-audio-graph-card-objs := audio-graph-card.o obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o -obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c deleted file mode 100644 index 9d7299d536a8..000000000000 --- a/sound/soc/generic/simple-scu-card.c +++ /dev/null @@ -1,474 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ASoC simple SCU sound card support -// -// Copyright (C) 2015 Renesas Solutions Corp. -// Kuninori Morimoto -// -// based on ${LINUX}/sound/soc/generic/simple-card.c - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct simple_card_data { - struct snd_soc_card snd_card; - struct simple_dai_props { - struct asoc_simple_dai *cpu_dai; - struct asoc_simple_dai *codec_dai; - struct snd_soc_dai_link_component codecs; - struct snd_soc_dai_link_component platform; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; - } *dai_props; - struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dais; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; -}; - -#define simple_priv_to_card(priv) (&(priv)->snd_card) -#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) -#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) - -#define DAI "sound-dai" -#define CELL "#sound-dai-cells" -#define PREFIX "simple-audio-card," - -static int asoc_simple_card_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); - int ret; - - ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); - if (ret) - return ret; - - ret = asoc_simple_card_clk_enable(dai_props->codec_dai); - if (ret) - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - return ret; -} - -static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); - - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - asoc_simple_card_clk_disable(dai_props->codec_dai); -} - -static const struct snd_soc_ops asoc_simple_card_ops = { - .startup = asoc_simple_card_startup, - .shutdown = asoc_simple_card_shutdown, -}; - -static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - int ret; - - ret = asoc_simple_card_init_dai(rtd->codec_dai, - dai_props->codec_dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_init_dai(rtd->cpu_dai, - dai_props->cpu_dai); - if (ret < 0) - return ret; - - return 0; -} - -static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - - asoc_simple_card_convert_fixup(&dai_props->adata, params); - - /* overwrite by top level adata if exist */ - asoc_simple_card_convert_fixup(&priv->adata, params); - - return 0; -} - -static int asoc_simple_card_dai_link_of(struct device_node *link, - struct device_node *np, - struct device_node *codec, - struct simple_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe, - bool is_top_level_node) -{ - struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); - struct snd_soc_card *card = simple_priv_to_card(priv); - struct asoc_simple_dai *dai; - char *prefix = ""; - int ret; - - /* For single DAI link & old style of DT node */ - if (is_top_level_node) - prefix = PREFIX; - - if (is_fe) { - int is_single_links = 0; - struct snd_soc_dai_link_component *codecs; - - /* BE is dummy */ - codecs = dai_link->codecs; - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; - - /* FE settings */ - dai_link->dynamic = 1; - dai_link->dpcm_merged_format = 1; - - dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; - - ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, - &is_single_links); - if (ret) - return ret; - - ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "fe.%s", - dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); - } else { - struct snd_soc_codec_conf *cconf; - - /* FE is dummy */ - dai_link->cpu_of_node = NULL; - dai_link->cpu_dai_name = "snd-soc-dummy-dai"; - dai_link->cpu_name = "snd-soc-dummy"; - - /* BE settings */ - dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; - - dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; - - cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; - - ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "be.%s", - dai_link->codecs->dai_name); - if (ret < 0) - return ret; - - /* check "prefix" from top node */ - snd_soc_of_parse_audio_prefix(card, cconf, - dai_link->codecs->of_node, - PREFIX "prefix"); - /* check "prefix" from each node if top doesn't have */ - if (!cconf->of_node) - snd_soc_of_parse_node_prefix(np, cconf, - dai_link->codecs->of_node, - "prefix"); - } - - asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata); - - ret = asoc_simple_card_of_parse_tdm(np, dai); - if (ret) - return ret; - - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_daifmt(dev, link, codec, - prefix, &dai_link->dai_fmt); - if (ret < 0) - return ret; - - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; - - return 0; -} - -static int asoc_simple_card_parse_of(struct simple_card_data *priv) - -{ - struct device *dev = simple_priv_to_dev(priv); - struct device_node *top = dev->of_node; - struct device_node *node; - struct device_node *np; - struct device_node *codec; - struct snd_soc_card *card = simple_priv_to_card(priv); - bool is_fe; - int ret, loop; - int dai_idx, link_idx, conf_idx; - - if (!top) - return -EINVAL; - - ret = asoc_simple_card_of_parse_widgets(card, PREFIX); - if (ret < 0) - return ret; - - ret = asoc_simple_card_of_parse_routing(card, PREFIX); - if (ret < 0) - return ret; - - asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata); - - loop = 1; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = dev->of_node; - loop = 0; - } - - do { - codec = of_get_child_by_name(node, - loop ? "codec" : PREFIX "codec"); - if (!codec) - return -ENODEV; - - for_each_child_of_node(node, np) { - is_fe = (np != codec); - - ret = asoc_simple_card_dai_link_of(node, np, codec, priv, - &dai_idx, link_idx++, - &conf_idx, - is_fe, !loop); - if (ret < 0) - return ret; - } - node = of_get_next_child(top, node); - } while (loop && node); - - ret = asoc_simple_card_parse_card_name(card, PREFIX); - if (ret < 0) - return ret; - - return 0; -} - -static void asoc_simple_card_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) -{ - struct device_node *top = dev->of_node; - struct device_node *node; - int loop; - int num; - - /* - * link_num : number of links. - * CPU-Codec / CPU-dummy / dummy-Codec - * dais_num : number of DAIs - * ccnf_num : number of codec_conf - * same number for "dummy-Codec" - * - * ex1) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 7 - * CPU2 -/ ccnf : 1 - * CPU3 --- Codec2 - * - * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec - * => 7 DAIs = 4xCPU + 3xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex2) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 6 - * CPU2 -/ ccnf : 1 - * CPU3 -/ - * - * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex3) - * CPU0 --- Codec0 link : 6 - * CPU1 -/ dais : 6 - * CPU2 --- Codec1 ccnf : 2 - * CPU3 -/ - * - * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 2 ccnf = 2xdummy-Codec - */ - if (!top) { - (*link_num) = 1; - (*dais_num) = 2; - (*ccnf_num) = 0; - return; - } - - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = top; - loop = 0; - } - - do { - num = of_get_child_count(node); - (*dais_num) += num; - if (num > 2) { - (*link_num) += num; - (*ccnf_num)++; - } else { - (*link_num)++; - } - node = of_get_next_child(top, node); - } while (loop && node); -} - -static int asoc_simple_card_probe(struct platform_device *pdev) -{ - struct simple_card_data *priv; - struct snd_soc_dai_link *dai_link; - struct simple_dai_props *dai_props; - struct asoc_simple_dai *dais; - struct snd_soc_card *card; - struct snd_soc_codec_conf *cconf; - struct device *dev = &pdev->dev; - int ret, i; - int lnum = 0, dnum = 0, cnum = 0; - - /* Allocate the private data */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) - return -EINVAL; - - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); - if (!dai_props || !dai_link || !dais) - return -ENOMEM; - - /* - * Use snd_soc_dai_link_component instead of legacy style - * It is codec only. but cpu/platform will be supported in the future. - * see - * soc-core.c :: snd_soc_init_multicodec() - */ - for (i = 0; i < lnum; i++) { - dai_link[i].codecs = &dai_props[i].codecs; - dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; - } - - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; - - /* Init snd_soc_card */ - card = simple_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; - card->dai_link = priv->dai_link; - card->num_links = lnum; - card->codec_conf = cconf; - card->num_configs = cnum; - - ret = asoc_simple_card_parse_of(priv); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - asoc_simple_card_clean_reference(card); - - return ret; -} - -static int asoc_simple_card_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_card_clean_reference(card); -} - -static const struct of_device_id asoc_simple_of_match[] = { - { .compatible = "renesas,rsrc-card", }, - { .compatible = "simple-scu-audio-card", }, - {}, -}; -MODULE_DEVICE_TABLE(of, asoc_simple_of_match); - -static struct platform_driver asoc_simple_card = { - .driver = { - .name = "simple-scu-audio-card", - .pm = &snd_soc_pm_ops, - .of_match_table = asoc_simple_of_match, - }, - .probe = asoc_simple_card_probe, - .remove = asoc_simple_card_remove, -}; - -module_platform_driver(asoc_simple_card); - -MODULE_ALIAS("platform:asoc-simple-scu-card"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ASoC Simple SCU Sound Card"); -MODULE_AUTHOR("Kuninori Morimoto "); -- cgit v1.2.3-58-ga151 From e3e12ec09a18ad779b637f4a006a908cb6045aa7 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 21 Dec 2018 14:27:27 +0530 Subject: dt-bindings: ASoC: xlnx, audio-formatter: Document audio formatter bindings Added documentation for audio formatter IP core DT bindings. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- .../bindings/sound/xlnx,audio-formatter.txt | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt diff --git a/Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt b/Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt new file mode 100644 index 000000000000..cbc93c8f4963 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/xlnx,audio-formatter.txt @@ -0,0 +1,29 @@ +Device-Tree bindings for Xilinx PL audio formatter + +The IP core supports DMA, data formatting(AES<->PCM conversion) +of audio samples. + +Required properties: + - compatible: "xlnx,audio-formatter-1.0" + - interrupt-names: Names specified to list of interrupts in same + order mentioned under "interrupts". + List of supported interrupt names are: + "irq_mm2s" : interrupt from MM2S block + "irq_s2mm" : interrupt from S2MM block + - interrupts-parent: Phandle for interrupt controller. + - interrupts: List of Interrupt numbers. + - reg: Base address and size of the IP core instance. + - clock-names: List of input clocks. + Required elements: "s_axi_lite_aclk", "aud_mclk" + - clocks: Input clock specifier. Refer to common clock bindings. + +Example: + audio_ss_0_audio_formatter_0: audio_formatter@80010000 { + compatible = "xlnx,audio-formatter-1.0"; + interrupt-names = "irq_mm2s", "irq_s2mm"; + interrupt-parent = <&gic>; + interrupts = <0 104 4>, <0 105 4>; + reg = <0x0 0x80010000 0x0 0x1000>; + clock-names = "s_axi_lite_aclk", "aud_mclk"; + clocks = <&clk 71>, <&clk_wiz_1 0>; + }; -- cgit v1.2.3-58-ga151 From 6f6c3c36f0917be24587eeba818ab4fdfcb5465a Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 21 Dec 2018 14:27:28 +0530 Subject: ASoC: xlnx: add pcm formatter platform driver The audio formatter PL IP supports DMA of two streams - mm2s and s2mm for playback and capture respectively. Apart from DMA, IP also does conversions like PCM to AES and viceversa. This patch adds DMA component driver for the IP. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_formatter_pcm.c | 565 ++++++++++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) create mode 100644 sound/soc/xilinx/xlnx_formatter_pcm.c diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c new file mode 100644 index 000000000000..f7235f7664d7 --- /dev/null +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Xilinx ASoC audio formatter support +// +// Copyright (C) 2018 Xilinx, Inc. +// +// Author: Maruthi Srinivas Bayyavarapu + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRV_NAME "xlnx_formatter_pcm" + +#define XLNX_S2MM_OFFSET 0 +#define XLNX_MM2S_OFFSET 0x100 + +#define XLNX_AUD_CORE_CONFIG 0x4 +#define XLNX_AUD_CTRL 0x10 +#define XLNX_AUD_STS 0x14 + +#define AUD_CTRL_RESET_MASK BIT(1) +#define AUD_CFG_MM2S_MASK BIT(15) +#define AUD_CFG_S2MM_MASK BIT(31) + +#define XLNX_AUD_FS_MULTIPLIER 0x18 +#define XLNX_AUD_PERIOD_CONFIG 0x1C +#define XLNX_AUD_BUFF_ADDR_LSB 0x20 +#define XLNX_AUD_BUFF_ADDR_MSB 0x24 +#define XLNX_AUD_XFER_COUNT 0x28 +#define XLNX_AUD_CH_STS_START 0x2C +#define XLNX_BYTES_PER_CH 0x44 + +#define AUD_STS_IOC_IRQ_MASK BIT(31) +#define AUD_STS_CH_STS_MASK BIT(29) +#define AUD_CTRL_IOC_IRQ_MASK BIT(13) +#define AUD_CTRL_TOUT_IRQ_MASK BIT(14) +#define AUD_CTRL_DMA_EN_MASK BIT(0) + +#define CFG_MM2S_CH_MASK GENMASK(11, 8) +#define CFG_MM2S_CH_SHIFT 8 +#define CFG_MM2S_XFER_MASK GENMASK(14, 13) +#define CFG_MM2S_XFER_SHIFT 13 +#define CFG_MM2S_PKG_MASK BIT(12) + +#define CFG_S2MM_CH_MASK GENMASK(27, 24) +#define CFG_S2MM_CH_SHIFT 24 +#define CFG_S2MM_XFER_MASK GENMASK(30, 29) +#define CFG_S2MM_XFER_SHIFT 29 +#define CFG_S2MM_PKG_MASK BIT(28) + +#define AUD_CTRL_DATA_WIDTH_SHIFT 16 +#define AUD_CTRL_ACTIVE_CH_SHIFT 19 +#define PERIOD_CFG_PERIODS_SHIFT 16 + +#define PERIODS_MIN 2 +#define PERIODS_MAX 6 +#define PERIOD_BYTES_MIN 192 +#define PERIOD_BYTES_MAX (50 * 1024) + +enum bit_depth { + BIT_DEPTH_8, + BIT_DEPTH_16, + BIT_DEPTH_20, + BIT_DEPTH_24, + BIT_DEPTH_32, +}; + +struct xlnx_pcm_drv_data { + void __iomem *mmio; + bool s2mm_presence; + bool mm2s_presence; + unsigned int s2mm_irq; + unsigned int mm2s_irq; + struct snd_pcm_substream *play_stream; + struct snd_pcm_substream *capture_stream; + struct clk *axi_clk; +}; + +/* + * struct xlnx_pcm_stream_param - stream configuration + * @mmio: base address offset + * @interleaved: audio channels arrangement in buffer + * @xfer_mode: data formatting mode during transfer + * @ch_limit: Maximum channels supported + * @buffer_size: stream ring buffer size + */ +struct xlnx_pcm_stream_param { + void __iomem *mmio; + bool interleaved; + u32 xfer_mode; + u32 ch_limit; + u64 buffer_size; +}; + +static const struct snd_pcm_hardware xlnx_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_BATCH | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_min = 8000, + .rate_max = 192000, + .buffer_bytes_max = PERIODS_MAX * PERIOD_BYTES_MAX, + .period_bytes_min = PERIOD_BYTES_MIN, + .period_bytes_max = PERIOD_BYTES_MAX, + .periods_min = PERIODS_MIN, + .periods_max = PERIODS_MAX, +}; + +static int xlnx_formatter_pcm_reset(void __iomem *mmio_base) +{ + u32 val, retries = 0; + + val = readl(mmio_base + XLNX_AUD_CTRL); + val |= AUD_CTRL_RESET_MASK; + writel(val, mmio_base + XLNX_AUD_CTRL); + + val = readl(mmio_base + XLNX_AUD_CTRL); + /* Poll for maximum timeout of approximately 100ms (1 * 100)*/ + while ((val & AUD_CTRL_RESET_MASK) && (retries < 100)) { + mdelay(1); + retries++; + val = readl(mmio_base + XLNX_AUD_CTRL); + } + if (val & AUD_CTRL_RESET_MASK) + return -ENODEV; + + return 0; +} + +static void xlnx_formatter_disable_irqs(void __iomem *mmio_base, int stream) +{ + u32 val; + + val = readl(mmio_base + XLNX_AUD_CTRL); + val &= ~AUD_CTRL_IOC_IRQ_MASK; + if (stream == SNDRV_PCM_STREAM_CAPTURE) + val &= ~AUD_CTRL_TOUT_IRQ_MASK; + + writel(val, mmio_base + XLNX_AUD_CTRL); +} + +static irqreturn_t xlnx_mm2s_irq_handler(int irq, void *arg) +{ + u32 val; + void __iomem *reg; + struct device *dev = arg; + struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev); + + reg = adata->mmio + XLNX_MM2S_OFFSET + XLNX_AUD_STS; + val = readl(reg); + if (val & AUD_STS_IOC_IRQ_MASK) { + writel(val & AUD_STS_IOC_IRQ_MASK, reg); + if (adata->play_stream) + snd_pcm_period_elapsed(adata->play_stream); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg) +{ + u32 val; + void __iomem *reg; + struct device *dev = arg; + struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev); + + reg = adata->mmio + XLNX_S2MM_OFFSET + XLNX_AUD_STS; + val = readl(reg); + if (val & AUD_STS_IOC_IRQ_MASK) { + writel(val & AUD_STS_IOC_IRQ_MASK, reg); + if (adata->capture_stream) + snd_pcm_period_elapsed(adata->capture_stream); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int xlnx_formatter_pcm_open(struct snd_pcm_substream *substream) +{ + int err; + u32 val, data_format_mode; + u32 ch_count_mask, ch_count_shift, data_xfer_mode, data_xfer_shift; + struct xlnx_pcm_stream_param *stream_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, + DRV_NAME); + struct xlnx_pcm_drv_data *adata = dev_get_drvdata(component->dev); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + !adata->mm2s_presence) + return -ENODEV; + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + !adata->s2mm_presence) + return -ENODEV; + + stream_data = kzalloc(sizeof(*stream_data), GFP_KERNEL); + if (!stream_data) + return -ENOMEM; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ch_count_mask = CFG_MM2S_CH_MASK; + ch_count_shift = CFG_MM2S_CH_SHIFT; + data_xfer_mode = CFG_MM2S_XFER_MASK; + data_xfer_shift = CFG_MM2S_XFER_SHIFT; + data_format_mode = CFG_MM2S_PKG_MASK; + stream_data->mmio = adata->mmio + XLNX_MM2S_OFFSET; + adata->play_stream = substream; + + } else { + ch_count_mask = CFG_S2MM_CH_MASK; + ch_count_shift = CFG_S2MM_CH_SHIFT; + data_xfer_mode = CFG_S2MM_XFER_MASK; + data_xfer_shift = CFG_S2MM_XFER_SHIFT; + data_format_mode = CFG_S2MM_PKG_MASK; + stream_data->mmio = adata->mmio + XLNX_S2MM_OFFSET; + adata->capture_stream = substream; + } + + val = readl(adata->mmio + XLNX_AUD_CORE_CONFIG); + + if (!(val & data_format_mode)) + stream_data->interleaved = true; + + stream_data->xfer_mode = (val & data_xfer_mode) >> data_xfer_shift; + stream_data->ch_limit = (val & ch_count_mask) >> ch_count_shift; + dev_info(component->dev, + "stream %d : format = %d mode = %d ch_limit = %d\n", + substream->stream, stream_data->interleaved, + stream_data->xfer_mode, stream_data->ch_limit); + + snd_soc_set_runtime_hwparams(substream, &xlnx_pcm_hardware); + runtime->private_data = stream_data; + + /* Resize the period size divisible by 64 */ + err = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); + if (err) { + dev_err(component->dev, + "unable to set constraint on period bytes\n"); + return err; + } + + /* enable DMA IOC irq */ + val = readl(stream_data->mmio + XLNX_AUD_CTRL); + val |= AUD_CTRL_IOC_IRQ_MASK; + writel(val, stream_data->mmio + XLNX_AUD_CTRL); + + return 0; +} + +static int xlnx_formatter_pcm_close(struct snd_pcm_substream *substream) +{ + int ret; + struct xlnx_pcm_stream_param *stream_data = + substream->runtime->private_data; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, + DRV_NAME); + + ret = xlnx_formatter_pcm_reset(stream_data->mmio); + if (ret) { + dev_err(component->dev, "audio formatter reset failed\n"); + goto err_reset; + } + xlnx_formatter_disable_irqs(stream_data->mmio, substream->stream); + +err_reset: + kfree(stream_data); + return 0; +} + +static snd_pcm_uframes_t +xlnx_formatter_pcm_pointer(struct snd_pcm_substream *substream) +{ + u32 pos; + struct snd_pcm_runtime *runtime = substream->runtime; + struct xlnx_pcm_stream_param *stream_data = runtime->private_data; + + pos = readl(stream_data->mmio + XLNX_AUD_XFER_COUNT); + + if (pos >= stream_data->buffer_size) + pos = 0; + + return bytes_to_frames(runtime, pos); +} + +static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample; + int status; + u64 size; + struct snd_pcm_runtime *runtime = substream->runtime; + struct xlnx_pcm_stream_param *stream_data = runtime->private_data; + + active_ch = params_channels(params); + if (active_ch > stream_data->ch_limit) + return -EINVAL; + + size = params_buffer_bytes(params); + status = snd_pcm_lib_malloc_pages(substream, size); + if (status < 0) + return status; + + stream_data->buffer_size = size; + + low = lower_32_bits(substream->dma_buffer.addr); + high = upper_32_bits(substream->dma_buffer.addr); + writel(low, stream_data->mmio + XLNX_AUD_BUFF_ADDR_LSB); + writel(high, stream_data->mmio + XLNX_AUD_BUFF_ADDR_MSB); + + val = readl(stream_data->mmio + XLNX_AUD_CTRL); + bits_per_sample = params_width(params); + switch (bits_per_sample) { + case 8: + val |= (BIT_DEPTH_8 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + case 16: + val |= (BIT_DEPTH_16 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + case 20: + val |= (BIT_DEPTH_20 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + case 24: + val |= (BIT_DEPTH_24 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + case 32: + val |= (BIT_DEPTH_32 << AUD_CTRL_DATA_WIDTH_SHIFT); + break; + default: + return -EINVAL; + } + + val |= active_ch << AUD_CTRL_ACTIVE_CH_SHIFT; + writel(val, stream_data->mmio + XLNX_AUD_CTRL); + + val = (params_periods(params) << PERIOD_CFG_PERIODS_SHIFT) + | params_period_bytes(params); + writel(val, stream_data->mmio + XLNX_AUD_PERIOD_CONFIG); + bytes_per_ch = DIV_ROUND_UP(params_period_bytes(params), active_ch); + writel(bytes_per_ch, stream_data->mmio + XLNX_BYTES_PER_CH); + + return 0; +} + +static int xlnx_formatter_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int xlnx_formatter_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + u32 val; + struct xlnx_pcm_stream_param *stream_data = + substream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + val = readl(stream_data->mmio + XLNX_AUD_CTRL); + val |= AUD_CTRL_DMA_EN_MASK; + writel(val, stream_data->mmio + XLNX_AUD_CTRL); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + val = readl(stream_data->mmio + XLNX_AUD_CTRL); + val &= ~AUD_CTRL_DMA_EN_MASK; + writel(val, stream_data->mmio + XLNX_AUD_CTRL); + break; + } + + return 0; +} + +static int xlnx_formatter_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, + DRV_NAME); + return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, + SNDRV_DMA_TYPE_DEV, component->dev, + xlnx_pcm_hardware.buffer_bytes_max, + xlnx_pcm_hardware.buffer_bytes_max); +} + +static const struct snd_pcm_ops xlnx_formatter_pcm_ops = { + .open = xlnx_formatter_pcm_open, + .close = xlnx_formatter_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = xlnx_formatter_pcm_hw_params, + .hw_free = xlnx_formatter_pcm_hw_free, + .trigger = xlnx_formatter_pcm_trigger, + .pointer = xlnx_formatter_pcm_pointer, +}; + +static const struct snd_soc_component_driver xlnx_asoc_component = { + .name = DRV_NAME, + .ops = &xlnx_formatter_pcm_ops, + .pcm_new = xlnx_formatter_pcm_new, +}; + +static int xlnx_formatter_pcm_probe(struct platform_device *pdev) +{ + int ret; + u32 val; + struct xlnx_pcm_drv_data *aud_drv_data; + struct resource *res; + struct device *dev = &pdev->dev; + + aud_drv_data = devm_kzalloc(dev, sizeof(*aud_drv_data), GFP_KERNEL); + if (!aud_drv_data) + return -ENOMEM; + + aud_drv_data->axi_clk = devm_clk_get(dev, "s_axi_lite_aclk"); + if (IS_ERR(aud_drv_data->axi_clk)) { + ret = PTR_ERR(aud_drv_data->axi_clk); + dev_err(dev, "failed to get s_axi_lite_aclk(%d)\n", ret); + return ret; + } + ret = clk_prepare_enable(aud_drv_data->axi_clk); + if (ret) { + dev_err(dev, + "failed to enable s_axi_lite_aclk(%d)\n", ret); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "audio formatter node:addr to resource failed\n"); + ret = -ENXIO; + goto clk_err; + } + aud_drv_data->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(aud_drv_data->mmio)) { + dev_err(dev, "audio formatter ioremap failed\n"); + ret = PTR_ERR(aud_drv_data->mmio); + goto clk_err; + } + + val = readl(aud_drv_data->mmio + XLNX_AUD_CORE_CONFIG); + if (val & AUD_CFG_MM2S_MASK) { + aud_drv_data->mm2s_presence = true; + ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio + + XLNX_MM2S_OFFSET); + if (ret) { + dev_err(dev, "audio formatter reset failed\n"); + goto clk_err; + } + xlnx_formatter_disable_irqs(aud_drv_data->mmio + + XLNX_MM2S_OFFSET, + SNDRV_PCM_STREAM_PLAYBACK); + + aud_drv_data->mm2s_irq = platform_get_irq_byname(pdev, + "irq_mm2s"); + if (aud_drv_data->mm2s_irq < 0) { + dev_err(dev, "xlnx audio mm2s irq resource failed\n"); + ret = aud_drv_data->mm2s_irq; + goto clk_err; + } + ret = devm_request_irq(dev, aud_drv_data->mm2s_irq, + xlnx_mm2s_irq_handler, 0, + "xlnx_formatter_pcm_mm2s_irq", dev); + if (ret) { + dev_err(dev, "xlnx audio mm2s irq request failed\n"); + goto clk_err; + } + } + if (val & AUD_CFG_S2MM_MASK) { + aud_drv_data->s2mm_presence = true; + ret = xlnx_formatter_pcm_reset(aud_drv_data->mmio + + XLNX_S2MM_OFFSET); + if (ret) { + dev_err(dev, "audio formatter reset failed\n"); + goto clk_err; + } + xlnx_formatter_disable_irqs(aud_drv_data->mmio + + XLNX_S2MM_OFFSET, + SNDRV_PCM_STREAM_CAPTURE); + + aud_drv_data->s2mm_irq = platform_get_irq_byname(pdev, + "irq_s2mm"); + if (aud_drv_data->s2mm_irq < 0) { + dev_err(dev, "xlnx audio s2mm irq resource failed\n"); + ret = aud_drv_data->s2mm_irq; + goto clk_err; + } + ret = devm_request_irq(dev, aud_drv_data->s2mm_irq, + xlnx_s2mm_irq_handler, 0, + "xlnx_formatter_pcm_s2mm_irq", + dev); + if (ret) { + dev_err(dev, "xlnx audio s2mm irq request failed\n"); + goto clk_err; + } + } + + dev_set_drvdata(dev, aud_drv_data); + + ret = devm_snd_soc_register_component(dev, &xlnx_asoc_component, + NULL, 0); + if (ret) { + dev_err(dev, "pcm platform device register failed\n"); + goto clk_err; + } + + return 0; + +clk_err: + clk_disable_unprepare(aud_drv_data->axi_clk); + return ret; +} + +static int xlnx_formatter_pcm_remove(struct platform_device *pdev) +{ + int ret = 0; + struct xlnx_pcm_drv_data *adata = dev_get_drvdata(&pdev->dev); + + if (adata->s2mm_presence) + ret = xlnx_formatter_pcm_reset(adata->mmio + XLNX_S2MM_OFFSET); + + /* Try MM2S reset, even if S2MM reset fails */ + if (adata->mm2s_presence) + ret = xlnx_formatter_pcm_reset(adata->mmio + XLNX_MM2S_OFFSET); + + if (ret) + dev_err(&pdev->dev, "audio formatter reset failed\n"); + + clk_disable_unprepare(adata->axi_clk); + return ret; +} + +static const struct of_device_id xlnx_formatter_pcm_of_match[] = { + { .compatible = "xlnx,audio-formatter-1.0"}, + {}, +}; +MODULE_DEVICE_TABLE(of, xlnx_formatter_pcm_of_match); + +static struct platform_driver xlnx_formatter_pcm_driver = { + .probe = xlnx_formatter_pcm_probe, + .remove = xlnx_formatter_pcm_remove, + .driver = { + .name = DRV_NAME, + .of_match_table = xlnx_formatter_pcm_of_match, + }, +}; + +module_platform_driver(xlnx_formatter_pcm_driver); +MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-58-ga151 From b31daa15af760747b91dbb76c80306d77d8ae05f Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Fri, 21 Dec 2018 14:27:29 +0530 Subject: ASoC: xlnx: enable audio formatter driver build Enable audio formatter driver build. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/Kconfig | 7 +++++++ sound/soc/xilinx/Makefile | 2 ++ 2 files changed, 9 insertions(+) diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig index 723a583a8d57..ac48d6a00c36 100644 --- a/sound/soc/xilinx/Kconfig +++ b/sound/soc/xilinx/Kconfig @@ -6,3 +6,10 @@ config SND_SOC_XILINX_I2S mode, IP receives audio in AES format, extracts PCM and sends PCM data. In receiver mode, IP receives PCM audio and encapsulates PCM in AES format and sends AES data. + +config SND_SOC_XILINX_AUDIO_FORMATTER + tristate "Audio support for the the Xilinx audio formatter" + help + Select this option to enable Xilinx audio formatter + support. This provides DMA platform device support for + audio functionality. diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile index 6c1209b9ee75..432693b1cc79 100644 --- a/sound/soc/xilinx/Makefile +++ b/sound/soc/xilinx/Makefile @@ -1,2 +1,4 @@ snd-soc-xlnx-i2s-objs := xlnx_i2s.o obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o +snd-soc-xlnx-formatter-pcm-objs := xlnx_formatter_pcm.o +obj-$(CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER) += snd-soc-xlnx-formatter-pcm.o -- cgit v1.2.3-58-ga151 From de2949fe262197298036989924d05f5de6b9815a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:54 +0900 Subject: ASoC: audio-graph-card: add 1 CPU : 1 Codec support again audio-graph-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= audio-graph-scu) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged audio-graph-card is completely forgeting about it. This patch re-support it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 44 ++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index c3e80bc27e80..638333cdac66 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -408,6 +408,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) struct device_node *codec_ep = NULL; struct device_node *codec_port = NULL; struct device_node *codec_port_old = NULL; + struct asoc_simple_card_data adata; int rc, ret; int link_idx, dai_idx, conf_idx; int cpu; @@ -453,7 +454,13 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep); - if (of_get_child_count(codec_port) > 1) { + memset(&adata, 0, sizeof(adata)); + asoc_graph_card_get_conversion(dev, codec_ep, &adata); + asoc_graph_card_get_conversion(dev, cpu_ep, &adata); + + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || + adata.convert_channels) { /* * for DPCM sound */ @@ -495,7 +502,7 @@ static void asoc_graph_get_dais_count(struct device *dev, struct device_node *codec_ep; struct device_node *codec_port; struct device_node *codec_port_old; - struct device_node *codec_port_old2; + struct asoc_simple_card_data adata; int rc; /* @@ -534,9 +541,17 @@ static void asoc_graph_get_dais_count(struct device *dev, * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec * => 6 DAIs = 4xCPU + 2xCodec * => 2 ccnf = 2xdummy-Codec + * + * ex4) + * CPU0 --- Codec0 (convert-rate) link : 3 + * CPU1 --- Codec1 dais : 4 + * ccnf : 1 + * + * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec + * => 4 DAIs = 2xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec */ codec_port_old = NULL; - codec_port_old2 = NULL; of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { cpu_port = it.node; cpu_ep = NULL; @@ -554,17 +569,22 @@ static void asoc_graph_get_dais_count(struct device *dev, (*link_num)++; (*dais_num)++; - if (codec_port_old == codec_port) { - if (codec_port_old2 != codec_port_old) { - (*link_num)++; - (*ccnf_num)++; - } + memset(&adata, 0, sizeof(adata)); + asoc_graph_card_get_conversion(dev, codec_ep, &adata); + asoc_graph_card_get_conversion(dev, cpu_ep, &adata); - codec_port_old2 = codec_port_old; - continue; - } + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || adata.convert_channels) { - (*dais_num)++; + if (codec_port_old == codec_port) + continue; + + (*link_num)++; + (*ccnf_num)++; + (*dais_num)++; + } else { + (*dais_num)++; + } codec_port_old = codec_port; } } -- cgit v1.2.3-58-ga151 From 1e4771a62fd7a6bab058529c450d3d87a8bd5b1a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:59 +0900 Subject: ASoC: audio-graph-card: add link_info Current audio-graph-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. To preparing cleanup code, this patch adds link_info which handles number of DAIs/Links/Codec Conf, and CPU/Codec turn. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 99 +++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 638333cdac66..cd9beb801fc1 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -39,6 +39,13 @@ struct graph_card_data { struct gpio_desc *pa_gpio; }; +struct link_info { + int dais; /* number of dai */ + int link; /* number of link */ + int conf; /* number of codec_conf */ + int cpu; /* turn for CPU / Codec */ +}; + #define graph_priv_to_card(priv) (&(priv)->snd_card) #define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) @@ -189,13 +196,12 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, struct device_node *cpu_ep, struct device_node *codec_ep, struct graph_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_cpu) + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); - struct device_node *ep = is_cpu ? cpu_ep : codec_ep; + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); + struct device_node *ep = li->cpu ? cpu_ep : codec_ep; struct device_node *port = of_get_parent(ep); struct device_node *ports = of_get_parent(port); struct device_node *node = of_graph_get_port_parent(ep); @@ -203,7 +209,9 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, struct snd_soc_dai_link_component *codecs = dai_link->codecs; int ret; - dev_dbg(dev, "link_of DPCM (for %s)\n", is_cpu ? "CPU" : "Codec"); + li->link++; + + dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs); @@ -215,7 +223,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, of_node_put(ports); of_node_put(port); - if (is_cpu) { + if (li->cpu) { /* BE is dummy */ codecs->of_node = NULL; @@ -227,7 +235,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, dai_link->dpcm_merged_format = 1; dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); if (ret) @@ -259,10 +267,10 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; + dai_props->codec_conf = &priv->codec_conf[li->conf++]; ret = asoc_simple_card_parse_graph_codec(ep, dai_link); if (ret < 0) @@ -314,11 +322,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *top, struct device_node *cpu_ep, struct device_node *codec_ep, struct graph_card_data *priv, - int *dai_idx, int link_idx) + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); struct device_node *cpu_port = of_get_parent(cpu_ep); struct device_node *codec_port = of_get_parent(codec_ep); struct device_node *cpu_ports = of_get_parent(cpu_port); @@ -327,12 +335,14 @@ static int asoc_graph_card_dai_link_of(struct device_node *top, struct asoc_simple_dai *codec_dai; int ret; - dev_dbg(dev, "link_of\n"); + dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); + + li->link++; cpu_dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; codec_dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; /* Factor to mclk, used in hw_params() */ of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); @@ -409,9 +419,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) struct device_node *codec_port = NULL; struct device_node *codec_port_old = NULL; struct asoc_simple_card_data adata; + struct link_info li; int rc, ret; - int link_idx, dai_idx, conf_idx; - int cpu; ret = asoc_simple_card_of_parse_widgets(card, NULL); if (ret < 0) @@ -421,11 +430,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) if (ret < 0) return ret; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; + memset(&li, 0, sizeof(li)); codec_port_old = NULL; - for (cpu = 1; cpu >= 0; cpu--) { + for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2nd. * @@ -464,22 +471,19 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) /* * for DPCM sound */ - if (!cpu) { + if (!li.cpu) { if (codec_port_old == codec_port) continue; codec_port_old = codec_port; } ret = asoc_graph_card_dai_link_of_dpcm( - top, cpu_ep, codec_ep, priv, - &dai_idx, link_idx++, - &conf_idx, cpu); - } else if (cpu) { + top, cpu_ep, codec_ep, priv, &li); + } else if (li.cpu) { /* * for Normal sound */ ret = asoc_graph_card_dai_link_of( - top, cpu_ep, codec_ep, priv, - &dai_idx, link_idx++); + top, cpu_ep, codec_ep, priv, &li); } if (ret < 0) return ret; @@ -491,9 +495,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) } static void asoc_graph_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) + struct link_info *li) { struct of_phandle_iterator it; struct device_node *node = dev->of_node; @@ -566,8 +568,8 @@ static void asoc_graph_get_dais_count(struct device *dev, of_node_put(codec_ep); of_node_put(codec_port); - (*link_num)++; - (*dais_num)++; + li->link++; + li->dais++; memset(&adata, 0, sizeof(adata)); asoc_graph_card_get_conversion(dev, codec_ep, &adata); @@ -579,11 +581,11 @@ static void asoc_graph_get_dais_count(struct device *dev, if (codec_port_old == codec_port) continue; - (*link_num)++; - (*ccnf_num)++; - (*dais_num)++; + li->link++; + li->conf++; + li->dais++; } else { - (*dais_num)++; + li->dais++; } codec_port_old = codec_port; } @@ -615,7 +617,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct snd_soc_card *card; struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; + struct link_info li; int ret, i; /* Allocate the private data and the DAI link array */ @@ -623,14 +625,15 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) + memset(&li, 0, sizeof(li)); + asoc_graph_get_dais_count(dev, &li); + if (!li.link || !li.dais) return -EINVAL; - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); + dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); + dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); + dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); + cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL); if (!dai_props || !dai_link || !dais) return -ENOMEM; @@ -640,7 +643,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) * see * soc-core.c :: snd_soc_init_multicodec() */ - for (i = 0; i < lnum; i++) { + for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; dai_link[i].platform = &dai_props[i].platform; @@ -663,12 +666,12 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dev = dev; card->dai_link = dai_link; - card->num_links = lnum; + card->num_links = li.link; card->dapm_widgets = asoc_graph_card_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); card->probe = asoc_graph_soc_card_probe; card->codec_conf = cconf; - card->num_configs = cnum; + card->num_configs = li.conf; ret = asoc_graph_card_parse_of(priv); if (ret < 0) { -- cgit v1.2.3-58-ga151 From dd98fbc558a035728beed08a16c443f9fd37eb2b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:05 +0900 Subject: ASoC: audio-graph-card: cleanup DAI link loop method - step1 Current audio-graph-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch adds/modifies counting and parsing function for "normal sound" and "DPCM sound", and call it from link loop. This is prepare for cleanup DAI link loop method. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 134 ++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 43 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index cd9beb801fc1..fbd32129c518 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -192,23 +192,32 @@ static void asoc_graph_card_get_conversion(struct device *dev, asoc_simple_card_parse_convert(dev, ep, NULL, adata); } -static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, +static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, struct device_node *cpu_ep, struct device_node *codec_ep, - struct graph_card_data *priv, - struct link_info *li) + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); + struct device_node *top = dev->of_node; struct device_node *ep = li->cpu ? cpu_ep : codec_ep; - struct device_node *port = of_get_parent(ep); - struct device_node *ports = of_get_parent(port); - struct device_node *node = of_graph_get_port_parent(ep); + struct device_node *port; + struct device_node *ports; + struct device_node *node; struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *codecs = dai_link->codecs; int ret; + /* Do it all CPU endpoint, and 1st Codec endpoint */ + if (!li->cpu && dup_codec) + return 0; + + port = of_get_parent(ep); + ports = of_get_parent(port); + node = of_graph_get_port_parent(ep); + li->link++; dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); @@ -222,6 +231,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, of_node_put(ports); of_node_put(port); + of_node_put(node); if (li->cpu) { @@ -318,23 +328,32 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, return 0; } -static int asoc_graph_card_dai_link_of(struct device_node *top, +static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, struct device_node *cpu_ep, struct device_node *codec_ep, - struct graph_card_data *priv, struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); - struct device_node *cpu_port = of_get_parent(cpu_ep); - struct device_node *codec_port = of_get_parent(codec_ep); - struct device_node *cpu_ports = of_get_parent(cpu_port); - struct device_node *codec_ports = of_get_parent(codec_port); + struct device_node *top = dev->of_node; + struct device_node *cpu_port; + struct device_node *codec_port; + struct device_node *cpu_ports; + struct device_node *codec_ports; struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; int ret; + /* Do it only CPU turn */ + if (!li->cpu) + return 0; + + cpu_port = of_get_parent(cpu_ep); + cpu_ports = of_get_parent(cpu_port); + codec_port = of_get_parent(codec_ep); + codec_ports = of_get_parent(codec_port); + dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); li->link++; @@ -471,22 +490,19 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) /* * for DPCM sound */ - if (!li.cpu) { - if (codec_port_old == codec_port) - continue; - codec_port_old = codec_port; - } ret = asoc_graph_card_dai_link_of_dpcm( - top, cpu_ep, codec_ep, priv, &li); + priv, cpu_ep, codec_ep, &li, + (codec_port_old == codec_port)); } else if (li.cpu) { /* * for Normal sound */ ret = asoc_graph_card_dai_link_of( - top, cpu_ep, codec_ep, priv, &li); + priv, cpu_ep, codec_ep, &li); } if (ret < 0) return ret; + codec_port_old = codec_port; } } } @@ -494,9 +510,47 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) return asoc_simple_card_parse_card_name(card, NULL); } -static void asoc_graph_get_dais_count(struct device *dev, +static int asoc_graph_card_count_noml(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, struct link_info *li) { + struct device *dev = graph_priv_to_dev(priv); + + li->link += 1; /* 1xCPU-Codec */ + li->dais += 2; /* 1xCPU + 1xCodec */ + + dev_dbg(dev, "Count As Normal\n"); + + return 0; +} + +static int asoc_graph_card_count_dpcm(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) +{ + struct device *dev = graph_priv_to_dev(priv); + + li->link++; /* 1xCPU-dummy */ + li->dais++; /* 1xCPU */ + + if (!dup_codec) { + li->link++; /* 1xdummy-Codec */ + li->conf++; /* 1xdummy-Codec */ + li->dais++; /* 1xCodec */ + } + + dev_dbg(dev, "Count As DPCM\n"); + + return 0; +} + +static void asoc_graph_get_dais_count(struct graph_card_data *priv, + struct link_info *li) +{ + struct device *dev = graph_priv_to_dev(priv); struct of_phandle_iterator it; struct device_node *node = dev->of_node; struct device_node *cpu_port; @@ -568,24 +622,18 @@ static void asoc_graph_get_dais_count(struct device *dev, of_node_put(codec_ep); of_node_put(codec_port); - li->link++; - li->dais++; - memset(&adata, 0, sizeof(adata)); asoc_graph_card_get_conversion(dev, codec_ep, &adata); asoc_graph_card_get_conversion(dev, cpu_ep, &adata); if ((of_get_child_count(codec_port) > 1) || adata.convert_rate || adata.convert_channels) { - - if (codec_port_old == codec_port) - continue; - - li->link++; - li->conf++; - li->dais++; + asoc_graph_card_count_dpcm(priv, + cpu_ep, codec_ep, li, + (codec_port_old == codec_port)); } else { - li->dais++; + asoc_graph_card_count_noml(priv, + cpu_ep, codec_ep, li); } codec_port_old = codec_port; } @@ -625,8 +673,15 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + card = graph_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->dapm_widgets = asoc_graph_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); + card->probe = asoc_graph_soc_card_probe; + memset(&li, 0, sizeof(li)); - asoc_graph_get_dais_count(dev, &li); + asoc_graph_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -656,20 +711,13 @@ static int asoc_graph_card_probe(struct platform_device *pdev) return ret; } - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + priv->dais = dais; + priv->codec_conf = cconf; - /* Init snd_soc_card */ - card = graph_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; card->dai_link = dai_link; card->num_links = li.link; - card->dapm_widgets = asoc_graph_card_dapm_widgets; - card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); - card->probe = asoc_graph_soc_card_probe; card->codec_conf = cconf; card->num_configs = li.conf; -- cgit v1.2.3-58-ga151 From fce9b90c1ab7e915553c57353355700c79b39c86 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:20 +0900 Subject: ASoC: audio-graph-card: cleanup DAI link loop method - step2 Current audio-graph-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch cleanups the code by using asoc_graph_card_for_each_link() which judges normal link / DPCM link. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 168 ++++++++++++++++------------------- 1 file changed, 77 insertions(+), 91 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index fbd32129c518..1152de37110e 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -425,22 +425,80 @@ static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_parse_of(struct graph_card_data *priv) +static int asoc_graph_card_for_each_link(struct graph_card_data *priv, + struct link_info *li, + int (*func_noml)(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li), + int (*func_dpcm)(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, int dup_codec)) { struct of_phandle_iterator it; struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *top = dev->of_node; - struct device_node *node = top; + struct device_node *node = dev->of_node; struct device_node *cpu_port; - struct device_node *cpu_ep = NULL; - struct device_node *codec_ep = NULL; - struct device_node *codec_port = NULL; - struct device_node *codec_port_old = NULL; + struct device_node *cpu_ep; + struct device_node *codec_ep; + struct device_node *codec_port; + struct device_node *codec_port_old = NULL; struct asoc_simple_card_data adata; - struct link_info li; int rc, ret; + /* loop for all listed CPU port */ + of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { + cpu_port = it.node; + cpu_ep = NULL; + + /* loop for all CPU endpoint */ + while (1) { + cpu_ep = of_get_next_child(cpu_port, cpu_ep); + if (!cpu_ep) + break; + + /* get codec */ + codec_ep = of_graph_get_remote_endpoint(cpu_ep); + codec_port = of_get_parent(codec_ep); + + of_node_put(codec_ep); + of_node_put(codec_port); + + /* get convert-xxx property */ + memset(&adata, 0, sizeof(adata)); + asoc_graph_card_get_conversion(dev, codec_ep, &adata); + asoc_graph_card_get_conversion(dev, cpu_ep, &adata); + + /* + * It is DPCM + * if Codec port has many endpoints, + * or has convert-xxx property + */ + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || adata.convert_channels) + ret = func_dpcm(priv, cpu_ep, codec_ep, li, + (codec_port_old == codec_port)); + /* else normal sound */ + else + ret = func_noml(priv, cpu_ep, codec_ep, li); + + if (ret < 0) + return ret; + + codec_port_old = codec_port; + } + } + + return 0; +} + +static int asoc_graph_card_parse_of(struct graph_card_data *priv) +{ + struct snd_soc_card *card = graph_priv_to_card(priv); + struct link_info li; + int ret; + ret = asoc_simple_card_of_parse_widgets(card, NULL); if (ret < 0) return ret; @@ -450,7 +508,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) return ret; memset(&li, 0, sizeof(li)); - codec_port_old = NULL; for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2nd. @@ -464,47 +521,11 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = NULL; - while (1) { - cpu_ep = of_get_next_child(cpu_port, cpu_ep); - if (!cpu_ep) - break; - - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_get_parent(codec_ep); - - of_node_put(codec_ep); - of_node_put(codec_port); - - dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep); - - memset(&adata, 0, sizeof(adata)); - asoc_graph_card_get_conversion(dev, codec_ep, &adata); - asoc_graph_card_get_conversion(dev, cpu_ep, &adata); - - if ((of_get_child_count(codec_port) > 1) || - adata.convert_rate || - adata.convert_channels) { - /* - * for DPCM sound - */ - ret = asoc_graph_card_dai_link_of_dpcm( - priv, cpu_ep, codec_ep, &li, - (codec_port_old == codec_port)); - } else if (li.cpu) { - /* - * for Normal sound - */ - ret = asoc_graph_card_dai_link_of( - priv, cpu_ep, codec_ep, &li); - } - if (ret < 0) - return ret; - codec_port_old = codec_port; - } - } + ret = asoc_graph_card_for_each_link(priv, &li, + asoc_graph_card_dai_link_of, + asoc_graph_card_dai_link_of_dpcm); + if (ret < 0) + return ret; } return asoc_simple_card_parse_card_name(card, NULL); @@ -551,15 +572,6 @@ static void asoc_graph_get_dais_count(struct graph_card_data *priv, struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); - struct of_phandle_iterator it; - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - struct asoc_simple_card_data adata; - int rc; /* * link_num : number of links. @@ -607,37 +619,11 @@ static void asoc_graph_get_dais_count(struct graph_card_data *priv, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - codec_port_old = NULL; - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = NULL; - while (1) { - cpu_ep = of_get_next_child(cpu_port, cpu_ep); - if (!cpu_ep) - break; - - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_get_parent(codec_ep); - - of_node_put(codec_ep); - of_node_put(codec_port); - - memset(&adata, 0, sizeof(adata)); - asoc_graph_card_get_conversion(dev, codec_ep, &adata); - asoc_graph_card_get_conversion(dev, cpu_ep, &adata); - - if ((of_get_child_count(codec_port) > 1) || - adata.convert_rate || adata.convert_channels) { - asoc_graph_card_count_dpcm(priv, - cpu_ep, codec_ep, li, - (codec_port_old == codec_port)); - } else { - asoc_graph_card_count_noml(priv, - cpu_ep, codec_ep, li); - } - codec_port_old = codec_port; - } - } + asoc_graph_card_for_each_link(priv, li, + asoc_graph_card_count_noml, + asoc_graph_card_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + li->link, li->dais, li->conf); } static int asoc_graph_soc_card_probe(struct snd_soc_card *card) -- cgit v1.2.3-58-ga151 From 97fe6ca4146583d8dccdde51c143c52b385c2682 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:33 +0900 Subject: ASoC: audio-graph-card: reduce naming prefix Current audio-graph-card is using asoc_graph_card_xxx() for function / data naming. Because of this long prefix, it is easy to be 80 character over. Let's reduce prefix from asoc_graph_card_xxx() to graph_xxx(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 164 +++++++++++++++++------------------ 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 1152de37110e..3ec96cdc683b 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -20,7 +20,7 @@ #include #include -struct graph_card_data { +struct graph_priv { struct snd_soc_card snd_card; struct graph_dai_props { struct asoc_simple_dai *cpu_dai; @@ -53,12 +53,12 @@ struct link_info { #define PREFIX "audio-graph-card," -static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) +static int graph_outdrv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) { struct snd_soc_dapm_context *dapm = w->dapm; - struct graph_card_data *priv = snd_soc_card_get_drvdata(dapm->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(dapm->card); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -74,16 +74,16 @@ static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, return 0; } -static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = { +static const struct snd_soc_dapm_widget graph_dapm_widgets[] = { SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM, - 0, 0, NULL, 0, asoc_graph_card_outdrv_event, + 0, 0, NULL, 0, graph_outdrv_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), }; -static int asoc_graph_card_startup(struct snd_pcm_substream *substream) +static int graph_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); int ret; @@ -98,10 +98,10 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) return ret; } -static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) +static void graph_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); asoc_simple_card_clk_disable(dai_props->cpu_dai); @@ -109,13 +109,13 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) asoc_simple_card_clk_disable(dai_props->codec_dai); } -static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int graph_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; int ret = 0; @@ -140,15 +140,15 @@ err: return ret; } -static const struct snd_soc_ops asoc_graph_card_ops = { - .startup = asoc_graph_card_startup, - .shutdown = asoc_graph_card_shutdown, - .hw_params = asoc_graph_card_hw_params, +static const struct snd_soc_ops graph_ops = { + .startup = graph_startup, + .shutdown = graph_shutdown, + .hw_params = graph_hw_params, }; -static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) +static int graph_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); int ret = 0; @@ -165,10 +165,10 @@ static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) +static int graph_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); asoc_simple_card_convert_fixup(&dai_props->adata, params); @@ -176,9 +176,9 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static void asoc_graph_card_get_conversion(struct device *dev, - struct device_node *ep, - struct asoc_simple_card_data *adata) +static void graph_get_conversion(struct device *dev, + struct device_node *ep, + struct asoc_simple_card_data *adata) { struct device_node *top = dev->of_node; struct device_node *port = of_get_parent(ep); @@ -192,11 +192,11 @@ static void asoc_graph_card_get_conversion(struct device *dev, asoc_simple_card_parse_convert(dev, ep, NULL, adata); } -static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li, - int dup_codec) +static int graph_dai_link_of_dpcm(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); @@ -227,7 +227,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs); - asoc_graph_card_get_conversion(dev, ep, &dai_props->adata); + graph_get_conversion(dev, ep, &dai_props->adata); of_node_put(ports); of_node_put(port); @@ -274,7 +274,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, /* BE settings */ dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; + dai_link->be_hw_params_fixup = graph_be_hw_params_fixup; dai = dai_props->codec_dai = &priv->dais[li->dais++]; @@ -322,24 +322,24 @@ static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, dai_link->dpcm_playback = 1; dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; + dai_link->ops = &graph_ops; + dai_link->init = graph_dai_init; return 0; } -static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li) +static int graph_dai_link_of(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); struct device_node *top = dev->of_node; struct device_node *cpu_port; - struct device_node *codec_port; struct device_node *cpu_ports; + struct device_node *codec_port; struct device_node *codec_ports; struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; @@ -416,8 +416,8 @@ static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, if (ret < 0) return ret; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; + dai_link->ops = &graph_ops; + dai_link->init = graph_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); @@ -425,13 +425,13 @@ static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_for_each_link(struct graph_card_data *priv, +static int graph_for_each_link(struct graph_priv *priv, struct link_info *li, - int (*func_noml)(struct graph_card_data *priv, + int (*func_noml)(struct graph_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, struct link_info *li), - int (*func_dpcm)(struct graph_card_data *priv, + int (*func_dpcm)(struct graph_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, struct link_info *li, int dup_codec)) @@ -467,8 +467,8 @@ static int asoc_graph_card_for_each_link(struct graph_card_data *priv, /* get convert-xxx property */ memset(&adata, 0, sizeof(adata)); - asoc_graph_card_get_conversion(dev, codec_ep, &adata); - asoc_graph_card_get_conversion(dev, cpu_ep, &adata); + graph_get_conversion(dev, codec_ep, &adata); + graph_get_conversion(dev, cpu_ep, &adata); /* * It is DPCM @@ -493,7 +493,7 @@ static int asoc_graph_card_for_each_link(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_parse_of(struct graph_card_data *priv) +static int graph_parse_of(struct graph_priv *priv) { struct snd_soc_card *card = graph_priv_to_card(priv); struct link_info li; @@ -521,9 +521,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - ret = asoc_graph_card_for_each_link(priv, &li, - asoc_graph_card_dai_link_of, - asoc_graph_card_dai_link_of_dpcm); + ret = graph_for_each_link(priv, &li, + graph_dai_link_of, + graph_dai_link_of_dpcm); if (ret < 0) return ret; } @@ -531,10 +531,10 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) return asoc_simple_card_parse_card_name(card, NULL); } -static int asoc_graph_card_count_noml(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li) +static int graph_count_noml(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); @@ -546,11 +546,11 @@ static int asoc_graph_card_count_noml(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_count_dpcm(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li, - int dup_codec) +static int graph_count_dpcm(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); @@ -568,8 +568,8 @@ static int asoc_graph_card_count_dpcm(struct graph_card_data *priv, return 0; } -static void asoc_graph_get_dais_count(struct graph_card_data *priv, - struct link_info *li) +static void graph_get_dais_count(struct graph_priv *priv, + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); @@ -619,16 +619,16 @@ static void asoc_graph_get_dais_count(struct graph_card_data *priv, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - asoc_graph_card_for_each_link(priv, li, - asoc_graph_card_count_noml, - asoc_graph_card_count_dpcm); + graph_for_each_link(priv, li, + graph_count_noml, + graph_count_dpcm); dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); } -static int asoc_graph_soc_card_probe(struct snd_soc_card *card) +static int graph_card_probe(struct snd_soc_card *card) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(card); + struct graph_priv *priv = snd_soc_card_get_drvdata(card); int ret; ret = asoc_simple_card_init_hp(card, &priv->hp_jack, NULL); @@ -642,9 +642,9 @@ static int asoc_graph_soc_card_probe(struct snd_soc_card *card) return 0; } -static int asoc_graph_card_probe(struct platform_device *pdev) +static int graph_probe(struct platform_device *pdev) { - struct graph_card_data *priv; + struct graph_priv *priv; struct snd_soc_dai_link *dai_link; struct graph_dai_props *dai_props; struct asoc_simple_dai *dais; @@ -662,12 +662,12 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card = graph_priv_to_card(priv); card->owner = THIS_MODULE; card->dev = dev; - card->dapm_widgets = asoc_graph_card_dapm_widgets; - card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); - card->probe = asoc_graph_soc_card_probe; + card->dapm_widgets = graph_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets); + card->probe = graph_card_probe; memset(&li, 0, sizeof(li)); - asoc_graph_get_dais_count(priv, &li); + graph_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -707,7 +707,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card->codec_conf = cconf; card->num_configs = li.conf; - ret = asoc_graph_card_parse_of(priv); + ret = graph_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); @@ -727,30 +727,30 @@ err: return ret; } -static int asoc_graph_card_remove(struct platform_device *pdev) +static int graph_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); return asoc_simple_card_clean_reference(card); } -static const struct of_device_id asoc_graph_of_match[] = { +static const struct of_device_id graph_of_match[] = { { .compatible = "audio-graph-card", }, { .compatible = "audio-graph-scu-card", }, {}, }; -MODULE_DEVICE_TABLE(of, asoc_graph_of_match); +MODULE_DEVICE_TABLE(of, graph_of_match); -static struct platform_driver asoc_graph_card = { +static struct platform_driver graph_card = { .driver = { .name = "asoc-audio-graph-card", .pm = &snd_soc_pm_ops, - .of_match_table = asoc_graph_of_match, + .of_match_table = graph_of_match, }, - .probe = asoc_graph_card_probe, - .remove = asoc_graph_card_remove, + .probe = graph_probe, + .remove = graph_remove, }; -module_platform_driver(asoc_graph_card); +module_platform_driver(graph_card); MODULE_ALIAS("platform:asoc-audio-graph-card"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-58-ga151 From 7e5e1f8bbaa82e6877d8bc121cb1b44cb1ce7ddf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:42 +0900 Subject: ASoC: simple-card: add asoc_simple_card_get_conversion() simple-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= simple-scu-card) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged simple-card is completely forgeting about it. To re-support 1 CPU : 1 Codec DPCM for hw_params_fixup(), it need to judge whether it is DPCM by checking convert-rate/channel. For this purpose, this patch adds asoc_simple_card_get_conversion() as preparation Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 37e001cf9cd1..52048069b25a 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -165,6 +165,21 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static void asoc_simple_card_get_conversion(struct device *dev, + struct device_node *np, + struct asoc_simple_card_data *adata) +{ + struct device_node *top = dev->of_node; + struct device_node *node = of_get_parent(np); + + asoc_simple_card_parse_convert(dev, top, PREFIX, adata); + asoc_simple_card_parse_convert(dev, node, PREFIX, adata); + asoc_simple_card_parse_convert(dev, node, NULL, adata); + asoc_simple_card_parse_convert(dev, np, NULL, adata); + + of_node_put(node); +} + static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, struct device_node *node, struct device_node *np, @@ -260,9 +275,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, "prefix"); } - asoc_simple_card_parse_convert(dev, top, PREFIX, &dai_props->adata); - asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata); - asoc_simple_card_parse_convert(dev, np, NULL, &dai_props->adata); + asoc_simple_card_get_conversion(dev, np, &dai_props->adata); ret = asoc_simple_card_of_parse_tdm(np, dai); if (ret) -- cgit v1.2.3-58-ga151 From 7adee60ee2732f23f703ff83ee35caad561490ba Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:47 +0900 Subject: ASoC: simple-card: add 1 CPU : 1 Codec support again simple-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= simple-scu-card) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged simple-card is completely forgeting about it. This patch re-support it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 52048069b25a..b15651409c7f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -453,6 +453,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device_node *node; struct device_node *np; struct device_node *codec; + struct asoc_simple_card_data adata; bool is_fe; int ret, loop; int dai_idx, link_idx, conf_idx; @@ -480,8 +481,13 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) } do { + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + /* DPCM */ - if (of_get_child_count(node) > 2) { + if (of_get_child_count(node) > 2 || + adata.convert_rate || adata.convert_channels) { for_each_child_of_node(node, np) { codec = of_get_child_by_name(node, loop ? "codec" : @@ -495,14 +501,16 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) top, node, np, codec, priv, &dai_idx, link_idx++, &conf_idx, is_fe, !loop); + if (ret < 0) + return ret; } } else { ret = asoc_simple_card_dai_link_of( top, node, priv, &dai_idx, link_idx++, !loop); + if (ret < 0) + return ret; } - if (ret < 0) - return ret; node = of_get_next_child(top, node); } while (loop && node); @@ -523,6 +531,8 @@ static void asoc_simple_card_get_dais_count(struct device *dev, { struct device_node *top = dev->of_node; struct device_node *node; + struct device_node *np; + struct asoc_simple_card_data adata; int loop; int num; @@ -562,6 +572,15 @@ static void asoc_simple_card_get_dais_count(struct device *dev, * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec * => 6 DAIs = 4xCPU + 2xCodec * => 2 ccnf = 2xdummy-Codec + * + * ex4) + * CPU0 --- Codec0 (convert-rate) link : 3 + * CPU1 --- Codec1 dais : 4 + * ccnf : 1 + * + * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec + * => 4 DAIs = 2xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec */ if (!top) { (*link_num) = 1; @@ -578,9 +597,14 @@ static void asoc_simple_card_get_dais_count(struct device *dev, } do { + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + num = of_get_child_count(node); (*dais_num) += num; - if (num > 2) { + if (num > 2 || + adata.convert_rate || adata.convert_channels) { (*link_num) += num; (*ccnf_num)++; } else { -- cgit v1.2.3-58-ga151 From 17029e494edc68337c9b99665e8f9b478f1d4ec5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:53 +0900 Subject: ASoC: simple-card: add link_info Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. To preparing cleanup code, this patch adds link_info which handles number of DAIs/Links/Codec Conf, and CPU/Codec turn. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 94 ++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index b15651409c7f..3820ad719059 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -33,6 +33,13 @@ struct simple_card_data { struct snd_soc_codec_conf *codec_conf; }; +struct link_info { + int dais; /* number of dai */ + int link; /* number of link */ + int conf; /* number of codec_conf */ + int cpu; /* turn for CPU / Codec */ +}; + #define simple_priv_to_card(priv) (&(priv)->snd_card) #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) @@ -185,25 +192,27 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, struct device_node *np, struct device_node *codec, struct simple_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe, + struct link_info *li, bool is_top_level_node) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *codecs = dai_link->codecs; - char prop[128]; char *prefix = ""; int ret; + dev_dbg(dev, "link_of DPCM (%pOF)\n", np); + + li->link++; + /* For single DAI link & old style of DT node */ if (is_top_level_node) prefix = PREFIX; - if (is_fe) { + if (np != codec) { int is_single_links = 0; /* BE is dummy */ @@ -216,7 +225,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, dai_link->dpcm_merged_format = 1; dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, &is_single_links); @@ -247,10 +256,10 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; + dai_props->codec_conf = &priv->codec_conf[li->conf++]; ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); if (ret < 0) @@ -306,12 +315,12 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, static int asoc_simple_card_dai_link_of(struct device_node *top, struct device_node *node, struct simple_card_data *priv, - int *dai_idx, int link_idx, + struct link_info *li, bool is_top_level_node) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct device_node *cpu = NULL; @@ -321,6 +330,10 @@ static int asoc_simple_card_dai_link_of(struct device_node *top, char *prefix = ""; int ret, single_cpu; + li->link++; + + dev_dbg(dev, "link_of (%pOF)\n", node); + /* For single DAI link & old style of DT node */ if (is_top_level_node) prefix = PREFIX; @@ -347,9 +360,9 @@ static int asoc_simple_card_dai_link_of(struct device_node *top, } cpu_dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; codec_dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); @@ -454,9 +467,8 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device_node *np; struct device_node *codec; struct asoc_simple_card_data adata; - bool is_fe; + struct link_info li; int ret, loop; - int dai_idx, link_idx, conf_idx; if (!top) return -EINVAL; @@ -470,10 +482,8 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) return ret; /* Single/Muti DAI link(s) & New style of DT node */ + memset(&li, 0, sizeof(li)); loop = 1; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; node = of_get_child_by_name(top, PREFIX "dai-link"); if (!node) { node = dev->of_node; @@ -495,19 +505,16 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) if (!codec) return -ENODEV; - is_fe = (np != codec); - ret = asoc_simple_card_dai_link_of_dpcm( top, node, np, codec, priv, - &dai_idx, link_idx++, &conf_idx, - is_fe, !loop); + &li, !loop); if (ret < 0) return ret; } } else { ret = asoc_simple_card_dai_link_of( top, node, priv, - &dai_idx, link_idx++, !loop); + &li, !loop); if (ret < 0) return ret; } @@ -525,9 +532,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) } static void asoc_simple_card_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) + struct link_info *li) { struct device_node *top = dev->of_node; struct device_node *node; @@ -583,9 +588,9 @@ static void asoc_simple_card_get_dais_count(struct device *dev, * => 1 ccnf = 1xdummy-Codec */ if (!top) { - (*link_num) = 1; - (*dais_num) = 2; - (*ccnf_num) = 0; + li->link = 1; + li->dais = 2; + li->conf = 0; return; } @@ -602,13 +607,13 @@ static void asoc_simple_card_get_dais_count(struct device *dev, asoc_simple_card_get_conversion(dev, np, &adata); num = of_get_child_count(node); - (*dais_num) += num; + li->dais += num; if (num > 2 || adata.convert_rate || adata.convert_channels) { - (*link_num) += num; - (*ccnf_num)++; + li->link += num; + li->conf++; } else { - (*link_num)++; + li->link++; } node = of_get_next_child(top, node); } while (loop && node); @@ -640,7 +645,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct snd_soc_card *card; struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; + struct link_info li; int ret, i; /* Allocate the private data and the DAI link array */ @@ -648,14 +653,15 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) + memset(&li, 0, sizeof(li)); + asoc_simple_card_get_dais_count(dev, &li); + if (!li.link || !li.dais) return -EINVAL; - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); + dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); + dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); + dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); + cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL); if (!dai_props || !dai_link || !dais) return -ENOMEM; @@ -665,7 +671,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) * see * soc-core.c :: snd_soc_init_multicodec() */ - for (i = 0; i < lnum; i++) { + for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; dai_link[i].platform = &dai_props[i].platform; @@ -681,9 +687,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dev = dev; card->dai_link = priv->dai_link; - card->num_links = lnum; + card->num_links = li.link; card->codec_conf = cconf; - card->num_configs = cnum; + card->num_configs = li.conf; card->probe = asoc_simple_soc_card_probe; if (np && of_device_is_available(np)) { -- cgit v1.2.3-58-ga151 From d947cdfd4be29c48c6c529c2b5ce7b1988387c67 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:47:23 +0900 Subject: ASoC: simple-card: cleanup DAI link loop method - step1 Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch adds/modifies counting and parsing function for "normal sound" and "DPCM sound", and call it from link loop. This is prepare for cleanup DAI link loop method. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 210 ++++++++++++++++++++++++++-------------- 1 file changed, 137 insertions(+), 73 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 3820ad719059..4987db667165 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -187,32 +187,43 @@ static void asoc_simple_card_get_conversion(struct device *dev, of_node_put(node); } -static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, - struct device_node *node, +static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, struct device_node *np, struct device_node *codec, - struct simple_card_data *priv, struct link_info *li, - bool is_top_level_node) + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct device_node *top = dev->of_node; + struct device_node *node = of_get_parent(np); char prop[128]; char *prefix = ""; int ret; + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|Pass + * np + */ + if (li->cpu == (np == codec)) + return 0; + dev_dbg(dev, "link_of DPCM (%pOF)\n", np); li->link++; + of_node_put(node); + /* For single DAI link & old style of DT node */ - if (is_top_level_node) + if (is_top) prefix = PREFIX; - if (np != codec) { + if (li->cpu) { int is_single_links = 0; /* BE is dummy */ @@ -312,53 +323,47 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, return 0; } -static int asoc_simple_card_dai_link_of(struct device_node *top, - struct device_node *node, - struct simple_card_data *priv, +static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, struct link_info *li, - bool is_top_level_node) + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; + struct device_node *top = dev->of_node; struct device_node *cpu = NULL; + struct device_node *node = NULL; struct device_node *plat = NULL; - struct device_node *codec = NULL; char prop[128]; char *prefix = ""; int ret, single_cpu; + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|return + * np + */ + if (!li->cpu || np == codec) + return 0; + + cpu = np; + node = of_get_parent(np); li->link++; dev_dbg(dev, "link_of (%pOF)\n", node); /* For single DAI link & old style of DT node */ - if (is_top_level_node) + if (is_top) prefix = PREFIX; - snprintf(prop, sizeof(prop), "%scpu", prefix); - cpu = of_get_child_by_name(node, prop); - - if (!cpu) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; - } - snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); - snprintf(prop, sizeof(prop), "%scodec", prefix); - codec = of_get_child_by_name(node, prop); - - if (!codec) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; - } - cpu_dai = dai_props->cpu_dai = &priv->dais[li->dais++]; codec_dai = @@ -421,8 +426,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *top, asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); dai_link_of_err: - of_node_put(cpu); - of_node_put(codec); + of_node_put(node); return ret; } @@ -464,9 +468,6 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device_node *top = dev->of_node; struct snd_soc_card *card = simple_priv_to_card(priv); struct device_node *node; - struct device_node *np; - struct device_node *codec; - struct asoc_simple_card_data adata; struct link_info li; int ret, loop; @@ -483,6 +484,10 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) /* Single/Muti DAI link(s) & New style of DT node */ memset(&li, 0, sizeof(li)); + + /* FIXME */ + li.cpu = 1; +parse_loop: loop = 1; node = of_get_child_by_name(top, PREFIX "dai-link"); if (!node) { @@ -491,37 +496,59 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) } do { + struct asoc_simple_card_data adata; + struct device_node *codec; + struct device_node *np; + int num = of_get_child_count(node); + int ret; + + codec = of_get_child_by_name(node, !loop ? + PREFIX "codec" : "codec"); + if (!codec) + return -ENODEV; + + of_node_put(codec); + memset(&adata, 0, sizeof(adata)); for_each_child_of_node(node, np) asoc_simple_card_get_conversion(dev, np, &adata); - /* DPCM */ - if (of_get_child_count(node) > 2 || - adata.convert_rate || adata.convert_channels) { - for_each_child_of_node(node, np) { - codec = of_get_child_by_name(node, - loop ? "codec" : - PREFIX "codec"); - if (!codec) - return -ENODEV; - + /* + * Detect all CPU first, and Detect all Codec 2nd. + * + * In Normal sound case, all DAIs are detected + * as "CPU-Codec". + * + * In DPCM sound case, + * all CPUs are detected as "CPU-dummy", and + * all Codecs are detected as "dummy-Codec". + * To avoid random sub-device numbering, + * detect "dummy-Codec" in last; + */ + + /* loop for all CPU/Codec node */ + for_each_child_of_node(node, np) { + if (num > 2 || + adata.convert_rate || adata.convert_channels) { ret = asoc_simple_card_dai_link_of_dpcm( - top, node, np, codec, priv, - &li, !loop); + priv, np, codec, &li, !loop); + if (ret < 0) + return ret; + } else { + ret = asoc_simple_card_dai_link_of( + priv, np, codec, &li, !loop); if (ret < 0) return ret; } - } else { - ret = asoc_simple_card_dai_link_of( - top, node, priv, - &li, !loop); - if (ret < 0) - return ret; } - node = of_get_next_child(top, node); } while (loop && node); + /* FIXME */ + li.cpu--; + if (li.cpu >= 0) + goto parse_loop; + ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) return ret; @@ -531,12 +558,39 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) return ret; } -static void asoc_simple_card_get_dais_count(struct device *dev, +static int asoc_simple_card_count_noml(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) +{ + li->dais++; /* CPU or Codec */ + if (np != codec) + li->link++; /* CPU-Codec */ + + return 0; +} + +static int asoc_simple_card_count_dpcm(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) +{ + li->dais++; /* CPU or Codec */ + li->link++; /* CPU-dummy or dummy-Codec */ + if (np == codec) + li->conf++; + + return 0; +} + +static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, struct link_info *li) { + struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct device_node *node; struct device_node *np; + struct device_node *codec; struct asoc_simple_card_data adata; int loop; int num; @@ -602,18 +656,28 @@ static void asoc_simple_card_get_dais_count(struct device *dev, } do { + num = of_get_child_count(node); + + codec = of_get_child_by_name(node, !loop ? + PREFIX "codec" : "codec"); + if (!codec) + return; + + of_node_put(codec); + memset(&adata, 0, sizeof(adata)); for_each_child_of_node(node, np) asoc_simple_card_get_conversion(dev, np, &adata); - num = of_get_child_count(node); - li->dais += num; - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - li->link += num; - li->conf++; - } else { - li->link++; + for_each_child_of_node(node, np) { + if (num > 2 || + adata.convert_rate || adata.convert_channels) { + asoc_simple_card_count_dpcm(priv, np, codec, + li, !loop); + } else { + asoc_simple_card_count_noml(priv, np, codec, + li, !loop); + } } node = of_get_next_child(top, node); } while (loop && node); @@ -653,8 +717,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + card = simple_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->probe = asoc_simple_soc_card_probe; + memset(&li, 0, sizeof(li)); - asoc_simple_card_get_dais_count(dev, &li); + asoc_simple_card_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -677,20 +746,15 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dai_link[i].platform = &dai_props[i].platform; } - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + priv->dais = dais; + priv->codec_conf = cconf; - /* Init snd_soc_card */ - card = simple_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; card->dai_link = priv->dai_link; card->num_links = li.link; card->codec_conf = cconf; card->num_configs = li.conf; - card->probe = asoc_simple_soc_card_probe; if (np && of_device_is_available(np)) { -- cgit v1.2.3-58-ga151 From c39291a76444e3177f7a89d603eae7f83fbdb9f9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:47:28 +0900 Subject: ASoC: simple-card: cleanup DAI link loop method - step2 Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch cleanups the code by using asoc_simple_card_for_each_link() which judges normal link / DPCM link. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 174 +++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 93 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 4987db667165..e796b1516b40 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -431,6 +431,74 @@ dai_link_of_err: return ret; } +static int asoc_simple_card_for_each_link(struct simple_card_data *priv, + struct link_info *li, + int (*func_noml)(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top), + int (*func_dpcm)(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top)) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; + struct device_node *node; + bool is_top = 0; + + /* Check if it has dai-link */ + node = of_get_child_by_name(top, PREFIX "dai-link"); + if (!node) { + node = top; + is_top = 1; + } + + /* loop for all dai-link */ + do { + struct asoc_simple_card_data adata; + struct device_node *codec; + struct device_node *np; + int num = of_get_child_count(node); + int ret; + + /* get codec */ + codec = of_get_child_by_name(node, is_top ? + PREFIX "codec" : "codec"); + if (!codec) + return -ENODEV; + + of_node_put(codec); + + /* get convert-xxx property */ + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + + /* loop for all CPU/Codec node */ + for_each_child_of_node(node, np) { + /* + * It is DPCM + * if it has many CPUs, + * or has convert-xxx property + */ + if (num > 2 || + adata.convert_rate || adata.convert_channels) + ret = func_dpcm(priv, np, codec, li, is_top); + /* else normal sound */ + else + ret = func_noml(priv, np, codec, li, is_top); + + if (ret < 0) + return ret; + } + + node = of_get_next_child(top, node); + } while (!is_top && node); + + return 0; +} + static int asoc_simple_card_parse_aux_devs(struct device_node *node, struct simple_card_data *priv) { @@ -467,9 +535,8 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct snd_soc_card *card = simple_priv_to_card(priv); - struct device_node *node; struct link_info li; - int ret, loop; + int ret; if (!top) return -EINVAL; @@ -484,35 +551,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) /* Single/Muti DAI link(s) & New style of DT node */ memset(&li, 0, sizeof(li)); - - /* FIXME */ - li.cpu = 1; -parse_loop: - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = dev->of_node; - loop = 0; - } - - do { - struct asoc_simple_card_data adata; - struct device_node *codec; - struct device_node *np; - int num = of_get_child_count(node); - int ret; - - codec = of_get_child_by_name(node, !loop ? - PREFIX "codec" : "codec"); - if (!codec) - return -ENODEV; - - of_node_put(codec); - - memset(&adata, 0, sizeof(adata)); - for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); - + for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2nd. * @@ -525,29 +564,12 @@ parse_loop: * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - - /* loop for all CPU/Codec node */ - for_each_child_of_node(node, np) { - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - ret = asoc_simple_card_dai_link_of_dpcm( - priv, np, codec, &li, !loop); - if (ret < 0) - return ret; - } else { - ret = asoc_simple_card_dai_link_of( - priv, np, codec, &li, !loop); - if (ret < 0) - return ret; - } - } - node = of_get_next_child(top, node); - } while (loop && node); - - /* FIXME */ - li.cpu--; - if (li.cpu >= 0) - goto parse_loop; + ret = asoc_simple_card_for_each_link(priv, &li, + asoc_simple_card_dai_link_of, + asoc_simple_card_dai_link_of_dpcm); + if (ret < 0) + return ret; + } ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) @@ -588,12 +610,6 @@ static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; - struct device_node *node; - struct device_node *np; - struct device_node *codec; - struct asoc_simple_card_data adata; - int loop; - int num; /* * link_num : number of links. @@ -648,39 +664,11 @@ static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, return; } - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = top; - loop = 0; - } - - do { - num = of_get_child_count(node); - - codec = of_get_child_by_name(node, !loop ? - PREFIX "codec" : "codec"); - if (!codec) - return; - - of_node_put(codec); - - memset(&adata, 0, sizeof(adata)); - for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); - - for_each_child_of_node(node, np) { - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - asoc_simple_card_count_dpcm(priv, np, codec, - li, !loop); - } else { - asoc_simple_card_count_noml(priv, np, codec, - li, !loop); - } - } - node = of_get_next_child(top, node); - } while (loop && node); + asoc_simple_card_for_each_link(priv, li, + asoc_simple_card_count_noml, + asoc_simple_card_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + li->link, li->dais, li->conf); } static int asoc_simple_soc_card_probe(struct snd_soc_card *card) -- cgit v1.2.3-58-ga151 From 2d01a84605a55cf07ea9c6886049cc85c5e98454 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:47:34 +0900 Subject: ASoC: simple-card: reduce naming prefix Current simple-card is using asoc_simple_card_xxx() for function / data naming. Because of this long prefix, it is easy to be 80 character over. Let's reduce prefix from asoc_simple_card_xxx() to simple_xxx(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 157 ++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e796b1516b40..479de236e694 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -15,7 +15,7 @@ #include #include -struct simple_card_data { +struct simple_priv { struct snd_soc_card snd_card; struct simple_dai_props { struct asoc_simple_dai *cpu_dai; @@ -49,10 +49,10 @@ struct link_info { #define CELL "#sound-dai-cells" #define PREFIX "simple-audio-card," -static int asoc_simple_card_startup(struct snd_pcm_substream *substream) +static int simple_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; @@ -68,10 +68,10 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) return ret; } -static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) +static void simple_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); @@ -80,8 +80,8 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) asoc_simple_card_clk_disable(dai_props->codec_dai); } -static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, - unsigned long rate) +static int simple_set_clk_rate(struct asoc_simple_dai *simple_dai, + unsigned long rate) { if (!simple_dai) return 0; @@ -95,13 +95,13 @@ static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, return clk_set_rate(simple_dai->clk, rate); } -static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int simple_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; @@ -113,11 +113,11 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, if (mclk_fs) { mclk = params_rate(params) * mclk_fs; - ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk); + ret = simple_set_clk_rate(dai_props->codec_dai, mclk); if (ret < 0) return ret; - ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk); + ret = simple_set_clk_rate(dai_props->cpu_dai, mclk); if (ret < 0) return ret; @@ -136,15 +136,15 @@ err: return ret; } -static const struct snd_soc_ops asoc_simple_card_ops = { - .startup = asoc_simple_card_startup, - .shutdown = asoc_simple_card_shutdown, - .hw_params = asoc_simple_card_hw_params, +static const struct snd_soc_ops simple_ops = { + .startup = simple_startup, + .shutdown = simple_shutdown, + .hw_params = simple_hw_params, }; -static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) +static int simple_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; @@ -161,10 +161,10 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) +static int simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); asoc_simple_card_convert_fixup(&dai_props->adata, params); @@ -172,9 +172,9 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static void asoc_simple_card_get_conversion(struct device *dev, - struct device_node *np, - struct asoc_simple_card_data *adata) +static void simple_get_conversion(struct device *dev, + struct device_node *np, + struct asoc_simple_card_data *adata) { struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); @@ -187,11 +187,11 @@ static void asoc_simple_card_get_conversion(struct device *dev, of_node_put(node); } -static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, - bool is_top) +static int simple_dai_link_of_dpcm(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); @@ -264,7 +264,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, /* BE settings */ dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; + dai_link->be_hw_params_fixup = simple_be_hw_params_fixup; dai = dai_props->codec_dai = &priv->dais[li->dais++]; @@ -295,7 +295,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, "prefix"); } - asoc_simple_card_get_conversion(dev, np, &dai_props->adata); + simple_get_conversion(dev, np, &dai_props->adata); ret = asoc_simple_card_of_parse_tdm(np, dai); if (ret) @@ -317,17 +317,17 @@ static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, dai_link->dpcm_playback = 1; dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; + dai_link->ops = &simple_ops; + dai_link->init = simple_dai_init; return 0; } -static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, - bool is_top) +static int simple_dai_link_of(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); @@ -420,8 +420,8 @@ static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, if (ret < 0) goto dai_link_of_err; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; + dai_link->ops = &simple_ops; + dai_link->init = simple_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); @@ -431,13 +431,13 @@ dai_link_of_err: return ret; } -static int asoc_simple_card_for_each_link(struct simple_card_data *priv, +static int simple_for_each_link(struct simple_priv *priv, struct link_info *li, - int (*func_noml)(struct simple_card_data *priv, + int (*func_noml)(struct simple_priv *priv, struct device_node *np, struct device_node *codec, struct link_info *li, bool is_top), - int (*func_dpcm)(struct simple_card_data *priv, + int (*func_dpcm)(struct simple_priv *priv, struct device_node *np, struct device_node *codec, struct link_info *li, bool is_top)) @@ -473,7 +473,7 @@ static int asoc_simple_card_for_each_link(struct simple_card_data *priv, /* get convert-xxx property */ memset(&adata, 0, sizeof(adata)); for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); + simple_get_conversion(dev, np, &adata); /* loop for all CPU/Codec node */ for_each_child_of_node(node, np) { @@ -499,8 +499,8 @@ static int asoc_simple_card_for_each_link(struct simple_card_data *priv, return 0; } -static int asoc_simple_card_parse_aux_devs(struct device_node *node, - struct simple_card_data *priv) +static int simple_parse_aux_devs(struct device_node *node, + struct simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); struct device_node *aux_node; @@ -530,7 +530,7 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, return 0; } -static int asoc_simple_card_parse_of(struct simple_card_data *priv) +static int simple_parse_of(struct simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; @@ -564,9 +564,9 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - ret = asoc_simple_card_for_each_link(priv, &li, - asoc_simple_card_dai_link_of, - asoc_simple_card_dai_link_of_dpcm); + ret = simple_for_each_link(priv, &li, + simple_dai_link_of, + simple_dai_link_of_dpcm); if (ret < 0) return ret; } @@ -575,15 +575,15 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) if (ret < 0) return ret; - ret = asoc_simple_card_parse_aux_devs(top, priv); + ret = simple_parse_aux_devs(top, priv); return ret; } -static int asoc_simple_card_count_noml(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, bool is_top) +static int simple_count_noml(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) { li->dais++; /* CPU or Codec */ if (np != codec) @@ -592,10 +592,10 @@ static int asoc_simple_card_count_noml(struct simple_card_data *priv, return 0; } -static int asoc_simple_card_count_dpcm(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, bool is_top) +static int simple_count_dpcm(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) { li->dais++; /* CPU or Codec */ li->link++; /* CPU-dummy or dummy-Codec */ @@ -605,8 +605,8 @@ static int asoc_simple_card_count_dpcm(struct simple_card_data *priv, return 0; } -static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, - struct link_info *li) +static void simple_get_dais_count(struct simple_priv *priv, + struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; @@ -664,16 +664,17 @@ static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, return; } - asoc_simple_card_for_each_link(priv, li, - asoc_simple_card_count_noml, - asoc_simple_card_count_dpcm); + simple_for_each_link(priv, li, + simple_count_noml, + simple_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); } -static int asoc_simple_soc_card_probe(struct snd_soc_card *card) +static int simple_soc_probe(struct snd_soc_card *card) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(card); + struct simple_priv *priv = snd_soc_card_get_drvdata(card); int ret; ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX); @@ -687,9 +688,9 @@ static int asoc_simple_soc_card_probe(struct snd_soc_card *card) return 0; } -static int asoc_simple_card_probe(struct platform_device *pdev) +static int simple_probe(struct platform_device *pdev) { - struct simple_card_data *priv; + struct simple_priv *priv; struct snd_soc_dai_link *dai_link; struct simple_dai_props *dai_props; struct asoc_simple_dai *dais; @@ -708,10 +709,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev) card = simple_priv_to_card(priv); card->owner = THIS_MODULE; card->dev = dev; - card->probe = asoc_simple_soc_card_probe; + card->probe = simple_soc_probe; memset(&li, 0, sizeof(li)); - asoc_simple_card_get_dais_count(priv, &li); + simple_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -746,7 +747,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (np && of_device_is_available(np)) { - ret = asoc_simple_card_parse_of(priv); + ret = simple_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); @@ -789,7 +790,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dai_link->stream_name = cinfo->name; dai_link->cpu_dai_name = cinfo->cpu_dai.name; dai_link->dai_fmt = cinfo->daifmt; - dai_link->init = asoc_simple_card_dai_init; + dai_link->init = simple_dai_init; memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai, sizeof(*priv->dai_props->cpu_dai)); memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai, @@ -809,28 +810,28 @@ err: return ret; } -static int asoc_simple_card_remove(struct platform_device *pdev) +static int simple_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); return asoc_simple_card_clean_reference(card); } -static const struct of_device_id asoc_simple_of_match[] = { +static const struct of_device_id simple_of_match[] = { { .compatible = "simple-audio-card", }, { .compatible = "simple-scu-audio-card", }, {}, }; -MODULE_DEVICE_TABLE(of, asoc_simple_of_match); +MODULE_DEVICE_TABLE(of, simple_of_match); static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", .pm = &snd_soc_pm_ops, - .of_match_table = asoc_simple_of_match, + .of_match_table = simple_of_match, }, - .probe = asoc_simple_card_probe, - .remove = asoc_simple_card_remove, + .probe = simple_probe, + .remove = simple_remove, }; module_platform_driver(asoc_simple_card); -- cgit v1.2.3-58-ga151 From c32759035ad246d3e4c65d23a07f9e6ba32caeaf Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Fri, 21 Dec 2018 00:36:35 +0900 Subject: ASoC: rockchip: support ACODEC for rk3328 This patch adds support for audio CODEC core of rk3328. Rockchip does not publish detail specification of this core but driver source code is opened on their GitHub repository. https://github.com/rockchip-linux/kernel So I ported this code to linux-next and added some trivial fixes. Signed-off-by: Katsuhiro Suzuki Signed-off-by: Mark Brown --- .../bindings/sound/rockchip,rk3328-codec.txt | 23 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rk3328_codec.c | 517 +++++++++++++++++++++ sound/soc/codecs/rk3328_codec.h | 210 +++++++++ 5 files changed, 757 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt create mode 100644 sound/soc/codecs/rk3328_codec.c create mode 100644 sound/soc/codecs/rk3328_codec.h diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt new file mode 100644 index 000000000000..2469588c7ccb --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip,rk3328-codec.txt @@ -0,0 +1,23 @@ +* Rockchip Rk3328 internal codec + +Required properties: + +- compatible: "rockchip,rk3328-codec" +- reg: physical base address of the controller and length of memory mapped + region. +- rockchip,grf: the phandle of the syscon node for GRF register. +- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. +- clock-names: should be "pclk". +- spk-depop-time-ms: speak depop time msec. + +Example for rk3328 internal codec: + +codec: codec@ff410000 { + compatible = "rockchip,rk3328-codec"; + reg = <0x0 0xff410000 0x0 0x1000>; + rockchip,grf = <&grf>; + clocks = <&cru PCLK_ACODEC>; + clock-names = "pclk"; + spk-depop-time-ms = 100; + status = "disabled"; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d46de3e04ff6..87cb9c51e6f5 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -130,6 +130,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM5102A select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER + select SND_SOC_RK3328 select SND_SOC_RT274 if I2C select SND_SOC_RT286 if I2C select SND_SOC_RT298 if I2C @@ -806,6 +807,10 @@ config SND_SOC_PCM512x_SPI select SND_SOC_PCM512x select REGMAP_SPI +config SND_SOC_RK3328 + tristate "Rockchip RK3328 audio CODEC" + select REGMAP_MMIO + config SND_SOC_RL6231 tristate default y if SND_SOC_RT5514=y diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fbe36e6177b0..9bb3346fab2f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -133,6 +133,7 @@ snd-soc-pcm5102a-objs := pcm5102a.o snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o +snd-soc-rk3328-objs := rk3328_codec.o snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt1305-objs := rt1305.o @@ -400,6 +401,7 @@ obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o +obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c new file mode 100644 index 000000000000..71f3fc2d970c --- /dev/null +++ b/sound/soc/codecs/rk3328_codec.c @@ -0,0 +1,517 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// rk3328 ALSA SoC Audio driver +// +// Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rk3328_codec.h" + +/* + * volume setting + * 0: -39dB + * 26: 0dB + * 31: 6dB + * Step: 1.5dB + */ +#define OUT_VOLUME (0x18) +#define RK3328_GRF_SOC_CON2 (0x0408) +#define RK3328_GRF_SOC_CON10 (0x0428) +#define INITIAL_FREQ (11289600) + +struct rk3328_codec_priv { + struct regmap *regmap; + struct regmap *grf; + struct clk *mclk; + struct clk *pclk; + unsigned int sclk; + int spk_depop_time; /* msec */ +}; + +static const struct reg_default rk3328_codec_reg_defaults[] = { + { CODEC_RESET, 0x03 }, + { DAC_INIT_CTRL1, 0x00 }, + { DAC_INIT_CTRL2, 0x50 }, + { DAC_INIT_CTRL3, 0x0e }, + { DAC_PRECHARGE_CTRL, 0x01 }, + { DAC_PWR_CTRL, 0x00 }, + { DAC_CLK_CTRL, 0x00 }, + { HPMIX_CTRL, 0x00 }, + { HPOUT_CTRL, 0x00 }, + { HPOUTL_GAIN_CTRL, 0x00 }, + { HPOUTR_GAIN_CTRL, 0x00 }, + { HPOUT_POP_CTRL, 0x11 }, +}; + +static int rk3328_codec_reset(struct rk3328_codec_priv *rk3328) +{ + regmap_write(rk3328->regmap, CODEC_RESET, 0x00); + mdelay(10); + regmap_write(rk3328->regmap, CODEC_RESET, 0x03); + + return 0; +} + +static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + unsigned int val; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE; + break; + case SND_SOC_DAIFMT_CBM_CFM: + val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL1, + PIN_DIRECTION_MASK | DAC_I2S_MODE_MASK, val); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + val = DAC_MODE_PCM; + break; + case SND_SOC_DAIFMT_I2S: + val = DAC_MODE_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + val = DAC_MODE_RJM; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = DAC_MODE_LJM; + break; + default: + return -EINVAL; + } + + regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2, + DAC_MODE_MASK, val); + + return 0; +} + +static void rk3328_analog_output(struct rk3328_codec_priv *rk3328, int mute) +{ + unsigned int val = BIT(17); + + if (mute) + val |= BIT(1); + + regmap_write(rk3328->grf, RK3328_GRF_SOC_CON10, val); +} + +static int rk3328_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + unsigned int val; + + if (mute) + val = HPOUTL_MUTE | HPOUTR_MUTE; + else + val = HPOUTL_UNMUTE | HPOUTR_UNMUTE; + + regmap_update_bits(rk3328->regmap, HPOUT_CTRL, + HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, val); + + return 0; +} + +static int rk3328_codec_power_on(struct rk3328_codec_priv *rk3328, int wait_ms) +{ + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_PRECHARGE); + mdelay(10); + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_CURRENT_ALL_MASK, + DAC_CHARGE_CURRENT_ALL_ON); + mdelay(wait_ms); + + return 0; +} + +static int rk3328_codec_power_off(struct rk3328_codec_priv *rk3328, int wait_ms) +{ + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_DISCHARGE); + mdelay(10); + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_CURRENT_ALL_MASK, + DAC_CHARGE_CURRENT_ALL_ON); + mdelay(wait_ms); + + return 0; +} + +static const struct rk3328_reg_msk_val playback_open_list[] = { + { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_ON }, + { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK, + DACL_PATH_REFV_ON | DACR_PATH_REFV_ON }, + { DAC_PWR_CTRL, HPOUTL_ZERO_CROSSING_MASK | HPOUTR_ZERO_CROSSING_MASK, + HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON }, + { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK, + HPOUTR_POP_WORK | HPOUTL_POP_WORK }, + { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_EN | HPMIXR_EN }, + { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK, + HPMIXL_INIT_EN | HPMIXR_INIT_EN }, + { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_EN | HPOUTR_EN }, + { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK, + HPOUTL_INIT_EN | HPOUTR_INIT_EN }, + { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK, + DACL_REFV_ON | DACR_REFV_ON }, + { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK, + DACL_CLK_ON | DACR_CLK_ON }, + { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_ON | DACR_ON }, + { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK, + DACL_INIT_ON | DACR_INIT_ON }, + { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK, + DACL_SELECT | DACR_SELECT }, + { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK, + HPMIXL_INIT2_EN | HPMIXR_INIT2_EN }, + { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, + HPOUTL_UNMUTE | HPOUTR_UNMUTE }, +}; + +static int rk3328_codec_open_playback(struct rk3328_codec_priv *rk3328) +{ + int i; + + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_CURRENT_ALL_MASK, + DAC_CHARGE_CURRENT_I); + + for (i = 0; i < ARRAY_SIZE(playback_open_list); i++) { + regmap_update_bits(rk3328->regmap, + playback_open_list[i].reg, + playback_open_list[i].msk, + playback_open_list[i].val); + mdelay(1); + } + + msleep(rk3328->spk_depop_time); + rk3328_analog_output(rk3328, 1); + + regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL, + HPOUTL_GAIN_MASK, OUT_VOLUME); + regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL, + HPOUTR_GAIN_MASK, OUT_VOLUME); + + return 0; +} + +static const struct rk3328_reg_msk_val playback_close_list[] = { + { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK, + HPMIXL_INIT2_DIS | HPMIXR_INIT2_DIS }, + { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK, + DACL_UNSELECT | DACR_UNSELECT }, + { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, + HPOUTL_MUTE | HPOUTR_MUTE }, + { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK, + HPOUTL_INIT_DIS | HPOUTR_INIT_DIS }, + { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_DIS | HPOUTR_DIS }, + { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_DIS | HPMIXR_DIS }, + { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_OFF | DACR_OFF }, + { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK, + DACL_CLK_OFF | DACR_CLK_OFF }, + { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK, + DACL_REFV_OFF | DACR_REFV_OFF }, + { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK, + HPOUTR_POP_XCHARGE | HPOUTL_POP_XCHARGE }, + { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK, + DACL_PATH_REFV_OFF | DACR_PATH_REFV_OFF }, + { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_OFF }, + { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK, + HPMIXL_INIT_DIS | HPMIXR_INIT_DIS }, + { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK, + DACL_INIT_OFF | DACR_INIT_OFF }, +}; + +static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328) +{ + size_t i; + + rk3328_analog_output(rk3328, 0); + + regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL, + HPOUTL_GAIN_MASK, 0); + regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL, + HPOUTR_GAIN_MASK, 0); + + for (i = 0; i < ARRAY_SIZE(playback_close_list); i++) { + regmap_update_bits(rk3328->regmap, + playback_close_list[i].reg, + playback_close_list[i].msk, + playback_close_list[i].val); + mdelay(1); + } + + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, + DAC_CHARGE_CURRENT_ALL_MASK, + DAC_CHARGE_CURRENT_I); + + return 0; +} + +static int rk3328_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + unsigned int val = 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + val = DAC_VDL_16BITS; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val = DAC_VDL_20BITS; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val = DAC_VDL_24BITS; + break; + case SNDRV_PCM_FORMAT_S32_LE: + val = DAC_VDL_32BITS; + break; + default: + return -EINVAL; + } + regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2, DAC_VDL_MASK, val); + + val = DAC_WL_32BITS | DAC_RST_DIS; + regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL3, + DAC_WL_MASK | DAC_RST_MASK, val); + + return 0; +} + +static int rk3328_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + + return rk3328_codec_open_playback(rk3328); +} + +static void rk3328_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(dai->component); + + rk3328_codec_close_playback(rk3328); +} + +static const struct snd_soc_dai_ops rk3328_dai_ops = { + .hw_params = rk3328_hw_params, + .set_fmt = rk3328_set_dai_fmt, + .digital_mute = rk3328_digital_mute, + .startup = rk3328_pcm_startup, + .shutdown = rk3328_pcm_shutdown, +}; + +static struct snd_soc_dai_driver rk3328_dai[] = { + { + .name = "rk3328-hifi", + .id = RK3328_HIFI, + .playback = { + .stream_name = "HIFI Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .capture = { + .stream_name = "HIFI Capture", + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), + }, + .ops = &rk3328_dai_ops, + }, +}; + +static int rk3328_codec_probe(struct snd_soc_component *component) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(component); + + rk3328_codec_reset(rk3328); + rk3328_codec_power_on(rk3328, 0); + + return 0; +} + +static void rk3328_codec_remove(struct snd_soc_component *component) +{ + struct rk3328_codec_priv *rk3328 = + snd_soc_component_get_drvdata(component); + + rk3328_codec_close_playback(rk3328); + rk3328_codec_power_off(rk3328, 0); +} + +static const struct snd_soc_component_driver soc_codec_rk3328 = { + .probe = rk3328_codec_probe, + .remove = rk3328_codec_remove, +}; + +static bool rk3328_codec_write_read_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CODEC_RESET: + case DAC_INIT_CTRL1: + case DAC_INIT_CTRL2: + case DAC_INIT_CTRL3: + case DAC_PRECHARGE_CTRL: + case DAC_PWR_CTRL: + case DAC_CLK_CTRL: + case HPMIX_CTRL: + case DAC_SELECT: + case HPOUT_CTRL: + case HPOUTL_GAIN_CTRL: + case HPOUTR_GAIN_CTRL: + case HPOUT_POP_CTRL: + return true; + default: + return false; + } +} + +static bool rk3328_codec_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CODEC_RESET: + return true; + default: + return false; + } +} + +static const struct regmap_config rk3328_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = HPOUT_POP_CTRL, + .writeable_reg = rk3328_codec_write_read_reg, + .readable_reg = rk3328_codec_write_read_reg, + .volatile_reg = rk3328_codec_volatile_reg, + .reg_defaults = rk3328_codec_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rk3328_codec_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static int rk3328_platform_probe(struct platform_device *pdev) +{ + struct device_node *rk3328_np = pdev->dev.of_node; + struct rk3328_codec_priv *rk3328; + struct resource *res; + struct regmap *grf; + void __iomem *base; + int ret = 0; + + rk3328 = devm_kzalloc(&pdev->dev, sizeof(*rk3328), GFP_KERNEL); + if (!rk3328) + return -ENOMEM; + + grf = syscon_regmap_lookup_by_phandle(rk3328_np, + "rockchip,grf"); + if (IS_ERR(grf)) { + dev_err(&pdev->dev, "missing 'rockchip,grf'\n"); + return PTR_ERR(grf); + } + rk3328->grf = grf; + /* enable i2s_acodec_en */ + regmap_write(grf, RK3328_GRF_SOC_CON2, + (BIT(14) << 16 | BIT(14))); + + ret = of_property_read_u32(rk3328_np, "spk-depop-time-ms", + &rk3328->spk_depop_time); + if (ret < 0) { + dev_info(&pdev->dev, "spk_depop_time use default value.\n"); + rk3328->spk_depop_time = 200; + } + + rk3328_analog_output(rk3328, 0); + + rk3328->mclk = devm_clk_get(&pdev->dev, "mclk"); + if (IS_ERR(rk3328->mclk)) + return PTR_ERR(rk3328->mclk); + + ret = clk_prepare_enable(rk3328->mclk); + if (ret) + return ret; + clk_set_rate(rk3328->mclk, INITIAL_FREQ); + + rk3328->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(rk3328->pclk)) { + dev_err(&pdev->dev, "can't get acodec pclk\n"); + return PTR_ERR(rk3328->pclk); + } + + ret = clk_prepare_enable(rk3328->pclk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable acodec pclk\n"); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + rk3328->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &rk3328_codec_regmap_config); + if (IS_ERR(rk3328->regmap)) + return PTR_ERR(rk3328->regmap); + + platform_set_drvdata(pdev, rk3328); + + return devm_snd_soc_register_component(&pdev->dev, &soc_codec_rk3328, + rk3328_dai, + ARRAY_SIZE(rk3328_dai)); +} + +static const struct of_device_id rk3328_codec_of_match[] = { + { .compatible = "rockchip,rk3328-codec", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rk3328_codec_of_match); + +static struct platform_driver rk3328_codec_driver = { + .driver = { + .name = "rk3328-codec", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rk3328_codec_of_match), + }, + .probe = rk3328_platform_probe, +}; +module_platform_driver(rk3328_codec_driver); + +MODULE_AUTHOR("Sugar Zhang "); +MODULE_DESCRIPTION("ASoC rk3328 codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rk3328_codec.h b/sound/soc/codecs/rk3328_codec.h new file mode 100644 index 000000000000..655103586241 --- /dev/null +++ b/sound/soc/codecs/rk3328_codec.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rk3328 ALSA SoC Audio driver + * + * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved. + */ + +#ifndef _RK3328_CODEC_H +#define _RK3328_CODEC_H + +#include + +/* codec register */ +#define CODEC_RESET (0x00 << 2) +#define DAC_INIT_CTRL1 (0x03 << 2) +#define DAC_INIT_CTRL2 (0x04 << 2) +#define DAC_INIT_CTRL3 (0x05 << 2) +#define DAC_PRECHARGE_CTRL (0x22 << 2) +#define DAC_PWR_CTRL (0x23 << 2) +#define DAC_CLK_CTRL (0x24 << 2) +#define HPMIX_CTRL (0x25 << 2) +#define DAC_SELECT (0x26 << 2) +#define HPOUT_CTRL (0x27 << 2) +#define HPOUTL_GAIN_CTRL (0x28 << 2) +#define HPOUTR_GAIN_CTRL (0x29 << 2) +#define HPOUT_POP_CTRL (0x2a << 2) + +/* REG00: CODEC_RESET */ +#define PWR_RST_BYPASS_DIS (0x0 << 6) +#define PWR_RST_BYPASS_EN (0x1 << 6) +#define DIG_CORE_RST (0x0 << 1) +#define DIG_CORE_WORK (0x1 << 1) +#define SYS_RST (0x0 << 0) +#define SYS_WORK (0x1 << 0) + +/* REG03: DAC_INIT_CTRL1 */ +#define PIN_DIRECTION_MASK BIT(5) +#define PIN_DIRECTION_IN (0x0 << 5) +#define PIN_DIRECTION_OUT (0x1 << 5) +#define DAC_I2S_MODE_MASK BIT(4) +#define DAC_I2S_MODE_SLAVE (0x0 << 4) +#define DAC_I2S_MODE_MASTER (0x1 << 4) + +/* REG04: DAC_INIT_CTRL2 */ +#define DAC_I2S_LRP_MASK BIT(7) +#define DAC_I2S_LRP_NORMAL (0x0 << 7) +#define DAC_I2S_LRP_REVERSAL (0x1 << 7) +#define DAC_VDL_MASK GENMASK(6, 5) +#define DAC_VDL_16BITS (0x0 << 5) +#define DAC_VDL_20BITS (0x1 << 5) +#define DAC_VDL_24BITS (0x2 << 5) +#define DAC_VDL_32BITS (0x3 << 5) +#define DAC_MODE_MASK GENMASK(4, 3) +#define DAC_MODE_RJM (0x0 << 3) +#define DAC_MODE_LJM (0x1 << 3) +#define DAC_MODE_I2S (0x2 << 3) +#define DAC_MODE_PCM (0x3 << 3) +#define DAC_LR_SWAP_MASK BIT(2) +#define DAC_LR_SWAP_DIS (0x0 << 2) +#define DAC_LR_SWAP_EN (0x1 << 2) + +/* REG05: DAC_INIT_CTRL3 */ +#define DAC_WL_MASK GENMASK(3, 2) +#define DAC_WL_16BITS (0x0 << 2) +#define DAC_WL_20BITS (0x1 << 2) +#define DAC_WL_24BITS (0x2 << 2) +#define DAC_WL_32BITS (0x3 << 2) +#define DAC_RST_MASK BIT(1) +#define DAC_RST_EN (0x0 << 1) +#define DAC_RST_DIS (0x1 << 1) +#define DAC_BCP_MASK BIT(0) +#define DAC_BCP_NORMAL (0x0 << 0) +#define DAC_BCP_REVERSAL (0x1 << 0) + +/* REG22: DAC_PRECHARGE_CTRL */ +#define DAC_CHARGE_XCHARGE_MASK BIT(7) +#define DAC_CHARGE_DISCHARGE (0x0 << 7) +#define DAC_CHARGE_PRECHARGE (0x1 << 7) +#define DAC_CHARGE_CURRENT_64I_MASK BIT(6) +#define DAC_CHARGE_CURRENT_64I (0x1 << 6) +#define DAC_CHARGE_CURRENT_32I_MASK BIT(5) +#define DAC_CHARGE_CURRENT_32I (0x1 << 5) +#define DAC_CHARGE_CURRENT_16I_MASK BIT(4) +#define DAC_CHARGE_CURRENT_16I (0x1 << 4) +#define DAC_CHARGE_CURRENT_08I_MASK BIT(3) +#define DAC_CHARGE_CURRENT_08I (0x1 << 3) +#define DAC_CHARGE_CURRENT_04I_MASK BIT(2) +#define DAC_CHARGE_CURRENT_04I (0x1 << 2) +#define DAC_CHARGE_CURRENT_02I_MASK BIT(1) +#define DAC_CHARGE_CURRENT_02I (0x1 << 1) +#define DAC_CHARGE_CURRENT_I_MASK BIT(0) +#define DAC_CHARGE_CURRENT_I (0x1 << 0) +#define DAC_CHARGE_CURRENT_ALL_MASK GENMASK(6, 0) +#define DAC_CHARGE_CURRENT_ALL_OFF 0x00 +#define DAC_CHARGE_CURRENT_ALL_ON 0x7f + +/* REG23: DAC_PWR_CTRL */ +#define DAC_PWR_MASK BIT(6) +#define DAC_PWR_OFF (0x0 << 6) +#define DAC_PWR_ON (0x1 << 6) +#define DACL_PATH_REFV_MASK BIT(5) +#define DACL_PATH_REFV_OFF (0x0 << 5) +#define DACL_PATH_REFV_ON (0x1 << 5) +#define HPOUTL_ZERO_CROSSING_MASK BIT(4) +#define HPOUTL_ZERO_CROSSING_OFF (0x0 << 4) +#define HPOUTL_ZERO_CROSSING_ON (0x1 << 4) +#define DACR_PATH_REFV_MASK BIT(1) +#define DACR_PATH_REFV_OFF (0x0 << 1) +#define DACR_PATH_REFV_ON (0x1 << 1) +#define HPOUTR_ZERO_CROSSING_MASK BIT(0) +#define HPOUTR_ZERO_CROSSING_OFF (0x0 << 0) +#define HPOUTR_ZERO_CROSSING_ON (0x1 << 0) + +/* REG24: DAC_CLK_CTRL */ +#define DACL_REFV_MASK BIT(7) +#define DACL_REFV_OFF (0x0 << 7) +#define DACL_REFV_ON (0x1 << 7) +#define DACL_CLK_MASK BIT(6) +#define DACL_CLK_OFF (0x0 << 6) +#define DACL_CLK_ON (0x1 << 6) +#define DACL_MASK BIT(5) +#define DACL_OFF (0x0 << 5) +#define DACL_ON (0x1 << 5) +#define DACL_INIT_MASK BIT(4) +#define DACL_INIT_OFF (0x0 << 4) +#define DACL_INIT_ON (0x1 << 4) +#define DACR_REFV_MASK BIT(3) +#define DACR_REFV_OFF (0x0 << 3) +#define DACR_REFV_ON (0x1 << 3) +#define DACR_CLK_MASK BIT(2) +#define DACR_CLK_OFF (0x0 << 2) +#define DACR_CLK_ON (0x1 << 2) +#define DACR_MASK BIT(1) +#define DACR_OFF (0x0 << 1) +#define DACR_ON (0x1 << 1) +#define DACR_INIT_MASK BIT(0) +#define DACR_INIT_OFF (0x0 << 0) +#define DACR_INIT_ON (0x1 << 0) + +/* REG25: HPMIX_CTRL*/ +#define HPMIXL_MASK BIT(6) +#define HPMIXL_DIS (0x0 << 6) +#define HPMIXL_EN (0x1 << 6) +#define HPMIXL_INIT_MASK BIT(5) +#define HPMIXL_INIT_DIS (0x0 << 5) +#define HPMIXL_INIT_EN (0x1 << 5) +#define HPMIXL_INIT2_MASK BIT(4) +#define HPMIXL_INIT2_DIS (0x0 << 4) +#define HPMIXL_INIT2_EN (0x1 << 4) +#define HPMIXR_MASK BIT(2) +#define HPMIXR_DIS (0x0 << 2) +#define HPMIXR_EN (0x1 << 2) +#define HPMIXR_INIT_MASK BIT(1) +#define HPMIXR_INIT_DIS (0x0 << 1) +#define HPMIXR_INIT_EN (0x1 << 1) +#define HPMIXR_INIT2_MASK BIT(0) +#define HPMIXR_INIT2_DIS (0x0 << 0) +#define HPMIXR_INIT2_EN (0x1 << 0) + +/* REG26: DAC_SELECT */ +#define DACL_SELECT_MASK BIT(4) +#define DACL_UNSELECT (0x0 << 4) +#define DACL_SELECT (0x1 << 4) +#define DACR_SELECT_MASK BIT(0) +#define DACR_UNSELECT (0x0 << 0) +#define DACR_SELECT (0x1 << 0) + +/* REG27: HPOUT_CTRL */ +#define HPOUTL_MASK BIT(7) +#define HPOUTL_DIS (0x0 << 7) +#define HPOUTL_EN (0x1 << 7) +#define HPOUTL_INIT_MASK BIT(6) +#define HPOUTL_INIT_DIS (0x0 << 6) +#define HPOUTL_INIT_EN (0x1 << 6) +#define HPOUTL_MUTE_MASK BIT(5) +#define HPOUTL_MUTE (0x0 << 5) +#define HPOUTL_UNMUTE (0x1 << 5) +#define HPOUTR_MASK BIT(4) +#define HPOUTR_DIS (0x0 << 4) +#define HPOUTR_EN (0x1 << 4) +#define HPOUTR_INIT_MASK BIT(3) +#define HPOUTR_INIT_DIS (0x0 << 3) +#define HPOUTR_INIT_EN (0x1 << 3) +#define HPOUTR_MUTE_MASK BIT(2) +#define HPOUTR_MUTE (0x0 << 2) +#define HPOUTR_UNMUTE (0x1 << 2) + +/* REG28: HPOUTL_GAIN_CTRL */ +#define HPOUTL_GAIN_MASK GENMASK(4, 0) + +/* REG29: HPOUTR_GAIN_CTRL */ +#define HPOUTR_GAIN_MASK GENMASK(4, 0) + +/* REG2a: HPOUT_POP_CTRL */ +#define HPOUTR_POP_MASK GENMASK(5, 4) +#define HPOUTR_POP_XCHARGE (0x1 << 4) +#define HPOUTR_POP_WORK (0x2 << 4) +#define HPOUTL_POP_MASK GENMASK(1, 0) +#define HPOUTL_POP_XCHARGE (0x1 << 0) +#define HPOUTL_POP_WORK (0x2 << 0) + +#define RK3328_HIFI 0 + +struct rk3328_reg_msk_val { + unsigned int reg; + unsigned int msk; + unsigned int val; +}; + +#endif -- cgit v1.2.3-58-ga151 From f5758544d98c8bec7793aeea28928f5e8bd45d47 Mon Sep 17 00:00:00 2001 From: Katsuhiro Suzuki Date: Fri, 21 Dec 2018 00:36:36 +0900 Subject: ASoC: rockchip: add workaround for silence of rk3288 ACODEC This patch adds reset and precharge in shutdown of PCM device. ACODEC goes to silence if we change Fs to 44.1kHz from 48kHz. This workaround seems to work but I don't know this workaround is correct sequence or not for ACODEC. Signed-off-by: Katsuhiro Suzuki Signed-off-by: Mark Brown --- sound/soc/codecs/rk3328_codec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index 71f3fc2d970c..f3442a2283ea 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -261,9 +261,12 @@ static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328) mdelay(1); } + /* Workaround for silence when changed Fs 48 -> 44.1kHz */ + rk3328_codec_reset(rk3328); + regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL, DAC_CHARGE_CURRENT_ALL_MASK, - DAC_CHARGE_CURRENT_I); + DAC_CHARGE_CURRENT_ALL_ON); return 0; } -- cgit v1.2.3-58-ga151 From 1d38b4e903d577f05393eb0ac6727f40d90dd6c6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 26 Dec 2018 15:11:06 -0600 Subject: ASoC: xlnx: fix error handling in xlnx_formatter_pcm_probe Currently, if platform_get_irq_byname() fails, the returned error turns into a huge value, once it is being store into a variable of type unsigned int, hence never actually reporting any error and causing unexpected behavior when using the values stored in aud_drv_data->s2mm_irq and aud_drv_data->mm2s_irq. Fix this by changing the type of variables s2mm_irq and mm2s_irq in structure xlnx_pcm_drv_data from unsigned int to int. Addresses-Coverity-ID: 1476096 ("Unsigned compared against 0") Fixes: 796175a94a7f ("ASoC: xlnx: add pcm formatter platform driver") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_formatter_pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index f7235f7664d7..d2194da928e7 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -76,8 +76,8 @@ struct xlnx_pcm_drv_data { void __iomem *mmio; bool s2mm_presence; bool mm2s_presence; - unsigned int s2mm_irq; - unsigned int mm2s_irq; + int s2mm_irq; + int mm2s_irq; struct snd_pcm_substream *play_stream; struct snd_pcm_substream *capture_stream; struct clk *axi_clk; -- cgit v1.2.3-58-ga151 From e1de3d237b5083fcd0da6fcf600848a4cef9cc67 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 25 Dec 2018 02:20:36 +0000 Subject: ASoC: rockchip: fix platform_no_drv_owner.cocci warnings Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: YueHaibing Signed-off-by: Mark Brown --- sound/soc/codecs/rk3328_codec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/rk3328_codec.c b/sound/soc/codecs/rk3328_codec.c index f3442a2283ea..24f8f86d58e9 100644 --- a/sound/soc/codecs/rk3328_codec.c +++ b/sound/soc/codecs/rk3328_codec.c @@ -508,7 +508,6 @@ MODULE_DEVICE_TABLE(of, rk3328_codec_of_match); static struct platform_driver rk3328_codec_driver = { .driver = { .name = "rk3328-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(rk3328_codec_of_match), }, .probe = rk3328_platform_probe, -- cgit v1.2.3-58-ga151 From 94f45df8aaa35471ab3fc802c2cf1b75c8107500 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 3 Jan 2019 13:53:59 -0300 Subject: tools headers x86: Sync disabled-features.h To silence the following tools/perf build warning: Warning: Kernel ABI header at 'tools/arch/x86/include/asm/disabled-features.h' differs from latest version at 'arch/x86/include/asm/disabled-features.h' diff -u tools/arch/x86/include/asm/disabled-features.h arch/x86/include/asm/disabled-features.h Picking up the changes in dae0a1059300 ("x86/cpufeatures, x86/fault: Mark SMAP as disabled when configured out") that didn't entail any functionality change in the tooling side. Cc: Adrian Hunter Cc: Andy Lutomirski Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-vvge5xh6ii12oszexqknbgwp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/x86/include/asm/disabled-features.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h index 33833d1909af..a5ea841cc6d2 100644 --- a/tools/arch/x86/include/asm/disabled-features.h +++ b/tools/arch/x86/include/asm/disabled-features.h @@ -16,6 +16,12 @@ # define DISABLE_MPX (1<<(X86_FEATURE_MPX & 31)) #endif +#ifdef CONFIG_X86_SMAP +# define DISABLE_SMAP 0 +#else +# define DISABLE_SMAP (1<<(X86_FEATURE_SMAP & 31)) +#endif + #ifdef CONFIG_X86_INTEL_UMIP # define DISABLE_UMIP 0 #else @@ -68,7 +74,7 @@ #define DISABLED_MASK6 0 #define DISABLED_MASK7 (DISABLE_PTI) #define DISABLED_MASK8 0 -#define DISABLED_MASK9 (DISABLE_MPX) +#define DISABLED_MASK9 (DISABLE_MPX|DISABLE_SMAP) #define DISABLED_MASK10 0 #define DISABLED_MASK11 0 #define DISABLED_MASK12 0 -- cgit v1.2.3-58-ga151 From 96d8f63c44e5d4db48d98c40bb74d0a0e47ae301 Mon Sep 17 00:00:00 2001 From: Kent Russell Date: Thu, 3 Jan 2019 08:33:15 -0500 Subject: drm/amdgpu: Cleanup 2 compiler warnings These 2 variables are unused now, so remove their references. Fixes: e4ae0fc drm/amdgpu: implement gfx8 post_soft_reset Fixes: 5e01c09 drm/amdgpu/gfx_v8_0: Reorder the gfx, kiq and kcq rings test sequence Signed-off-by: Kent Russell Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 164ffc91b645..57cb3a51bda7 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -4233,7 +4233,6 @@ static int gfx_v8_0_cp_gfx_resume(struct amdgpu_device *adev) u32 tmp; u32 rb_bufsz; u64 rb_addr, rptr_addr, wptr_gpu_addr; - int r; /* Set the write pointer delay */ WREG32(mmCP_RB_WPTR_DELAY, 0); @@ -5075,7 +5074,6 @@ static int gfx_v8_0_post_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; u32 grbm_soft_reset = 0; - struct amdgpu_ring *ring; if ((!adev->gfx.grbm_soft_reset) && (!adev->gfx.srbm_soft_reset)) -- cgit v1.2.3-58-ga151 From abc856259a6dc513868ad91e00a70379825d59c4 Mon Sep 17 00:00:00 2001 From: Likun Gao Date: Wed, 2 Jan 2019 12:20:12 +0800 Subject: drm/amdgpu: make gfx9 enter into rlc safe mode when set MGCG MGCG should RLC enter into safe mode first. Signed-off-by: Likun Gao Reviewed-by: Huang Rui Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index f62d570a81a8..618639b8775a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3586,6 +3586,8 @@ static void gfx_v9_0_update_medium_grain_clock_gating(struct amdgpu_device *adev { uint32_t data, def; + amdgpu_gfx_rlc_enter_safe_mode(adev); + /* It is disabled by HW by default */ if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) { /* 1 - RLC_CGTT_MGCG_OVERRIDE */ @@ -3650,6 +3652,8 @@ static void gfx_v9_0_update_medium_grain_clock_gating(struct amdgpu_device *adev WREG32_SOC15(GC, 0, mmCP_MEM_SLP_CNTL, data); } } + + amdgpu_gfx_rlc_exit_safe_mode(adev); } static void gfx_v9_0_update_3d_clock_gating(struct amdgpu_device *adev, -- cgit v1.2.3-58-ga151 From 3d32c4531958c433a6ee087f31891cb02d6b68d9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 3 Jan 2019 14:56:20 -0300 Subject: tools headers uapi: Sync prctl.h with the kernel sources To get the changes in ba8308856564 ("arm64: add prctl control for resetting ptrauth keys"), that introduce a prctl with a name that needs to be catch by the prctl cmd table generator, which will be done in the next cset. Cc: Adrian Hunter Cc: Jiri Olsa Cc: Kristina Martsenko Cc: Namhyung Kim Cc: Will Deacon Link: https://lkml.kernel.org/n/tip-a1pahzc8lci0ey1fjvv1chdm@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/prctl.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/include/uapi/linux/prctl.h b/tools/include/uapi/linux/prctl.h index b17201edfa09..b4875a93363a 100644 --- a/tools/include/uapi/linux/prctl.h +++ b/tools/include/uapi/linux/prctl.h @@ -220,4 +220,12 @@ struct prctl_mm_map { # define PR_SPEC_DISABLE (1UL << 2) # define PR_SPEC_FORCE_DISABLE (1UL << 3) +/* Reset arm64 pointer authentication keys */ +#define PR_PAC_RESET_KEYS 54 +# define PR_PAC_APIAKEY (1UL << 0) +# define PR_PAC_APIBKEY (1UL << 1) +# define PR_PAC_APDAKEY (1UL << 2) +# define PR_PAC_APDBKEY (1UL << 3) +# define PR_PAC_APGAKEY (1UL << 4) + #endif /* _LINUX_PRCTL_H */ -- cgit v1.2.3-58-ga151 From 805e4c8b61bd62f6d3f416c915cb9bb423835fee Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 3 Jan 2019 14:59:11 -0300 Subject: tools beauty: Make the prctl option table generator catch all PR_ options In ba8308856564 ("arm64: add prctl control for resetting ptrauth keys") the PR_PAC_RESET_KEYS prctl option was introduced, get that into the regex in addition to PR_GET_* and PR_SET_*: So just get everything that matches '^#define PR_\w+' this ends up adding these entries: $ tools/perf/trace/beauty/prctl_option.sh > after $ diff -u before after --- before 2019-01-03 14:58:51.541807353 -0300 +++ after 2019-01-03 15:17:05.909583804 -0300 @@ -19,12 +19,18 @@ [20] = "SET_ENDIAN", [21] = "GET_SECCOMP", [22] = "SET_SECCOMP", + [23] = "CAPBSET_READ", + [24] = "CAPBSET_DROP", [25] = "GET_TSC", [26] = "SET_TSC", [27] = "GET_SECUREBITS", [28] = "SET_SECUREBITS", [29] = "SET_TIMERSLACK", [30] = "GET_TIMERSLACK", + [31] = "TASK_PERF_EVENTS_DISABLE", + [32] = "TASK_PERF_EVENTS_ENABLE", + [33] = "MCE_KILL", + [34] = "MCE_KILL_GET", [35] = "SET_MM", [36] = "SET_CHILD_SUBREAPER", [37] = "GET_CHILD_SUBREAPER", @@ -33,8 +39,13 @@ [40] = "GET_TID_ADDRESS", [41] = "SET_THP_DISABLE", [42] = "GET_THP_DISABLE", + [43] = "MPX_ENABLE_MANAGEMENT", + [44] = "MPX_DISABLE_MANAGEMENT", [45] = "SET_FP_MODE", [46] = "GET_FP_MODE", + [47] = "CAP_AMBIENT", + [50] = "SVE_SET_VL", + [51] = "SVE_GET_VL", [52] = "GET_SPECULATION_CTRL", [53] = "SET_SPECULATION_CTRL", [54] = "PAC_RESET_KEYS", $ Cc: Adrian Hunter Cc: Jiri Olsa Cc: Kristina Martsenko Cc: Namhyung Kim Cc: Will Deacon Link: https://lkml.kernel.org/n/tip-sg2pkmtjr5988bhbcp4yp6sw@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/prctl_option.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/trace/beauty/prctl_option.sh b/tools/perf/trace/beauty/prctl_option.sh index d32f8f1124af..3109d7b05e11 100755 --- a/tools/perf/trace/beauty/prctl_option.sh +++ b/tools/perf/trace/beauty/prctl_option.sh @@ -4,7 +4,7 @@ [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ printf "static const char *prctl_options[] = {\n" -regex='^#define[[:space:]]+PR_([GS]ET\w+)[[:space:]]*([[:xdigit:]]+).*' +regex='^#define[[:space:]]+PR_(\w+)[[:space:]]*([[:xdigit:]]+).*' egrep $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \ sed -r "s/$regex/\2 \1/g" | \ sort -n | xargs printf "\t[%s] = \"%s\",\n" -- cgit v1.2.3-58-ga151 From 09ad32dc6dc23beb638c48d0a2e5a9eaa8e85c6c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 3 Jan 2019 11:30:07 +0100 Subject: cpuidle / Documentation: Update cpuidle MAINTAINERS entry Update the MAINTAINERS entry for cpuidle by making it clear that it is not just drivers and adding a documentation record to it. Signed-off-by: Rafael J. Wysocki --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7808b166fdb9..5cc9e96ff2c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3964,13 +3964,14 @@ S: Supported F: drivers/cpuidle/cpuidle-exynos.c F: arch/arm/mach-exynos/pm.c -CPUIDLE DRIVERS +CPU IDLE TIME MANAGEMENT FRAMEWORK M: "Rafael J. Wysocki" M: Daniel Lezcano L: linux-pm@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git B: https://bugzilla.kernel.org +F: Documentation/admin-guide/pm/cpuidle.rst F: drivers/cpuidle/* F: include/linux/cpuidle.h -- cgit v1.2.3-58-ga151 From 1690d8bb91e370ab772062b79bd434ce815c4729 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 4 Jan 2019 15:14:33 +0530 Subject: cpufreq: scpi/scmi: Fix freeing of dynamic OPPs Since the commit 2a4eb7358aba "OPP: Don't remove dynamic OPPs from _dev_pm_opp_remove_table()", dynamically created OPP aren't automatically removed anymore by dev_pm_opp_cpumask_remove_table(). This affects the scpi and scmi cpufreq drivers which no longer free OPPs on failures or on invocations of the policy->exit() callback. Create a generic OPP helper dev_pm_opp_remove_all_dynamic() which can be called from these drivers instead of dev_pm_opp_cpumask_remove_table(). In dev_pm_opp_remove_all_dynamic(), we need to make sure that the opp_list isn't getting accessed simultaneously from other parts of the OPP core while the helper is freeing dynamic OPPs, i.e. we can't drop the opp_table->lock while traversing through the OPP list. And to accomplish that, this patch also creates _opp_kref_release_unlocked() which can be called from this new helper with the opp_table lock already held. Cc: 4.20 # v4.20 Reported-by: Valentin Schneider Fixes: 2a4eb7358aba "OPP: Don't remove dynamic OPPs from _dev_pm_opp_remove_table()" Signed-off-by: Viresh Kumar Tested-by: Valentin Schneider Reviewed-by: Sudeep Holla Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/scmi-cpufreq.c | 4 +-- drivers/cpufreq/scpi-cpufreq.c | 4 +-- drivers/opp/core.c | 63 ++++++++++++++++++++++++++++++++++++++---- include/linux/pm_opp.h | 5 ++++ 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index 50b1551ba894..c2e66528f5ee 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -176,7 +176,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) out_free_priv: kfree(priv); out_free_opp: - dev_pm_opp_cpumask_remove_table(policy->cpus); + dev_pm_opp_remove_all_dynamic(cpu_dev); return ret; } @@ -188,7 +188,7 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy) cpufreq_cooling_unregister(priv->cdev); dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); kfree(priv); - dev_pm_opp_cpumask_remove_table(policy->related_cpus); + dev_pm_opp_remove_all_dynamic(priv->cpu_dev); return 0; } diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index 87a98ec77773..99449738faa4 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c @@ -177,7 +177,7 @@ out_free_cpufreq_table: out_free_priv: kfree(priv); out_free_opp: - dev_pm_opp_cpumask_remove_table(policy->cpus); + dev_pm_opp_remove_all_dynamic(cpu_dev); return ret; } @@ -190,7 +190,7 @@ static int scpi_cpufreq_exit(struct cpufreq_policy *policy) clk_put(priv->clk); dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); kfree(priv); - dev_pm_opp_cpumask_remove_table(policy->related_cpus); + dev_pm_opp_remove_all_dynamic(priv->cpu_dev); return 0; } diff --git a/drivers/opp/core.c b/drivers/opp/core.c index e5507add8f04..18f1639dbc4a 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -988,11 +988,9 @@ void _opp_free(struct dev_pm_opp *opp) kfree(opp); } -static void _opp_kref_release(struct kref *kref) +static void _opp_kref_release(struct dev_pm_opp *opp, + struct opp_table *opp_table) { - struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref); - struct opp_table *opp_table = opp->opp_table; - /* * Notify the changes in the availability of the operable * frequency/voltage list. @@ -1002,7 +1000,22 @@ static void _opp_kref_release(struct kref *kref) opp_debug_remove_one(opp); list_del(&opp->node); kfree(opp); +} +static void _opp_kref_release_unlocked(struct kref *kref) +{ + struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref); + struct opp_table *opp_table = opp->opp_table; + + _opp_kref_release(opp, opp_table); +} + +static void _opp_kref_release_locked(struct kref *kref) +{ + struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref); + struct opp_table *opp_table = opp->opp_table; + + _opp_kref_release(opp, opp_table); mutex_unlock(&opp_table->lock); } @@ -1013,10 +1026,16 @@ void dev_pm_opp_get(struct dev_pm_opp *opp) void dev_pm_opp_put(struct dev_pm_opp *opp) { - kref_put_mutex(&opp->kref, _opp_kref_release, &opp->opp_table->lock); + kref_put_mutex(&opp->kref, _opp_kref_release_locked, + &opp->opp_table->lock); } EXPORT_SYMBOL_GPL(dev_pm_opp_put); +static void dev_pm_opp_put_unlocked(struct dev_pm_opp *opp) +{ + kref_put(&opp->kref, _opp_kref_release_unlocked); +} + /** * dev_pm_opp_remove() - Remove an OPP from OPP table * @dev: device for which we do this operation @@ -1060,6 +1079,40 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) } EXPORT_SYMBOL_GPL(dev_pm_opp_remove); +/** + * dev_pm_opp_remove_all_dynamic() - Remove all dynamically created OPPs + * @dev: device for which we do this operation + * + * This function removes all dynamically created OPPs from the opp table. + */ +void dev_pm_opp_remove_all_dynamic(struct device *dev) +{ + struct opp_table *opp_table; + struct dev_pm_opp *opp, *temp; + int count = 0; + + opp_table = _find_opp_table(dev); + if (IS_ERR(opp_table)) + return; + + mutex_lock(&opp_table->lock); + list_for_each_entry_safe(opp, temp, &opp_table->opp_list, node) { + if (opp->dynamic) { + dev_pm_opp_put_unlocked(opp); + count++; + } + } + mutex_unlock(&opp_table->lock); + + /* Drop the references taken by dev_pm_opp_add() */ + while (count--) + dev_pm_opp_put_opp_table(opp_table); + + /* Drop the reference taken by _find_opp_table() */ + dev_pm_opp_put_opp_table(opp_table); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic); + struct dev_pm_opp *_opp_allocate(struct opp_table *table) { struct dev_pm_opp *opp; diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 0a2a88e5a383..b895f4e79868 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -108,6 +108,7 @@ void dev_pm_opp_put(struct dev_pm_opp *opp); int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt); void dev_pm_opp_remove(struct device *dev, unsigned long freq); +void dev_pm_opp_remove_all_dynamic(struct device *dev); int dev_pm_opp_enable(struct device *dev, unsigned long freq); @@ -217,6 +218,10 @@ static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq) { } +static inline void dev_pm_opp_remove_all_dynamic(struct device *dev) +{ +} + static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq) { return 0; -- cgit v1.2.3-58-ga151 From 822257661031faa437336058d8a32bf1844ad9c6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:26 +0100 Subject: ASoC: es8316: Add jack-detect support Adding jack-detect support may seem weird for a codec with only a single output, but it is necessary. The ES8316 appnote showing the intended usage uses a jack-receptacle which physically disconnects the speakers from the output when a jack is plugged in. But all 3 devices using the es8316 which I have (2 Cherry Trail devices and one Bay Trail CR device), use an analog mux to disconnect the speakers, driven by a GPIO. In order to enable/disable the speakers at the right time, we need jack-detect. The same goes for the microphone where we must correctly set the mux for the single ADC to either the internal or the headset microphone. All devices I have support the es8316's builtin jack-detect functionality. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 195 +++++++++++++++++++++++++++++++++++++++++++++- sound/soc/codecs/es8316.h | 7 ++ 2 files changed, 198 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index e97d12d578b0..26413851e434 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -15,12 +15,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "es8316.h" /* In slave mode at single speed, the codec is documented as accepting 5 @@ -33,6 +35,11 @@ static const unsigned int supported_mclk_lrck_ratios[] = { }; struct es8316_priv { + struct mutex lock; + struct regmap *regmap; + struct snd_soc_component *component; + struct snd_soc_jack *jack; + int irq; unsigned int sysclk; unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS]; struct snd_pcm_hw_constraint_list sysclk_constraints; @@ -529,8 +536,162 @@ static struct snd_soc_dai_driver es8316_dai = { .symmetric_rates = 1, }; +static void es8316_enable_micbias_for_mic_gnd_short_detect( + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Bias"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Analog power"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Bias"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); + + msleep(20); +} + +static void es8316_disable_micbias_for_mic_gnd_short_detect( + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Bias"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Analog power"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Bias"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static irqreturn_t es8316_irq(int irq, void *data) +{ + struct es8316_priv *es8316 = data; + struct snd_soc_component *comp = es8316->component; + unsigned int flags; + + mutex_lock(&es8316->lock); + + regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); + if (flags == 0x00) + goto out; /* Powered-down / reset */ + + /* Catch spurious IRQ before set_jack is called */ + if (!es8316->jack) + goto out; + + dev_dbg(comp->dev, "gpio flags %#04x\n", flags); + if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { + /* Jack removed, or spurious IRQ? */ + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + + if (es8316->jack->status & SND_JACK_HEADPHONE) { + snd_soc_jack_report(es8316->jack, 0, + SND_JACK_HEADSET | SND_JACK_BTN_0); + dev_dbg(comp->dev, "jack unplugged\n"); + } + } else if (!(es8316->jack->status & SND_JACK_HEADPHONE)) { + /* Jack inserted, determine type */ + es8316_enable_micbias_for_mic_gnd_short_detect(comp); + regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); + dev_dbg(comp->dev, "gpio flags %#04x\n", flags); + if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { + /* Jack unplugged underneath us */ + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + } else if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) { + /* Open, headset */ + snd_soc_jack_report(es8316->jack, + SND_JACK_HEADSET, + SND_JACK_HEADSET); + /* Keep mic-gnd-short detection on for button press */ + } else { + /* Shorted, headphones */ + snd_soc_jack_report(es8316->jack, + SND_JACK_HEADPHONE, + SND_JACK_HEADSET); + /* No longer need mic-gnd-short detection */ + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + } + } else if (es8316->jack->status & SND_JACK_MICROPHONE) { + /* Interrupt while jack inserted, report button state */ + if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) { + /* Open, button release */ + snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0); + } else { + /* Short, button press */ + snd_soc_jack_report(es8316->jack, + SND_JACK_BTN_0, + SND_JACK_BTN_0); + } + } + +out: + mutex_unlock(&es8316->lock); + return IRQ_HANDLED; +} + +static void es8316_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + mutex_lock(&es8316->lock); + + es8316->jack = jack; + + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_enable_micbias_for_mic_gnd_short_detect(component); + + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, + ES8316_GPIO_ENABLE_INTERRUPT); + + mutex_unlock(&es8316->lock); + + /* Enable irq and sync initial jack state */ + enable_irq(es8316->irq); + es8316_irq(es8316->irq, es8316); +} + +static void es8316_disable_jack_detect(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + disable_irq(es8316->irq); + + mutex_lock(&es8316->lock); + + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, 0); + + if (es8316->jack->status & SND_JACK_MICROPHONE) { + es8316_disable_micbias_for_mic_gnd_short_detect(component); + snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0); + } + + es8316->jack = NULL; + + mutex_unlock(&es8316->lock); +} + +static int es8316_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (jack) + es8316_enable_jack_detect(component, jack); + else + es8316_disable_jack_detect(component); + + return 0; +} + static int es8316_probe(struct snd_soc_component *component) { + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + es8316->component = component; + /* Reset codec and enable current state machine */ snd_soc_component_write(component, ES8316_RESET, 0x3f); usleep_range(5000, 5500); @@ -555,6 +716,7 @@ static int es8316_probe(struct snd_soc_component *component) static const struct snd_soc_component_driver soc_component_dev_es8316 = { .probe = es8316_probe, + .set_jack = es8316_set_jack, .controls = es8316_snd_controls, .num_controls = ARRAY_SIZE(es8316_snd_controls), .dapm_widgets = es8316_dapm_widgets, @@ -566,18 +728,29 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = { .non_legacy_dai_naming = 1, }; +static const struct regmap_range es8316_volatile_ranges[] = { + regmap_reg_range(ES8316_GPIO_FLAG, ES8316_GPIO_FLAG), +}; + +static const struct regmap_access_table es8316_volatile_table = { + .yes_ranges = es8316_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(es8316_volatile_ranges), +}; + static const struct regmap_config es8316_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = 0x53, + .volatile_table = &es8316_volatile_table, .cache_type = REGCACHE_RBTREE, }; static int es8316_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { + struct device *dev = &i2c_client->dev; struct es8316_priv *es8316; - struct regmap *regmap; + int ret; es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv), GFP_KERNEL); @@ -586,9 +759,23 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client, i2c_set_clientdata(i2c_client, es8316); - regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); + if (IS_ERR(es8316->regmap)) + return PTR_ERR(es8316->regmap); + + es8316->irq = i2c_client->irq; + mutex_init(&es8316->lock); + + ret = devm_request_threaded_irq(dev, es8316->irq, NULL, es8316_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "es8316", es8316); + if (ret == 0) { + /* Gets re-enabled by es8316_set_jack() */ + disable_irq(es8316->irq); + } else { + dev_warn(dev, "Failed to get IRQ %d: %d\n", es8316->irq, ret); + es8316->irq = -ENXIO; + } return devm_snd_soc_register_component(&i2c_client->dev, &soc_component_dev_es8316, diff --git a/sound/soc/codecs/es8316.h b/sound/soc/codecs/es8316.h index 6bcdd63ea459..439a0130cbb7 100644 --- a/sound/soc/codecs/es8316.h +++ b/sound/soc/codecs/es8316.h @@ -126,4 +126,11 @@ #define ES8316_SERDATA2_LEN_16 0x0c #define ES8316_SERDATA2_LEN_32 0x10 +/* ES8316_GPIO_DEBOUNCE */ +#define ES8316_GPIO_ENABLE_INTERRUPT 0x02 + +/* ES8316_GPIO_FLAG */ +#define ES8316_GPIO_FLAG_GM_NOT_SHORTED 0x02 +#define ES8316_GPIO_FLAG_HP_NOT_INSERTED 0x04 + #endif -- cgit v1.2.3-58-ga151 From 24b53f17a3f24967b8b523243f9f7fc361427119 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:27 +0100 Subject: ASoC: es8316: Add DAC mono mix switch mixer control Export the DAC functionality to mix left + right together and then output the same (mixed) signal on both outputs. Various (x86) tablets with an ES8316 codec use a single speaker connected between the headhpone LOUT and ROUT pins, expecting the output to be in a mono differential mode. Presumably this is done to use the power of both the left and right outputs to allow the speaker to be louder. The ES8316 codec does not have a differential output mode, but we can emulate this by making both channels output the same through the mono mix switch, combined with setting the Playback Polarity control to "R Invert", which applias a 180 degrees phase inversion to the right channel. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 26413851e434..98464ba1046c 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -101,6 +101,7 @@ static const struct snd_kcontrol_new es8316_snd_controls[] = { SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0), SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0), SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0), + SOC_SINGLE("DAC Mono Mix Switch", ES8316_DAC_SET3, 3, 1, 0), SOC_ENUM("Capture Polarity", adcpol), SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0), -- cgit v1.2.3-58-ga151 From 6ca382c4363d6c636200ccdd9ac95f44b1a498ea Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:28 +0100 Subject: ASoC: Intel: bytcht_es8316: Sort includes alphabetically For lack of a better (non-random) way of sorting includes more and more files in the kernel are moving over to sorting the includes alphabetically. Move the bytcht_es8316 driver over to this sorting before we add a bunch of more includes. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index adc26dfc7d65..5d8ecc100766 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -19,13 +19,13 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include +#include #include #include #include -#include #include #include -#include #include #include #include -- cgit v1.2.3-58-ga151 From 86909c8f77c5eda17a9b5dc954849e25df1ffe0f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:29 +0100 Subject: ASoC: Intel: bytcht_es8316: Minor refactoring Some minor refactoring: 1) Group the code setting the card dev and prive pointers together with registering the card 2) Properly put the comment about registering the card at the place where we actually register the card and add a new comment for getting the clk 3) Add a struct device *dev helper variable (this will be used more in follow up commits) 4) Reword error message to have the same "foo failed: %d" wording as others Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 5d8ecc100766..e29f00560b00 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -237,17 +237,18 @@ static char codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; + struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; int dai_index = 0; int i; int ret = 0; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - mach = (&pdev->dev)->platform_data; + mach = dev->platform_data; /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { if (!strcmp(byt_cht_es8316_dais[i].codec_name, @@ -265,26 +266,25 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } - /* register the soc card */ - byt_cht_es8316_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); - - priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + /* get the clock */ + priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { ret = PTR_ERR(priv->mclk); - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %d\n", - ret); + dev_err(dev, "clk_get pmc_plt_clk_3 failed: %d\n", ret); return ret; } - ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card); + /* register the soc card */ + byt_cht_es8316_card.dev = dev; + snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); + + ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); + dev_err(dev, "snd_soc_register_card failed: %d\n", ret); return ret; } platform_set_drvdata(pdev, &byt_cht_es8316_card); - return ret; + return 0; } static struct platform_driver snd_byt_cht_es8316_mc_driver = { -- cgit v1.2.3-58-ga151 From 349e13862c9975c613aac9dc7fa953e70cff9d06 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:30 +0100 Subject: ASoC: Intel: bytcht_es8316: Add support for SSP0 (BYTCR) Add support for having the codec connected to SSP0 instead of SSP2. This is controlled through a new quirk parameter, similar to how this is done in the bytcr_rt5640 and bytcr_rt5651 machine drivers. Bay Trail CR (cost reduced) SoCs do not have an SSP2, so we default to SSP0 there. Note the SPP0 quirk gets BIT(16) because bits 0-15 are reserved for non boolean quirks like the input-map added in a later commit in this series. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 76 ++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index e29f00560b00..3358d82499a3 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -37,6 +39,20 @@ struct byt_cht_es8316_private { struct clk *mclk; }; +#define BYT_CHT_ES8316_SSP0 BIT(16) + +static int quirk; + +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + +static void log_quirks(struct device *dev) +{ + if (quirk & BYT_CHT_ES8316_SSP0) + dev_info(dev, "quirk SSP0 enabled"); +} + static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), @@ -55,7 +71,16 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { + {"Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx"}, + {"ssp0 Rx", NULL, "Capture"}, +}; +static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { {"Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, @@ -74,10 +99,23 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + const struct snd_soc_dapm_route *custom_map; + int num_routes; int ret; card->dapm.idle_bias_off = true; + if (quirk & BYT_CHT_ES8316_SSP0) { + custom_map = byt_cht_es8316_ssp0_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); + } else { + custom_map = byt_cht_es8316_ssp2_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_ssp2_map); + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + /* * The firmware might enable the clock at boot (this information * may or may not be reflected in the enable clock register). @@ -123,14 +161,21 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - int ret; + int ret, bits; /* The DSP will covert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; - /* set SSP2 to 24-bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + if (quirk & BYT_CHT_ES8316_SSP0) { + /* set SSP0 to 16-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + bits = 16; + } else { + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + bits = 24; + } /* * Default mode for SSP configuration is TDM 4 slot, override config @@ -147,7 +192,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, return ret; } - ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, bits); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -232,6 +277,11 @@ static struct snd_soc_card byt_cht_es8316_card = { .fully_routed = true, }; +static const struct x86_cpu_id baytrail_cpu_ids[] = { + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT }, /* Valleyview */ + {} +}; + static char codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) @@ -266,6 +316,24 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } + /* Check for BYTCR or other platform and setup quirks */ + if (x86_match_cpu(baytrail_cpu_ids) && + mach->mach_params.acpi_ipc_irq_index == 0) { + /* On BYTCR default to SSP0 */ + quirk = BYT_CHT_ES8316_SSP0; + } else { + quirk = 0; + } + if (quirk_override != -1) { + dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, + quirk_override); + quirk = quirk_override; + } + log_quirks(dev); + + if (quirk & BYT_CHT_ES8316_SSP0) + byt_cht_es8316_dais[dai_index].cpu_dai_name = "ssp0-port"; + /* get the clock */ priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { -- cgit v1.2.3-58-ga151 From 4bf538b42933253296daf86aab7ede56b5fb97bf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:31 +0100 Subject: ASoC: Intel: bytcht_es8316: Add jack-detect support Hookup the jack-detect support added to the codec driver. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 67 +++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 3358d82499a3..905dd6904710 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -22,12 +22,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -37,6 +39,7 @@ struct byt_cht_es8316_private { struct clk *mclk; + struct snd_soc_jack jack; }; #define BYT_CHT_ES8316_SSP0 BIT(16) @@ -55,6 +58,7 @@ static void log_quirks(struct device *dev) static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), /* * The codec supports two analog microphone inputs. I have only @@ -68,6 +72,7 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"MIC1", NULL, "Microphone 1"}, {"MIC2", NULL, "Microphone 2"}, + {"MIC1", NULL, "Headset Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, @@ -91,12 +96,25 @@ static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Microphone 1"), SOC_DAPM_PIN_SWITCH("Microphone 2"), }; +static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { + struct snd_soc_component *codec = runtime->codec_dai->component; struct snd_soc_card *card = runtime->card; struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; @@ -143,6 +161,18 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) return ret; } + ret = snd_soc_card_jack_new(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, byt_cht_es8316_jack_pins, + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + return 0; } @@ -263,6 +293,39 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ +static char codec_name[SND_ACPI_I2C_ID_LEN]; + +static int byt_cht_es8316_suspend(struct snd_soc_card *card) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) { + if (!strcmp(component->name, codec_name)) { + dev_dbg(component->dev, "disabling jack detect before suspend\n"); + snd_soc_component_set_jack(component, NULL, NULL); + break; + } + } + + return 0; +} + +static int byt_cht_es8316_resume(struct snd_soc_card *card) +{ + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + + for_each_card_components(card, component) { + if (!strcmp(component->name, codec_name)) { + dev_dbg(component->dev, "re-enabling jack detect after resume\n"); + snd_soc_component_set_jack(component, &priv->jack, NULL); + break; + } + } + + return 0; +} + static struct snd_soc_card byt_cht_es8316_card = { .name = "bytcht-es8316", .owner = THIS_MODULE, @@ -275,6 +338,8 @@ static struct snd_soc_card byt_cht_es8316_card = { .controls = byt_cht_es8316_controls, .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), .fully_routed = true, + .suspend_pre = byt_cht_es8316_suspend, + .resume_post = byt_cht_es8316_resume, }; static const struct x86_cpu_id baytrail_cpu_ids[] = { @@ -282,8 +347,6 @@ static const struct x86_cpu_id baytrail_cpu_ids[] = { {} }; -static char codec_name[SND_ACPI_I2C_ID_LEN]; - static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; -- cgit v1.2.3-58-ga151 From 0d3e91da0750835cfd5c16487ffb3cdd752ea53a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:32 +0100 Subject: ASoC: Intel: bytcht_es8316: Add external speaker mux support The ES8316 only has a single (amplified) output. The ES8316 appnote showing the intended usage uses a jack-receptacle which physically disconnects the speakers from the output when a jack is plugged in. But all 3 devices using the es8316 which I have (2 Cherry Trail devices and one Bay Trail CR device), use an analog mux to disconnect the speakers, driven by a GPIO. This commit adds support for this, modelling this as a separate speaker widget / dapm pin-switch which sets the mux to drive the speakers when selected. The intend is for userspace to use the recently added jack-detect support and then automatically select either the Headphone or Speaker output based on that. Note this commit includes a workaround for an ACPI table bug which is present on 2 of the 3 devices I have, see the added comment in the code. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 98 ++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 905dd6904710..8e504fca4624 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -19,8 +19,11 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include #include #include +#include +#include #include #include #include @@ -40,6 +43,8 @@ struct byt_cht_es8316_private { struct clk *mclk; struct snd_soc_jack jack; + struct gpio_desc *speaker_en_gpio; + bool speaker_en; }; #define BYT_CHT_ES8316_SSP0 BIT(16) @@ -56,7 +61,24 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk SSP0 enabled"); } +static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + + if (SND_SOC_DAPM_EVENT_ON(event)) + priv->speaker_en = true; + else + priv->speaker_en = false; + + gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); + + return 0; +} + static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -67,6 +89,10 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { */ SND_SOC_DAPM_MIC("Microphone 1", NULL), SND_SOC_DAPM_MIC("Microphone 2", NULL), + + SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, + byt_cht_es8316_speaker_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), }; static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { @@ -76,6 +102,14 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, + + /* + * There is no separate speaker output instead the speakers are muxed to + * the HP outputs. The mux is controlled by the "Speaker Power" supply. + */ + {"Speaker", NULL, "HPOL"}, + {"Speaker", NULL, "HPOR"}, + {"Speaker", NULL, "Speaker Power"}, }; static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { @@ -95,6 +129,7 @@ static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { }; static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Microphone 1"), @@ -323,6 +358,25 @@ static int byt_cht_es8316_resume(struct snd_soc_card *card) } } + /* + * Some Cherry Trail boards with an ES8316 codec have a bug in their + * ACPI tables where the MSSL1680 touchscreen's _PS0 and _PS3 methods + * wrongly also set the speaker-enable GPIO to 1/0. Testing has shown + * that this really is a bug and the GPIO has no influence on the + * touchscreen at all. + * + * The silead.c touchscreen driver does not support runtime suspend, so + * the GPIO can only be changed underneath us during a system suspend. + * This resume() function runs from a pm complete() callback, and thus + * is guaranteed to run after the touchscreen driver/ACPI-subsys has + * brought the touchscreen back up again (and thus changed the GPIO). + * + * So to work around this we pass GPIOD_FLAGS_BIT_NONEXCLUSIVE when + * requesting the GPIO and we set its value here to undo any changes + * done by the touchscreen's broken _PS0 ACPI method. + */ + gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); + return 0; } @@ -347,12 +401,20 @@ static const struct x86_cpu_id baytrail_cpu_ids[] = { {} }; +static const struct acpi_gpio_params first_gpio = { 0, 0, false }; + +static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { + { "speaker-enable-gpios", &first_gpio, 1 }, + { }, +}; + static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; + struct device *codec_dev; int dai_index = 0; int i; int ret = 0; @@ -405,12 +467,39 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return ret; } + /* get speaker enable GPIO */ + codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, codec_name); + if (!codec_dev) + return -EPROBE_DEFER; + + devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); + priv->speaker_en_gpio = + gpiod_get_index(codec_dev, "speaker-enable", 0, + /* see comment in byt_cht_es8316_resume */ + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); + put_device(codec_dev); + + if (IS_ERR(priv->speaker_en_gpio)) { + ret = PTR_ERR(priv->speaker_en_gpio); + switch (ret) { + case -ENOENT: + priv->speaker_en_gpio = NULL; + break; + default: + dev_err(dev, "get speaker GPIO failed: %d\n", ret); + /* fall through */ + case -EPROBE_DEFER: + return ret; + } + } + /* register the soc card */ byt_cht_es8316_card.dev = dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); if (ret) { + gpiod_put(priv->speaker_en_gpio); dev_err(dev, "snd_soc_register_card failed: %d\n", ret); return ret; } @@ -418,11 +507,20 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return 0; } +static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) +{ + struct byt_cht_es8316_private *priv = platform_get_drvdata(pdev); + + gpiod_put(priv->speaker_en_gpio); + return 0; +} + static struct platform_driver snd_byt_cht_es8316_mc_driver = { .driver = { .name = "bytcht_es8316", }, .probe = snd_byt_cht_es8316_mc_probe, + .remove = snd_byt_cht_es8316_mc_remove, }; module_platform_driver(snd_byt_cht_es8316_mc_driver); -- cgit v1.2.3-58-ga151 From 730501a91d94b652275e049e101ed44cdbfdf31b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:33 +0100 Subject: ASoC: Intel: bytcht_es8316: Add input-map support After adding jack-detect support we have 3 microphone input switches: "Microphone 1", "Microphone 2" and "Headset Mic". But the ES8316 has only 2 microphone inputs. In the app-note explaining how to use the codec and on the 3 boards I have one input is used for an internal microphone and one for the headset microphone. On the 2 CHT boards I have the internal mic is on on MIC1 and the headset mic is on MIC2, on the BYTCR board I have it is the other way around. This commit replaces the 2 "Microphone 1" and "Microphone 2" input switches with a single "Internal Mic" switch and adds support for selecting either possible input mapping. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 58 ++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 8e504fca4624..941a66f94660 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -47,6 +47,12 @@ struct byt_cht_es8316_private { bool speaker_en; }; +enum { + BYT_CHT_ES8316_INTMIC_IN1_MAP, + BYT_CHT_ES8316_INTMIC_IN2_MAP, +}; + +#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) #define BYT_CHT_ES8316_SSP0 BIT(16) static int quirk; @@ -57,6 +63,10 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { + if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN1_MAP) + dev_info(dev, "quirk IN1_MAP enabled"); + if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN2_MAP) + dev_info(dev, "quirk IN2_MAP enabled"); if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); } @@ -81,14 +91,7 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_SPK("Speaker", NULL), SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - - /* - * The codec supports two analog microphone inputs. I have only - * tested MIC1. A DMIC route could also potentially be added - * if such functionality is found on another platform. - */ - SND_SOC_DAPM_MIC("Microphone 1", NULL), - SND_SOC_DAPM_MIC("Microphone 2", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, byt_cht_es8316_speaker_power_event, @@ -96,10 +99,6 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { }; static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { - {"MIC1", NULL, "Microphone 1"}, - {"MIC2", NULL, "Microphone 2"}, - {"MIC1", NULL, "Headset Mic"}, - {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, @@ -112,6 +111,16 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Speaker", NULL, "Speaker Power"}, }; +static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in1_map[] = { + {"MIC1", NULL, "Internal Mic"}, + {"MIC2", NULL, "Headset Mic"}, +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in2_map[] = { + {"MIC2", NULL, "Internal Mic"}, + {"MIC1", NULL, "Headset Mic"}, +}; + static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { {"Playback", NULL, "ssp0 Tx"}, {"ssp0 Tx", NULL, "modem_out"}, @@ -132,8 +141,7 @@ static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Microphone 1"), - SOC_DAPM_PIN_SWITCH("Microphone 2"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), }; static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { @@ -158,6 +166,21 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) card->dapm.idle_bias_off = true; + switch (BYT_CHT_ES8316_MAP(quirk)) { + case BYT_CHT_ES8316_INTMIC_IN1_MAP: + default: + custom_map = byt_cht_es8316_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in1_map); + break; + case BYT_CHT_ES8316_INTMIC_IN2_MAP: + custom_map = byt_cht_es8316_intmic_in2_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in2_map); + break; + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + if (quirk & BYT_CHT_ES8316_SSP0) { custom_map = byt_cht_es8316_ssp0_map; num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); @@ -444,10 +467,11 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { - /* On BYTCR default to SSP0 */ - quirk = BYT_CHT_ES8316_SSP0; + /* On BYTCR default to SSP0, internal-mic-in2-map */ + quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP; } else { - quirk = 0; + /* Others default to internal-mic-in1-map */ + quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP; } if (quirk_override != -1) { dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, -- cgit v1.2.3-58-ga151 From 249d2fc9e55c324dda968252ea3ad0ac21c72b8f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:34 +0100 Subject: ASoC: Intel: bytcht_es8316: Set card long_name based on quirks Depending on the input-map and on if 1 or 2 speakers are connected, userspace needs to use a different UCM profile. Since we already deal with quirks in the kernel driver and set the input-map from the kernel, add a quirk for devices with a single / mono speaker and set the card's long_name based on the input and speaker quirks, so that userspace can use the long_name to pick the right UCM profile. This change, including how the long_name is build-up mirrors how we do this in the bytcr_rt5640 and bytcr_rt5651 machine drivers. Note since all devices I have access to use a mono speaker setup I've chosen to default the speaker setting to mono. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 941a66f94660..cdf2061e7613 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -54,6 +54,7 @@ enum { #define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) #define BYT_CHT_ES8316_SSP0 BIT(16) +#define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) static int quirk; @@ -69,6 +70,8 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk IN2_MAP enabled"); if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); + if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) + dev_info(dev, "quirk MONO_SPEAKER enabled\n"); } static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, @@ -352,6 +355,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ static char codec_name[SND_ACPI_I2C_ID_LEN]; +static char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */ static int byt_cht_es8316_suspend(struct snd_soc_card *card) { @@ -433,6 +437,7 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { + const char * const mic_name[] = { "in1", "in2" }; struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; @@ -467,11 +472,13 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { - /* On BYTCR default to SSP0, internal-mic-in2-map */ - quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP; + /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ + quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | + BYT_CHT_ES8316_MONO_SPEAKER; } else { - /* Others default to internal-mic-in1-map */ - quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP; + /* Others default to internal-mic-in1-map, mono-speaker */ + quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP | + BYT_CHT_ES8316_MONO_SPEAKER; } if (quirk_override != -1) { dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, @@ -518,6 +525,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) } /* register the soc card */ + snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic", + (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo", + mic_name[BYT_CHT_ES8316_MAP(quirk)]); + byt_cht_es8316_card.long_name = long_name; byt_cht_es8316_card.dev = dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); -- cgit v1.2.3-58-ga151 From 5198baf8817d7e6e0fe2f3e74ea2ead714b74d9c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:35 +0100 Subject: ASoC: Intel: Add ACPI match table entry for ES8316 codec on BYTCR platform Some BYTCR devices use an ES8316 codec, add an ACPI match table entry for this. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 097dc06377ba..47a90909b956 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -154,6 +154,15 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .sof_tplg_filename = "intel/sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, + { + .id = "ESSX8316", + .drv_name = "bytcht_es8316", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_es8316", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt-es8316.tplg", + .asoc_plat_name = "sst-mfld-platform", + }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ { .id = "10EC5645", -- cgit v1.2.3-58-ga151 From b97205ef95efddee018061dfee14c995be08dde3 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:03 +0100 Subject: ASoC: Intel: sst: Simplify is_byt_cr() is_byt_cr() and its usage can be simplified by returning the bool directly, instead of through a pointer. This works because the return value is just treated as bytcr = false and is not used otherwise. This patch also removes the extra check of IS_ENABLED(CONFIG_IOSF_MBI) in favor of checking iosf_mbi_available() directly. The header already takes care of returning false if the config option is not enabled. No functional change. Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 3a95ebbfc45d..9eaac450f864 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -255,18 +255,15 @@ static int is_byt(void) return status; } -static int is_byt_cr(struct device *dev, bool *bytcr) +static bool is_byt_cr(struct device *dev) { int status = 0; - if (IS_ENABLED(CONFIG_IOSF_MBI)) { - u32 bios_status; - - if (!is_byt() || !iosf_mbi_available()) { - /* bail silently */ - return status; - } + if (!is_byt()) + return false; + if (iosf_mbi_available()) { + u32 bios_status; status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ MBI_REG_READ, /* 0x10 */ 0x006, /* BIOS_CONFIG */ @@ -278,15 +275,17 @@ static int is_byt_cr(struct device *dev, bool *bytcr) /* bits 26:27 mirror PMIC options */ bios_status = (bios_status >> 26) & 3; - if ((bios_status == 1) || (bios_status == 3)) - *bytcr = true; - else - dev_info(dev, "BYT-CR not detected\n"); + if (bios_status == 1 || bios_status == 3) { + dev_info(dev, "Detected Baytrail-CR platform\n"); + return true; + } + + dev_info(dev, "BYT-CR not detected\n"); } } else { - dev_info(dev, "IOSF_MBI not enabled, no BYT-CR detection\n"); + dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); } - return status; + return false; } @@ -301,7 +300,6 @@ static int sst_acpi_probe(struct platform_device *pdev) struct platform_device *plat_dev; struct sst_platform_info *pdata; unsigned int dev_id; - bool bytcr = false; id = acpi_match_device(dev->driver->acpi_match_table, dev); if (!id) @@ -333,10 +331,7 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = is_byt_cr(dev, &bytcr); - if (!(ret < 0 || !bytcr)) { - dev_info(dev, "Detected Baytrail-CR platform\n"); - + if (is_byt_cr(dev)) { /* override resource info */ byt_rvp_platform_data.res_info = &bytcr_res_info; } -- cgit v1.2.3-58-ga151 From fee15714552dbf420264da6f88dd813b8502592b Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:06 +0100 Subject: ASoC: Intel: sst: Fallback to BYT-CR if IRQ 5 is missing Some devices detected as BYT-T by the PMIC-type based detection have only a single IRQ listed in the 80860F28 ACPI device. This causes -ENXIO later when attempting to get the IRQ at index 5. It turns out these devices behave more like BYT-CR devices, and using the IRQ at index 0 makes sound work correctly. This patch adds a fallback for these devices to is_byt_cr(): If there is no IRQ resource at index 5, treating the device as BYT-T is guaranteed to fail later, so we can safely treat these devices as BYT-CR without breaking any working device. Link: http://mailman.alsa-project.org/pipermail/alsa-devel/2018-December/143176.html Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 9eaac450f864..ae17ce4677a5 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -255,8 +255,9 @@ static int is_byt(void) return status; } -static bool is_byt_cr(struct device *dev) +static bool is_byt_cr(struct platform_device *pdev) { + struct device *dev = &pdev->dev; int status = 0; if (!is_byt()) @@ -285,6 +286,17 @@ static bool is_byt_cr(struct device *dev) } else { dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); } + + if (platform_get_resource(pdev, IORESOURCE_IRQ, 5) == NULL) { + /* + * Some devices detected as BYT-T have only a single IRQ listed, + * causing platform_get_irq with index 5 to return -ENXIO. + * The correct IRQ in this case is at index 0, as on BYT-CR. + */ + dev_info(dev, "Falling back to Baytrail-CR platform\n"); + return true; + } + return false; } @@ -331,7 +343,7 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (is_byt_cr(dev)) { + if (is_byt_cr(pdev)) { /* override resource info */ byt_rvp_platform_data.res_info = &bytcr_res_info; } -- cgit v1.2.3-58-ga151 From 51a13e401a83ef37aa98c049c2c30bba885676c2 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:08 +0100 Subject: ASoC: Intel: bytcr_rt5640: Add quirks for ASUS MeMO Pad 7 (ME176C) Add quirks to select the correct input map, jack-detect options and channel map to make sound work on the ASUS MeMO Pad 7 (ME176C). Note: Although sound works out of the box, jack detection currently requires overriding the ACPI DSDT table. This is necessary because the rt5640 ACPI device (10EC5640) has the wrong GPIO listed as interrupt (one of the Bluetooth GPIOs). The correct GPIO is GPO2 0x0004 (listed as the first GPIO in the Intel(R) Audio Machine Driver - AMCR0F28 device). Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a22366ce33c4..ca8b4d5ff70f 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -428,6 +428,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), -- cgit v1.2.3-58-ga151 From 2130f15d6cd9898a68dc7244084985353030514f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 3 Jan 2019 14:53:45 +0200 Subject: ASoC: ti: davinci-mcasp: No need for IS_MODULE/BUILTIN check for pcm driver Since the platform drivers are selected by the DAI drivers (including McASP) there is no longer a need to check whether the modules are built-in or module. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index eeda6d5565bc..ee9ab58d4d0c 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -2149,26 +2149,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev) ret = davinci_mcasp_get_dma_type(mcasp); switch (ret) { case PCM_EDMA: -#if IS_BUILTIN(CONFIG_SND_SOC_TI_EDMA_PCM) || \ - (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \ - IS_MODULE(CONFIG_SND_SOC_TI_EDMA_PCM)) ret = edma_pcm_platform_register(&pdev->dev); -#else - dev_err(&pdev->dev, "Missing SND_EDMA_SOC\n"); - ret = -EINVAL; - goto err; -#endif break; case PCM_SDMA: -#if IS_BUILTIN(CONFIG_SND_SOC_TI_SDMA_PCM) || \ - (IS_MODULE(CONFIG_SND_SOC_DAVINCI_MCASP) && \ - IS_MODULE(CONFIG_SND_SOC_TI_SDMA_PCM)) ret = sdma_pcm_platform_register(&pdev->dev, NULL, NULL); -#else - dev_err(&pdev->dev, "Missing SND_SDMA_SOC\n"); - ret = -EINVAL; - goto err; -#endif break; default: dev_err(&pdev->dev, "No DMA controller found (%d)\n", ret); -- cgit v1.2.3-58-ga151 From 4664b94c98b4f9fdd3845da41d5c65288e59c66c Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 3 Jan 2019 16:05:51 +0200 Subject: ASoC: davinci-mcasp: Document GPIO support McASP pins can be used as GPIO, add optional section to enable GPIO support for McASP. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/davinci-mcasp-audio.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index b279b6072bd5..a58f79f5345c 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -45,6 +45,23 @@ Optional properties: - fck_parent : Should contain a valid clock name which will be used as parent for the McASP fck +Optional GPIO support: +If any McASP pin need to be used as GPIO then the McASP node must have: +... + gpio-controller + #gpio-cells = <2>; +... + +When requesting a GPIO, the first parameter is the PIN index in McASP_P* +registers. +For example to request the AXR2 pin of mcasp8: +function-gpios = <&mcasp8 2 0>; + +Or to request the ACLKR pin of mcasp8: +function-gpios = <&mcasp8 29 0>; + +For generic gpio information, please refer to bindings/gpio/gpio.txt + Example: mcasp0: mcasp0@1d00000 { -- cgit v1.2.3-58-ga151 From 540f1ba7b3a5596827a3bfeaae9c5e754347c933 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 3 Jan 2019 16:05:52 +0200 Subject: ASoC: ti: davinci-mcasp: Add support for GPIO mode of the pins All McASP pin can be configured as GPIO. Add gpiochip support for McASP and only enable it when the gpio-controller is present in the DT node. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/ti/davinci-mcasp.c | 159 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 156 insertions(+), 3 deletions(-) diff --git a/sound/soc/ti/davinci-mcasp.c b/sound/soc/ti/davinci-mcasp.c index a6a470a76900..a3a67a8f0f54 100644 --- a/sound/soc/ti/davinci-mcasp.c +++ b/sound/soc/ti/davinci-mcasp.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,7 @@ static u32 context_regs[] = { DAVINCI_MCASP_AHCLKXCTL_REG, DAVINCI_MCASP_AHCLKRCTL_REG, DAVINCI_MCASP_PDIR_REG, + DAVINCI_MCASP_PFUNC_REG, DAVINCI_MCASP_RXMASK_REG, DAVINCI_MCASP_TXMASK_REG, DAVINCI_MCASP_RXTDM_REG, @@ -108,6 +110,10 @@ struct davinci_mcasp { /* Used for comstraint setting on the second stream */ u32 channels; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio_chip; +#endif + #ifdef CONFIG_PM struct davinci_mcasp_context context; #endif @@ -818,9 +824,6 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, if (mcasp->version < MCASP_VERSION_3) mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); - /* All PINS as McASP */ - mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS); @@ -1845,6 +1848,147 @@ static u32 davinci_mcasp_rxdma_offset(struct davinci_mcasp_pdata *pdata) return offset; } +#ifdef CONFIG_GPIOLIB +static int davinci_mcasp_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + + if (mcasp->num_serializer && offset < mcasp->num_serializer && + mcasp->serial_dir[offset] != INACTIVE_MODE) { + dev_err(mcasp->dev, "AXR%u pin is used for audio\n", offset); + return -EBUSY; + } + + /* Do not change the PIN yet */ + + return pm_runtime_get_sync(mcasp->dev); +} + +static void davinci_mcasp_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + + /* Set the direction to input */ + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); + + /* Set the pin as McASP pin */ + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); + + pm_runtime_put_sync(mcasp->dev); +} + +static int davinci_mcasp_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + u32 val; + + if (value) + mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); + else + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); + + val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); + if (!(val & BIT(offset))) { + /* Set the pin as GPIO pin */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); + + /* Set the direction to output */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); + } + + return 0; +} + +static void davinci_mcasp_gpio_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + + if (value) + mcasp_set_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); + else + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDOUT_REG, BIT(offset)); +} + +static int davinci_mcasp_gpio_direction_in(struct gpio_chip *chip, + unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + u32 val; + + val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PFUNC_REG); + if (!(val & BIT(offset))) { + /* Set the direction to input */ + mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, BIT(offset)); + + /* Set the pin as GPIO pin */ + mcasp_set_bits(mcasp, DAVINCI_MCASP_PFUNC_REG, BIT(offset)); + } + + return 0; +} + +static int davinci_mcasp_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + u32 val; + + val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDSET_REG); + if (val & BIT(offset)) + return 1; + + return 0; +} + +static int davinci_mcasp_gpio_get_direction(struct gpio_chip *chip, + unsigned offset) +{ + struct davinci_mcasp *mcasp = gpiochip_get_data(chip); + u32 val; + + val = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); + if (val & BIT(offset)) + return 0; + + return 1; +} + +static const struct gpio_chip davinci_mcasp_template_chip = { + .owner = THIS_MODULE, + .request = davinci_mcasp_gpio_request, + .free = davinci_mcasp_gpio_free, + .direction_output = davinci_mcasp_gpio_direction_out, + .set = davinci_mcasp_gpio_set, + .direction_input = davinci_mcasp_gpio_direction_in, + .get = davinci_mcasp_gpio_get, + .get_direction = davinci_mcasp_gpio_get_direction, + .base = -1, + .ngpio = 32, +}; + +static int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) +{ + if (!of_property_read_bool(mcasp->dev->of_node, "gpio-controller")) + return 0; + + mcasp->gpio_chip = davinci_mcasp_template_chip; + mcasp->gpio_chip.label = dev_name(mcasp->dev); + mcasp->gpio_chip.parent = mcasp->dev; +#ifdef CONFIG_OF_GPIO + mcasp->gpio_chip.of_node = mcasp->dev->of_node; +#endif + + return devm_gpiochip_add_data(mcasp->dev, &mcasp->gpio_chip, mcasp); +} + +#else /* CONFIG_GPIOLIB */ +static inline int davinci_mcasp_init_gpiochip(struct davinci_mcasp *mcasp) +{ + return 0; +} +#endif /* CONFIG_GPIOLIB */ + static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; @@ -2069,6 +2213,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp_reparent_fck(pdev); + /* All PINS as McASP */ + pm_runtime_get_sync(mcasp->dev); + mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000); + pm_runtime_put(mcasp->dev); + + ret = davinci_mcasp_init_gpiochip(mcasp); + if (ret) + goto err; + ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[pdata->op_mode], 1); -- cgit v1.2.3-58-ga151 From 302df34c4e64b9e83ee31cbf508b38b62b428bd6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 3 Jan 2019 17:13:49 +0100 Subject: tools thermal tmon: Use -O3 instead of -O1 if available Using -O3 instead of -O1 if it's supported by compiler. Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Brian Norris Cc: Markus Mayer Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zhang Rui Link: http://lkml.kernel.org/r/20190103161350.11446-2-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/thermal/tmon/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile index 89a2444c1df2..59e417ec3e13 100644 --- a/tools/thermal/tmon/Makefile +++ b/tools/thermal/tmon/Makefile @@ -6,7 +6,7 @@ VERSION = 1.0 BINDIR=usr/bin WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int -override CFLAGS+= -O1 ${WARNFLAGS} +override CFLAGS+= $(call cc-option,-O3,-O1) ${WARNFLAGS} # Add "-fstack-protector" only if toolchain supports it. override CFLAGS+= $(call cc-option,-fstack-protector-strong) CC?= $(CROSS_COMPILE)gcc -- cgit v1.2.3-58-ga151 From 536cdb684d2d5139708d290b9dc124b1420886c1 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 3 Jan 2019 17:13:50 +0100 Subject: tools iio: Override CFLAGS assignments So user could specify outside CFLAGS values. Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andy Shevchenko Cc: Hartmut Knaack Cc: Jonathan Cameron Cc: Lars-Peter Clausen Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20190103161350.11446-3-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/iio/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/iio/Makefile b/tools/iio/Makefile index 332ed2f6c2c2..e22378dba244 100644 --- a/tools/iio/Makefile +++ b/tools/iio/Makefile @@ -12,7 +12,7 @@ endif # (this improves performance and avoids hard-to-debug behaviour); MAKEFLAGS += -r -CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include +override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include ALL_TARGETS := iio_event_monitor lsiio iio_generic_buffer ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) -- cgit v1.2.3-58-ga151 From 8858ecb5a28d871b79aa5b4eed45414b553a5b6e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Jan 2019 11:36:10 -0300 Subject: tools headers uapi: Update i915_drm.h To get the changes in these csets: fe841686470d Revert "drm/i915/perf: add a parameter to control the size of OA buffer" cd956bfcd0f5 drm/i915/perf: add a parameter to control the size of OA buffer 4bdafb9ddfa4 drm/i915: Remove i915.enable_ppgtt override Not one of them result in any changes in tools/perf/, this is just to silence this perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/drm/i915_drm.h' differs from latest version at 'include/uapi/drm/i915_drm.h' diff -u tools/include/uapi/drm/i915_drm.h include/uapi/drm/i915_drm.h Cc: Adrian Hunter Cc: Chris Wilson Cc: Jiri Olsa Cc: Joonas Lahtinen Cc: Lionel Landwerlin Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-mdw7ta6qz7d2rl77gf00uqe8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/drm/i915_drm.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/include/uapi/drm/i915_drm.h b/tools/include/uapi/drm/i915_drm.h index a4446f452040..298b2e197744 100644 --- a/tools/include/uapi/drm/i915_drm.h +++ b/tools/include/uapi/drm/i915_drm.h @@ -412,6 +412,14 @@ typedef struct drm_i915_irq_wait { int irq_seq; } drm_i915_irq_wait_t; +/* + * Different modes of per-process Graphics Translation Table, + * see I915_PARAM_HAS_ALIASING_PPGTT + */ +#define I915_GEM_PPGTT_NONE 0 +#define I915_GEM_PPGTT_ALIASING 1 +#define I915_GEM_PPGTT_FULL 2 + /* Ioctl to query kernel params: */ #define I915_PARAM_IRQ_ACTIVE 1 -- cgit v1.2.3-58-ga151 From 4001b6a080aaca9a13ea07ae8972b82fdbd9ea6b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Jan 2019 11:41:42 -0300 Subject: tools headers uapi: Sync linux/in.h copy from the kernel sources To get the changes in this cset: 65cab850f0ee ("net: Allow class-e address assignment via ifconfig ioctl") The macros changed in this cset are not used in tools/, so this is just to silence this perf tools build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/in.h' differs from latest version at 'include/uapi/linux/in.h' diff -u tools/include/uapi/linux/in.h include/uapi/linux/in.h Cc: Dave Taht Cc: David S. Miller Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-smghvyxb3budqd1e70i0ylw1@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/in.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/include/uapi/linux/in.h b/tools/include/uapi/linux/in.h index 48e8a225b985..f6052e70bf40 100644 --- a/tools/include/uapi/linux/in.h +++ b/tools/include/uapi/linux/in.h @@ -266,10 +266,14 @@ struct sockaddr_in { #define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) #define IN_MULTICAST(a) IN_CLASSD(a) -#define IN_MULTICAST_NET 0xF0000000 +#define IN_MULTICAST_NET 0xe0000000 -#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) -#define IN_BADCLASS(a) IN_EXPERIMENTAL((a)) +#define IN_BADCLASS(a) ((((long int) (a) ) == 0xffffffff) +#define IN_EXPERIMENTAL(a) IN_BADCLASS((a)) + +#define IN_CLASSE(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) +#define IN_CLASSE_NET 0xffffffff +#define IN_CLASSE_NSHIFT 0 /* Address to accept any incoming messages. */ #define INADDR_ANY ((unsigned long int) 0x00000000) -- cgit v1.2.3-58-ga151 From 558517c52c87da91a963708fe589044172470653 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Jan 2019 11:45:03 -0300 Subject: tools headers uapi: Sync linux/kvm.h with the kernel sources To get the changes from these csets: 2bc39970e932 ("x86/kvm/hyper-v: Introduce KVM_GET_SUPPORTED_HV_CPUID") 2a31b9db1535 ("kvm: introduce manual dirty log reprotect") That results in these new KVM IOCTLs being supported in 'perf trace' when beautifying the cmd ioctl syscall argument: $ cp include/uapi/linux/kvm.h tools/include/uapi/linux/kvm.h $ tools/perf/trace/beauty/kvm_ioctl.sh > after $ diff -u before after --- before 2019-01-04 11:44:23.506605301 -0300 +++ after 2019-01-04 11:44:36.878730583 -0300 @@ -86,6 +86,8 @@ [0xbd] = "HYPERV_EVENTFD", [0xbe] = "GET_NESTED_STATE", [0xbf] = "SET_NESTED_STATE", + [0xc0] = "CLEAR_DIRTY_LOG", + [0xc1] = "GET_SUPPORTED_HV_CPUID", [0xe0] = "CREATE_DEVICE", [0xe1] = "SET_DEVICE_ATTR", [0xe2] = "GET_DEVICE_ATTR", $ At some point we should be able to do something: # perf trace -e ioctl(cmd == KVM_CLEAR_DIRTY_LOG) And have just those ioctls, optionally with callchains, etc. Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paolo Bonzini Cc: Vitaly Kuznetsov Link: https://lkml.kernel.org/n/tip-konm3iigl2os6ritt7d2bori@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/kvm.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 2b7a652c9fa4..6d4ea4b6c922 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -492,6 +492,17 @@ struct kvm_dirty_log { }; }; +/* for KVM_CLEAR_DIRTY_LOG */ +struct kvm_clear_dirty_log { + __u32 slot; + __u32 num_pages; + __u64 first_page; + union { + void __user *dirty_bitmap; /* one bit per page */ + __u64 padding2; + }; +}; + /* for KVM_SET_SIGNAL_MASK */ struct kvm_signal_mask { __u32 len; @@ -975,6 +986,8 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163 #define KVM_CAP_EXCEPTION_PAYLOAD 164 #define KVM_CAP_ARM_VM_IPA_SIZE 165 +#define KVM_CAP_MANUAL_DIRTY_LOG_PROTECT 166 +#define KVM_CAP_HYPERV_CPUID 167 #ifdef KVM_CAP_IRQ_ROUTING @@ -1421,6 +1434,12 @@ struct kvm_enc_region { #define KVM_GET_NESTED_STATE _IOWR(KVMIO, 0xbe, struct kvm_nested_state) #define KVM_SET_NESTED_STATE _IOW(KVMIO, 0xbf, struct kvm_nested_state) +/* Available with KVM_CAP_MANUAL_DIRTY_LOG_PROTECT */ +#define KVM_CLEAR_DIRTY_LOG _IOWR(KVMIO, 0xc0, struct kvm_clear_dirty_log) + +/* Available with KVM_CAP_HYPERV_CPUID */ +#define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2) + /* Secure Encrypted Virtualization command */ enum sev_cmd_id { /* Guest initialization commands */ -- cgit v1.2.3-58-ga151 From 8c91fd605e1a66050c9c4dbc3e159a08e8c5f7d4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Jan 2019 12:08:31 -0300 Subject: tools headers uapi: Sync copy of asm-generic/unistd.h with the kernel sources To get the changes in: b7d624ab4312 asm-generic: unistd.h: fixup broken macro include. 4e21565b7fd4 asm-generic: add kexec_file_load system call to unistd.h With this the 'kexec_file_load' syscall will be added to arm64's syscall table and will appear on the output of 'perf trace' on that platform. This silences this tools/perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/asm-generic/unistd.h' differs from latest version at 'include/uapi/asm-generic/unistd.h' diff -u tools/include/uapi/asm-generic/unistd.h include/uapi/asm-generic/unistd.h Cc: Adrian Hunter Cc: AKASHI Takahiro Cc: Arnd Bergmann Cc: Guo Ren Cc: Jiri Olsa Cc: Namhyung Kim Cc: Will Deacon Link: https://lkml.kernel.org/n/tip-er8j7qhavtdw0kdga3zswynm@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/asm-generic/unistd.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index c7f3321fbe43..d90127298f12 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h @@ -738,9 +738,11 @@ __SYSCALL(__NR_statx, sys_statx) __SC_COMP(__NR_io_pgetevents, sys_io_pgetevents, compat_sys_io_pgetevents) #define __NR_rseq 293 __SYSCALL(__NR_rseq, sys_rseq) +#define __NR_kexec_file_load 294 +__SYSCALL(__NR_kexec_file_load, sys_kexec_file_load) #undef __NR_syscalls -#define __NR_syscalls 294 +#define __NR_syscalls 295 /* * 32 bit systems traditionally used different -- cgit v1.2.3-58-ga151 From 86c22ab7227f59169f64275875c97ef495668b77 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Jan 2019 12:13:34 -0300 Subject: tools headers x86: Sync asm/cpufeatures.h copy with the kernel sources To get the changes from: a0aea130afeb ("KVM: x86: Add CPUID support for new instruction WBNOINVD") 20c3a2c33e9f ("x86/speculation: Add support for STIBP always-on preferred mode") Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paolo Bonzini Cc: Robert Hoo Cc: Thomas Gleixner Cc: Thomas Lendacky Link: https://lkml.kernel.org/n/tip-aonti3bu9rhnqe5hlawbidcp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/x86/include/asm/cpufeatures.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 28c4a502b419..6d6122524711 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -281,9 +281,11 @@ #define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */ #define X86_FEATURE_IRPERF (13*32+ 1) /* Instructions Retired Count */ #define X86_FEATURE_XSAVEERPTR (13*32+ 2) /* Always save/restore FP error pointers */ +#define X86_FEATURE_WBNOINVD (13*32+ 9) /* WBNOINVD instruction */ #define X86_FEATURE_AMD_IBPB (13*32+12) /* "" Indirect Branch Prediction Barrier */ #define X86_FEATURE_AMD_IBRS (13*32+14) /* "" Indirect Branch Restricted Speculation */ #define X86_FEATURE_AMD_STIBP (13*32+15) /* "" Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_AMD_STIBP_ALWAYS_ON (13*32+17) /* "" Single Thread Indirect Branch Predictors always-on preferred */ #define X86_FEATURE_AMD_SSBD (13*32+24) /* "" Speculative Store Bypass Disable */ #define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */ #define X86_FEATURE_AMD_SSB_NO (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */ -- cgit v1.2.3-58-ga151 From a3366db06bb656cef2e03f30f780d93059bcc594 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Fri, 4 Jan 2019 14:10:30 +0800 Subject: perf report: Fix wrong iteration count in --branch-history By calculating the removed loops, we can get the iteration count. But the iteration count could be reported incorrectly, reporting impossibly high counts. That's because previous code uses the number of removed LBR entries for the iteration count. That's not good. Fix this by increasing the iteration count when a loop is detected. When matching the chain, the iteration count would be added up, finally we need to compute the average value when printing out. For example, $ perf report --branch-history --stdio --no-children Before: ---f2 +0 | |--33.62%--f1 +9 (cycles:1) | f1 +0 | main +22 (cycles:1) | main +17 | main +38 (cycles:1) | main +27 | f1 +26 (cycles:1) | f1 +24 | f2 +27 (cycles:7) | f2 +0 | f1 +19 (cycles:1) | f1 +14 | f2 +27 (cycles:11) | f2 +0 | f1 +9 (cycles:1 iter:2968 avg_cycles:3) | f1 +0 | main +22 (cycles:1 iter:2968 avg_cycles:3) | main +17 | main +38 (cycles:1 iter:2968 avg_cycles:3) 2968 is an impossible high iteration count and avg_cycles is too small. After: ---f2 +0 | |--33.62%--f1 +9 (cycles:1) | f1 +0 | main +22 (cycles:1) | main +17 | main +38 (cycles:1) | main +27 | f1 +26 (cycles:1) | f1 +24 | f2 +27 (cycles:7) | f2 +0 | f1 +19 (cycles:1) | f1 +14 | f2 +27 (cycles:11) | f2 +0 | f1 +9 (cycles:1 iter:1 avg_cycles:23) | f1 +0 | main +22 (cycles:1 iter:1 avg_cycles:23) | main +17 | main +38 (cycles:1 iter:1 avg_cycles:23) avg_cycles:23 is the average cycles of this iteration. Fixes: c4ee06251d42 ("perf report: Calculate the average cycles of iterations") Signed-off-by: Jin Yao Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1546582230-17507-1-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/callchain.c | 32 ++++++++++++++++++++------------ tools/perf/util/callchain.h | 1 + tools/perf/util/machine.c | 2 +- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 32ef7bdca1cf..dc2212e12184 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -766,6 +766,7 @@ static enum match_result match_chain(struct callchain_cursor_node *node, cnode->cycles_count += node->branch_flags.cycles; cnode->iter_count += node->nr_loop_iter; cnode->iter_cycles += node->iter_cycles; + cnode->from_count++; } } @@ -1345,10 +1346,10 @@ static int branch_to_str(char *bf, int bfsize, static int branch_from_str(char *bf, int bfsize, u64 branch_count, u64 cycles_count, u64 iter_count, - u64 iter_cycles) + u64 iter_cycles, u64 from_count) { int printed = 0, i = 0; - u64 cycles; + u64 cycles, v = 0; cycles = cycles_count / branch_count; if (cycles) { @@ -1357,14 +1358,16 @@ static int branch_from_str(char *bf, int bfsize, bf + printed, bfsize - printed); } - if (iter_count) { - printed += count_pri64_printf(i++, "iter", - iter_count, - bf + printed, bfsize - printed); + if (iter_count && from_count) { + v = iter_count / from_count; + if (v) { + printed += count_pri64_printf(i++, "iter", + v, bf + printed, bfsize - printed); - printed += count_pri64_printf(i++, "avg_cycles", - iter_cycles / iter_count, - bf + printed, bfsize - printed); + printed += count_pri64_printf(i++, "avg_cycles", + iter_cycles / iter_count, + bf + printed, bfsize - printed); + } } if (i) @@ -1377,6 +1380,7 @@ static int counts_str_build(char *bf, int bfsize, u64 branch_count, u64 predicted_count, u64 abort_count, u64 cycles_count, u64 iter_count, u64 iter_cycles, + u64 from_count, struct branch_type_stat *brtype_stat) { int printed; @@ -1389,7 +1393,8 @@ static int counts_str_build(char *bf, int bfsize, predicted_count, abort_count, brtype_stat); } else { printed = branch_from_str(bf, bfsize, branch_count, - cycles_count, iter_count, iter_cycles); + cycles_count, iter_count, iter_cycles, + from_count); } if (!printed) @@ -1402,13 +1407,14 @@ static int callchain_counts_printf(FILE *fp, char *bf, int bfsize, u64 branch_count, u64 predicted_count, u64 abort_count, u64 cycles_count, u64 iter_count, u64 iter_cycles, + u64 from_count, struct branch_type_stat *brtype_stat) { char str[256]; counts_str_build(str, sizeof(str), branch_count, predicted_count, abort_count, cycles_count, - iter_count, iter_cycles, brtype_stat); + iter_count, iter_cycles, from_count, brtype_stat); if (fp) return fprintf(fp, "%s", str); @@ -1422,6 +1428,7 @@ int callchain_list_counts__printf_value(struct callchain_list *clist, u64 branch_count, predicted_count; u64 abort_count, cycles_count; u64 iter_count, iter_cycles; + u64 from_count; branch_count = clist->branch_count; predicted_count = clist->predicted_count; @@ -1429,11 +1436,12 @@ int callchain_list_counts__printf_value(struct callchain_list *clist, cycles_count = clist->cycles_count; iter_count = clist->iter_count; iter_cycles = clist->iter_cycles; + from_count = clist->from_count; return callchain_counts_printf(fp, bf, bfsize, branch_count, predicted_count, abort_count, cycles_count, iter_count, iter_cycles, - &clist->brtype_stat); + from_count, &clist->brtype_stat); } static void free_callchain_node(struct callchain_node *node) diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 154560b1eb65..99d38ac019b8 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -118,6 +118,7 @@ struct callchain_list { bool has_children; }; u64 branch_count; + u64 from_count; u64 predicted_count; u64 abort_count; u64 cycles_count; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 6fcb3bce0442..143f7057d581 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -2005,7 +2005,7 @@ static void save_iterations(struct iterations *iter, { int i; - iter->nr_loop_iter = nr; + iter->nr_loop_iter++; iter->cycles = 0; for (i = 0; i < nr; i++) -- cgit v1.2.3-58-ga151 From 442b4eb3af44906fcbb526d98c314b27f8c9acf3 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Sun, 14 Oct 2018 11:18:03 +0300 Subject: perf annotate: Pass filename to objdump via execl The symbol__disassemble() function uses shell to launch objdump and filter its output via grep. Passing filenames by interpolating them into the command line via "%s" may lead to problems if said filenames contain special characters. Instead, pass the filename as a command line argument where it is not subject to any kind of interpretation, then use quoted shell interpolation to build the strings we need safely. Signed-off-by: Ivan Krylov Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20181014111803.5d83b806@Tarkus Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ac9805e0bc76..70de8f6b3aee 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1723,15 +1723,14 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) err = asprintf(&command, "%s %s%s --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 - " -l -d %s %s -C \"%s\" 2>/dev/null|grep -v \"%s:\"|expand", + " -l -d %s %s -C \"$1\" 2>/dev/null|grep -v \"$1:\"|expand", opts->objdump_path ?: "objdump", opts->disassembler_style ? "-M " : "", opts->disassembler_style ?: "", map__rip_2objdump(map, sym->start), map__rip_2objdump(map, sym->end), opts->show_asm_raw ? "" : "--no-show-raw", - opts->annotate_src ? "-S" : "", - symfs_filename, symfs_filename); + opts->annotate_src ? "-S" : ""); if (err < 0) { pr_err("Failure allocating memory for the command to run\n"); @@ -1756,7 +1755,8 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) close(stdout_fd[0]); dup2(stdout_fd[1], 1); close(stdout_fd[1]); - execl("/bin/sh", "sh", "-c", command, NULL); + execl("/bin/sh", "sh", "-c", command, "--", symfs_filename, + NULL); perror(command); exit(-1); } -- cgit v1.2.3-58-ga151 From 099be748865eece21362aee416c350c0b1ae34df Mon Sep 17 00:00:00 2001 From: Mattias Jacobsson <2pi@mok.nu> Date: Sat, 29 Dec 2018 15:17:50 +0100 Subject: perf strbuf: Remove redundant va_end() in strbuf_addv() Each call to va_copy() should have one, and only one, corresponding call to va_end(). In strbuf_addv() some code paths result in va_end() getting called multiple times. Remove the superfluous va_end(). Signed-off-by: Mattias Jacobsson <2pi@mok.nu> Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Sanskriti Sharma Link: http://lkml.kernel.org/r/20181229141750.16945-1-2pi@mok.nu Fixes: ce49d8436cff ("perf strbuf: Match va_{add,copy} with va_end") Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/strbuf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 9005fbe0780e..23092fd6451d 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -109,7 +109,6 @@ static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) return ret; } len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); - va_end(ap_saved); if (len > strbuf_avail(sb)) { pr_debug("this should not happen, your vsnprintf is broken"); va_end(ap_saved); -- cgit v1.2.3-58-ga151 From f712a86c1406abf50b0dcff0500c723e2aca050a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 3 Jan 2019 16:03:46 -0300 Subject: perf python: Make sure the python binding output directory is in place Instead of doing an unconditional mkdir, use a dummy Makefile variable to check if the directory is there and if not, create it. This is better than what we had and will help with other python bindings that are in development, like one involved with python backtraces. Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-iis6us2nocw3y4uuoon9osd7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index ff29c3372ec3..2921f829a0f4 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -524,12 +524,14 @@ $(arch_errno_name_array): $(arch_errno_tbl) all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS) +# Create python binding output directory if not already present +_dummy := $(shell [ -d '$(OUTPUT)python' ] || mkdir -p '$(OUTPUT)python') + $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) $(QUIET_GEN)LDSHARED="$(CC) -pthread -shared" \ CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \ $(PYTHON_WORD) util/setup.py \ --quiet build_ext; \ - mkdir -p $(OUTPUT)python && \ cp $(PYTHON_EXTBUILD_LIB)perf*.so $(OUTPUT)python/ please_set_SHELL_PATH_to_a_more_modern_shell: -- cgit v1.2.3-58-ga151 From 1f8ce09b36c41a026a37a24b20efa32000892a64 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 4 Jan 2019 06:03:40 +0000 Subject: xen/pvcalls: remove set but not used variable 'intf' Fixes gcc '-Wunused-but-set-variable' warning: drivers/xen/pvcalls-back.c: In function 'pvcalls_sk_state_change': drivers/xen/pvcalls-back.c:286:28: warning: variable 'intf' set but not used [-Wunused-but-set-variable] It not used since e6587cdbd732 ("pvcalls-back: set -ENOTCONN in pvcalls_conn_back_read") Signed-off-by: YueHaibing Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky --- drivers/xen/pvcalls-back.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c index 71b628774c6f..7aa64d1b119c 100644 --- a/drivers/xen/pvcalls-back.c +++ b/drivers/xen/pvcalls-back.c @@ -283,12 +283,10 @@ static int pvcalls_back_socket(struct xenbus_device *dev, static void pvcalls_sk_state_change(struct sock *sock) { struct sock_mapping *map = sock->sk_user_data; - struct pvcalls_data_intf *intf; if (map == NULL) return; - intf = map->ring; atomic_inc(&map->read); notify_remote_via_irq(map->irq); } -- cgit v1.2.3-58-ga151 From 03fa483821c0b4db7c2b1453d3332f397d82313f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Jan 2019 15:10:00 -0300 Subject: perf test shell: Use a fallback to get the pathname in vfs_getname Some kernels, like 4.19.13-300.fc29.x86_64 in fedora 29, fail with the existing probe definition asking for the contents of result->name, working when we ask for the 'filename' variable instead, so add a fallback to that. Now those tests are back working on fedora 29 systems with that kernel: # perf test vfs_getname 65: Use vfs_getname probe to get syscall args filenames : Ok 66: Add vfs_getname probe to get syscall args filenames : Ok 67: Check open filename arg using perf trace + vfs_getname: Ok # Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-klt3n0i58dfqttveti09q3fi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/lib/probe_vfs_getname.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/shell/lib/probe_vfs_getname.sh b/tools/perf/tests/shell/lib/probe_vfs_getname.sh index 1c16e56cd93e..7cb99b433888 100644 --- a/tools/perf/tests/shell/lib/probe_vfs_getname.sh +++ b/tools/perf/tests/shell/lib/probe_vfs_getname.sh @@ -13,7 +13,8 @@ add_probe_vfs_getname() { local verbose=$1 if [ $had_vfs_getname -eq 1 ] ; then line=$(perf probe -L getname_flags 2>&1 | egrep 'result.*=.*filename;' | sed -r 's/[[:space:]]+([[:digit:]]+)[[:space:]]+result->uptr.*/\1/') - perf probe $verbose "vfs_getname=getname_flags:${line} pathname=result->name:string" + perf probe -q "vfs_getname=getname_flags:${line} pathname=result->name:string" || \ + perf probe $verbose "vfs_getname=getname_flags:${line} pathname=filename:string" fi } -- cgit v1.2.3-58-ga151 From 1492623e837fe7ca6296f7f5411328307e242771 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 29 Dec 2018 17:42:22 +0100 Subject: octeontx2-af: Fix a resource leak in an error handling path in 'cgx_probe()' If an error occurs after the call to 'pci_alloc_irq_vectors()', we must call 'pci_free_irq_vectors()' in order to avoid a resource leak. The same sequence is already in place in the corresponding 'cgx_remove()' function. Fixes: 1463f382f58d ("octeontx2-af: Add support for CGX link management") Signed-off-by: Christophe JAILLET Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 742f0c1f60df..6d55e3d0b7ea 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -825,7 +825,7 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!cgx->cgx_cmd_workq) { dev_err(dev, "alloc workqueue failed for cgx cmd"); err = -ENOMEM; - goto err_release_regions; + goto err_free_irq_vectors; } list_add(&cgx->cgx_list, &cgx_list); @@ -841,6 +841,8 @@ static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) err_release_lmac: cgx_lmac_exit(cgx); list_del(&cgx->cgx_list); +err_free_irq_vectors: + pci_free_irq_vectors(pdev); err_release_regions: pci_release_regions(pdev); err_disable_device: -- cgit v1.2.3-58-ga151 From 7c1e8a3817c55d73b27cc29b84075999c8894179 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 31 Dec 2018 02:10:58 +0000 Subject: netlink: fixup regression in RTM_GETADDR This commit fixes a regression in AF_INET/RTM_GETADDR and AF_INET6/RTM_GETADDR. Before this commit, the kernel would stop dumping addresses once the first skb was full and end the stream with NLMSG_DONE(-EMSGSIZE). The error shouldn't be sent back to netlink_dump so the callback is kept alive. The userspace is expected to call back with a new empty skb. Changes from V1: - The error is not handled in netlink_dump anymore but rather in inet_dump_ifaddr and inet6_dump_addr directly as suggested by David Ahern. Fixes: d7e38611b81e ("net/ipv4: Put target net when address dump fails due to bad attributes") Fixes: 242afaa6968c ("net/ipv6: Put target net when address dump fails due to bad attributes") Cc: David Ahern Cc: "David S . Miller" Cc: netdev@vger.kernel.org Signed-off-by: Arthur Gautier Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 2 +- net/ipv6/addrconf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 04ba321ae5ce..e258a00b4a3d 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1826,7 +1826,7 @@ put_tgt_net: if (fillargs.netnsid >= 0) put_net(tgt_net); - return err < 0 ? err : skb->len; + return skb->len ? : err; } static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 8eeec6eb2bd3..93d5ad2b1a69 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -5154,7 +5154,7 @@ put_tgt_net: if (fillargs.netnsid >= 0) put_net(tgt_net); - return err < 0 ? err : skb->len; + return skb->len ? : err; } static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) -- cgit v1.2.3-58-ga151 From 36352991835ce99e46b4441dd0eb6980f9a83e8f Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Wed, 2 Jan 2019 14:45:07 +0800 Subject: r8169: Add support for new Realtek Ethernet There are two new Realtek Ethernet devices which are re-branded r8168h. Add the IDs to to support them. Signed-off-by: Kai-Heng Feng Reviewed-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 298930d39b79..7fe9180261b8 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -205,6 +205,8 @@ enum cfg_version { }; static const struct pci_device_id rtl8169_pci_tbl[] = { + { PCI_VDEVICE(REALTEK, 0x2502), RTL_CFG_1 }, + { PCI_VDEVICE(REALTEK, 0x2600), RTL_CFG_1 }, { PCI_VDEVICE(REALTEK, 0x8129), RTL_CFG_0 }, { PCI_VDEVICE(REALTEK, 0x8136), RTL_CFG_2 }, { PCI_VDEVICE(REALTEK, 0x8161), RTL_CFG_1 }, -- cgit v1.2.3-58-ga151 From 8d68100ab4ad92560a16a68b72e068613ac4d573 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Thu, 3 Jan 2019 01:09:53 +0800 Subject: soc/fsl/qe: fix err handling of ucc_of_parse_tdm Currently there are some issues with the ucc_of_parse_tdm function: 1, a possible null pointer dereference in ucc_of_parse_tdm, detected by the semantic patch deref_null.cocci, with the following warning: drivers/soc/fsl/qe/qe_tdm.c:177:21-24: ERROR: pdev is NULL but dereferenced. 2, dev gets modified, so in any case that devm_iounmap() will fail even when the new pdev is valid, because the iomap was done with a different pdev. 3, there is no driver bind with the "fsl,t1040-qe-si" or "fsl,t1040-qe-siram" device. So allocating resources using devm_*() with these devices won't provide a cleanup path for these resources when the caller fails. This patch fixes them. Suggested-by: Li Yang Suggested-by: Christophe LEROY Signed-off-by: Wen Yang Reviewed-by: Peng Hao CC: Julia Lawall CC: Zhao Qiang CC: David S. Miller CC: netdev@vger.kernel.org CC: linuxppc-dev@lists.ozlabs.org CC: linux-kernel@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/wan/fsl_ucc_hdlc.c | 62 +++++++++++++++++++++++++++++++++++++++++- drivers/soc/fsl/qe/qe_tdm.c | 55 ------------------------------------- 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 839fa7715709..f30a040efd2c 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -1057,6 +1057,54 @@ static const struct net_device_ops uhdlc_ops = { .ndo_tx_timeout = uhdlc_tx_timeout, }; +static int hdlc_map_iomem(char *name, int init_flag, void __iomem **ptr) +{ + struct device_node *np; + struct platform_device *pdev; + struct resource *res; + static int siram_init_flag; + int ret = 0; + + np = of_find_compatible_node(NULL, NULL, name); + if (!np) + return -EINVAL; + + pdev = of_find_device_by_node(np); + if (!pdev) { + pr_err("%pOFn: failed to lookup pdev\n", np); + of_node_put(np); + return -EINVAL; + } + + of_node_put(np); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -EINVAL; + goto error_put_device; + } + *ptr = ioremap(res->start, resource_size(res)); + if (!*ptr) { + ret = -ENOMEM; + goto error_put_device; + } + + /* We've remapped the addresses, and we don't need the device any + * more, so we should release it. + */ + put_device(&pdev->dev); + + if (init_flag && siram_init_flag == 0) { + memset_io(*ptr, 0, resource_size(res)); + siram_init_flag = 1; + } + return 0; + +error_put_device: + put_device(&pdev->dev); + + return ret; +} + static int ucc_hdlc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1151,6 +1199,15 @@ static int ucc_hdlc_probe(struct platform_device *pdev) ret = ucc_of_parse_tdm(np, utdm, ut_info); if (ret) goto free_utdm; + + ret = hdlc_map_iomem("fsl,t1040-qe-si", 0, + (void __iomem **)&utdm->si_regs); + if (ret) + goto free_utdm; + ret = hdlc_map_iomem("fsl,t1040-qe-siram", 1, + (void __iomem **)&utdm->siram); + if (ret) + goto unmap_si_regs; } if (of_property_read_u16(np, "fsl,hmask", &uhdlc_priv->hmask)) @@ -1159,7 +1216,7 @@ static int ucc_hdlc_probe(struct platform_device *pdev) ret = uhdlc_init(uhdlc_priv); if (ret) { dev_err(&pdev->dev, "Failed to init uhdlc\n"); - goto free_utdm; + goto undo_uhdlc_init; } dev = alloc_hdlcdev(uhdlc_priv); @@ -1188,6 +1245,9 @@ static int ucc_hdlc_probe(struct platform_device *pdev) free_dev: free_netdev(dev); undo_uhdlc_init: + iounmap(utdm->siram); +unmap_si_regs: + iounmap(utdm->si_regs); free_utdm: if (uhdlc_priv->tsa) kfree(utdm); diff --git a/drivers/soc/fsl/qe/qe_tdm.c b/drivers/soc/fsl/qe/qe_tdm.c index f78c34647ca2..76480df195a8 100644 --- a/drivers/soc/fsl/qe/qe_tdm.c +++ b/drivers/soc/fsl/qe/qe_tdm.c @@ -44,10 +44,6 @@ int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm, const char *sprop; int ret = 0; u32 val; - struct resource *res; - struct device_node *np2; - static int siram_init_flag; - struct platform_device *pdev; sprop = of_get_property(np, "fsl,rx-sync-clock", NULL); if (sprop) { @@ -124,57 +120,6 @@ int ucc_of_parse_tdm(struct device_node *np, struct ucc_tdm *utdm, utdm->siram_entry_id = val; set_si_param(utdm, ut_info); - - np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-si"); - if (!np2) - return -EINVAL; - - pdev = of_find_device_by_node(np2); - if (!pdev) { - pr_err("%pOFn: failed to lookup pdev\n", np2); - of_node_put(np2); - return -EINVAL; - } - - of_node_put(np2); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - utdm->si_regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(utdm->si_regs)) { - ret = PTR_ERR(utdm->si_regs); - goto err_miss_siram_property; - } - - np2 = of_find_compatible_node(NULL, NULL, "fsl,t1040-qe-siram"); - if (!np2) { - ret = -EINVAL; - goto err_miss_siram_property; - } - - pdev = of_find_device_by_node(np2); - if (!pdev) { - ret = -EINVAL; - pr_err("%pOFn: failed to lookup pdev\n", np2); - of_node_put(np2); - goto err_miss_siram_property; - } - - of_node_put(np2); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - utdm->siram = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(utdm->siram)) { - ret = PTR_ERR(utdm->siram); - goto err_miss_siram_property; - } - - if (siram_init_flag == 0) { - memset_io(utdm->siram, 0, resource_size(res)); - siram_init_flag = 1; - } - - return ret; - -err_miss_siram_property: - devm_iounmap(&pdev->dev, utdm->si_regs); return ret; } EXPORT_SYMBOL(ucc_of_parse_tdm); -- cgit v1.2.3-58-ga151 From f8c468e8537925e0c4607263f498a1b7c0c8982e Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Wed, 2 Jan 2019 13:01:43 -0800 Subject: net, skbuff: do not prefer skb allocation fails early Commit dcda9b04713c ("mm, tree wide: replace __GFP_REPEAT by __GFP_RETRY_MAYFAIL with more useful semantic") replaced __GFP_REPEAT in alloc_skb_with_frags() with __GFP_RETRY_MAYFAIL when the allocation may directly reclaim. The previous behavior would require reclaim up to 1 << order pages for skb aligned header_len of order > PAGE_ALLOC_COSTLY_ORDER before failing, otherwise the allocations in alloc_skb() would loop in the page allocator looking for memory. __GFP_RETRY_MAYFAIL makes both allocations failable under memory pressure, including for the HEAD allocation. This can cause, among many other things, write() to fail with ENOTCONN during RPC when under memory pressure. These allocations should succeed as they did previous to dcda9b04713c even if it requires calling the oom killer and additional looping in the page allocator to find memory. There is no way to specify the previous behavior of __GFP_REPEAT, but it's unlikely to be necessary since the previous behavior only guaranteed that 1 << order pages would be reclaimed before failing for order > PAGE_ALLOC_COSTLY_ORDER. That reclaim is not guaranteed to be contiguous memory, so repeating for such large orders is usually not beneficial. Removing the setting of __GFP_RETRY_MAYFAIL to restore the previous behavior, specifically not allowing alloc_skb() to fail for small orders and oom kill if necessary rather than allowing RPCs to fail. Fixes: dcda9b04713c ("mm, tree wide: replace __GFP_REPEAT by __GFP_RETRY_MAYFAIL with more useful semantic") Signed-off-by: David Rientjes Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/skbuff.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 37317ffec146..26d848484912 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -5270,7 +5270,6 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len, unsigned long chunk; struct sk_buff *skb; struct page *page; - gfp_t gfp_head; int i; *errcode = -EMSGSIZE; @@ -5280,12 +5279,8 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len, if (npages > MAX_SKB_FRAGS) return NULL; - gfp_head = gfp_mask; - if (gfp_head & __GFP_DIRECT_RECLAIM) - gfp_head |= __GFP_RETRY_MAYFAIL; - *errcode = -ENOBUFS; - skb = alloc_skb(header_len, gfp_head); + skb = alloc_skb(header_len, gfp_mask); if (!skb) return NULL; -- cgit v1.2.3-58-ga151 From 2d533a9287f2011632977e87ce2783f4c689c984 Mon Sep 17 00:00:00 2001 From: Denis Bolotin Date: Thu, 3 Jan 2019 12:02:39 +0200 Subject: qed: Fix qed_chain_set_prod() for PBL chains with non power of 2 page count In PBL chains with non power of 2 page count, the producer is not at the beginning of the chain when index is 0 after a wrap. Therefore, after the producer index wrap around, page index should be calculated more carefully. Signed-off-by: Denis Bolotin Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- include/linux/qed/qed_chain.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/linux/qed/qed_chain.h b/include/linux/qed/qed_chain.h index 59ddf9af909e..2dd0a9ed5b36 100644 --- a/include/linux/qed/qed_chain.h +++ b/include/linux/qed/qed_chain.h @@ -663,6 +663,37 @@ out: static inline void qed_chain_set_prod(struct qed_chain *p_chain, u32 prod_idx, void *p_prod_elem) { + if (p_chain->mode == QED_CHAIN_MODE_PBL) { + u32 cur_prod, page_mask, page_cnt, page_diff; + + cur_prod = is_chain_u16(p_chain) ? p_chain->u.chain16.prod_idx : + p_chain->u.chain32.prod_idx; + + /* Assume that number of elements in a page is power of 2 */ + page_mask = ~p_chain->elem_per_page_mask; + + /* Use "cur_prod - 1" and "prod_idx - 1" since producer index + * reaches the first element of next page before the page index + * is incremented. See qed_chain_produce(). + * Index wrap around is not a problem because the difference + * between current and given producer indices is always + * positive and lower than the chain's capacity. + */ + page_diff = (((cur_prod - 1) & page_mask) - + ((prod_idx - 1) & page_mask)) / + p_chain->elem_per_page; + + page_cnt = qed_chain_get_page_cnt(p_chain); + if (is_chain_u16(p_chain)) + p_chain->pbl.c.u16.prod_page_idx = + (p_chain->pbl.c.u16.prod_page_idx - + page_diff + page_cnt) % page_cnt; + else + p_chain->pbl.c.u32.prod_page_idx = + (p_chain->pbl.c.u32.prod_page_idx - + page_diff + page_cnt) % page_cnt; + } + if (is_chain_u16(p_chain)) p_chain->u.chain16.prod_idx = (u16) prod_idx; else -- cgit v1.2.3-58-ga151 From 46721c3d9e273aea880e9ff835b0e1271e1cd2fb Mon Sep 17 00:00:00 2001 From: Denis Bolotin Date: Thu, 3 Jan 2019 12:02:40 +0200 Subject: qed: Fix qed_ll2_post_rx_buffer_notify_fw() by adding a write memory barrier Make sure chain element is updated before ringing the doorbell. Signed-off-by: Denis Bolotin Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_ll2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 90afd514ffe1..d9237c65a838 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -1619,6 +1619,10 @@ static void qed_ll2_post_rx_buffer_notify_fw(struct qed_hwfn *p_hwfn, cq_prod = qed_chain_get_prod_idx(&p_rx->rcq_chain); rx_prod.bd_prod = cpu_to_le16(bd_prod); rx_prod.cqe_prod = cpu_to_le16(cq_prod); + + /* Make sure chain element is updated before ringing the doorbell */ + dma_wmb(); + DIRECT_REG_WR(p_rx->set_prod_addr, *((u32 *)&rx_prod)); } -- cgit v1.2.3-58-ga151 From a09b42ba1a5e1cbeb934fd94cb7b5b9018bf15c7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 3 Jan 2019 13:36:43 +0100 Subject: net: dsa: microchip: Drop unused GPIO includes This driver does not use the old GPIO includes so drop them. Signed-off-by: Linus Walleij Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz_common.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 3b12e2dcff31..8a5111f9414c 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -15,7 +14,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-58-ga151 From ba3e1847d6471f30241f11069d8f153ed8cb052b Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 3 Jan 2019 14:59:35 +0000 Subject: net: macb: remove unnecessary code Commit 653e92a9175e ("net: macb: add support for padding and fcs computation") introduced a bug fixed by commit 899ecaedd155 ("net: ethernet: cadence: fix socket buffer corruption problem"). Code removed in this patch is not reachable at all so remove it. Fixes: 653e92a9175e ("net: macb: add support for padding and fcs computation") Cc: Tristram Ha Signed-off-by: Claudiu Beznea Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index b126926ef7f5..66cc7927061a 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1738,12 +1738,8 @@ static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev) *skb = nskb; } - if (padlen) { - if (padlen >= ETH_FCS_LEN) - skb_put_zero(*skb, padlen - ETH_FCS_LEN); - else - skb_trim(*skb, ETH_FCS_LEN - padlen); - } + if (padlen > ETH_FCS_LEN) + skb_put_zero(*skb, padlen - ETH_FCS_LEN); add_fcs: /* set FCS to packet */ -- cgit v1.2.3-58-ga151 From 41e4e2cd75346667b0c531c07dab05cce5b06d15 Mon Sep 17 00:00:00 2001 From: Yi-Hung Wei Date: Thu, 3 Jan 2019 09:51:57 -0800 Subject: openvswitch: Fix IPv6 later frags parsing The previous commit fa642f08839b ("openvswitch: Derive IP protocol number for IPv6 later frags") introduces IP protocol number parsing for IPv6 later frags that can mess up the network header length calculation logic, i.e. nh_len < 0. However, the network header length calculation is mainly for deriving the transport layer header in the key extraction process which the later fragment does not apply. Therefore, this commit skips the network header length calculation to fix the issue. Reported-by: Chris Mi Reported-by: Greg Rose Fixes: fa642f08839b ("openvswitch: Derive IP protocol number for IPv6 later frags") Signed-off-by: Yi-Hung Wei Signed-off-by: David S. Miller --- net/openvswitch/flow.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 57e07768c9d1..f54cf17ef7a8 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -276,10 +276,12 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) nexthdr = ipv6_find_hdr(skb, &payload_ofs, -1, &frag_off, &flags); if (flags & IP6_FH_F_FRAG) { - if (frag_off) + if (frag_off) { key->ip.frag = OVS_FRAG_TYPE_LATER; - else - key->ip.frag = OVS_FRAG_TYPE_FIRST; + key->ip.proto = nexthdr; + return 0; + } + key->ip.frag = OVS_FRAG_TYPE_FIRST; } else { key->ip.frag = OVS_FRAG_TYPE_NONE; } -- cgit v1.2.3-58-ga151 From bc6e019b6ee65ff4ebf3ca272f774cf6c67db669 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Thu, 3 Jan 2019 21:43:34 +0100 Subject: fou: Prevent unbounded recursion in GUE error handler also with UDP-Lite In commit 11789039da53 ("fou: Prevent unbounded recursion in GUE error handler"), I didn't take care of the case where UDP-Lite is encapsulated into UDP or UDP-Lite with GUE. From a syzbot report about a possibly similar issue with GUE on IPv6, I just realised the same thing might happen with a UDP-Lite inner payload. Also skip exception handling for inner UDP-Lite protocol. Fixes: 11789039da53 ("fou: Prevent unbounded recursion in GUE error handler") Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- net/ipv4/fou.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 0c9f171fb085..632863541082 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -1065,7 +1065,8 @@ static int gue_err(struct sk_buff *skb, u32 info) * recursion. Besides, this kind of encapsulation can't even be * configured currently. Discard this. */ - if (guehdr->proto_ctype == IPPROTO_UDP) + if (guehdr->proto_ctype == IPPROTO_UDP || + guehdr->proto_ctype == IPPROTO_UDPLITE) return -EOPNOTSUPP; skb_set_transport_header(skb, -(int)sizeof(struct icmphdr)); -- cgit v1.2.3-58-ga151 From 44039e00171b0fe930c07ff7b43e6023eaf1ed31 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Thu, 3 Jan 2019 21:43:35 +0100 Subject: fou6: Prevent unbounded recursion in GUE error handler I forgot to deal with IPv6 in commit 11789039da53 ("fou: Prevent unbounded recursion in GUE error handler"). Now syzbot reported what might be the same type of issue, caused by gue6_err(), that is, handling exceptions for direct UDP encapsulation in GUE (UDP-in-UDP) leads to unbounded recursion in the GUE exception handler. As it probably doesn't make sense to set up GUE this way, and it's currently not even possible to configure this, skip exception handling for UDP (or UDP-Lite) packets encapsulated in UDP (or UDP-Lite) packets with GUE on IPv6. Reported-by: syzbot+4ad25edc7a33e4ab91e0@syzkaller.appspotmail.com Reported-by: Willem de Bruijn Reported-by: Eric Dumazet Fixes: b8a51b38e4d4 ("fou, fou6: ICMP error handlers for FoU and GUE") Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- net/ipv6/fou6.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c index bd675c61deb1..7da7bf3b7fe3 100644 --- a/net/ipv6/fou6.c +++ b/net/ipv6/fou6.c @@ -131,6 +131,14 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (validate_gue_flags(guehdr, optlen)) return -EINVAL; + /* Handling exceptions for direct UDP encapsulation in GUE would lead to + * recursion. Besides, this kind of encapsulation can't even be + * configured currently. Discard this. + */ + if (guehdr->proto_ctype == IPPROTO_UDP || + guehdr->proto_ctype == IPPROTO_UDPLITE) + return -EOPNOTSUPP; + skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr)); ret = gue6_err_proto_handler(guehdr->proto_ctype, skb, opt, type, code, offset, info); -- cgit v1.2.3-58-ga151 From cff1e01f16f84083e5b4e3a98331ba405fb3fbb5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 3 Jan 2019 22:31:32 +0100 Subject: net: dsa: mt7530: Drop unused GPIO include This driver uses GPIO descriptors only, is not used so drop the include. Signed-off-by: Linus Walleij Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mt7530.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 74547f43b938..a8a2c728afba 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-58-ga151 From c77804be53369dd4c15bfc376cf9b45948194cab Mon Sep 17 00:00:00 2001 From: Yonglong Liu Date: Fri, 4 Jan 2019 20:18:10 +0800 Subject: net: hns: Fix WARNING when hns modules installed Commit 308c6cafde01 ("net: hns: All ports can not work when insmod hns ko after rmmod.") add phy_stop in hns_nic_init_phy(), In the branch of "net", this method is effective, but in the branch of "net-next", it will cause a WARNING when hns modules loaded, reference to commit 2b3e88ea6528 ("net: phy: improve phy state checking"): [10.092168] ------------[ cut here ]------------ [10.092171] called from state READY [10.092189] WARNING: CPU: 4 PID: 1 at ../drivers/net/phy/phy.c:854 phy_stop+0x90/0xb0 [10.092192] Modules linked in: [10.092197] CPU: 4 PID:1 Comm:swapper/0 Not tainted 4.20.0-rc7-next-20181220 #1 [10.092200] Hardware name: Huawei TaiShan 2280 /D05, BIOS Hisilicon D05 UEFI 16.12 Release 05/15/2017 [10.092202] pstate: 60000005 (nZCv daif -PAN -UAO) [10.092205] pc : phy_stop+0x90/0xb0 [10.092208] lr : phy_stop+0x90/0xb0 [10.092209] sp : ffff00001159ba90 [10.092212] x29: ffff00001159ba90 x28: 0000000000000007 [10.092215] x27: ffff000011180068 x26: ffff0000110a5620 [10.092218] x25: ffff0000113b6000 x24: ffff842f96dac000 [10.092221] x23: 0000000000000000 x22: 0000000000000000 [10.092223] x21: ffff841fb8425e18 x20: ffff801fb3a56438 [10.092226] x19: ffff801fb3a56000 x18: ffffffffffffffff [10.092228] x17: 0000000000000000 x16: 0000000000000000 [10.092231] x15: ffff00001122d6c8 x14: ffff00009159b7b7 [10.092234] x13: ffff00001159b7c5 x12: ffff000011245000 [10.092236] x11: 0000000005f5e0ff x10: ffff00001159b750 [10.092239] x9 : 00000000ffffffd0 x8 : 0000000000000465 [10.092242] x7 : ffff0000112457f8 x6 : ffff0000113bd7ce [10.092245] x5 : 0000000000000000 x4 : 0000000000000000 [10.092247] x3 : 00000000ffffffff x2 : ffff000011245828 [10.092250] x1 : 4b5860bd05871300 x0 : 0000000000000000 [10.092253] Call trace: [10.092255] phy_stop+0x90/0xb0 [10.092260] hns_nic_init_phy+0xf8/0x110 [10.092262] hns_nic_try_get_ae+0x4c/0x3b0 [10.092264] hns_nic_dev_probe+0x1fc/0x480 [10.092268] platform_drv_probe+0x50/0xa0 [10.092271] really_probe+0x1f4/0x298 [10.092273] driver_probe_device+0x58/0x108 [10.092275] __driver_attach+0xdc/0xe0 [10.092278] bus_for_each_dev+0x74/0xc8 [10.092280] driver_attach+0x20/0x28 [10.092283] bus_add_driver+0x1b8/0x228 [10.092285] driver_register+0x60/0x110 [10.092288] __platform_driver_register+0x40/0x48 [10.092292] hns_nic_dev_driver_init+0x18/0x20 [10.092296] do_one_initcall+0x5c/0x180 [10.092299] kernel_init_freeable+0x198/0x240 [10.092303] kernel_init+0x10/0x108 [10.092306] ret_from_fork+0x10/0x18 [10.092308] ---[ end trace 1396dd0278e397eb ]--- This WARNING occurred because of calling phy_stop before phy_start. The root cause of the problem in commit '308c6cafde01' is: Reference to hns_nic_init_phy, the flag phydev->supported is changed after phy_connect_direct. The flag phydev->supported is 0x6ff when hns modules is loaded, so will not change Fiber Port power(Reference to marvell.c), which is power on at default. Then the flag phydev->supported is changed to 0x6f, so Fiber Port power is off when removing hns modules. When hns modules installed again, the flag phydev->supported is default value 0x6ff, so will not change Fiber Port power(now is off), causing mac link not up problem. So the solution is change phy flags before phy_connect_direct. Fixes: 308c6cafde01 ("net: hns: All ports can not work when insmod hns ko after rmmod.") Signed-off-by: Yonglong Liu Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 5748d3f722f6..5b33238c6680 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -1170,6 +1170,13 @@ int hns_nic_init_phy(struct net_device *ndev, struct hnae_handle *h) if (!h->phy_dev) return 0; + ethtool_convert_legacy_u32_to_link_mode(supported, h->if_support); + linkmode_and(phy_dev->supported, phy_dev->supported, supported); + linkmode_copy(phy_dev->advertising, phy_dev->supported); + + if (h->phy_if == PHY_INTERFACE_MODE_XGMII) + phy_dev->autoneg = false; + if (h->phy_if != PHY_INTERFACE_MODE_XGMII) { phy_dev->dev_flags = 0; @@ -1181,16 +1188,6 @@ int hns_nic_init_phy(struct net_device *ndev, struct hnae_handle *h) if (unlikely(ret)) return -ENODEV; - ethtool_convert_legacy_u32_to_link_mode(supported, h->if_support); - linkmode_and(phy_dev->supported, phy_dev->supported, supported); - linkmode_copy(phy_dev->advertising, phy_dev->supported); - - if (h->phy_if == PHY_INTERFACE_MODE_XGMII) - phy_dev->autoneg = false; - - if (h->phy_if == PHY_INTERFACE_MODE_SGMII) - phy_stop(phy_dev); - return 0; } -- cgit v1.2.3-58-ga151 From bb989501abcafa0de5f18b0ec0ec459b5b817908 Mon Sep 17 00:00:00 2001 From: Yonglong Liu Date: Fri, 4 Jan 2019 20:18:11 +0800 Subject: net: hns: Fix use after free identified by SLUB debug When enable SLUB debug, than remove hns_enet_drv module, SLUB debug will identify a use after free bug: [134.189505] Unable to handle kernel paging request at virtual address 006b6b6b6b6b6b6b [134.197553] Mem abort info: [134.200381] ESR = 0x96000004 [134.203487] Exception class = DABT (current EL), IL = 32 bits [134.209497] SET = 0, FnV = 0 [134.212596] EA = 0, S1PTW = 0 [134.215777] Data abort info: [134.218701] ISV = 0, ISS = 0x00000004 [134.222596] CM = 0, WnR = 0 [134.225606] [006b6b6b6b6b6b6b] address between user and kernel address ranges [134.232851] Internal error: Oops: 96000004 [#1] SMP [134.237798] CPU: 21 PID: 27834 Comm: rmmod Kdump: loaded Tainted: G OE 4.19.5-1.2.34.aarch64 #1 [134.247856] Hardware name: Huawei TaiShan 2280 /BC11SPCD, BIOS 1.58 10/24/2018 [134.255181] pstate: 20000005 (nzCv daif -PAN -UAO) [134.260044] pc : hns_ae_put_handle+0x38/0x60 [134.264372] lr : hns_ae_put_handle+0x24/0x60 [134.268700] sp : ffff00001be93c50 [134.272054] x29: ffff00001be93c50 x28: ffff802faaec8040 [134.277442] x27: 0000000000000000 x26: 0000000000000000 [134.282830] x25: 0000000056000000 x24: 0000000000000015 [134.288284] x23: ffff0000096fe098 x22: ffff000001050070 [134.293671] x21: ffff801fb3c044a0 x20: ffff80afb75ec098 [134.303287] x19: ffff80afb75ec098 x18: 0000000000000000 [134.312945] x17: 0000000000000000 x16: 0000000000000000 [134.322517] x15: 0000000000000002 x14: 0000000000000000 [134.332030] x13: dead000000000100 x12: ffff7e02bea3c988 [134.341487] x11: ffff80affbee9e68 x10: 0000000000000000 [134.351033] x9 : 6fffff8000008101 x8 : 0000000000000000 [134.360569] x7 : dead000000000100 x6 : ffff000009579748 [134.370059] x5 : 0000000000210d00 x4 : 0000000000000000 [134.379550] x3 : 0000000000000001 x2 : 0000000000000000 [134.388813] x1 : 6b6b6b6b6b6b6b6b x0 : 0000000000000000 [134.397993] Process rmmod (pid: 27834, stack limit = 0x00000000d474b7fd) [134.408498] Call trace: [134.414611] hns_ae_put_handle+0x38/0x60 [134.422208] hnae_put_handle+0xd4/0x108 [134.429563] hns_nic_dev_remove+0x60/0xc0 [hns_enet_drv] [134.438342] platform_drv_remove+0x2c/0x70 [134.445958] device_release_driver_internal+0x174/0x208 [134.454810] driver_detach+0x70/0xd8 [134.461913] bus_remove_driver+0x64/0xe8 [134.469396] driver_unregister+0x34/0x60 [134.476822] platform_driver_unregister+0x20/0x30 [134.485130] hns_nic_dev_driver_exit+0x14/0x6e4 [hns_enet_drv] [134.494634] __arm64_sys_delete_module+0x238/0x290 struct hnae_handle is a member of struct hnae_vf_cb, so when vf_cb is freed, than use hnae_handle will cause use after free panic. This patch frees vf_cb after hnae_handle used. Signed-off-by: Yonglong Liu Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c index ad1779fc410e..a78bfafd212c 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c @@ -147,12 +147,10 @@ static void hns_ae_put_handle(struct hnae_handle *handle) struct hnae_vf_cb *vf_cb = hns_ae_get_vf_cb(handle); int i; - vf_cb->mac_cb = NULL; - - kfree(vf_cb); - for (i = 0; i < handle->q_num; i++) hns_ae_get_ring_pair(handle->qs[i])->used_by_vf = 0; + + kfree(vf_cb); } static int hns_ae_wait_flow_down(struct hnae_handle *handle) -- cgit v1.2.3-58-ga151 From f87118d5760f00af7228033fbe783c7f380d2866 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Fri, 4 Jan 2019 13:26:10 +0100 Subject: qmi_wwan: add MTU default to qmap network interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds MTU default value to qmap network interface in order to avoid "RTNETLINK answers: No buffer space available" error when setting an ipv6 address. Signed-off-by: Daniele Palmas Acked-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 774e1ff01c9a..735ad838e2ba 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -123,6 +123,7 @@ static void qmimux_setup(struct net_device *dev) dev->addr_len = 0; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->netdev_ops = &qmimux_netdev_ops; + dev->mtu = 1500; dev->needs_free_netdev = true; } -- cgit v1.2.3-58-ga151 From 3271a4821882a64214acc1bd7b173900ec70c9bf Mon Sep 17 00:00:00 2001 From: Peter Oskolkov Date: Fri, 4 Jan 2019 09:43:08 -0800 Subject: selftests: net: fix/improve ip_defrag selftest Commit ade446403bfb ("net: ipv4: do not handle duplicate fragments as overlapping") changed IPv4 defragmentation so that duplicate fragments, as well as _some_ fragments completely covered by previously delivered fragments, do not lead to the whole frag queue being discarded. This makes the existing ip_defrag selftest flaky. This patch * makes sure that negative IPv4 defrag tests generate truly overlapping fragments that trigger defrag queue drops; * tests that duplicate IPv4 fragments do not trigger defrag queue drops; * makes a couple of minor tweaks to the test aimed at increasing its code coverage and reduce flakiness. Signed-off-by: Peter Oskolkov Signed-off-by: David S. Miller --- tools/testing/selftests/net/ip_defrag.c | 96 +++++++++++++++++++++++++++++--- tools/testing/selftests/net/ip_defrag.sh | 9 ++- 2 files changed, 95 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/net/ip_defrag.c b/tools/testing/selftests/net/ip_defrag.c index 61ae2782388e..5d56cc0838f6 100644 --- a/tools/testing/selftests/net/ip_defrag.c +++ b/tools/testing/selftests/net/ip_defrag.c @@ -203,6 +203,7 @@ static void send_udp_frags(int fd_raw, struct sockaddr *addr, { struct ip *iphdr = (struct ip *)ip_frame; struct ip6_hdr *ip6hdr = (struct ip6_hdr *)ip_frame; + const bool ipv4 = !ipv6; int res; int offset; int frag_len; @@ -239,19 +240,53 @@ static void send_udp_frags(int fd_raw, struct sockaddr *addr, iphdr->ip_sum = 0; } + /* Occasionally test in-order fragments. */ + if (!cfg_overlap && (rand() % 100 < 15)) { + offset = 0; + while (offset < (UDP_HLEN + payload_len)) { + send_fragment(fd_raw, addr, alen, offset, ipv6); + offset += max_frag_len; + } + return; + } + + /* Occasionally test IPv4 "runs" (see net/ipv4/ip_fragment.c) */ + if (ipv4 && !cfg_overlap && (rand() % 100 < 20) && + (payload_len > 9 * max_frag_len)) { + offset = 6 * max_frag_len; + while (offset < (UDP_HLEN + payload_len)) { + send_fragment(fd_raw, addr, alen, offset, ipv6); + offset += max_frag_len; + } + offset = 3 * max_frag_len; + while (offset < 6 * max_frag_len) { + send_fragment(fd_raw, addr, alen, offset, ipv6); + offset += max_frag_len; + } + offset = 0; + while (offset < 3 * max_frag_len) { + send_fragment(fd_raw, addr, alen, offset, ipv6); + offset += max_frag_len; + } + return; + } + /* Odd fragments. */ offset = max_frag_len; while (offset < (UDP_HLEN + payload_len)) { send_fragment(fd_raw, addr, alen, offset, ipv6); + /* IPv4 ignores duplicates, so randomly send a duplicate. */ + if (ipv4 && (1 == rand() % 100)) + send_fragment(fd_raw, addr, alen, offset, ipv6); offset += 2 * max_frag_len; } if (cfg_overlap) { /* Send an extra random fragment. */ - offset = rand() % (UDP_HLEN + payload_len - 1); - /* sendto() returns EINVAL if offset + frag_len is too small. */ if (ipv6) { struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN); + /* sendto() returns EINVAL if offset + frag_len is too small. */ + offset = rand() % (UDP_HLEN + payload_len - 1); frag_len = max_frag_len + rand() % 256; /* In IPv6 if !!(frag_len % 8), the fragment is dropped. */ frag_len &= ~0x7; @@ -259,13 +294,29 @@ static void send_udp_frags(int fd_raw, struct sockaddr *addr, ip6hdr->ip6_plen = htons(frag_len); frag_len += IP6_HLEN; } else { - frag_len = IP4_HLEN + UDP_HLEN + rand() % 256; + /* In IPv4, duplicates and some fragments completely inside + * previously sent fragments are dropped/ignored. So + * random offset and frag_len can result in a dropped + * fragment instead of a dropped queue/packet. So we + * hard-code offset and frag_len. + * + * See ade446403bfb ("net: ipv4: do not handle duplicate + * fragments as overlapping"). + */ + if (max_frag_len * 4 < payload_len || max_frag_len < 16) { + /* not enough payload to play with random offset and frag_len. */ + offset = 8; + frag_len = IP4_HLEN + UDP_HLEN + max_frag_len; + } else { + offset = rand() % (payload_len / 2); + frag_len = 2 * max_frag_len + 1 + rand() % 256; + } iphdr->ip_off = htons(offset / 8 | IP4_MF); iphdr->ip_len = htons(frag_len); } res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen); if (res < 0) - error(1, errno, "sendto overlap"); + error(1, errno, "sendto overlap: %d", frag_len); if (res != frag_len) error(1, 0, "sendto overlap: %d vs %d", (int)res, frag_len); frag_counter++; @@ -275,6 +326,9 @@ static void send_udp_frags(int fd_raw, struct sockaddr *addr, offset = 0; while (offset < (UDP_HLEN + payload_len)) { send_fragment(fd_raw, addr, alen, offset, ipv6); + /* IPv4 ignores duplicates, so randomly send a duplicate. */ + if (ipv4 && (1 == rand() % 100)) + send_fragment(fd_raw, addr, alen, offset, ipv6); offset += 2 * max_frag_len; } } @@ -282,7 +336,11 @@ static void send_udp_frags(int fd_raw, struct sockaddr *addr, static void run_test(struct sockaddr *addr, socklen_t alen, bool ipv6) { int fd_tx_raw, fd_rx_udp; - struct timeval tv = { .tv_sec = 0, .tv_usec = 10 * 1000 }; + /* Frag queue timeout is set to one second in the calling script; + * socket timeout should be just a bit longer to avoid tests interfering + * with each other. + */ + struct timeval tv = { .tv_sec = 1, .tv_usec = 10 }; int idx; int min_frag_len = ipv6 ? 1280 : 8; @@ -308,12 +366,32 @@ static void run_test(struct sockaddr *addr, socklen_t alen, bool ipv6) payload_len += (rand() % 4096)) { if (cfg_verbose) printf("payload_len: %d\n", payload_len); - max_frag_len = min_frag_len; - do { + + if (cfg_overlap) { + /* With overlaps, one send/receive pair below takes + * at least one second (== timeout) to run, so there + * is not enough test time to run a nested loop: + * the full overlap test takes 20-30 seconds. + */ + max_frag_len = min_frag_len + + rand() % (1500 - FRAG_HLEN - min_frag_len); send_udp_frags(fd_tx_raw, addr, alen, ipv6); recv_validate_udp(fd_rx_udp); - max_frag_len += 8 * (rand() % 8); - } while (max_frag_len < (1500 - FRAG_HLEN) && max_frag_len <= payload_len); + } else { + /* Without overlaps, each packet reassembly (== one + * send/receive pair below) takes very little time to + * run, so we can easily afford more thourough testing + * with a nested loop: the full non-overlap test takes + * less than one second). + */ + max_frag_len = min_frag_len; + do { + send_udp_frags(fd_tx_raw, addr, alen, ipv6); + recv_validate_udp(fd_rx_udp); + max_frag_len += 8 * (rand() % 8); + } while (max_frag_len < (1500 - FRAG_HLEN) && + max_frag_len <= payload_len); + } } /* Cleanup. */ diff --git a/tools/testing/selftests/net/ip_defrag.sh b/tools/testing/selftests/net/ip_defrag.sh index f34672796044..7dd79a9efb17 100755 --- a/tools/testing/selftests/net/ip_defrag.sh +++ b/tools/testing/selftests/net/ip_defrag.sh @@ -11,10 +11,17 @@ readonly NETNS="ns-$(mktemp -u XXXXXX)" setup() { ip netns add "${NETNS}" ip -netns "${NETNS}" link set lo up + ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_high_thresh=9000000 >/dev/null 2>&1 ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_low_thresh=7000000 >/dev/null 2>&1 + ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_time=1 >/dev/null 2>&1 + ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_high_thresh=9000000 >/dev/null 2>&1 ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_low_thresh=7000000 >/dev/null 2>&1 + ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_time=1 >/dev/null 2>&1 + + # DST cache can get full with a lot of frags, with GC not keeping up with the test. + ip netns exec "${NETNS}" sysctl -w net.ipv6.route.max_size=65536 >/dev/null 2>&1 } cleanup() { @@ -27,7 +34,6 @@ setup echo "ipv4 defrag" ip netns exec "${NETNS}" ./ip_defrag -4 - echo "ipv4 defrag with overlaps" ip netns exec "${NETNS}" ./ip_defrag -4o @@ -37,3 +43,4 @@ ip netns exec "${NETNS}" ./ip_defrag -6 echo "ipv6 defrag with overlaps" ip netns exec "${NETNS}" ./ip_defrag -6o +echo "all tests done" -- cgit v1.2.3-58-ga151 From 8d933670452107e41165bea70a30dffbd281bef1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 4 Jan 2019 11:00:00 -0800 Subject: ipv6: make icmp6_send() robust against null skb->dev syzbot was able to crash one host with the following stack trace : kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] PREEMPT SMP KASAN CPU: 0 PID: 8625 Comm: syz-executor4 Not tainted 4.20.0+ #8 RIP: 0010:dev_net include/linux/netdevice.h:2169 [inline] RIP: 0010:icmp6_send+0x116/0x2d30 net/ipv6/icmp.c:426 icmpv6_send smack_socket_sock_rcv_skb security_sock_rcv_skb sk_filter_trim_cap __sk_receive_skb dccp_v6_do_rcv release_sock This is because a RX packet found socket owned by user and was stored into socket backlog. Before leaving RCU protected section, skb->dev was cleared in __sk_receive_skb(). When socket backlog was finally handled at release_sock() time, skb was fed to smack_socket_sock_rcv_skb() then icmp6_send() We could fix the bug in smack_socket_sock_rcv_skb(), or simply make icmp6_send() more robust against such possibility. In the future we might provide to icmp6_send() the net pointer instead of infering it. Fixes: d66a8acbda92 ("Smack: Inform peer that IPv6 traffic has been blocked") Signed-off-by: Eric Dumazet Cc: Piotr Sawicki Cc: Casey Schaufler Reported-by: syzbot Acked-by: Casey Schaufler Signed-off-by: David S. Miller --- net/ipv6/icmp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 5d7aa2c2770c..bbcdfd299692 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -423,10 +423,10 @@ static int icmp6_iif(const struct sk_buff *skb) static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, const struct in6_addr *force_saddr) { - struct net *net = dev_net(skb->dev); struct inet6_dev *idev = NULL; struct ipv6hdr *hdr = ipv6_hdr(skb); struct sock *sk; + struct net *net; struct ipv6_pinfo *np; const struct in6_addr *saddr = NULL; struct dst_entry *dst; @@ -437,12 +437,16 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, int iif = 0; int addr_type = 0; int len; - u32 mark = IP6_REPLY_MARK(net, skb->mark); + u32 mark; if ((u8 *)hdr < skb->head || (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) return; + if (!skb->dev) + return; + net = dev_net(skb->dev); + mark = IP6_REPLY_MARK(net, skb->mark); /* * Make sure we respect the rules * i.e. RFC 1885 2.4(e) -- cgit v1.2.3-58-ga151 From ae84e4a8eb6f0d7f3b902ce238f285e98cf2ac12 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 4 Jan 2019 10:48:02 -0800 Subject: ixgbe: fix Kconfig when driver is not a module The new ability added to the driver to use mii_bus to handle MII related ioctls is causing compile issues when the driver is compiled into the kernel (i.e. not a module). The problem was in selecting MDIO_DEVICE instead of the preferred PHYLIB Kconfig option. The reason being that MDIO_DEVICE had a dependency on PHYLIB and would be compiled as a module when PHYLIB was a module, no matter whether ixgbe was compiled into the kernel. CC: Dave Jones CC: Steve Douthit CC: Florian Fainelli Signed-off-by: Jeff Kirsher Reviewed-by: Stephen Douthit Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 31fb76ee9d82..a1246e89aad4 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -159,7 +159,7 @@ config IXGBE tristate "Intel(R) 10GbE PCI Express adapters support" depends on PCI select MDIO - select MDIO_DEVICE + select PHYLIB imply PTP_1588_CLOCK ---help--- This driver supports Intel(R) 10GbE PCI Express family of -- cgit v1.2.3-58-ga151 From ec90ad334986fa5856d11dd272f7f22fa86c55c4 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 4 Jan 2019 16:58:15 -0800 Subject: ipv6: Consider sk_bound_dev_if when binding a socket to a v4 mapped address Similar to c5ee066333eb ("ipv6: Consider sk_bound_dev_if when binding a socket to an address"), binding a socket to v4 mapped addresses needs to consider if the socket is bound to a device. This problem also exists from the beginning of git history. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 0bfb6cc0a30a..93288b9f1697 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -310,6 +310,7 @@ static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, /* Check if the address belongs to the host. */ if (addr_type == IPV6_ADDR_MAPPED) { + struct net_device *dev = NULL; int chk_addr_ret; /* Binding to v4-mapped address on a v6-only socket @@ -320,9 +321,17 @@ static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, goto out; } + if (sk->sk_bound_dev_if) { + dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); + if (!dev) { + err = -ENODEV; + goto out; + } + } + /* Reproduce AF_INET checks to make the bindings consistent */ v4addr = addr->sin6_addr.s6_addr32[3]; - chk_addr_ret = inet_addr_type(net, v4addr); + chk_addr_ret = inet_addr_type_dev_table(net, dev, v4addr); if (!inet_can_nonlocal_bind(net, inet) && v4addr != htonl(INADDR_ANY) && chk_addr_ret != RTN_LOCAL && -- cgit v1.2.3-58-ga151 From bb351abaf5cd4f9237e1b3094d9cc04853de6d95 Mon Sep 17 00:00:00 2001 From: Weiping Zhang Date: Wed, 26 Dec 2018 11:56:33 +0800 Subject: block: add documentation for io_timeout Add documentation for /sys/block//queue/io_timeout. Reviewed-by: Bart Van Assche Signed-off-by: Weiping Zhang Signed-off-by: Jens Axboe --- Documentation/ABI/testing/sysfs-block | 9 +++++++++ Documentation/block/queue-sysfs.txt | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block index 7710d4022b19..dfad7427817c 100644 --- a/Documentation/ABI/testing/sysfs-block +++ b/Documentation/ABI/testing/sysfs-block @@ -279,3 +279,12 @@ Description: size in 512B sectors of the zones of the device, with the eventual exception of the last zone of the device which may be smaller. + +What: /sys/block//queue/io_timeout +Date: November 2018 +Contact: Weiping Zhang +Description: + io_timeout is the request timeout in milliseconds. If a request + does not complete in this time then the block driver timeout + handler is invoked. That timeout handler can decide to retry + the request, to fail it or to start a device recovery strategy. diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt index 39e286d7afc9..83b457e24bba 100644 --- a/Documentation/block/queue-sysfs.txt +++ b/Documentation/block/queue-sysfs.txt @@ -67,6 +67,13 @@ If set to a value larger than 0, the kernel will put the process issuing IO to sleep for this amount of microseconds before entering classic polling. +io_timeout (RW) +--------------- +io_timeout is the request timeout in milliseconds. If a request does not +complete in this time then the block driver timeout handler is invoked. +That timeout handler can decide to retry the request, to fail it or to start +a device recovery strategy. + iostats (RW) ------------- This file is used to control (on/off) the iostats accounting of the -- cgit v1.2.3-58-ga151 From e8e36984080b55ac5e57bdb09a5b570f2fc8e963 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 4 Jan 2019 01:07:07 -0800 Subject: bpf: Fix [::] -> [::1] rewrite in sys_sendmsg sys_sendmsg has supported unspecified destination IPv6 (wildcard) for unconnected UDP sockets since 876c7f41. When [::] is passed by user as destination, sys_sendmsg rewrites it with [::1] to be consistent with BSD (see "BSD'ism" comment in the code). This didn't work when cgroup-bpf was enabled though since the rewrite [::] -> [::1] happened before passing control to cgroup-bpf block where fl6.daddr was updated with passed by user sockaddr_in6.sin6_addr (that might or might not be changed by BPF program). That way if user passed [::] as dst IPv6 it was first rewritten with [::1] by original code from 876c7f41, but then rewritten back with [::] by cgroup-bpf block. It happened even when BPF_CGROUP_UDP6_SENDMSG program was not present (CONFIG_CGROUP_BPF=y was enough). The fix is to apply BSD'ism after cgroup-bpf block so that [::] is replaced with [::1] no matter where it came from: passed by user to sys_sendmsg or set by BPF_CGROUP_UDP6_SENDMSG program. Fixes: 1cedee13d25a ("bpf: Hooks for sys_sendmsg") Reported-by: Nitin Rawat Signed-off-by: Andrey Ignatov Signed-off-by: Alexei Starovoitov --- net/ipv6/udp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 9cbf363172bd..7c3505006f8e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1390,10 +1390,7 @@ do_udp_sendmsg: ipc6.opt = opt; fl6.flowi6_proto = sk->sk_protocol; - if (!ipv6_addr_any(daddr)) - fl6.daddr = *daddr; - else - fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ + fl6.daddr = *daddr; if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) fl6.saddr = np->saddr; fl6.fl6_sport = inet->inet_sport; @@ -1421,6 +1418,9 @@ do_udp_sendmsg: } } + if (ipv6_addr_any(&fl6.daddr)) + fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ + final_p = fl6_update_dst(&fl6, opt, &final); if (final_p) connected = false; -- cgit v1.2.3-58-ga151 From 976b4f3a4646fbf0d189caca25f91f82e4be4b5a Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 4 Jan 2019 01:07:08 -0800 Subject: selftests/bpf: Test [::] -> [::1] rewrite in sys_sendmsg in test_sock_addr Test that sys_sendmsg BPF hook doesn't break sys_sendmsg behaviour to rewrite destination IPv6 = [::] with [::1] (BSD'ism). Two test cases are added: 1) User passes dst IPv6 = [::] and BPF_CGROUP_UDP6_SENDMSG program doesn't touch it. 2) User passes dst IPv6 != [::], but BPF_CGROUP_UDP6_SENDMSG program rewrites it with [::]. In both cases [::1] is used by sys_sendmsg code eventually and datagram is sent successfully for unconnected UDP socket. Example of relevant output: Test case: sendmsg6: set dst IP = [::] (BSD'ism) .. [PASS] Test case: sendmsg6: preserve dst IP = [::] (BSD'ism) .. [PASS] Signed-off-by: Andrey Ignatov Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_sock_addr.c | 53 ++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c index 73b7493d4120..d94336cbd8bd 100644 --- a/tools/testing/selftests/bpf/test_sock_addr.c +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -44,6 +44,7 @@ #define SERV6_V4MAPPED_IP "::ffff:192.168.0.4" #define SRC6_IP "::1" #define SRC6_REWRITE_IP "::6" +#define WILDCARD6_IP "::" #define SERV6_PORT 6060 #define SERV6_REWRITE_PORT 6666 @@ -85,12 +86,14 @@ static int bind4_prog_load(const struct sock_addr_test *test); static int bind6_prog_load(const struct sock_addr_test *test); static int connect4_prog_load(const struct sock_addr_test *test); static int connect6_prog_load(const struct sock_addr_test *test); +static int sendmsg_allow_prog_load(const struct sock_addr_test *test); static int sendmsg_deny_prog_load(const struct sock_addr_test *test); static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test); static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test); static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test); static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test); static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test); +static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test); static struct sock_addr_test tests[] = { /* bind */ @@ -462,6 +465,34 @@ static struct sock_addr_test tests[] = { SRC6_REWRITE_IP, SYSCALL_ENOTSUPP, }, + { + "sendmsg6: set dst IP = [::] (BSD'ism)", + sendmsg6_rw_wildcard_prog_load, + BPF_CGROUP_UDP6_SENDMSG, + BPF_CGROUP_UDP6_SENDMSG, + AF_INET6, + SOCK_DGRAM, + SERV6_IP, + SERV6_PORT, + SERV6_REWRITE_IP, + SERV6_REWRITE_PORT, + SRC6_REWRITE_IP, + SUCCESS, + }, + { + "sendmsg6: preserve dst IP = [::] (BSD'ism)", + sendmsg_allow_prog_load, + BPF_CGROUP_UDP6_SENDMSG, + BPF_CGROUP_UDP6_SENDMSG, + AF_INET6, + SOCK_DGRAM, + WILDCARD6_IP, + SERV6_PORT, + SERV6_REWRITE_IP, + SERV6_PORT, + SRC6_IP, + SUCCESS, + }, { "sendmsg6: deny call", sendmsg_deny_prog_load, @@ -734,16 +765,27 @@ static int connect6_prog_load(const struct sock_addr_test *test) return load_path(test, CONNECT6_PROG_PATH); } -static int sendmsg_deny_prog_load(const struct sock_addr_test *test) +static int sendmsg_ret_only_prog_load(const struct sock_addr_test *test, + int32_t rc) { struct bpf_insn insns[] = { - /* return 0 */ - BPF_MOV64_IMM(BPF_REG_0, 0), + /* return rc */ + BPF_MOV64_IMM(BPF_REG_0, rc), BPF_EXIT_INSN(), }; return load_insns(test, insns, sizeof(insns) / sizeof(struct bpf_insn)); } +static int sendmsg_allow_prog_load(const struct sock_addr_test *test) +{ + return sendmsg_ret_only_prog_load(test, /*rc*/ 1); +} + +static int sendmsg_deny_prog_load(const struct sock_addr_test *test) +{ + return sendmsg_ret_only_prog_load(test, /*rc*/ 0); +} + static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test) { struct sockaddr_in dst4_rw_addr; @@ -864,6 +906,11 @@ static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test) return sendmsg6_rw_dst_asm_prog_load(test, SERV6_V4MAPPED_IP); } +static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test) +{ + return sendmsg6_rw_dst_asm_prog_load(test, WILDCARD6_IP); +} + static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test) { return load_path(test, SENDMSG6_PROG_PATH); -- cgit v1.2.3-58-ga151 From d4a7e9bb74b5aaf07b89f6531c080b1130bdf019 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sat, 5 Jan 2019 07:35:04 -0800 Subject: ipv6: Take rcu_read_lock in __inet6_bind for mapped addresses I realized the last patch calls dev_get_by_index_rcu in a branch not holding the rcu lock. Add the calls to rcu_read_lock and rcu_read_unlock. Fixes: ec90ad334986 ("ipv6: Consider sk_bound_dev_if when binding a socket to a v4 mapped address") Signed-off-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 93288b9f1697..d99753b5e39b 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -321,17 +321,20 @@ static int __inet6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len, goto out; } + rcu_read_lock(); if (sk->sk_bound_dev_if) { dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; - goto out; + goto out_unlock; } } /* Reproduce AF_INET checks to make the bindings consistent */ v4addr = addr->sin6_addr.s6_addr32[3]; chk_addr_ret = inet_addr_type_dev_table(net, dev, v4addr); + rcu_read_unlock(); + if (!inet_can_nonlocal_bind(net, inet) && v4addr != htonl(INADDR_ANY) && chk_addr_ret != RTN_LOCAL && -- cgit v1.2.3-58-ga151 From d3bd7413e0ca40b60cf60d4003246d067cafdeda Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sun, 6 Jan 2019 00:54:37 +0100 Subject: bpf: fix sanitation of alu op with pointer / scalar type from different paths While 979d63d50c0c ("bpf: prevent out of bounds speculation on pointer arithmetic") took care of rejecting alu op on pointer when e.g. pointer came from two different map values with different map properties such as value size, Jann reported that a case was not covered yet when a given alu op is used in both "ptr_reg += reg" and "numeric_reg += reg" from different branches where we would incorrectly try to sanitize based on the pointer's limit. Catch this corner case and reject the program instead. Fixes: 979d63d50c0c ("bpf: prevent out of bounds speculation on pointer arithmetic") Reported-by: Jann Horn Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 1 + kernel/bpf/verifier.c | 61 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 27b74947cd2b..573cca00a0e6 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -172,6 +172,7 @@ struct bpf_verifier_state_list { #define BPF_ALU_SANITIZE_SRC 1U #define BPF_ALU_SANITIZE_DST 2U #define BPF_ALU_NEG_VALUE (1U << 2) +#define BPF_ALU_NON_POINTER (1U << 3) #define BPF_ALU_SANITIZE (BPF_ALU_SANITIZE_SRC | \ BPF_ALU_SANITIZE_DST) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f6bc62a9ee8e..56674a7c3778 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3103,6 +3103,40 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg, } } +static bool can_skip_alu_sanitation(const struct bpf_verifier_env *env, + const struct bpf_insn *insn) +{ + return env->allow_ptr_leaks || BPF_SRC(insn->code) == BPF_K; +} + +static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux, + u32 alu_state, u32 alu_limit) +{ + /* If we arrived here from different branches with different + * state or limits to sanitize, then this won't work. + */ + if (aux->alu_state && + (aux->alu_state != alu_state || + aux->alu_limit != alu_limit)) + return -EACCES; + + /* Corresponding fixup done in fixup_bpf_calls(). */ + aux->alu_state = alu_state; + aux->alu_limit = alu_limit; + return 0; +} + +static int sanitize_val_alu(struct bpf_verifier_env *env, + struct bpf_insn *insn) +{ + struct bpf_insn_aux_data *aux = cur_aux(env); + + if (can_skip_alu_sanitation(env, insn)) + return 0; + + return update_alu_sanitation_state(aux, BPF_ALU_NON_POINTER, 0); +} + static int sanitize_ptr_alu(struct bpf_verifier_env *env, struct bpf_insn *insn, const struct bpf_reg_state *ptr_reg, @@ -3117,7 +3151,7 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env, struct bpf_reg_state tmp; bool ret; - if (env->allow_ptr_leaks || BPF_SRC(insn->code) == BPF_K) + if (can_skip_alu_sanitation(env, insn)) return 0; /* We already marked aux for masking from non-speculative @@ -3133,19 +3167,8 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env, if (retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg)) return 0; - - /* If we arrived here from different branches with different - * limits to sanitize, then this won't work. - */ - if (aux->alu_state && - (aux->alu_state != alu_state || - aux->alu_limit != alu_limit)) + if (update_alu_sanitation_state(aux, alu_state, alu_limit)) return -EACCES; - - /* Corresponding fixup done in fixup_bpf_calls(). */ - aux->alu_state = alu_state; - aux->alu_limit = alu_limit; - do_sim: /* Simulate and find potential out-of-bounds access under * speculative execution from truncation as a result of @@ -3418,6 +3441,8 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, s64 smin_val, smax_val; u64 umin_val, umax_val; u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32; + u32 dst = insn->dst_reg; + int ret; if (insn_bitness == 32) { /* Relevant for 32-bit RSH: Information can propagate towards @@ -3452,6 +3477,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, switch (opcode) { case BPF_ADD: + ret = sanitize_val_alu(env, insn); + if (ret < 0) { + verbose(env, "R%d tried to add from different pointers or scalars\n", dst); + return ret; + } if (signed_add_overflows(dst_reg->smin_value, smin_val) || signed_add_overflows(dst_reg->smax_value, smax_val)) { dst_reg->smin_value = S64_MIN; @@ -3471,6 +3501,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off); break; case BPF_SUB: + ret = sanitize_val_alu(env, insn); + if (ret < 0) { + verbose(env, "R%d tried to sub from different pointers or scalars\n", dst); + return ret; + } if (signed_sub_overflows(dst_reg->smin_value, smax_val) || signed_sub_overflows(dst_reg->smax_value, smin_val)) { /* Overflow possible, we know nothing */ -- cgit v1.2.3-58-ga151 From 1cbbcfbbd56efd994d643428c69467fe3c8ab672 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sun, 6 Jan 2019 00:54:38 +0100 Subject: bpf: add various test cases for alu op on mixed dst register types Add couple of test_verifier tests to check sanitation of alu op insn with pointer and scalar type coming from different paths. This also includes BPF insns of the test reproducer provided by Jann Horn. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 120 ++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 10d44446e801..2fd90d456892 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -6933,6 +6933,126 @@ static struct bpf_test tests[] = { .result = ACCEPT, .retval = 1, }, + { + "map access: mixing value pointer and scalar, 1", + .insns = { + // load map value pointer into r0 and r2 + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_LD_MAP_FD(BPF_REG_ARG1, 0), + BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG2, -16), + BPF_ST_MEM(BPF_DW, BPF_REG_FP, -16, 0), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + // load some number from the map into r1 + BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + // depending on r1, branch: + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 3), + // branch A + BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), + BPF_MOV64_IMM(BPF_REG_3, 0), + BPF_JMP_A(2), + // branch B + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_MOV64_IMM(BPF_REG_3, 0x100000), + // common instruction + BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3), + // depending on r1, branch: + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), + // branch A + BPF_JMP_A(4), + // branch B + BPF_MOV64_IMM(BPF_REG_0, 0x13371337), + // verifier follows fall-through + BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 0x100000, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + // fake-dead code; targeted from branch A to + // prevent dead code sanitization + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map_array_48b = { 1 }, + .result = ACCEPT, + .result_unpriv = REJECT, + .errstr_unpriv = "R2 tried to add from different pointers or scalars", + .retval = 0, + }, + { + "map access: mixing value pointer and scalar, 2", + .insns = { + // load map value pointer into r0 and r2 + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_LD_MAP_FD(BPF_REG_ARG1, 0), + BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG2, -16), + BPF_ST_MEM(BPF_DW, BPF_REG_FP, -16, 0), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + // load some number from the map into r1 + BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + // depending on r1, branch: + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3), + // branch A + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_MOV64_IMM(BPF_REG_3, 0x100000), + BPF_JMP_A(2), + // branch B + BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), + BPF_MOV64_IMM(BPF_REG_3, 0), + // common instruction + BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3), + // depending on r1, branch: + BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, 1), + // branch A + BPF_JMP_A(4), + // branch B + BPF_MOV64_IMM(BPF_REG_0, 0x13371337), + // verifier follows fall-through + BPF_JMP_IMM(BPF_JNE, BPF_REG_2, 0x100000, 2), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + // fake-dead code; targeted from branch A to + // prevent dead code sanitization + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .fixup_map_array_48b = { 1 }, + .result = ACCEPT, + .result_unpriv = REJECT, + .errstr_unpriv = "R2 tried to add from different maps or paths", + .retval = 0, + }, + { + "sanitation: alu with different scalars", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_LD_MAP_FD(BPF_REG_ARG1, 0), + BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_FP), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG2, -16), + BPF_ST_MEM(BPF_DW, BPF_REG_FP, -16, 0), + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_MOV64_IMM(BPF_REG_3, 0x100000), + BPF_JMP_A(2), + BPF_MOV64_IMM(BPF_REG_2, 42), + BPF_MOV64_IMM(BPF_REG_3, 0x100001), + BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_3), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_EXIT_INSN(), + }, + .fixup_map_array_48b = { 1 }, + .result = ACCEPT, + .retval = 0x100000, + }, { "map access: value_ptr += known scalar, upper oob arith, test 1", .insns = { -- cgit v1.2.3-58-ga151 From 373282e7ab6840cd583a223fa90628f2d8293c26 Mon Sep 17 00:00:00 2001 From: John Pittman Date: Fri, 4 Jan 2019 12:06:37 -0500 Subject: null_blk: add zoned config support information If the kernel is built without CONFIG_BLK_DEV_ZONED, a modprobe of the null_blk driver with zoned=1 fails with 'Invalid argument'. This can be confusing to users, prompting a search as to why the parameter is invalid. To assist in that search, add a bit more information to the failure, additionally adding to the documentation that CONFIG_BLK_DEV_ZONED is needed for zoned=1. Reviewed-by: Bart Van Assche Signed-off-by: John Pittman Added null_blk prefix to error message. Signed-off-by: Jens Axboe --- Documentation/block/null_blk.txt | 3 ++- drivers/block/null_blk.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/block/null_blk.txt b/Documentation/block/null_blk.txt index ea2dafe49ae8..4cad1024fff7 100644 --- a/Documentation/block/null_blk.txt +++ b/Documentation/block/null_blk.txt @@ -88,7 +88,8 @@ shared_tags=[0/1]: Default: 0 zoned=[0/1]: Default: 0 0: Block device is exposed as a random-access block device. - 1: Block device is exposed as a host-managed zoned block device. + 1: Block device is exposed as a host-managed zoned block device. Requires + CONFIG_BLK_DEV_ZONED. zone_size=[MB]: Default: 256 Per zone size when exposed as a zoned block device. Must be a power of two. diff --git a/drivers/block/null_blk.h b/drivers/block/null_blk.h index b3df2793e7cd..34b22d6523ba 100644 --- a/drivers/block/null_blk.h +++ b/drivers/block/null_blk.h @@ -97,6 +97,7 @@ void null_zone_reset(struct nullb_cmd *cmd, sector_t sector); #else static inline int null_zone_init(struct nullb_device *dev) { + pr_err("null_blk: CONFIG_BLK_DEV_ZONED not enabled\n"); return -EINVAL; } static inline void null_zone_exit(struct nullb_device *dev) {} -- cgit v1.2.3-58-ga151 From 3bd6e94bec122a951d462c239b47954cf5f36e33 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 7 Jan 2019 11:08:08 +0900 Subject: arch: restore generic-y += shmparam.h for some architectures For some reasons, I accidentally got rid of "generic-y += shmparam.h" from some architectures. Restore them to fix building c6x, h8300, hexagon, m68k, microblaze, openrisc, and unicore32. Fixes: d6e4b3e326d8 ("arch: remove redundant UAPI generic-y defines") Signed-off-by: Masahiro Yamada Signed-off-by: Linus Torvalds --- arch/c6x/include/uapi/asm/Kbuild | 1 + arch/h8300/include/uapi/asm/Kbuild | 1 + arch/hexagon/include/uapi/asm/Kbuild | 1 + arch/m68k/include/uapi/asm/Kbuild | 1 + arch/microblaze/include/uapi/asm/Kbuild | 1 + arch/openrisc/include/uapi/asm/Kbuild | 1 + arch/unicore32/include/uapi/asm/Kbuild | 1 + 7 files changed, 7 insertions(+) diff --git a/arch/c6x/include/uapi/asm/Kbuild b/arch/c6x/include/uapi/asm/Kbuild index 0febf1a07c30..6c6f6301012e 100644 --- a/arch/c6x/include/uapi/asm/Kbuild +++ b/arch/c6x/include/uapi/asm/Kbuild @@ -1,4 +1,5 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += kvm_para.h +generic-y += shmparam.h generic-y += ucontext.h diff --git a/arch/h8300/include/uapi/asm/Kbuild b/arch/h8300/include/uapi/asm/Kbuild index 0febf1a07c30..6c6f6301012e 100644 --- a/arch/h8300/include/uapi/asm/Kbuild +++ b/arch/h8300/include/uapi/asm/Kbuild @@ -1,4 +1,5 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += kvm_para.h +generic-y += shmparam.h generic-y += ucontext.h diff --git a/arch/hexagon/include/uapi/asm/Kbuild b/arch/hexagon/include/uapi/asm/Kbuild index c1b06dcf6cf8..61d955c1747a 100644 --- a/arch/hexagon/include/uapi/asm/Kbuild +++ b/arch/hexagon/include/uapi/asm/Kbuild @@ -1,3 +1,4 @@ include include/uapi/asm-generic/Kbuild.asm +generic-y += shmparam.h generic-y += ucontext.h diff --git a/arch/m68k/include/uapi/asm/Kbuild b/arch/m68k/include/uapi/asm/Kbuild index 960bf1e4be53..b8b3525271fa 100644 --- a/arch/m68k/include/uapi/asm/Kbuild +++ b/arch/m68k/include/uapi/asm/Kbuild @@ -2,3 +2,4 @@ include include/uapi/asm-generic/Kbuild.asm generated-y += unistd_32.h generic-y += kvm_para.h +generic-y += shmparam.h diff --git a/arch/microblaze/include/uapi/asm/Kbuild b/arch/microblaze/include/uapi/asm/Kbuild index 97823ec46e97..28823e3db825 100644 --- a/arch/microblaze/include/uapi/asm/Kbuild +++ b/arch/microblaze/include/uapi/asm/Kbuild @@ -2,4 +2,5 @@ include include/uapi/asm-generic/Kbuild.asm generated-y += unistd_32.h generic-y += kvm_para.h +generic-y += shmparam.h generic-y += ucontext.h diff --git a/arch/openrisc/include/uapi/asm/Kbuild b/arch/openrisc/include/uapi/asm/Kbuild index 0febf1a07c30..6c6f6301012e 100644 --- a/arch/openrisc/include/uapi/asm/Kbuild +++ b/arch/openrisc/include/uapi/asm/Kbuild @@ -1,4 +1,5 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += kvm_para.h +generic-y += shmparam.h generic-y += ucontext.h diff --git a/arch/unicore32/include/uapi/asm/Kbuild b/arch/unicore32/include/uapi/asm/Kbuild index 0febf1a07c30..6c6f6301012e 100644 --- a/arch/unicore32/include/uapi/asm/Kbuild +++ b/arch/unicore32/include/uapi/asm/Kbuild @@ -1,4 +1,5 @@ include include/uapi/asm-generic/Kbuild.asm generic-y += kvm_para.h +generic-y += shmparam.h generic-y += ucontext.h -- cgit v1.2.3-58-ga151 From 490fd30f859572ac97a51faa31860869744ba97b Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 17 Dec 2018 17:37:25 -0500 Subject: XArray tests: Add RCU locking 0day picked up that I'd forgotten to add locking to this new test. Signed-off-by: Matthew Wilcox --- lib/test_xarray.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/test_xarray.c b/lib/test_xarray.c index 4676c0a1eeca..a885afde0aef 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -839,6 +839,7 @@ static noinline void check_find_3(struct xarray *xa) for (i = 0; i < 100; i++) { for (j = 0; j < 100; j++) { + rcu_read_lock(); for (k = 0; k < 100; k++) { xas_set(&xas, j); xas_for_each_marked(&xas, entry, k, XA_MARK_0) @@ -847,6 +848,7 @@ static noinline void check_find_3(struct xarray *xa) XA_BUG_ON(xa, xas.xa_node != XAS_RESTART); } + rcu_read_unlock(); } xa_store_index(xa, i, GFP_KERNEL); xa_set_mark(xa, i, XA_MARK_0); -- cgit v1.2.3-58-ga151 From 02669b17a433c242a40f01f14b691c9c9d1f8a13 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 5 Dec 2018 16:37:03 -0500 Subject: XArray: Turn xa_init_flags into a static inline A regular xa_init_flags() put all dynamically-initialised XArrays into the same locking class. That leads to lockdep believing that taking one XArray lock while holding another is a deadlock. It's possible to work around some of these situations with separate locking classes for irq/bh/regular XArrays, and SINGLE_DEPTH_NESTING, but that's ugly, and it doesn't work for all situations (where we have completely unrelated XArrays). Signed-off-by: Matthew Wilcox --- include/linux/xarray.h | 19 ++++++++++++++++++- lib/xarray.c | 29 ----------------------------- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/include/linux/xarray.h b/include/linux/xarray.h index f492e21c4aa2..4cf3cd128689 100644 --- a/include/linux/xarray.h +++ b/include/linux/xarray.h @@ -286,7 +286,6 @@ struct xarray { */ #define DEFINE_XARRAY_ALLOC(name) DEFINE_XARRAY_FLAGS(name, XA_FLAGS_ALLOC) -void xa_init_flags(struct xarray *, gfp_t flags); void *xa_load(struct xarray *, unsigned long index); void *xa_store(struct xarray *, unsigned long index, void *entry, gfp_t); void *xa_erase(struct xarray *, unsigned long index); @@ -303,6 +302,24 @@ unsigned int xa_extract(struct xarray *, void **dst, unsigned long start, unsigned long max, unsigned int n, xa_mark_t); void xa_destroy(struct xarray *); +/** + * xa_init_flags() - Initialise an empty XArray with flags. + * @xa: XArray. + * @flags: XA_FLAG values. + * + * If you need to initialise an XArray with special flags (eg you need + * to take the lock from interrupt context), use this function instead + * of xa_init(). + * + * Context: Any context. + */ +static inline void xa_init_flags(struct xarray *xa, gfp_t flags) +{ + spin_lock_init(&xa->xa_lock); + xa->xa_flags = flags; + xa->xa_head = NULL; +} + /** * xa_init() - Initialise an empty XArray. * @xa: XArray. diff --git a/lib/xarray.c b/lib/xarray.c index 5f3f9311de89..dda6026d202e 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -1250,35 +1250,6 @@ void *xas_find_conflict(struct xa_state *xas) } EXPORT_SYMBOL_GPL(xas_find_conflict); -/** - * xa_init_flags() - Initialise an empty XArray with flags. - * @xa: XArray. - * @flags: XA_FLAG values. - * - * If you need to initialise an XArray with special flags (eg you need - * to take the lock from interrupt context), use this function instead - * of xa_init(). - * - * Context: Any context. - */ -void xa_init_flags(struct xarray *xa, gfp_t flags) -{ - unsigned int lock_type; - static struct lock_class_key xa_lock_irq; - static struct lock_class_key xa_lock_bh; - - spin_lock_init(&xa->xa_lock); - xa->xa_flags = flags; - xa->xa_head = NULL; - - lock_type = xa_lock_type(xa); - if (lock_type == XA_LOCK_IRQ) - lockdep_set_class(&xa->xa_lock, &xa_lock_irq); - else if (lock_type == XA_LOCK_BH) - lockdep_set_class(&xa->xa_lock, &xa_lock_bh); -} -EXPORT_SYMBOL(xa_init_flags); - /** * xa_load() - Load an entry from an XArray. * @xa: XArray. -- cgit v1.2.3-58-ga151 From 4a31896c5b5a2715ecf4033426aa0a35066d92d6 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 17 Dec 2018 14:45:36 -0500 Subject: XArray: Change xa_for_each iterator There were three problems with this API: 1. It took too many arguments; almost all users wanted to iterate over every element in the array rather than a subset. 2. It required that 'index' be initialised before use, and there's no realistic way to make GCC catch that. 3. 'index' and 'entry' were the opposite way round from every other member of the XArray APIs. So split it into three different APIs: xa_for_each(xa, index, entry) xa_for_each_start(xa, index, entry, start) xa_for_each_marked(xa, index, entry, filter) Signed-off-by: Matthew Wilcox --- include/linux/xarray.h | 78 +++++++++++++++++++++++++++++++++++++++++--------- lib/test_xarray.c | 11 ++++--- 2 files changed, 70 insertions(+), 19 deletions(-) diff --git a/include/linux/xarray.h b/include/linux/xarray.h index 4cf3cd128689..3d0ce8b267e3 100644 --- a/include/linux/xarray.h +++ b/include/linux/xarray.h @@ -359,20 +359,45 @@ static inline bool xa_marked(const struct xarray *xa, xa_mark_t mark) } /** - * xa_for_each() - Iterate over a portion of an XArray. + * xa_for_each_start() - Iterate over a portion of an XArray. * @xa: XArray. + * @index: Index of @entry. * @entry: Entry retrieved from array. + * @start: First index to retrieve from array. + * + * During the iteration, @entry will have the value of the entry stored + * in @xa at @index. You may modify @index during the iteration if you + * want to skip or reprocess indices. It is safe to modify the array + * during the iteration. At the end of the iteration, @entry will be set + * to NULL and @index will have a value less than or equal to max. + * + * xa_for_each_start() is O(n.log(n)) while xas_for_each() is O(n). You have + * to handle your own locking with xas_for_each(), and if you have to unlock + * after each iteration, it will also end up being O(n.log(n)). + * xa_for_each_start() will spin if it hits a retry entry; if you intend to + * see retry entries, you should use the xas_for_each() iterator instead. + * The xas_for_each() iterator will expand into more inline code than + * xa_for_each_start(). + * + * Context: Any context. Takes and releases the RCU lock. + */ +#define xa_for_each_start(xa, index, entry, start) \ + for (index = start, \ + entry = xa_find(xa, &index, ULONG_MAX, XA_PRESENT); \ + entry; \ + entry = xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT)) + +/** + * xa_for_each() - Iterate over present entries in an XArray. + * @xa: XArray. * @index: Index of @entry. - * @max: Maximum index to retrieve from array. - * @filter: Selection criterion. + * @entry: Entry retrieved from array. * - * Initialise @index to the lowest index you want to retrieve from the - * array. During the iteration, @entry will have the value of the entry - * stored in @xa at @index. The iteration will skip all entries in the - * array which do not match @filter. You may modify @index during the - * iteration if you want to skip or reprocess indices. It is safe to modify - * the array during the iteration. At the end of the iteration, @entry will - * be set to NULL and @index will have a value less than or equal to max. + * During the iteration, @entry will have the value of the entry stored + * in @xa at @index. You may modify @index during the iteration if you want + * to skip or reprocess indices. It is safe to modify the array during the + * iteration. At the end of the iteration, @entry will be set to NULL and + * @index will have a value less than or equal to max. * * xa_for_each() is O(n.log(n)) while xas_for_each() is O(n). You have * to handle your own locking with xas_for_each(), and if you have to unlock @@ -383,9 +408,36 @@ static inline bool xa_marked(const struct xarray *xa, xa_mark_t mark) * * Context: Any context. Takes and releases the RCU lock. */ -#define xa_for_each(xa, entry, index, max, filter) \ - for (entry = xa_find(xa, &index, max, filter); entry; \ - entry = xa_find_after(xa, &index, max, filter)) +#define xa_for_each(xa, index, entry) \ + xa_for_each_start(xa, index, entry, 0) + +/** + * xa_for_each_marked() - Iterate over marked entries in an XArray. + * @xa: XArray. + * @index: Index of @entry. + * @entry: Entry retrieved from array. + * @filter: Selection criterion. + * + * During the iteration, @entry will have the value of the entry stored + * in @xa at @index. The iteration will skip all entries in the array + * which do not match @filter. You may modify @index during the iteration + * if you want to skip or reprocess indices. It is safe to modify the array + * during the iteration. At the end of the iteration, @entry will be set to + * NULL and @index will have a value less than or equal to max. + * + * xa_for_each_marked() is O(n.log(n)) while xas_for_each_marked() is O(n). + * You have to handle your own locking with xas_for_each(), and if you have + * to unlock after each iteration, it will also end up being O(n.log(n)). + * xa_for_each_marked() will spin if it hits a retry entry; if you intend to + * see retry entries, you should use the xas_for_each_marked() iterator + * instead. The xas_for_each_marked() iterator will expand into more inline + * code than xa_for_each_marked(). + * + * Context: Any context. Takes and releases the RCU lock. + */ +#define xa_for_each_marked(xa, index, entry, filter) \ + for (index = 0, entry = xa_find(xa, &index, ULONG_MAX, filter); \ + entry; entry = xa_find_after(xa, &index, ULONG_MAX, filter)) #define xa_trylock(xa) spin_trylock(&(xa)->xa_lock) #define xa_lock(xa) spin_lock(&(xa)->xa_lock) diff --git a/lib/test_xarray.c b/lib/test_xarray.c index a885afde0aef..dc02eff562b8 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -357,7 +357,7 @@ static noinline void check_cmpxchg(struct xarray *xa) static noinline void check_reserve(struct xarray *xa) { void *entry; - unsigned long index = 0; + unsigned long index; /* An array with a reserved entry is not empty */ XA_BUG_ON(xa, !xa_empty(xa)); @@ -393,7 +393,7 @@ static noinline void check_reserve(struct xarray *xa) xa_reserve(xa, 6, GFP_KERNEL); xa_store_index(xa, 7, GFP_KERNEL); - xa_for_each(xa, entry, index, ULONG_MAX, XA_PRESENT) { + xa_for_each(xa, index, entry) { XA_BUG_ON(xa, index != 5 && index != 7); } xa_destroy(xa); @@ -812,17 +812,16 @@ static noinline void check_find_1(struct xarray *xa) static noinline void check_find_2(struct xarray *xa) { void *entry; - unsigned long i, j, index = 0; + unsigned long i, j, index; - xa_for_each(xa, entry, index, ULONG_MAX, XA_PRESENT) { + xa_for_each(xa, index, entry) { XA_BUG_ON(xa, true); } for (i = 0; i < 1024; i++) { xa_store_index(xa, index, GFP_KERNEL); j = 0; - index = 0; - xa_for_each(xa, entry, index, ULONG_MAX, XA_PRESENT) { + xa_for_each(xa, index, entry) { XA_BUG_ON(xa, xa_mk_index(index) != entry); XA_BUG_ON(xa, index != j++); } -- cgit v1.2.3-58-ga151 From 76b4e52995654af260f14558e0e07b5b039ae202 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 28 Dec 2018 23:20:44 -0500 Subject: XArray: Permit storing 2-byte-aligned pointers On m68k, statically allocated pointers may only be two-byte aligned. This clashes with the XArray's method for tagging internal pointers. Permit storing these pointers in single slots (ie not in multislots). Signed-off-by: Matthew Wilcox --- include/linux/xarray.h | 18 +++++++++++++++--- lib/test_xarray.c | 30 ++++++++++++++++++++++++++++++ lib/xarray.c | 22 +++++++++++++--------- 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/include/linux/xarray.h b/include/linux/xarray.h index 3d0ce8b267e3..435c25b29079 100644 --- a/include/linux/xarray.h +++ b/include/linux/xarray.h @@ -176,7 +176,8 @@ static inline bool xa_is_internal(const void *entry) */ static inline bool xa_is_err(const void *entry) { - return unlikely(xa_is_internal(entry)); + return unlikely(xa_is_internal(entry) && + (unsigned long)entry >= -((MAX_ERRNO << 2) + 2)); } /** @@ -1039,8 +1040,8 @@ static inline bool xa_is_sibling(const void *entry) (entry < xa_mk_sibling(XA_CHUNK_SIZE - 1)); } -#define XA_ZERO_ENTRY xa_mk_internal(256) -#define XA_RETRY_ENTRY xa_mk_internal(257) +#define XA_RETRY_ENTRY xa_mk_internal(256) +#define XA_ZERO_ENTRY xa_mk_internal(257) /** * xa_is_zero() - Is the entry a zero entry? @@ -1064,6 +1065,17 @@ static inline bool xa_is_retry(const void *entry) return unlikely(entry == XA_RETRY_ENTRY); } +/** + * xa_is_advanced() - Is the entry only permitted for the advanced API? + * @entry: Entry to be stored in the XArray. + * + * Return: %true if the entry cannot be stored by the normal API. + */ +static inline bool xa_is_advanced(const void *entry) +{ + return xa_is_internal(entry) && (entry <= XA_RETRY_ENTRY); +} + /** * typedef xa_update_node_t - A callback function from the XArray. * @node: The node which is being processed diff --git a/lib/test_xarray.c b/lib/test_xarray.c index dc02eff562b8..6e0212a60b08 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -1184,6 +1184,35 @@ static noinline void check_store_range(struct xarray *xa) } } +static void check_align_1(struct xarray *xa, char *name) +{ + int i; + unsigned int id; + unsigned long index; + void *entry; + + for (i = 0; i < 8; i++) { + id = 0; + XA_BUG_ON(xa, xa_alloc(xa, &id, UINT_MAX, name + i, GFP_KERNEL) + != 0); + XA_BUG_ON(xa, id != i); + } + xa_for_each(xa, index, entry) + XA_BUG_ON(xa, xa_is_err(entry)); + xa_destroy(xa); +} + +static noinline void check_align(struct xarray *xa) +{ + char name[] = "Motorola 68000"; + + check_align_1(xa, name); + check_align_1(xa, name + 1); + check_align_1(xa, name + 2); + check_align_1(xa, name + 3); +// check_align_2(xa, name); +} + static LIST_HEAD(shadow_nodes); static void test_update_node(struct xa_node *node) @@ -1333,6 +1362,7 @@ static int xarray_checks(void) check_create_range(&array); check_store_range(&array); check_store_iter(&array); + check_align(&xa0); check_workingset(&array, 0); check_workingset(&array, 64); diff --git a/lib/xarray.c b/lib/xarray.c index dda6026d202e..bffa26b1f0d6 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -232,6 +232,8 @@ void *xas_load(struct xa_state *xas) if (xas->xa_shift > node->shift) break; entry = xas_descend(xas, node); + if (node->shift == 0) + break; } return entry; } @@ -506,7 +508,7 @@ static void xas_free_nodes(struct xa_state *xas, struct xa_node *top) for (;;) { void *entry = xa_entry_locked(xas->xa, node, offset); - if (xa_is_node(entry)) { + if (node->shift && xa_is_node(entry)) { node = xa_to_node(entry); offset = 0; continue; @@ -604,6 +606,7 @@ static int xas_expand(struct xa_state *xas, void *head) /* * xas_create() - Create a slot to store an entry in. * @xas: XArray operation state. + * @allow_root: %true if we can store the entry in the root directly * * Most users will not need to call this function directly, as it is called * by xas_store(). It is useful for doing conditional store operations @@ -613,7 +616,7 @@ static int xas_expand(struct xa_state *xas, void *head) * If the slot was newly created, returns %NULL. If it failed to create the * slot, returns %NULL and indicates the error in @xas. */ -static void *xas_create(struct xa_state *xas) +static void *xas_create(struct xa_state *xas, bool allow_root) { struct xarray *xa = xas->xa; void *entry; @@ -628,6 +631,8 @@ static void *xas_create(struct xa_state *xas) shift = xas_expand(xas, entry); if (shift < 0) return NULL; + if (!shift && !allow_root) + shift = XA_CHUNK_SHIFT; entry = xa_head_locked(xa); slot = &xa->xa_head; } else if (xas_error(xas)) { @@ -687,7 +692,7 @@ void xas_create_range(struct xa_state *xas) xas->xa_sibs = 0; for (;;) { - xas_create(xas); + xas_create(xas, true); if (xas_error(xas)) goto restore; if (xas->xa_index <= (index | XA_CHUNK_MASK)) @@ -754,7 +759,7 @@ void *xas_store(struct xa_state *xas, void *entry) bool value = xa_is_value(entry); if (entry) - first = xas_create(xas); + first = xas_create(xas, !xa_is_node(entry)); else first = xas_load(xas); @@ -1279,7 +1284,6 @@ static void *xas_result(struct xa_state *xas, void *curr) { if (xa_is_zero(curr)) return NULL; - XA_NODE_BUG_ON(xas->xa_node, xa_is_internal(curr)); if (xas_error(xas)) curr = xas->xa_node; return curr; @@ -1349,7 +1353,7 @@ void *__xa_store(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) XA_STATE(xas, xa, index); void *curr; - if (WARN_ON_ONCE(xa_is_internal(entry))) + if (WARN_ON_ONCE(xa_is_advanced(entry))) return XA_ERROR(-EINVAL); if (xa_track_free(xa) && !entry) entry = XA_ZERO_ENTRY; @@ -1415,7 +1419,7 @@ void *__xa_cmpxchg(struct xarray *xa, unsigned long index, XA_STATE(xas, xa, index); void *curr; - if (WARN_ON_ONCE(xa_is_internal(entry))) + if (WARN_ON_ONCE(xa_is_advanced(entry))) return XA_ERROR(-EINVAL); if (xa_track_free(xa) && !entry) entry = XA_ZERO_ENTRY; @@ -1538,7 +1542,7 @@ void *xa_store_range(struct xarray *xa, unsigned long first, if (last + 1) order = __ffs(last + 1); xas_set_order(&xas, last, order); - xas_create(&xas); + xas_create(&xas, true); if (xas_error(&xas)) goto unlock; } @@ -1580,7 +1584,7 @@ int __xa_alloc(struct xarray *xa, u32 *id, u32 max, void *entry, gfp_t gfp) XA_STATE(xas, xa, 0); int err; - if (WARN_ON_ONCE(xa_is_internal(entry))) + if (WARN_ON_ONCE(xa_is_advanced(entry))) return -EINVAL; if (WARN_ON_ONCE(!xa_track_free(xa))) return -EINVAL; -- cgit v1.2.3-58-ga151 From b0606fed6eece16a421034eca0bbea9a08b90e91 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 2 Jan 2019 13:57:03 -0500 Subject: XArray: Honour reserved entries in xa_insert xa_insert() should treat reserved entries as occupied, not as available. Also, it should treat requests to insert a NULL pointer as a request to reserve the slot. Add xa_insert_bh() and xa_insert_irq() for completeness. Signed-off-by: Matthew Wilcox --- Documentation/core-api/xarray.rst | 15 +++--- include/linux/xarray.h | 110 ++++++++++++++++++++++++-------------- lib/test_xarray.c | 8 +-- lib/xarray.c | 41 ++++++++++++++ 4 files changed, 126 insertions(+), 48 deletions(-) diff --git a/Documentation/core-api/xarray.rst b/Documentation/core-api/xarray.rst index 6a6d67acaf69..5d54b27c6eba 100644 --- a/Documentation/core-api/xarray.rst +++ b/Documentation/core-api/xarray.rst @@ -108,12 +108,13 @@ some, but not all of the other indices changing. Sometimes you need to ensure that a subsequent call to :c:func:`xa_store` will not need to allocate memory. The :c:func:`xa_reserve` function -will store a reserved entry at the indicated index. Users of the normal -API will see this entry as containing ``NULL``. If you do not need to -use the reserved entry, you can call :c:func:`xa_release` to remove the -unused entry. If another user has stored to the entry in the meantime, -:c:func:`xa_release` will do nothing; if instead you want the entry to -become ``NULL``, you should use :c:func:`xa_erase`. +will store a reserved entry at the indicated index. Users of the +normal API will see this entry as containing ``NULL``. If you do +not need to use the reserved entry, you can call :c:func:`xa_release` +to remove the unused entry. If another user has stored to the entry +in the meantime, :c:func:`xa_release` will do nothing; if instead you +want the entry to become ``NULL``, you should use :c:func:`xa_erase`. +Using :c:func:`xa_insert` on a reserved entry will fail. If all entries in the array are ``NULL``, the :c:func:`xa_empty` function will return ``true``. @@ -183,6 +184,8 @@ Takes xa_lock internally: * :c:func:`xa_store_bh` * :c:func:`xa_store_irq` * :c:func:`xa_insert` + * :c:func:`xa_insert_bh` + * :c:func:`xa_insert_irq` * :c:func:`xa_erase` * :c:func:`xa_erase_bh` * :c:func:`xa_erase_irq` diff --git a/include/linux/xarray.h b/include/linux/xarray.h index 435c25b29079..12244aa98a69 100644 --- a/include/linux/xarray.h +++ b/include/linux/xarray.h @@ -463,39 +463,12 @@ void *__xa_erase(struct xarray *, unsigned long index); void *__xa_store(struct xarray *, unsigned long index, void *entry, gfp_t); void *__xa_cmpxchg(struct xarray *, unsigned long index, void *old, void *entry, gfp_t); +int __xa_insert(struct xarray *, unsigned long index, void *entry, gfp_t); int __xa_alloc(struct xarray *, u32 *id, u32 max, void *entry, gfp_t); int __xa_reserve(struct xarray *, unsigned long index, gfp_t); void __xa_set_mark(struct xarray *, unsigned long index, xa_mark_t); void __xa_clear_mark(struct xarray *, unsigned long index, xa_mark_t); -/** - * __xa_insert() - Store this entry in the XArray unless another entry is - * already present. - * @xa: XArray. - * @index: Index into array. - * @entry: New entry. - * @gfp: Memory allocation flags. - * - * If you would rather see the existing entry in the array, use __xa_cmpxchg(). - * This function is for users who don't care what the entry is, only that - * one is present. - * - * Context: Any context. Expects xa_lock to be held on entry. May - * release and reacquire xa_lock if the @gfp flags permit. - * Return: 0 if the store succeeded. -EEXIST if another entry was present. - * -ENOMEM if memory could not be allocated. - */ -static inline int __xa_insert(struct xarray *xa, unsigned long index, - void *entry, gfp_t gfp) -{ - void *curr = __xa_cmpxchg(xa, index, NULL, entry, gfp); - if (!curr) - return 0; - if (xa_is_err(curr)) - return xa_err(curr); - return -EEXIST; -} - /** * xa_store_bh() - Store this entry in the XArray. * @xa: XArray. @@ -685,24 +658,83 @@ static inline void *xa_cmpxchg_irq(struct xarray *xa, unsigned long index, * @entry: New entry. * @gfp: Memory allocation flags. * - * If you would rather see the existing entry in the array, use xa_cmpxchg(). - * This function is for users who don't care what the entry is, only that - * one is present. + * Inserting a NULL entry will store a reserved entry (like xa_reserve()) + * if no entry is present. Inserting will fail if a reserved entry is + * present, even though loading from this index will return NULL. * - * Context: Process context. Takes and releases the xa_lock. - * May sleep if the @gfp flags permit. + * Context: Any context. Takes and releases the xa_lock. May sleep if + * the @gfp flags permit. * Return: 0 if the store succeeded. -EEXIST if another entry was present. * -ENOMEM if memory could not be allocated. */ static inline int xa_insert(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) { - void *curr = xa_cmpxchg(xa, index, NULL, entry, gfp); - if (!curr) - return 0; - if (xa_is_err(curr)) - return xa_err(curr); - return -EEXIST; + int err; + + xa_lock(xa); + err = __xa_insert(xa, index, entry, gfp); + xa_unlock(xa); + + return err; +} + +/** + * xa_insert_bh() - Store this entry in the XArray unless another entry is + * already present. + * @xa: XArray. + * @index: Index into array. + * @entry: New entry. + * @gfp: Memory allocation flags. + * + * Inserting a NULL entry will store a reserved entry (like xa_reserve()) + * if no entry is present. Inserting will fail if a reserved entry is + * present, even though loading from this index will return NULL. + * + * Context: Any context. Takes and releases the xa_lock while + * disabling softirqs. May sleep if the @gfp flags permit. + * Return: 0 if the store succeeded. -EEXIST if another entry was present. + * -ENOMEM if memory could not be allocated. + */ +static inline int xa_insert_bh(struct xarray *xa, unsigned long index, + void *entry, gfp_t gfp) +{ + int err; + + xa_lock_bh(xa); + err = __xa_insert(xa, index, entry, gfp); + xa_unlock_bh(xa); + + return err; +} + +/** + * xa_insert_irq() - Store this entry in the XArray unless another entry is + * already present. + * @xa: XArray. + * @index: Index into array. + * @entry: New entry. + * @gfp: Memory allocation flags. + * + * Inserting a NULL entry will store a reserved entry (like xa_reserve()) + * if no entry is present. Inserting will fail if a reserved entry is + * present, even though loading from this index will return NULL. + * + * Context: Process context. Takes and releases the xa_lock while + * disabling interrupts. May sleep if the @gfp flags permit. + * Return: 0 if the store succeeded. -EEXIST if another entry was present. + * -ENOMEM if memory could not be allocated. + */ +static inline int xa_insert_irq(struct xarray *xa, unsigned long index, + void *entry, gfp_t gfp) +{ + int err; + + xa_lock_irq(xa); + err = __xa_insert(xa, index, entry, gfp); + xa_unlock_irq(xa); + + return err; } /** diff --git a/lib/test_xarray.c b/lib/test_xarray.c index 6e0212a60b08..3cf17338b0a4 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -382,10 +382,12 @@ static noinline void check_reserve(struct xarray *xa) xa_erase_index(xa, 12345678); XA_BUG_ON(xa, !xa_empty(xa)); - /* And so does xa_insert */ + /* But xa_insert does not */ xa_reserve(xa, 12345678, GFP_KERNEL); - XA_BUG_ON(xa, xa_insert(xa, 12345678, xa_mk_value(12345678), 0) != 0); - xa_erase_index(xa, 12345678); + XA_BUG_ON(xa, xa_insert(xa, 12345678, xa_mk_value(12345678), 0) != + -EEXIST); + XA_BUG_ON(xa, xa_empty(xa)); + XA_BUG_ON(xa, xa_erase(xa, 12345678) != NULL); XA_BUG_ON(xa, !xa_empty(xa)); /* Can iterate through a reserved entry */ diff --git a/lib/xarray.c b/lib/xarray.c index bffa26b1f0d6..81c3171ddde9 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -1439,6 +1439,47 @@ void *__xa_cmpxchg(struct xarray *xa, unsigned long index, } EXPORT_SYMBOL(__xa_cmpxchg); +/** + * __xa_insert() - Store this entry in the XArray if no entry is present. + * @xa: XArray. + * @index: Index into array. + * @entry: New entry. + * @gfp: Memory allocation flags. + * + * Inserting a NULL entry will store a reserved entry (like xa_reserve()) + * if no entry is present. Inserting will fail if a reserved entry is + * present, even though loading from this index will return NULL. + * + * Context: Any context. Expects xa_lock to be held on entry. May + * release and reacquire xa_lock if @gfp flags permit. + * Return: 0 if the store succeeded. -EEXIST if another entry was present. + * -ENOMEM if memory could not be allocated. + */ +int __xa_insert(struct xarray *xa, unsigned long index, void *entry, gfp_t gfp) +{ + XA_STATE(xas, xa, index); + void *curr; + + if (WARN_ON_ONCE(xa_is_advanced(entry))) + return -EINVAL; + if (!entry) + entry = XA_ZERO_ENTRY; + + do { + curr = xas_load(&xas); + if (!curr) { + xas_store(&xas, entry); + if (xa_track_free(xa)) + xas_clear_mark(&xas, XA_FREE_MARK); + } else { + xas_set_err(&xas, -EEXIST); + } + } while (__xas_nomem(&xas, gfp)); + + return xas_error(&xas); +} +EXPORT_SYMBOL(__xa_insert); + /** * __xa_reserve() - Reserve this index in the XArray. * @xa: XArray. -- cgit v1.2.3-58-ga151 From 264142bc70ec039e26d8f3b46a717e8037f59ca0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 26 Dec 2018 07:34:31 -0800 Subject: hwmon: (nct6775) Fix chip ID for NCT6798D The chip ID is 0xd42[8-f], not 0xd45[8-f]. Fixes: 0599682b826f ("hwmon: (nct6775) Add support for NCT6798D") Reported-by: Michael Cook Cc: Michael Cook Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6775.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index c3040079b1cb..8f91e366866f 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -44,8 +44,8 @@ * nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3 * nct6797d 14 7 7 2+6 0xd450 0xc1 0x5ca3 * (0xd451) - * nct6798d 14 7 7 2+6 0xd458 0xc1 0x5ca3 - * (0xd459) + * nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3 + * (0xd429) * * #temp lists the number of monitored temperature sources (first value) plus * the number of directly connectable temperature sensors (second value). @@ -138,7 +138,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_NCT6795_ID 0xd350 #define SIO_NCT6796_ID 0xd420 #define SIO_NCT6797_ID 0xd450 -#define SIO_NCT6798_ID 0xd458 +#define SIO_NCT6798_ID 0xd428 #define SIO_ID_MASK 0xFFF8 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; -- cgit v1.2.3-58-ga151 From 9de15c95a63f527c8f7a968cd95e6ec71fc6891d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 26 Dec 2018 13:56:15 -0800 Subject: hwmon: (nct6775) Enable IO mapping for NCT6797D and NCT6798D Similar to other recent chips from Nuvoton, IO mapping may be disabled by default. Enable it when instantiating the driver and after resume. Fixes: 0599682b826f ("hwmon: (nct6775) Add support for NCT6798D") Fixes: e41da286a2fd ("hwmon: (nct6775) Add support for NCT6797D") Reported-by: Michael Cook Cc: Michael Cook Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6775.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 8f91e366866f..4adec4ab7d06 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -4508,7 +4508,8 @@ static int __maybe_unused nct6775_resume(struct device *dev) if (data->kind == nct6791 || data->kind == nct6792 || data->kind == nct6793 || data->kind == nct6795 || - data->kind == nct6796) + data->kind == nct6796 || data->kind == nct6797 || + data->kind == nct6798) nct6791_enable_io_mapping(sioreg); superio_exit(sioreg); @@ -4644,7 +4645,8 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) if (sio_data->kind == nct6791 || sio_data->kind == nct6792 || sio_data->kind == nct6793 || sio_data->kind == nct6795 || - sio_data->kind == nct6796) + sio_data->kind == nct6796 || sio_data->kind == nct6797 || + sio_data->kind == nct6798) nct6791_enable_io_mapping(sioaddr); superio_exit(sioaddr); -- cgit v1.2.3-58-ga151 From 07bd14ccc3049f9c0147a91a4227a571f981601a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 26 Dec 2018 11:28:24 +0000 Subject: hwmon: (lm80) Fix missing unlock on error in set_fan_div() Add the missing unlock before return from function set_fan_div() in the error handling case. Fixes: c9c63915519b ("hwmon: (lm80) fix a missing check of the status of SMBus read") Signed-off-by: Wei Yongjun Signed-off-by: Guenter Roeck --- drivers/hwmon/lm80.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 0e30fa00204c..f9b8e3e23a8e 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -393,8 +393,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, } rv = lm80_read_value(client, LM80_REG_FANDIV); - if (rv < 0) + if (rv < 0) { + mutex_unlock(&data->update_lock); return rv; + } reg = (rv & ~(3 << (2 * (nr + 1)))) | (data->fan_div[nr] << (2 * (nr + 1))); lm80_write_value(client, LM80_REG_FANDIV, reg); -- cgit v1.2.3-58-ga151 From de96e9fea7ba56042f105b6fe163447b280eb800 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 3 Jan 2019 10:23:47 +0100 Subject: sysfs: convert BUG_ON to WARN_ON It's rude to crash the system just because the developer did something wrong, as it prevents them from usually even seeing what went wrong. So convert the few BUG_ON() calls that have snuck into the sysfs code over the years to WARN_ON() to make it more "friendly". All of these are able to be recovered from, so it makes no sense to crash. Reported-by: Linus Torvalds Reviewed-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 3 ++- fs/sysfs/file.c | 6 ++++-- fs/sysfs/group.c | 3 ++- fs/sysfs/symlink.c | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index feeae8081c22..aa85f2874a9f 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -43,7 +43,8 @@ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) kuid_t uid; kgid_t gid; - BUG_ON(!kobj); + if (WARN_ON(!kobj)) + return -EINVAL; if (kobj->parent) parent = kobj->parent->sd; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index bb71db63c99c..51398457fe00 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -325,7 +325,8 @@ int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, kuid_t uid; kgid_t gid; - BUG_ON(!kobj || !kobj->sd || !attr); + if (WARN_ON(!kobj || !kobj->sd || !attr)) + return -EINVAL; kobject_get_ownership(kobj, &uid, &gid); return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, @@ -537,7 +538,8 @@ int sysfs_create_bin_file(struct kobject *kobj, kuid_t uid; kgid_t gid; - BUG_ON(!kobj || !kobj->sd || !attr); + if (WARN_ON(!kobj || !kobj->sd || !attr)) + return -EINVAL; kobject_get_ownership(kobj, &uid, &gid); return sysfs_add_file_mode_ns(kobj->sd, &attr->attr, true, diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 1eb2d6307663..57038604d4a8 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -112,7 +112,8 @@ static int internal_create_group(struct kobject *kobj, int update, kgid_t gid; int error; - BUG_ON(!kobj || (!update && !kobj->sd)); + if (WARN_ON(!kobj || (!update && !kobj->sd))) + return -EINVAL; /* Updates may happen before the object has been instantiated */ if (unlikely(update && !kobj->sd)) diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 215c225b2ca1..c4deecc80f67 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -23,7 +23,8 @@ static int sysfs_do_create_link_sd(struct kernfs_node *parent, { struct kernfs_node *kn, *target = NULL; - BUG_ON(!name || !parent); + if (WARN_ON(!name || !parent)) + return -EINVAL; /* * We don't own @target_kobj and it may be removed at any time. -- cgit v1.2.3-58-ga151 From 862523297778775a0543110dcbf2ca832782f675 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 28 Nov 2018 17:57:56 +0100 Subject: gpiolib-acpi: Remove unnecessary WARN_ON from acpi_gpiochip_free_interrupts acpi_gpiochip_alloc_event only continues allocating an event and adding it to the list if gpiochip_request_own_desc does not return an error. So events with an error desc are never placed on the events list and this check is really not necessary. Suggested-by: Andy Shevchenko Signed-off-by: Hans de Goede Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 48534bda73d3..259cf6ab969b 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -357,8 +357,6 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) mutex_unlock(&acpi_gpio_deferred_req_irqs_lock); list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { - struct gpio_desc *desc; - if (event->irq_requested) { if (event->irq_is_wake) disable_irq_wake(event->irq); @@ -366,11 +364,8 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) free_irq(event->irq, event); } - desc = event->desc; - if (WARN_ON(IS_ERR(desc))) - continue; gpiochip_unlock_as_irq(chip, event->pin); - gpiochip_free_own_desc(desc); + gpiochip_free_own_desc(event->desc); list_del(&event->node); kfree(event); } -- cgit v1.2.3-58-ga151 From 3aa8b8bbc142eeaac89891de584535ceb7fce405 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sun, 30 Dec 2018 14:21:52 +1100 Subject: watchdog: mt7621_wdt/rt2880_wdt: Fix compilation problem These files need #include to compile correctly. Fixes: ac3167257b9f ("headers: separate linux/mod_devicetable.h from linux/platform_device.h") Signed-off-by: NeilBrown Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mt7621_wdt.c | 1 + drivers/watchdog/rt2880_wdt.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c index 5c4a764717c4..81208cd3f4ec 100644 --- a/drivers/watchdog/mt7621_wdt.c +++ b/drivers/watchdog/mt7621_wdt.c @@ -17,6 +17,7 @@ #include #include #include +#include #include diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index 98967f0a7d10..db7c57d82cfd 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c @@ -18,6 +18,7 @@ #include #include #include +#include #include -- cgit v1.2.3-58-ga151 From 4a22fc534f2f55808c41197cf17d829099032acb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Jan 2019 09:47:25 +0300 Subject: watchdog: tqmx86: Fix a couple IS_ERR() vs NULL bugs These functions return NULL on error but we accidentally check for IS_ERR() instead. Fixes: e3c21e088f89 ("watchdog: tqmx86: Add watchdog driver for the IO controller") Signed-off-by: Dan Carpenter Reviewed-by: Andrew Lunn Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/tqmx86_wdt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/tqmx86_wdt.c b/drivers/watchdog/tqmx86_wdt.c index 0d3a0fbbd7a5..52941207a12a 100644 --- a/drivers/watchdog/tqmx86_wdt.c +++ b/drivers/watchdog/tqmx86_wdt.c @@ -79,13 +79,13 @@ static int tqmx86_wdt_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (IS_ERR(res)) - return PTR_ERR(res); + if (!res) + return -ENODEV; priv->io_base = devm_ioport_map(&pdev->dev, res->start, resource_size(res)); - if (IS_ERR(priv->io_base)) - return PTR_ERR(priv->io_base); + if (!priv->io_base) + return -ENOMEM; watchdog_set_drvdata(&priv->wdd, priv); -- cgit v1.2.3-58-ga151 From 605c0351fa36e857e29d34ebab2719d9c04e95f6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 2 Jan 2019 14:02:08 -0600 Subject: MAINTAINERS: Add entry for staging driver r8188eu This entry was missed when the driver was added. Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 32d444476a90..5c7ea0d96dd9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14432,6 +14432,11 @@ M: Florian Schilhabel . S: Odd Fixes F: drivers/staging/rtl8712/ +STAGING - REALTEK RTL8188EU DRIVERS +M: Larry Finger +S: Odd Fixes +F: drivers/staging/rtl8188eu/ + STAGING - SILICON MOTION SM750 FRAME BUFFER DRIVER M: Sudip Mukherjee M: Teddy Wang -- cgit v1.2.3-58-ga151 From 2b531d71595d2b5b12782a49b23c335869e2621e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 4 Jan 2019 23:10:54 +0100 Subject: ACPI / PMIC: xpower: Fix TS-pin current-source handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current-source used for the battery temp-sensor (TS) is shared with the GPADC. For proper fuel-gauge and charger operation the TS current-source needs to be permanently on. But to read the GPADC we need to temporary switch the TS current-source to ondemand, so that the GPADC can use it, otherwise we will always read an all 0 value. The switching from on to on-ondemand is not necessary when the TS current-source is off (this happens on devices which do not have a TS). Prior to this commit there were 2 issues with our handling of the TS current-source switching: 1) We were writing hardcoded values to the ADC TS pin-ctrl register, overwriting various other unrelated bits. Specifically we were overwriting the current-source setting for the TS and GPIO0 pins, forcing it to 80ųA independent of its original setting. On a Chuwi Vi10 tablet this was causing us to get a too high adc value (due to a too high current-source) resulting in acpi_lpat_raw_to_temp() returning -ENOENT, resulting in: ACPI Error: AE_ERROR, Returned by Handler for [UserDefinedRegion] ACPI Error: Method parse/execution failed \_SB.SXP1._TMP, AE_ERROR This commit fixes this by using regmap_update_bits to change only the relevant bits. 2) At the end of intel_xpower_pmic_get_raw_temp() we were unconditionally enabling the TS current-source even on devices where the TS-pin is not used and the current-source thus was off on entry of the function. This commit fixes this by checking if the TS current-source is off when entering intel_xpower_pmic_get_raw_temp() and if so it is left as is. Fixes: 58eefe2f3f53 (ACPI / PMIC: xpower: Do pinswitch ... reading GPADC) Signed-off-by: Hans de Goede Acked-by: Andy Shevchenko Cc: 4.14+ # 4.14+ Signed-off-by: Rafael J. Wysocki --- drivers/acpi/pmic/intel_pmic_xpower.c | 41 ++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index 2579675b7082..e7c0006e6602 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -20,8 +20,11 @@ #define GPI1_LDO_ON (3 << 0) #define GPI1_LDO_OFF (4 << 0) -#define AXP288_ADC_TS_PIN_GPADC 0xf2 -#define AXP288_ADC_TS_PIN_ON 0xf3 +#define AXP288_ADC_TS_CURRENT_ON_OFF_MASK GENMASK(1, 0) +#define AXP288_ADC_TS_CURRENT_OFF (0 << 0) +#define AXP288_ADC_TS_CURRENT_ON_WHEN_CHARGING (1 << 0) +#define AXP288_ADC_TS_CURRENT_ON_ONDEMAND (2 << 0) +#define AXP288_ADC_TS_CURRENT_ON (3 << 0) static struct pmic_table power_table[] = { { @@ -212,22 +215,44 @@ out: */ static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg) { + int ret, adc_ts_pin_ctrl; u8 buf[2]; - int ret; - ret = regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, - AXP288_ADC_TS_PIN_GPADC); + /* + * The current-source used for the battery temp-sensor (TS) is shared + * with the GPADC. For proper fuel-gauge and charger operation the TS + * current-source needs to be permanently on. But to read the GPADC we + * need to temporary switch the TS current-source to ondemand, so that + * the GPADC can use it, otherwise we will always read an all 0 value. + * + * Note that the switching from on to on-ondemand is not necessary + * when the TS current-source is off (this happens on devices which + * do not use the TS-pin). + */ + ret = regmap_read(regmap, AXP288_ADC_TS_PIN_CTRL, &adc_ts_pin_ctrl); if (ret) return ret; - /* After switching to the GPADC pin give things some time to settle */ - usleep_range(6000, 10000); + if (adc_ts_pin_ctrl & AXP288_ADC_TS_CURRENT_ON_OFF_MASK) { + ret = regmap_update_bits(regmap, AXP288_ADC_TS_PIN_CTRL, + AXP288_ADC_TS_CURRENT_ON_OFF_MASK, + AXP288_ADC_TS_CURRENT_ON_ONDEMAND); + if (ret) + return ret; + + /* Wait a bit after switching the current-source */ + usleep_range(6000, 10000); + } ret = regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2); if (ret == 0) ret = (buf[0] << 4) + ((buf[1] >> 4) & 0x0f); - regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON); + if (adc_ts_pin_ctrl & AXP288_ADC_TS_CURRENT_ON_OFF_MASK) { + regmap_update_bits(regmap, AXP288_ADC_TS_PIN_CTRL, + AXP288_ADC_TS_CURRENT_ON_OFF_MASK, + AXP288_ADC_TS_CURRENT_ON); + } return ret; } -- cgit v1.2.3-58-ga151 From 8070ba6348608aa1da15eb83dbaa9ece596aaa67 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 10 Dec 2018 22:00:23 +0100 Subject: ARM: shmobile: fix build regressions A number of Kconfig options have become available now to random ARM platforms outside of ARCH_MULTIPLATFORM, which now causes Kconfig warnings, and other build errors when those select options that lack additional dependencies, e.g.: WARNING: unmet direct dependencies detected for HAVE_ARM_ARCH_TIMER Depends on [n]: CPU_V7 [=n] Selected by [y]: - ARCH_RCAR_GEN2 [=y] && SOC_RENESAS [=y] - ARCH_R8A73A4 [=y] && SOC_RENESAS [=y] && ARM [=y] WARNING: unmet direct dependencies detected for SYS_SUPPORTS_EM_STI Depends on [n]: GENERIC_CLOCKEVENTS [=n] Selected by [y]: - ARCH_EMEV2 [=y] && SOC_RENESAS [=y] && ARM [=y] Put the old dependency on ARCH_RENESAS back for the moment to restore the previous behavior. Fixes: 062887bf5ef7 ("ARM: shmobile: Move SoC Kconfig symbols to drivers/soc/renesas/") Signed-off-by: Arnd Bergmann Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 4d8012e1205c..68bfca6f20dd 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -44,7 +44,7 @@ config ARCH_RZN1 bool select ARM_AMBA -if ARM +if ARM && ARCH_RENESAS #comment "Renesas ARM SoCs System Type" -- cgit v1.2.3-58-ga151 From 19e16fb4f319b84b3220e98abf726218beba8c34 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 2 Jan 2019 15:36:53 +0100 Subject: mtd: Fix the check on nvmem_register() ret code Commit 20167b70c894 ("nvmem: use EOPNOTSUPP instead of ENOSYS") changed the nvmem_register() ret code from ENOSYS to EOPNOTSUPP when CONFIG_NVMEM is not enabled, but the check in mtd_nvmem_add() was not adjusted accordingly. Cc: Bartosz Golaszewski Cc: Alban Bedel Fixes: c4dfa25ab307 ("mtd: add support for reading MTD devices via the nvmem API") Reported-by: kernel test robot Signed-off-by: Boris Brezillon Reviewed-by: Bartosz Golaszewski Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 21e3cdc04036..999b705769a8 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -522,7 +522,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd) mtd->nvmem = nvmem_register(&config); if (IS_ERR(mtd->nvmem)) { /* Just ignore if there is no NVMEM support in the kernel */ - if (PTR_ERR(mtd->nvmem) == -ENOSYS) { + if (PTR_ERR(mtd->nvmem) == -EOPNOTSUPP) { mtd->nvmem = NULL; } else { dev_err(&mtd->dev, "Failed to register NVMEM device\n"); -- cgit v1.2.3-58-ga151 From 2b6f0090a3335b7bdd03ca520c35591159463041 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 2 Jan 2019 15:36:54 +0100 Subject: mtd: Check add_mtd_device() ret code add_mtd_device() can fail. We should always check its return value and gracefully handle the failure case. Fix the call sites where this not done (in mtdpart.c) and add a __must_check attribute to the prototype to avoid this kind of mistakes. Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.h | 2 +- drivers/mtd/mtdpart.c | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h index 9887bda317cd..b31c868019ad 100644 --- a/drivers/mtd/mtdcore.h +++ b/drivers/mtd/mtdcore.h @@ -7,7 +7,7 @@ extern struct mutex mtd_table_mutex; struct mtd_info *__mtd_next_device(int i); -int add_mtd_device(struct mtd_info *mtd); +int __must_check add_mtd_device(struct mtd_info *mtd); int del_mtd_device(struct mtd_info *mtd); int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); int del_mtd_partitions(struct mtd_info *); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index b6af41b04622..60104e1079c5 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -618,10 +618,22 @@ int mtd_add_partition(struct mtd_info *parent, const char *name, list_add(&new->list, &mtd_partitions); mutex_unlock(&mtd_partitions_mutex); - add_mtd_device(&new->mtd); + ret = add_mtd_device(&new->mtd); + if (ret) + goto err_remove_part; mtd_add_partition_attrs(new); + return 0; + +err_remove_part: + mutex_lock(&mtd_partitions_mutex); + list_del(&new->list); + mutex_unlock(&mtd_partitions_mutex); + + free_partition(new); + pr_info("%s:%i\n", __func__, __LINE__); + return ret; } EXPORT_SYMBOL_GPL(mtd_add_partition); @@ -712,22 +724,31 @@ int add_mtd_partitions(struct mtd_info *master, { struct mtd_part *slave; uint64_t cur_offset = 0; - int i; + int i, ret; printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); for (i = 0; i < nbparts; i++) { slave = allocate_partition(master, parts + i, i, cur_offset); if (IS_ERR(slave)) { - del_mtd_partitions(master); - return PTR_ERR(slave); + ret = PTR_ERR(slave); + goto err_del_partitions; } mutex_lock(&mtd_partitions_mutex); list_add(&slave->list, &mtd_partitions); mutex_unlock(&mtd_partitions_mutex); - add_mtd_device(&slave->mtd); + ret = add_mtd_device(&slave->mtd); + if (ret) { + mutex_lock(&mtd_partitions_mutex); + list_del(&slave->list); + mutex_unlock(&mtd_partitions_mutex); + + free_partition(slave); + goto err_del_partitions; + } + mtd_add_partition_attrs(slave); /* Look for subpartitions */ parse_mtd_partitions(&slave->mtd, parts[i].types, NULL); @@ -736,6 +757,11 @@ int add_mtd_partitions(struct mtd_info *master, } return 0; + +err_del_partitions: + del_mtd_partitions(master); + + return ret; } static DEFINE_SPINLOCK(part_parser_lock); -- cgit v1.2.3-58-ga151 From f65e192af35058e5c82da9e90871b472d24912bc Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 3 Jan 2019 10:23:23 -0700 Subject: net/mlx4: Get rid of page operation after dma_alloc_coherent This patch solves a crash at the time of mlx4 driver unload or system shutdown. The crash occurs because dma_alloc_coherent() returns one value in mlx4_alloc_icm_coherent(), but a different value is passed to dma_free_coherent() in mlx4_free_icm_coherent(). In turn this is because when allocated, that pointer is passed to sg_set_buf() to record it, then when freed it is re-calculated by calling lowmem_page_address(sg_page()) which returns a different value. Solve this by recording the value that dma_alloc_coherent() returns, and passing this to dma_free_coherent(). This patch is roughly equivalent to commit 378efe798ecf ("RDMA/hns: Get rid of page operation after dma_alloc_coherent"). Based-on-code-from: Christoph Hellwig Signed-off-by: Stephen Warren Reviewed-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/icm.c | 92 +++++++++++++++++++------------- drivers/net/ethernet/mellanox/mlx4/icm.h | 22 ++++++-- 2 files changed, 75 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c index 4b4351141b94..76b84d08a058 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.c +++ b/drivers/net/ethernet/mellanox/mlx4/icm.c @@ -57,12 +57,12 @@ static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chu int i; if (chunk->nsg > 0) - pci_unmap_sg(dev->persist->pdev, chunk->mem, chunk->npages, + pci_unmap_sg(dev->persist->pdev, chunk->sg, chunk->npages, PCI_DMA_BIDIRECTIONAL); for (i = 0; i < chunk->npages; ++i) - __free_pages(sg_page(&chunk->mem[i]), - get_order(chunk->mem[i].length)); + __free_pages(sg_page(&chunk->sg[i]), + get_order(chunk->sg[i].length)); } static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) @@ -71,9 +71,9 @@ static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk * for (i = 0; i < chunk->npages; ++i) dma_free_coherent(&dev->persist->pdev->dev, - chunk->mem[i].length, - lowmem_page_address(sg_page(&chunk->mem[i])), - sg_dma_address(&chunk->mem[i])); + chunk->buf[i].size, + chunk->buf[i].addr, + chunk->buf[i].dma_addr); } void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent) @@ -111,22 +111,21 @@ static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, return 0; } -static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem, - int order, gfp_t gfp_mask) +static int mlx4_alloc_icm_coherent(struct device *dev, struct mlx4_icm_buf *buf, + int order, gfp_t gfp_mask) { - void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, - &sg_dma_address(mem), gfp_mask); - if (!buf) + buf->addr = dma_alloc_coherent(dev, PAGE_SIZE << order, + &buf->dma_addr, gfp_mask); + if (!buf->addr) return -ENOMEM; - if (offset_in_page(buf)) { - dma_free_coherent(dev, PAGE_SIZE << order, - buf, sg_dma_address(mem)); + if (offset_in_page(buf->addr)) { + dma_free_coherent(dev, PAGE_SIZE << order, buf->addr, + buf->dma_addr); return -ENOMEM; } - sg_set_buf(mem, buf, PAGE_SIZE << order); - sg_dma_len(mem) = PAGE_SIZE << order; + buf->size = PAGE_SIZE << order; return 0; } @@ -159,21 +158,21 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, while (npages > 0) { if (!chunk) { - chunk = kmalloc_node(sizeof(*chunk), + chunk = kzalloc_node(sizeof(*chunk), gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN), dev->numa_node); if (!chunk) { - chunk = kmalloc(sizeof(*chunk), + chunk = kzalloc(sizeof(*chunk), gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); if (!chunk) goto fail; } + chunk->coherent = coherent; - sg_init_table(chunk->mem, MLX4_ICM_CHUNK_LEN); - chunk->npages = 0; - chunk->nsg = 0; + if (!coherent) + sg_init_table(chunk->sg, MLX4_ICM_CHUNK_LEN); list_add_tail(&chunk->list, &icm->chunk_list); } @@ -186,10 +185,10 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, if (coherent) ret = mlx4_alloc_icm_coherent(&dev->persist->pdev->dev, - &chunk->mem[chunk->npages], - cur_order, mask); + &chunk->buf[chunk->npages], + cur_order, mask); else - ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages], + ret = mlx4_alloc_icm_pages(&chunk->sg[chunk->npages], cur_order, mask, dev->numa_node); @@ -205,7 +204,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, if (coherent) ++chunk->nsg; else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { - chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->mem, + chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->sg, chunk->npages, PCI_DMA_BIDIRECTIONAL); @@ -220,7 +219,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, } if (!coherent && chunk) { - chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->mem, + chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->sg, chunk->npages, PCI_DMA_BIDIRECTIONAL); @@ -320,7 +319,7 @@ void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj, u64 idx; struct mlx4_icm_chunk *chunk; struct mlx4_icm *icm; - struct page *page = NULL; + void *addr = NULL; if (!table->lowmem) return NULL; @@ -336,28 +335,49 @@ void *mlx4_table_find(struct mlx4_icm_table *table, u32 obj, list_for_each_entry(chunk, &icm->chunk_list, list) { for (i = 0; i < chunk->npages; ++i) { + dma_addr_t dma_addr; + size_t len; + + if (table->coherent) { + len = chunk->buf[i].size; + dma_addr = chunk->buf[i].dma_addr; + addr = chunk->buf[i].addr; + } else { + struct page *page; + + len = sg_dma_len(&chunk->sg[i]); + dma_addr = sg_dma_address(&chunk->sg[i]); + + /* XXX: we should never do this for highmem + * allocation. This function either needs + * to be split, or the kernel virtual address + * return needs to be made optional. + */ + page = sg_page(&chunk->sg[i]); + addr = lowmem_page_address(page); + } + if (dma_handle && dma_offset >= 0) { - if (sg_dma_len(&chunk->mem[i]) > dma_offset) - *dma_handle = sg_dma_address(&chunk->mem[i]) + - dma_offset; - dma_offset -= sg_dma_len(&chunk->mem[i]); + if (len > dma_offset) + *dma_handle = dma_addr + dma_offset; + dma_offset -= len; } + /* * DMA mapping can merge pages but not split them, * so if we found the page, dma_handle has already * been assigned to. */ - if (chunk->mem[i].length > offset) { - page = sg_page(&chunk->mem[i]); + if (len > offset) goto out; - } - offset -= chunk->mem[i].length; + offset -= len; } } + addr = NULL; out: mutex_unlock(&table->mutex); - return page ? lowmem_page_address(page) + offset : NULL; + return addr ? addr + offset : NULL; } int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.h b/drivers/net/ethernet/mellanox/mlx4/icm.h index c9169a490557..d199874b1c07 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.h +++ b/drivers/net/ethernet/mellanox/mlx4/icm.h @@ -47,11 +47,21 @@ enum { MLX4_ICM_PAGE_SIZE = 1 << MLX4_ICM_PAGE_SHIFT, }; +struct mlx4_icm_buf { + void *addr; + size_t size; + dma_addr_t dma_addr; +}; + struct mlx4_icm_chunk { struct list_head list; int npages; int nsg; - struct scatterlist mem[MLX4_ICM_CHUNK_LEN]; + bool coherent; + union { + struct scatterlist sg[MLX4_ICM_CHUNK_LEN]; + struct mlx4_icm_buf buf[MLX4_ICM_CHUNK_LEN]; + }; }; struct mlx4_icm { @@ -114,12 +124,18 @@ static inline void mlx4_icm_next(struct mlx4_icm_iter *iter) static inline dma_addr_t mlx4_icm_addr(struct mlx4_icm_iter *iter) { - return sg_dma_address(&iter->chunk->mem[iter->page_idx]); + if (iter->chunk->coherent) + return iter->chunk->buf[iter->page_idx].dma_addr; + else + return sg_dma_address(&iter->chunk->sg[iter->page_idx]); } static inline unsigned long mlx4_icm_size(struct mlx4_icm_iter *iter) { - return sg_dma_len(&iter->chunk->mem[iter->page_idx]); + if (iter->chunk->coherent) + return iter->chunk->buf[iter->page_idx].size; + else + return sg_dma_len(&iter->chunk->sg[iter->page_idx]); } int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm); -- cgit v1.2.3-58-ga151 From 01cd364a15f42575ef4aac8f82ff05516ea5da9a Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 3 Jan 2019 10:23:24 -0700 Subject: net/mlx4: replace pci_{,un}map_sg with dma_{,un}map_sg pci_{,un}map_sg are deprecated and replaced by dma_{,un}map_sg. This is especially relevant since the rest of the driver uses the DMA API. Fix the driver to use the replacement APIs. Signed-off-by: Stephen Warren Reviewed-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/icm.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c index 76b84d08a058..d89a3da89e5a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.c +++ b/drivers/net/ethernet/mellanox/mlx4/icm.c @@ -57,8 +57,8 @@ static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chu int i; if (chunk->nsg > 0) - pci_unmap_sg(dev->persist->pdev, chunk->sg, chunk->npages, - PCI_DMA_BIDIRECTIONAL); + dma_unmap_sg(&dev->persist->pdev->dev, chunk->sg, chunk->npages, + DMA_BIDIRECTIONAL); for (i = 0; i < chunk->npages; ++i) __free_pages(sg_page(&chunk->sg[i]), @@ -204,9 +204,9 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, if (coherent) ++chunk->nsg; else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { - chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->sg, - chunk->npages, - PCI_DMA_BIDIRECTIONAL); + chunk->nsg = dma_map_sg(&dev->persist->pdev->dev, + chunk->sg, chunk->npages, + DMA_BIDIRECTIONAL); if (chunk->nsg <= 0) goto fail; @@ -219,9 +219,8 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, } if (!coherent && chunk) { - chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->sg, - chunk->npages, - PCI_DMA_BIDIRECTIONAL); + chunk->nsg = dma_map_sg(&dev->persist->pdev->dev, chunk->sg, + chunk->npages, DMA_BIDIRECTIONAL); if (chunk->nsg <= 0) goto fail; -- cgit v1.2.3-58-ga151 From 0aaa81377c5a01f686bcdb8c7a6929a7bf330c68 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 4 Jan 2019 15:55:26 +0100 Subject: can: gw: ensure DLC boundaries after CAN frame modification Muyu Yu provided a POC where user root with CAP_NET_ADMIN can create a CAN frame modification rule that makes the data length code a higher value than the available CAN frame data size. In combination with a configured checksum calculation where the result is stored relatively to the end of the data (e.g. cgw_csum_xor_rel) the tail of the skb (e.g. frag_list pointer in skb_shared_info) can be rewritten which finally can cause a system crash. Michael Kubecek suggested to drop frames that have a DLC exceeding the available space after the modification process and provided a patch that can handle CAN FD frames too. Within this patch we also limit the length for the checksum calculations to the maximum of Classic CAN data length (8). CAN frames that are dropped by these additional checks are counted with the CGW_DELETED counter which indicates misconfigurations in can-gw rules. This fixes CVE-2019-3701. Reported-by: Muyu Yu Reported-by: Marcus Meissner Suggested-by: Michal Kubecek Tested-by: Muyu Yu Tested-by: Oliver Hartkopp Signed-off-by: Oliver Hartkopp Cc: linux-stable # >= v3.2 Signed-off-by: Marc Kleine-Budde Signed-off-by: David S. Miller --- net/can/gw.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/net/can/gw.c b/net/can/gw.c index faa3da88a127..53859346dc9a 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -416,13 +416,29 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) while (modidx < MAX_MODFUNCTIONS && gwj->mod.modfunc[modidx]) (*gwj->mod.modfunc[modidx++])(cf, &gwj->mod); - /* check for checksum updates when the CAN frame has been modified */ + /* Has the CAN frame been modified? */ if (modidx) { - if (gwj->mod.csumfunc.crc8) + /* get available space for the processed CAN frame type */ + int max_len = nskb->len - offsetof(struct can_frame, data); + + /* dlc may have changed, make sure it fits to the CAN frame */ + if (cf->can_dlc > max_len) + goto out_delete; + + /* check for checksum updates in classic CAN length only */ + if (gwj->mod.csumfunc.crc8) { + if (cf->can_dlc > 8) + goto out_delete; + (*gwj->mod.csumfunc.crc8)(cf, &gwj->mod.csum.crc8); + } + + if (gwj->mod.csumfunc.xor) { + if (cf->can_dlc > 8) + goto out_delete; - if (gwj->mod.csumfunc.xor) (*gwj->mod.csumfunc.xor)(cf, &gwj->mod.csum.xor); + } } /* clear the skb timestamp if not configured the other way */ @@ -434,6 +450,14 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data) gwj->dropped_frames++; else gwj->handled_frames++; + + return; + + out_delete: + /* delete frame due to misconfiguration */ + gwj->deleted_frames++; + kfree_skb(nskb); + return; } static inline int cgw_register_filter(struct net *net, struct cgw_job *gwj) -- cgit v1.2.3-58-ga151 From 0fac32f24ceadad801ef1f4de468f1d5186c808d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 29 Dec 2018 01:05:40 +0100 Subject: i3c: master: Fix an error checking typo in 'cdns_i3c_master_probe()' Fix a cut'n'paste typo. Checking 'master->sysclk' is expected here. Fixes: 603f2bee2c54 ("i3c: master: Add driver for Cadence IP") Signed-off-by: Christophe JAILLET Signed-off-by: Boris Brezillon --- drivers/i3c/master/i3c-master-cdns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index bbd79b8b1a80..8889a4fdb454 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -1556,8 +1556,8 @@ static int cdns_i3c_master_probe(struct platform_device *pdev) return PTR_ERR(master->pclk); master->sysclk = devm_clk_get(&pdev->dev, "sysclk"); - if (IS_ERR(master->pclk)) - return PTR_ERR(master->pclk); + if (IS_ERR(master->sysclk)) + return PTR_ERR(master->sysclk); irq = platform_get_irq(pdev, 0); if (irq < 0) -- cgit v1.2.3-58-ga151 From a64597227d0de5610407fcc95dc835745a53f5d0 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Wed, 12 Dec 2018 12:17:11 +0000 Subject: soc: renesas: r8a774c0-sysc: Fix initialization order of 3DG-{A,B} The workaround for the wrong hierarchy of the 3DG-{A,B} power domains on RZ/G2E ES1.0 corrected the parent domains. However, the 3DG-{A,B} power domains were still initialized and powered in the wrong order, causing 3DG operation to fail. Fix this by changing the order in the table at runtime, when running on an affected SoC. This work is based on the work done by Geert for R-Car E3. Fixes: f37d211c687588328 ("soc: renesas: rcar-sysc: Add r8a774c0 support") Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/r8a774c0-sysc.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/soc/renesas/r8a774c0-sysc.c b/drivers/soc/renesas/r8a774c0-sysc.c index e1ac4c0f6640..11050e17ea81 100644 --- a/drivers/soc/renesas/r8a774c0-sysc.c +++ b/drivers/soc/renesas/r8a774c0-sysc.c @@ -28,19 +28,6 @@ static struct rcar_sysc_area r8a774c0_areas[] __initdata = { { "3dg-b", 0x100, 1, R8A774C0_PD_3DG_B, R8A774C0_PD_3DG_A }, }; -static void __init rcar_sysc_fix_parent(struct rcar_sysc_area *areas, - unsigned int num_areas, u8 id, - int new_parent) -{ - unsigned int i; - - for (i = 0; i < num_areas; i++) - if (areas[i].isr_bit == id) { - areas[i].parent = new_parent; - return; - } -} - /* Fixups for RZ/G2E ES1.0 revision */ static const struct soc_device_attribute r8a774c0[] __initconst = { { .soc_id = "r8a774c0", .revision = "ES1.0" }, @@ -50,12 +37,10 @@ static const struct soc_device_attribute r8a774c0[] __initconst = { static int __init r8a774c0_sysc_init(void) { if (soc_device_match(r8a774c0)) { - rcar_sysc_fix_parent(r8a774c0_areas, - ARRAY_SIZE(r8a774c0_areas), - R8A774C0_PD_3DG_A, R8A774C0_PD_3DG_B); - rcar_sysc_fix_parent(r8a774c0_areas, - ARRAY_SIZE(r8a774c0_areas), - R8A774C0_PD_3DG_B, R8A774C0_PD_ALWAYS_ON); + /* Fix incorrect 3DG hierarchy */ + swap(r8a774c0_areas[6], r8a774c0_areas[7]); + r8a774c0_areas[6].parent = R8A774C0_PD_ALWAYS_ON; + r8a774c0_areas[7].parent = R8A774C0_PD_3DG_B; } return 0; -- cgit v1.2.3-58-ga151 From 8a5aaf97cc4876a9b61cb3b7c07128d4569ac536 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Fri, 4 Jan 2019 11:17:33 +0800 Subject: Documentation/features: Add csky kernel features core/ cBPF-JIT : TODO | core/ eBPF-JIT : TODO | core/ generic-idle-thread : ok | core/ jump-labels : TODO | core/ tracehook : ok | debug/ KASAN : TODO | debug/ gcov-profile-all : TODO | debug/ kgdb : TODO | debug/ kprobes-on-ftrace : TODO | debug/ kprobes : TODO | debug/ kretprobes : TODO | debug/ optprobes : TODO | debug/ stackprotector : TODO | debug/ uprobes : TODO | debug/ user-ret-profiler : TODO | io/ dma-contiguous : ok | locking/ cmpxchg-local : TODO | locking/ lockdep : TODO | locking/ queued-rwlocks : ok | locking/ queued-spinlocks : TODO | locking/ rwsem-optimized : TODO | perf/ kprobes-event : TODO | perf/ perf-regs : TODO | perf/ perf-stackdump : TODO | sched/ membarrier-sync-core : TODO | sched/ numa-balancing : .. | seccomp/ seccomp-filter : TODO | time/ arch-tick-broadcast : TODO | time/ clockevents : ok | time/ context-tracking : TODO | time/ irq-time-acct : TODO | time/ modern-timekeeping : ok | time/ virt-cpuacct : TODO | vm/ ELF-ASLR : TODO | vm/ PG_uncached : TODO | vm/ THP : .. | vm/ batch-unmap-tlb-flush: TODO | vm/ huge-vmap : TODO | vm/ ioremap_prot : TODO | vm/ numa-memblock : .. | vm/ pte_special : TODO | Signed-off-by: Guo Ren Cc: Arnd Bergmann --- Documentation/features/core/cBPF-JIT/arch-support.txt | 1 + Documentation/features/core/eBPF-JIT/arch-support.txt | 1 + Documentation/features/core/generic-idle-thread/arch-support.txt | 1 + Documentation/features/core/jump-labels/arch-support.txt | 1 + Documentation/features/core/tracehook/arch-support.txt | 1 + Documentation/features/debug/KASAN/arch-support.txt | 1 + Documentation/features/debug/gcov-profile-all/arch-support.txt | 1 + Documentation/features/debug/kgdb/arch-support.txt | 1 + Documentation/features/debug/kprobes-on-ftrace/arch-support.txt | 1 + Documentation/features/debug/kprobes/arch-support.txt | 1 + Documentation/features/debug/kretprobes/arch-support.txt | 1 + Documentation/features/debug/optprobes/arch-support.txt | 1 + Documentation/features/debug/stackprotector/arch-support.txt | 1 + Documentation/features/debug/uprobes/arch-support.txt | 1 + Documentation/features/debug/user-ret-profiler/arch-support.txt | 1 + Documentation/features/io/dma-contiguous/arch-support.txt | 1 + Documentation/features/locking/cmpxchg-local/arch-support.txt | 1 + Documentation/features/locking/lockdep/arch-support.txt | 1 + Documentation/features/locking/queued-rwlocks/arch-support.txt | 1 + Documentation/features/locking/queued-spinlocks/arch-support.txt | 1 + Documentation/features/locking/rwsem-optimized/arch-support.txt | 1 + Documentation/features/perf/kprobes-event/arch-support.txt | 1 + Documentation/features/perf/perf-regs/arch-support.txt | 1 + Documentation/features/perf/perf-stackdump/arch-support.txt | 1 + Documentation/features/sched/membarrier-sync-core/arch-support.txt | 1 + Documentation/features/sched/numa-balancing/arch-support.txt | 1 + Documentation/features/seccomp/seccomp-filter/arch-support.txt | 1 + Documentation/features/time/arch-tick-broadcast/arch-support.txt | 1 + Documentation/features/time/clockevents/arch-support.txt | 1 + Documentation/features/time/context-tracking/arch-support.txt | 1 + Documentation/features/time/irq-time-acct/arch-support.txt | 1 + Documentation/features/time/modern-timekeeping/arch-support.txt | 1 + Documentation/features/time/virt-cpuacct/arch-support.txt | 1 + Documentation/features/vm/ELF-ASLR/arch-support.txt | 1 + Documentation/features/vm/PG_uncached/arch-support.txt | 1 + Documentation/features/vm/THP/arch-support.txt | 1 + Documentation/features/vm/TLB/arch-support.txt | 1 + Documentation/features/vm/huge-vmap/arch-support.txt | 1 + Documentation/features/vm/ioremap_prot/arch-support.txt | 1 + Documentation/features/vm/numa-memblock/arch-support.txt | 1 + Documentation/features/vm/pte_special/arch-support.txt | 1 + 41 files changed, 41 insertions(+) diff --git a/Documentation/features/core/cBPF-JIT/arch-support.txt b/Documentation/features/core/cBPF-JIT/arch-support.txt index 90459cdde314..8620c38d4db0 100644 --- a/Documentation/features/core/cBPF-JIT/arch-support.txt +++ b/Documentation/features/core/cBPF-JIT/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | TODO | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/core/eBPF-JIT/arch-support.txt b/Documentation/features/core/eBPF-JIT/arch-support.txt index c90a0382fe66..9ae6e8d0d10d 100644 --- a/Documentation/features/core/eBPF-JIT/arch-support.txt +++ b/Documentation/features/core/eBPF-JIT/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/core/generic-idle-thread/arch-support.txt b/Documentation/features/core/generic-idle-thread/arch-support.txt index 0ef6acdb991c..365df2c2ff0b 100644 --- a/Documentation/features/core/generic-idle-thread/arch-support.txt +++ b/Documentation/features/core/generic-idle-thread/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | ok | | h8300: | TODO | | hexagon: | ok | | ia64: | ok | diff --git a/Documentation/features/core/jump-labels/arch-support.txt b/Documentation/features/core/jump-labels/arch-support.txt index 60111395f932..7fc2e243dee9 100644 --- a/Documentation/features/core/jump-labels/arch-support.txt +++ b/Documentation/features/core/jump-labels/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/core/tracehook/arch-support.txt b/Documentation/features/core/tracehook/arch-support.txt index f44c274e40ed..d344b99aae1e 100644 --- a/Documentation/features/core/tracehook/arch-support.txt +++ b/Documentation/features/core/tracehook/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | ok | + | csky: | ok | | h8300: | TODO | | hexagon: | ok | | ia64: | ok | diff --git a/Documentation/features/debug/KASAN/arch-support.txt b/Documentation/features/debug/KASAN/arch-support.txt index 282ecc8ea1da..304dcd461795 100644 --- a/Documentation/features/debug/KASAN/arch-support.txt +++ b/Documentation/features/debug/KASAN/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/debug/gcov-profile-all/arch-support.txt b/Documentation/features/debug/gcov-profile-all/arch-support.txt index 01b2b3004e0a..059d58a549c7 100644 --- a/Documentation/features/debug/gcov-profile-all/arch-support.txt +++ b/Documentation/features/debug/gcov-profile-all/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/debug/kgdb/arch-support.txt b/Documentation/features/debug/kgdb/arch-support.txt index 3b4dff22329f..3e6b8f07d5d0 100644 --- a/Documentation/features/debug/kgdb/arch-support.txt +++ b/Documentation/features/debug/kgdb/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | ok | | hexagon: | ok | | ia64: | TODO | diff --git a/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt index 7e963d0ae646..68f266944d5f 100644 --- a/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt +++ b/Documentation/features/debug/kprobes-on-ftrace/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | TODO | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/debug/kprobes/arch-support.txt b/Documentation/features/debug/kprobes/arch-support.txt index 4ada027faf16..f4e45bd58fea 100644 --- a/Documentation/features/debug/kprobes/arch-support.txt +++ b/Documentation/features/debug/kprobes/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | ok | diff --git a/Documentation/features/debug/kretprobes/arch-support.txt b/Documentation/features/debug/kretprobes/arch-support.txt index 044e13fcca5d..1d5651ef11f8 100644 --- a/Documentation/features/debug/kretprobes/arch-support.txt +++ b/Documentation/features/debug/kretprobes/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | ok | diff --git a/Documentation/features/debug/optprobes/arch-support.txt b/Documentation/features/debug/optprobes/arch-support.txt index dce7669c918f..fb297a88f62c 100644 --- a/Documentation/features/debug/optprobes/arch-support.txt +++ b/Documentation/features/debug/optprobes/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | TODO | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/debug/stackprotector/arch-support.txt b/Documentation/features/debug/stackprotector/arch-support.txt index 954ac1c95553..9999ea521f3e 100644 --- a/Documentation/features/debug/stackprotector/arch-support.txt +++ b/Documentation/features/debug/stackprotector/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/debug/uprobes/arch-support.txt b/Documentation/features/debug/uprobes/arch-support.txt index 1a3f9d3229bf..1c577d0cfc7f 100644 --- a/Documentation/features/debug/uprobes/arch-support.txt +++ b/Documentation/features/debug/uprobes/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/debug/user-ret-profiler/arch-support.txt b/Documentation/features/debug/user-ret-profiler/arch-support.txt index 1d78d1069a5f..6bfa36b0e017 100644 --- a/Documentation/features/debug/user-ret-profiler/arch-support.txt +++ b/Documentation/features/debug/user-ret-profiler/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | TODO | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/io/dma-contiguous/arch-support.txt b/Documentation/features/io/dma-contiguous/arch-support.txt index 30c072d2b67c..eb28b5c97ca6 100644 --- a/Documentation/features/io/dma-contiguous/arch-support.txt +++ b/Documentation/features/io/dma-contiguous/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | ok | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/locking/cmpxchg-local/arch-support.txt b/Documentation/features/locking/cmpxchg-local/arch-support.txt index 51704a2dc8d1..242ff5a6586e 100644 --- a/Documentation/features/locking/cmpxchg-local/arch-support.txt +++ b/Documentation/features/locking/cmpxchg-local/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/locking/lockdep/arch-support.txt b/Documentation/features/locking/lockdep/arch-support.txt index bd39c5edd460..941fd5b1094d 100644 --- a/Documentation/features/locking/lockdep/arch-support.txt +++ b/Documentation/features/locking/lockdep/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | ok | | ia64: | TODO | diff --git a/Documentation/features/locking/queued-rwlocks/arch-support.txt b/Documentation/features/locking/queued-rwlocks/arch-support.txt index da7aff3bee0b..c683da198f31 100644 --- a/Documentation/features/locking/queued-rwlocks/arch-support.txt +++ b/Documentation/features/locking/queued-rwlocks/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | ok | | c6x: | TODO | + | csky: | ok | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/locking/queued-spinlocks/arch-support.txt b/Documentation/features/locking/queued-spinlocks/arch-support.txt index 478e9101322c..e3080b82aefd 100644 --- a/Documentation/features/locking/queued-spinlocks/arch-support.txt +++ b/Documentation/features/locking/queued-spinlocks/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | TODO | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/locking/rwsem-optimized/arch-support.txt b/Documentation/features/locking/rwsem-optimized/arch-support.txt index e54b1f1a8091..7521d7500fbe 100644 --- a/Documentation/features/locking/rwsem-optimized/arch-support.txt +++ b/Documentation/features/locking/rwsem-optimized/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | ok | diff --git a/Documentation/features/perf/kprobes-event/arch-support.txt b/Documentation/features/perf/kprobes-event/arch-support.txt index 7331402d1887..d8278bf62b85 100644 --- a/Documentation/features/perf/kprobes-event/arch-support.txt +++ b/Documentation/features/perf/kprobes-event/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | ok | | ia64: | TODO | diff --git a/Documentation/features/perf/perf-regs/arch-support.txt b/Documentation/features/perf/perf-regs/arch-support.txt index 53feeee6cdad..687d049d9cee 100644 --- a/Documentation/features/perf/perf-regs/arch-support.txt +++ b/Documentation/features/perf/perf-regs/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/perf/perf-stackdump/arch-support.txt b/Documentation/features/perf/perf-stackdump/arch-support.txt index 16164348e0ea..90996e3d18a8 100644 --- a/Documentation/features/perf/perf-stackdump/arch-support.txt +++ b/Documentation/features/perf/perf-stackdump/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/sched/membarrier-sync-core/arch-support.txt b/Documentation/features/sched/membarrier-sync-core/arch-support.txt index c7858dd1ea8f..8a521a622966 100644 --- a/Documentation/features/sched/membarrier-sync-core/arch-support.txt +++ b/Documentation/features/sched/membarrier-sync-core/arch-support.txt @@ -34,6 +34,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/sched/numa-balancing/arch-support.txt b/Documentation/features/sched/numa-balancing/arch-support.txt index c68bb2c2cb62..350823692f28 100644 --- a/Documentation/features/sched/numa-balancing/arch-support.txt +++ b/Documentation/features/sched/numa-balancing/arch-support.txt @@ -11,6 +11,7 @@ | arm: | .. | | arm64: | ok | | c6x: | .. | + | csky: | .. | | h8300: | .. | | hexagon: | .. | | ia64: | TODO | diff --git a/Documentation/features/seccomp/seccomp-filter/arch-support.txt b/Documentation/features/seccomp/seccomp-filter/arch-support.txt index d4271b493b41..4fe6c3c3be5c 100644 --- a/Documentation/features/seccomp/seccomp-filter/arch-support.txt +++ b/Documentation/features/seccomp/seccomp-filter/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/time/arch-tick-broadcast/arch-support.txt b/Documentation/features/time/arch-tick-broadcast/arch-support.txt index 83d9e68462bb..593536f7925b 100644 --- a/Documentation/features/time/arch-tick-broadcast/arch-support.txt +++ b/Documentation/features/time/arch-tick-broadcast/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/time/clockevents/arch-support.txt b/Documentation/features/time/clockevents/arch-support.txt index 3d4908fce6da..7a27157da408 100644 --- a/Documentation/features/time/clockevents/arch-support.txt +++ b/Documentation/features/time/clockevents/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | ok | + | csky: | ok | | h8300: | ok | | hexagon: | ok | | ia64: | TODO | diff --git a/Documentation/features/time/context-tracking/arch-support.txt b/Documentation/features/time/context-tracking/arch-support.txt index c29974afffaa..048bfb6d3872 100644 --- a/Documentation/features/time/context-tracking/arch-support.txt +++ b/Documentation/features/time/context-tracking/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/time/irq-time-acct/arch-support.txt b/Documentation/features/time/irq-time-acct/arch-support.txt index 8d73c463ec27..a14bbad8e948 100644 --- a/Documentation/features/time/irq-time-acct/arch-support.txt +++ b/Documentation/features/time/irq-time-acct/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | .. | diff --git a/Documentation/features/time/modern-timekeeping/arch-support.txt b/Documentation/features/time/modern-timekeeping/arch-support.txt index e7c6ea6b8fb3..2855dfe2464d 100644 --- a/Documentation/features/time/modern-timekeeping/arch-support.txt +++ b/Documentation/features/time/modern-timekeeping/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | ok | | c6x: | ok | + | csky: | ok | | h8300: | ok | | hexagon: | ok | | ia64: | ok | diff --git a/Documentation/features/time/virt-cpuacct/arch-support.txt b/Documentation/features/time/virt-cpuacct/arch-support.txt index 4646457461cf..fb0d0cab9cab 100644 --- a/Documentation/features/time/virt-cpuacct/arch-support.txt +++ b/Documentation/features/time/virt-cpuacct/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | ok | diff --git a/Documentation/features/vm/ELF-ASLR/arch-support.txt b/Documentation/features/vm/ELF-ASLR/arch-support.txt index 1f71d090ff2c..adc25878d217 100644 --- a/Documentation/features/vm/ELF-ASLR/arch-support.txt +++ b/Documentation/features/vm/ELF-ASLR/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/vm/PG_uncached/arch-support.txt b/Documentation/features/vm/PG_uncached/arch-support.txt index fbd5aa463b0a..f05588f9e4b4 100644 --- a/Documentation/features/vm/PG_uncached/arch-support.txt +++ b/Documentation/features/vm/PG_uncached/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | TODO | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | ok | diff --git a/Documentation/features/vm/THP/arch-support.txt b/Documentation/features/vm/THP/arch-support.txt index 5d7ecc378f29..cdfe8925f881 100644 --- a/Documentation/features/vm/THP/arch-support.txt +++ b/Documentation/features/vm/THP/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | .. | + | csky: | .. | | h8300: | .. | | hexagon: | .. | | ia64: | TODO | diff --git a/Documentation/features/vm/TLB/arch-support.txt b/Documentation/features/vm/TLB/arch-support.txt index f7af9678eb66..2bdd3b6cee3c 100644 --- a/Documentation/features/vm/TLB/arch-support.txt +++ b/Documentation/features/vm/TLB/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | TODO | | c6x: | .. | + | csky: | TODO | | h8300: | .. | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/vm/huge-vmap/arch-support.txt b/Documentation/features/vm/huge-vmap/arch-support.txt index d0713ccc7117..019131c5acce 100644 --- a/Documentation/features/vm/huge-vmap/arch-support.txt +++ b/Documentation/features/vm/huge-vmap/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/vm/ioremap_prot/arch-support.txt b/Documentation/features/vm/ioremap_prot/arch-support.txt index 326e4797bc65..3a6b87de6a19 100644 --- a/Documentation/features/vm/ioremap_prot/arch-support.txt +++ b/Documentation/features/vm/ioremap_prot/arch-support.txt @@ -11,6 +11,7 @@ | arm: | TODO | | arm64: | TODO | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | diff --git a/Documentation/features/vm/numa-memblock/arch-support.txt b/Documentation/features/vm/numa-memblock/arch-support.txt index 1a988052cd24..3004beb0fd71 100644 --- a/Documentation/features/vm/numa-memblock/arch-support.txt +++ b/Documentation/features/vm/numa-memblock/arch-support.txt @@ -11,6 +11,7 @@ | arm: | .. | | arm64: | ok | | c6x: | .. | + | csky: | .. | | h8300: | .. | | hexagon: | .. | | ia64: | ok | diff --git a/Documentation/features/vm/pte_special/arch-support.txt b/Documentation/features/vm/pte_special/arch-support.txt index a8378424bc98..2dc5df6a1cf5 100644 --- a/Documentation/features/vm/pte_special/arch-support.txt +++ b/Documentation/features/vm/pte_special/arch-support.txt @@ -11,6 +11,7 @@ | arm: | ok | | arm64: | ok | | c6x: | TODO | + | csky: | TODO | | h8300: | TODO | | hexagon: | TODO | | ia64: | TODO | -- cgit v1.2.3-58-ga151 From 84cad97a717f5749a0236abd5ce68da582ea074f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 2 Jan 2019 20:12:46 -0600 Subject: staging: rtl8188eu: Fix module loading from tasklet for CCMP encryption Commit 6bd082af7e36 ("staging:r8188eu: use lib80211 CCMP decrypt") causes scheduling while atomic bugs followed by a hard freeze whenever the driver tries to connect to a CCMP-encrypted network. Experimentation showed that the freezes were eliminated when module lib80211 was preloaded, which can be forced by calling lib80211_get_crypto_ops() directly rather than indirectly through try_then_request_module(). With this change, no BUG messages are logged. Fixes: 6bd082af7e36 ("staging:r8188eu: use lib80211 CCMP decrypt") Cc: Stable # v4.17+ Reported-and-tested-by: Michael Straube Cc: Ivan Safonov Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_security.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c index 364d6ea14bf8..dbb84e00077f 100644 --- a/drivers/staging/rtl8188eu/core/rtw_security.c +++ b/drivers/staging/rtl8188eu/core/rtw_security.c @@ -1291,7 +1291,7 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) struct sk_buff *skb = ((struct recv_frame *)precvframe)->pkt; void *crypto_private = NULL; u8 *key, *pframe = skb->data; - struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("CCMP"), "lib80211_crypt_ccmp"); + struct lib80211_crypto_ops *crypto_ops = lib80211_get_crypto_ops("CCMP"); struct security_priv *psecuritypriv = &padapter->securitypriv; char iv[8], icv[8]; -- cgit v1.2.3-58-ga151 From 7775665aadc48a562051834a73519129bf717d73 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 2 Jan 2019 20:12:47 -0600 Subject: staging: rtl8188eu: Fix module loading from tasklet for WEP encryption Commit 2b2ea09e74a5 ("staging:r8188eu: Use lib80211 to decrypt WEP-frames") causes scheduling while atomic bugs followed by a hard freeze whenever the driver tries to connect to a WEP-encrypted network. Experimentation showed that the freezes were eliminated when module lib80211 was preloaded, which can be forced by calling lib80211_get_crypto_ops() directly rather than indirectly through try_then_request_module(). With this change, no BUG messages are logged. Fixes: 2b2ea09e74a5 ("staging:r8188eu: Use lib80211 to decrypt WEP-frames") Cc: Stable # v4.17+ Cc: Michael Straube Cc: Ivan Safonov Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_security.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c index dbb84e00077f..2f90f60f1681 100644 --- a/drivers/staging/rtl8188eu/core/rtw_security.c +++ b/drivers/staging/rtl8188eu/core/rtw_security.c @@ -154,7 +154,7 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe) pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; - crypto_ops = try_then_request_module(lib80211_get_crypto_ops("WEP"), "lib80211_crypt_wep"); + crypto_ops = lib80211_get_crypto_ops("WEP"); if (!crypto_ops) return; @@ -210,7 +210,7 @@ int rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe) void *crypto_private = NULL; int status = _SUCCESS; const int keyindex = prxattrib->key_index; - struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("WEP"), "lib80211_crypt_wep"); + struct lib80211_crypto_ops *crypto_ops = lib80211_get_crypto_ops("WEP"); char iv[4], icv[4]; if (!crypto_ops) { -- cgit v1.2.3-58-ga151 From 10262b0b53666cbc506989b17a3ead1e9c3b43b4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 6 Jan 2019 20:44:00 +0100 Subject: r8169: don't try to read counters if chip is in a PCI power-save state Avoid log spam caused by trying to read counters from the chip whilst it is in a PCI power-save state. Reference: https://bugzilla.kernel.org/show_bug.cgi?id=107421 Fixes: 1ef7286e7f36 ("r8169: Dereference MMIO address immediately before use") Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 7fe9180261b8..784ae5001656 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -1681,11 +1681,13 @@ static bool rtl8169_reset_counters(struct rtl8169_private *tp) static bool rtl8169_update_counters(struct rtl8169_private *tp) { + u8 val = RTL_R8(tp, ChipCmd); + /* * Some chips are unable to dump tally counters when the receiver - * is disabled. + * is disabled. If 0xff chip may be in a PCI power-save state. */ - if ((RTL_R8(tp, ChipCmd) & CmdRxEnb) == 0) + if (!(val & CmdRxEnb) || val == 0xff) return true; return rtl8169_do_counters(tp, CounterDump); -- cgit v1.2.3-58-ga151 From eeb2c4fb6a3d0ebed35fbc13a255f691c8b8d7e5 Mon Sep 17 00:00:00 2001 From: Jacob Wen Date: Mon, 7 Jan 2019 09:59:59 +0800 Subject: rds: use DIV_ROUND_UP instead of ceil Yes indeed, DIV_ROUND_UP is in kernel.h. Signed-off-by: Jacob Wen Signed-off-by: David S. Miller --- net/rds/ib_send.c | 4 ++-- net/rds/message.c | 4 ++-- net/rds/rds.h | 4 ---- net/rds/send.c | 2 +- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index 2dcb555e6350..4e0c36acf866 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c @@ -522,7 +522,7 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0) i = 1; else - i = ceil(be32_to_cpu(rm->m_inc.i_hdr.h_len), RDS_FRAG_SIZE); + i = DIV_ROUND_UP(be32_to_cpu(rm->m_inc.i_hdr.h_len), RDS_FRAG_SIZE); work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos); if (work_alloc == 0) { @@ -879,7 +879,7 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op) * Instead of knowing how to return a partial rdma read/write we insist that there * be enough work requests to send the entire message. */ - i = ceil(op->op_count, max_sge); + i = DIV_ROUND_UP(op->op_count, max_sge); work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos); if (work_alloc != i) { diff --git a/net/rds/message.c b/net/rds/message.c index f139420ba1f6..50f13f1d4ae0 100644 --- a/net/rds/message.c +++ b/net/rds/message.c @@ -341,7 +341,7 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in { struct rds_message *rm; unsigned int i; - int num_sgs = ceil(total_len, PAGE_SIZE); + int num_sgs = DIV_ROUND_UP(total_len, PAGE_SIZE); int extra_bytes = num_sgs * sizeof(struct scatterlist); int ret; @@ -351,7 +351,7 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in set_bit(RDS_MSG_PAGEVEC, &rm->m_flags); rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len); - rm->data.op_nents = ceil(total_len, PAGE_SIZE); + rm->data.op_nents = DIV_ROUND_UP(total_len, PAGE_SIZE); rm->data.op_sg = rds_message_alloc_sgs(rm, num_sgs, &ret); if (!rm->data.op_sg) { rds_message_put(rm); diff --git a/net/rds/rds.h b/net/rds/rds.h index 02ec4a3b2799..4ffe100ff5e6 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -48,10 +48,6 @@ void rdsdebug(char *fmt, ...) } #endif -/* XXX is there one of these somewhere? */ -#define ceil(x, y) \ - ({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; }) - #define RDS_FRAG_SHIFT 12 #define RDS_FRAG_SIZE ((unsigned int)(1 << RDS_FRAG_SHIFT)) diff --git a/net/rds/send.c b/net/rds/send.c index 3d822bad7de9..fd8b687d5c05 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -1107,7 +1107,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) size_t total_payload_len = payload_len, rdma_payload_len = 0; bool zcopy = ((msg->msg_flags & MSG_ZEROCOPY) && sock_flag(rds_rs_to_sk(rs), SOCK_ZEROCOPY)); - int num_sgs = ceil(payload_len, PAGE_SIZE); + int num_sgs = DIV_ROUND_UP(payload_len, PAGE_SIZE); int namelen; struct rds_iov_vector_arr vct; int ind; -- cgit v1.2.3-58-ga151 From b81c2c33eab79dfd3650293b2227ee5c6036585c Mon Sep 17 00:00:00 2001 From: Max Schulze Date: Mon, 7 Jan 2019 08:31:49 +0100 Subject: USB: serial: simple: add Motorola Tetra TPG2200 device id Add new Motorola Tetra device id for Motorola Solutions TETRA PEI device T: Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 4 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=0cad ProdID=9016 Rev=24.16 S: Manufacturer=Motorola Solutions, Inc. S: Product=TETRA PEI interface C: #Ifs= 2 Cfg#= 1 Atr=80 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=usb_serial_simple I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=usb_serial_simple Signed-off-by: Max Schulze Cc: stable Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial-simple.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 4d0273508043..edbbb13d6de6 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -85,7 +85,8 @@ DEVICE(moto_modem, MOTO_IDS); /* Motorola Tetra driver */ #define MOTOROLA_TETRA_IDS() \ { USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \ - { USB_DEVICE(0x0cad, 0x9012) } /* MTP6550 */ + { USB_DEVICE(0x0cad, 0x9012) }, /* MTP6550 */ \ + { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); /* Novatel Wireless GPS driver */ -- cgit v1.2.3-58-ga151 From 42f03ab3c75197e8fec2dbd6b50bc699619aab9b Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Wed, 17 Oct 2018 17:05:52 +0300 Subject: ARC: HSDK: improve reset driver As for today HSDK reset driver implements only .reset() callback. In case of driver which implements one of standard reset controller usage pattern (call *_deassert() in probe(), call *_assert() in remove()) that leads to inoperability of this reset driver. Improve HSDK reset driver by calling .reset() callback inside of .deassert() callback to avoid each reset controller user adaptation for work with both reset methods (reset() and {.assert() & .deassert()} pair) Signed-off-by: Eugeniy Paltsev Signed-off-by: Philipp Zabel --- drivers/reset/reset-hsdk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/reset/reset-hsdk.c b/drivers/reset/reset-hsdk.c index 8bce391c6943..4c7b8647b49c 100644 --- a/drivers/reset/reset-hsdk.c +++ b/drivers/reset/reset-hsdk.c @@ -86,6 +86,7 @@ static int hsdk_reset_reset(struct reset_controller_dev *rcdev, static const struct reset_control_ops hsdk_reset_ops = { .reset = hsdk_reset_reset, + .deassert = hsdk_reset_reset, }; static int hsdk_reset_probe(struct platform_device *pdev) -- cgit v1.2.3-58-ga151 From 12c62b9d6ce57d37f3c03cc902c30498909fbc42 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 8 Oct 2018 13:15:43 +0200 Subject: reset: Improve reset controller kernel docs Grammar and indentation fixes. Signed-off-by: Geert Uytterhoeven [p.zabel@pengutronix.de: dropped "shared among" -> "shared between"] Signed-off-by: Philipp Zabel --- include/linux/reset.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/reset.h b/include/linux/reset.h index 29af6d6b2f4b..76690cf2e3e0 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -138,7 +138,7 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id) * * Returns a struct reset_control or IS_ERR() condition containing errno. * This function is intended for use with reset-controls which are shared - * between hardware-blocks. + * between hardware blocks. * * When a reset-control is shared, the behavior of reset_control_assert / * deassert is changed, the reset-core will keep track of a deassert_count @@ -187,7 +187,7 @@ static inline struct reset_control *of_reset_control_get_exclusive( } /** - * of_reset_control_get_shared - Lookup and obtain an shared reference + * of_reset_control_get_shared - Lookup and obtain a shared reference * to a reset controller. * @node: device to be reset by the controller * @id: reset line name @@ -229,7 +229,7 @@ static inline struct reset_control *of_reset_control_get_exclusive_by_index( } /** - * of_reset_control_get_shared_by_index - Lookup and obtain an shared + * of_reset_control_get_shared_by_index - Lookup and obtain a shared * reference to a reset controller * by index. * @node: device to be reset by the controller @@ -322,7 +322,7 @@ devm_reset_control_get_exclusive_by_index(struct device *dev, int index) /** * devm_reset_control_get_shared_by_index - resource managed - * reset_control_get_shared + * reset_control_get_shared * @dev: device to be reset by the controller * @index: index of the reset controller * -- cgit v1.2.3-58-ga151 From eaf91db0ab22dc2c664a9782f2f31dcbc410f3b5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 13 Nov 2018 13:47:44 +0100 Subject: reset: Add reset_control_get_count() Currently the reset core has internal support for counting the number of resets for a device described in DT. Generalize this to devices using lookup resets, and export it for public use. This will be used by generic drivers that need to be sure a device is controlled by a single, dedicated reset line (e.g. vfio-platform). Signed-off-by: Geert Uytterhoeven [p.zabel@pengutronix.de: fixed a typo in reset_control_get_count comment] Signed-off-by: Philipp Zabel --- drivers/reset/core.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/linux/reset.h | 7 +++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index d1887c0ed5d3..bce2d6aefef9 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -795,3 +795,44 @@ devm_reset_control_array_get(struct device *dev, bool shared, bool optional) return rstc; } EXPORT_SYMBOL_GPL(devm_reset_control_array_get); + +static int reset_control_get_count_from_lookup(struct device *dev) +{ + const struct reset_control_lookup *lookup; + const char *dev_id = dev_name(dev); + int count = 0; + + if (!dev) + return -EINVAL; + + mutex_lock(&reset_lookup_mutex); + + list_for_each_entry(lookup, &reset_lookup_list, list) { + if (!strcmp(lookup->dev_id, dev_id)) + count++; + } + + mutex_unlock(&reset_lookup_mutex); + + if (count == 0) + count = -ENOENT; + + return count; +} + +/** + * reset_control_get_count - Count number of resets available with a device + * + * @dev: device for which to return the number of resets + * + * Returns positive reset count on success, or error number on failure and + * on count being zero. + */ +int reset_control_get_count(struct device *dev) +{ + if (dev->of_node) + return of_reset_control_get_count(dev->of_node); + + return reset_control_get_count_from_lookup(dev); +} +EXPORT_SYMBOL_GPL(reset_control_get_count); diff --git a/include/linux/reset.h b/include/linux/reset.h index 76690cf2e3e0..c1901b61ca30 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -32,6 +32,8 @@ struct reset_control *devm_reset_control_array_get(struct device *dev, struct reset_control *of_reset_control_array_get(struct device_node *np, bool shared, bool optional); +int reset_control_get_count(struct device *dev); + #else static inline int reset_control_reset(struct reset_control *rstc) @@ -97,6 +99,11 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional) return optional ? NULL : ERR_PTR(-ENOTSUPP); } +static inline int reset_control_get_count(struct device *dev) +{ + return -ENOENT; +} + #endif /* CONFIG_RESET_CONTROLLER */ static inline int __must_check device_reset(struct device *dev) -- cgit v1.2.3-58-ga151 From 151f72f493f2605ebbed0198362eed05918ed839 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 14 Nov 2018 21:49:35 +0000 Subject: reset: fix null pointer dereference on dev by dev_name The call to dev_name will dereference dev, however, dev is later being null checked, so there is a possibility of a null pointer dereference on dev by the call to dev_name. Fix this by null checking dev first before the call to dev_name Detected by CoverityScan, CID#1475475 ("Dereference before null check") Fixes: 2a6cb2b1d83b ("reset: Add reset_control_get_count()") Signed-off-by: Colin Ian King Signed-off-by: Philipp Zabel --- drivers/reset/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index bce2d6aefef9..9582efb70025 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -799,12 +799,13 @@ EXPORT_SYMBOL_GPL(devm_reset_control_array_get); static int reset_control_get_count_from_lookup(struct device *dev) { const struct reset_control_lookup *lookup; - const char *dev_id = dev_name(dev); + const char *dev_id; int count = 0; if (!dev) return -EINVAL; + dev_id = dev_name(dev); mutex_lock(&reset_lookup_mutex); list_for_each_entry(lookup, &reset_lookup_list, list) { -- cgit v1.2.3-58-ga151 From b3ca9888f35fa6919569cf27c929dc0ac49e9716 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Tue, 13 Nov 2018 12:50:48 -0600 Subject: reset: socfpga: add an early reset driver for SoCFPGA Create a separate reset driver that uses the reset operations in reset-simple. The reset driver for the SoCFPGA platform needs to register early in order to be able bring online timers that needed early in the kernel bootup. We do not need this early reset driver for Stratix10, because on arm64, Linux does not need the timers are that in reset. Linux is able to run just fine with the internal armv8 timer. Thus, we use a new binding "altr,stratix10-rst-mgr" for the Stratix10 platform. The Stratix10 platform will continue to use the reset-simple platform driver, while the 32-bit platforms(Cyclone5/Arria5/Arria10) will use the early reset driver. Signed-off-by: Dinh Nguyen [p.zabel@pengutronix.de: fixed socfpga of_device_id in reset-simple] Signed-off-by: Philipp Zabel --- arch/arm/mach-socfpga/socfpga.c | 4 ++ drivers/reset/Kconfig | 10 ++++- drivers/reset/Makefile | 1 + drivers/reset/reset-simple.c | 13 ++---- drivers/reset/reset-socfpga.c | 88 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 drivers/reset/reset-socfpga.c diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c index 5fb6f79059a8..afd98971d903 100644 --- a/arch/arm/mach-socfpga/socfpga.c +++ b/arch/arm/mach-socfpga/socfpga.c @@ -32,6 +32,8 @@ void __iomem *rst_manager_base_addr; void __iomem *sdr_ctl_base_addr; unsigned long socfpga_cpu1start_addr; +extern void __init socfpga_reset_init(void); + static void __init socfpga_sysmgr_init(void) { struct device_node *np; @@ -64,6 +66,7 @@ static void __init socfpga_init_irq(void) if (IS_ENABLED(CONFIG_EDAC_ALTERA_OCRAM)) socfpga_init_ocram_ecc(); + socfpga_reset_init(); } static void __init socfpga_arria10_init_irq(void) @@ -74,6 +77,7 @@ static void __init socfpga_arria10_init_irq(void) socfpga_init_arria10_l2_ecc(); if (IS_ENABLED(CONFIG_EDAC_ALTERA_OCRAM)) socfpga_init_arria10_ocram_ecc(); + socfpga_reset_init(); } static void socfpga_cyclone5_restart(enum reboot_mode mode, const char *cmd) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index c21da9fe51ec..7ee64988faac 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -109,7 +109,7 @@ config RESET_QCOM_PDC config RESET_SIMPLE bool "Simple Reset Controller Driver" if COMPILE_TEST - default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED + default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED help This enables a simple reset controller driver for reset lines that that can be asserted and deasserted by toggling bits in a contiguous, @@ -128,6 +128,14 @@ config RESET_STM32MP157 help This enables the RCC reset controller driver for STM32 MPUs. +config RESET_SOCFPGA + bool "SoCFPGA Reset Driver" if COMPILE_TEST && !ARCH_SOCFPGA + default ARCH_SOCFPGA + select RESET_SIMPLE + help + This enables the reset driver for the SoCFPGA ARMv7 platforms. This + driver gets initialized early during platform init calls. + config RESET_SUNXI bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI default ARCH_SUNXI diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index d08e8b90046a..b14de32eb610 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o +obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c index a91107fc9e27..77fbba3100c8 100644 --- a/drivers/reset/reset-simple.c +++ b/drivers/reset/reset-simple.c @@ -109,7 +109,7 @@ struct reset_simple_devdata { #define SOCFPGA_NR_BANKS 8 static const struct reset_simple_devdata reset_simple_socfpga = { - .reg_offset = 0x10, + .reg_offset = 0x20, .nr_resets = SOCFPGA_NR_BANKS * 32, .status_active_low = true, }; @@ -120,7 +120,8 @@ static const struct reset_simple_devdata reset_simple_active_low = { }; static const struct of_device_id reset_simple_dt_ids[] = { - { .compatible = "altr,rst-mgr", .data = &reset_simple_socfpga }, + { .compatible = "altr,stratix10-rst-mgr", + .data = &reset_simple_socfpga }, { .compatible = "st,stm32-rcc", }, { .compatible = "allwinner,sun6i-a31-clock-reset", .data = &reset_simple_active_low }, @@ -166,14 +167,6 @@ static int reset_simple_probe(struct platform_device *pdev) data->status_active_low = devdata->status_active_low; } - if (of_device_is_compatible(dev->of_node, "altr,rst-mgr") && - of_property_read_u32(dev->of_node, "altr,modrst-offset", - ®_offset)) { - dev_warn(dev, - "missing altr,modrst-offset property, assuming 0x%x!\n", - reg_offset); - } - data->membase += reg_offset; return devm_reset_controller_register(dev, &data->rcdev); diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c new file mode 100644 index 000000000000..318cfc51c441 --- /dev/null +++ b/drivers/reset/reset-socfpga.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018, Intel Corporation + * Copied from reset-sunxi.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "reset-simple.h" + +#define SOCFPGA_NR_BANKS 8 +void __init socfpga_reset_init(void); + +static int a10_reset_init(struct device_node *np) +{ + struct reset_simple_data *data; + struct resource res; + resource_size_t size; + int ret; + u32 reg_offset = 0x10; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = of_address_to_resource(np, 0, &res); + if (ret) + goto err_alloc; + + size = resource_size(&res); + if (!request_mem_region(res.start, size, np->name)) { + ret = -EBUSY; + goto err_alloc; + } + + data->membase = ioremap(res.start, size); + if (!data->membase) { + ret = -ENOMEM; + goto err_alloc; + } + + if (of_property_read_u32(np, "altr,modrst-offset", ®_offset)) + pr_warn("missing altr,modrst-offset property, assuming 0x10\n"); + data->membase += reg_offset; + + spin_lock_init(&data->lock); + + data->rcdev.owner = THIS_MODULE; + data->rcdev.nr_resets = SOCFPGA_NR_BANKS * 32; + data->rcdev.ops = &reset_simple_ops; + data->rcdev.of_node = np; + data->status_active_low = true; + + return reset_controller_register(&data->rcdev); + +err_alloc: + kfree(data); + return ret; +}; + +/* + * These are the reset controller we need to initialize early on in + * our system, before we can even think of using a regular device + * driver for it. + * The controllers that we can register through the regular device + * model are handled by the simple reset driver directly. + */ +static const struct of_device_id socfpga_early_reset_dt_ids[] __initconst = { + { .compatible = "altr,rst-mgr", }, + { /* sentinel */ }, +}; + +void __init socfpga_reset_init(void) +{ + struct device_node *np; + + for_each_matching_node(np, socfpga_early_reset_dt_ids) + a10_reset_init(np); +} -- cgit v1.2.3-58-ga151 From a277105b239bdcb6490ec51366413643dbc8ed4a Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 5 Nov 2018 14:05:49 -0600 Subject: ARM: socfpga: dts: document "altr,stratix10-rst-mgr" binding "altr,stratix10-rst-mgr" is used for the Stratix10 reset manager. Signed-off-by: Dinh Nguyen Signed-off-by: Philipp Zabel --- Documentation/devicetree/bindings/reset/socfpga-reset.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/reset/socfpga-reset.txt b/Documentation/devicetree/bindings/reset/socfpga-reset.txt index 98c9f560e5c5..38fe34fd8b8a 100644 --- a/Documentation/devicetree/bindings/reset/socfpga-reset.txt +++ b/Documentation/devicetree/bindings/reset/socfpga-reset.txt @@ -1,7 +1,8 @@ Altera SOCFPGA Reset Manager Required properties: -- compatible : "altr,rst-mgr" +- compatible : "altr,rst-mgr" for (Cyclone5/Arria5/Arria10) + "altr,stratix10-rst-mgr","altr,rst-mgr" for Stratix10 ARM64 SoC - reg : Should contain 1 register ranges(address and length) - altr,modrst-offset : Should contain the offset of the first modrst register. - #reset-cells: 1 -- cgit v1.2.3-58-ga151 From 21b22136b4330abd1467e59fbe651ae4d18f0357 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 9 Nov 2018 10:42:04 +0900 Subject: dt-bindings: reset: uniphier: Replace the expression of USB3 with generic peripherals Replace the expression of "USB3 glue layer" with the glue layer of the generic peripherals to allow other devices to use it. The reset control belongs to this glue layer. Signed-off-by: Kunihiko Hayashi Reviewed-by: Rob Herring Signed-off-by: Philipp Zabel --- .../devicetree/bindings/reset/uniphier-reset.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/reset/uniphier-reset.txt b/Documentation/devicetree/bindings/reset/uniphier-reset.txt index 101743dda223..f63c511a9de8 100644 --- a/Documentation/devicetree/bindings/reset/uniphier-reset.txt +++ b/Documentation/devicetree/bindings/reset/uniphier-reset.txt @@ -120,27 +120,27 @@ Example: }; -USB3 core reset ---------------- +Peripheral core reset in glue layer +----------------------------------- -USB3 core reset belongs to USB3 glue layer. Before using the core reset, -it is necessary to control the clocks and resets to enable this layer. -These clocks and resets should be described in each property. +Some peripheral core reset belongs to its own glue layer. Before using +this core reset, it is necessary to control the clocks and resets to enable +this layer. These clocks and resets should be described in each property. Required properties: - compatible: Should be - "socionext,uniphier-pro4-usb3-reset" - for Pro4 SoC - "socionext,uniphier-pxs2-usb3-reset" - for PXs2 SoC - "socionext,uniphier-ld20-usb3-reset" - for LD20 SoC - "socionext,uniphier-pxs3-usb3-reset" - for PXs3 SoC + "socionext,uniphier-pro4-usb3-reset" - for Pro4 SoC USB3 + "socionext,uniphier-pxs2-usb3-reset" - for PXs2 SoC USB3 + "socionext,uniphier-ld20-usb3-reset" - for LD20 SoC USB3 + "socionext,uniphier-pxs3-usb3-reset" - for PXs3 SoC USB3 - #reset-cells: Should be 1. - reg: Specifies offset and length of the register set for the device. -- clocks: A list of phandles to the clock gate for USB3 glue layer. +- clocks: A list of phandles to the clock gate for the glue layer. According to the clock-names, appropriate clocks are required. - clock-names: Should contain "gio", "link" - for Pro4 SoC "link" - for others -- resets: A list of phandles to the reset control for USB3 glue layer. +- resets: A list of phandles to the reset control for the glue layer. According to the reset-names, appropriate resets are required. - reset-names: Should contain "gio", "link" - for Pro4 SoC -- cgit v1.2.3-58-ga151 From 3eb8f765f5aeca6e4195246f41e534025f69eee8 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 9 Nov 2018 10:42:05 +0900 Subject: reset: uniphier-usb3: Rename to reset-uniphier-glue This driver works for controlling the reset lines including USB3 glue layer, however, this can be applied to other glue layers. Now this patch renames the driver from "reset-uniphier-usb3" to "reset-uniphier-glue". At the same time, this changes CONFIG_RESET_UNIPHIER_USB3 to CONFIG_RESET_UNIPHIER_GLUE. Signed-off-by: Kunihiko Hayashi Signed-off-by: Philipp Zabel --- drivers/reset/Kconfig | 10 +-- drivers/reset/Makefile | 2 +- drivers/reset/reset-uniphier-glue.c | 171 ++++++++++++++++++++++++++++++++++++ drivers/reset/reset-uniphier-usb3.c | 171 ------------------------------------ 4 files changed, 177 insertions(+), 177 deletions(-) create mode 100644 drivers/reset/reset-uniphier-glue.c delete mode 100644 drivers/reset/reset-uniphier-usb3.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 7ee64988faac..2e01bd833ffd 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -171,15 +171,15 @@ config RESET_UNIPHIER Say Y if you want to control reset signals provided by System Control block, Media I/O block, Peripheral Block. -config RESET_UNIPHIER_USB3 - tristate "USB3 reset driver for UniPhier SoCs" +config RESET_UNIPHIER_GLUE + tristate "Reset driver in glue layer for UniPhier SoCs" depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF default ARCH_UNIPHIER select RESET_SIMPLE help - Support for the USB3 core reset on UniPhier SoCs. - Say Y if you want to control reset signals provided by - USB3 glue layer. + Support for peripheral core reset included in its own glue layer + on UniPhier SoCs. Say Y if you want to control reset signals + provided by the glue layer. config RESET_ZYNQ bool "ZYNQ Reset Driver" if COMPILE_TEST diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index b14de32eb610..dc7874df78d9 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -24,6 +24,6 @@ obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o -obj-$(CONFIG_RESET_UNIPHIER_USB3) += reset-uniphier-usb3.o +obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o diff --git a/drivers/reset/reset-uniphier-glue.c b/drivers/reset/reset-uniphier-glue.c new file mode 100644 index 000000000000..1b8ea03be9a0 --- /dev/null +++ b/drivers/reset/reset-uniphier-glue.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// reset-uniphier-glue.c - Glue layer reset driver for UniPhier +// Copyright 2018 Socionext Inc. +// Author: Kunihiko Hayashi + +#include +#include +#include +#include +#include + +#include "reset-simple.h" + +#define MAX_CLKS 2 +#define MAX_RSTS 2 + +struct uniphier_glue_reset_soc_data { + int nclks; + const char * const *clock_names; + int nrsts; + const char * const *reset_names; +}; + +struct uniphier_glue_reset_priv { + struct clk_bulk_data clk[MAX_CLKS]; + struct reset_control *rst[MAX_RSTS]; + struct reset_simple_data rdata; + const struct uniphier_glue_reset_soc_data *data; +}; + +static int uniphier_glue_reset_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_glue_reset_priv *priv; + struct resource *res; + resource_size_t size; + const char *name; + int i, ret, nr; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_device_get_match_data(dev); + if (WARN_ON(!priv->data || priv->data->nclks > MAX_CLKS || + priv->data->nrsts > MAX_RSTS)) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + size = resource_size(res); + priv->rdata.membase = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->rdata.membase)) + return PTR_ERR(priv->rdata.membase); + + for (i = 0; i < priv->data->nclks; i++) + priv->clk[i].id = priv->data->clock_names[i]; + ret = devm_clk_bulk_get(dev, priv->data->nclks, priv->clk); + if (ret) + return ret; + + for (i = 0; i < priv->data->nrsts; i++) { + name = priv->data->reset_names[i]; + priv->rst[i] = devm_reset_control_get_shared(dev, name); + if (IS_ERR(priv->rst[i])) + return PTR_ERR(priv->rst[i]); + } + + ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk); + if (ret) + return ret; + + for (nr = 0; nr < priv->data->nrsts; nr++) { + ret = reset_control_deassert(priv->rst[nr]); + if (ret) + goto out_rst_assert; + } + + spin_lock_init(&priv->rdata.lock); + priv->rdata.rcdev.owner = THIS_MODULE; + priv->rdata.rcdev.nr_resets = size * BITS_PER_BYTE; + priv->rdata.rcdev.ops = &reset_simple_ops; + priv->rdata.rcdev.of_node = dev->of_node; + priv->rdata.active_low = true; + + platform_set_drvdata(pdev, priv); + + ret = devm_reset_controller_register(dev, &priv->rdata.rcdev); + if (ret) + goto out_rst_assert; + + return 0; + +out_rst_assert: + while (nr--) + reset_control_assert(priv->rst[nr]); + + clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); + + return ret; +} + +static int uniphier_glue_reset_remove(struct platform_device *pdev) +{ + struct uniphier_glue_reset_priv *priv = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < priv->data->nrsts; i++) + reset_control_assert(priv->rst[i]); + + clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); + + return 0; +} + +static const char * const uniphier_pro4_clock_reset_names[] = { + "gio", "link", +}; + +static const struct uniphier_glue_reset_soc_data uniphier_pro4_data = { + .nclks = ARRAY_SIZE(uniphier_pro4_clock_reset_names), + .clock_names = uniphier_pro4_clock_reset_names, + .nrsts = ARRAY_SIZE(uniphier_pro4_clock_reset_names), + .reset_names = uniphier_pro4_clock_reset_names, +}; + +static const char * const uniphier_pxs2_clock_reset_names[] = { + "link", +}; + +static const struct uniphier_glue_reset_soc_data uniphier_pxs2_data = { + .nclks = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), + .clock_names = uniphier_pxs2_clock_reset_names, + .nrsts = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), + .reset_names = uniphier_pxs2_clock_reset_names, +}; + +static const struct of_device_id uniphier_glue_reset_match[] = { + { + .compatible = "socionext,uniphier-pro4-usb3-reset", + .data = &uniphier_pro4_data, + }, + { + .compatible = "socionext,uniphier-pxs2-usb3-reset", + .data = &uniphier_pxs2_data, + }, + { + .compatible = "socionext,uniphier-ld20-usb3-reset", + .data = &uniphier_pxs2_data, + }, + { + .compatible = "socionext,uniphier-pxs3-usb3-reset", + .data = &uniphier_pxs2_data, + }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_glue_reset_match); + +static struct platform_driver uniphier_glue_reset_driver = { + .probe = uniphier_glue_reset_probe, + .remove = uniphier_glue_reset_remove, + .driver = { + .name = "uniphier-glue-reset", + .of_match_table = uniphier_glue_reset_match, + }, +}; +module_platform_driver(uniphier_glue_reset_driver); + +MODULE_AUTHOR("Kunihiko Hayashi "); +MODULE_DESCRIPTION("UniPhier Glue layer reset driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/reset/reset-uniphier-usb3.c b/drivers/reset/reset-uniphier-usb3.c deleted file mode 100644 index ffa1b19b594d..000000000000 --- a/drivers/reset/reset-uniphier-usb3.c +++ /dev/null @@ -1,171 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// reset-uniphier-usb3.c - USB3 reset driver for UniPhier -// Copyright 2018 Socionext Inc. -// Author: Kunihiko Hayashi - -#include -#include -#include -#include -#include - -#include "reset-simple.h" - -#define MAX_CLKS 2 -#define MAX_RSTS 2 - -struct uniphier_usb3_reset_soc_data { - int nclks; - const char * const *clock_names; - int nrsts; - const char * const *reset_names; -}; - -struct uniphier_usb3_reset_priv { - struct clk_bulk_data clk[MAX_CLKS]; - struct reset_control *rst[MAX_RSTS]; - struct reset_simple_data rdata; - const struct uniphier_usb3_reset_soc_data *data; -}; - -static int uniphier_usb3_reset_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct uniphier_usb3_reset_priv *priv; - struct resource *res; - resource_size_t size; - const char *name; - int i, ret, nr; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->data = of_device_get_match_data(dev); - if (WARN_ON(!priv->data || priv->data->nclks > MAX_CLKS || - priv->data->nrsts > MAX_RSTS)) - return -EINVAL; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - size = resource_size(res); - priv->rdata.membase = devm_ioremap_resource(dev, res); - if (IS_ERR(priv->rdata.membase)) - return PTR_ERR(priv->rdata.membase); - - for (i = 0; i < priv->data->nclks; i++) - priv->clk[i].id = priv->data->clock_names[i]; - ret = devm_clk_bulk_get(dev, priv->data->nclks, priv->clk); - if (ret) - return ret; - - for (i = 0; i < priv->data->nrsts; i++) { - name = priv->data->reset_names[i]; - priv->rst[i] = devm_reset_control_get_shared(dev, name); - if (IS_ERR(priv->rst[i])) - return PTR_ERR(priv->rst[i]); - } - - ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk); - if (ret) - return ret; - - for (nr = 0; nr < priv->data->nrsts; nr++) { - ret = reset_control_deassert(priv->rst[nr]); - if (ret) - goto out_rst_assert; - } - - spin_lock_init(&priv->rdata.lock); - priv->rdata.rcdev.owner = THIS_MODULE; - priv->rdata.rcdev.nr_resets = size * BITS_PER_BYTE; - priv->rdata.rcdev.ops = &reset_simple_ops; - priv->rdata.rcdev.of_node = dev->of_node; - priv->rdata.active_low = true; - - platform_set_drvdata(pdev, priv); - - ret = devm_reset_controller_register(dev, &priv->rdata.rcdev); - if (ret) - goto out_rst_assert; - - return 0; - -out_rst_assert: - while (nr--) - reset_control_assert(priv->rst[nr]); - - clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); - - return ret; -} - -static int uniphier_usb3_reset_remove(struct platform_device *pdev) -{ - struct uniphier_usb3_reset_priv *priv = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < priv->data->nrsts; i++) - reset_control_assert(priv->rst[i]); - - clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); - - return 0; -} - -static const char * const uniphier_pro4_clock_reset_names[] = { - "gio", "link", -}; - -static const struct uniphier_usb3_reset_soc_data uniphier_pro4_data = { - .nclks = ARRAY_SIZE(uniphier_pro4_clock_reset_names), - .clock_names = uniphier_pro4_clock_reset_names, - .nrsts = ARRAY_SIZE(uniphier_pro4_clock_reset_names), - .reset_names = uniphier_pro4_clock_reset_names, -}; - -static const char * const uniphier_pxs2_clock_reset_names[] = { - "link", -}; - -static const struct uniphier_usb3_reset_soc_data uniphier_pxs2_data = { - .nclks = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), - .clock_names = uniphier_pxs2_clock_reset_names, - .nrsts = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), - .reset_names = uniphier_pxs2_clock_reset_names, -}; - -static const struct of_device_id uniphier_usb3_reset_match[] = { - { - .compatible = "socionext,uniphier-pro4-usb3-reset", - .data = &uniphier_pro4_data, - }, - { - .compatible = "socionext,uniphier-pxs2-usb3-reset", - .data = &uniphier_pxs2_data, - }, - { - .compatible = "socionext,uniphier-ld20-usb3-reset", - .data = &uniphier_pxs2_data, - }, - { - .compatible = "socionext,uniphier-pxs3-usb3-reset", - .data = &uniphier_pxs2_data, - }, - { /* Sentinel */ } -}; -MODULE_DEVICE_TABLE(of, uniphier_usb3_reset_match); - -static struct platform_driver uniphier_usb3_reset_driver = { - .probe = uniphier_usb3_reset_probe, - .remove = uniphier_usb3_reset_remove, - .driver = { - .name = "uniphier-usb3-reset", - .of_match_table = uniphier_usb3_reset_match, - }, -}; -module_platform_driver(uniphier_usb3_reset_driver); - -MODULE_AUTHOR("Kunihiko Hayashi "); -MODULE_DESCRIPTION("UniPhier USB3 Reset Driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3-58-ga151 From 69af3d1b8a91cf9b426c4238964df847036bf214 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 9 Nov 2018 10:42:06 +0900 Subject: dt-bindings: reset: uniphier: Add AHCI core reset description Add compatible strings for reset control of AHCI core implemented in UniPhier SoCs. The reset control belongs to AHCI glue layer. Signed-off-by: Kunihiko Hayashi Reviewed-by: Rob Herring Signed-off-by: Philipp Zabel --- Documentation/devicetree/bindings/reset/uniphier-reset.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/reset/uniphier-reset.txt b/Documentation/devicetree/bindings/reset/uniphier-reset.txt index f63c511a9de8..ea005177d20a 100644 --- a/Documentation/devicetree/bindings/reset/uniphier-reset.txt +++ b/Documentation/devicetree/bindings/reset/uniphier-reset.txt @@ -133,6 +133,9 @@ Required properties: "socionext,uniphier-pxs2-usb3-reset" - for PXs2 SoC USB3 "socionext,uniphier-ld20-usb3-reset" - for LD20 SoC USB3 "socionext,uniphier-pxs3-usb3-reset" - for PXs3 SoC USB3 + "socionext,uniphier-pro4-ahci-reset" - for Pro4 SoC AHCI + "socionext,uniphier-pxs2-ahci-reset" - for PXs2 SoC AHCI + "socionext,uniphier-pxs3-ahci-reset" - for PXs3 SoC AHCI - #reset-cells: Should be 1. - reg: Specifies offset and length of the register set for the device. - clocks: A list of phandles to the clock gate for the glue layer. -- cgit v1.2.3-58-ga151 From d0c2d2101b4c1a41e6ebeca6a28c70df43d2a6a3 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Fri, 9 Nov 2018 10:42:07 +0900 Subject: reset: uniphier-glue: Add AHCI reset control support in glue layer Add a reset line included in AHCI glue layer to enable AHCI core implemented in UniPhier SoCs. Signed-off-by: Kunihiko Hayashi Signed-off-by: Philipp Zabel --- drivers/reset/reset-uniphier-glue.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/reset/reset-uniphier-glue.c b/drivers/reset/reset-uniphier-glue.c index 1b8ea03be9a0..a45923f4df6d 100644 --- a/drivers/reset/reset-uniphier-glue.c +++ b/drivers/reset/reset-uniphier-glue.c @@ -152,6 +152,18 @@ static const struct of_device_id uniphier_glue_reset_match[] = { .compatible = "socionext,uniphier-pxs3-usb3-reset", .data = &uniphier_pxs2_data, }, + { + .compatible = "socionext,uniphier-pro4-ahci-reset", + .data = &uniphier_pro4_data, + }, + { + .compatible = "socionext,uniphier-pxs2-ahci-reset", + .data = &uniphier_pxs2_data, + }, + { + .compatible = "socionext,uniphier-pxs3-ahci-reset", + .data = &uniphier_pxs2_data, + }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, uniphier_glue_reset_match); -- cgit v1.2.3-58-ga151 From 22e6a2e14cb8ebcae059488cf24e778e4058c2bf Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 19 Dec 2018 18:06:57 +0530 Subject: RISC-V: Make BSS section as the last section in vmlinux.lds.S The objcopy only emits loadable sections when creating flat kernel Image. To have minimal possible size of flat kernel Image, we should have all non-loadable sections after loadable sections. Currently, execption table section (loadable section) is after BSS section (non-loadable section) in the RISC-V vmlinux.lds.S. This is not optimal for having minimal flat kernel Image size hence this patch makes BSS section as the last section in RISC-V vmlinux.lds.S. In addition, we make BSS section aligned to 16byte instead of PAGE aligned which further reduces flat kernel Image size by few KBs. The flat kernel Image size of Linux-4.20-rc4 using GCC 8.2.0 is 8819980 bytes with current RISC-V vmlinux.lds.S and it reduces to 7991740 bytes with this patch applied. In summary, this patch reduces Linux-4.20-rc4 flat kernel Image size by 809 KB. Signed-off-by: Anup Patel Reviewed-by: Bin Meng Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/vmlinux.lds.S | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S index 65df1dfdc303..1e1395d63dab 100644 --- a/arch/riscv/kernel/vmlinux.lds.S +++ b/arch/riscv/kernel/vmlinux.lds.S @@ -18,6 +18,8 @@ #include #include +#define MAX_BYTES_PER_LONG 0x10 + OUTPUT_ARCH(riscv) ENTRY(_start) @@ -74,8 +76,6 @@ SECTIONS *(.sbss*) } - BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0) - EXCEPTION_TABLE(0x10) NOTES @@ -83,6 +83,10 @@ SECTIONS *(.rel.dyn*) } + BSS_SECTION(MAX_BYTES_PER_LONG, + MAX_BYTES_PER_LONG, + MAX_BYTES_PER_LONG) + _end = .; STABS_DEBUG -- cgit v1.2.3-58-ga151 From d0df00e30e4bf9bc27ddbd092ad683ff6121b360 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 25 Dec 2018 15:46:24 +0100 Subject: tools uapi: fix RISC-V 64-bit support The BPF library is not built on 64-bit RISC-V, as the BPF feature is not detected. Looking more in details, feature/test-bpf.c fails to build with the following error: | In file included from /tmp/linux-4.19.12/tools/include/uapi/asm/bitsperlong.h:17, | from /tmp/linux-4.19.12/tools/include/uapi/asm-generic/unistd.h:2, | from /usr/include/riscv64-linux-gnu/asm/unistd.h:1, | from test-bpf.c:2: | /tmp/linux-4.19.12/tools/include/asm-generic/bitsperlong.h:14:2: error: #error Inconsistent word size. Check asm/bitsperlong.h | #error Inconsistent word size. Check asm/bitsperlong.h | ^~~~~ The UAPI from the tools directory is missing RISC-V support, therefore bitsperlong.h from asm-generic is used, defaulting to 32 bits. Fix that by adding tools/arch/riscv/include/uapi/asm/bitsperlong.h as a copy of arch/riscv/include/uapi/asm/bitsperlong.h and by updating tools/include/uapi/asm/bitsperlong.h. Signed-off-by: Aurelien Jarno Signed-off-by: Palmer Dabbelt --- tools/arch/riscv/include/uapi/asm/bitsperlong.h | 25 +++++++++++++++++++++++++ tools/include/uapi/asm/bitsperlong.h | 2 ++ 2 files changed, 27 insertions(+) create mode 100644 tools/arch/riscv/include/uapi/asm/bitsperlong.h diff --git a/tools/arch/riscv/include/uapi/asm/bitsperlong.h b/tools/arch/riscv/include/uapi/asm/bitsperlong.h new file mode 100644 index 000000000000..0b3cb52fd29d --- /dev/null +++ b/tools/arch/riscv/include/uapi/asm/bitsperlong.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2012 ARM Ltd. + * Copyright (C) 2015 Regents of the University of California + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _UAPI_ASM_RISCV_BITSPERLONG_H +#define _UAPI_ASM_RISCV_BITSPERLONG_H + +#define __BITS_PER_LONG (__SIZEOF_POINTER__ * 8) + +#include + +#endif /* _UAPI_ASM_RISCV_BITSPERLONG_H */ diff --git a/tools/include/uapi/asm/bitsperlong.h b/tools/include/uapi/asm/bitsperlong.h index 8dd6aefdafa4..fd92ce8388fc 100644 --- a/tools/include/uapi/asm/bitsperlong.h +++ b/tools/include/uapi/asm/bitsperlong.h @@ -13,6 +13,8 @@ #include "../../arch/mips/include/uapi/asm/bitsperlong.h" #elif defined(__ia64__) #include "../../arch/ia64/include/uapi/asm/bitsperlong.h" +#elif defined(__riscv) +#include "../../arch/riscv/include/uapi/asm/bitsperlong.h" #else #include #endif -- cgit v1.2.3-58-ga151 From 8fd6e05c7463b635e51ec7df0a1858c1b5a6e350 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Mon, 17 Dec 2018 19:15:12 -0800 Subject: arch: riscv: support kernel command line forcing when no DTB passed CONFIG_CMDLINE_FORCE doesn't work on RISC-V when no DTB is passed into the kernel. This is because the code that forces the kernel command line only runs if a valid DTB is present at boot. During debugging, it's useful to have the ability to force kernel command lines even when no DTB is present. This patch adds support for doing so. Cc: Palmer Dabbelt Cc: Albert Ou Cc: linux-riscv@lists.infradead.org Cc: linux-kernel@vger.kernel.org (open list) Signed-off-by: Paul Walmsley Signed-off-by: Paul Walmsley Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/setup.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index fc8006a042eb..6e079e94b638 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -149,7 +149,14 @@ asmlinkage void __init setup_vm(void) void __init parse_dtb(unsigned int hartid, void *dtb) { - early_init_dt_scan(__va(dtb)); + if (!early_init_dt_scan(__va(dtb))) + return; + + pr_err("No DTB passed to the kernel\n"); +#ifdef CONFIG_CMDLINE_FORCE + strlcpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); + pr_info("Forcing kernel command line to: %s\n", boot_command_line); +#endif } static void __init setup_bootmem(void) -- cgit v1.2.3-58-ga151 From 37a107ff6dcd773da4dc75b62b9bf4349dd7300f Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 11 Dec 2018 11:20:40 +0100 Subject: riscv: don't stop itself in smp_send_stop Add IPI_CPU_STOP message and use it in smp_send_stop to stop other cpus, but not itself. Mark cpu offline on reception of IPI_CPU_STOP. Signed-off-by: Andreas Schwab Reviewed-by: Atish Patra Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/smp.c | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index 57b1383e5ef7..246635eac7bb 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ enum ipi_message_type { IPI_RESCHEDULE, IPI_CALL_FUNC, + IPI_CPU_STOP, IPI_MAX }; @@ -66,6 +68,13 @@ int setup_profiling_timer(unsigned int multiplier) return -EINVAL; } +static void ipi_stop(void) +{ + set_cpu_online(smp_processor_id(), false); + while (1) + wait_for_interrupt(); +} + void riscv_software_interrupt(void) { unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; @@ -94,6 +103,11 @@ void riscv_software_interrupt(void) generic_smp_call_function_interrupt(); } + if (ops & (1 << IPI_CPU_STOP)) { + stats[IPI_CPU_STOP]++; + ipi_stop(); + } + BUG_ON((ops >> IPI_MAX) != 0); /* Order data access and bit testing. */ @@ -121,6 +135,7 @@ send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation) static const char * const ipi_names[] = { [IPI_RESCHEDULE] = "Rescheduling interrupts", [IPI_CALL_FUNC] = "Function call interrupts", + [IPI_CPU_STOP] = "CPU stop interrupts", }; void show_ipi_stats(struct seq_file *p, int prec) @@ -146,15 +161,29 @@ void arch_send_call_function_single_ipi(int cpu) send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC); } -static void ipi_stop(void *unused) -{ - while (1) - wait_for_interrupt(); -} - void smp_send_stop(void) { - on_each_cpu(ipi_stop, NULL, 1); + unsigned long timeout; + + if (num_online_cpus() > 1) { + cpumask_t mask; + + cpumask_copy(&mask, cpu_online_mask); + cpumask_clear_cpu(smp_processor_id(), &mask); + + if (system_state <= SYSTEM_RUNNING) + pr_crit("SMP: stopping secondary CPUs\n"); + send_ipi_message(&mask, IPI_CPU_STOP); + } + + /* Wait up to one second for other CPUs to stop */ + timeout = USEC_PER_SEC; + while (num_online_cpus() > 1 && timeout--) + udelay(1); + + if (num_online_cpus() > 1) + pr_warn("SMP: failed to stop secondary CPUs %*pbl\n", + cpumask_pr_args(cpu_online_mask)); } void smp_send_reschedule(int cpu) -- cgit v1.2.3-58-ga151 From af5f462c2d9ed227ffca4c8d02eb38679c9b8846 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Mon, 17 Dec 2018 16:09:58 -0800 Subject: MAINTAINERS: SiFive drivers: change the git tree to a SiFive git tree Update the git tree URL for drivers for SiFive-related IP blocks to point to a SiFive-managed URL. Cc: Albert Ou Cc: Palmer Dabbelt Cc: linux-kernel@vger.kernel.org Cc: linux-riscv@lists.infradead.org Signed-off-by: Paul Walmsley Signed-off-by: Paul Walmsley Signed-off-by: Palmer Dabbelt --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 32d444476a90..5ef3535dea5e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13821,7 +13821,7 @@ F: drivers/media/mmc/siano/ SIFIVE DRIVERS M: Palmer Dabbelt L: linux-riscv@lists.infradead.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux.git +T: git git://github.com/sifive/riscv-linux.git S: Supported K: sifive N: sifive -- cgit v1.2.3-58-ga151 From 3b56adcf94d03533666e87e41d23ac91756cec9b Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Mon, 17 Dec 2018 16:09:59 -0800 Subject: MAINTAINERS: SiFive drivers: add myself as a SiFive driver maintainer I'll be helping Palmer review drivers for SiFive-specific IP blocks, so add myself to the MAINTAINERS file. Cc: Albert Ou Cc: Palmer Dabbelt Cc: linux-kernel@vger.kernel.org Cc: linux-riscv@lists.infradead.org Signed-off-by: Paul Walmsley Signed-off-by: Paul Walmsley Signed-off-by: Palmer Dabbelt --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5ef3535dea5e..f3a226379e57 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13820,6 +13820,7 @@ F: drivers/media/mmc/siano/ SIFIVE DRIVERS M: Palmer Dabbelt +M: Paul Walmsley L: linux-riscv@lists.infradead.org T: git git://github.com/sifive/riscv-linux.git S: Supported -- cgit v1.2.3-58-ga151 From 2cffc9569050a8dbc0c4a6ee7186c0919487c3ec Mon Sep 17 00:00:00 2001 From: Zong Li Date: Fri, 7 Dec 2018 17:02:16 +0800 Subject: RISC-V: Support MODULE_SECTIONS mechanism on RV32 This patch supports dynamic generate got and plt sections mechanism on rv32. It contains the modification as follows: - Always enable MODULE_SECTIONS (both rv64 and rv32) - Change the fixed size type. This patch had been tested by following modules: btrfs 6795991 0 - Live 0xa544b000 test_static_keys 17304 0 - Live 0xa28be000 zstd_compress 1198986 1 btrfs, Live 0xa2a25000 zstd_decompress 608112 1 btrfs, Live 0xa24e7000 lzo 8787 0 - Live 0xa2049000 xor 27461 1 btrfs, Live 0xa2041000 zram 78849 0 - Live 0xa2276000 netdevsim 55909 0 - Live 0xa202d000 tun 211534 0 - Live 0xa21b5000 fuse 566049 0 - Live 0xa25fb000 nfs_layout_flexfiles 192597 0 - Live 0xa229b000 ramoops 74895 0 - Live 0xa2019000 xfs 3973221 0 - Live 0xa507f000 libcrc32c 3053 2 btrfs,xfs, Live 0xa34af000 lzo_compress 17302 2 btrfs,lzo, Live 0xa347d000 lzo_decompress 7178 2 btrfs,lzo, Live 0xa3451000 raid6_pq 142086 1 btrfs, Live 0xa33a4000 reed_solomon 31022 1 ramoops, Live 0xa31eb000 test_bitmap 3734 0 - Live 0xa31af000 test_bpf 1588736 0 - Live 0xa2c11000 test_kmod 41161 0 - Live 0xa29f8000 test_module 1356 0 - Live 0xa299e000 test_printf 6024 0 [permanent], Live 0xa2971000 test_static_key_base 5797 1 test_static_keys, Live 0xa2931000 test_user_copy 4382 0 - Live 0xa28c9000 xxhash 70501 2 zstd_compress,zstd_decompress, Live 0xa2055000 Signed-off-by: Zong Li Signed-off-by: Palmer Dabbelt --- arch/riscv/Kconfig | 2 +- arch/riscv/include/asm/module.h | 28 +++++++++++++++------------- arch/riscv/kernel/module-sections.c | 30 ++++++++++++++++-------------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index e0d7d61779a6..6be2c08ff2b5 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -40,6 +40,7 @@ config RISCV select HAVE_ARCH_TRACEHOOK select HAVE_PCI select MODULES_USE_ELF_RELA if MODULES + select MODULE_SECTIONS if MODULES select THREAD_INFO_IN_TASK select PCI_DOMAINS_GENERIC if PCI select PCI_MSI if PCI @@ -152,7 +153,6 @@ choice bool "2GiB" config MAXPHYSMEM_128GB depends on 64BIT && CMODEL_MEDANY - select MODULE_SECTIONS if MODULES bool "128GiB" endchoice diff --git a/arch/riscv/include/asm/module.h b/arch/riscv/include/asm/module.h index cd2af4b013e3..46202dad365d 100644 --- a/arch/riscv/include/asm/module.h +++ b/arch/riscv/include/asm/module.h @@ -9,12 +9,12 @@ #define MODULE_ARCH_VERMAGIC "riscv" struct module; -u64 module_emit_got_entry(struct module *mod, u64 val); -u64 module_emit_plt_entry(struct module *mod, u64 val); +unsigned long module_emit_got_entry(struct module *mod, unsigned long val); +unsigned long module_emit_plt_entry(struct module *mod, unsigned long val); #ifdef CONFIG_MODULE_SECTIONS struct mod_section { - struct elf64_shdr *shdr; + Elf_Shdr *shdr; int num_entries; int max_entries; }; @@ -26,18 +26,18 @@ struct mod_arch_specific { }; struct got_entry { - u64 symbol_addr; /* the real variable address */ + unsigned long symbol_addr; /* the real variable address */ }; -static inline struct got_entry emit_got_entry(u64 val) +static inline struct got_entry emit_got_entry(unsigned long val) { return (struct got_entry) {val}; } -static inline struct got_entry *get_got_entry(u64 val, +static inline struct got_entry *get_got_entry(unsigned long val, const struct mod_section *sec) { - struct got_entry *got = (struct got_entry *)sec->shdr->sh_addr; + struct got_entry *got = (struct got_entry *)(sec->shdr->sh_addr); int i; for (i = 0; i < sec->num_entries; i++) { if (got[i].symbol_addr == val) @@ -62,7 +62,9 @@ struct plt_entry { #define REG_T0 0x5 #define REG_T1 0x6 -static inline struct plt_entry emit_plt_entry(u64 val, u64 plt, u64 got_plt) +static inline struct plt_entry emit_plt_entry(unsigned long val, + unsigned long plt, + unsigned long got_plt) { /* * U-Type encoding: @@ -76,7 +78,7 @@ static inline struct plt_entry emit_plt_entry(u64 val, u64 plt, u64 got_plt) * +------------+------------+--------+----------+----------+ * */ - u64 offset = got_plt - plt; + unsigned long offset = got_plt - plt; u32 hi20 = (offset + 0x800) & 0xfffff000; u32 lo12 = (offset - hi20); return (struct plt_entry) { @@ -86,7 +88,7 @@ static inline struct plt_entry emit_plt_entry(u64 val, u64 plt, u64 got_plt) }; } -static inline int get_got_plt_idx(u64 val, const struct mod_section *sec) +static inline int get_got_plt_idx(unsigned long val, const struct mod_section *sec) { struct got_entry *got_plt = (struct got_entry *)sec->shdr->sh_addr; int i; @@ -97,9 +99,9 @@ static inline int get_got_plt_idx(u64 val, const struct mod_section *sec) return -1; } -static inline struct plt_entry *get_plt_entry(u64 val, - const struct mod_section *sec_plt, - const struct mod_section *sec_got_plt) +static inline struct plt_entry *get_plt_entry(unsigned long val, + const struct mod_section *sec_plt, + const struct mod_section *sec_got_plt) { struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr; int got_plt_idx = get_got_plt_idx(val, sec_got_plt); diff --git a/arch/riscv/kernel/module-sections.c b/arch/riscv/kernel/module-sections.c index bbbd26e19bfd..c9ae48333114 100644 --- a/arch/riscv/kernel/module-sections.c +++ b/arch/riscv/kernel/module-sections.c @@ -9,14 +9,14 @@ #include #include -u64 module_emit_got_entry(struct module *mod, u64 val) +unsigned long module_emit_got_entry(struct module *mod, unsigned long val) { struct mod_section *got_sec = &mod->arch.got; int i = got_sec->num_entries; struct got_entry *got = get_got_entry(val, got_sec); if (got) - return (u64)got; + return (unsigned long)got; /* There is no duplicate entry, create a new one */ got = (struct got_entry *)got_sec->shdr->sh_addr; @@ -25,10 +25,10 @@ u64 module_emit_got_entry(struct module *mod, u64 val) got_sec->num_entries++; BUG_ON(got_sec->num_entries > got_sec->max_entries); - return (u64)&got[i]; + return (unsigned long)&got[i]; } -u64 module_emit_plt_entry(struct module *mod, u64 val) +unsigned long module_emit_plt_entry(struct module *mod, unsigned long val) { struct mod_section *got_plt_sec = &mod->arch.got_plt; struct got_entry *got_plt; @@ -37,27 +37,29 @@ u64 module_emit_plt_entry(struct module *mod, u64 val) int i = plt_sec->num_entries; if (plt) - return (u64)plt; + return (unsigned long)plt; /* There is no duplicate entry, create a new one */ got_plt = (struct got_entry *)got_plt_sec->shdr->sh_addr; got_plt[i] = emit_got_entry(val); plt = (struct plt_entry *)plt_sec->shdr->sh_addr; - plt[i] = emit_plt_entry(val, (u64)&plt[i], (u64)&got_plt[i]); + plt[i] = emit_plt_entry(val, + (unsigned long)&plt[i], + (unsigned long)&got_plt[i]); plt_sec->num_entries++; got_plt_sec->num_entries++; BUG_ON(plt_sec->num_entries > plt_sec->max_entries); - return (u64)&plt[i]; + return (unsigned long)&plt[i]; } -static int is_rela_equal(const Elf64_Rela *x, const Elf64_Rela *y) +static int is_rela_equal(const Elf_Rela *x, const Elf_Rela *y) { return x->r_info == y->r_info && x->r_addend == y->r_addend; } -static bool duplicate_rela(const Elf64_Rela *rela, int idx) +static bool duplicate_rela(const Elf_Rela *rela, int idx) { int i; for (i = 0; i < idx; i++) { @@ -67,13 +69,13 @@ static bool duplicate_rela(const Elf64_Rela *rela, int idx) return false; } -static void count_max_entries(Elf64_Rela *relas, int num, +static void count_max_entries(Elf_Rela *relas, int num, unsigned int *plts, unsigned int *gots) { unsigned int type, i; for (i = 0; i < num; i++) { - type = ELF64_R_TYPE(relas[i].r_info); + type = ELF_RISCV_R_TYPE(relas[i].r_info); if (type == R_RISCV_CALL_PLT) { if (!duplicate_rela(relas, i)) (*plts)++; @@ -118,9 +120,9 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, /* Calculate the maxinum number of entries */ for (i = 0; i < ehdr->e_shnum; i++) { - Elf64_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset; - int num_rela = sechdrs[i].sh_size / sizeof(Elf64_Rela); - Elf64_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info; + Elf_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset; + int num_rela = sechdrs[i].sh_size / sizeof(Elf_Rela); + Elf_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info; if (sechdrs[i].sh_type != SHT_RELA) continue; -- cgit v1.2.3-58-ga151 From efe75c494f57890900caf6c8a0667db35bfaf56a Mon Sep 17 00:00:00 2001 From: David Abdurachmanov Date: Mon, 29 Oct 2018 11:48:53 +0100 Subject: riscv: add audit support On RISC-V (riscv) audit is supported through generic lib/audit.c. The patch adds required arch specific definitions. Signed-off-by: David Abdurachmanov Signed-off-by: Palmer Dabbelt --- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/ptrace.h | 5 +++++ arch/riscv/include/asm/syscall.h | 10 ++++++++++ arch/riscv/include/asm/thread_info.h | 6 ++++++ arch/riscv/kernel/entry.S | 4 ++-- include/uapi/linux/audit.h | 2 ++ 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 55da93f4e818..38787c48d76c 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -28,6 +28,7 @@ config RISCV select GENERIC_STRNLEN_USER select GENERIC_SMP_IDLE_THREAD select GENERIC_ATOMIC64 if !64BIT || !RISCV_ISA_A + select HAVE_ARCH_AUDITSYSCALL select HAVE_MEMBLOCK_NODE_MAP select HAVE_DMA_CONTIGUOUS select HAVE_FUTEX_CMPXCHG if FUTEX diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index bbe1862e8f80..d35ec2f41381 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h @@ -113,6 +113,11 @@ static inline void frame_pointer_set(struct pt_regs *regs, SET_FP(regs, val); } +static inline unsigned long regs_return_value(struct pt_regs *regs) +{ + return regs->a0; +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_PTRACE_H */ diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h index 8d25f8904c00..bba3da6ef157 100644 --- a/arch/riscv/include/asm/syscall.h +++ b/arch/riscv/include/asm/syscall.h @@ -18,6 +18,7 @@ #ifndef _ASM_RISCV_SYSCALL_H #define _ASM_RISCV_SYSCALL_H +#include #include #include @@ -99,4 +100,13 @@ static inline void syscall_set_arguments(struct task_struct *task, memcpy(®s->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0)); } +static inline int syscall_get_arch(void) +{ +#ifdef CONFIG_64BIT + return AUDIT_ARCH_RISCV64; +#else + return AUDIT_ARCH_RISCV32; +#endif +} + #endif /* _ASM_RISCV_SYSCALL_H */ diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index f8fa1cd2dad9..1c9cc8389928 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -80,13 +80,19 @@ struct thread_info { #define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */ #define TIF_MEMDIE 5 /* is terminating due to OOM killer */ #define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */ +#define TIF_SYSCALL_AUDIT 7 /* syscall auditing */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) +#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_WORK_MASK \ (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED) +#define _TIF_SYSCALL_WORK \ + (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT) + #endif /* _ASM_RISCV_THREAD_INFO_H */ diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 13d4826ab2a1..355166f57205 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -201,7 +201,7 @@ handle_syscall: REG_S s2, PT_SEPC(sp) /* Trace syscalls, but only if requested by the user. */ REG_L t0, TASK_TI_FLAGS(tp) - andi t0, t0, _TIF_SYSCALL_TRACE + andi t0, t0, _TIF_SYSCALL_WORK bnez t0, handle_syscall_trace_enter check_syscall_nr: /* Check to make sure we don't jump to a bogus syscall number. */ @@ -221,7 +221,7 @@ ret_from_syscall: REG_S a0, PT_A0(sp) /* Trace syscalls, but only if requested by the user. */ REG_L t0, TASK_TI_FLAGS(tp) - andi t0, t0, _TIF_SYSCALL_TRACE + andi t0, t0, _TIF_SYSCALL_WORK bnez t0, handle_syscall_trace_exit ret_from_exception: diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 818ae690ab79..d0e037a96a7b 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -399,6 +399,8 @@ enum { /* do not define AUDIT_ARCH_PPCLE since it is not supported by audit */ #define AUDIT_ARCH_PPC64 (EM_PPC64|__AUDIT_ARCH_64BIT) #define AUDIT_ARCH_PPC64LE (EM_PPC64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_RISCV32 (EM_RISCV|__AUDIT_ARCH_LE) +#define AUDIT_ARCH_RISCV64 (EM_RISCV|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) #define AUDIT_ARCH_S390 (EM_S390) #define AUDIT_ARCH_S390X (EM_S390|__AUDIT_ARCH_64BIT) #define AUDIT_ARCH_SH (EM_SH) -- cgit v1.2.3-58-ga151 From 0aea89430a4c79c65c541c947497007d33fbe002 Mon Sep 17 00:00:00 2001 From: David Abdurachmanov Date: Mon, 29 Oct 2018 11:48:54 +0100 Subject: riscv: audit: add audit hook in do_syscall_trace_enter/exit() This patch adds auditing functions on entry to and exit from every system call invocation. Signed-off-by: David Abdurachmanov Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/ptrace.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index 60f1e02eed36..c1b51539c3e2 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -163,10 +164,14 @@ void do_syscall_trace_enter(struct pt_regs *regs) if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_enter(regs, syscall_get_nr(current, regs)); #endif + + audit_syscall_entry(regs->a7, regs->a0, regs->a1, regs->a2, regs->a3); } void do_syscall_trace_exit(struct pt_regs *regs) { + audit_syscall_exit(regs); + if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall_exit(regs, 0); -- cgit v1.2.3-58-ga151 From 45ef1aa8a0e3b0da449c619035b0841f28abca63 Mon Sep 17 00:00:00 2001 From: David Abdurachmanov Date: Mon, 10 Dec 2018 21:43:54 +0100 Subject: riscv: define NR_syscalls in unistd.h This macro is used by kernel/trace/{trace.h,trace_syscalls.c} if we have CONFIG_FTRACE_SYSCALLS enabled. Signed-off-by: David Abdurachmanov Fixes: b78002b395b4 ("riscv: add HAVE_SYSCALL_TRACEPOINTS to Kconfig") Signed-off-by: Palmer Dabbelt --- arch/riscv/include/asm/unistd.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/include/asm/unistd.h b/arch/riscv/include/asm/unistd.h index fef96f117b4d..073ee80fdf74 100644 --- a/arch/riscv/include/asm/unistd.h +++ b/arch/riscv/include/asm/unistd.h @@ -19,3 +19,5 @@ #define __ARCH_WANT_SYS_CLONE #include + +#define NR_syscalls (__NR_syscalls) -- cgit v1.2.3-58-ga151 From 008e901b70282183b52ee80d838d2994b2610231 Mon Sep 17 00:00:00 2001 From: David Abdurachmanov Date: Mon, 10 Dec 2018 21:43:55 +0100 Subject: riscv: define CREATE_TRACE_POINTS in ptrace.c Define CREATE_TRACE_POINTS in order to create functions and structures for the trace events. This is needed if HAVE_SYSCALL_TRACEPOINTS and CONFIG_FTRACE_SYSCALLS are enabled, otherwise we get linking errors: [..] MODPOST vmlinux.o kernel/trace/trace_syscalls.o: In function `.L0 ': trace_syscalls.c:(.text+0x1152): undefined reference to `__tracepoint_sys_enter' trace_syscalls.c:(.text+0x126c): undefined reference to `__tracepoint_sys_enter' trace_syscalls.c:(.text+0x1328): undefined reference to `__tracepoint_sys_enter' trace_syscalls.c:(.text+0x14aa): undefined reference to `__tracepoint_sys_enter' trace_syscalls.c:(.text+0x1684): undefined reference to `__tracepoint_sys_exit' trace_syscalls.c:(.text+0x17a0): undefined reference to `__tracepoint_sys_exit' trace_syscalls.c:(.text+0x185c): undefined reference to `__tracepoint_sys_exit' trace_syscalls.c:(.text+0x19de): undefined reference to `__tracepoint_sys_exit' arch/riscv/kernel/ptrace.o: In function `.L0 ': ptrace.c:(.text+0x4dc): undefined reference to `__tracepoint_sys_enter' ptrace.c:(.text+0x632): undefined reference to `__tracepoint_sys_exit' make: *** [Makefile:1036: vmlinux] Error 1 Signed-off-by: David Abdurachmanov Fixes: b78002b395b4 ("riscv: add HAVE_SYSCALL_TRACEPOINTS to Kconfig") Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/ptrace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index c1b51539c3e2..a34c98b49dcb 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -25,6 +25,8 @@ #include #include #include + +#define CREATE_TRACE_POINTS #include enum riscv_regset { -- cgit v1.2.3-58-ga151 From 775800b0f1d7303d4fd8ce0e0d9eca4ff2f338f2 Mon Sep 17 00:00:00 2001 From: David Abdurachmanov Date: Thu, 6 Dec 2018 16:26:34 +0100 Subject: riscv: fix trace_sys_exit hook Fix compilation error. Signed-off-by: David Abdurachmanov Signed-off-by: Palmer Dabbelt --- arch/riscv/kernel/ptrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index a34c98b49dcb..2ae5e0284f56 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -179,6 +179,6 @@ void do_syscall_trace_exit(struct pt_regs *regs) #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) - trace_sys_exit(regs, regs->regs[0]); + trace_sys_exit(regs, regs_return_value(regs)); #endif } -- cgit v1.2.3-58-ga151 From 5aeb1b36cedd3a1dfdbfe368629fed52dee34103 Mon Sep 17 00:00:00 2001 From: David Abdurachmanov Date: Thu, 6 Dec 2018 16:26:35 +0100 Subject: riscv: add HAVE_SYSCALL_TRACEPOINTS to Kconfig I looked into Documentation/trace/ftrace-design.rst and, I think, we check all the boxes needed for HAVE_SYSCALL_TRACEPOINTS. Signed-off-by: David Abdurachmanov Signed-off-by: Palmer Dabbelt --- arch/riscv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 38787c48d76c..0ae078655c1b 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -34,6 +34,7 @@ config RISCV select HAVE_FUTEX_CMPXCHG if FUTEX select HAVE_GENERIC_DMA_COHERENT select HAVE_PERF_EVENTS + select HAVE_SYSCALL_TRACEPOINTS select IRQ_DOMAIN select RISCV_ISA_A if SMP select SPARSE_IRQ -- cgit v1.2.3-58-ga151 From 34aabf918717dd14e05051896aaecd3b16b53d95 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Fri, 28 Dec 2018 16:15:41 +0100 Subject: usb: cdc-acm: send ZLP for Telit 3G Intel based modems Telit 3G Intel based modems require zero packet to be sent if out data size is equal to the endpoint max packet size. Signed-off-by: Daniele Palmas Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ed8c62b2d9d1..739f8960811a 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1865,6 +1865,13 @@ static const struct usb_device_id acm_ids[] = { .driver_info = IGNORE_DEVICE, }, + { USB_DEVICE(0x1bc7, 0x0021), /* Telit 3G ACM only composition */ + .driver_info = SEND_ZERO_PACKET, + }, + { USB_DEVICE(0x1bc7, 0x0023), /* Telit 3G ACM + ECM composition */ + .driver_info = SEND_ZERO_PACKET, + }, + /* control interfaces without any protocol set */ { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, USB_CDC_PROTO_NONE) }, -- cgit v1.2.3-58-ga151 From c5603d2fdb424849360fe7e3f8c1befc97571b8c Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 3 Jan 2019 11:26:17 +0800 Subject: USB: storage: don't insert sane sense for SPC3+ when bad sense specified Currently the code will set US_FL_SANE_SENSE flag unconditionally if device claims SPC3+, however we should allow US_FL_BAD_SENSE flag to prevent this behavior, because SMI SM3350 UFS-USB bridge controller, which claims SPC4, will show strange behavior with 96-byte sense (put the chip into a wrong state that cannot read/write anything). Check the presence of US_FL_BAD_SENSE when assuming US_FL_SANE_SENSE on SPC4+ devices. Signed-off-by: Icenowy Zheng Cc: stable Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/scsiglue.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index fde2e71a6ade..a73ea495d5a7 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -235,8 +235,12 @@ static int slave_configure(struct scsi_device *sdev) if (!(us->fflags & US_FL_NEEDS_CAP16)) sdev->try_rc_10_first = 1; - /* assume SPC3 or latter devices support sense size > 18 */ - if (sdev->scsi_level > SCSI_SPC_2) + /* + * assume SPC3 or latter devices support sense size > 18 + * unless US_FL_BAD_SENSE quirk is specified. + */ + if (sdev->scsi_level > SCSI_SPC_2 && + !(us->fflags & US_FL_BAD_SENSE)) us->fflags |= US_FL_SANE_SENSE; /* -- cgit v1.2.3-58-ga151 From 0a99cc4b8ee83885ab9f097a3737d1ab28455ac0 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 3 Jan 2019 11:26:18 +0800 Subject: USB: storage: add quirk for SMI SM3350 The SMI SM3350 USB-UFS bridge controller cannot handle long sense request correctly and will make the chip refuse to do read/write when requested long sense. Add a bad sense quirk for it. Signed-off-by: Icenowy Zheng Cc: stable Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index f7f83b21dc74..ea0d27a94afe 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1265,6 +1265,18 @@ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* + * Reported by Icenowy Zheng + * The SMI SM3350 USB-UFS bridge controller will enter a wrong state + * that do not process read/write command if a long sense is requested, + * so force to use 18-byte sense. + */ +UNUSUAL_DEV( 0x090c, 0x3350, 0x0000, 0xffff, + "SMI", + "SM3350 UFS-to-USB-Mass-Storage bridge", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BAD_SENSE ), + /* * Reported by Paul Hartman * This card reader returns "Illegal Request, Logical Block Address -- cgit v1.2.3-58-ga151 From ff2a8c532c14fd22fb26a36574d9ff199afbbe54 Mon Sep 17 00:00:00 2001 From: Saranya Gopal Date: Sun, 6 Jan 2019 08:14:02 +0530 Subject: usbcore: Select only first configuration for non-UAC3 compliant devices In most of the UAC1 and UAC2 audio devices, the first configuration is most often the best configuration. However, with recent patch to support UAC3 configuration, second configuration was unintentionally chosen for some of the UAC1/2 devices that had more than one configuration. This was because of the existing check after the audio config check which selected any config which had a non-vendor class. This patch fixes this issue. Fixes: f13912d3f014 ("usbcore: Select UAC3 configuration for audio if present") Reported-by: Con Kolivas Signed-off-by: Saranya Gopal Tested-by: Con Kolivas Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 356b05c82dbc..f713cecc1f41 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -143,9 +143,12 @@ int usb_choose_configuration(struct usb_device *udev) continue; } - if (i > 0 && desc && is_audio(desc) && is_uac3_config(desc)) { - best = c; - break; + if (i > 0 && desc && is_audio(desc)) { + if (is_uac3_config(desc)) { + best = c; + break; + } + continue; } /* From the remaining configs, choose the first one whose -- cgit v1.2.3-58-ga151 From 3483254b89438e60f719937376c5e0ce2bc46761 Mon Sep 17 00:00:00 2001 From: Jack Stocker Date: Thu, 3 Jan 2019 21:56:53 +0000 Subject: USB: Add USB_QUIRK_DELAY_CTRL_MSG quirk for Corsair K70 RGB To match the Corsair Strafe RGB, the Corsair K70 RGB also requires USB_QUIRK_DELAY_CTRL_MSG to completely resolve boot connection issues discussed here: https://github.com/ckb-next/ckb-next/issues/42. Otherwise roughly 1 in 10 boots the keyboard will fail to be detected. Patch that applied delay control quirk for Corsair Strafe RGB: cb88a0588717 ("usb: quirks: add control message delay for 1b1c:1b20") Previous K70 RGB patch to add delay-init quirk: 7a1646d92257 ("Add delay-init quirk for Corsair K70 RGB keyboards") Signed-off-by: Jack Stocker Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 514c5214ddb2..8bc35d53408b 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -394,7 +394,8 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1a40, 0x0101), .driver_info = USB_QUIRK_HUB_SLOW_RESET }, /* Corsair K70 RGB */ - { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT | + USB_QUIRK_DELAY_CTRL_MSG }, /* Corsair Strafe */ { USB_DEVICE(0x1b1c, 0x1b15), .driver_info = USB_QUIRK_DELAY_INIT | -- cgit v1.2.3-58-ga151 From a29c3c09bad18ac2c91dfdbcc892a7a37e407227 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Sat, 5 Jan 2019 14:32:39 +0100 Subject: cdc_ether: trivial whitespace readability fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function is unreadable enough without indenting mismatches and unnecessary line breaks. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ether.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index b3b3c05903a1..3305f23793c7 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -179,10 +179,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) * probed with) and a slave/data interface; union * descriptors sort this all out. */ - info->control = usb_ifnum_to_if(dev->udev, - info->u->bMasterInterface0); - info->data = usb_ifnum_to_if(dev->udev, - info->u->bSlaveInterface0); + info->control = usb_ifnum_to_if(dev->udev, info->u->bMasterInterface0); + info->data = usb_ifnum_to_if(dev->udev, info->u->bSlaveInterface0); if (!info->control || !info->data) { dev_dbg(&intf->dev, "master #%u/%p slave #%u/%p\n", @@ -216,18 +214,16 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) /* a data interface altsetting does the real i/o */ d = &info->data->cur_altsetting->desc; if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { - dev_dbg(&intf->dev, "slave class %u\n", - d->bInterfaceClass); + dev_dbg(&intf->dev, "slave class %u\n", d->bInterfaceClass); goto bad_desc; } skip: - if ( rndis && - header.usb_cdc_acm_descriptor && - header.usb_cdc_acm_descriptor->bmCapabilities) { - dev_dbg(&intf->dev, - "ACM capabilities %02x, not really RNDIS?\n", - header.usb_cdc_acm_descriptor->bmCapabilities); - goto bad_desc; + if (rndis && header.usb_cdc_acm_descriptor && + header.usb_cdc_acm_descriptor->bmCapabilities) { + dev_dbg(&intf->dev, + "ACM capabilities %02x, not really RNDIS?\n", + header.usb_cdc_acm_descriptor->bmCapabilities); + goto bad_desc; } if (header.usb_cdc_ether_desc && info->ether->wMaxSegmentSize) { @@ -238,7 +234,7 @@ skip: } if (header.usb_cdc_mdlm_desc && - memcmp(header.usb_cdc_mdlm_desc->bGUID, mbm_guid, 16)) { + memcmp(header.usb_cdc_mdlm_desc->bGUID, mbm_guid, 16)) { dev_dbg(&intf->dev, "GUID doesn't match\n"); goto bad_desc; } @@ -302,7 +298,7 @@ skip: if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { struct usb_endpoint_descriptor *desc; - dev->status = &info->control->cur_altsetting->endpoint [0]; + dev->status = &info->control->cur_altsetting->endpoint[0]; desc = &dev->status->desc; if (!usb_endpoint_is_int_in(desc) || (le16_to_cpu(desc->wMaxPacketSize) -- cgit v1.2.3-58-ga151 From f87d8ad9233f115db92c6c087d58403b0009ed36 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sat, 5 Jan 2019 10:52:23 -0600 Subject: tipc: fix memory leak in tipc_nl_compat_publ_dump There is a memory leak in case genlmsg_put fails. Fix this by freeing *args* before return. Addresses-Coverity-ID: 1476406 ("Resource leak") Fixes: 46273cf7e009 ("tipc: fix a missing check of genlmsg_put") Signed-off-by: Gustavo A. R. Silva Acked-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/netlink_compat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 40f5cae623a7..77e4b2418f30 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -904,8 +904,10 @@ static int tipc_nl_compat_publ_dump(struct tipc_nl_compat_msg *msg, u32 sock) hdr = genlmsg_put(args, 0, 0, &tipc_genl_family, NLM_F_MULTI, TIPC_NL_PUBL_GET); - if (!hdr) + if (!hdr) { + kfree_skb(args); return -EMSGSIZE; + } nest = nla_nest_start(args, TIPC_NLA_SOCK); if (!nest) { -- cgit v1.2.3-58-ga151 From ee6047b82888148e688e46f17017cae8e088b246 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 4 Jan 2019 16:27:03 +0000 Subject: ASoC: ak4458: Add support for AK4497 AK4497 is a 32-bit 2ch DAC and has the same register map as AK4458 with few exceptions: * AK4497 has one more register at the end of register space DFS_READ which is a read only register that allows users to read FS Auto Detection mode. We currently do not use this register so we use the same regmap structure as for ak4458. * Because AK4458 is an 8ch DAC there are some fields that are only used by AK4458 and marked as reserved for AK4497, so for this reason we need to have a distinct set of controls, widgets and routes. Datasheet for AK4497 is at: https://www.akm.com/akm/en/file/ev-board-manual/AK4497EQ.pdf Datasheet for AK4458 is at: https://www.akm.com/akm/en/file/datasheet/AK4458VN.pdf Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- sound/soc/codecs/ak4458.c | 79 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 70d4c89bd6fc..eab7c76cfcd9 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -21,6 +21,11 @@ #include "ak4458.h" +struct ak4458_drvdata { + struct snd_soc_dai_driver *dai_drv; + const struct snd_soc_component_driver *comp_drv; +}; + /* AK4458 Codec Private Data */ struct ak4458_priv { struct device *dev; @@ -258,6 +263,33 @@ static const struct snd_soc_dapm_route ak4458_intercon[] = { {"AK4458 AOUTD", NULL, "AK4458 DAC4"}, }; +/* ak4497 controls */ +static const struct snd_kcontrol_new ak4497_snd_controls[] = { + SOC_DOUBLE_R_TLV("DAC Playback Volume", AK4458_03_LCHATT, + AK4458_04_RCHATT, 0, 0xFF, 0, dac_tlv), + SOC_ENUM("AK4497 De-emphasis Response DAC", ak4458_dac1_dem_enum), + SOC_ENUM_EXT("AK4497 Digital Filter Setting", ak4458_digfil_enum, + get_digfil, set_digfil), + SOC_ENUM("AK4497 Inverting Enable of DZFB", ak4458_dzfb_enum), + SOC_ENUM("AK4497 Sound Mode", ak4458_sm_enum), + SOC_ENUM("AK4497 Attenuation transition Time Setting", + ak4458_ats_enum), +}; + +/* ak4497 dapm widgets */ +static const struct snd_soc_dapm_widget ak4497_dapm_widgets[] = { + SND_SOC_DAPM_DAC("AK4497 DAC", NULL, AK4458_0A_CONTROL6, 2, 0), + SND_SOC_DAPM_AIF_IN("AK4497 SDTI", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("AK4497 AOUT"), +}; + +/* ak4497 dapm routes */ +static const struct snd_soc_dapm_route ak4497_intercon[] = { + {"AK4497 DAC", NULL, "AK4497 SDTI"}, + {"AK4497 AOUT", NULL, "AK4497 DAC"}, + +}; + static int ak4458_rstn_control(struct snd_soc_component *component, int bit) { int ret; @@ -476,6 +508,18 @@ static struct snd_soc_dai_driver ak4458_dai = { .ops = &ak4458_dai_ops, }; +static struct snd_soc_dai_driver ak4497_dai = { + .name = "ak4497-aif", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = AK4458_FORMATS, + }, + .ops = &ak4458_dai_ops, +}; + static void ak4458_power_off(struct ak4458_priv *ak4458) { if (ak4458->reset_gpiod) { @@ -573,6 +617,21 @@ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { .non_legacy_dai_naming = 1, }; +static const struct snd_soc_component_driver soc_codec_dev_ak4497 = { + .probe = ak4458_probe, + .remove = ak4458_remove, + .controls = ak4497_snd_controls, + .num_controls = ARRAY_SIZE(ak4497_snd_controls), + .dapm_widgets = ak4497_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak4497_dapm_widgets), + .dapm_routes = ak4497_intercon, + .num_dapm_routes = ARRAY_SIZE(ak4497_intercon), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + static const struct regmap_config ak4458_regmap = { .reg_bits = 8, .val_bits = 8, @@ -583,6 +642,16 @@ static const struct regmap_config ak4458_regmap = { .cache_type = REGCACHE_RBTREE, }; +static const struct ak4458_drvdata ak4458_drvdata = { + .dai_drv = &ak4458_dai, + .comp_drv = &soc_codec_dev_ak4458, +}; + +static const struct ak4458_drvdata ak4497_drvdata = { + .dai_drv = &ak4497_dai, + .comp_drv = &soc_codec_dev_ak4497, +}; + static const struct dev_pm_ops ak4458_pm = { SET_RUNTIME_PM_OPS(ak4458_runtime_suspend, ak4458_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, @@ -592,6 +661,7 @@ static const struct dev_pm_ops ak4458_pm = { static int ak4458_i2c_probe(struct i2c_client *i2c) { struct ak4458_priv *ak4458; + const struct ak4458_drvdata *drvdata; int ret; ak4458 = devm_kzalloc(&i2c->dev, sizeof(*ak4458), GFP_KERNEL); @@ -605,6 +675,8 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) i2c_set_clientdata(i2c, ak4458); ak4458->dev = &i2c->dev; + drvdata = of_device_get_match_data(&i2c->dev); + ak4458->reset_gpiod = devm_gpiod_get_optional(ak4458->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ak4458->reset_gpiod)) @@ -615,8 +687,8 @@ static int ak4458_i2c_probe(struct i2c_client *i2c) if (IS_ERR(ak4458->mute_gpiod)) return PTR_ERR(ak4458->mute_gpiod); - ret = devm_snd_soc_register_component(ak4458->dev, &soc_codec_dev_ak4458, - &ak4458_dai, 1); + ret = devm_snd_soc_register_component(ak4458->dev, drvdata->comp_drv, + drvdata->dai_drv, 1); if (ret < 0) { dev_err(ak4458->dev, "Failed to register CODEC: %d\n", ret); return ret; @@ -635,7 +707,8 @@ static int ak4458_i2c_remove(struct i2c_client *i2c) } static const struct of_device_id ak4458_of_match[] = { - { .compatible = "asahi-kasei,ak4458", }, + { .compatible = "asahi-kasei,ak4458", .data = &ak4458_drvdata}, + { .compatible = "asahi-kasei,ak4497", .data = &ak4497_drvdata}, { }, }; -- cgit v1.2.3-58-ga151 From 5d8d66077af12681441897a350f346c0da7f5576 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 4 Jan 2019 16:27:04 +0000 Subject: ASoC: dt-bindings: Document support for ak4497 ak4458 driver supports also ak4497 codec. Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ak4458.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/ak4458.txt b/Documentation/devicetree/bindings/sound/ak4458.txt index 7839be78448d..e5820235e0d5 100644 --- a/Documentation/devicetree/bindings/sound/ak4458.txt +++ b/Documentation/devicetree/bindings/sound/ak4458.txt @@ -4,7 +4,7 @@ This device supports I2C mode. Required properties: -- compatible : "asahi-kasei,ak4458" +- compatible : "asahi-kasei,ak4458" or "asahi-kasei,ak4497" - reg : The I2C address of the device for I2C Optional properties: -- cgit v1.2.3-58-ga151 From 902d82222270c957d12fa2e9856484d600a88d20 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:29 -0600 Subject: ASoC: dmic: declare trigger function as static No reason why this is global, fix warnings with W=1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/dmic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index da921da50ef0..de041369e5a7 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -44,8 +44,8 @@ struct dmic { int modeswitch_delay; }; -int dmic_daiops_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) +static int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct dmic *dmic = snd_soc_component_get_drvdata(component); -- cgit v1.2.3-58-ga151 From 97d8f6b71f56865e52d472247fe728700ef7128d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:30 -0600 Subject: ASoC: max98090: remove unused constant variables Fix warnings with W=1 If these variables are useful then this driver should be modified to expose them. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index c97f21836c66..30c242c38d99 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -314,9 +314,6 @@ static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_dvg_tlv, 0, 600, 0); static const DECLARE_TLV_DB_SCALE(max98090_dv_tlv, -1500, 100, 0); -static const DECLARE_TLV_DB_SCALE(max98090_sidetone_tlv, -6050, 200, 0); - -static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0); @@ -817,18 +814,6 @@ static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text); static const struct snd_kcontrol_new max98090_dmic_mux = SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum); -static const char *max98090_micpre_text[] = { "Off", "On" }; - -static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum, - M98090_REG_MIC1_INPUT_LEVEL, - M98090_MIC_PA1EN_SHIFT, - max98090_micpre_text); - -static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum, - M98090_REG_MIC2_INPUT_LEVEL, - M98090_MIC_PA2EN_SHIFT, - max98090_micpre_text); - /* LINEA mixer switch */ static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { SOC_DAPM_SINGLE("IN1 Switch", M98090_REG_LINE_INPUT_CONFIG, -- cgit v1.2.3-58-ga151 From 37b6f0350374e6c683bc2c2d8a54d4504bc04ec1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:31 -0600 Subject: ASoC: es8316: remove unused constant variables Fix warnings with W=1 If these variables are useful this driver should be modified to expose them. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 98464ba1046c..6d4a323f786b 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -167,8 +167,6 @@ static const char * const es8316_hpmux_texts[] = { "lin-rin with Boost and PGA" }; -static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 }; - static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL, 4, es8316_hpmux_texts); @@ -199,8 +197,6 @@ static const char * const es8316_dacsrc_texts[] = { "RDATA TO LDAC, LDATA TO RDAC", }; -static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 }; - static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1, 6, es8316_dacsrc_texts); -- cgit v1.2.3-58-ga151 From dc22a4093f5d2973bef5f72b00da74ce61458bc0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:32 -0600 Subject: ASoC: codecs: fix kernel doc descriptions Missing or spurious parameter descriptions. Fix warnings with W=1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 1 + sound/soc/codecs/rt5514.c | 1 + sound/soc/codecs/rt5677.c | 8 ++++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 7bbcbf5f05c8..47e65cf99879 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -351,6 +351,7 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825, * Computes log10 of a value; the result is round off to 3 decimal. This func- * tion takes reference to dvb-math. The source code locates as the following. * Linux/drivers/media/dvb-core/dvb_math.c + * @value: input for log10 * * return log10(value) * 1000 */ diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index a67de68b6da6..f9ad6e36ab16 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -489,6 +489,7 @@ static const struct snd_kcontrol_new rt5514_sto2_dmic_mux = /** * rt5514_calc_dmic_clk - Calculate the frequency divider parameter of dmic. * + * @component: only used for dev_warn * @rate: base clock rate. * * Choose divider parameter that gives the highest possible DMIC frequency in diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 9b7a1833d331..6fc70e441458 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -547,7 +547,7 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg) * @rt5677: Private Data. * @addr: Address index. * @value: Address data. - * + * @opcode: opcode value * * Returns 0 for success or negative error code. */ @@ -602,7 +602,7 @@ err: /** * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode. - * rt5677: Private Data. + * @rt5677: Private Data. * @addr: Address index. * @value: Address data. * @@ -651,7 +651,7 @@ err: /** * rt5677_dsp_mode_i2c_write - Write register on DSP mode. - * rt5677: Private Data. + * @rt5677: Private Data. * @reg: Register index. * @value: Register data. * @@ -667,7 +667,7 @@ static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677, /** * rt5677_dsp_mode_i2c_read - Read register on DSP mode. - * @codec: SoC audio codec device. + * @rt5677: Private Data * @reg: Register index. * @value: Register data. * -- cgit v1.2.3-58-ga151 From c3db21324442137552041711a878d75358c993ae Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:33 -0600 Subject: ASoC: rt5645: remove unused mux define rt5645_if3_adc_in_mux, rt5645_inr_mux, and rt5645_inl_mux are not used. Remove them from the driver. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index be674688dc40..52ce380c8f3a 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1288,30 +1288,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_dac_r2_mux = SOC_DAPM_ENUM("DAC2 R source", rt5645_dac2r_enum); - -/* INL/R source */ -static const char * const rt5645_inl_src[] = { - "IN2P", "MonoP" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_inl_enum, RT5645_INL1_INR1_VOL, - RT5645_INL_SEL_SFT, rt5645_inl_src); - -static const struct snd_kcontrol_new rt5645_inl_mux = - SOC_DAPM_ENUM("INL source", rt5645_inl_enum); - -static const char * const rt5645_inr_src[] = { - "IN2N", "MonoN" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_inr_enum, RT5645_INL1_INR1_VOL, - RT5645_INR_SEL_SFT, rt5645_inr_src); - -static const struct snd_kcontrol_new rt5645_inr_mux = - SOC_DAPM_ENUM("INR source", rt5645_inr_enum); - /* Stereo1 ADC source */ /* MX-27 [12] */ static const char * const rt5645_stereo_adc1_src[] = { @@ -1611,18 +1587,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_if2_adc_in_mux = SOC_DAPM_ENUM("IF2 ADC IN source", rt5645_if2_adc_in_enum); -/* MX-2F [1:0] */ -static const char * const rt5645_if3_adc_in_src[] = { - "IF_ADC1", "IF_ADC2", "VAD_ADC" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_if3_adc_in_enum, RT5645_DIG_INF1_DATA, - RT5645_IF3_ADC_IN_SFT, rt5645_if3_adc_in_src); - -static const struct snd_kcontrol_new rt5645_if3_adc_in_mux = - SOC_DAPM_ENUM("IF3 ADC IN source", rt5645_if3_adc_in_enum); - /* MX-31 [15] [13] [11] [9] */ static const char * const rt5645_pdm_src[] = { "Mono DAC", "Stereo DAC" -- cgit v1.2.3-58-ga151 From 6606f9df60bcb632e047e0f8a268e327cebcc3db Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:34 -0600 Subject: ASoC: rt5670: remove unused mux/mixer define Some mux/mixer are not used. Remove them from the driver. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 54 ----------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 453328c988c0..9a037108b1ae 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1057,20 +1057,6 @@ static const struct snd_kcontrol_new rt5670_lout_mix[] = { RT5670_M_OV_R_LM_SFT, 1, 1), }; -static const struct snd_kcontrol_new rt5670_hpl_mix[] = { - SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_HPO_MIXER, - RT5670_M_DACL1_HML_SFT, 1, 1), - SOC_DAPM_SINGLE("INL1 Switch", RT5670_HPO_MIXER, - RT5670_M_INL1_HML_SFT, 1, 1), -}; - -static const struct snd_kcontrol_new rt5670_hpr_mix[] = { - SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_HPO_MIXER, - RT5670_M_DACR1_HMR_SFT, 1, 1), - SOC_DAPM_SINGLE("INR1 Switch", RT5670_HPO_MIXER, - RT5670_M_INR1_HMR_SFT, 1, 1), -}; - static const struct snd_kcontrol_new lout_l_enable_control = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5670_LOUT1, RT5670_L_MUTE_SFT, 1, 1); @@ -1196,24 +1182,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc2_enum, RT5670_STO2_ADC_MIXER, static const struct snd_kcontrol_new rt5670_sto2_adc_2_mux = SOC_DAPM_ENUM("Stereo2 ADC 2 Mux", rt5670_stereo2_adc2_enum); - -/* MX-27 MX26 [10] */ -static const char * const rt5670_stereo_adc_src[] = { - "ADC1L ADC2R", "ADC3" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc_enum, RT5670_STO1_ADC_MIXER, - RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); - -static const struct snd_kcontrol_new rt5670_sto_adc_mux = - SOC_DAPM_ENUM("Stereo1 ADC source", rt5670_stereo1_adc_enum); - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc_enum, RT5670_STO2_ADC_MIXER, - RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); - -static const struct snd_kcontrol_new rt5670_sto2_adc_mux = - SOC_DAPM_ENUM("Stereo2 ADC source", rt5670_stereo2_adc_enum); - /* MX-27 MX-26 [9:8] */ static const char * const rt5670_stereo_dmic_src[] = { "DMIC1", "DMIC2", "DMIC3" @@ -1231,17 +1199,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_dmic_enum, RT5670_STO2_ADC_MIXER, static const struct snd_kcontrol_new rt5670_sto2_dmic_mux = SOC_DAPM_ENUM("Stereo2 DMIC source", rt5670_stereo2_dmic_enum); -/* MX-27 [0] */ -static const char * const rt5670_stereo_dmic3_src[] = { - "DMIC3", "PDM ADC" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo_dmic3_enum, RT5670_STO1_ADC_MIXER, - RT5670_DMIC3_SRC_SFT, rt5670_stereo_dmic3_src); - -static const struct snd_kcontrol_new rt5670_sto_dmic3_mux = - SOC_DAPM_ENUM("Stereo DMIC3 source", rt5670_stereo_dmic3_enum); - /* Mono ADC source */ /* MX-28 [12] */ static const char * const rt5670_mono_adc_l1_src[] = { @@ -1334,17 +1291,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_in_enum, RT5670_DIG_INF1_DATA, static const struct snd_kcontrol_new rt5670_if2_adc_in_mux = SOC_DAPM_ENUM("IF2 ADC IN source", rt5670_if2_adc_in_enum); -/* MX-30 [5:4] */ -static const char * const rt5670_if4_adc_in_src[] = { - "IF_ADC1", "IF_ADC2", "IF_ADC3" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_if4_adc_in_enum, RT5670_DIG_INF2_DATA, - RT5670_IF4_ADC_IN_SFT, rt5670_if4_adc_in_src); - -static const struct snd_kcontrol_new rt5670_if4_adc_in_mux = - SOC_DAPM_ENUM("IF4 ADC IN source", rt5670_if4_adc_in_enum); - /* MX-31 [15] [13] [11] [9] */ static const char * const rt5670_pdm_src[] = { "Mono DAC", "Stereo DAC" -- cgit v1.2.3-58-ga151 From 7c3727ba7de2b94a066e38776660e648fa4ed28a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:35 -0600 Subject: ASoC: max98383: fix boolean assignments to true/false Reported by Coccinelle: sound/soc/codecs/max98373.c:411:2-20: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98373.c:922:2-27: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98373.c:924:2-27: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 9c8616a7b61c..528695cd6a1c 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -408,7 +408,7 @@ static int max98373_dac_event(struct snd_soc_dapm_widget *w, regmap_update_bits(max98373->regmap, MAX98373_R20FF_GLOBAL_SHDN, MAX98373_GLOBAL_EN_MASK, 0); - max98373->tdm_mode = 0; + max98373->tdm_mode = false; break; default: return 0; @@ -919,9 +919,9 @@ static int max98373_i2c_probe(struct i2c_client *i2c, /* update interleave mode info */ if (device_property_read_bool(&i2c->dev, "maxim,interleave_mode")) - max98373->interleave_mode = 1; + max98373->interleave_mode = true; else - max98373->interleave_mode = 0; + max98373->interleave_mode = false; /* regmap initialization */ -- cgit v1.2.3-58-ga151 From 3c17bcfd35bca1bee34709e7509646b5bc88643f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:37 -0600 Subject: ASoC: cs4271: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/cs4271.c:226:2-16: WARNING: Assignment of bool to 0/1 sound/soc/codecs/cs4271.c:229:2-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/cs4271.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 849fdb2cb260..1104830edaf8 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -223,10 +223,10 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (format & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - cs4271->master = 0; + cs4271->master = false; break; case SND_SOC_DAIFMT_CBM_CFM: - cs4271->master = 1; + cs4271->master = true; val |= CS4271_MODE1_MASTER; break; default: -- cgit v1.2.3-58-ga151 From b793a1e4ebad5c9066f404dee13fec875fb9b4e5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:38 -0600 Subject: ASoC: rt274: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt274.c:958:6-8: WARNING: Comparison to bool sound/soc/codecs/rt274.c:961:6-9: WARNING: Comparison to bool sound/soc/codecs/rt274.c:384:5-7: WARNING: Comparison to bool sound/soc/codecs/rt274.c:387:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt274.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index e2855ab9a2c6..9e88f7b25d38 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -381,10 +381,10 @@ static void rt274_jack_detect_work(struct work_struct *work) if (rt274_jack_detect(rt274, &hp, &mic) < 0) return; - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt274->jack, status, @@ -955,10 +955,10 @@ static irqreturn_t rt274_irq(int irq, void *data) ret = rt274_jack_detect(rt274, &hp, &mic); if (ret == 0) { - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt274->jack, status, -- cgit v1.2.3-58-ga151 From af3b2b54cb294b997ad9a2a88ed3c6c9af7d03c0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:39 -0600 Subject: ASoc: rt286: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt286.c:927:5-7: WARNING: Comparison to bool sound/soc/codecs/rt286.c:930:5-8: WARNING: Comparison to bool sound/soc/codecs/rt286.c:299:5-7: WARNING: Comparison to bool sound/soc/codecs/rt286.c:302:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 0b0f748bffbe..c9457c247a03 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -296,10 +296,10 @@ static void rt286_jack_detect_work(struct work_struct *work) rt286_jack_detect(rt286, &hp, &mic); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt286->jack, status, @@ -924,10 +924,10 @@ static irqreturn_t rt286_irq(int irq, void *data) /* Clear IRQ */ regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x1, 0x1); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt286->jack, status, -- cgit v1.2.3-58-ga151 From e0a99927ff5f395f24e09e6297858cd2006793f7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:40 -0600 Subject: ASoC: rt5640: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/rt5640.c:980:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5640.c:984:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5640.c:2825:1-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index fc530481a6e4..b3580ecadecf 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -977,11 +977,11 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: rt5640_pmu_depop(component); - rt5640->hp_mute = 0; + rt5640->hp_mute = false; break; case SND_SOC_DAPM_PRE_PMD: - rt5640->hp_mute = 1; + rt5640->hp_mute = true; msleep(70); break; @@ -2822,7 +2822,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, RT5640_MCLK_DET, RT5640_MCLK_DET); - rt5640->hp_mute = 1; + rt5640->hp_mute = true; rt5640->irq = i2c->irq; INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work); INIT_WORK(&rt5640->jack_work, rt5640_jack_work); -- cgit v1.2.3-58-ga151 From 091cd877d8d6b2b934d565134172db771907d50a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:41 -0600 Subject: ASoC: max98927: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/max98927.c:508:2-20: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:889:3-28: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:891:3-28: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:893:2-27: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/max98927.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 065303a46535..e53d2007f3be 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -505,7 +505,7 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - max98927->tdm_mode = 0; + max98927->tdm_mode = false; break; case SND_SOC_DAPM_POST_PMU: regmap_update_bits(max98927->regmap, @@ -886,11 +886,11 @@ static int max98927_i2c_probe(struct i2c_client *i2c, if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode", &value)) { if (value > 0) - max98927->interleave_mode = 1; + max98927->interleave_mode = true; else - max98927->interleave_mode = 0; + max98927->interleave_mode = false; } else - max98927->interleave_mode = 0; + max98927->interleave_mode = false; /* regmap initialization */ max98927->regmap -- cgit v1.2.3-58-ga151 From 577dc32f9a6fc20cd404e0eb965659e9271c78be Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:42 -0600 Subject: ASoC: rt5651: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/rt5651.c:750:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5651.c:754:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5651.c:2192:1-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index b7ba64350a07..3882e238ff99 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -747,11 +747,11 @@ static int rt5651_hp_event(struct snd_soc_dapm_widget *w, RT5651_HP_CP_PD | RT5651_HP_SG_EN); regmap_update_bits(rt5651->regmap, RT5651_PR_BASE + RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400); - rt5651->hp_mute = 0; + rt5651->hp_mute = false; break; case SND_SOC_DAPM_PRE_PMD: - rt5651->hp_mute = 1; + rt5651->hp_mute = true; usleep_range(70000, 75000); break; @@ -2189,7 +2189,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); rt5651->irq = i2c->irq; - rt5651->hp_mute = 1; + rt5651->hp_mute = true; INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work); INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); -- cgit v1.2.3-58-ga151 From 290da7a7e349566f0e1541b14f25b722f58f236b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:43 -0600 Subject: ASoC: nau8824: fix boolean assignment Reported by Coccinelle: nau8824.c:810:6-12: ERROR: Assignment of bool to non-0/1 constant Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/nau8824.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 468d5143e2c4..87ed3dc496dc 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -807,7 +807,7 @@ static const struct snd_soc_dapm_route nau8824_dapm_routes[] = { static bool nau8824_is_jack_inserted(struct nau8824 *nau8824) { struct snd_soc_jack *jack = nau8824->jack; - bool insert = FALSE; + bool insert = false; if (nau8824->irq && jack) insert = jack->status & SND_JACK_HEADPHONE; -- cgit v1.2.3-58-ga151 From f361ca36802031ae3abf9860a02e1d5931c04b63 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:44 -0600 Subject: ASoC: tscs42xx.c: fix boolean test Reported by Coccinelle: sound/soc/codecs/tscs42xx.c:392:5-31: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/tscs42xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index 7396a6e5277e..27b8c6ba72fa 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -389,7 +389,7 @@ static int dac_event(struct snd_soc_dapm_widget *w, mutex_lock(&tscs42xx->coeff_ram_lock); - if (tscs42xx->coeff_ram_synced == false) { + if (!tscs42xx->coeff_ram_synced) { ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00, COEFF_RAM_COEFF_COUNT); if (ret < 0) -- cgit v1.2.3-58-ga151 From d61780c155e8bef8dceb3ac98d29f79c24e264eb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:45 -0600 Subject: ASoC: mt6351: remove unneeded variable Reported by Coccinelle: mt6351.c:1418:5-8: Unneeded variable: "ret". Return "0" on line 1437 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/mt6351.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c index f73dcd753584..4b3ce01c5a93 100644 --- a/sound/soc/codecs/mt6351.c +++ b/sound/soc/codecs/mt6351.c @@ -1415,8 +1415,6 @@ static const struct snd_soc_dapm_route mt6351_dapm_routes[] = { static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt) { - int ret = 0; - /* Disable CLKSQ 26MHz */ regmap_update_bits(cmpnt->regmap, MT6351_TOP_CLKSQ, 0x0001, 0x0); /* disable AUDGLB */ @@ -1434,7 +1432,7 @@ static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt) /* Reverse the PMIC clock*/ regmap_update_bits(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG2, 0x8000, 0x8000); - return ret; + return 0; } static int mt6351_codec_probe(struct snd_soc_component *cmpnt) -- cgit v1.2.3-58-ga151 From 123c3def3bc5ea9958b8191d8139f610ed972d18 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:46 -0600 Subject: ASoC: da7219: fix endianness issues Reported by Sparse. da7219.c:440:44: warning: cast to restricted __le16 da7219.c:461:13: warning: incorrect type in assignment (different base types) da7219.c:461:13: expected unsigned short [unsigned] [usertype] val da7219.c:461:13: got restricted __le16 [usertype] da7219.c:1451:16: warning: incorrect type in assignment (different base types) da7219.c:1451:16: expected unsigned short [unsigned] [usertype] offset da7219.c:1451:16: got restricted __le16 [usertype] da7219-aad.c:150:37: warning: incorrect type in assignment (different base types) da7219-aad.c:150:37: expected unsigned short [unsigned] [usertype] tonegen_freq_hptest da7219-aad.c:150:37: got restricted __le16 [usertype] da7219-aad.c:157:37: warning: incorrect type in assignment (different base types) da7219-aad.c:157:37: expected unsigned short [unsigned] [usertype] tonegen_freq_hptest da7219-aad.c:157:37: got restricted __le16 [usertype] Cc: Adam Thomson Signed-off-by: Pierre-Louis Bossart Reviewed-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219-aad.c | 2 +- sound/soc/codecs/da7219.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 2c7d5088e6f2..e0964b20a389 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -117,7 +117,7 @@ static void da7219_aad_hptest_work(struct work_struct *work) struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - u16 tonegen_freq_hptest; + __le16 tonegen_freq_hptest; u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8; int report = 0, ret = 0; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index e46e9f4bc994..ce165047b9f9 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -423,7 +423,7 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mixer_ctrl = (struct soc_mixer_control *) kcontrol->private_value; unsigned int reg = mixer_ctrl->reg; - u16 val; + __le16 val; int ret; mutex_lock(&da7219->ctrl_lock); @@ -450,7 +450,7 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mixer_ctrl = (struct soc_mixer_control *) kcontrol->private_value; unsigned int reg = mixer_ctrl->reg; - u16 val; + __le16 val; int ret; /* @@ -1396,7 +1396,7 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, struct snd_soc_component *component = dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); u8 dai_bclks_per_wclk; - u16 offset; + __le16 offset; u32 frame_size; /* No channels enabled so disable TDM, revert to 64-bit frames */ -- cgit v1.2.3-58-ga151 From b468f379e1e01b723825267431d3ba60f824fda2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:47 -0600 Subject: ASoC: da7219: use logical AND Reported by Sparse: da7219.c:841:57: warning: dubious: x & !y Cc: Adam Thomson Signed-off-by: Pierre-Louis Bossart Reviewed-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index ce165047b9f9..513ec0368653 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -838,7 +838,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(50); } - } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock)); + } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock)); if (!srm_lock) dev_warn(component->dev, "SRM failed to lock\n"); -- cgit v1.2.3-58-ga151 From 60b52ed627213d1782e70b9810f5668f61bba3a8 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:48 -0600 Subject: ASoC: rt5645: store eq kcontrol byte in __be The eq parameters binary is stored in __be. However, it is unsigned short in rt5645_eq_param_s{} which will cause incorrect type assignment. So add struct rt5645_eq_param_s_be16{} to store the eq binary and convert it to unsigned short in rt5645->eq_param. Cc: Oder Chiou Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 52ce380c8f3a..9a0751978090 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -401,6 +401,11 @@ struct rt5645_eq_param_s { unsigned short val; }; +struct rt5645_eq_param_s_be16 { + __be16 reg; + __be16 val; +}; + static const char *const rt5645_supply_names[] = { "avdd", "cpvdd", @@ -672,8 +677,8 @@ static int rt5645_hweq_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); - struct rt5645_eq_param_s *eq_param = - (struct rt5645_eq_param_s *)ucontrol->value.bytes.data; + struct rt5645_eq_param_s_be16 *eq_param = + (struct rt5645_eq_param_s_be16 *)ucontrol->value.bytes.data; int i; for (i = 0; i < RT5645_HWEQ_NUM; i++) { @@ -698,36 +703,33 @@ static int rt5645_hweq_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); - struct rt5645_eq_param_s *eq_param = - (struct rt5645_eq_param_s *)ucontrol->value.bytes.data; + struct rt5645_eq_param_s_be16 *eq_param = + (struct rt5645_eq_param_s_be16 *)ucontrol->value.bytes.data; int i; for (i = 0; i < RT5645_HWEQ_NUM; i++) { - eq_param[i].reg = be16_to_cpu(eq_param[i].reg); - eq_param[i].val = be16_to_cpu(eq_param[i].val); + rt5645->eq_param[i].reg = be16_to_cpu(eq_param[i].reg); + rt5645->eq_param[i].val = be16_to_cpu(eq_param[i].val); } /* The final setting of the table should be RT5645_EQ_CTRL2 */ for (i = RT5645_HWEQ_NUM - 1; i >= 0; i--) { - if (eq_param[i].reg == 0) + if (rt5645->eq_param[i].reg == 0) continue; - else if (eq_param[i].reg != RT5645_EQ_CTRL2) + else if (rt5645->eq_param[i].reg != RT5645_EQ_CTRL2) return 0; else break; } for (i = 0; i < RT5645_HWEQ_NUM; i++) { - if (!rt5645_validate_hweq(eq_param[i].reg) && - eq_param[i].reg != 0) + if (!rt5645_validate_hweq(rt5645->eq_param[i].reg) && + rt5645->eq_param[i].reg != 0) return 0; - else if (eq_param[i].reg == 0) + else if (rt5645->eq_param[i].reg == 0) break; } - memcpy(rt5645->eq_param, eq_param, - RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s)); - return 0; } -- cgit v1.2.3-58-ga151 From b8e022e83ba99a0deb27e929033008402f863dd7 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:49 -0600 Subject: ASoC: rl6437a: use __be32 for a __be32 buf The buf in rl6347a_hw_read is __be32. Cc: Oder Chiou Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rl6347a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c index 8f571cf8edd4..c0d729b45277 100644 --- a/sound/soc/codecs/rl6347a.c +++ b/sound/soc/codecs/rl6347a.c @@ -64,8 +64,8 @@ int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value) struct i2c_client *client = context; struct i2c_msg xfer[2]; int ret; - __be32 be_reg; - unsigned int index, vid, buf = 0x0; + __be32 be_reg, buf = 0x0; + unsigned int index, vid; /* handle index registers */ if (reg <= 0xff) { -- cgit v1.2.3-58-ga151 From f0627d006047299e427f026942fed22b111f04f5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:36 -0600 Subject: ASoC: rt298: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt298.c:992:6-8: WARNING: Comparison to bool sound/soc/codecs/rt298.c:995:6-9: WARNING: Comparison to bool sound/soc/codecs/rt298.c:317:5-7: WARNING: Comparison to bool sound/soc/codecs/rt298.c:320:5-8: WARNING: Comparison to bool sound/soc/codecs/rt298.c:348:5-7: WARNING: Comparison to bool sound/soc/codecs/rt298.c:351:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt298.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 06cdba4edfe2..bcf5bab31969 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -314,10 +314,10 @@ static void rt298_jack_detect_work(struct work_struct *work) if (rt298_jack_detect(rt298, &hp, &mic) < 0) return; - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, @@ -345,10 +345,10 @@ int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); rt298_jack_detect(rt298, &hp, &mic); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, @@ -989,10 +989,10 @@ static irqreturn_t rt298_irq(int irq, void *data) regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x1, 0x1); if (ret == 0) { - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, -- cgit v1.2.3-58-ga151 From e147c189c10911def4c3d98aa1111a474a64111c Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 4 Jan 2019 19:55:30 +0100 Subject: ASoC: eliminate left-over from Raumfeld machine driver removal Commit f84a6273dd9107c ("ASoC: pxa: remove raumfeld machine driver") removed the Raumfeld ASoC machine driver but forgot to kill one line in the Makefile. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/pxa/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 0ab2a9dcb720..ea4929d73318 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -30,7 +30,6 @@ snd-soc-magician-objs := magician.o snd-soc-mioa701-objs := mioa701_wm9713.o snd-soc-z2-objs := z2.o snd-soc-imote2-objs := imote2.o -snd-soc-raumfeld-objs := raumfeld.o snd-soc-brownstone-objs := brownstone.o snd-soc-ttc-dkb-objs := ttc-dkb.o -- cgit v1.2.3-58-ga151 From e595da28ecc87e7cec2681c01d5970e31153bddd Mon Sep 17 00:00:00 2001 From: Cosmin Samoila Date: Fri, 4 Jan 2019 09:17:37 +0000 Subject: ASoC: micfil: Add bindings for MICFIL DAI Document the bindings for MICFIL DAI. Signed-off-by: Cosmin-Gabriel Samoila Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl,micfil.txt | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,micfil.txt diff --git a/Documentation/devicetree/bindings/sound/fsl,micfil.txt b/Documentation/devicetree/bindings/sound/fsl,micfil.txt new file mode 100644 index 000000000000..53e227b15277 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,micfil.txt @@ -0,0 +1,32 @@ +NXP MICFIL Digital Audio Interface (MICFIL). + +The MICFIL digital interface provides a 16-bit audio signal from a PDM +microphone bitstream in a configurable output sampling rate. + +Required properties: + + - compatible : Compatible list, contains "fsl,imx8mm-micfil" + + - reg : Offset and length of the register set for the device. + + - interrupts : Contains the micfil interrupts. + + - clocks : Must contain an entry for each entry in clock-names. + + - clock-names : Must include the "ipg_clk" for register access and + "ipg_clk_app" for internal micfil clock. + + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + +Example: +micfil: micfil@30080000 { + compatible = "fsl,imx8mm-micfil"; + reg = <0x0 0x30080000 0x0 0x10000>; + interrupts = , + ; + clocks = <&clk IMX8MM_CLK_PDM_IPG>, + <&clk IMX8MM_CLK_PDM_ROOT>; + clock-names = "ipg_clk", "ipg_clk_app"; + dmas = <&sdma2 24 26 0x80000000>; +}; -- cgit v1.2.3-58-ga151 From 47a70e6fc9a80c8d5ef69e978d25582842f9777f Mon Sep 17 00:00:00 2001 From: Cosmin Samoila Date: Fri, 4 Jan 2019 09:17:38 +0000 Subject: ASoC: Add MICFIL SoC Digital Audio Interface driver. Add Digital Audio Interface driver that convers PDM bitstream to PCM format. Features: - Fixed filtering characteristics for audio application. - Full or partial set of channels operation with individual enable control. - Programmable PDM clock generator. - Programmable decimation rate. - 16-bit signed output result. - Overall stopband attenuation more than 80dB. - Overall passband ripple less than 0.2dB. Signed-off-by: Cosmin-Gabriel Samoila Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 9 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_micfil.c | 826 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_micfil.h | 283 ++++++++++++++++ 4 files changed, 1120 insertions(+) create mode 100644 sound/soc/fsl/fsl_micfil.c create mode 100644 sound/soc/fsl/fsl_micfil.h diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 2e75b5bc5f1d..7b1d9970be8b 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -57,6 +57,15 @@ config SND_SOC_FSL_ESAI This option is only useful for out-of-tree drivers since in-tree drivers select it automatically. +config SND_SOC_FSL_MICFIL + tristate "Pulse Density Modulation Microphone Interface (MICFIL) module support" + select REGMAP_MMIO + select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y if you want to add Pulse Density Modulation microphone + interface (MICFIL) support for NXP. + config SND_SOC_FSL_UTILS tristate diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index de94fa057e24..3c0ff315b971 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -19,6 +19,7 @@ snd-soc-fsl-ssi-y := fsl_ssi.o snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o snd-soc-fsl-spdif-objs := fsl_spdif.o snd-soc-fsl-esai-objs := fsl_esai.o +snd-soc-fsl-micfil-objs := fsl_micfil.o snd-soc-fsl-utils-objs := fsl_utils.o snd-soc-fsl-dma-objs := fsl_dma.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o @@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o +obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c new file mode 100644 index 000000000000..40c07e756481 --- /dev/null +++ b/sound/soc/fsl/fsl_micfil.c @@ -0,0 +1,826 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2018 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_micfil.h" +#include "imx-pcm.h" + +#define FSL_MICFIL_RATES SNDRV_PCM_RATE_8000_48000 +#define FSL_MICFIL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) + +struct fsl_micfil { + struct platform_device *pdev; + struct regmap *regmap; + const struct fsl_micfil_soc_data *soc; + struct clk *mclk; + struct snd_dmaengine_dai_dma_data dma_params_rx; + unsigned int dataline; + char name[32]; + int irq[MICFIL_IRQ_LINES]; + unsigned int mclk_streams; + int quality; /*QUALITY 2-0 bits */ + bool slave_mode; + int channel_gain[8]; +}; + +struct fsl_micfil_soc_data { + unsigned int fifos; + unsigned int fifo_depth; + unsigned int dataline; + bool imx; +}; + +static struct fsl_micfil_soc_data fsl_micfil_imx8mm = { + .imx = true, + .fifos = 8, + .fifo_depth = 8, + .dataline = 0xf, +}; + +static const struct of_device_id fsl_micfil_dt_ids[] = { + { .compatible = "fsl,imx8mm-micfil", .data = &fsl_micfil_imx8mm }, + {} +}; +MODULE_DEVICE_TABLE(of, fsl_micfil_dt_ids); + +/* Table 5. Quality Modes + * Medium 0 0 0 + * High 0 0 1 + * Very Low 2 1 0 0 + * Very Low 1 1 0 1 + * Very Low 0 1 1 0 + * Low 1 1 1 + */ +static const char * const micfil_quality_select_texts[] = { + "Medium", "High", + "N/A", "N/A", + "VLow2", "VLow1", + "VLow0", "Low", +}; + +static const struct soc_enum fsl_micfil_quality_enum = + SOC_ENUM_SINGLE(REG_MICFIL_CTRL2, + MICFIL_CTRL2_QSEL_SHIFT, + ARRAY_SIZE(micfil_quality_select_texts), + micfil_quality_select_texts); + +static DECLARE_TLV_DB_SCALE(gain_tlv, 0, 100, 0); + +static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { + SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0x7, gain_tlv), + SOC_SINGLE_SX_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL, + MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0x7, gain_tlv), + SOC_ENUM_EXT("MICFIL Quality Select", + fsl_micfil_quality_enum, + snd_soc_get_enum_double, snd_soc_put_enum_double), +}; + +static inline int get_pdm_clk(struct fsl_micfil *micfil, + unsigned int rate) +{ + u32 ctrl2_reg; + int qsel, osr; + int bclk; + + regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); + osr = 16 - ((ctrl2_reg & MICFIL_CTRL2_CICOSR_MASK) + >> MICFIL_CTRL2_CICOSR_SHIFT); + + regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); + qsel = ctrl2_reg & MICFIL_CTRL2_QSEL_MASK; + + switch (qsel) { + case MICFIL_HIGH_QUALITY: + bclk = rate * 8 * osr / 2; /* kfactor = 0.5 */ + break; + case MICFIL_MEDIUM_QUALITY: + case MICFIL_VLOW0_QUALITY: + bclk = rate * 4 * osr * 1; /* kfactor = 1 */ + break; + case MICFIL_LOW_QUALITY: + case MICFIL_VLOW1_QUALITY: + bclk = rate * 2 * osr * 2; /* kfactor = 2 */ + break; + case MICFIL_VLOW2_QUALITY: + bclk = rate * osr * 4; /* kfactor = 4 */ + break; + default: + dev_err(&micfil->pdev->dev, + "Please make sure you select a valid quality.\n"); + bclk = -1; + break; + } + + return bclk; +} + +static inline int get_clk_div(struct fsl_micfil *micfil, + unsigned int rate) +{ + u32 ctrl2_reg; + long mclk_rate; + int osr; + int clk_div; + + regmap_read(micfil->regmap, REG_MICFIL_CTRL2, &ctrl2_reg); + osr = 16 - ((ctrl2_reg & MICFIL_CTRL2_CICOSR_MASK) + >> MICFIL_CTRL2_CICOSR_SHIFT); + + mclk_rate = clk_get_rate(micfil->mclk); + + clk_div = mclk_rate / (get_pdm_clk(micfil, rate) * 2); + + return clk_div; +} + +/* The SRES is a self-negated bit which provides the CPU with the + * capability to initialize the PDM Interface module through the + * slave-bus interface. This bit always reads as zero, and this + * bit is only effective when MDIS is cleared + */ +static int fsl_micfil_reset(struct device *dev) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + int ret; + + ret = regmap_update_bits(micfil->regmap, + REG_MICFIL_CTRL1, + MICFIL_CTRL1_MDIS_MASK, + 0); + if (ret) { + dev_err(dev, "failed to clear MDIS bit %d\n", ret); + return ret; + } + + ret = regmap_update_bits(micfil->regmap, + REG_MICFIL_CTRL1, + MICFIL_CTRL1_SRES_MASK, + MICFIL_CTRL1_SRES); + if (ret) { + dev_err(dev, "failed to reset MICFIL: %d\n", ret); + return ret; + } + + return 0; +} + +static int fsl_micfil_set_mclk_rate(struct fsl_micfil *micfil, + unsigned int freq) +{ + struct device *dev = &micfil->pdev->dev; + int ret; + + clk_disable_unprepare(micfil->mclk); + + ret = clk_set_rate(micfil->mclk, freq * 1024); + if (ret) + dev_warn(dev, "failed to set rate (%u): %d\n", + freq * 1024, ret); + + clk_prepare_enable(micfil->mclk); + + return ret; +} + +static int fsl_micfil_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + + if (!micfil) { + dev_err(dai->dev, + "micfil dai priv_data not set\n"); + return -EINVAL; + } + + return 0; +} + +static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + struct device *dev = &micfil->pdev->dev; + int ret; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = fsl_micfil_reset(dev); + if (ret) { + dev_err(dev, "failed to soft reset\n"); + return ret; + } + + /* DMA Interrupt Selection - DISEL bits + * 00 - DMA and IRQ disabled + * 01 - DMA req enabled + * 10 - IRQ enabled + * 11 - reserved + */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_DISEL_MASK, + (1 << MICFIL_CTRL1_DISEL_SHIFT)); + if (ret) { + dev_err(dev, "failed to update DISEL bits\n"); + return ret; + } + + /* Enable the module */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_PDMIEN_MASK, + MICFIL_CTRL1_PDMIEN); + if (ret) { + dev_err(dev, "failed to enable the module\n"); + return ret; + } + + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + /* Disable the module */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_PDMIEN_MASK, + 0); + if (ret) { + dev_err(dev, "failed to enable the module\n"); + return ret; + } + + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_DISEL_MASK, + (0 << MICFIL_CTRL1_DISEL_SHIFT)); + if (ret) { + dev_err(dev, "failed to update DISEL bits\n"); + return ret; + } + break; + default: + return -EINVAL; + } + return 0; +} + +static int fsl_set_clock_params(struct device *dev, unsigned int rate) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + int clk_div; + int ret = 0; + + ret = fsl_micfil_set_mclk_rate(micfil, rate); + if (ret < 0) + dev_err(dev, "failed to set mclk[%lu] to rate %u\n", + clk_get_rate(micfil->mclk), rate); + + /* set CICOSR */ + ret |= regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, + MICFIL_CTRL2_CICOSR_MASK, + MICFIL_CTRL2_OSR_DEFAULT); + if (ret) + dev_err(dev, "failed to set CICOSR in reg 0x%X\n", + REG_MICFIL_CTRL2); + + /* set CLK_DIV */ + clk_div = get_clk_div(micfil, rate); + if (clk_div < 0) + ret = -EINVAL; + + ret |= regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, + MICFIL_CTRL2_CLKDIV_MASK, clk_div); + if (ret) + dev_err(dev, "failed to set CLKDIV in reg 0x%X\n", + REG_MICFIL_CTRL2); + + return ret; +} + +static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); + struct device *dev = &micfil->pdev->dev; + int ret; + + /* 1. Disable the module */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + MICFIL_CTRL1_PDMIEN_MASK, 0); + if (ret) { + dev_err(dev, "failed to disable the module\n"); + return ret; + } + + /* enable channels */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL1, + 0xFF, ((1 << channels) - 1)); + if (ret) { + dev_err(dev, "failed to enable channels %d, reg 0x%X\n", ret, + REG_MICFIL_CTRL1); + return ret; + } + + ret = fsl_set_clock_params(dev, rate); + if (ret < 0) { + dev_err(dev, "Failed to set clock parameters [%d]\n", ret); + return ret; + } + + micfil->dma_params_rx.maxburst = channels * MICFIL_DMA_MAXBURST_RX; + + return 0; +} + +static int fsl_micfil_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + struct device *dev = &micfil->pdev->dev; + + int ret; + + if (!freq) + return 0; + + ret = fsl_micfil_set_mclk_rate(micfil, freq); + if (ret < 0) + dev_err(dev, "failed to set mclk[%lu] to rate %u\n", + clk_get_rate(micfil->mclk), freq); + + return ret; +} + +static struct snd_soc_dai_ops fsl_micfil_dai_ops = { + .startup = fsl_micfil_startup, + .trigger = fsl_micfil_trigger, + .hw_params = fsl_micfil_hw_params, + .set_sysclk = fsl_micfil_set_dai_sysclk, +}; + +static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) +{ + struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); + struct device *dev = cpu_dai->dev; + unsigned int val; + int ret; + int i; + + /* set qsel to medium */ + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, + MICFIL_CTRL2_QSEL_MASK, MICFIL_MEDIUM_QUALITY); + if (ret) { + dev_err(dev, "failed to set quality mode bits, reg 0x%X\n", + REG_MICFIL_CTRL2); + return ret; + } + + /* set default gain to max_gain */ + regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x77777777); + for (i = 0; i < 8; i++) + micfil->channel_gain[i] = 0xF; + + snd_soc_dai_init_dma_data(cpu_dai, NULL, + &micfil->dma_params_rx); + + /* FIFO Watermark Control - FIFOWMK*/ + val = MICFIL_FIFO_CTRL_FIFOWMK(micfil->soc->fifo_depth) - 1; + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_FIFO_CTRL, + MICFIL_FIFO_CTRL_FIFOWMK_MASK, + val); + if (ret) { + dev_err(dev, "failed to set FIFOWMK\n"); + return ret; + } + + snd_soc_dai_set_drvdata(cpu_dai, micfil); + + return 0; +} + +static struct snd_soc_dai_driver fsl_micfil_dai = { + .probe = fsl_micfil_dai_probe, + .capture = { + .stream_name = "CPU-Capture", + .channels_min = 1, + .channels_max = 8, + .rates = FSL_MICFIL_RATES, + .formats = FSL_MICFIL_FORMATS, + }, + .ops = &fsl_micfil_dai_ops, +}; + +static const struct snd_soc_component_driver fsl_micfil_component = { + .name = "fsl-micfil-dai", + .controls = fsl_micfil_snd_controls, + .num_controls = ARRAY_SIZE(fsl_micfil_snd_controls), + +}; + +/* REGMAP */ +static const struct reg_default fsl_micfil_reg_defaults[] = { + {REG_MICFIL_CTRL1, 0x00000000}, + {REG_MICFIL_CTRL2, 0x00000000}, + {REG_MICFIL_STAT, 0x00000000}, + {REG_MICFIL_FIFO_CTRL, 0x00000007}, + {REG_MICFIL_FIFO_STAT, 0x00000000}, + {REG_MICFIL_DATACH0, 0x00000000}, + {REG_MICFIL_DATACH1, 0x00000000}, + {REG_MICFIL_DATACH2, 0x00000000}, + {REG_MICFIL_DATACH3, 0x00000000}, + {REG_MICFIL_DATACH4, 0x00000000}, + {REG_MICFIL_DATACH5, 0x00000000}, + {REG_MICFIL_DATACH6, 0x00000000}, + {REG_MICFIL_DATACH7, 0x00000000}, + {REG_MICFIL_DC_CTRL, 0x00000000}, + {REG_MICFIL_OUT_CTRL, 0x00000000}, + {REG_MICFIL_OUT_STAT, 0x00000000}, + {REG_MICFIL_VAD0_CTRL1, 0x00000000}, + {REG_MICFIL_VAD0_CTRL2, 0x000A0000}, + {REG_MICFIL_VAD0_STAT, 0x00000000}, + {REG_MICFIL_VAD0_SCONFIG, 0x00000000}, + {REG_MICFIL_VAD0_NCONFIG, 0x80000000}, + {REG_MICFIL_VAD0_NDATA, 0x00000000}, + {REG_MICFIL_VAD0_ZCD, 0x00000004}, +}; + +static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_MICFIL_CTRL1: + case REG_MICFIL_CTRL2: + case REG_MICFIL_STAT: + case REG_MICFIL_FIFO_CTRL: + case REG_MICFIL_FIFO_STAT: + case REG_MICFIL_DATACH0: + case REG_MICFIL_DATACH1: + case REG_MICFIL_DATACH2: + case REG_MICFIL_DATACH3: + case REG_MICFIL_DATACH4: + case REG_MICFIL_DATACH5: + case REG_MICFIL_DATACH6: + case REG_MICFIL_DATACH7: + case REG_MICFIL_DC_CTRL: + case REG_MICFIL_OUT_CTRL: + case REG_MICFIL_OUT_STAT: + case REG_MICFIL_VAD0_CTRL1: + case REG_MICFIL_VAD0_CTRL2: + case REG_MICFIL_VAD0_STAT: + case REG_MICFIL_VAD0_SCONFIG: + case REG_MICFIL_VAD0_NCONFIG: + case REG_MICFIL_VAD0_NDATA: + case REG_MICFIL_VAD0_ZCD: + return true; + default: + return false; + } +} + +static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_MICFIL_CTRL1: + case REG_MICFIL_CTRL2: + case REG_MICFIL_STAT: /* Write 1 to Clear */ + case REG_MICFIL_FIFO_CTRL: + case REG_MICFIL_FIFO_STAT: /* Write 1 to Clear */ + case REG_MICFIL_DC_CTRL: + case REG_MICFIL_OUT_CTRL: + case REG_MICFIL_OUT_STAT: /* Write 1 to Clear */ + case REG_MICFIL_VAD0_CTRL1: + case REG_MICFIL_VAD0_CTRL2: + case REG_MICFIL_VAD0_STAT: /* Write 1 to Clear */ + case REG_MICFIL_VAD0_SCONFIG: + case REG_MICFIL_VAD0_NCONFIG: + case REG_MICFIL_VAD0_ZCD: + return true; + default: + return false; + } +} + +static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_MICFIL_STAT: + case REG_MICFIL_DATACH0: + case REG_MICFIL_DATACH1: + case REG_MICFIL_DATACH2: + case REG_MICFIL_DATACH3: + case REG_MICFIL_DATACH4: + case REG_MICFIL_DATACH5: + case REG_MICFIL_DATACH6: + case REG_MICFIL_DATACH7: + case REG_MICFIL_VAD0_STAT: + case REG_MICFIL_VAD0_NDATA: + return true; + default: + return false; + } +} + +static const struct regmap_config fsl_micfil_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .max_register = REG_MICFIL_VAD0_ZCD, + .reg_defaults = fsl_micfil_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(fsl_micfil_reg_defaults), + .readable_reg = fsl_micfil_readable_reg, + .volatile_reg = fsl_micfil_volatile_reg, + .writeable_reg = fsl_micfil_writeable_reg, + .cache_type = REGCACHE_RBTREE, +}; + +/* END OF REGMAP */ + +static irqreturn_t micfil_isr(int irq, void *devid) +{ + struct fsl_micfil *micfil = (struct fsl_micfil *)devid; + struct platform_device *pdev = micfil->pdev; + u32 stat_reg; + u32 fifo_stat_reg; + u32 ctrl1_reg; + bool dma_enabled; + int i; + + regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); + regmap_read(micfil->regmap, REG_MICFIL_CTRL1, &ctrl1_reg); + regmap_read(micfil->regmap, REG_MICFIL_FIFO_STAT, &fifo_stat_reg); + + dma_enabled = MICFIL_DMA_ENABLED(ctrl1_reg); + + /* Channel 0-7 Output Data Flags */ + for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) { + if (stat_reg & MICFIL_STAT_CHXF_MASK(i)) + dev_dbg(&pdev->dev, + "Data available in Data Channel %d\n", i); + /* if DMA is not enabled, field must be written with 1 + * to clear + */ + if (!dma_enabled) + regmap_write_bits(micfil->regmap, + REG_MICFIL_STAT, + MICFIL_STAT_CHXF_MASK(i), + 1); + } + + for (i = 0; i < MICFIL_FIFO_NUM; i++) { + if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_OVER_MASK(i)) + dev_dbg(&pdev->dev, + "FIFO Overflow Exception flag for channel %d\n", + i); + + if (fifo_stat_reg & MICFIL_FIFO_STAT_FIFOX_UNDER_MASK(i)) + dev_dbg(&pdev->dev, + "FIFO Underflow Exception flag for channel %d\n", + i); + } + + return IRQ_HANDLED; +} + +static irqreturn_t micfil_err_isr(int irq, void *devid) +{ + struct fsl_micfil *micfil = (struct fsl_micfil *)devid; + struct platform_device *pdev = micfil->pdev; + u32 stat_reg; + + regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); + + if (stat_reg & MICFIL_STAT_BSY_FIL_MASK) + dev_dbg(&pdev->dev, "isr: Decimation Filter is running\n"); + + if (stat_reg & MICFIL_STAT_FIR_RDY_MASK) + dev_dbg(&pdev->dev, "isr: FIR Filter Data ready\n"); + + if (stat_reg & MICFIL_STAT_LOWFREQF_MASK) { + dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n"); + regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, + MICFIL_STAT_LOWFREQF_MASK, 1); + } + + return IRQ_HANDLED; +} + +static int fsl_micfil_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id; + struct fsl_micfil *micfil; + struct resource *res; + void __iomem *regs; + int ret, i; + unsigned long irqflag = 0; + + micfil = devm_kzalloc(&pdev->dev, sizeof(*micfil), GFP_KERNEL); + if (!micfil) + return -ENOMEM; + + micfil->pdev = pdev; + strncpy(micfil->name, np->name, sizeof(micfil->name) - 1); + + of_id = of_match_device(fsl_micfil_dt_ids, &pdev->dev); + if (!of_id || !of_id->data) + return -EINVAL; + + micfil->soc = of_id->data; + + /* ipg_clk is used to control the registers + * ipg_clk_app is used to operate the filter + */ + micfil->mclk = devm_clk_get(&pdev->dev, "ipg_clk_app"); + if (IS_ERR(micfil->mclk)) { + dev_err(&pdev->dev, "failed to get core clock: %ld\n", + PTR_ERR(micfil->mclk)); + return PTR_ERR(micfil->mclk); + } + + /* init regmap */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + micfil->regmap = devm_regmap_init_mmio_clk(&pdev->dev, + "ipg_clk", + regs, + &fsl_micfil_regmap_config); + if (IS_ERR(micfil->regmap)) { + dev_err(&pdev->dev, "failed to init MICFIL regmap: %ld\n", + PTR_ERR(micfil->regmap)); + return PTR_ERR(micfil->regmap); + } + + /* dataline mask for RX */ + ret = of_property_read_u32_index(np, + "fsl,dataline", + 0, + &micfil->dataline); + if (ret) + micfil->dataline = 1; + + if (micfil->dataline & ~micfil->soc->dataline) { + dev_err(&pdev->dev, "dataline setting error, Mask is 0x%X\n", + micfil->soc->dataline); + return -EINVAL; + } + + /* get IRQs */ + for (i = 0; i < MICFIL_IRQ_LINES; i++) { + micfil->irq[i] = platform_get_irq(pdev, i); + dev_err(&pdev->dev, "GET IRQ: %d\n", micfil->irq[i]); + if (micfil->irq[i] < 0) { + dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); + return micfil->irq[i]; + } + } + + if (of_property_read_bool(np, "fsl,shared-interrupt")) + irqflag = IRQF_SHARED; + + /* Digital Microphone interface interrupt - IRQ 109 */ + ret = devm_request_irq(&pdev->dev, micfil->irq[0], + micfil_isr, irqflag, + micfil->name, micfil); + if (ret) { + dev_err(&pdev->dev, "failed to claim mic interface irq %u\n", + micfil->irq[0]); + return ret; + } + + /* Digital Microphone interface error interrupt - IRQ 110 */ + ret = devm_request_irq(&pdev->dev, micfil->irq[1], + micfil_err_isr, irqflag, + micfil->name, micfil); + if (ret) { + dev_err(&pdev->dev, "failed to claim mic interface error irq %u\n", + micfil->irq[1]); + return ret; + } + + micfil->dma_params_rx.chan_name = "rx"; + micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0; + micfil->dma_params_rx.maxburst = MICFIL_DMA_MAXBURST_RX; + + + platform_set_drvdata(pdev, micfil); + + pm_runtime_enable(&pdev->dev); + + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_micfil_component, + &fsl_micfil_dai, 1); + if (ret) { + dev_err(&pdev->dev, "failed to register component %s\n", + fsl_micfil_component.name); + return ret; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + dev_err(&pdev->dev, "failed to pcm register\n"); + + return ret; +} + +#ifdef CONFIG_PM +static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + + regcache_cache_only(micfil->regmap, true); + + clk_disable_unprepare(micfil->mclk); + + return 0; +} + +static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev) +{ + struct fsl_micfil *micfil = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(micfil->mclk); + if (ret < 0) + return ret; + + regcache_cache_only(micfil->regmap, false); + regcache_mark_dirty(micfil->regmap); + regcache_sync(micfil->regmap); + + return 0; +} +#endif /* CONFIG_PM*/ + +#ifdef CONFIG_PM_SLEEP +static int __maybe_unused fsl_micfil_suspend(struct device *dev) +{ + pm_runtime_force_suspend(dev); + + return 0; +} + +static int __maybe_unused fsl_micfil_resume(struct device *dev) +{ + pm_runtime_force_resume(dev); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops fsl_micfil_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend, + fsl_micfil_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(fsl_micfil_suspend, + fsl_micfil_resume) +}; + +static struct platform_driver fsl_micfil_driver = { + .probe = fsl_micfil_probe, + .driver = { + .name = "fsl-micfil-dai", + .pm = &fsl_micfil_pm_ops, + .of_match_table = fsl_micfil_dt_ids, + }, +}; +module_platform_driver(fsl_micfil_driver); + +MODULE_AUTHOR("Cosmin-Gabriel Samoila "); +MODULE_DESCRIPTION("NXP PDM Microphone Interface (MICFIL) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h new file mode 100644 index 000000000000..bac825c3135a --- /dev/null +++ b/sound/soc/fsl/fsl_micfil.h @@ -0,0 +1,283 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PDM Microphone Interface for the NXP i.MX SoC + * Copyright 2018 NXP + */ + +#ifndef _FSL_MICFIL_H +#define _FSL_MICFIL_H + +/* MICFIL Register Map */ +#define REG_MICFIL_CTRL1 0x00 +#define REG_MICFIL_CTRL2 0x04 +#define REG_MICFIL_STAT 0x08 +#define REG_MICFIL_FIFO_CTRL 0x10 +#define REG_MICFIL_FIFO_STAT 0x14 +#define REG_MICFIL_DATACH0 0x24 +#define REG_MICFIL_DATACH1 0x28 +#define REG_MICFIL_DATACH2 0x2C +#define REG_MICFIL_DATACH3 0x30 +#define REG_MICFIL_DATACH4 0x34 +#define REG_MICFIL_DATACH5 0x38 +#define REG_MICFIL_DATACH6 0x3C +#define REG_MICFIL_DATACH7 0x40 +#define REG_MICFIL_DC_CTRL 0x64 +#define REG_MICFIL_OUT_CTRL 0x74 +#define REG_MICFIL_OUT_STAT 0x7C +#define REG_MICFIL_VAD0_CTRL1 0x90 +#define REG_MICFIL_VAD0_CTRL2 0x94 +#define REG_MICFIL_VAD0_STAT 0x98 +#define REG_MICFIL_VAD0_SCONFIG 0x9C +#define REG_MICFIL_VAD0_NCONFIG 0xA0 +#define REG_MICFIL_VAD0_NDATA 0xA4 +#define REG_MICFIL_VAD0_ZCD 0xA8 + +/* MICFIL Control Register 1 -- REG_MICFILL_CTRL1 0x00 */ +#define MICFIL_CTRL1_MDIS_SHIFT 31 +#define MICFIL_CTRL1_MDIS_MASK BIT(MICFIL_CTRL1_MDIS_SHIFT) +#define MICFIL_CTRL1_MDIS BIT(MICFIL_CTRL1_MDIS_SHIFT) +#define MICFIL_CTRL1_DOZEN_SHIFT 30 +#define MICFIL_CTRL1_DOZEN_MASK BIT(MICFIL_CTRL1_DOZEN_SHIFT) +#define MICFIL_CTRL1_DOZEN BIT(MICFIL_CTRL1_DOZEN_SHIFT) +#define MICFIL_CTRL1_PDMIEN_SHIFT 29 +#define MICFIL_CTRL1_PDMIEN_MASK BIT(MICFIL_CTRL1_PDMIEN_SHIFT) +#define MICFIL_CTRL1_PDMIEN BIT(MICFIL_CTRL1_PDMIEN_SHIFT) +#define MICFIL_CTRL1_DBG_SHIFT 28 +#define MICFIL_CTRL1_DBG_MASK BIT(MICFIL_CTRL1_DBG_SHIFT) +#define MICFIL_CTRL1_DBG BIT(MICFIL_CTRL1_DBG_SHIFT) +#define MICFIL_CTRL1_SRES_SHIFT 27 +#define MICFIL_CTRL1_SRES_MASK BIT(MICFIL_CTRL1_SRES_SHIFT) +#define MICFIL_CTRL1_SRES BIT(MICFIL_CTRL1_SRES_SHIFT) +#define MICFIL_CTRL1_DBGE_SHIFT 26 +#define MICFIL_CTRL1_DBGE_MASK BIT(MICFIL_CTRL1_DBGE_SHIFT) +#define MICFIL_CTRL1_DBGE BIT(MICFIL_CTRL1_DBGE_SHIFT) +#define MICFIL_CTRL1_DISEL_SHIFT 24 +#define MICFIL_CTRL1_DISEL_WIDTH 2 +#define MICFIL_CTRL1_DISEL_MASK ((BIT(MICFIL_CTRL1_DISEL_WIDTH) - 1) \ + << MICFIL_CTRL1_DISEL_SHIFT) +#define MICFIL_CTRL1_DISEL(v) (((v) << MICFIL_CTRL1_DISEL_SHIFT) \ + & MICFIL_CTRL1_DISEL_MASK) +#define MICFIL_CTRL1_ERREN_SHIFT 23 +#define MICFIL_CTRL1_ERREN_MASK BIT(MICFIL_CTRL1_ERREN_SHIFT) +#define MICFIL_CTRL1_ERREN BIT(MICFIL_CTRL1_ERREN_SHIFT) +#define MICFIL_CTRL1_CHEN_SHIFT 0 +#define MICFIL_CTRL1_CHEN_WIDTH 8 +#define MICFIL_CTRL1_CHEN_MASK(x) (BIT(x) << MICFIL_CTRL1_CHEN_SHIFT) +#define MICFIL_CTRL1_CHEN(x) (MICFIL_CTRL1_CHEN_MASK(x)) + +/* MICFIL Control Register 2 -- REG_MICFILL_CTRL2 0x04 */ +#define MICFIL_CTRL2_QSEL_SHIFT 25 +#define MICFIL_CTRL2_QSEL_WIDTH 3 +#define MICFIL_CTRL2_QSEL_MASK ((BIT(MICFIL_CTRL2_QSEL_WIDTH) - 1) \ + << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_HIGH_QUALITY BIT(MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_MEDIUM_QUALITY (0 << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_LOW_QUALITY (7 << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_VLOW0_QUALITY (6 << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_VLOW1_QUALITY (5 << MICFIL_CTRL2_QSEL_SHIFT) +#define MICFIL_VLOW2_QUALITY (4 << MICFIL_CTRL2_QSEL_SHIFT) + +#define MICFIL_CTRL2_CICOSR_SHIFT 16 +#define MICFIL_CTRL2_CICOSR_WIDTH 4 +#define MICFIL_CTRL2_CICOSR_MASK ((BIT(MICFIL_CTRL2_CICOSR_WIDTH) - 1) \ + << MICFIL_CTRL2_CICOSR_SHIFT) +#define MICFIL_CTRL2_CICOSR(v) (((v) << MICFIL_CTRL2_CICOSR_SHIFT) \ + & MICFIL_CTRL2_CICOSR_MASK) +#define MICFIL_CTRL2_CLKDIV_SHIFT 0 +#define MICFIL_CTRL2_CLKDIV_WIDTH 8 +#define MICFIL_CTRL2_CLKDIV_MASK ((BIT(MICFIL_CTRL2_CLKDIV_WIDTH) - 1) \ + << MICFIL_CTRL2_CLKDIV_SHIFT) +#define MICFIL_CTRL2_CLKDIV(v) (((v) << MICFIL_CTRL2_CLKDIV_SHIFT) \ + & MICFIL_CTRL2_CLKDIV_MASK) + +/* MICFIL Status Register -- REG_MICFIL_STAT 0x08 */ +#define MICFIL_STAT_BSY_FIL_SHIFT 31 +#define MICFIL_STAT_BSY_FIL_MASK BIT(MICFIL_STAT_BSY_FIL_SHIFT) +#define MICFIL_STAT_BSY_FIL BIT(MICFIL_STAT_BSY_FIL_SHIFT) +#define MICFIL_STAT_FIR_RDY_SHIFT 30 +#define MICFIL_STAT_FIR_RDY_MASK BIT(MICFIL_STAT_FIR_RDY_SHIFT) +#define MICFIL_STAT_FIR_RDY BIT(MICFIL_STAT_FIR_RDY_SHIFT) +#define MICFIL_STAT_LOWFREQF_SHIFT 29 +#define MICFIL_STAT_LOWFREQF_MASK BIT(MICFIL_STAT_LOWFREQF_SHIFT) +#define MICFIL_STAT_LOWFREQF BIT(MICFIL_STAT_LOWFREQF_SHIFT) +#define MICFIL_STAT_CHXF_SHIFT(v) (v) +#define MICFIL_STAT_CHXF_MASK(v) BIT(MICFIL_STAT_CHXF_SHIFT(v)) +#define MICFIL_STAT_CHXF(v) BIT(MICFIL_STAT_CHXF_SHIFT(v)) + +/* MICFIL FIFO Control Register -- REG_MICFIL_FIFO_CTRL 0x10 */ +#define MICFIL_FIFO_CTRL_FIFOWMK_SHIFT 0 +#define MICFIL_FIFO_CTRL_FIFOWMK_WIDTH 3 +#define MICFIL_FIFO_CTRL_FIFOWMK_MASK ((BIT(MICFIL_FIFO_CTRL_FIFOWMK_WIDTH) - 1) \ + << MICFIL_FIFO_CTRL_FIFOWMK_SHIFT) +#define MICFIL_FIFO_CTRL_FIFOWMK(v) (((v) << MICFIL_FIFO_CTRL_FIFOWMK_SHIFT) \ + & MICFIL_FIFO_CTRL_FIFOWMK_MASK) + +/* MICFIL FIFO Status Register -- REG_MICFIL_FIFO_STAT 0x14 */ +#define MICFIL_FIFO_STAT_FIFOX_OVER_SHIFT(v) (v) +#define MICFIL_FIFO_STAT_FIFOX_OVER_MASK(v) BIT(MICFIL_FIFO_STAT_FIFOX_OVER_SHIFT(v)) +#define MICFIL_FIFO_STAT_FIFOX_UNDER_SHIFT(v) ((v) + 8) +#define MICFIL_FIFO_STAT_FIFOX_UNDER_MASK(v) BIT(MICFIL_FIFO_STAT_FIFOX_UNDER_SHIFT(v)) + +/* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/ +#define MICFIL_VAD0_CTRL1_CHSEL_SHIFT 24 +#define MICFIL_VAD0_CTRL1_CHSEL_WIDTH 3 +#define MICFIL_VAD0_CTRL1_CHSEL_MASK ((BIT(MICFIL_VAD0_CTRL1_CHSEL_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL1_CHSEL_SHIFT) +#define MICFIL_VAD0_CTRL1_CHSEL(v) (((v) << MICFIL_VAD0_CTRL1_CHSEL_SHIFT) \ + & MICFIL_VAD0_CTRL1_CHSEL_MASK) +#define MICFIL_VAD0_CTRL1_CICOSR_SHIFT 16 +#define MICFIL_VAD0_CTRL1_CICOSR_WIDTH 4 +#define MICFIL_VAD0_CTRL1_CICOSR_MASK ((BIT(MICFIL_VAD0_CTRL1_CICOSR_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL1_CICOSR_SHIFT) +#define MICFIL_VAD0_CTRL1_CICOSR(v) (((v) << MICFIL_VAD0_CTRL1_CICOSR_SHIFT) \ + & MICFIL_VAD0_CTRL1_CICOSR_MASK) +#define MICFIL_VAD0_CTRL1_INITT_SHIFT 8 +#define MICFIL_VAD0_CTRL1_INITT_WIDTH 5 +#define MICFIL_VAD0_CTRL1_INITT_MASK ((BIT(MICFIL_VAD0_CTRL1_INITT_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL1_INITT_SHIFT) +#define MICFIL_VAD0_CTRL1_INITT(v) (((v) << MICFIL_VAD0_CTRL1_INITT_SHIFT) \ + & MICFIL_VAD0_CTRL1_INITT_MASK) +#define MICFIL_VAD0_CTRL1_ST10_SHIFT 4 +#define MICFIL_VAD0_CTRL1_ST10_MASK BIT(MICFIL_VAD0_CTRL1_ST10_SHIFT) +#define MICFIL_VAD0_CTRL1_ST10 BIT(MICFIL_VAD0_CTRL1_ST10_SHIFT) +#define MICFIL_VAD0_CTRL1_ERIE_SHIFT 3 +#define MICFIL_VAD0_CTRL1_ERIE_MASK BIT(MICFIL_VAD0_CTRL1_ERIE_SHIFT) +#define MICFIL_VAD0_CTRL1_ERIE BIT(MICFIL_VAD0_CTRL1_ERIE_SHIFT) +#define MICFIL_VAD0_CTRL1_IE_SHIFT 2 +#define MICFIL_VAD0_CTRL1_IE_MASK BIT(MICFIL_VAD0_CTRL1_IE_SHIFT) +#define MICFIL_VAD0_CTRL1_IE BIT(MICFIL_VAD0_CTRL1_IE_SHIFT) +#define MICFIL_VAD0_CTRL1_RST_SHIFT 1 +#define MICFIL_VAD0_CTRL1_RST_MASK BIT(MICFIL_VAD0_CTRL1_RST_SHIFT) +#define MICFIL_VAD0_CTRL1_RST BIT(MICFIL_VAD0_CTRL1_RST_SHIFT) +#define MICFIL_VAD0_CTRL1_EN_SHIFT 0 +#define MICFIL_VAD0_CTRL1_EN_MASK BIT(MICFIL_VAD0_CTRL1_EN_SHIFT) +#define MICFIL_VAD0_CTRL1_EN BIT(MICFIL_VAD0_CTRL1_EN_SHIFT) + +/* MICFIL HWVAD0 Control 2 Register -- REG_MICFIL_VAD0_CTRL2*/ +#define MICFIL_VAD0_CTRL2_FRENDIS_SHIFT 31 +#define MICFIL_VAD0_CTRL2_FRENDIS_MASK BIT(MICFIL_VAD0_CTRL2_FRENDIS_SHIFT) +#define MICFIL_VAD0_CTRL2_FRENDIS BIT(MICFIL_VAD0_CTRL2_FRENDIS_SHIFT) +#define MICFIL_VAD0_CTRL2_PREFEN_SHIFT 30 +#define MICFIL_VAD0_CTRL2_PREFEN_MASK BIT(MICFIL_VAD0_CTRL2_PREFEN_SHIFT) +#define MICFIL_VAD0_CTRL2_PREFEN BIT(MICFIL_VAD0_CTRL2_PREFEN_SHIFT) +#define MICFIL_VAD0_CTRL2_FOUTDIS_SHIFT 28 +#define MICFIL_VAD0_CTRL2_FOUTDIS_MASK BIT(MICFIL_VAD0_CTRL2_FOUTDIS_SHIFT) +#define MICFIL_VAD0_CTRL2_FOUTDIS BIT(MICFIL_VAD0_CTRL2_FOUTDIS_SHIFT) +#define MICFIL_VAD0_CTRL2_FRAMET_SHIFT 16 +#define MICFIL_VAD0_CTRL2_FRAMET_WIDTH 6 +#define MICFIL_VAD0_CTRL2_FRAMET_MASK ((BIT(MICFIL_VAD0_CTRL2_FRAMET_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL2_FRAMET_SHIFT) +#define MICFIL_VAD0_CTRL2_FRAMET(v) (((v) << MICFIL_VAD0_CTRL2_FRAMET_SHIFT) \ + & MICFIL_VAD0_CTRL2_FRAMET_MASK) +#define MICFIL_VAD0_CTRL2_INPGAIN_SHIFT 8 +#define MICFIL_VAD0_CTRL2_INPGAIN_WIDTH 4 +#define MICFIL_VAD0_CTRL2_INPGAIN_MASK ((BIT(MICFIL_VAD0_CTRL2_INPGAIN_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL2_INPGAIN_SHIFT) +#define MICFIL_VAD0_CTRL2_INPGAIN(v) (((v) << MICFIL_VAD0_CTRL2_INPGAIN_SHIFT) \ + & MICFIL_VAD0_CTRL2_INPGAIN_MASK) +#define MICFIL_VAD0_CTRL2_HPF_SHIFT 0 +#define MICFIL_VAD0_CTRL2_HPF_WIDTH 2 +#define MICFIL_VAD0_CTRL2_HPF_MASK ((BIT(MICFIL_VAD0_CTRL2_HPF_WIDTH) - 1) \ + << MICFIL_VAD0_CTRL2_HPF_SHIFT) +#define MICFIL_VAD0_CTRL2_HPF(v) (((v) << MICFIL_VAD0_CTRL2_HPF_SHIFT) \ + & MICFIL_VAD0_CTRL2_HPF_MASK) + +/* MICFIL HWVAD0 Signal CONFIG Register -- REG_MICFIL_VAD0_SCONFIG */ +#define MICFIL_VAD0_SCONFIG_SFILEN_SHIFT 31 +#define MICFIL_VAD0_SCONFIG_SFILEN_MASK BIT(MICFIL_VAD0_SCONFIG_SFILEN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SFILEN BIT(MICFIL_VAD0_SCONFIG_SFILEN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SMAXEN_SHIFT 30 +#define MICFIL_VAD0_SCONFIG_SMAXEN_MASK BIT(MICFIL_VAD0_SCONFIG_SMAXEN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SMAXEN BIT(MICFIL_VAD0_SCONFIG_SMAXEN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SGAIN_SHIFT 0 +#define MICFIL_VAD0_SCONFIG_SGAIN_WIDTH 4 +#define MICFIL_VAD0_SCONFIG_SGAIN_MASK ((BIT(MICFIL_VAD0_SCONFIG_SGAIN_WIDTH) - 1) \ + << MICFIL_VAD0_SCONFIG_SGAIN_SHIFT) +#define MICFIL_VAD0_SCONFIG_SGAIN(v) (((v) << MICFIL_VAD0_SCONFIG_SGAIN_SHIFT) \ + & MICFIL_VAD0_SCONFIG_SGAIN_MASK) + +/* MICFIL HWVAD0 Noise CONFIG Register -- REG_MICFIL_VAD0_NCONFIG */ +#define MICFIL_VAD0_NCONFIG_NFILAUT_SHIFT 31 +#define MICFIL_VAD0_NCONFIG_NFILAUT_MASK BIT(MICFIL_VAD0_NCONFIG_NFILAUT_SHIFT) +#define MICFIL_VAD0_NCONFIG_NFILAUT BIT(MICFIL_VAD0_NCONFIG_NFILAUT_SHIFT) +#define MICFIL_VAD0_NCONFIG_NMINEN_SHIFT 30 +#define MICFIL_VAD0_NCONFIG_NMINEN_MASK BIT(MICFIL_VAD0_NCONFIG_NMINEN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NMINEN BIT(MICFIL_VAD0_NCONFIG_NMINEN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NDECEN_SHIFT 29 +#define MICFIL_VAD0_NCONFIG_NDECEN_MASK BIT(MICFIL_VAD0_NCONFIG_NDECEN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NDECEN BIT(MICFIL_VAD0_NCONFIG_NDECEN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NOREN_SHIFT 28 +#define MICFIL_VAD0_NCONFIG_NOREN BIT(MICFIL_VAD0_NCONFIG_NOREN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NFILADJ_SHIFT 8 +#define MICFIL_VAD0_NCONFIG_NFILADJ_WIDTH 5 +#define MICFIL_VAD0_NCONFIG_NFILADJ_MASK ((BIT(MICFIL_VAD0_NCONFIG_NFILADJ_WIDTH) - 1) \ + << MICFIL_VAD0_NCONFIG_NFILADJ_SHIFT) +#define MICFIL_VAD0_NCONFIG_NFILADJ(v) (((v) << MICFIL_VAD0_NCONFIG_NFILADJ_SHIFT) \ + & MICFIL_VAD0_NCONFIG_NFILADJ_MASK) +#define MICFIL_VAD0_NCONFIG_NGAIN_SHIFT 0 +#define MICFIL_VAD0_NCONFIG_NGAIN_WIDTH 4 +#define MICFIL_VAD0_NCONFIG_NGAIN_MASK ((BIT(MICFIL_VAD0_NCONFIG_NGAIN_WIDTH) - 1) \ + << MICFIL_VAD0_NCONFIG_NGAIN_SHIFT) +#define MICFIL_VAD0_NCONFIG_NGAIN(v) (((v) << MICFIL_VAD0_NCONFIG_NGAIN_SHIFT) \ + & MICFIL_VAD0_NCONFIG_NGAIN_MASK) + +/* MICFIL HWVAD0 Zero-Crossing Detector - REG_MICFIL_VAD0_ZCD */ +#define MICFIL_VAD0_ZCD_ZCDTH_SHIFT 16 +#define MICFIL_VAD0_ZCD_ZCDTH_WIDTH 10 +#define MICFIL_VAD0_ZCD_ZCDTH_MASK ((BIT(MICFIL_VAD0_ZCD_ZCDTH_WIDTH) - 1) \ + << MICFIL_VAD0_ZCD_ZCDTH_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDTH(v) (((v) << MICFIL_VAD0_ZCD_ZCDTH_SHIFT)\ + & MICFIL_VAD0_ZCD_ZCDTH_MASK) +#define MICFIL_VAD0_ZCD_ZCDADJ_SHIFT 8 +#define MICFIL_VAD0_ZCD_ZCDADJ_WIDTH 4 +#define MICFIL_VAD0_ZCD_ZCDADJ_MASK ((BIT(MICFIL_VAD0_ZCD_ZCDADJ_WIDTH) - 1)\ + << MICFIL_VAD0_ZCD_ZCDADJ_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDADJ(v) (((v) << MICFIL_VAD0_ZCD_ZCDADJ_SHIFT)\ + & MICFIL_VAD0_ZCD_ZCDADJ_MASK) +#define MICFIL_VAD0_ZCD_ZCDAND_SHIFT 4 +#define MICFIL_VAD0_ZCD_ZCDAND_MASK BIT(MICFIL_VAD0_ZCD_ZCDAND_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDAND BIT(MICFIL_VAD0_ZCD_ZCDAND_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDAUT_SHIFT 2 +#define MICFIL_VAD0_ZCD_ZCDAUT_MASK BIT(MICFIL_VAD0_ZCD_ZCDAUT_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDAUT BIT(MICFIL_VAD0_ZCD_ZCDAUT_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDEN_SHIFT 0 +#define MICFIL_VAD0_ZCD_ZCDEN_MASK BIT(MICFIL_VAD0_ZCD_ZCDEN_SHIFT) +#define MICFIL_VAD0_ZCD_ZCDEN BIT(MICFIL_VAD0_ZCD_ZCDEN_SHIFT) + +/* MICFIL HWVAD0 Status Register - REG_MICFIL_VAD0_STAT */ +#define MICFIL_VAD0_STAT_INITF_SHIFT 31 +#define MICFIL_VAD0_STAT_INITF_MASK BIT(MICFIL_VAD0_STAT_INITF_SHIFT) +#define MICFIL_VAD0_STAT_INITF BIT(MICFIL_VAD0_STAT_INITF_SHIFT) +#define MICFIL_VAD0_STAT_INSATF_SHIFT 16 +#define MICFIL_VAD0_STAT_INSATF_MASK BIT(MICFIL_VAD0_STAT_INSATF_SHIFT) +#define MICFIL_VAD0_STAT_INSATF BIT(MICFIL_VAD0_STAT_INSATF_SHIFT) +#define MICFIL_VAD0_STAT_EF_SHIFT 15 +#define MICFIL_VAD0_STAT_EF_MASK BIT(MICFIL_VAD0_STAT_EF_SHIFT) +#define MICFIL_VAD0_STAT_EF BIT(MICFIL_VAD0_STAT_EF_SHIFT) +#define MICFIL_VAD0_STAT_IF_SHIFT 0 +#define MICFIL_VAD0_STAT_IF_MASK BIT(MICFIL_VAD0_STAT_IF_SHIFT) +#define MICFIL_VAD0_STAT_IF BIT(MICFIL_VAD0_STAT_IF_SHIFT) + +/* MICFIL Output Control Register */ +#define MICFIL_OUTGAIN_CHX_SHIFT(v) (4 * (v)) + +/* Constants */ +#define MICFIL_DMA_IRQ_DISABLED(v) ((v) & MICFIL_CTRL1_DISEL_MASK) +#define MICFIL_DMA_ENABLED(v) ((0x1 << MICFIL_CTRL1_DISEL_SHIFT) \ + == ((v) & MICFIL_CTRL1_DISEL_MASK)) +#define MICFIL_IRQ_ENABLED(v) ((0x2 << MICFIL_CTRL1_DISEL_SHIFT) \ + == ((v) & MICFIL_CTRL1_DISEL_MASK)) +#define MICFIL_OUTPUT_CHANNELS 8 +#define MICFIL_FIFO_NUM 8 + +#define FIFO_PTRWID 3 +#define FIFO_LEN BIT(FIFO_PTRWID) + +#define MICFIL_IRQ_LINES 2 +#define MICFIL_MAX_RETRY 25 +#define MICFIL_SLEEP_MIN 90000 /* in us */ +#define MICFIL_SLEEP_MAX 100000 /* in us */ +#define MICFIL_DMA_MAXBURST_RX 6 +#define MICFIL_CTRL2_OSR_DEFAULT (0 << MICFIL_CTRL2_CICOSR_SHIFT) + +#endif /* _FSL_MICFIL_H */ -- cgit v1.2.3-58-ga151 From 4c84edc11b76590859b1e45dd676074c59602dc4 Mon Sep 17 00:00:00 2001 From: JianJhen Chen Date: Sun, 6 Jan 2019 11:28:13 +0800 Subject: net: bridge: fix a bug on using a neighbour cache entry without checking its state When handling DNAT'ed packets on a bridge device, the neighbour cache entry from lookup was used without checking its state. It means that a cache entry in the NUD_STALE state will be used directly instead of entering the NUD_DELAY state to confirm the reachability of the neighbor. This problem becomes worse after commit 2724680bceee ("neigh: Keep neighbour cache entries if number of them is small enough."), since all neighbour cache entries in the NUD_STALE state will be kept in the neighbour table as long as the number of cache entries does not exceed the value specified in gc_thresh1. This commit validates the state of a neighbour cache entry before using the entry. Signed-off-by: JianJhen Chen Reviewed-by: JinLin Chen Signed-off-by: David S. Miller --- net/bridge/br_netfilter_hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index d21a23698410..c93c35bb73dd 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c @@ -265,7 +265,7 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_ struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb); int ret; - if (neigh->hh.hh_len) { + if ((neigh->nud_state & NUD_CONNECTED) && neigh->hh.hh_len) { neigh_hh_bridge(&neigh->hh, skb); skb->dev = nf_bridge->physindev; ret = br_handle_frame_finish(net, sk, skb); -- cgit v1.2.3-58-ga151 From 6b68835b5af4feb2a3f31592a52a1a68d7c1b1f3 Mon Sep 17 00:00:00 2001 From: Qian Cai Date: Mon, 7 Jan 2019 16:42:07 +0000 Subject: ACPI/IORT: Fix build when CONFIG_IOMMU_API=n Commit 8097e53eaba2 ("ACPI/IORT: Use helper functions to access dev->iommu_fwspec") changed by mistake the iort_fwspec_iommu_ops() stub definition (compiled in when CONFIG_IOMMU_API=n), that caused the following compilation failure: drivers/acpi/arm64/iort.c:880:1: error: expected identifier or '(' before '{' token { return NULL; } ^ drivers/acpi/arm64/iort.c:879:39: warning: 'iort_fwspec_iommu_ops' used but never defined static inline const struct iommu_ops *iort_fwspec_iommu_ops(struct device *dev); ^~~~~~~~~~~~~~~~~~~~~ Fix it. Fixes: 8097e53eaba2 ("ACPI/IORT: Use helper functions to access dev->iommu_fwspec") Signed-off-by: Qian Cai [lorenzo.pieralisi@arm.com: updated tags and log] Signed-off-by: Lorenzo Pieralisi Acked-by: Hanjun Guo Cc: Will Deacon Cc: Sudeep Holla Cc: Catalin Marinas Cc: Joerg Roedel Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index fdd90ffceb85..5d29783ee5bd 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -876,7 +876,7 @@ int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head *head) return (resv == its->its_count) ? resv : -ENODEV; } #else -static inline const struct iommu_ops *iort_fwspec_iommu_ops(struct device *dev); +static inline const struct iommu_ops *iort_fwspec_iommu_ops(struct device *dev) { return NULL; } static inline int iort_add_device_replay(const struct iommu_ops *ops, struct device *dev) -- cgit v1.2.3-58-ga151 From 2f00f7715e624d04e25d9cb8bb0f53884d3bcb59 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Thu, 3 Jan 2019 23:39:51 +0530 Subject: dt-bindings: ASoC: xlnx, spdif: Document spdif bindings Added documentation for SPDIF IP DT bindings. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/xlnx,spdif.txt | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/xlnx,spdif.txt diff --git a/Documentation/devicetree/bindings/sound/xlnx,spdif.txt b/Documentation/devicetree/bindings/sound/xlnx,spdif.txt new file mode 100644 index 000000000000..15c2d64d247c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/xlnx,spdif.txt @@ -0,0 +1,28 @@ +Device-Tree bindings for Xilinx SPDIF IP + +The IP supports playback and capture of SPDIF audio + +Required properties: + - compatible: "xlnx,spdif-2.0" + - clock-names: List of input clocks. + Required elements: "s_axi_aclk", "aud_clk_i" + - clocks: Input clock specifier. Refer to common clock bindings. + - reg: Base address and address length of the IP core instance. + - interrupts-parent: Phandle for interrupt controller. + - interrupts: List of Interrupt numbers. + - xlnx,spdif-mode: 0 :- receiver mode + 1 :- transmitter mode + - xlnx,aud_clk_i: input audio clock value. + +Example: + spdif_0: spdif@80010000 { + clock-names = "aud_clk_i", "s_axi_aclk"; + clocks = <&misc_clk_0>, <&clk 71>; + compatible = "xlnx,spdif-2.0"; + interrupt-names = "spdif_interrupt"; + interrupt-parent = <&gic>; + interrupts = <0 91 4>; + reg = <0x0 0x80010000 0x0 0x10000>; + xlnx,spdif-mode = <1>; + xlnx,aud_clk_i = <49152913>; + }; -- cgit v1.2.3-58-ga151 From b1d2a4cca20cb84ffe02116fd8d2b91a94d49d5e Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Thu, 3 Jan 2019 23:39:52 +0530 Subject: ASoC: xlnx: add SPDIF audio driver Added SPDIF audio driver. This provides playback and capture of AES audio over SPDIF interface. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_spdif.c | 339 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 sound/soc/xilinx/xlnx_spdif.c diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c new file mode 100644 index 000000000000..3b9000fd8c49 --- /dev/null +++ b/sound/soc/xilinx/xlnx_spdif.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Xilinx ASoC SPDIF audio support +// +// Copyright (C) 2018 Xilinx, Inc. +// +// Author: Maruthi Srinivas Bayyavarapu +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#define XLNX_SPDIF_RATES \ + (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000) + +#define XLNX_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) + +#define XSPDIF_IRQ_STS_REG 0x20 +#define XSPDIF_IRQ_ENABLE_REG 0x28 +#define XSPDIF_SOFT_RESET_REG 0x40 +#define XSPDIF_CONTROL_REG 0x44 +#define XSPDIF_CHAN_0_STS_REG 0x4C +#define XSPDIF_GLOBAL_IRQ_ENABLE_REG 0x1C +#define XSPDIF_CH_A_USER_DATA_REG_0 0x64 + +#define XSPDIF_CORE_ENABLE_MASK BIT(0) +#define XSPDIF_FIFO_FLUSH_MASK BIT(1) +#define XSPDIF_CH_STS_MASK BIT(5) +#define XSPDIF_GLOBAL_IRQ_ENABLE BIT(31) +#define XSPDIF_CLOCK_CONFIG_BITS_MASK GENMASK(5, 2) +#define XSPDIF_CLOCK_CONFIG_BITS_SHIFT 2 +#define XSPDIF_SOFT_RESET_VALUE 0xA + +#define MAX_CHANNELS 2 +#define AES_SAMPLE_WIDTH 32 +#define CH_STATUS_UPDATE_TIMEOUT 40 + +struct spdif_dev_data { + u32 mode; + u32 aclk; + bool rx_chsts_updated; + void __iomem *base; + struct clk *axi_clk; + wait_queue_head_t chsts_q; +}; + +static irqreturn_t xlnx_spdifrx_irq_handler(int irq, void *arg) +{ + u32 val; + struct spdif_dev_data *ctx = arg; + + val = readl(ctx->base + XSPDIF_IRQ_STS_REG); + if (val & XSPDIF_CH_STS_MASK) { + writel(val & XSPDIF_CH_STS_MASK, + ctx->base + XSPDIF_IRQ_STS_REG); + val = readl(ctx->base + + XSPDIF_IRQ_ENABLE_REG); + writel(val & ~XSPDIF_CH_STS_MASK, + ctx->base + XSPDIF_IRQ_ENABLE_REG); + + ctx->rx_chsts_updated = true; + wake_up_interruptible(&ctx->chsts_q); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int xlnx_spdif_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + u32 val; + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + + val = readl(ctx->base + XSPDIF_CONTROL_REG); + val |= XSPDIF_FIFO_FLUSH_MASK; + writel(val, ctx->base + XSPDIF_CONTROL_REG); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + writel(XSPDIF_CH_STS_MASK, + ctx->base + XSPDIF_IRQ_ENABLE_REG); + writel(XSPDIF_GLOBAL_IRQ_ENABLE, + ctx->base + XSPDIF_GLOBAL_IRQ_ENABLE_REG); + } + + return 0; +} + +static void xlnx_spdif_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + + writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG); +} + +static int xlnx_spdif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + u32 val, clk_div, clk_cfg; + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + + clk_div = DIV_ROUND_CLOSEST(ctx->aclk, MAX_CHANNELS * AES_SAMPLE_WIDTH * + params_rate(params)); + + switch (clk_div) { + case 4: + clk_cfg = 0; + break; + case 8: + clk_cfg = 1; + break; + case 16: + clk_cfg = 2; + break; + case 24: + clk_cfg = 3; + break; + case 32: + clk_cfg = 4; + break; + case 48: + clk_cfg = 5; + break; + case 64: + clk_cfg = 6; + break; + default: + return -EINVAL; + } + + val = readl(ctx->base + XSPDIF_CONTROL_REG); + val &= ~XSPDIF_CLOCK_CONFIG_BITS_MASK; + val |= clk_cfg << XSPDIF_CLOCK_CONFIG_BITS_SHIFT; + writel(val, ctx->base + XSPDIF_CONTROL_REG); + + return 0; +} + +static int rx_stream_detect(struct snd_soc_dai *dai) +{ + int err; + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + unsigned long jiffies = msecs_to_jiffies(CH_STATUS_UPDATE_TIMEOUT); + + /* start capture only if stream is detected within 40ms timeout */ + err = wait_event_interruptible_timeout(ctx->chsts_q, + ctx->rx_chsts_updated, + jiffies); + if (!err) { + dev_err(dai->dev, "No streaming audio detected!\n"); + return -EINVAL; + } + ctx->rx_chsts_updated = false; + + return 0; +} + +static int xlnx_spdif_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + u32 val; + int ret = 0; + struct spdif_dev_data *ctx = dev_get_drvdata(dai->dev); + + val = readl(ctx->base + XSPDIF_CONTROL_REG); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + val |= XSPDIF_CORE_ENABLE_MASK; + writel(val, ctx->base + XSPDIF_CONTROL_REG); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + ret = rx_stream_detect(dai); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + val &= ~XSPDIF_CORE_ENABLE_MASK; + writel(val, ctx->base + XSPDIF_CONTROL_REG); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct snd_soc_dai_ops xlnx_spdif_dai_ops = { + .startup = xlnx_spdif_startup, + .shutdown = xlnx_spdif_shutdown, + .trigger = xlnx_spdif_trigger, + .hw_params = xlnx_spdif_hw_params, +}; + +static struct snd_soc_dai_driver xlnx_spdif_tx_dai = { + .name = "xlnx_spdif_tx", + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = XLNX_SPDIF_RATES, + .formats = XLNX_SPDIF_FORMATS, + }, + .ops = &xlnx_spdif_dai_ops, +}; + +static struct snd_soc_dai_driver xlnx_spdif_rx_dai = { + .name = "xlnx_spdif_rx", + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = XLNX_SPDIF_RATES, + .formats = XLNX_SPDIF_FORMATS, + }, + .ops = &xlnx_spdif_dai_ops, +}; + +static const struct snd_soc_component_driver xlnx_spdif_component = { + .name = "xlnx-spdif", +}; + +static const struct of_device_id xlnx_spdif_of_match[] = { + { .compatible = "xlnx,spdif-2.0", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xlnx_spdif_of_match); + +static int xlnx_spdif_probe(struct platform_device *pdev) +{ + int ret; + struct resource *res; + struct snd_soc_dai_driver *dai_drv; + struct spdif_dev_data *ctx; + + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->axi_clk = devm_clk_get(dev, "s_axi_aclk"); + if (IS_ERR(ctx->axi_clk)) { + ret = PTR_ERR(ctx->axi_clk); + dev_err(dev, "failed to get s_axi_aclk(%d)\n", ret); + return ret; + } + ret = clk_prepare_enable(ctx->axi_clk); + if (ret) { + dev_err(dev, "failed to enable s_axi_aclk(%d)\n", ret); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ctx->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ctx->base)) { + ret = PTR_ERR(ctx->base); + goto clk_err; + } + ret = of_property_read_u32(node, "xlnx,spdif-mode", &ctx->mode); + if (ret < 0) { + dev_err(dev, "cannot get SPDIF mode\n"); + goto clk_err; + } + if (ctx->mode) { + dai_drv = &xlnx_spdif_tx_dai; + } else { + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "No IRQ resource found\n"); + ret = -ENODEV; + goto clk_err; + } + ret = devm_request_irq(dev, res->start, + xlnx_spdifrx_irq_handler, + 0, "XLNX_SPDIF_RX", ctx); + if (ret) { + dev_err(dev, "spdif rx irq request failed\n"); + ret = -ENODEV; + goto clk_err; + } + + init_waitqueue_head(&ctx->chsts_q); + dai_drv = &xlnx_spdif_rx_dai; + } + + ret = of_property_read_u32(node, "xlnx,aud_clk_i", &ctx->aclk); + if (ret < 0) { + dev_err(dev, "cannot get aud_clk_i value\n"); + goto clk_err; + } + + dev_set_drvdata(dev, ctx); + + ret = devm_snd_soc_register_component(dev, &xlnx_spdif_component, + dai_drv, 1); + if (ret) { + dev_err(dev, "SPDIF component registration failed\n"); + goto clk_err; + } + + writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG); + dev_info(dev, "%s DAI registered\n", dai_drv->name); + +clk_err: + clk_disable_unprepare(ctx->axi_clk); + return ret; +} + +static int xlnx_spdif_remove(struct platform_device *pdev) +{ + struct spdif_dev_data *ctx = dev_get_drvdata(&pdev->dev); + + clk_disable_unprepare(ctx->axi_clk); + return 0; +} + +static struct platform_driver xlnx_spdif_driver = { + .driver = { + .name = "xlnx-spdif", + .of_match_table = xlnx_spdif_of_match, + }, + .probe = xlnx_spdif_probe, + .remove = xlnx_spdif_remove, +}; +module_platform_driver(xlnx_spdif_driver); + +MODULE_AUTHOR("Maruthi Srinivas Bayyavarapu "); +MODULE_DESCRIPTION("XILINX SPDIF driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-58-ga151 From 47caf048a017ecc95cdd0802bc3b015a1559e601 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Thu, 3 Jan 2019 23:39:53 +0530 Subject: ASoC: xlnx: enable SPDIF driver build Added SPDIF driver build related changes. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/Kconfig | 7 +++++++ sound/soc/xilinx/Makefile | 2 ++ 2 files changed, 9 insertions(+) diff --git a/sound/soc/xilinx/Kconfig b/sound/soc/xilinx/Kconfig index ac48d6a00c36..47f606b924e4 100644 --- a/sound/soc/xilinx/Kconfig +++ b/sound/soc/xilinx/Kconfig @@ -13,3 +13,10 @@ config SND_SOC_XILINX_AUDIO_FORMATTER Select this option to enable Xilinx audio formatter support. This provides DMA platform device support for audio functionality. + +config SND_SOC_XILINX_SPDIF + tristate "Audio support for the the Xilinx SPDIF" + help + Select this option to enable Xilinx SPDIF Audio. + This provides playback and capture of SPDIF audio in + AES format. diff --git a/sound/soc/xilinx/Makefile b/sound/soc/xilinx/Makefile index 432693b1cc79..d79fd38b094b 100644 --- a/sound/soc/xilinx/Makefile +++ b/sound/soc/xilinx/Makefile @@ -2,3 +2,5 @@ snd-soc-xlnx-i2s-objs := xlnx_i2s.o obj-$(CONFIG_SND_SOC_XILINX_I2S) += snd-soc-xlnx-i2s.o snd-soc-xlnx-formatter-pcm-objs := xlnx_formatter_pcm.o obj-$(CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER) += snd-soc-xlnx-formatter-pcm.o +snd-soc-xlnx-spdif-objs := xlnx_spdif.o +obj-$(CONFIG_SND_SOC_XILINX_SPDIF) += snd-soc-xlnx-spdif.o -- cgit v1.2.3-58-ga151 From 5dc4ca2996840db569e43d00420c10499140274a Mon Sep 17 00:00:00 2001 From: Alison Wang Date: Wed, 26 Dec 2018 08:59:53 +0800 Subject: ASoC: sgtl5000: Allow SCLK pad drive strength to be changed This patch introduces "sclk-strength" property to allow SCLK pad drive strength to be changed via device tree. When running playback test on LS1028ARDB, Tx Frame sync error interrupt will occur sometimes. Some noises also exist. After changing SCLK pad drive strength to the maximum value, the issues are gone. Signed-off-by: Alison Wang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/sgtl5000.txt | 9 +++++++++ sound/soc/codecs/sgtl5000.c | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt index 9c58f724396a..9d9ff5184939 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt @@ -37,6 +37,15 @@ VDDIO 1.8V 2.5V 3.3V 2 = 3.33 mA 5.74 mA 8.03 mA 3 = 4.99 mA 8.61 mA 12.05 mA +- sclk-strength: the SCLK pad strength. Possible values are: +0, 1, 2 and 3 as per the table below: + +VDDIO 1.8V 2.5V 3.3V +0 = Disable +1 = 1.66 mA 2.87 mA 4.02 mA +2 = 3.33 mA 5.74 mA 8.03 mA +3 = 4.99 mA 8.61 mA 12.05 mA + Example: sgtl5000: codec@a { diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index add18d6d77da..a6a4748c97f9 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -116,6 +116,13 @@ enum { I2S_LRCLK_STRENGTH_HIGH, }; +enum { + I2S_SCLK_STRENGTH_DISABLE, + I2S_SCLK_STRENGTH_LOW, + I2S_SCLK_STRENGTH_MEDIUM, + I2S_SCLK_STRENGTH_HIGH, +}; + /* sgtl5000 private structure in codec */ struct sgtl5000_priv { int sysclk; /* sysclk rate */ @@ -129,6 +136,7 @@ struct sgtl5000_priv { u8 micbias_resistor; u8 micbias_voltage; u8 lrclk_strength; + u8 sclk_strength; }; /* @@ -1302,7 +1310,9 @@ static int sgtl5000_probe(struct snd_soc_component *component) SGTL5000_DAC_MUTE_RIGHT | SGTL5000_DAC_MUTE_LEFT); - reg = ((sgtl5000->lrclk_strength) << SGTL5000_PAD_I2S_LRCLK_SHIFT | 0x5f); + reg = ((sgtl5000->lrclk_strength) << SGTL5000_PAD_I2S_LRCLK_SHIFT | + (sgtl5000->sclk_strength) << SGTL5000_PAD_I2S_SCLK_SHIFT | + 0x1f); snd_soc_component_write(component, SGTL5000_CHIP_PAD_STRENGTH, reg); snd_soc_component_write(component, SGTL5000_CHIP_ANA_CTRL, @@ -1542,6 +1552,13 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, sgtl5000->lrclk_strength = value; } + sgtl5000->sclk_strength = I2S_SCLK_STRENGTH_LOW; + if (!of_property_read_u32(np, "sclk-strength", &value)) { + if (value > I2S_SCLK_STRENGTH_HIGH) + value = I2S_SCLK_STRENGTH_LOW; + sgtl5000->sclk_strength = value; + } + /* Ensure sgtl5000 will start with sane register values */ sgtl5000_fill_defaults(client); -- cgit v1.2.3-58-ga151 From 7674bec4fc09e85803a8f2bd26a013d0076a80a9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 25 Dec 2018 14:05:28 +0900 Subject: ASoC: rsnd: update BSDSR/BSDISR handling Current BSDSR/BSDISR are using temporary/generic settings, but it can't handle all SRCx/SoC. It needs to handle correctry. Otherwise, sampling rate converted sound channel will be broken if it was TDM. One note is that it needs to overwrite settings on E3 case. Signed-off-by: Kuninori Morimoto Tested-by: chaoliang qin Tested-by: Yusuke Goda Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 125 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 50348a2c9203..db81e066b92e 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -14,6 +14,7 @@ */ #include "rsnd.h" +#include #define SRC_NAME "src" @@ -134,20 +135,83 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, return rate; } +const static u32 bsdsr_table_pattern1[] = { + 0x01800000, /* 6 - 1/6 */ + 0x01000000, /* 6 - 1/4 */ + 0x00c00000, /* 6 - 1/3 */ + 0x00800000, /* 6 - 1/2 */ + 0x00600000, /* 6 - 2/3 */ + 0x00400000, /* 6 - 1 */ +}; + +const static u32 bsdsr_table_pattern2[] = { + 0x02400000, /* 6 - 1/6 */ + 0x01800000, /* 6 - 1/4 */ + 0x01200000, /* 6 - 1/3 */ + 0x00c00000, /* 6 - 1/2 */ + 0x00900000, /* 6 - 2/3 */ + 0x00600000, /* 6 - 1 */ +}; + +const static u32 bsisr_table[] = { + 0x00100060, /* 6 - 1/6 */ + 0x00100040, /* 6 - 1/4 */ + 0x00100030, /* 6 - 1/3 */ + 0x00100020, /* 6 - 1/2 */ + 0x00100020, /* 6 - 2/3 */ + 0x00100020, /* 6 - 1 */ +}; + +const static u32 chan288888[] = { + 0x00000006, /* 1 to 2 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ +}; + +const static u32 chan244888[] = { + 0x00000006, /* 1 to 2 */ + 0x0000001e, /* 1 to 4 */ + 0x0000001e, /* 1 to 4 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ +}; + +const static u32 chan222222[] = { + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ +}; + +static const struct soc_device_attribute ov_soc[] = { + { .soc_id = "r8a77990" }, /* E3 */ + { /* sentinel */ } +}; + static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + const struct soc_device_attribute *soc = soc_device_match(ov_soc); int is_play = rsnd_io_is_play(io); int use_src = 0; u32 fin, fout; u32 ifscr, fsrate, adinr; u32 cr, route; - u32 bsdsr, bsisr; u32 i_busif, o_busif, tmp; + const u32 *bsdsr_table; + const u32 *chptn; uint ratio; + int chan; + int idx; if (!runtime) return; @@ -155,6 +219,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, fin = rsnd_src_get_in_rate(priv, io); fout = rsnd_src_get_out_rate(priv, io); + chan = rsnd_runtime_channel_original(io); + /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ if (fin == fout) ratio = 0; @@ -173,8 +239,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, /* * SRC_ADINR */ - adinr = rsnd_get_adinr_bit(mod, io) | - rsnd_runtime_channel_original(io); + adinr = rsnd_get_adinr_bit(mod, io) | chan; /* * SRC_IFSCR / SRC_IFSVR @@ -207,21 +272,56 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, /* * SRC_BSDSR / SRC_BSISR + * + * see + * Combination of Register Setting Related to + * FSO/FSI Ratio and Channel, Latency */ switch (rsnd_mod_id(mod)) { + case 0: + chptn = chan288888; + bsdsr_table = bsdsr_table_pattern1; + break; + case 1: + case 3: + case 4: + chptn = chan244888; + bsdsr_table = bsdsr_table_pattern1; + break; + case 2: + case 9: + chptn = chan222222; + bsdsr_table = bsdsr_table_pattern1; + break; case 5: case 6: case 7: case 8: - bsdsr = 0x02400000; /* 6 - 1/6 */ - bsisr = 0x00100060; /* 6 - 1/6 */ + chptn = chan222222; + bsdsr_table = bsdsr_table_pattern2; break; default: - bsdsr = 0x01800000; /* 6 - 1/6 */ - bsisr = 0x00100060 ;/* 6 - 1/6 */ - break; + goto convert_rate_err; } + /* + * E3 need to overwrite + */ + if (soc) + switch (rsnd_mod_id(mod)) { + case 0: + case 4: + chptn = chan222222; + } + + for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++) + if (chptn[idx] & (1 << chan)) + break; + + if (chan > 8 || + idx >= ARRAY_SIZE(chan222222)) + goto convert_rate_err; + /* BUSIF_MODE */ tmp = rsnd_get_busif_shift(io, mod); i_busif = ( is_play ? tmp : 0) | 1; @@ -234,8 +334,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_IFSCR, ifscr); rsnd_mod_write(mod, SRC_IFSVR, fsrate); rsnd_mod_write(mod, SRC_SRCCR, cr); - rsnd_mod_write(mod, SRC_BSDSR, bsdsr); - rsnd_mod_write(mod, SRC_BSISR, bsisr); + rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]); + rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]); rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif); @@ -244,6 +344,11 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout); + + return; + +convert_rate_err: + dev_err(dev, "unknown BSDSR/BSDIR settings\n"); } static int rsnd_src_irq(struct rsnd_mod *mod, -- cgit v1.2.3-58-ga151 From f687ccea10d23a9b0faed67ceac535b76604669a Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 7 Jan 2019 13:36:56 +0200 Subject: RDMA/uverbs: Fix post send success return value in case of error If get QP object fails 'ret' must be assigned with a proper error code. Fixes: 9a0738575f26 ("RDMA/uverbs: Use uverbs_response() for remaining response copying") Signed-off-by: Gal Pressman Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/uverbs_cmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 6b12cc5f97b2..1b82cb74276c 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2012,8 +2012,10 @@ static int ib_uverbs_post_send(struct uverbs_attr_bundle *attrs) return -ENOMEM; qp = uobj_get_obj_read(qp, UVERBS_OBJECT_QP, cmd.qp_handle, attrs); - if (!qp) + if (!qp) { + ret = -EINVAL; goto out; + } is_ud = qp->qp_type == IB_QPT_UD; sg_ind = 0; -- cgit v1.2.3-58-ga151 From d3dcc5882ca95c9207b5232395c291d34a511627 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:19 +0100 Subject: ASoC: Intel: common: Add quirk for PoV P1006W tablet The Point of View TAB-P1006W-232 (v1.0) tablet uses 10EC5640 as ACPI HID, but it has a rt5651 codec add a quirk for this. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 35 +++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 47a90909b956..96f9c553fe6c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -21,6 +21,7 @@ static unsigned long byt_machine_id; #define BYT_THINKPAD_10 1 +#define BYT_POV_P1006W 2 static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) { @@ -28,6 +29,11 @@ static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) return 1; } +static int byt_pov_p1006w_quirk_cb(const struct dmi_system_id *id) +{ + byt_machine_id = BYT_POV_P1006W; + return 1; +} static const struct dmi_system_id byt_table[] = { { @@ -58,6 +64,17 @@ static const struct dmi_system_id byt_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"), }, }, + { + /* Point of View mobii wintab p1006w (v1.0) */ + .callback = byt_pov_p1006w_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Note 105b is Foxcon's USB/PCI vendor id */ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), + }, + }, { } }; @@ -71,16 +88,30 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .asoc_plat_name = "sst-mfld-platform", }; +static struct snd_soc_acpi_mach byt_pov_p1006w = { + .id = "10EC5640", + .drv_name = "bytcr_rt5651", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5651", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .asoc_plat_name = "sst-mfld-platform", +}; + static struct snd_soc_acpi_mach *byt_quirk(void *arg) { struct snd_soc_acpi_mach *mach = arg; dmi_check_system(byt_table); - if (byt_machine_id == BYT_THINKPAD_10) + switch (byt_machine_id) { + case BYT_THINKPAD_10: return &byt_thinkpad_10; - else + case BYT_POV_P1006W: + return &byt_pov_p1006w; + default: return mach; + } } struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_legacy_machines[] = { -- cgit v1.2.3-58-ga151 From 7acf8b36a2ac6eb4fdc53c4d862570089e56c69e Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 7 Jan 2019 17:54:14 +0000 Subject: phy: ti: Fix compilation failures without REGMAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver requires regmap or the compile fails: drivers/phy/ti/phy-gmii-sel.c:43:27: error: array type has incomplete element type ‘struct reg_field’ const struct reg_field (*regfields)[PHY_GMII_SEL_LAST]; Add it to kconfig. Signed-off-by: Jason Gunthorpe Signed-off-by: David S. Miller --- drivers/phy/ti/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig index f137e0107764..c4709ed7fb0e 100644 --- a/drivers/phy/ti/Kconfig +++ b/drivers/phy/ti/Kconfig @@ -82,6 +82,7 @@ config PHY_TI_GMII_SEL default y if TI_CPSW=y depends on TI_CPSW || COMPILE_TEST select GENERIC_PHY + select REGMAP default m help This driver supports configuring of the TI CPSW Port mode depending on -- cgit v1.2.3-58-ga151 From d306873589c5a4c13df7176cd73d66ebfa690064 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:20 +0100 Subject: ASoC: rt5651: Add ACPI ID 10EC5640 Some BYT platforms have a RT5651 codec while using an ACPI node with a HID of 10EC5640 to describe the coded. Add the 10EC5640 HID to the acpi_device_id list, so that the rt5651 will bind to the codec on these devices. Like the rt5645 and rt5670 drivers which also have the 10EC5640 ACPI HID in their acpi_device_id list for similar reasons, the rt5651 driver checks the codecs device-id register so that it will only bind if the codec actually is a rt5651 and it will ignore actual rt5640 codecs. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 3882e238ff99..9a007c162631 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2138,6 +2138,7 @@ MODULE_DEVICE_TABLE(of, rt5651_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5651_acpi_match[] = { { "10EC5651", 0 }, + { "10EC5640", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match); -- cgit v1.2.3-58-ga151 From c2ec9d957d2bf49d69afb1b872cb2363c6cb5862 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:21 +0100 Subject: ASoC: rt5651: Add support for jack detect using an external GPIO Some board designs hook the jack-detect up to an external GPIO, rather then to one of the codec pins, add support for this. Figuring out which GPIO to use is pretty much board specific so I've chosen to let the machine driver pass the gpio_desc as data argument to snd_soc_component_set_jack() rather then add support for getting the GPIO to the codec driver. This keeps the codec code nice and clean. Note that using an external GPIO for this conflicts with button-press support, so this commit disables button-press support when an external GPIO is used. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 54 +++++++++++++++++++++++++++++++++-------------- sound/soc/codecs/rt5651.h | 1 + 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 9a007c162631..75994297c896 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1621,6 +1622,12 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component) struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); int val; + if (rt5651->gpiod_hp_det) { + val = gpiod_get_value_cansleep(rt5651->gpiod_hp_det); + dev_dbg(component->dev, "jack-detect gpio %d\n", val); + return val; + } + val = snd_soc_component_read32(component, RT5651_INT_IRQ_ST); dev_dbg(component->dev, "irq status %#04x\n", val); @@ -1761,6 +1768,13 @@ static int rt5651_detect_headset(struct snd_soc_component *component) return SND_JACK_HEADPHONE; } +static bool rt5651_support_button_press(struct rt5651_priv *rt5651) +{ + /* Button press support only works with internal jack-detection */ + return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) && + rt5651->gpiod_hp_det == NULL; +} + static void rt5651_jack_detect_work(struct work_struct *work) { struct rt5651_priv *rt5651 = @@ -1785,15 +1799,15 @@ static void rt5651_jack_detect_work(struct work_struct *work) WARN_ON(rt5651->ovcd_irq_enabled); rt5651_enable_micbias1_for_ovcd(component); report = rt5651_detect_headset(component); - if (report == SND_JACK_HEADSET) { + dev_dbg(component->dev, "detect report %#02x\n", report); + snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); + if (rt5651_support_button_press(rt5651)) { /* Enable ovcd IRQ for button press detect. */ rt5651_enable_micbias1_ovcd_irq(component); } else { /* No more need for overcurrent detect. */ rt5651_disable_micbias1_for_ovcd(component); } - dev_dbg(component->dev, "detect report %#02x\n", report); - snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); } else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) { dev_dbg(component->dev, "OVCD IRQ\n"); @@ -1837,16 +1851,20 @@ static void rt5651_cancel_work(void *data) } static void rt5651_enable_jack_detect(struct snd_soc_component *component, - struct snd_soc_jack *hp_jack) + struct snd_soc_jack *hp_jack, + struct gpio_desc *gpiod_hp_det) { struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); - - /* IRQ output on GPIO1 */ - snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, - RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + bool using_internal_jack_detect = true; /* Select jack detect source */ switch (rt5651->jd_src) { + case RT5651_JD_NULL: + rt5651->gpiod_hp_det = gpiod_hp_det; + if (!rt5651->gpiod_hp_det) + return; /* No jack detect */ + using_internal_jack_detect = false; + break; case RT5651_JD1_1: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1); @@ -1865,16 +1883,20 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN); break; - case RT5651_JD_NULL: - return; default: dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n"); return; } - /* Enable jack detect power */ - snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, - RT5651_PWR_JD_M, RT5651_PWR_JD_M); + if (using_internal_jack_detect) { + /* IRQ output on GPIO1 */ + snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, + RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + + /* Enable jack detect power */ + snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, + RT5651_PWR_JD_M, RT5651_PWR_JD_M); + } /* Set OVCD threshold current and scale-factor */ snd_soc_component_write(component, RT5651_PR_BASE + RT5651_BIAS_CUR4, @@ -1903,7 +1925,7 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN); rt5651->hp_jack = hp_jack; - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_enable_micbias1_for_ovcd(component); rt5651_enable_micbias1_ovcd_irq(component); } @@ -1920,7 +1942,7 @@ static void rt5651_disable_jack_detect(struct snd_soc_component *component) disable_irq(rt5651->irq); rt5651_cancel_work(rt5651); - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_disable_micbias1_ovcd_irq(component); rt5651_disable_micbias1_for_ovcd(component); snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0); @@ -1933,7 +1955,7 @@ static int rt5651_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *data) { if (jack) - rt5651_enable_jack_detect(component, jack); + rt5651_enable_jack_detect(component, jack, data); else rt5651_disable_jack_detect(component); diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h index ac6de6fb5414..41fcb8b5eb40 100644 --- a/sound/soc/codecs/rt5651.h +++ b/sound/soc/codecs/rt5651.h @@ -2073,6 +2073,7 @@ struct rt5651_priv { struct regmap *regmap; /* Jack and button detect data */ struct snd_soc_jack *hp_jack; + struct gpio_desc *gpiod_hp_det; struct work_struct jack_detect_work; struct delayed_work bp_work; bool ovcd_irq_enabled; -- cgit v1.2.3-58-ga151 From aee48a9ffa5a128bf4e433c57c39e015ea5b0208 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:22 +0100 Subject: ASoC: Intel: bytcr_rt5651: Revert "Fix DMIC map headsetmic mapping" Commit 37c7401e8c1f ("ASoC: Intel: bytcr_rt5651: Fix DMIC map headsetmic mapping"), changed the headsetmic mapping from IN3P to IN2P, this was based on the observation that all bytcr_rt5651 devices I have access to (7 devices) where all using IN3P for the headsetmic. This was an attempt to unifify / simplify the mapping, but it was wrong. None of those devices was actually using a digital internal mic. Now I've access to a Point of View TAB-P1006W-232 (v1.0) tabler, which does use a DMIC and it does have its headsetmic connected to IN2P, showing that the original mapping was correct, so this commit reverts the change changing the mapping back to IN2P. Fixes: 37c7401e8c1f ("ASoC: Intel: bytcr_rt5651: Fix DMIC map ... mapping") Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e528995668b7..0ed844f2ad01 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -266,7 +266,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = { {"DMIC L1", NULL, "Internal Mic"}, {"DMIC R1", NULL, "Internal Mic"}, - {"IN3P", NULL, "Headset Mic"}, + {"IN2P", NULL, "Headset Mic"}, }; static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = { -- cgit v1.2.3-58-ga151 From 7eb187313eef4c8faa49f70c9c7d8918e1052207 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:23 +0100 Subject: ASoC: Intel: bytcr_rt5651: Add quirks module parameter Add quirks module parameter to allow manually specifying quirks from the kernel commandline (or modprobe.conf). Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 0ed844f2ad01..6d8ef9dd106e 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -98,6 +98,10 @@ struct byt_rt5651_private { static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | BYT_RT5651_IN2_MAP; +static unsigned int quirk_override; +module_param_named(quirk, quirk_override, uint, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + static void log_quirks(struct device *dev) { if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC_MAP) @@ -973,6 +977,12 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* check quirks before creating card */ dmi_check_system(byt_rt5651_quirk_table); + if (quirk_override) { + dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", + (unsigned int)byt_rt5651_quirk, quirk_override); + byt_rt5651_quirk = quirk_override; + } + /* Must be called before register_card, also see declaration comment. */ ret_val = byt_rt5651_add_codec_device_props(codec_dev); if (ret_val) { -- cgit v1.2.3-58-ga151 From 90768eaf064041937ef4d6ca95c7e86774cd34a4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:24 +0100 Subject: ASoC: Intel: bytcr_rt5651: Add support for jack-detect using an external GPIO Some board designs hook the jack-detect up to an external GPIO, rather then to one of the codec pins, add support for this. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 43 +++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 6d8ef9dd106e..9a2ee9080897 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -91,6 +91,7 @@ enum { struct byt_rt5651_private { struct clk *mclk; struct gpio_desc *ext_amp_gpio; + struct gpio_desc *hp_detect; struct snd_soc_jack jack; }; @@ -499,6 +500,7 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; int num_routes; + int report; int ret; card->dapm.idle_bias_off = true; @@ -582,20 +584,27 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "unable to set MCLK rate\n"); } - if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) { + report = 0; + if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) + report = SND_JACK_HEADSET | SND_JACK_BTN_0; + else if (priv->hp_detect) + report = SND_JACK_HEADSET; + + if (report) { ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &priv->jack, bytcr_jack_pins, + report, &priv->jack, bytcr_jack_pins, ARRAY_SIZE(bytcr_jack_pins)); if (ret) { dev_err(runtime->dev, "jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, - KEY_PLAYPAUSE); + if (report & SND_JACK_BTN_0) + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, + KEY_PLAYPAUSE); - ret = snd_soc_component_set_jack(codec, &priv->jack, NULL); + ret = snd_soc_component_set_jack(codec, &priv->jack, + priv->hp_detect); if (ret) return ret; } @@ -767,7 +776,8 @@ static int byt_rt5651_resume(struct snd_soc_card *card) for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); - snd_soc_component_set_jack(component, &priv->jack, NULL); + snd_soc_component_set_jack(component, &priv->jack, + priv->hp_detect); break; } } @@ -1012,6 +1022,25 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) return ret_val; } } + priv->hp_detect = devm_fwnode_get_index_gpiod_from_child( + &pdev->dev, "hp-detect", 0, + codec_dev->fwnode, + GPIOD_IN, "hp-detect"); + if (IS_ERR(priv->hp_detect)) { + ret_val = PTR_ERR(priv->hp_detect); + switch (ret_val) { + case -ENOENT: + priv->hp_detect = NULL; + break; + default: + dev_err(&pdev->dev, "Failed to get hp-detect GPIO: %d\n", + ret_val); + /* fall through */ + case -EPROBE_DEFER: + put_device(codec_dev); + return ret_val; + } + } } put_device(codec_dev); -- cgit v1.2.3-58-ga151 From fee3e1cbd6cd74925286a571b567ec18728818a7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:25 +0100 Subject: ASoC: Intel: bytcr_rt5651: Add quirk for PoV TAB-P1006W-232 (v1.0) tablet Add a DMI quirk for the Point of View TAB-P1006W-232 (v1.0) tablet, this tablet is special in a number of ways: 1) It uses the 2nd GPIO resource in the ACPI tables for jack-detect rather then using the rt5651 codec's builtin jack-detect functionality 2) It uses the 3th GPIO resource in the ACPI tables to control the external amplifier rather then the usual first non GpioInt resource and the GPIO is active-low. 3) It is a BYTCR device, without a CHAN package and it uses SSP0-AIF1 rather then the default SSP0-AIF2. 4) Its internal mic is a digital mic (the first x86 rt5651 device that I'm aware of which does this), combined with having its headset-mic connected to IN2. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 48 +++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 9a2ee9080897..b618d984e2d5 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -95,6 +95,8 @@ struct byt_rt5651_private { struct snd_soc_jack jack; }; +static const struct acpi_gpio_mapping *byt_rt5651_gpios; + /* Default: jack-detect on JD1_1, internal mic on in2, headsetmic on in3 */ static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | BYT_RT5651_IN2_MAP; @@ -365,6 +367,22 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, return byt_rt5651_prepare_and_enable_pll1(codec_dai, rate, bclk_ratio); } +static const struct acpi_gpio_params pov_p1006w_hp_detect = { 1, 0, false }; +static const struct acpi_gpio_params pov_p1006w_ext_amp_en = { 2, 0, true }; + +static const struct acpi_gpio_mapping byt_rt5651_pov_p1006w_gpios[] = { + { "hp-detect-gpios", &pov_p1006w_hp_detect, 1, }, + { "ext-amp-enable-gpios", &pov_p1006w_ext_amp_en, 1, }, + { }, +}; + +static int byt_rt5651_pov_p1006w_quirk_cb(const struct dmi_system_id *id) +{ + byt_rt5651_quirk = (unsigned long)id->driver_data; + byt_rt5651_gpios = byt_rt5651_pov_p1006w_gpios; + return 1; +} + static int byt_rt5651_quirk_cb(const struct dmi_system_id *id) { byt_rt5651_quirk = (unsigned long)id->driver_data; @@ -440,6 +458,23 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { .driver_data = (void *)(BYT_RT5651_MCLK_EN | BYT_RT5651_IN1_MAP), }, + { + /* Point of View mobii wintab p1006w (v1.0) */ + .callback = byt_rt5651_pov_p1006w_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Note 105b is Foxcon's USB/PCI vendor id */ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), + }, + .driver_data = (void *)(BYT_RT5651_DMIC_MAP | + BYT_RT5651_OVCD_TH_2000UA | + BYT_RT5651_OVCD_SF_0P75 | + BYT_RT5651_DMIC_EN | + BYT_RT5651_MCLK_EN | + BYT_RT5651_SSP0_AIF1), + }, { /* VIOS LTH17 */ .callback = byt_rt5651_quirk_cb, @@ -848,7 +883,7 @@ static int snd_byt_rt5651_acpi_resource(struct acpi_resource *ares, void *arg) return 0; } -static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec) +static void snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(struct device *codec) { struct byt_rt5651_acpi_resource_data data = { 0, -1 }; LIST_HEAD(resources); @@ -866,10 +901,10 @@ static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec) switch (data.gpio_int_idx) { case 0: - devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_second); + byt_rt5651_gpios = byt_rt5651_amp_en_second; break; case 1: - devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_first); + byt_rt5651_gpios = byt_rt5651_amp_en_first; break; default: dev_warn(codec, "Unknown GpioInt index %d, not adding external amplifier GPIO mapping\n", @@ -1001,8 +1036,11 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) } /* Cherry Trail devices use an external amplifier enable gpio */ - if (x86_match_cpu(cherrytrail_cpu_ids)) { - snd_byt_rt5651_mc_add_amp_en_gpio_mapping(codec_dev); + if (x86_match_cpu(cherrytrail_cpu_ids) && !byt_rt5651_gpios) + snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(codec_dev); + + if (byt_rt5651_gpios) { + devm_acpi_dev_add_driver_gpios(codec_dev, byt_rt5651_gpios); priv->ext_amp_gpio = devm_fwnode_get_index_gpiod_from_child( &pdev->dev, "ext-amp-enable", 0, codec_dev->fwnode, -- cgit v1.2.3-58-ga151 From 26d92e951fe0a44ee4aec157cabb65a818cc8151 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Sat, 5 Jan 2019 23:45:26 -0800 Subject: smc: move unhash as early as possible in smc_release() In smc_release() we release smc->clcsock before unhash the smc sock, but a parallel smc_diag_dump() may be still reading smc->clcsock, therefore this could cause a use-after-free as reported by syzbot. Reported-and-tested-by: syzbot+fbd1e5476e4c94c7b34e@syzkaller.appspotmail.com Fixes: 51f1de79ad8e ("net/smc: replace sock_put worker by socket refcounting") Cc: Ursula Braun Signed-off-by: Cong Wang Reported-by: syzbot+0bf2e01269f1274b4b03@syzkaller.appspotmail.com Reported-by: syzbot+e3132895630f957306bc@syzkaller.appspotmail.com Signed-off-by: David S. Miller --- net/smc/af_smc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index c4da4a78d369..c4e56602e0c6 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -146,6 +146,9 @@ static int smc_release(struct socket *sock) sock_set_flag(sk, SOCK_DEAD); sk->sk_shutdown |= SHUTDOWN_MASK; } + + sk->sk_prot->unhash(sk); + if (smc->clcsock) { if (smc->use_fallback && sk->sk_state == SMC_LISTEN) { /* wake up clcsock accept */ @@ -170,7 +173,6 @@ static int smc_release(struct socket *sock) smc_conn_free(&smc->conn); release_sock(sk); - sk->sk_prot->unhash(sk); sock_put(sk); /* final sock_put */ out: return rc; -- cgit v1.2.3-58-ga151 From a9666c1cae8dbcd1a9aacd08a778bf2a28eea300 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 24 Dec 2018 11:05:16 +0200 Subject: RDMA/nldev: Don't expose unsafe global rkey to regular user Unsafe global rkey is considered dangerous because it exposes memory registered for all memory in the system. Only users with a QP on the same PD can use the rkey, and generally those QPs will already know the value. However, out of caution, do not expose the value to unprivleged users on the local system. Require CAP_NET_ADMIN instead. Cc: # 4.16 Fixes: 29cf1351d450 ("RDMA/nldev: provide detailed PD information") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/nldev.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c index e600fc23ae62..3c97a8b6bf1e 100644 --- a/drivers/infiniband/core/nldev.c +++ b/drivers/infiniband/core/nldev.c @@ -584,10 +584,6 @@ static int fill_res_pd_entry(struct sk_buff *msg, struct netlink_callback *cb, if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_RES_USECNT, atomic_read(&pd->usecnt), RDMA_NLDEV_ATTR_PAD)) goto err; - if ((pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY) && - nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY, - pd->unsafe_global_rkey)) - goto err; if (fill_res_name_pid(msg, res)) goto err; -- cgit v1.2.3-58-ga151 From a8911d6d5878587767a78c6bde371298ca2a3be3 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 7 Jan 2019 09:46:46 -0800 Subject: selftests/bpf: fix incorrect users of create_and_get_cgroup We have some tests that assume create_and_get_cgroup returns -1 on error which is incorrect (it returns 0 on error). Since fd might be zero in general case, change create_and_get_cgroup to return -1 on error and fix the users that assume 0 on error. Fixes: f269099a7e7a ("tools/bpf: add a selftest for bpf_get_current_cgroup_id() helper") Fixes: 7d2c6cfc5411 ("bpf: use --cgroup in test_suite if supplied") v2: - instead of fixing the uses that assume -1 on error, convert the users that assume 0 on error (fd might be zero in general case) Signed-off-by: Stanislav Fomichev Signed-off-by: Alexei Starovoitov --- samples/bpf/test_cgrp2_attach2.c | 14 +++++++------- samples/bpf/test_current_task_under_cgroup_user.c | 2 +- tools/testing/selftests/bpf/cgroup_helpers.c | 6 +++--- tools/testing/selftests/bpf/test_cgroup_storage.c | 2 +- tools/testing/selftests/bpf/test_dev_cgroup.c | 2 +- tools/testing/selftests/bpf/test_netcnt.c | 2 +- tools/testing/selftests/bpf/test_skb_cgroup_id_user.c | 2 +- tools/testing/selftests/bpf/test_sock.c | 2 +- tools/testing/selftests/bpf/test_sock_addr.c | 2 +- tools/testing/selftests/bpf/test_socket_cookie.c | 2 +- tools/testing/selftests/bpf/test_tcpbpf_user.c | 2 +- tools/testing/selftests/bpf/test_tcpnotify_user.c | 2 +- 12 files changed, 20 insertions(+), 20 deletions(-) diff --git a/samples/bpf/test_cgrp2_attach2.c b/samples/bpf/test_cgrp2_attach2.c index d7b68ef5ba79..0bb6507256b7 100644 --- a/samples/bpf/test_cgrp2_attach2.c +++ b/samples/bpf/test_cgrp2_attach2.c @@ -77,7 +77,7 @@ static int test_foo_bar(void) /* Create cgroup /foo, get fd, and join it */ foo = create_and_get_cgroup(FOO); - if (!foo) + if (foo < 0) goto err; if (join_cgroup(FOO)) @@ -94,7 +94,7 @@ static int test_foo_bar(void) /* Create cgroup /foo/bar, get fd, and join it */ bar = create_and_get_cgroup(BAR); - if (!bar) + if (bar < 0) goto err; if (join_cgroup(BAR)) @@ -298,19 +298,19 @@ static int test_multiprog(void) goto err; cg1 = create_and_get_cgroup("/cg1"); - if (!cg1) + if (cg1 < 0) goto err; cg2 = create_and_get_cgroup("/cg1/cg2"); - if (!cg2) + if (cg2 < 0) goto err; cg3 = create_and_get_cgroup("/cg1/cg2/cg3"); - if (!cg3) + if (cg3 < 0) goto err; cg4 = create_and_get_cgroup("/cg1/cg2/cg3/cg4"); - if (!cg4) + if (cg4 < 0) goto err; cg5 = create_and_get_cgroup("/cg1/cg2/cg3/cg4/cg5"); - if (!cg5) + if (cg5 < 0) goto err; if (join_cgroup("/cg1/cg2/cg3/cg4/cg5")) diff --git a/samples/bpf/test_current_task_under_cgroup_user.c b/samples/bpf/test_current_task_under_cgroup_user.c index 2259f997a26c..f082d6ac59f0 100644 --- a/samples/bpf/test_current_task_under_cgroup_user.c +++ b/samples/bpf/test_current_task_under_cgroup_user.c @@ -32,7 +32,7 @@ int main(int argc, char **argv) cg2 = create_and_get_cgroup(CGROUP_PATH); - if (!cg2) + if (cg2 < 0) goto err; if (bpf_map_update_elem(map_fd[0], &idx, &cg2, BPF_ANY)) { diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index cf16948aad4a..6692a40a6979 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -155,7 +155,7 @@ void cleanup_cgroup_environment(void) * This function creates a cgroup under the top level workdir and returns the * file descriptor. It is idempotent. * - * On success, it returns the file descriptor. On failure it returns 0. + * On success, it returns the file descriptor. On failure it returns -1. * If there is a failure, it prints the error to stderr. */ int create_and_get_cgroup(const char *path) @@ -166,13 +166,13 @@ int create_and_get_cgroup(const char *path) format_cgroup_path(cgroup_path, path); if (mkdir(cgroup_path, 0777) && errno != EEXIST) { log_err("mkdiring cgroup %s .. %s", path, cgroup_path); - return 0; + return -1; } fd = open(cgroup_path, O_RDONLY); if (fd < 0) { log_err("Opening Cgroup"); - return 0; + return -1; } return fd; diff --git a/tools/testing/selftests/bpf/test_cgroup_storage.c b/tools/testing/selftests/bpf/test_cgroup_storage.c index f44834155f25..2fc4625c1a15 100644 --- a/tools/testing/selftests/bpf/test_cgroup_storage.c +++ b/tools/testing/selftests/bpf/test_cgroup_storage.c @@ -81,7 +81,7 @@ int main(int argc, char **argv) /* Create a cgroup, get fd, and join it */ cgroup_fd = create_and_get_cgroup(TEST_CGROUP); - if (!cgroup_fd) { + if (cgroup_fd < 0) { printf("Failed to create test cgroup\n"); goto err; } diff --git a/tools/testing/selftests/bpf/test_dev_cgroup.c b/tools/testing/selftests/bpf/test_dev_cgroup.c index 9c8b50bac7e0..76e4993b7c16 100644 --- a/tools/testing/selftests/bpf/test_dev_cgroup.c +++ b/tools/testing/selftests/bpf/test_dev_cgroup.c @@ -43,7 +43,7 @@ int main(int argc, char **argv) /* Create a cgroup, get fd, and join it */ cgroup_fd = create_and_get_cgroup(TEST_CGROUP); - if (!cgroup_fd) { + if (cgroup_fd < 0) { printf("Failed to create test cgroup\n"); goto err; } diff --git a/tools/testing/selftests/bpf/test_netcnt.c b/tools/testing/selftests/bpf/test_netcnt.c index 44ed7f29f8ab..c1da5404454a 100644 --- a/tools/testing/selftests/bpf/test_netcnt.c +++ b/tools/testing/selftests/bpf/test_netcnt.c @@ -65,7 +65,7 @@ int main(int argc, char **argv) /* Create a cgroup, get fd, and join it */ cgroup_fd = create_and_get_cgroup(TEST_CGROUP); - if (!cgroup_fd) { + if (cgroup_fd < 0) { printf("Failed to create test cgroup\n"); goto err; } diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c b/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c index c121cc59f314..9220747c069d 100644 --- a/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c +++ b/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c @@ -164,7 +164,7 @@ int main(int argc, char **argv) goto err; cgfd = create_and_get_cgroup(CGROUP_PATH); - if (!cgfd) + if (cgfd < 0) goto err; if (join_cgroup(CGROUP_PATH)) diff --git a/tools/testing/selftests/bpf/test_sock.c b/tools/testing/selftests/bpf/test_sock.c index b8ebe2f58074..561ffb6d6433 100644 --- a/tools/testing/selftests/bpf/test_sock.c +++ b/tools/testing/selftests/bpf/test_sock.c @@ -458,7 +458,7 @@ int main(int argc, char **argv) goto err; cgfd = create_and_get_cgroup(CG_PATH); - if (!cgfd) + if (cgfd < 0) goto err; if (join_cgroup(CG_PATH)) diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c index d94336cbd8bd..3f110eaaf29c 100644 --- a/tools/testing/selftests/bpf/test_sock_addr.c +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -1442,7 +1442,7 @@ int main(int argc, char **argv) goto err; cgfd = create_and_get_cgroup(CG_PATH); - if (!cgfd) + if (cgfd < 0) goto err; if (join_cgroup(CG_PATH)) diff --git a/tools/testing/selftests/bpf/test_socket_cookie.c b/tools/testing/selftests/bpf/test_socket_cookie.c index b6c2c605d8c0..fc7832ee566b 100644 --- a/tools/testing/selftests/bpf/test_socket_cookie.c +++ b/tools/testing/selftests/bpf/test_socket_cookie.c @@ -202,7 +202,7 @@ int main(int argc, char **argv) goto err; cgfd = create_and_get_cgroup(CG_PATH); - if (!cgfd) + if (cgfd < 0) goto err; if (join_cgroup(CG_PATH)) diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c index e6eebda7d112..716b4e3be581 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_user.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c @@ -103,7 +103,7 @@ int main(int argc, char **argv) goto err; cg_fd = create_and_get_cgroup(cg_path); - if (!cg_fd) + if (cg_fd < 0) goto err; if (join_cgroup(cg_path)) diff --git a/tools/testing/selftests/bpf/test_tcpnotify_user.c b/tools/testing/selftests/bpf/test_tcpnotify_user.c index ff3c4522aed6..4e4353711a86 100644 --- a/tools/testing/selftests/bpf/test_tcpnotify_user.c +++ b/tools/testing/selftests/bpf/test_tcpnotify_user.c @@ -115,7 +115,7 @@ int main(int argc, char **argv) goto err; cg_fd = create_and_get_cgroup(cg_path); - if (!cg_fd) + if (cg_fd < 0) goto err; if (join_cgroup(cg_path)) -- cgit v1.2.3-58-ga151 From 2b4dba55b04b212a7fd1f0395b41d79ee3a9801b Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 6 Jan 2019 19:44:11 +0100 Subject: MIPS: lantiq: Fix IPI interrupt handling This makes SMP on the vrx200 work again, by removing all the MIPS CPU interrupt specific code and making it fully use the generic MIPS CPU interrupt controller. The mti,cpu-interrupt-controller from irq-mips-cpu.c now handles the CPU interrupts and also the IPI interrupts which are used to communication between the CPUs in a SMP system. The generic interrupt code was already used before but the interrupt vectors were overwritten again when we called set_vi_handler() in the lantiq interrupt driver and we also provided our own plat_irq_dispatch() function which overwrote the weak generic implementation. Now the code uses the generic handler for the MIPS CPU interrupts including the IPI interrupts and registers a handler for the CPU interrupts which are handled by the lantiq ICU with irq_set_chained_handler() which was already called before. Calling the set_c0_status() function is also not needed any more because the generic MIPS CPU interrupt already activates the needed bits. Fixes: 1eed40043579 ("MIPS: smp-mt: Use CPU interrupt controller IPI IRQ domain support") Cc: stable@kernel.org # v4.12 Signed-off-by: Hauke Mehrtens Signed-off-by: Paul Burton Cc: jhogan@kernel.org Cc: ralf@linux-mips.org Cc: john@phrozen.org Cc: linux-mips@linux-mips.org Cc: linux-mips@vger.kernel.org --- arch/mips/lantiq/irq.c | 68 ++++---------------------------------------------- 1 file changed, 5 insertions(+), 63 deletions(-) diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index f0bc3312ed11..c4ef1c31e0c4 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -224,9 +224,11 @@ static struct irq_chip ltq_eiu_type = { .irq_set_type = ltq_eiu_settype, }; -static void ltq_hw_irqdispatch(int module) +static void ltq_hw_irq_handler(struct irq_desc *desc) { + int module = irq_desc_get_irq(desc) - 2; u32 irq; + int hwirq; irq = ltq_icu_r32(module, LTQ_ICU_IM0_IOSR); if (irq == 0) @@ -237,7 +239,8 @@ static void ltq_hw_irqdispatch(int module) * other bits might be bogus */ irq = __fls(irq); - do_IRQ((int)irq + MIPS_CPU_IRQ_CASCADE + (INT_NUM_IM_OFFSET * module)); + hwirq = irq + MIPS_CPU_IRQ_CASCADE + (INT_NUM_IM_OFFSET * module); + generic_handle_irq(irq_linear_revmap(ltq_domain, hwirq)); /* if this is a EBU irq, we need to ack it or get a deadlock */ if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0) && LTQ_EBU_PCC_ISTAT) @@ -245,49 +248,6 @@ static void ltq_hw_irqdispatch(int module) LTQ_EBU_PCC_ISTAT); } -#define DEFINE_HWx_IRQDISPATCH(x) \ - static void ltq_hw ## x ## _irqdispatch(void) \ - { \ - ltq_hw_irqdispatch(x); \ - } -DEFINE_HWx_IRQDISPATCH(0) -DEFINE_HWx_IRQDISPATCH(1) -DEFINE_HWx_IRQDISPATCH(2) -DEFINE_HWx_IRQDISPATCH(3) -DEFINE_HWx_IRQDISPATCH(4) - -#if MIPS_CPU_TIMER_IRQ == 7 -static void ltq_hw5_irqdispatch(void) -{ - do_IRQ(MIPS_CPU_TIMER_IRQ); -} -#else -DEFINE_HWx_IRQDISPATCH(5) -#endif - -static void ltq_hw_irq_handler(struct irq_desc *desc) -{ - ltq_hw_irqdispatch(irq_desc_get_irq(desc) - 2); -} - -asmlinkage void plat_irq_dispatch(void) -{ - unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; - int irq; - - if (!pending) { - spurious_interrupt(); - return; - } - - pending >>= CAUSEB_IP; - while (pending) { - irq = fls(pending) - 1; - do_IRQ(MIPS_CPU_IRQ_BASE + irq); - pending &= ~BIT(irq); - } -} - static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { struct irq_chip *chip = <q_irq_type; @@ -343,28 +303,10 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) for (i = 0; i < MAX_IM; i++) irq_set_chained_handler(i + 2, ltq_hw_irq_handler); - if (cpu_has_vint) { - pr_info("Setting up vectored interrupts\n"); - set_vi_handler(2, ltq_hw0_irqdispatch); - set_vi_handler(3, ltq_hw1_irqdispatch); - set_vi_handler(4, ltq_hw2_irqdispatch); - set_vi_handler(5, ltq_hw3_irqdispatch); - set_vi_handler(6, ltq_hw4_irqdispatch); - set_vi_handler(7, ltq_hw5_irqdispatch); - } - ltq_domain = irq_domain_add_linear(node, (MAX_IM * INT_NUM_IM_OFFSET) + MIPS_CPU_IRQ_CASCADE, &irq_domain_ops, 0); -#ifndef CONFIG_MIPS_MT_SMP - set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | - IE_IRQ3 | IE_IRQ4 | IE_IRQ5); -#else - set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | - IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); -#endif - /* tell oprofile which irq to use */ ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ); -- cgit v1.2.3-58-ga151 From 390d1b461eec4b15aed78df0ce72a5c4bc40d619 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 6 Jan 2019 19:44:12 +0100 Subject: MIPS: lantiq: Use CP0_LEGACY_COMPARE_IRQ Instead of using the lantiq specific MIPS_CPU_TIMER_IRQ use the generic CP0_LEGACY_COMPARE_IRQ constant for the timer interrupt number. MIPS_CPU_TIMER_IRQ was already defined to 7 for both supported SoC families. Signed-off-by: Hauke Mehrtens Signed-off-by: Paul Burton Cc: jhogan@kernel.org Cc: ralf@linux-mips.org Cc: john@phrozen.org Cc: linux-mips@linux-mips.org Cc: linux-mips@vger.kernel.org --- arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h | 2 -- arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 2 -- arch/mips/lantiq/irq.c | 9 +-------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h b/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h index c6b63a409641..6dd8ad2409dc 100644 --- a/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h +++ b/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h @@ -18,8 +18,6 @@ #define INT_NUM_EXTRA_START (INT_NUM_IM4_IRL0 + 32) #define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0) -#define MIPS_CPU_TIMER_IRQ 7 - #define MAX_IM 5 #endif /* _FALCON_IRQ__ */ diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h index 141076325307..0b424214a5e9 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h @@ -19,8 +19,6 @@ #define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0) -#define MIPS_CPU_TIMER_IRQ 7 - #define MAX_IM 5 #endif diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index c4ef1c31e0c4..6549499eb202 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -310,13 +310,6 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) /* tell oprofile which irq to use */ ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ); - /* - * if the timer irq is not one of the mips irqs we need to - * create a mapping - */ - if (MIPS_CPU_TIMER_IRQ != 7) - irq_create_mapping(ltq_domain, MIPS_CPU_TIMER_IRQ); - /* the external interrupts are optional and xway only */ eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway"); if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { @@ -353,7 +346,7 @@ EXPORT_SYMBOL_GPL(get_c0_perfcount_int); unsigned int get_c0_compare_int(void) { - return MIPS_CPU_TIMER_IRQ; + return CP0_LEGACY_COMPARE_IRQ; } static struct of_device_id __initdata of_irq_ids[] = { -- cgit v1.2.3-58-ga151 From 565dc8a4f55e491935bfb04866068d21784ea9a4 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Mon, 7 Jan 2019 20:45:15 +0100 Subject: MIPS: ath79: Enable OF serial ports in the default config CONFIG_SERIAL_OF_PLATFORM is needed to get a working console on the OF boards, enable it in the default config to get a working setup out of the box. Signed-off-by: Alban Bedel Signed-off-by: Paul Burton Cc: linux-mips@vger.kernel.org Cc: Ralf Baechle Cc: James Hogan Cc: linux-kernel@vger.kernel.org --- arch/mips/configs/ath79_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/configs/ath79_defconfig b/arch/mips/configs/ath79_defconfig index 4e4ec779f182..6f981af67826 100644 --- a/arch/mips/configs/ath79_defconfig +++ b/arch/mips/configs/ath79_defconfig @@ -66,6 +66,7 @@ CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_SERIAL_8250_PCI is not set CONFIG_SERIAL_8250_NR_UARTS=1 CONFIG_SERIAL_8250_RUNTIME_UARTS=1 +CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIAL_AR933X=y CONFIG_SERIAL_AR933X_CONSOLE=y # CONFIG_HW_RANDOM is not set -- cgit v1.2.3-58-ga151 From 02b2f549d502b46e68b97ea1452fb8853b3327dd Mon Sep 17 00:00:00 2001 From: Dongsheng Yang Date: Tue, 18 Dec 2018 04:31:48 -0500 Subject: libceph: allow setting abort_on_full for rbd Introduce a new option abort_on_full, default to false. Then we can get -ENOSPC when the pool is full, or reaches quota. [ Don't show abort_on_full in /proc/mounts. ] Signed-off-by: Dongsheng Yang Reviewed-by: Ilya Dryomov Signed-off-by: Ilya Dryomov --- fs/ceph/super.c | 4 ++-- include/linux/ceph/libceph.h | 6 ++++-- include/linux/ceph/osd_client.h | 1 - net/ceph/ceph_common.c | 11 ++++++++++- net/ceph/debugfs.c | 2 +- net/ceph/osd_client.c | 4 ++-- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 4e9a7cc488da..da2cd8e89062 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -530,7 +530,7 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) seq_putc(m, ','); pos = m->count; - ret = ceph_print_client_options(m, fsc->client); + ret = ceph_print_client_options(m, fsc->client, false); if (ret) return ret; @@ -640,7 +640,7 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, opt = NULL; /* fsc->client now owns this */ fsc->client->extra_mon_dispatch = extra_mon_dispatch; - fsc->client->osdc.abort_on_full = true; + ceph_set_opt(fsc->client, ABORT_ON_FULL); if (!fsopt->mds_namespace) { ceph_monc_want_map(&fsc->client->monc, CEPH_SUB_MDSMAP, diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 68bb09c29ce8..a420c07904bc 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -35,6 +35,7 @@ #define CEPH_OPT_NOMSGAUTH (1<<4) /* don't require msg signing feat */ #define CEPH_OPT_TCP_NODELAY (1<<5) /* TCP_NODELAY on TCP sockets */ #define CEPH_OPT_NOMSGSIGN (1<<6) /* don't sign msgs */ +#define CEPH_OPT_ABORT_ON_FULL (1<<7) /* abort w/ ENOSPC when full */ #define CEPH_OPT_DEFAULT (CEPH_OPT_TCP_NODELAY) @@ -53,7 +54,7 @@ struct ceph_options { unsigned long osd_request_timeout; /* jiffies */ /* - * any type that can't be simply compared or doesn't need need + * any type that can't be simply compared or doesn't need * to be compared should go beyond this point, * ceph_compare_options() should be updated accordingly */ @@ -281,7 +282,8 @@ extern struct ceph_options *ceph_parse_options(char *options, const char *dev_name, const char *dev_name_end, int (*parse_extra_token)(char *c, void *private), void *private); -int ceph_print_client_options(struct seq_file *m, struct ceph_client *client); +int ceph_print_client_options(struct seq_file *m, struct ceph_client *client, + bool show_all); extern void ceph_destroy_options(struct ceph_options *opt); extern int ceph_compare_options(struct ceph_options *new_opt, struct ceph_client *client); diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index 7a2af5034278..2294f963dab7 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -354,7 +354,6 @@ struct ceph_osd_client { struct rb_root linger_map_checks; atomic_t num_requests; atomic_t num_homeless; - bool abort_on_full; /* abort w/ ENOSPC when full */ int abort_err; struct delayed_work timeout_work; struct delayed_work osds_timeout_work; diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 87afb9ec4c68..9cab80207ced 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -255,6 +255,7 @@ enum { Opt_nocephx_sign_messages, Opt_tcp_nodelay, Opt_notcp_nodelay, + Opt_abort_on_full, }; static match_table_t opt_tokens = { @@ -280,6 +281,7 @@ static match_table_t opt_tokens = { {Opt_nocephx_sign_messages, "nocephx_sign_messages"}, {Opt_tcp_nodelay, "tcp_nodelay"}, {Opt_notcp_nodelay, "notcp_nodelay"}, + {Opt_abort_on_full, "abort_on_full"}, {-1, NULL} }; @@ -535,6 +537,10 @@ ceph_parse_options(char *options, const char *dev_name, opt->flags &= ~CEPH_OPT_TCP_NODELAY; break; + case Opt_abort_on_full: + opt->flags |= CEPH_OPT_ABORT_ON_FULL; + break; + default: BUG_ON(token); } @@ -549,7 +555,8 @@ out: } EXPORT_SYMBOL(ceph_parse_options); -int ceph_print_client_options(struct seq_file *m, struct ceph_client *client) +int ceph_print_client_options(struct seq_file *m, struct ceph_client *client, + bool show_all) { struct ceph_options *opt = client->options; size_t pos = m->count; @@ -574,6 +581,8 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client) seq_puts(m, "nocephx_sign_messages,"); if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0) seq_puts(m, "notcp_nodelay,"); + if (show_all && (opt->flags & CEPH_OPT_ABORT_ON_FULL)) + seq_puts(m, "abort_on_full,"); if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) seq_printf(m, "mount_timeout=%d,", diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c index 02952605d121..46f65709a6ff 100644 --- a/net/ceph/debugfs.c +++ b/net/ceph/debugfs.c @@ -375,7 +375,7 @@ static int client_options_show(struct seq_file *s, void *p) struct ceph_client *client = s->private; int ret; - ret = ceph_print_client_options(s, client); + ret = ceph_print_client_options(s, client, true); if (ret) return ret; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index d23a9f81f3d7..fa9530dd876e 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -2315,7 +2315,7 @@ again: (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) || pool_full(osdc, req->r_t.base_oloc.pool))) { dout("req %p full/pool_full\n", req); - if (osdc->abort_on_full) { + if (ceph_test_opt(osdc->client, ABORT_ON_FULL)) { err = -ENOSPC; } else { pr_warn_ratelimited("FULL or reached pool quota\n"); @@ -2545,7 +2545,7 @@ static void ceph_osdc_abort_on_full(struct ceph_osd_client *osdc) { bool victims = false; - if (osdc->abort_on_full && + if (ceph_test_opt(osdc->client, ABORT_ON_FULL) && (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL) || have_pool_full(osdc))) for_each_request(osdc, abort_on_full_fn, &victims); } -- cgit v1.2.3-58-ga151 From c64a2b0516a02361d8deb1f038647c29020d0852 Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Sat, 5 Jan 2019 01:00:29 +0530 Subject: ceph: use vmf_error() in ceph_filemap_fault() This code is converted to use vmf_error(). Signed-off-by: Souptick Joarder Reviewed-by: Ilya Dryomov Signed-off-by: Ilya Dryomov --- fs/ceph/addr.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 5d0c05e288cc..a47c541f8006 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1494,10 +1494,7 @@ static vm_fault_t ceph_filemap_fault(struct vm_fault *vmf) if (err < 0 || off >= i_size_read(inode)) { unlock_page(page); put_page(page); - if (err == -ENOMEM) - ret = VM_FAULT_OOM; - else - ret = VM_FAULT_SIGBUS; + ret = vmf_error(err); goto out_inline; } if (err < PAGE_SIZE) -- cgit v1.2.3-58-ga151 From a769fa7208b94f37b6240215dc6970f9d76fc58c Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 7 Jan 2019 22:57:17 +0100 Subject: bpf, doc: update design qa to reflect kern_version requirement Update the bpf_design_QA.rst to also reflect recent changes in 6c4fc209fcf9 ("bpf: remove useless version check for prog load"). Suggested-by: Quentin Monnet Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: Alexei Starovoitov --- Documentation/bpf/bpf_design_QA.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Documentation/bpf/bpf_design_QA.rst b/Documentation/bpf/bpf_design_QA.rst index 6780a6d81745..7cc9e368c1e9 100644 --- a/Documentation/bpf/bpf_design_QA.rst +++ b/Documentation/bpf/bpf_design_QA.rst @@ -157,12 +157,11 @@ Q: Does BPF have a stable ABI? ------------------------------ A: YES. BPF instructions, arguments to BPF programs, set of helper functions and their arguments, recognized return codes are all part -of ABI. However when tracing programs are using bpf_probe_read() helper -to walk kernel internal datastructures and compile with kernel -internal headers these accesses can and will break with newer -kernels. The union bpf_attr -> kern_version is checked at load time -to prevent accidentally loading kprobe-based bpf programs written -for a different kernel. Networking programs don't do kern_version check. +of ABI. However there is one specific exception to tracing programs +which are using helpers like bpf_probe_read() to walk kernel internal +data structures and compile with kernel internal headers. Both of these +kernel internals are subject to change and can break with newer kernels +such that the program needs to be adapted accordingly. Q: How much stack space a BPF program uses? ------------------------------------------- -- cgit v1.2.3-58-ga151 From 80f21ff987eb377140d27102285f8dd1167b335c Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 7 Jan 2019 22:57:18 +0100 Subject: bpf, doc: add note for libbpf's stand-alone build Given this came up couple of times, add a note to libbpf's readme about the semi-automated mirror for a stand-alone build which is officially managed by BPF folks. While at it, also explicitly state the libbpf license in the readme file. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/README.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/lib/bpf/README.rst b/tools/lib/bpf/README.rst index 056f38310722..607aae40f4ed 100644 --- a/tools/lib/bpf/README.rst +++ b/tools/lib/bpf/README.rst @@ -132,6 +132,20 @@ For example, if current state of ``libbpf.map`` is: Format of version script and ways to handle ABI changes, including incompatible ones, described in details in [1]. +Stand-alone build +================= + +Under https://github.com/libbpf/libbpf there is a (semi-)automated +mirror of the mainline's version of libbpf for a stand-alone build. + +However, all changes to libbpf's code base must be upstreamed through +the mainline kernel tree. + +License +======= + +libbpf is dual-licensed under LGPL 2.1 and BSD 2-Clause. + Links ===== -- cgit v1.2.3-58-ga151 From b0407d820b65272fcaa77e0dd1347dc7678d23b8 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 7 Jan 2019 12:34:31 -0600 Subject: hwmon: (occ) Fix potential integer overflow Cast get_unaligned_be32(...) to u64 in order to give the compiler complete information about the proper arithmetic to use and avoid a potential integer overflow. Notice that such function call is used in contexts that expect expressions of type u64 (64 bits, unsigned); and the following expressions are currently being evaluated using 32-bit arithmetic: val = get_unaligned_be32(&power->update_tag) * occ->powr_sample_time_us; val = get_unaligned_be32(&power->vdn.update_tag) * occ->powr_sample_time_us; Addresses-Coverity-ID: 1442357 ("Unintentional integer overflow") Addresses-Coverity-ID: 1442476 ("Unintentional integer overflow") Addresses-Coverity-ID: 1442508 ("Unintentional integer overflow") Fixes: ff692d80b2e2 ("hwmon (occ): Add sensor types and versions") Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Reviewed-by: Eddie James Signed-off-by: Guenter Roeck --- drivers/hwmon/occ/common.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index 423903f87955..391118c8aae8 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -380,8 +380,8 @@ static ssize_t occ_show_power_1(struct device *dev, val *= 1000000ULL; break; case 2: - val = get_unaligned_be32(&power->update_tag) * - occ->powr_sample_time_us; + val = (u64)get_unaligned_be32(&power->update_tag) * + occ->powr_sample_time_us; break; case 3: val = get_unaligned_be16(&power->value) * 1000000ULL; @@ -425,8 +425,8 @@ static ssize_t occ_show_power_2(struct device *dev, &power->update_tag); break; case 2: - val = get_unaligned_be32(&power->update_tag) * - occ->powr_sample_time_us; + val = (u64)get_unaligned_be32(&power->update_tag) * + occ->powr_sample_time_us; break; case 3: val = get_unaligned_be16(&power->value) * 1000000ULL; @@ -463,8 +463,8 @@ static ssize_t occ_show_power_a0(struct device *dev, &power->system.update_tag); break; case 2: - val = get_unaligned_be32(&power->system.update_tag) * - occ->powr_sample_time_us; + val = (u64)get_unaligned_be32(&power->system.update_tag) * + occ->powr_sample_time_us; break; case 3: val = get_unaligned_be16(&power->system.value) * 1000000ULL; @@ -477,8 +477,8 @@ static ssize_t occ_show_power_a0(struct device *dev, &power->proc.update_tag); break; case 6: - val = get_unaligned_be32(&power->proc.update_tag) * - occ->powr_sample_time_us; + val = (u64)get_unaligned_be32(&power->proc.update_tag) * + occ->powr_sample_time_us; break; case 7: val = get_unaligned_be16(&power->proc.value) * 1000000ULL; @@ -491,8 +491,8 @@ static ssize_t occ_show_power_a0(struct device *dev, &power->vdd.update_tag); break; case 10: - val = get_unaligned_be32(&power->vdd.update_tag) * - occ->powr_sample_time_us; + val = (u64)get_unaligned_be32(&power->vdd.update_tag) * + occ->powr_sample_time_us; break; case 11: val = get_unaligned_be16(&power->vdd.value) * 1000000ULL; @@ -505,8 +505,8 @@ static ssize_t occ_show_power_a0(struct device *dev, &power->vdn.update_tag); break; case 14: - val = get_unaligned_be32(&power->vdn.update_tag) * - occ->powr_sample_time_us; + val = (u64)get_unaligned_be32(&power->vdn.update_tag) * + occ->powr_sample_time_us; break; case 15: val = get_unaligned_be16(&power->vdn.value) * 1000000ULL; -- cgit v1.2.3-58-ga151 From a77d1d196bc63b37d9b4d1b614884669e8e79d32 Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Mon, 7 Jan 2019 16:16:31 -0700 Subject: samples/seccomp: Fix 32-bit build Both the .o and the actual executable need to be built with -m32 in order to link correctly. Reported-by: Ingo Molnar Signed-off-by: Tycho Andersen Reviewed-by: Kees Cook Cc: Borislav Petkov Cc: James Morris Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: fec7b6690541 ("samples: add an example of seccomp user trap") Link: http://lkml.kernel.org/r/20190107231631.1849-1-tycho@tycho.ws Signed-off-by: Ingo Molnar --- samples/seccomp/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile index 4920903c8009..fb43a814d4c0 100644 --- a/samples/seccomp/Makefile +++ b/samples/seccomp/Makefile @@ -34,6 +34,7 @@ HOSTCFLAGS_bpf-direct.o += $(MFLAG) HOSTCFLAGS_dropper.o += $(MFLAG) HOSTCFLAGS_bpf-helper.o += $(MFLAG) HOSTCFLAGS_bpf-fancy.o += $(MFLAG) +HOSTCFLAGS_user-trap.o += $(MFLAG) HOSTLDLIBS_bpf-direct += $(MFLAG) HOSTLDLIBS_bpf-fancy += $(MFLAG) HOSTLDLIBS_dropper += $(MFLAG) -- cgit v1.2.3-58-ga151 From 6529870cb0323823f49b3e95d1760383910f96cd Mon Sep 17 00:00:00 2001 From: Madhavan Srinivasan Date: Sun, 9 Dec 2018 14:55:36 +0530 Subject: powerpc/perf: Update perf_regs structure to include MMCRA On each sample, Monitor Mode Control Register A (MMCRA) content is saved in pt_regs. MMCRA does not have a entry as-is in the pt_regs but instead, MMCRA content is saved in the "dsisr" register of pt_regs. Patch adds another entry to the perf_regs structure to include the "MMCRA" printing which internally maps to the "dsisr" of pt_regs. It also check for the MMCRA availability in the platform and present value accordingly mpe: This was the 2nd patch in a series with commit 333804dc3b7a ("powerpc/perf: Update perf_regs structure to include SIER") but I accidentally only merged the 1st patch, so merge this one now. Signed-off-by: Madhavan Srinivasan Signed-off-by: Michael Ellerman --- arch/powerpc/include/uapi/asm/perf_regs.h | 1 + arch/powerpc/perf/perf_regs.c | 6 ++++++ tools/arch/powerpc/include/uapi/asm/perf_regs.h | 1 + tools/perf/arch/powerpc/include/perf_regs.h | 3 ++- tools/perf/arch/powerpc/util/perf_regs.c | 1 + 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/uapi/asm/perf_regs.h b/arch/powerpc/include/uapi/asm/perf_regs.h index ff91192407d1..f599064dd8dc 100644 --- a/arch/powerpc/include/uapi/asm/perf_regs.h +++ b/arch/powerpc/include/uapi/asm/perf_regs.h @@ -47,6 +47,7 @@ enum perf_event_powerpc_regs { PERF_REG_POWERPC_DAR, PERF_REG_POWERPC_DSISR, PERF_REG_POWERPC_SIER, + PERF_REG_POWERPC_MMCRA, PERF_REG_POWERPC_MAX, }; #endif /* _UAPI_ASM_POWERPC_PERF_REGS_H */ diff --git a/arch/powerpc/perf/perf_regs.c b/arch/powerpc/perf/perf_regs.c index 5c36b3a8d47a..3349f3f8fe84 100644 --- a/arch/powerpc/perf/perf_regs.c +++ b/arch/powerpc/perf/perf_regs.c @@ -70,6 +70,7 @@ static unsigned int pt_regs_offset[PERF_REG_POWERPC_MAX] = { PT_REGS_OFFSET(PERF_REG_POWERPC_DAR, dar), PT_REGS_OFFSET(PERF_REG_POWERPC_DSISR, dsisr), PT_REGS_OFFSET(PERF_REG_POWERPC_SIER, dar), + PT_REGS_OFFSET(PERF_REG_POWERPC_MMCRA, dsisr), }; u64 perf_reg_value(struct pt_regs *regs, int idx) @@ -83,6 +84,11 @@ u64 perf_reg_value(struct pt_regs *regs, int idx) !is_sier_available())) return 0; + if (idx == PERF_REG_POWERPC_MMCRA && + (IS_ENABLED(CONFIG_FSL_EMB_PERF_EVENT) || + IS_ENABLED(CONFIG_PPC32))) + return 0; + return regs_get_register(regs, pt_regs_offset[idx]); } diff --git a/tools/arch/powerpc/include/uapi/asm/perf_regs.h b/tools/arch/powerpc/include/uapi/asm/perf_regs.h index ff91192407d1..f599064dd8dc 100644 --- a/tools/arch/powerpc/include/uapi/asm/perf_regs.h +++ b/tools/arch/powerpc/include/uapi/asm/perf_regs.h @@ -47,6 +47,7 @@ enum perf_event_powerpc_regs { PERF_REG_POWERPC_DAR, PERF_REG_POWERPC_DSISR, PERF_REG_POWERPC_SIER, + PERF_REG_POWERPC_MMCRA, PERF_REG_POWERPC_MAX, }; #endif /* _UAPI_ASM_POWERPC_PERF_REGS_H */ diff --git a/tools/perf/arch/powerpc/include/perf_regs.h b/tools/perf/arch/powerpc/include/perf_regs.h index 1076393e6f43..e18a3556f5e3 100644 --- a/tools/perf/arch/powerpc/include/perf_regs.h +++ b/tools/perf/arch/powerpc/include/perf_regs.h @@ -63,7 +63,8 @@ static const char *reg_names[] = { [PERF_REG_POWERPC_TRAP] = "trap", [PERF_REG_POWERPC_DAR] = "dar", [PERF_REG_POWERPC_DSISR] = "dsisr", - [PERF_REG_POWERPC_SIER] = "sier" + [PERF_REG_POWERPC_SIER] = "sier", + [PERF_REG_POWERPC_MMCRA] = "mmcra" }; static inline const char *perf_reg_name(int id) diff --git a/tools/perf/arch/powerpc/util/perf_regs.c b/tools/perf/arch/powerpc/util/perf_regs.c index 07fcd977d93e..34d5134681d9 100644 --- a/tools/perf/arch/powerpc/util/perf_regs.c +++ b/tools/perf/arch/powerpc/util/perf_regs.c @@ -53,6 +53,7 @@ const struct sample_reg sample_reg_masks[] = { SMPL_REG(dar, PERF_REG_POWERPC_DAR), SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR), SMPL_REG(sier, PERF_REG_POWERPC_SIER), + SMPL_REG(mmcra, PERF_REG_POWERPC_MMCRA), SMPL_REG_END }; -- cgit v1.2.3-58-ga151 From 2f66196208c98b3d1b4294edffb2c5a8197be899 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 7 Jan 2019 18:51:53 +0000 Subject: cpufreq: check if policy is inactive early in __cpufreq_get() cpuinfo_cur_freq gets current CPU frequency as detected by hardware while scaling_cur_freq last known CPU frequency. Some platforms may not allow checking the CPU frequency of an offline CPU or the associated resources may have been released via cpufreq_exit when the CPU gets offlined, in which case the policy would have been invalidated already. If we attempt to get current frequency from the hardware, it may result in hang or crash. For example on Juno, I see: Unable to handle kernel NULL pointer dereference at virtual address 0000000000000188 [0000000000000188] pgd=0000000000000000 Internal error: Oops: 96000004 [#1] PREEMPT SMP Modules linked in: CPU: 5 PID: 4202 Comm: cat Not tainted 4.20.0-08251-ga0f2c0318a15-dirty #87 Hardware name: ARM LTD ARM Juno Development Platform/ARM Juno Development Platform pstate: 40000005 (nZcv daif -PAN -UAO) pc : scmi_cpufreq_get_rate+0x34/0xb0 lr : scmi_cpufreq_get_rate+0x34/0xb0 Call trace: scmi_cpufreq_get_rate+0x34/0xb0 __cpufreq_get+0x34/0xc0 show_cpuinfo_cur_freq+0x24/0x78 show+0x40/0x60 sysfs_kf_seq_show+0xc0/0x148 kernfs_seq_show+0x44/0x50 seq_read+0xd4/0x480 kernfs_fop_read+0x15c/0x208 __vfs_read+0x60/0x188 vfs_read+0x94/0x150 ksys_read+0x6c/0xd8 __arm64_sys_read+0x24/0x30 el0_svc_common+0x78/0x100 el0_svc_handler+0x38/0x78 el0_svc+0x8/0xc ---[ end trace 3d1024e58f77f6b2 ]--- So fix the issue by checking if the policy is invalid early in __cpufreq_get before attempting to get the current frequency. Signed-off-by: Sudeep Holla Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 7aa3dcad2175..df34a12a388f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1530,17 +1530,16 @@ static unsigned int __cpufreq_get(struct cpufreq_policy *policy) { unsigned int ret_freq = 0; - if (!cpufreq_driver->get) + if (unlikely(policy_is_inactive(policy)) || !cpufreq_driver->get) return ret_freq; ret_freq = cpufreq_driver->get(policy->cpu); /* - * Updating inactive policies is invalid, so avoid doing that. Also - * if fast frequency switching is used with the given policy, the check + * If fast frequency switching is used with the given policy, the check * against policy->cur is pointless, so skip it in that case too. */ - if (unlikely(policy_is_inactive(policy)) || policy->fast_switch_enabled) + if (policy->fast_switch_enabled) return ret_freq; if (ret_freq && policy->cur && @@ -1569,10 +1568,7 @@ unsigned int cpufreq_get(unsigned int cpu) if (policy) { down_read(&policy->rwsem); - - if (!policy_is_inactive(policy)) - ret_freq = __cpufreq_get(policy); - + ret_freq = __cpufreq_get(policy); up_read(&policy->rwsem); cpufreq_cpu_put(policy); -- cgit v1.2.3-58-ga151 From 81d9bdf59092e4755fc4307c93c4589ef0fe2e0f Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 23 Dec 2018 01:31:26 +0100 Subject: mtd: rawnand: qcom: fix memory corruption that causes panic This patch fixes a memory corruption that occurred in the qcom-nandc driver since it was converted to nand_scan(). On boot, an affected device will panic from a NPE at a weird place: | Unable to handle kernel NULL pointer dereference at virtual address 0 | pgd = (ptrval) | [00000000] *pgd=00000000 | Internal error: Oops: 80000005 [#1] SMP ARM | CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.9 #0 | Hardware name: Generic DT based system | PC is at (null) | LR is at nand_block_isbad+0x90/0xa4 | pc : [<00000000>] lr : [] psr: 80000013 | sp : cf839d40 ip : 00000000 fp : cfae9e20 | r10: cf815810 r9 : 00000000 r8 : 00000000 | r7 : 00000000 r6 : 00000000 r5 : 00000001 r4 : cf815810 | r3 : 00000000 r2 : cfae9810 r1 : ffffffff r0 : cf815810 | Flags: Nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none | Control: 10c5387d Table: 8020406a DAC: 00000051 | Process swapper/0 (pid: 1, stack limit = 0x(ptrval)) | [] (nand_block_isbad) from [] | [] (allocate_partition) from [] | [] (add_mtd_partitions) from [] | [] (parse_mtd_partitions) from [] | [] (mtd_device_parse_register) from [] | [] (qcom_nandc_probe) from [] The problem is that the nand_scan()'s qcom_nand_attach_chip callback is updating the nandc->max_cwperpage from 1 to 4. This causes the sg_init_table of clear_bam_transaction() in the driver's qcom_nandc_block_bad() to memset much more than what was initially allocated by alloc_bam_transaction(). This patch restores the old behavior by reallocating the shared bam transaction alloc_bam_transaction() after the chip was identified, but before mtd_device_parse_register() (which is an alias for mtd_device_register() - see panic) gets called. This fixes the corruption and the driver is working again. Cc: stable@vger.kernel.org Fixes: 6a3cec64f18c ("mtd: rawnand: qcom: convert driver to nand_scan()") Signed-off-by: Christian Lamparter Acked-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/qcom_nandc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 46c62a31fa46..920e7375084f 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2833,6 +2833,16 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, if (ret) return ret; + if (nandc->props->is_bam) { + free_bam_transaction(nandc); + nandc->bam_txn = alloc_bam_transaction(nandc); + if (!nandc->bam_txn) { + dev_err(nandc->dev, + "failed to allocate bam transaction\n"); + return -ENOMEM; + } + } + ret = mtd_device_register(mtd, NULL, 0); if (ret) nand_cleanup(chip); @@ -2847,16 +2857,6 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc) struct qcom_nand_host *host; int ret; - if (nandc->props->is_bam) { - free_bam_transaction(nandc); - nandc->bam_txn = alloc_bam_transaction(nandc); - if (!nandc->bam_txn) { - dev_err(nandc->dev, - "failed to allocate bam transaction\n"); - return -ENOMEM; - } - } - for_each_available_child_of_node(dn, child) { host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); if (!host) { -- cgit v1.2.3-58-ga151 From f553aa1c13cbc29aaf420349a28fc33ca98440e5 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 8 Jan 2019 19:52:22 +0800 Subject: csky: fixup relocation error with 807 & 860 810 doesn't support jsri instruction and csky-as will leave jsri + nop for relocation. Module-probe need replace them with lrw + jsr. Signed-off-by: Guo Ren Cc: Hui Kai --- arch/csky/kernel/module.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/arch/csky/kernel/module.c b/arch/csky/kernel/module.c index 65abab0c7a47..0b028ee3c764 100644 --- a/arch/csky/kernel/module.c +++ b/arch/csky/kernel/module.c @@ -12,7 +12,7 @@ #include #include -#if defined(__CSKYABIV2__) +#ifdef CONFIG_CPU_CK810 #define IS_BSR32(hi16, lo16) (((hi16) & 0xFC00) == 0xE000) #define IS_JSRI32(hi16, lo16) ((hi16) == 0xEAE0) @@ -25,6 +25,26 @@ *(uint16_t *)(addr) = 0xE8Fa; \ *((uint16_t *)(addr) + 1) = 0x0000; \ } while (0) + +static void jsri_2_lrw_jsr(uint32_t *location) +{ + uint16_t location_tmp = (uint16_t *)location; + + if (IS_BSR32(*location_tmp, *(location_tmp + 1))) + return; + + if (IS_JSRI32(*location_tmp, *(location_tmp + 1))) { + /* jsri 0x... --> lrw r26, 0x... */ + CHANGE_JSRI_TO_LRW(location); + /* lsli r0, r0 --> jsr r26 */ + SET_JSR32_R26(location + 1); + } +} +#else +static void inline jsri_2_lrw_jsr(uint32_t *location) +{ + return; +} #endif int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, @@ -35,9 +55,6 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, Elf32_Sym *sym; uint32_t *location; short *temp; -#if defined(__CSKYABIV2__) - uint16_t *location_tmp; -#endif for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ @@ -59,18 +76,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, case R_CSKY_PCRELJSR_IMM11BY2: break; case R_CSKY_PCRELJSR_IMM26BY2: -#if defined(__CSKYABIV2__) - location_tmp = (uint16_t *)location; - if (IS_BSR32(*location_tmp, *(location_tmp + 1))) - break; - - if (IS_JSRI32(*location_tmp, *(location_tmp + 1))) { - /* jsri 0x... --> lrw r26, 0x... */ - CHANGE_JSRI_TO_LRW(location); - /* lsli r0, r0 --> jsr r26 */ - SET_JSR32_R26(location + 1); - } -#endif + jsri_2_lrw_jsr(location); break; case R_CSKY_ADDR_HI16: temp = ((short *)location) + 1; -- cgit v1.2.3-58-ga151 From 750afb08ca71310fcf0c4e2cb1565c63b8235b60 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Fri, 4 Jan 2019 09:23:09 +0100 Subject: cross-tree: phase out dma_zalloc_coherent() We already need to zero out memory for dma_alloc_coherent(), as such using dma_zalloc_coherent() is superflous. Phase it out. This change was generated with the following Coccinelle SmPL patch: @ replace_dma_zalloc_coherent @ expression dev, size, data, handle, flags; @@ -dma_zalloc_coherent(dev, size, handle, flags) +dma_alloc_coherent(dev, size, handle, flags) Suggested-by: Christoph Hellwig Signed-off-by: Luis Chamberlain [hch: re-ran the script on the latest tree] Signed-off-by: Christoph Hellwig --- arch/mips/lantiq/xway/dma.c | 6 +- arch/powerpc/platforms/pasemi/dma_lib.c | 2 +- arch/powerpc/sysdev/fsl_rmu.c | 7 ++- drivers/ata/sata_fsl.c | 4 +- drivers/atm/he.c | 39 ++++++------- drivers/atm/idt77252.c | 16 ++--- drivers/block/skd_main.c | 4 +- drivers/crypto/amcc/crypto4xx_core.c | 6 +- drivers/crypto/cavium/cpt/cptpf_main.c | 4 +- drivers/crypto/cavium/cpt/cptvf_main.c | 7 ++- drivers/crypto/cavium/nitrox/nitrox_lib.c | 6 +- drivers/crypto/ccp/ccp-dev-v5.c | 6 +- drivers/crypto/hisilicon/sec/sec_algs.c | 4 +- drivers/crypto/hisilicon/sec/sec_drv.c | 15 ++--- drivers/crypto/ixp4xx_crypto.c | 6 +- drivers/crypto/mediatek/mtk-platform.c | 16 ++--- drivers/crypto/qat/qat_common/adf_admin.c | 12 ++-- drivers/crypto/qat/qat_common/qat_algs.c | 24 ++++---- drivers/crypto/qat/qat_common/qat_asym_algs.c | 68 +++++++++++----------- drivers/dma/imx-sdma.c | 8 +-- drivers/dma/mediatek/mtk-hsdma.c | 4 +- drivers/dma/mxs-dma.c | 6 +- drivers/dma/xgene-dma.c | 4 +- drivers/dma/xilinx/xilinx_dma.c | 14 ++--- drivers/dma/xilinx/zynqmp_dma.c | 6 +- drivers/gpu/drm/drm_pci.c | 5 +- drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 4 +- drivers/infiniband/hw/bnxt_re/qplib_res.c | 8 +-- drivers/infiniband/hw/cxgb3/cxio_hal.c | 6 +- drivers/infiniband/hw/cxgb4/qp.c | 5 +- drivers/infiniband/hw/hfi1/init.c | 29 ++++----- drivers/infiniband/hw/hfi1/pio.c | 9 ++- drivers/infiniband/hw/hfi1/sdma.c | 27 +++------ drivers/infiniband/hw/hns/hns_roce_alloc.c | 11 ++-- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 10 ++-- drivers/infiniband/hw/i40iw/i40iw_utils.c | 4 +- drivers/infiniband/hw/mthca/mthca_memfree.c | 5 +- drivers/infiniband/hw/ocrdma/ocrdma_hw.c | 14 ++--- drivers/infiniband/hw/ocrdma/ocrdma_stats.c | 4 +- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 6 +- drivers/infiniband/hw/qedr/verbs.c | 4 +- drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c | 4 +- drivers/input/touchscreen/raspberrypi-ts.c | 4 +- drivers/iommu/mtk_iommu_v1.c | 5 +- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 4 +- .../media/platform/mtk-vcodec/mtk_vcodec_util.c | 2 +- drivers/misc/genwqe/card_utils.c | 4 +- drivers/mmc/host/sdhci.c | 5 +- drivers/net/ethernet/aeroflex/greth.c | 12 ++-- drivers/net/ethernet/alacritech/slicoss.c | 12 ++-- drivers/net/ethernet/amazon/ena/ena_com.c | 61 +++++++++---------- drivers/net/ethernet/apm/xgene-v2/main.c | 8 +-- drivers/net/ethernet/atheros/alx/main.c | 7 +-- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 4 +- drivers/net/ethernet/broadcom/bcm63xx_enet.c | 8 +-- drivers/net/ethernet/broadcom/bcmsysport.c | 4 +- drivers/net/ethernet/broadcom/bgmac.c | 12 ++-- drivers/net/ethernet/broadcom/bnx2.c | 4 +- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 16 ++--- drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c | 4 +- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 4 +- drivers/net/ethernet/broadcom/tg3.c | 22 +++---- drivers/net/ethernet/cavium/thunder/nicvf_queues.c | 2 +- drivers/net/ethernet/chelsio/cxgb3/sge.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/sge.c | 2 +- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 2 +- drivers/net/ethernet/emulex/benet/be_cmds.c | 68 +++++++++++----------- drivers/net/ethernet/emulex/benet/be_ethtool.c | 18 +++--- drivers/net/ethernet/emulex/benet/be_main.c | 18 +++--- drivers/net/ethernet/faraday/ftgmac100.c | 14 ++--- drivers/net/ethernet/faraday/ftmac100.c | 7 +-- drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 4 +- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 5 +- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 5 +- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c | 5 +- .../net/ethernet/huawei/hinic/hinic_hw_api_cmd.c | 16 ++--- drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c | 8 +-- drivers/net/ethernet/huawei/hinic/hinic_hw_io.c | 6 +- drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c | 10 ++-- drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c | 8 +-- drivers/net/ethernet/ibm/emac/mal.c | 4 +- drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 8 +-- drivers/net/ethernet/intel/e1000e/netdev.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 +- drivers/net/ethernet/intel/ixgb/ixgb_main.c | 8 +-- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 6 +- drivers/net/ethernet/marvell/pxa168_eth.c | 18 +++--- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 18 +++--- drivers/net/ethernet/mellanox/mlx4/alloc.c | 8 +-- drivers/net/ethernet/mellanox/mlx5/core/alloc.c | 4 +- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 10 ++-- drivers/net/ethernet/myricom/myri10ge/myri10ge.c | 6 +- .../net/ethernet/netronome/nfp/nfp_net_common.c | 12 ++-- drivers/net/ethernet/ni/nixge.c | 12 ++-- .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 12 ++-- drivers/net/ethernet/pasemi/pasemi_mac.c | 6 +- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 16 ++--- drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 28 ++++----- drivers/net/ethernet/qualcomm/emac/emac-mac.c | 2 +- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 12 ++-- drivers/net/ethernet/sfc/falcon/nic.c | 4 +- drivers/net/ethernet/sfc/nic.c | 4 +- drivers/net/ethernet/sgi/meth.c | 4 +- drivers/net/ethernet/socionext/netsec.c | 4 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 40 +++++-------- drivers/net/ethernet/tundra/tsi108_eth.c | 8 +-- drivers/net/ethernet/xilinx/ll_temac_main.c | 12 ++-- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 12 ++-- drivers/net/fddi/defxx.c | 6 +- drivers/net/fddi/skfp/skfddi.c | 8 +-- drivers/net/vmxnet3/vmxnet3_drv.c | 8 +-- drivers/net/wan/fsl_ucc_hdlc.c | 7 +-- drivers/net/wireless/ath/ath10k/ce.c | 7 +-- drivers/net/wireless/ath/ath10k/mac.c | 8 +-- drivers/net/wireless/ath/ath10k/pci.c | 3 +- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- drivers/net/wireless/ath/wcn36xx/dxe.c | 17 +++--- drivers/net/wireless/ath/wil6210/txrx_edma.c | 8 +-- drivers/net/wireless/broadcom/b43/dma.c | 6 +- drivers/net/wireless/broadcom/b43legacy/dma.c | 6 +- .../wireless/broadcom/brcm80211/brcmfmac/pcie.c | 16 ++--- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 39 +++++-------- drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c | 6 +- drivers/ntb/hw/mscc/ntb_hw_switchtec.c | 8 +-- drivers/nvme/host/pci.c | 8 +-- drivers/pci/controller/pcie-iproc-msi.c | 6 +- drivers/pci/switch/switchtec.c | 8 +-- drivers/rapidio/devices/tsi721.c | 22 +++---- drivers/rapidio/devices/tsi721_dma.c | 8 +-- drivers/s390/net/ism_drv.c | 15 +++-- drivers/scsi/3w-sas.c | 5 +- drivers/scsi/a100u2w.c | 8 +-- drivers/scsi/arcmsr/arcmsr_hba.c | 18 ++++-- drivers/scsi/be2iscsi/be_main.c | 4 +- drivers/scsi/be2iscsi/be_mgmt.c | 11 ++-- drivers/scsi/bfa/bfad_bsg.c | 6 +- drivers/scsi/bnx2fc/bnx2fc_hwi.c | 49 ++++++++-------- drivers/scsi/bnx2fc/bnx2fc_tgt.c | 44 +++++++------- drivers/scsi/bnx2i/bnx2i_hwi.c | 8 +-- drivers/scsi/csiostor/csio_wr.c | 4 +- drivers/scsi/lpfc/lpfc_bsg.c | 4 +- drivers/scsi/lpfc/lpfc_init.c | 14 ++--- drivers/scsi/lpfc/lpfc_mbox.c | 6 +- drivers/scsi/lpfc/lpfc_sli.c | 15 +++-- drivers/scsi/megaraid/megaraid_mbox.c | 15 ++--- drivers/scsi/megaraid/megaraid_sas_base.c | 26 ++++----- drivers/scsi/megaraid/megaraid_sas_fusion.c | 5 +- drivers/scsi/mesh.c | 5 +- drivers/scsi/mvumi.c | 9 +-- drivers/scsi/pm8001/pm8001_sas.c | 4 +- drivers/scsi/qedf/qedf_main.c | 29 +++++---- drivers/scsi/qedi/qedi_main.c | 39 ++++++------- drivers/scsi/qla2xxx/qla_attr.c | 4 +- drivers/scsi/qla2xxx/qla_bsg.c | 4 +- drivers/scsi/qla2xxx/qla_gs.c | 14 +++-- drivers/scsi/qla2xxx/qla_init.c | 8 +-- drivers/scsi/qla4xxx/ql4_init.c | 4 +- drivers/scsi/qla4xxx/ql4_mbx.c | 18 +++--- drivers/scsi/qla4xxx/ql4_nx.c | 4 +- drivers/scsi/qla4xxx/ql4_os.c | 10 ++-- drivers/scsi/smartpqi/smartpqi_init.c | 32 +++++----- drivers/soc/fsl/qbman/dpaa_sys.c | 2 +- drivers/spi/spi-pic32-sqi.c | 6 +- drivers/staging/mt7621-eth/mtk_eth_soc.c | 3 +- .../interface/vchiq_arm/vchiq_2835_arm.c | 6 +- drivers/staging/vt6655/device_main.c | 19 ++---- drivers/usb/gadget/udc/bdc/bdc_core.c | 13 ++--- drivers/usb/host/uhci-hcd.c | 6 +- drivers/usb/host/xhci-mem.c | 8 +-- drivers/video/fbdev/da8xx-fb.c | 6 +- include/linux/pci-dma-compat.h | 2 +- sound/aoa/soundbus/i2sbus/core.c | 4 +- sound/sparc/dbri.c | 4 +- 173 files changed, 915 insertions(+), 949 deletions(-) diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c index 982859f2b2a3..5e6a1a45cbd2 100644 --- a/arch/mips/lantiq/xway/dma.c +++ b/arch/mips/lantiq/xway/dma.c @@ -129,9 +129,9 @@ ltq_dma_alloc(struct ltq_dma_channel *ch) unsigned long flags; ch->desc = 0; - ch->desc_base = dma_zalloc_coherent(ch->dev, - LTQ_DESC_NUM * LTQ_DESC_SIZE, - &ch->phys, GFP_ATOMIC); + ch->desc_base = dma_alloc_coherent(ch->dev, + LTQ_DESC_NUM * LTQ_DESC_SIZE, + &ch->phys, GFP_ATOMIC); spin_lock_irqsave(<q_dma_lock, flags); ltq_dma_w32(ch->nr, LTQ_DMA_CS); diff --git a/arch/powerpc/platforms/pasemi/dma_lib.c b/arch/powerpc/platforms/pasemi/dma_lib.c index d18d16489a15..bdf9b716e848 100644 --- a/arch/powerpc/platforms/pasemi/dma_lib.c +++ b/arch/powerpc/platforms/pasemi/dma_lib.c @@ -255,7 +255,7 @@ int pasemi_dma_alloc_ring(struct pasemi_dmachan *chan, int ring_size) chan->ring_size = ring_size; - chan->ring_virt = dma_zalloc_coherent(&dma_pdev->dev, + chan->ring_virt = dma_alloc_coherent(&dma_pdev->dev, ring_size * sizeof(u64), &chan->ring_dma, GFP_KERNEL); diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c index 8b0ebf3940d2..ebed46f80254 100644 --- a/arch/powerpc/sysdev/fsl_rmu.c +++ b/arch/powerpc/sysdev/fsl_rmu.c @@ -756,9 +756,10 @@ fsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) } /* Initialize outbound message descriptor ring */ - rmu->msg_tx_ring.virt = dma_zalloc_coherent(priv->dev, - rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE, - &rmu->msg_tx_ring.phys, GFP_KERNEL); + rmu->msg_tx_ring.virt = dma_alloc_coherent(priv->dev, + rmu->msg_tx_ring.size * RIO_MSG_DESC_SIZE, + &rmu->msg_tx_ring.phys, + GFP_KERNEL); if (!rmu->msg_tx_ring.virt) { rc = -ENOMEM; goto out_dma; diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 4dc528bf8e85..9c1247d42897 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -729,8 +729,8 @@ static int sata_fsl_port_start(struct ata_port *ap) if (!pp) return -ENOMEM; - mem = dma_zalloc_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, &mem_dma, - GFP_KERNEL); + mem = dma_alloc_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, &mem_dma, + GFP_KERNEL); if (!mem) { kfree(pp); return -ENOMEM; diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 29f102dcfec4..2e9d1cfe3aeb 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -533,9 +533,10 @@ static void he_init_tx_lbfp(struct he_dev *he_dev) static int he_init_tpdrq(struct he_dev *he_dev) { - he_dev->tpdrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, - CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), - &he_dev->tpdrq_phys, GFP_KERNEL); + he_dev->tpdrq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, + CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), + &he_dev->tpdrq_phys, + GFP_KERNEL); if (he_dev->tpdrq_base == NULL) { hprintk("failed to alloc tpdrq\n"); return -ENOMEM; @@ -805,9 +806,9 @@ static int he_init_group(struct he_dev *he_dev, int group) goto out_free_rbpl_virt; } - he_dev->rbpl_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, - CONFIG_RBPL_SIZE * sizeof(struct he_rbp), - &he_dev->rbpl_phys, GFP_KERNEL); + he_dev->rbpl_base = dma_alloc_coherent(&he_dev->pci_dev->dev, + CONFIG_RBPL_SIZE * sizeof(struct he_rbp), + &he_dev->rbpl_phys, GFP_KERNEL); if (he_dev->rbpl_base == NULL) { hprintk("failed to alloc rbpl_base\n"); goto out_destroy_rbpl_pool; @@ -844,9 +845,9 @@ static int he_init_group(struct he_dev *he_dev, int group) /* rx buffer ready queue */ - he_dev->rbrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, - CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), - &he_dev->rbrq_phys, GFP_KERNEL); + he_dev->rbrq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, + CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), + &he_dev->rbrq_phys, GFP_KERNEL); if (he_dev->rbrq_base == NULL) { hprintk("failed to allocate rbrq\n"); goto out_free_rbpl; @@ -868,9 +869,9 @@ static int he_init_group(struct he_dev *he_dev, int group) /* tx buffer ready queue */ - he_dev->tbrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, - CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), - &he_dev->tbrq_phys, GFP_KERNEL); + he_dev->tbrq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, + CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), + &he_dev->tbrq_phys, GFP_KERNEL); if (he_dev->tbrq_base == NULL) { hprintk("failed to allocate tbrq\n"); goto out_free_rbpq_base; @@ -913,11 +914,9 @@ static int he_init_irq(struct he_dev *he_dev) /* 2.9.3.5 tail offset for each interrupt queue is located after the end of the interrupt queue */ - he_dev->irq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev, - (CONFIG_IRQ_SIZE + 1) - * sizeof(struct he_irq), - &he_dev->irq_phys, - GFP_KERNEL); + he_dev->irq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, + (CONFIG_IRQ_SIZE + 1) * sizeof(struct he_irq), + &he_dev->irq_phys, GFP_KERNEL); if (he_dev->irq_base == NULL) { hprintk("failed to allocate irq\n"); return -ENOMEM; @@ -1464,9 +1463,9 @@ static int he_start(struct atm_dev *dev) /* host status page */ - he_dev->hsp = dma_zalloc_coherent(&he_dev->pci_dev->dev, - sizeof(struct he_hsp), - &he_dev->hsp_phys, GFP_KERNEL); + he_dev->hsp = dma_alloc_coherent(&he_dev->pci_dev->dev, + sizeof(struct he_hsp), + &he_dev->hsp_phys, GFP_KERNEL); if (he_dev->hsp == NULL) { hprintk("failed to allocate host status page\n"); return -ENOMEM; diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 6e737142ceaa..43a14579e80e 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -641,8 +641,8 @@ alloc_scq(struct idt77252_dev *card, int class) scq = kzalloc(sizeof(struct scq_info), GFP_KERNEL); if (!scq) return NULL; - scq->base = dma_zalloc_coherent(&card->pcidev->dev, SCQ_SIZE, - &scq->paddr, GFP_KERNEL); + scq->base = dma_alloc_coherent(&card->pcidev->dev, SCQ_SIZE, + &scq->paddr, GFP_KERNEL); if (scq->base == NULL) { kfree(scq); return NULL; @@ -971,8 +971,8 @@ init_rsq(struct idt77252_dev *card) { struct rsq_entry *rsqe; - card->rsq.base = dma_zalloc_coherent(&card->pcidev->dev, RSQSIZE, - &card->rsq.paddr, GFP_KERNEL); + card->rsq.base = dma_alloc_coherent(&card->pcidev->dev, RSQSIZE, + &card->rsq.paddr, GFP_KERNEL); if (card->rsq.base == NULL) { printk("%s: can't allocate RSQ.\n", card->name); return -1; @@ -3390,10 +3390,10 @@ static int init_card(struct atm_dev *dev) writel(0, SAR_REG_GP); /* Initialize RAW Cell Handle Register */ - card->raw_cell_hnd = dma_zalloc_coherent(&card->pcidev->dev, - 2 * sizeof(u32), - &card->raw_cell_paddr, - GFP_KERNEL); + card->raw_cell_hnd = dma_alloc_coherent(&card->pcidev->dev, + 2 * sizeof(u32), + &card->raw_cell_paddr, + GFP_KERNEL); if (!card->raw_cell_hnd) { printk("%s: memory allocation failure.\n", card->name); deinit_card(card); diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index a10d5736d8f7..ab893a7571a2 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -2641,8 +2641,8 @@ static int skd_cons_skcomp(struct skd_device *skdev) "comp pci_alloc, total bytes %zd entries %d\n", SKD_SKCOMP_SIZE, SKD_N_COMPLETION_ENTRY); - skcomp = dma_zalloc_coherent(&skdev->pdev->dev, SKD_SKCOMP_SIZE, - &skdev->cq_dma_address, GFP_KERNEL); + skcomp = dma_alloc_coherent(&skdev->pdev->dev, SKD_SKCOMP_SIZE, + &skdev->cq_dma_address, GFP_KERNEL); if (skcomp == NULL) { rc = -ENOMEM; diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 63cb6956c948..acf79889d903 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -283,9 +283,9 @@ static u32 crypto4xx_put_pd_to_pdr(struct crypto4xx_device *dev, u32 idx) */ static u32 crypto4xx_build_gdr(struct crypto4xx_device *dev) { - dev->gdr = dma_zalloc_coherent(dev->core_dev->device, - sizeof(struct ce_gd) * PPC4XX_NUM_GD, - &dev->gdr_pa, GFP_ATOMIC); + dev->gdr = dma_alloc_coherent(dev->core_dev->device, + sizeof(struct ce_gd) * PPC4XX_NUM_GD, + &dev->gdr_pa, GFP_ATOMIC); if (!dev->gdr) return -ENOMEM; diff --git a/drivers/crypto/cavium/cpt/cptpf_main.c b/drivers/crypto/cavium/cpt/cptpf_main.c index 06ad85ab5e86..a876535529d1 100644 --- a/drivers/crypto/cavium/cpt/cptpf_main.c +++ b/drivers/crypto/cavium/cpt/cptpf_main.c @@ -278,8 +278,8 @@ static int cpt_ucode_load_fw(struct cpt_device *cpt, const u8 *fw, bool is_ae) mcode->num_cores = is_ae ? 6 : 10; /* Allocate DMAable space */ - mcode->code = dma_zalloc_coherent(&cpt->pdev->dev, mcode->code_size, - &mcode->phys_base, GFP_KERNEL); + mcode->code = dma_alloc_coherent(&cpt->pdev->dev, mcode->code_size, + &mcode->phys_base, GFP_KERNEL); if (!mcode->code) { dev_err(dev, "Unable to allocate space for microcode"); ret = -ENOMEM; diff --git a/drivers/crypto/cavium/cpt/cptvf_main.c b/drivers/crypto/cavium/cpt/cptvf_main.c index 5c796ed55eba..2ca431ed1db8 100644 --- a/drivers/crypto/cavium/cpt/cptvf_main.c +++ b/drivers/crypto/cavium/cpt/cptvf_main.c @@ -236,9 +236,10 @@ static int alloc_command_queues(struct cpt_vf *cptvf, c_size = (rem_q_size > qcsize_bytes) ? qcsize_bytes : rem_q_size; - curr->head = (u8 *)dma_zalloc_coherent(&pdev->dev, - c_size + CPT_NEXT_CHUNK_PTR_SIZE, - &curr->dma_addr, GFP_KERNEL); + curr->head = (u8 *)dma_alloc_coherent(&pdev->dev, + c_size + CPT_NEXT_CHUNK_PTR_SIZE, + &curr->dma_addr, + GFP_KERNEL); if (!curr->head) { dev_err(&pdev->dev, "Command Q (%d) chunk (%d) allocation failed\n", i, queue->nchunks); diff --git a/drivers/crypto/cavium/nitrox/nitrox_lib.c b/drivers/crypto/cavium/nitrox/nitrox_lib.c index 9138bae12521..4ace9bcd603a 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_lib.c +++ b/drivers/crypto/cavium/nitrox/nitrox_lib.c @@ -25,9 +25,9 @@ static int nitrox_cmdq_init(struct nitrox_cmdq *cmdq, int align_bytes) struct nitrox_device *ndev = cmdq->ndev; cmdq->qsize = (ndev->qlen * cmdq->instr_size) + align_bytes; - cmdq->unalign_base = dma_zalloc_coherent(DEV(ndev), cmdq->qsize, - &cmdq->unalign_dma, - GFP_KERNEL); + cmdq->unalign_base = dma_alloc_coherent(DEV(ndev), cmdq->qsize, + &cmdq->unalign_dma, + GFP_KERNEL); if (!cmdq->unalign_base) return -ENOMEM; diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c index 44a4d2779b15..c9bfd4f439ce 100644 --- a/drivers/crypto/ccp/ccp-dev-v5.c +++ b/drivers/crypto/ccp/ccp-dev-v5.c @@ -822,9 +822,9 @@ static int ccp5_init(struct ccp_device *ccp) /* Page alignment satisfies our needs for N <= 128 */ BUILD_BUG_ON(COMMANDS_PER_QUEUE > 128); cmd_q->qsize = Q_SIZE(Q_DESC_SIZE); - cmd_q->qbase = dma_zalloc_coherent(dev, cmd_q->qsize, - &cmd_q->qbase_dma, - GFP_KERNEL); + cmd_q->qbase = dma_alloc_coherent(dev, cmd_q->qsize, + &cmd_q->qbase_dma, + GFP_KERNEL); if (!cmd_q->qbase) { dev_err(dev, "unable to allocate command queue\n"); ret = -ENOMEM; diff --git a/drivers/crypto/hisilicon/sec/sec_algs.c b/drivers/crypto/hisilicon/sec/sec_algs.c index cdc4f9a171d9..adc0cd8ae97b 100644 --- a/drivers/crypto/hisilicon/sec/sec_algs.c +++ b/drivers/crypto/hisilicon/sec/sec_algs.c @@ -241,8 +241,8 @@ static int sec_alg_skcipher_setkey(struct crypto_skcipher *tfm, memset(ctx->key, 0, SEC_MAX_CIPHER_KEY); } else { /* new key */ - ctx->key = dma_zalloc_coherent(dev, SEC_MAX_CIPHER_KEY, - &ctx->pkey, GFP_KERNEL); + ctx->key = dma_alloc_coherent(dev, SEC_MAX_CIPHER_KEY, + &ctx->pkey, GFP_KERNEL); if (!ctx->key) { mutex_unlock(&ctx->lock); return -ENOMEM; diff --git a/drivers/crypto/hisilicon/sec/sec_drv.c b/drivers/crypto/hisilicon/sec/sec_drv.c index c1ee4e7bf996..91ee2bb575df 100644 --- a/drivers/crypto/hisilicon/sec/sec_drv.c +++ b/drivers/crypto/hisilicon/sec/sec_drv.c @@ -1082,9 +1082,8 @@ static int sec_queue_res_cfg(struct sec_queue *queue) struct sec_queue_ring_db *ring_db = &queue->ring_db; int ret; - ring_cmd->vaddr = dma_zalloc_coherent(dev, SEC_Q_CMD_SIZE, - &ring_cmd->paddr, - GFP_KERNEL); + ring_cmd->vaddr = dma_alloc_coherent(dev, SEC_Q_CMD_SIZE, + &ring_cmd->paddr, GFP_KERNEL); if (!ring_cmd->vaddr) return -ENOMEM; @@ -1092,17 +1091,15 @@ static int sec_queue_res_cfg(struct sec_queue *queue) mutex_init(&ring_cmd->lock); ring_cmd->callback = sec_alg_callback; - ring_cq->vaddr = dma_zalloc_coherent(dev, SEC_Q_CQ_SIZE, - &ring_cq->paddr, - GFP_KERNEL); + ring_cq->vaddr = dma_alloc_coherent(dev, SEC_Q_CQ_SIZE, + &ring_cq->paddr, GFP_KERNEL); if (!ring_cq->vaddr) { ret = -ENOMEM; goto err_free_ring_cmd; } - ring_db->vaddr = dma_zalloc_coherent(dev, SEC_Q_DB_SIZE, - &ring_db->paddr, - GFP_KERNEL); + ring_db->vaddr = dma_alloc_coherent(dev, SEC_Q_DB_SIZE, + &ring_db->paddr, GFP_KERNEL); if (!ring_db->vaddr) { ret = -ENOMEM; goto err_free_ring_cq; diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 19fba998b86b..1b0d156bb9be 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -260,9 +260,9 @@ static int setup_crypt_desc(void) { struct device *dev = &pdev->dev; BUILD_BUG_ON(sizeof(struct crypt_ctl) != 64); - crypt_virt = dma_zalloc_coherent(dev, - NPE_QLEN * sizeof(struct crypt_ctl), - &crypt_phys, GFP_ATOMIC); + crypt_virt = dma_alloc_coherent(dev, + NPE_QLEN * sizeof(struct crypt_ctl), + &crypt_phys, GFP_ATOMIC); if (!crypt_virt) return -ENOMEM; return 0; diff --git a/drivers/crypto/mediatek/mtk-platform.c b/drivers/crypto/mediatek/mtk-platform.c index ee0404e27a0f..5660e5e5e022 100644 --- a/drivers/crypto/mediatek/mtk-platform.c +++ b/drivers/crypto/mediatek/mtk-platform.c @@ -453,17 +453,17 @@ static int mtk_desc_ring_alloc(struct mtk_cryp *cryp) if (!ring[i]) goto err_cleanup; - ring[i]->cmd_base = dma_zalloc_coherent(cryp->dev, - MTK_DESC_RING_SZ, - &ring[i]->cmd_dma, - GFP_KERNEL); + ring[i]->cmd_base = dma_alloc_coherent(cryp->dev, + MTK_DESC_RING_SZ, + &ring[i]->cmd_dma, + GFP_KERNEL); if (!ring[i]->cmd_base) goto err_cleanup; - ring[i]->res_base = dma_zalloc_coherent(cryp->dev, - MTK_DESC_RING_SZ, - &ring[i]->res_dma, - GFP_KERNEL); + ring[i]->res_base = dma_alloc_coherent(cryp->dev, + MTK_DESC_RING_SZ, + &ring[i]->res_dma, + GFP_KERNEL); if (!ring[i]->res_base) goto err_cleanup; diff --git a/drivers/crypto/qat/qat_common/adf_admin.c b/drivers/crypto/qat/qat_common/adf_admin.c index 3744b22f0c46..d28cba34773e 100644 --- a/drivers/crypto/qat/qat_common/adf_admin.c +++ b/drivers/crypto/qat/qat_common/adf_admin.c @@ -244,18 +244,18 @@ int adf_init_admin_comms(struct adf_accel_dev *accel_dev) dev_to_node(&GET_DEV(accel_dev))); if (!admin) return -ENOMEM; - admin->virt_addr = dma_zalloc_coherent(&GET_DEV(accel_dev), PAGE_SIZE, - &admin->phy_addr, GFP_KERNEL); + admin->virt_addr = dma_alloc_coherent(&GET_DEV(accel_dev), PAGE_SIZE, + &admin->phy_addr, GFP_KERNEL); if (!admin->virt_addr) { dev_err(&GET_DEV(accel_dev), "Failed to allocate dma buff\n"); kfree(admin); return -ENOMEM; } - admin->virt_tbl_addr = dma_zalloc_coherent(&GET_DEV(accel_dev), - PAGE_SIZE, - &admin->const_tbl_addr, - GFP_KERNEL); + admin->virt_tbl_addr = dma_alloc_coherent(&GET_DEV(accel_dev), + PAGE_SIZE, + &admin->const_tbl_addr, + GFP_KERNEL); if (!admin->virt_tbl_addr) { dev_err(&GET_DEV(accel_dev), "Failed to allocate const_tbl\n"); dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE, diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c index d2698299896f..975c75198f56 100644 --- a/drivers/crypto/qat/qat_common/qat_algs.c +++ b/drivers/crypto/qat/qat_common/qat_algs.c @@ -601,15 +601,15 @@ static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key, dev = &GET_DEV(inst->accel_dev); ctx->inst = inst; - ctx->enc_cd = dma_zalloc_coherent(dev, sizeof(*ctx->enc_cd), - &ctx->enc_cd_paddr, - GFP_ATOMIC); + ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd), + &ctx->enc_cd_paddr, + GFP_ATOMIC); if (!ctx->enc_cd) { return -ENOMEM; } - ctx->dec_cd = dma_zalloc_coherent(dev, sizeof(*ctx->dec_cd), - &ctx->dec_cd_paddr, - GFP_ATOMIC); + ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd), + &ctx->dec_cd_paddr, + GFP_ATOMIC); if (!ctx->dec_cd) { goto out_free_enc; } @@ -933,16 +933,16 @@ static int qat_alg_ablkcipher_setkey(struct crypto_ablkcipher *tfm, dev = &GET_DEV(inst->accel_dev); ctx->inst = inst; - ctx->enc_cd = dma_zalloc_coherent(dev, sizeof(*ctx->enc_cd), - &ctx->enc_cd_paddr, - GFP_ATOMIC); + ctx->enc_cd = dma_alloc_coherent(dev, sizeof(*ctx->enc_cd), + &ctx->enc_cd_paddr, + GFP_ATOMIC); if (!ctx->enc_cd) { spin_unlock(&ctx->lock); return -ENOMEM; } - ctx->dec_cd = dma_zalloc_coherent(dev, sizeof(*ctx->dec_cd), - &ctx->dec_cd_paddr, - GFP_ATOMIC); + ctx->dec_cd = dma_alloc_coherent(dev, sizeof(*ctx->dec_cd), + &ctx->dec_cd_paddr, + GFP_ATOMIC); if (!ctx->dec_cd) { spin_unlock(&ctx->lock); goto out_free_enc; diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c index 320e7854b4ee..c9f324730d71 100644 --- a/drivers/crypto/qat/qat_common/qat_asym_algs.c +++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c @@ -332,10 +332,10 @@ static int qat_dh_compute_value(struct kpp_request *req) } else { int shift = ctx->p_size - req->src_len; - qat_req->src_align = dma_zalloc_coherent(dev, - ctx->p_size, - &qat_req->in.dh.in.b, - GFP_KERNEL); + qat_req->src_align = dma_alloc_coherent(dev, + ctx->p_size, + &qat_req->in.dh.in.b, + GFP_KERNEL); if (unlikely(!qat_req->src_align)) return ret; @@ -360,9 +360,9 @@ static int qat_dh_compute_value(struct kpp_request *req) goto unmap_src; } else { - qat_req->dst_align = dma_zalloc_coherent(dev, ctx->p_size, - &qat_req->out.dh.r, - GFP_KERNEL); + qat_req->dst_align = dma_alloc_coherent(dev, ctx->p_size, + &qat_req->out.dh.r, + GFP_KERNEL); if (unlikely(!qat_req->dst_align)) goto unmap_src; } @@ -447,7 +447,7 @@ static int qat_dh_set_params(struct qat_dh_ctx *ctx, struct dh *params) return -EINVAL; ctx->p_size = params->p_size; - ctx->p = dma_zalloc_coherent(dev, ctx->p_size, &ctx->dma_p, GFP_KERNEL); + ctx->p = dma_alloc_coherent(dev, ctx->p_size, &ctx->dma_p, GFP_KERNEL); if (!ctx->p) return -ENOMEM; memcpy(ctx->p, params->p, ctx->p_size); @@ -458,7 +458,7 @@ static int qat_dh_set_params(struct qat_dh_ctx *ctx, struct dh *params) return 0; } - ctx->g = dma_zalloc_coherent(dev, ctx->p_size, &ctx->dma_g, GFP_KERNEL); + ctx->g = dma_alloc_coherent(dev, ctx->p_size, &ctx->dma_g, GFP_KERNEL); if (!ctx->g) return -ENOMEM; memcpy(ctx->g + (ctx->p_size - params->g_size), params->g, @@ -503,8 +503,8 @@ static int qat_dh_set_secret(struct crypto_kpp *tfm, const void *buf, if (ret < 0) goto err_clear_ctx; - ctx->xa = dma_zalloc_coherent(dev, ctx->p_size, &ctx->dma_xa, - GFP_KERNEL); + ctx->xa = dma_alloc_coherent(dev, ctx->p_size, &ctx->dma_xa, + GFP_KERNEL); if (!ctx->xa) { ret = -ENOMEM; goto err_clear_ctx; @@ -737,9 +737,9 @@ static int qat_rsa_enc(struct akcipher_request *req) } else { int shift = ctx->key_sz - req->src_len; - qat_req->src_align = dma_zalloc_coherent(dev, ctx->key_sz, - &qat_req->in.rsa.enc.m, - GFP_KERNEL); + qat_req->src_align = dma_alloc_coherent(dev, ctx->key_sz, + &qat_req->in.rsa.enc.m, + GFP_KERNEL); if (unlikely(!qat_req->src_align)) return ret; @@ -756,9 +756,9 @@ static int qat_rsa_enc(struct akcipher_request *req) goto unmap_src; } else { - qat_req->dst_align = dma_zalloc_coherent(dev, ctx->key_sz, - &qat_req->out.rsa.enc.c, - GFP_KERNEL); + qat_req->dst_align = dma_alloc_coherent(dev, ctx->key_sz, + &qat_req->out.rsa.enc.c, + GFP_KERNEL); if (unlikely(!qat_req->dst_align)) goto unmap_src; @@ -881,9 +881,9 @@ static int qat_rsa_dec(struct akcipher_request *req) } else { int shift = ctx->key_sz - req->src_len; - qat_req->src_align = dma_zalloc_coherent(dev, ctx->key_sz, - &qat_req->in.rsa.dec.c, - GFP_KERNEL); + qat_req->src_align = dma_alloc_coherent(dev, ctx->key_sz, + &qat_req->in.rsa.dec.c, + GFP_KERNEL); if (unlikely(!qat_req->src_align)) return ret; @@ -900,9 +900,9 @@ static int qat_rsa_dec(struct akcipher_request *req) goto unmap_src; } else { - qat_req->dst_align = dma_zalloc_coherent(dev, ctx->key_sz, - &qat_req->out.rsa.dec.m, - GFP_KERNEL); + qat_req->dst_align = dma_alloc_coherent(dev, ctx->key_sz, + &qat_req->out.rsa.dec.m, + GFP_KERNEL); if (unlikely(!qat_req->dst_align)) goto unmap_src; @@ -989,7 +989,7 @@ static int qat_rsa_set_n(struct qat_rsa_ctx *ctx, const char *value, goto err; ret = -ENOMEM; - ctx->n = dma_zalloc_coherent(dev, ctx->key_sz, &ctx->dma_n, GFP_KERNEL); + ctx->n = dma_alloc_coherent(dev, ctx->key_sz, &ctx->dma_n, GFP_KERNEL); if (!ctx->n) goto err; @@ -1018,7 +1018,7 @@ static int qat_rsa_set_e(struct qat_rsa_ctx *ctx, const char *value, return -EINVAL; } - ctx->e = dma_zalloc_coherent(dev, ctx->key_sz, &ctx->dma_e, GFP_KERNEL); + ctx->e = dma_alloc_coherent(dev, ctx->key_sz, &ctx->dma_e, GFP_KERNEL); if (!ctx->e) return -ENOMEM; @@ -1044,7 +1044,7 @@ static int qat_rsa_set_d(struct qat_rsa_ctx *ctx, const char *value, goto err; ret = -ENOMEM; - ctx->d = dma_zalloc_coherent(dev, ctx->key_sz, &ctx->dma_d, GFP_KERNEL); + ctx->d = dma_alloc_coherent(dev, ctx->key_sz, &ctx->dma_d, GFP_KERNEL); if (!ctx->d) goto err; @@ -1077,7 +1077,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key) qat_rsa_drop_leading_zeros(&ptr, &len); if (!len) goto err; - ctx->p = dma_zalloc_coherent(dev, half_key_sz, &ctx->dma_p, GFP_KERNEL); + ctx->p = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_p, GFP_KERNEL); if (!ctx->p) goto err; memcpy(ctx->p + (half_key_sz - len), ptr, len); @@ -1088,7 +1088,7 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key) qat_rsa_drop_leading_zeros(&ptr, &len); if (!len) goto free_p; - ctx->q = dma_zalloc_coherent(dev, half_key_sz, &ctx->dma_q, GFP_KERNEL); + ctx->q = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_q, GFP_KERNEL); if (!ctx->q) goto free_p; memcpy(ctx->q + (half_key_sz - len), ptr, len); @@ -1099,8 +1099,8 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key) qat_rsa_drop_leading_zeros(&ptr, &len); if (!len) goto free_q; - ctx->dp = dma_zalloc_coherent(dev, half_key_sz, &ctx->dma_dp, - GFP_KERNEL); + ctx->dp = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_dp, + GFP_KERNEL); if (!ctx->dp) goto free_q; memcpy(ctx->dp + (half_key_sz - len), ptr, len); @@ -1111,8 +1111,8 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key) qat_rsa_drop_leading_zeros(&ptr, &len); if (!len) goto free_dp; - ctx->dq = dma_zalloc_coherent(dev, half_key_sz, &ctx->dma_dq, - GFP_KERNEL); + ctx->dq = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_dq, + GFP_KERNEL); if (!ctx->dq) goto free_dp; memcpy(ctx->dq + (half_key_sz - len), ptr, len); @@ -1123,8 +1123,8 @@ static void qat_rsa_setkey_crt(struct qat_rsa_ctx *ctx, struct rsa_key *rsa_key) qat_rsa_drop_leading_zeros(&ptr, &len); if (!len) goto free_dq; - ctx->qinv = dma_zalloc_coherent(dev, half_key_sz, &ctx->dma_qinv, - GFP_KERNEL); + ctx->qinv = dma_alloc_coherent(dev, half_key_sz, &ctx->dma_qinv, + GFP_KERNEL); if (!ctx->qinv) goto free_dq; memcpy(ctx->qinv + (half_key_sz - len), ptr, len); diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index a2b0a0e71168..86708fb9bda1 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1182,8 +1182,8 @@ static int sdma_request_channel0(struct sdma_engine *sdma) { int ret = -EBUSY; - sdma->bd0 = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdma->bd0_phys, - GFP_NOWAIT); + sdma->bd0 = dma_alloc_coherent(NULL, PAGE_SIZE, &sdma->bd0_phys, + GFP_NOWAIT); if (!sdma->bd0) { ret = -ENOMEM; goto out; @@ -1205,8 +1205,8 @@ static int sdma_alloc_bd(struct sdma_desc *desc) u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor); int ret = 0; - desc->bd = dma_zalloc_coherent(NULL, bd_size, &desc->bd_phys, - GFP_NOWAIT); + desc->bd = dma_alloc_coherent(NULL, bd_size, &desc->bd_phys, + GFP_NOWAIT); if (!desc->bd) { ret = -ENOMEM; goto out; diff --git a/drivers/dma/mediatek/mtk-hsdma.c b/drivers/dma/mediatek/mtk-hsdma.c index b7ec56ae02a6..1a2028e1c29e 100644 --- a/drivers/dma/mediatek/mtk-hsdma.c +++ b/drivers/dma/mediatek/mtk-hsdma.c @@ -325,8 +325,8 @@ static int mtk_hsdma_alloc_pchan(struct mtk_hsdma_device *hsdma, * and [MTK_DMA_SIZE ... 2 * MTK_DMA_SIZE - 1] is for RX ring. */ pc->sz_ring = 2 * MTK_DMA_SIZE * sizeof(*ring->txd); - ring->txd = dma_zalloc_coherent(hsdma2dev(hsdma), pc->sz_ring, - &ring->tphys, GFP_NOWAIT); + ring->txd = dma_alloc_coherent(hsdma2dev(hsdma), pc->sz_ring, + &ring->tphys, GFP_NOWAIT); if (!ring->txd) return -ENOMEM; diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index 35193b31a9e0..22cc7f68ef6e 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -416,9 +416,9 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan) struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; int ret; - mxs_chan->ccw = dma_zalloc_coherent(mxs_dma->dma_device.dev, - CCW_BLOCK_SIZE, - &mxs_chan->ccw_phys, GFP_KERNEL); + mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev, + CCW_BLOCK_SIZE, + &mxs_chan->ccw_phys, GFP_KERNEL); if (!mxs_chan->ccw) { ret = -ENOMEM; goto err_alloc; diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c index 1d5988849aa6..eafd6c4b90fe 100644 --- a/drivers/dma/xgene-dma.c +++ b/drivers/dma/xgene-dma.c @@ -1208,8 +1208,8 @@ static int xgene_dma_create_ring_one(struct xgene_dma_chan *chan, ring->size = ret; /* Allocate memory for DMA ring descriptor */ - ring->desc_vaddr = dma_zalloc_coherent(chan->dev, ring->size, - &ring->desc_paddr, GFP_KERNEL); + ring->desc_vaddr = dma_alloc_coherent(chan->dev, ring->size, + &ring->desc_paddr, GFP_KERNEL); if (!ring->desc_vaddr) { chan_err(chan, "Failed to allocate ring desc\n"); return -ENOMEM; diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 02880963092f..cb20b411493e 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -879,10 +879,9 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) */ if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { /* Allocate the buffer descriptors. */ - chan->seg_v = dma_zalloc_coherent(chan->dev, - sizeof(*chan->seg_v) * - XILINX_DMA_NUM_DESCS, - &chan->seg_p, GFP_KERNEL); + chan->seg_v = dma_alloc_coherent(chan->dev, + sizeof(*chan->seg_v) * XILINX_DMA_NUM_DESCS, + &chan->seg_p, GFP_KERNEL); if (!chan->seg_v) { dev_err(chan->dev, "unable to allocate channel %d descriptors\n", @@ -895,9 +894,10 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) * so allocating a desc segment during channel allocation for * programming tail descriptor. */ - chan->cyclic_seg_v = dma_zalloc_coherent(chan->dev, - sizeof(*chan->cyclic_seg_v), - &chan->cyclic_seg_p, GFP_KERNEL); + chan->cyclic_seg_v = dma_alloc_coherent(chan->dev, + sizeof(*chan->cyclic_seg_v), + &chan->cyclic_seg_p, + GFP_KERNEL); if (!chan->cyclic_seg_v) { dev_err(chan->dev, "unable to allocate desc segment for cyclic DMA\n"); diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 8db51750ce93..4478787a247f 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -490,9 +490,9 @@ static int zynqmp_dma_alloc_chan_resources(struct dma_chan *dchan) list_add_tail(&desc->node, &chan->free_list); } - chan->desc_pool_v = dma_zalloc_coherent(chan->dev, - (2 * chan->desc_size * ZYNQMP_DMA_NUM_DESCS), - &chan->desc_pool_p, GFP_KERNEL); + chan->desc_pool_v = dma_alloc_coherent(chan->dev, + (2 * chan->desc_size * ZYNQMP_DMA_NUM_DESCS), + &chan->desc_pool_p, GFP_KERNEL); if (!chan->desc_pool_v) return -ENOMEM; diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index a9d9df6c85ad..693748ad8b88 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -61,8 +61,9 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali return NULL; dmah->size = size; - dmah->vaddr = dma_zalloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, - GFP_KERNEL | __GFP_COMP); + dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, + &dmah->busaddr, + GFP_KERNEL | __GFP_COMP); if (dmah->vaddr == NULL) { kfree(dmah); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 326805461265..19551aa43850 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -766,8 +766,8 @@ struct bnxt_qplib_rcfw_sbuf *bnxt_qplib_rcfw_alloc_sbuf( return NULL; sbuf->size = size; - sbuf->sb = dma_zalloc_coherent(&rcfw->pdev->dev, sbuf->size, - &sbuf->dma_addr, GFP_ATOMIC); + sbuf->sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf->size, + &sbuf->dma_addr, GFP_ATOMIC); if (!sbuf->sb) goto bail; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 59eeac55626f..57d4951679cb 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -105,10 +105,10 @@ static int __alloc_pbl(struct pci_dev *pdev, struct bnxt_qplib_pbl *pbl, if (!sghead) { for (i = 0; i < pages; i++) { - pbl->pg_arr[i] = dma_zalloc_coherent(&pdev->dev, - pbl->pg_size, - &pbl->pg_map_arr[i], - GFP_KERNEL); + pbl->pg_arr[i] = dma_alloc_coherent(&pdev->dev, + pbl->pg_size, + &pbl->pg_map_arr[i], + GFP_KERNEL); if (!pbl->pg_arr[i]) goto fail; pbl->pg_count++; diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index df4f7a3f043d..8ac72ac7cbac 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -291,9 +291,9 @@ int cxio_create_qp(struct cxio_rdev *rdev_p, u32 kernel_domain, if (!wq->sq) goto err3; - wq->queue = dma_zalloc_coherent(&(rdev_p->rnic_info.pdev->dev), - depth * sizeof(union t3_wr), - &(wq->dma_addr), GFP_KERNEL); + wq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev), + depth * sizeof(union t3_wr), + &(wq->dma_addr), GFP_KERNEL); if (!wq->queue) goto err4; diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 981ff5cfb5d1..504cf525508f 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -2564,9 +2564,8 @@ static int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx, wq->rqt_abs_idx = (wq->rqt_hwaddr - rdev->lldi.vr->rq.start) >> T4_RQT_ENTRY_SHIFT; - wq->queue = dma_zalloc_coherent(&rdev->lldi.pdev->dev, - wq->memsize, &wq->dma_addr, - GFP_KERNEL); + wq->queue = dma_alloc_coherent(&rdev->lldi.pdev->dev, wq->memsize, + &wq->dma_addr, GFP_KERNEL); if (!wq->queue) goto err_free_rqtpool; diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index 09044905284f..7835eb52e7c5 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -899,10 +899,10 @@ int hfi1_init(struct hfi1_devdata *dd, int reinit) goto done; /* allocate dummy tail memory for all receive contexts */ - dd->rcvhdrtail_dummy_kvaddr = dma_zalloc_coherent( - &dd->pcidev->dev, sizeof(u64), - &dd->rcvhdrtail_dummy_dma, - GFP_KERNEL); + dd->rcvhdrtail_dummy_kvaddr = dma_alloc_coherent(&dd->pcidev->dev, + sizeof(u64), + &dd->rcvhdrtail_dummy_dma, + GFP_KERNEL); if (!dd->rcvhdrtail_dummy_kvaddr) { dd_dev_err(dd, "cannot allocate dummy tail memory\n"); @@ -1863,9 +1863,9 @@ int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) gfp_flags = GFP_KERNEL; else gfp_flags = GFP_USER; - rcd->rcvhdrq = dma_zalloc_coherent( - &dd->pcidev->dev, amt, &rcd->rcvhdrq_dma, - gfp_flags | __GFP_COMP); + rcd->rcvhdrq = dma_alloc_coherent(&dd->pcidev->dev, amt, + &rcd->rcvhdrq_dma, + gfp_flags | __GFP_COMP); if (!rcd->rcvhdrq) { dd_dev_err(dd, @@ -1876,9 +1876,10 @@ int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL) || HFI1_CAP_UGET_MASK(rcd->flags, DMA_RTAIL)) { - rcd->rcvhdrtail_kvaddr = dma_zalloc_coherent( - &dd->pcidev->dev, PAGE_SIZE, - &rcd->rcvhdrqtailaddr_dma, gfp_flags); + rcd->rcvhdrtail_kvaddr = dma_alloc_coherent(&dd->pcidev->dev, + PAGE_SIZE, + &rcd->rcvhdrqtailaddr_dma, + gfp_flags); if (!rcd->rcvhdrtail_kvaddr) goto bail_free; } @@ -1974,10 +1975,10 @@ int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd) while (alloced_bytes < rcd->egrbufs.size && rcd->egrbufs.alloced < rcd->egrbufs.count) { rcd->egrbufs.buffers[idx].addr = - dma_zalloc_coherent(&dd->pcidev->dev, - rcd->egrbufs.rcvtid_size, - &rcd->egrbufs.buffers[idx].dma, - gfp_flags); + dma_alloc_coherent(&dd->pcidev->dev, + rcd->egrbufs.rcvtid_size, + &rcd->egrbufs.buffers[idx].dma, + gfp_flags); if (rcd->egrbufs.buffers[idx].addr) { rcd->egrbufs.buffers[idx].len = rcd->egrbufs.rcvtid_size; diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index dd5a5c030066..04126d7e318d 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -2098,11 +2098,10 @@ int init_credit_return(struct hfi1_devdata *dd) int bytes = TXE_NUM_CONTEXTS * sizeof(struct credit_return); set_dev_node(&dd->pcidev->dev, i); - dd->cr_base[i].va = dma_zalloc_coherent( - &dd->pcidev->dev, - bytes, - &dd->cr_base[i].dma, - GFP_KERNEL); + dd->cr_base[i].va = dma_alloc_coherent(&dd->pcidev->dev, + bytes, + &dd->cr_base[i].dma, + GFP_KERNEL); if (!dd->cr_base[i].va) { set_dev_node(&dd->pcidev->dev, dd->node); dd_dev_err(dd, diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index b84356e1a4c1..96897a91fb0a 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -1453,12 +1453,9 @@ int sdma_init(struct hfi1_devdata *dd, u8 port) timer_setup(&sde->err_progress_check_timer, sdma_err_progress_check, 0); - sde->descq = dma_zalloc_coherent( - &dd->pcidev->dev, - descq_cnt * sizeof(u64[2]), - &sde->descq_phys, - GFP_KERNEL - ); + sde->descq = dma_alloc_coherent(&dd->pcidev->dev, + descq_cnt * sizeof(u64[2]), + &sde->descq_phys, GFP_KERNEL); if (!sde->descq) goto bail; sde->tx_ring = @@ -1471,24 +1468,18 @@ int sdma_init(struct hfi1_devdata *dd, u8 port) dd->sdma_heads_size = L1_CACHE_BYTES * num_engines; /* Allocate memory for DMA of head registers to memory */ - dd->sdma_heads_dma = dma_zalloc_coherent( - &dd->pcidev->dev, - dd->sdma_heads_size, - &dd->sdma_heads_phys, - GFP_KERNEL - ); + dd->sdma_heads_dma = dma_alloc_coherent(&dd->pcidev->dev, + dd->sdma_heads_size, + &dd->sdma_heads_phys, + GFP_KERNEL); if (!dd->sdma_heads_dma) { dd_dev_err(dd, "failed to allocate SendDMA head memory\n"); goto bail; } /* Allocate memory for pad */ - dd->sdma_pad_dma = dma_zalloc_coherent( - &dd->pcidev->dev, - sizeof(u32), - &dd->sdma_pad_phys, - GFP_KERNEL - ); + dd->sdma_pad_dma = dma_alloc_coherent(&dd->pcidev->dev, sizeof(u32), + &dd->sdma_pad_phys, GFP_KERNEL); if (!dd->sdma_pad_dma) { dd_dev_err(dd, "failed to allocate SendDMA pad memory\n"); goto bail; diff --git a/drivers/infiniband/hw/hns/hns_roce_alloc.c b/drivers/infiniband/hw/hns/hns_roce_alloc.c index 6300033a448f..dac058d3df53 100644 --- a/drivers/infiniband/hw/hns/hns_roce_alloc.c +++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c @@ -197,8 +197,8 @@ int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct, buf->npages = 1 << order; buf->page_shift = page_shift; /* MTT PA must be recorded in 4k alignment, t is 4k aligned */ - buf->direct.buf = dma_zalloc_coherent(dev, - size, &t, GFP_KERNEL); + buf->direct.buf = dma_alloc_coherent(dev, size, &t, + GFP_KERNEL); if (!buf->direct.buf) return -ENOMEM; @@ -219,9 +219,10 @@ int hns_roce_buf_alloc(struct hns_roce_dev *hr_dev, u32 size, u32 max_direct, return -ENOMEM; for (i = 0; i < buf->nbufs; ++i) { - buf->page_list[i].buf = dma_zalloc_coherent(dev, - page_size, &t, - GFP_KERNEL); + buf->page_list[i].buf = dma_alloc_coherent(dev, + page_size, + &t, + GFP_KERNEL); if (!buf->page_list[i].buf) goto err_free; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 3a669451cf86..543fa1504cd3 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -5091,7 +5091,7 @@ static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev, eqe_alloc = i * (buf_chk_sz / eq->eqe_size); size = (eq->entries - eqe_alloc) * eq->eqe_size; } - eq->buf[i] = dma_zalloc_coherent(dev, size, + eq->buf[i] = dma_alloc_coherent(dev, size, &(eq->buf_dma[i]), GFP_KERNEL); if (!eq->buf[i]) @@ -5126,9 +5126,9 @@ static int hns_roce_mhop_alloc_eq(struct hns_roce_dev *hr_dev, size = (eq->entries - eqe_alloc) * eq->eqe_size; } - eq->buf[idx] = dma_zalloc_coherent(dev, size, - &(eq->buf_dma[idx]), - GFP_KERNEL); + eq->buf[idx] = dma_alloc_coherent(dev, size, + &(eq->buf_dma[idx]), + GFP_KERNEL); if (!eq->buf[idx]) goto err_dma_alloc_buf; @@ -5241,7 +5241,7 @@ static int hns_roce_v2_create_eq(struct hns_roce_dev *hr_dev, goto free_cmd_mbox; } - eq->buf_list->buf = dma_zalloc_coherent(dev, buf_chk_sz, + eq->buf_list->buf = dma_alloc_coherent(dev, buf_chk_sz, &(eq->buf_list->map), GFP_KERNEL); if (!eq->buf_list->buf) { diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c index a9ea966877f2..59e978141ad4 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_utils.c +++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c @@ -745,8 +745,8 @@ enum i40iw_status_code i40iw_allocate_dma_mem(struct i40iw_hw *hw, if (!mem) return I40IW_ERR_PARAM; mem->size = ALIGN(size, alignment); - mem->va = dma_zalloc_coherent(&pcidev->dev, mem->size, - (dma_addr_t *)&mem->pa, GFP_KERNEL); + mem->va = dma_alloc_coherent(&pcidev->dev, mem->size, + (dma_addr_t *)&mem->pa, GFP_KERNEL); if (!mem->va) return I40IW_ERR_NO_MEMORY; return 0; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index cc9c0c8ccba3..112d2f38e0de 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -623,8 +623,9 @@ int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, page = dev->db_tab->page + end; alloc: - page->db_rec = dma_zalloc_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE, - &page->mapping, GFP_KERNEL); + page->db_rec = dma_alloc_coherent(&dev->pdev->dev, + MTHCA_ICM_PAGE_SIZE, &page->mapping, + GFP_KERNEL); if (!page->db_rec) { ret = -ENOMEM; goto out; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c index 241a57a07485..097e5ab2a19f 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c @@ -380,8 +380,8 @@ static int ocrdma_alloc_q(struct ocrdma_dev *dev, q->len = len; q->entry_size = entry_size; q->size = len * entry_size; - q->va = dma_zalloc_coherent(&dev->nic_info.pdev->dev, q->size, - &q->dma, GFP_KERNEL); + q->va = dma_alloc_coherent(&dev->nic_info.pdev->dev, q->size, &q->dma, + GFP_KERNEL); if (!q->va) return -ENOMEM; return 0; @@ -1819,7 +1819,7 @@ int ocrdma_mbx_create_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq, return -ENOMEM; ocrdma_init_mch(&cmd->cmd.req, OCRDMA_CMD_CREATE_CQ, OCRDMA_SUBSYS_COMMON, sizeof(*cmd)); - cq->va = dma_zalloc_coherent(&pdev->dev, cq->len, &cq->pa, GFP_KERNEL); + cq->va = dma_alloc_coherent(&pdev->dev, cq->len, &cq->pa, GFP_KERNEL); if (!cq->va) { status = -ENOMEM; goto mem_err; @@ -2209,7 +2209,7 @@ static int ocrdma_set_create_qp_sq_cmd(struct ocrdma_create_qp_req *cmd, qp->sq.max_cnt = max_wqe_allocated; len = (hw_pages * hw_page_size); - qp->sq.va = dma_zalloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL); + qp->sq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL); if (!qp->sq.va) return -EINVAL; qp->sq.len = len; @@ -2259,7 +2259,7 @@ static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd, qp->rq.max_cnt = max_rqe_allocated; len = (hw_pages * hw_page_size); - qp->rq.va = dma_zalloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL); + qp->rq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL); if (!qp->rq.va) return -ENOMEM; qp->rq.pa = pa; @@ -2315,8 +2315,8 @@ static int ocrdma_set_create_qp_ird_cmd(struct ocrdma_create_qp_req *cmd, if (dev->attr.ird == 0) return 0; - qp->ird_q_va = dma_zalloc_coherent(&pdev->dev, ird_q_len, &pa, - GFP_KERNEL); + qp->ird_q_va = dma_alloc_coherent(&pdev->dev, ird_q_len, &pa, + GFP_KERNEL); if (!qp->ird_q_va) return -ENOMEM; ocrdma_build_q_pages(&cmd->ird_addr[0], dev->attr.num_ird_pages, diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c index dd15474b19b7..6be0ea109138 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c @@ -73,8 +73,8 @@ bool ocrdma_alloc_stats_resources(struct ocrdma_dev *dev) mem->size = max_t(u32, sizeof(struct ocrdma_rdma_stats_req), sizeof(struct ocrdma_rdma_stats_resp)); - mem->va = dma_zalloc_coherent(&dev->nic_info.pdev->dev, mem->size, - &mem->pa, GFP_KERNEL); + mem->va = dma_alloc_coherent(&dev->nic_info.pdev->dev, mem->size, + &mem->pa, GFP_KERNEL); if (!mem->va) { pr_err("%s: stats mbox allocation failed\n", __func__); return false; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index c46bed0c5513..287c332ff0e6 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -504,8 +504,8 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev, INIT_LIST_HEAD(&ctx->mm_head); mutex_init(&ctx->mm_list_lock); - ctx->ah_tbl.va = dma_zalloc_coherent(&pdev->dev, map_len, - &ctx->ah_tbl.pa, GFP_KERNEL); + ctx->ah_tbl.va = dma_alloc_coherent(&pdev->dev, map_len, + &ctx->ah_tbl.pa, GFP_KERNEL); if (!ctx->ah_tbl.va) { kfree(ctx); return ERR_PTR(-ENOMEM); @@ -838,7 +838,7 @@ static int ocrdma_build_pbl_tbl(struct ocrdma_dev *dev, struct ocrdma_hw_mr *mr) return -ENOMEM; for (i = 0; i < mr->num_pbls; i++) { - va = dma_zalloc_coherent(&pdev->dev, dma_len, &pa, GFP_KERNEL); + va = dma_alloc_coherent(&pdev->dev, dma_len, &pa, GFP_KERNEL); if (!va) { ocrdma_free_mr_pbl_tbl(dev, mr); status = -ENOMEM; diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index b342a70e2814..e1ccf32b1c3d 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -556,8 +556,8 @@ static struct qedr_pbl *qedr_alloc_pbl_tbl(struct qedr_dev *dev, return ERR_PTR(-ENOMEM); for (i = 0; i < pbl_info->num_pbls; i++) { - va = dma_zalloc_coherent(&pdev->dev, pbl_info->pbl_size, - &pa, flags); + va = dma_alloc_coherent(&pdev->dev, pbl_info->pbl_size, &pa, + flags); if (!va) goto err; diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c index eaa109dbc96a..39c37b6fd715 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c @@ -890,8 +890,8 @@ static int pvrdma_pci_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "device version %d, driver version %d\n", dev->dsr_version, PVRDMA_VERSION); - dev->dsr = dma_zalloc_coherent(&pdev->dev, sizeof(*dev->dsr), - &dev->dsrbase, GFP_KERNEL); + dev->dsr = dma_alloc_coherent(&pdev->dev, sizeof(*dev->dsr), + &dev->dsrbase, GFP_KERNEL); if (!dev->dsr) { dev_err(&pdev->dev, "failed to allocate shared region\n"); ret = -ENOMEM; diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index f456c1125bd6..69881265d121 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -147,8 +147,8 @@ static int rpi_ts_probe(struct platform_device *pdev) return -ENOMEM; ts->pdev = pdev; - ts->fw_regs_va = dma_zalloc_coherent(dev, PAGE_SIZE, &ts->fw_regs_phys, - GFP_KERNEL); + ts->fw_regs_va = dma_alloc_coherent(dev, PAGE_SIZE, &ts->fw_regs_phys, + GFP_KERNEL); if (!ts->fw_regs_va) { dev_err(dev, "failed to dma_alloc_coherent\n"); return -ENOMEM; diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index 6ede4286b835..730f7dabcf37 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -232,9 +232,8 @@ static int mtk_iommu_domain_finalise(struct mtk_iommu_data *data) spin_lock_init(&dom->pgtlock); - dom->pgt_va = dma_zalloc_coherent(data->dev, - M2701_IOMMU_PGT_SIZE, - &dom->pgt_pa, GFP_KERNEL); + dom->pgt_va = dma_alloc_coherent(data->dev, M2701_IOMMU_PGT_SIZE, + &dom->pgt_pa, GFP_KERNEL); if (!dom->pgt_va) return -ENOMEM; diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 447baaebca44..cdb79ae2d8dc 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -218,8 +218,8 @@ static int cio2_fbpt_init(struct cio2_device *cio2, struct cio2_queue *q) { struct device *dev = &cio2->pci_dev->dev; - q->fbpt = dma_zalloc_coherent(dev, CIO2_FBPT_SIZE, &q->fbpt_bus_addr, - GFP_KERNEL); + q->fbpt = dma_alloc_coherent(dev, CIO2_FBPT_SIZE, &q->fbpt_bus_addr, + GFP_KERNEL); if (!q->fbpt) return -ENOMEM; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c index e80123cba406..060c0ad6243a 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c @@ -49,7 +49,7 @@ int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data, struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data; struct device *dev = &ctx->dev->plat_dev->dev; - mem->va = dma_zalloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL); + mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL); if (!mem->va) { mtk_v4l2_err("%s dma_alloc size=%ld failed!", dev_name(dev), size); diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index efe2fb72d54b..25265fd0fd6e 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -218,8 +218,8 @@ void *__genwqe_alloc_consistent(struct genwqe_dev *cd, size_t size, if (get_order(size) >= MAX_ORDER) return NULL; - return dma_zalloc_coherent(&cd->pci_dev->dev, size, dma_handle, - GFP_KERNEL); + return dma_alloc_coherent(&cd->pci_dev->dev, size, dma_handle, + GFP_KERNEL); } void __genwqe_free_consistent(struct genwqe_dev *cd, size_t size, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a22e11a65658..eba9bcc92ad3 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3763,8 +3763,9 @@ int sdhci_setup_host(struct sdhci_host *host) * Use zalloc to zero the reserved high 32-bits of 128-bit * descriptors so that they never need to be written. */ - buf = dma_zalloc_coherent(mmc_dev(mmc), host->align_buffer_sz + - host->adma_table_sz, &dma, GFP_KERNEL); + buf = dma_alloc_coherent(mmc_dev(mmc), + host->align_buffer_sz + host->adma_table_sz, + &dma, GFP_KERNEL); if (!buf) { pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", mmc_hostname(mmc)); diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c index 91fc64c1145e..47e5984f16fb 100644 --- a/drivers/net/ethernet/aeroflex/greth.c +++ b/drivers/net/ethernet/aeroflex/greth.c @@ -1433,18 +1433,18 @@ static int greth_of_probe(struct platform_device *ofdev) } /* Allocate TX descriptor ring in coherent memory */ - greth->tx_bd_base = dma_zalloc_coherent(greth->dev, 1024, - &greth->tx_bd_base_phys, - GFP_KERNEL); + greth->tx_bd_base = dma_alloc_coherent(greth->dev, 1024, + &greth->tx_bd_base_phys, + GFP_KERNEL); if (!greth->tx_bd_base) { err = -ENOMEM; goto error3; } /* Allocate RX descriptor ring in coherent memory */ - greth->rx_bd_base = dma_zalloc_coherent(greth->dev, 1024, - &greth->rx_bd_base_phys, - GFP_KERNEL); + greth->rx_bd_base = dma_alloc_coherent(greth->dev, 1024, + &greth->rx_bd_base_phys, + GFP_KERNEL); if (!greth->rx_bd_base) { err = -ENOMEM; goto error4; diff --git a/drivers/net/ethernet/alacritech/slicoss.c b/drivers/net/ethernet/alacritech/slicoss.c index 0b60921c392f..16477aa6d61f 100644 --- a/drivers/net/ethernet/alacritech/slicoss.c +++ b/drivers/net/ethernet/alacritech/slicoss.c @@ -795,8 +795,8 @@ static int slic_init_stat_queue(struct slic_device *sdev) size = stq->len * sizeof(*descs) + DESC_ALIGN_MASK; for (i = 0; i < SLIC_NUM_STAT_DESC_ARRAYS; i++) { - descs = dma_zalloc_coherent(&sdev->pdev->dev, size, &paddr, - GFP_KERNEL); + descs = dma_alloc_coherent(&sdev->pdev->dev, size, &paddr, + GFP_KERNEL); if (!descs) { netdev_err(sdev->netdev, "failed to allocate status descriptors\n"); @@ -1240,8 +1240,8 @@ static int slic_init_shmem(struct slic_device *sdev) struct slic_shmem_data *sm_data; dma_addr_t paddr; - sm_data = dma_zalloc_coherent(&sdev->pdev->dev, sizeof(*sm_data), - &paddr, GFP_KERNEL); + sm_data = dma_alloc_coherent(&sdev->pdev->dev, sizeof(*sm_data), + &paddr, GFP_KERNEL); if (!sm_data) { dev_err(&sdev->pdev->dev, "failed to allocate shared memory\n"); return -ENOMEM; @@ -1621,8 +1621,8 @@ static int slic_read_eeprom(struct slic_device *sdev) int err = 0; u8 *mac[2]; - eeprom = dma_zalloc_coherent(&sdev->pdev->dev, SLIC_EEPROM_SIZE, - &paddr, GFP_KERNEL); + eeprom = dma_alloc_coherent(&sdev->pdev->dev, SLIC_EEPROM_SIZE, + &paddr, GFP_KERNEL); if (!eeprom) return -ENOMEM; diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 420cede41ca4..b17d435de09f 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -111,8 +111,8 @@ static int ena_com_admin_init_sq(struct ena_com_admin_queue *queue) struct ena_com_admin_sq *sq = &queue->sq; u16 size = ADMIN_SQ_SIZE(queue->q_depth); - sq->entries = dma_zalloc_coherent(queue->q_dmadev, size, &sq->dma_addr, - GFP_KERNEL); + sq->entries = dma_alloc_coherent(queue->q_dmadev, size, &sq->dma_addr, + GFP_KERNEL); if (!sq->entries) { pr_err("memory allocation failed"); @@ -133,8 +133,8 @@ static int ena_com_admin_init_cq(struct ena_com_admin_queue *queue) struct ena_com_admin_cq *cq = &queue->cq; u16 size = ADMIN_CQ_SIZE(queue->q_depth); - cq->entries = dma_zalloc_coherent(queue->q_dmadev, size, &cq->dma_addr, - GFP_KERNEL); + cq->entries = dma_alloc_coherent(queue->q_dmadev, size, &cq->dma_addr, + GFP_KERNEL); if (!cq->entries) { pr_err("memory allocation failed"); @@ -156,8 +156,8 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *dev, dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH; size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH); - aenq->entries = dma_zalloc_coherent(dev->dmadev, size, &aenq->dma_addr, - GFP_KERNEL); + aenq->entries = dma_alloc_coherent(dev->dmadev, size, &aenq->dma_addr, + GFP_KERNEL); if (!aenq->entries) { pr_err("memory allocation failed"); @@ -344,15 +344,15 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, dev_node = dev_to_node(ena_dev->dmadev); set_dev_node(ena_dev->dmadev, ctx->numa_node); io_sq->desc_addr.virt_addr = - dma_zalloc_coherent(ena_dev->dmadev, size, - &io_sq->desc_addr.phys_addr, - GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, size, + &io_sq->desc_addr.phys_addr, + GFP_KERNEL); set_dev_node(ena_dev->dmadev, dev_node); if (!io_sq->desc_addr.virt_addr) { io_sq->desc_addr.virt_addr = - dma_zalloc_coherent(ena_dev->dmadev, size, - &io_sq->desc_addr.phys_addr, - GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, size, + &io_sq->desc_addr.phys_addr, + GFP_KERNEL); } if (!io_sq->desc_addr.virt_addr) { @@ -425,14 +425,14 @@ static int ena_com_init_io_cq(struct ena_com_dev *ena_dev, prev_node = dev_to_node(ena_dev->dmadev); set_dev_node(ena_dev->dmadev, ctx->numa_node); io_cq->cdesc_addr.virt_addr = - dma_zalloc_coherent(ena_dev->dmadev, size, - &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, size, + &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); set_dev_node(ena_dev->dmadev, prev_node); if (!io_cq->cdesc_addr.virt_addr) { io_cq->cdesc_addr.virt_addr = - dma_zalloc_coherent(ena_dev->dmadev, size, - &io_cq->cdesc_addr.phys_addr, - GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, size, + &io_cq->cdesc_addr.phys_addr, + GFP_KERNEL); } if (!io_cq->cdesc_addr.virt_addr) { @@ -1026,8 +1026,8 @@ static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev) struct ena_rss *rss = &ena_dev->rss; rss->hash_key = - dma_zalloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), - &rss->hash_key_dma_addr, GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), + &rss->hash_key_dma_addr, GFP_KERNEL); if (unlikely(!rss->hash_key)) return -ENOMEM; @@ -1050,8 +1050,8 @@ static int ena_com_hash_ctrl_init(struct ena_com_dev *ena_dev) struct ena_rss *rss = &ena_dev->rss; rss->hash_ctrl = - dma_zalloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), - &rss->hash_ctrl_dma_addr, GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), + &rss->hash_ctrl_dma_addr, GFP_KERNEL); if (unlikely(!rss->hash_ctrl)) return -ENOMEM; @@ -1094,8 +1094,8 @@ static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev, sizeof(struct ena_admin_rss_ind_table_entry); rss->rss_ind_tbl = - dma_zalloc_coherent(ena_dev->dmadev, tbl_size, - &rss->rss_ind_tbl_dma_addr, GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, tbl_size, + &rss->rss_ind_tbl_dma_addr, GFP_KERNEL); if (unlikely(!rss->rss_ind_tbl)) goto mem_err1; @@ -1649,9 +1649,9 @@ int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) spin_lock_init(&mmio_read->lock); mmio_read->read_resp = - dma_zalloc_coherent(ena_dev->dmadev, - sizeof(*mmio_read->read_resp), - &mmio_read->read_resp_dma_addr, GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, + sizeof(*mmio_read->read_resp), + &mmio_read->read_resp_dma_addr, GFP_KERNEL); if (unlikely(!mmio_read->read_resp)) goto err; @@ -2623,8 +2623,8 @@ int ena_com_allocate_host_info(struct ena_com_dev *ena_dev) struct ena_host_attribute *host_attr = &ena_dev->host_attr; host_attr->host_info = - dma_zalloc_coherent(ena_dev->dmadev, SZ_4K, - &host_attr->host_info_dma_addr, GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, SZ_4K, + &host_attr->host_info_dma_addr, GFP_KERNEL); if (unlikely(!host_attr->host_info)) return -ENOMEM; @@ -2641,8 +2641,9 @@ int ena_com_allocate_debug_area(struct ena_com_dev *ena_dev, struct ena_host_attribute *host_attr = &ena_dev->host_attr; host_attr->debug_area_virt_addr = - dma_zalloc_coherent(ena_dev->dmadev, debug_area_size, - &host_attr->debug_area_dma_addr, GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, debug_area_size, + &host_attr->debug_area_dma_addr, + GFP_KERNEL); if (unlikely(!host_attr->debug_area_virt_addr)) { host_attr->debug_area_size = 0; return -ENOMEM; diff --git a/drivers/net/ethernet/apm/xgene-v2/main.c b/drivers/net/ethernet/apm/xgene-v2/main.c index 0f2ad50f3bd7..87b142a312e0 100644 --- a/drivers/net/ethernet/apm/xgene-v2/main.c +++ b/drivers/net/ethernet/apm/xgene-v2/main.c @@ -206,8 +206,8 @@ static netdev_tx_t xge_start_xmit(struct sk_buff *skb, struct net_device *ndev) } /* Packet buffers should be 64B aligned */ - pkt_buf = dma_zalloc_coherent(dev, XGENE_ENET_STD_MTU, &dma_addr, - GFP_ATOMIC); + pkt_buf = dma_alloc_coherent(dev, XGENE_ENET_STD_MTU, &dma_addr, + GFP_ATOMIC); if (unlikely(!pkt_buf)) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; @@ -428,8 +428,8 @@ static struct xge_desc_ring *xge_create_desc_ring(struct net_device *ndev) ring->ndev = ndev; size = XGENE_ENET_DESC_SIZE * XGENE_ENET_NUM_DESC; - ring->desc_addr = dma_zalloc_coherent(dev, size, &ring->dma_addr, - GFP_KERNEL); + ring->desc_addr = dma_alloc_coherent(dev, size, &ring->dma_addr, + GFP_KERNEL); if (!ring->desc_addr) goto err; diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index c131cfc1b79d..e3538ba7d0e7 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -660,10 +660,9 @@ static int alx_alloc_rings(struct alx_priv *alx) alx->num_txq + sizeof(struct alx_rrd) * alx->rx_ringsz + sizeof(struct alx_rfd) * alx->rx_ringsz; - alx->descmem.virt = dma_zalloc_coherent(&alx->hw.pdev->dev, - alx->descmem.size, - &alx->descmem.dma, - GFP_KERNEL); + alx->descmem.virt = dma_alloc_coherent(&alx->hw.pdev->dev, + alx->descmem.size, + &alx->descmem.dma, GFP_KERNEL); if (!alx->descmem.virt) return -ENOMEM; diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 7087b88550db..3a3b35b5df67 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1019,8 +1019,8 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter) sizeof(struct atl1c_recv_ret_status) * rx_desc_count + 8 * 4; - ring_header->desc = dma_zalloc_coherent(&pdev->dev, ring_header->size, - &ring_header->dma, GFP_KERNEL); + ring_header->desc = dma_alloc_coherent(&pdev->dev, ring_header->size, + &ring_header->dma, GFP_KERNEL); if (unlikely(!ring_header->desc)) { dev_err(&pdev->dev, "could not get memory for DMA buffer\n"); goto err_nomem; diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 6bae973d4dce..09cd188826b1 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -936,7 +936,7 @@ static int bcm_enet_open(struct net_device *dev) /* allocate rx dma ring */ size = priv->rx_ring_size * sizeof(struct bcm_enet_desc); - p = dma_zalloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL); + p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL); if (!p) { ret = -ENOMEM; goto out_freeirq_tx; @@ -947,7 +947,7 @@ static int bcm_enet_open(struct net_device *dev) /* allocate tx dma ring */ size = priv->tx_ring_size * sizeof(struct bcm_enet_desc); - p = dma_zalloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL); + p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL); if (!p) { ret = -ENOMEM; goto out_free_rx_ring; @@ -2120,7 +2120,7 @@ static int bcm_enetsw_open(struct net_device *dev) /* allocate rx dma ring */ size = priv->rx_ring_size * sizeof(struct bcm_enet_desc); - p = dma_zalloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL); + p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL); if (!p) { dev_err(kdev, "cannot allocate rx ring %u\n", size); ret = -ENOMEM; @@ -2132,7 +2132,7 @@ static int bcm_enetsw_open(struct net_device *dev) /* allocate tx dma ring */ size = priv->tx_ring_size * sizeof(struct bcm_enet_desc); - p = dma_zalloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL); + p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL); if (!p) { dev_err(kdev, "cannot allocate tx ring\n"); ret = -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 4574275ef445..f9521d0274b7 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -1506,8 +1506,8 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv, /* We just need one DMA descriptor which is DMA-able, since writing to * the port will allocate a new descriptor in its internal linked-list */ - p = dma_zalloc_coherent(kdev, sizeof(struct dma_desc), &ring->desc_dma, - GFP_KERNEL); + p = dma_alloc_coherent(kdev, sizeof(struct dma_desc), &ring->desc_dma, + GFP_KERNEL); if (!p) { netif_err(priv, hw, priv->netdev, "DMA alloc failed\n"); return -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index cabc8e49ad24..2d3a44c40221 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -634,9 +634,9 @@ static int bgmac_dma_alloc(struct bgmac *bgmac) /* Alloc ring of descriptors */ size = BGMAC_TX_RING_SLOTS * sizeof(struct bgmac_dma_desc); - ring->cpu_base = dma_zalloc_coherent(dma_dev, size, - &ring->dma_base, - GFP_KERNEL); + ring->cpu_base = dma_alloc_coherent(dma_dev, size, + &ring->dma_base, + GFP_KERNEL); if (!ring->cpu_base) { dev_err(bgmac->dev, "Allocation of TX ring 0x%X failed\n", ring->mmio_base); @@ -659,9 +659,9 @@ static int bgmac_dma_alloc(struct bgmac *bgmac) /* Alloc ring of descriptors */ size = BGMAC_RX_RING_SLOTS * sizeof(struct bgmac_dma_desc); - ring->cpu_base = dma_zalloc_coherent(dma_dev, size, - &ring->dma_base, - GFP_KERNEL); + ring->cpu_base = dma_alloc_coherent(dma_dev, size, + &ring->dma_base, + GFP_KERNEL); if (!ring->cpu_base) { dev_err(bgmac->dev, "Allocation of RX ring 0x%X failed\n", ring->mmio_base); diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index bbb247116045..d63371d70bce 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -844,8 +844,8 @@ bnx2_alloc_stats_blk(struct net_device *dev) BNX2_SBLK_MSIX_ALIGN_SIZE); bp->status_stats_size = status_blk_size + sizeof(struct statistics_block); - status_blk = dma_zalloc_coherent(&bp->pdev->dev, bp->status_stats_size, - &bp->status_blk_mapping, GFP_KERNEL); + status_blk = dma_alloc_coherent(&bp->pdev->dev, bp->status_stats_size, + &bp->status_blk_mapping, GFP_KERNEL); if (!status_blk) return -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 3aa80da973d7..4ab6eb3baefc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3449,10 +3449,10 @@ alloc_ext_stats: goto alloc_tx_ext_stats; bp->hw_rx_port_stats_ext = - dma_zalloc_coherent(&pdev->dev, - sizeof(struct rx_port_stats_ext), - &bp->hw_rx_port_stats_ext_map, - GFP_KERNEL); + dma_alloc_coherent(&pdev->dev, + sizeof(struct rx_port_stats_ext), + &bp->hw_rx_port_stats_ext_map, + GFP_KERNEL); if (!bp->hw_rx_port_stats_ext) return 0; @@ -3462,10 +3462,10 @@ alloc_tx_ext_stats: if (bp->hwrm_spec_code >= 0x10902) { bp->hw_tx_port_stats_ext = - dma_zalloc_coherent(&pdev->dev, - sizeof(struct tx_port_stats_ext), - &bp->hw_tx_port_stats_ext_map, - GFP_KERNEL); + dma_alloc_coherent(&pdev->dev, + sizeof(struct tx_port_stats_ext), + &bp->hw_tx_port_stats_ext_map, + GFP_KERNEL); } bp->flags |= BNXT_FLAG_PORT_STATS_EXT; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c index 15c7041e937b..70775158c8c4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c @@ -316,8 +316,8 @@ static int bnxt_hwrm_set_dcbx_app(struct bnxt *bp, struct dcb_app *app, n = IEEE_8021QAZ_MAX_TCS; data_len = sizeof(*data) + sizeof(*fw_app) * n; - data = dma_zalloc_coherent(&bp->pdev->dev, data_len, &mapping, - GFP_KERNEL); + data = dma_alloc_coherent(&bp->pdev->dev, data_len, &mapping, + GFP_KERNEL); if (!data) return -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 140dbd62106d..7f56032e44ac 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -85,8 +85,8 @@ static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, return -EFAULT; } - data_addr = dma_zalloc_coherent(&bp->pdev->dev, bytesize, - &data_dma_addr, GFP_KERNEL); + data_addr = dma_alloc_coherent(&bp->pdev->dev, bytesize, + &data_dma_addr, GFP_KERNEL); if (!data_addr) return -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 3b1397af81f7..b1627dd5f2fd 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8712,10 +8712,10 @@ static int tg3_mem_rx_acquire(struct tg3 *tp) if (!i && tg3_flag(tp, ENABLE_RSS)) continue; - tnapi->rx_rcb = dma_zalloc_coherent(&tp->pdev->dev, - TG3_RX_RCB_RING_BYTES(tp), - &tnapi->rx_rcb_mapping, - GFP_KERNEL); + tnapi->rx_rcb = dma_alloc_coherent(&tp->pdev->dev, + TG3_RX_RCB_RING_BYTES(tp), + &tnapi->rx_rcb_mapping, + GFP_KERNEL); if (!tnapi->rx_rcb) goto err_out; } @@ -8768,9 +8768,9 @@ static int tg3_alloc_consistent(struct tg3 *tp) { int i; - tp->hw_stats = dma_zalloc_coherent(&tp->pdev->dev, - sizeof(struct tg3_hw_stats), - &tp->stats_mapping, GFP_KERNEL); + tp->hw_stats = dma_alloc_coherent(&tp->pdev->dev, + sizeof(struct tg3_hw_stats), + &tp->stats_mapping, GFP_KERNEL); if (!tp->hw_stats) goto err_out; @@ -8778,10 +8778,10 @@ static int tg3_alloc_consistent(struct tg3 *tp) struct tg3_napi *tnapi = &tp->napi[i]; struct tg3_hw_status *sblk; - tnapi->hw_status = dma_zalloc_coherent(&tp->pdev->dev, - TG3_HW_STATUS_SIZE, - &tnapi->status_mapping, - GFP_KERNEL); + tnapi->hw_status = dma_alloc_coherent(&tp->pdev->dev, + TG3_HW_STATUS_SIZE, + &tnapi->status_mapping, + GFP_KERNEL); if (!tnapi->hw_status) goto err_out; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index fcaf18fa3904..5b4d3badcb73 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -59,7 +59,7 @@ static int nicvf_alloc_q_desc_mem(struct nicvf *nic, struct q_desc_mem *dmem, dmem->q_len = q_len; dmem->size = (desc_size * q_len) + align_bytes; /* Save address, need it while freeing */ - dmem->unalign_base = dma_zalloc_coherent(&nic->pdev->dev, dmem->size, + dmem->unalign_base = dma_alloc_coherent(&nic->pdev->dev, dmem->size, &dmem->dma, GFP_KERNEL); if (!dmem->unalign_base) return -ENOMEM; diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index 20b6e1b3f5e3..85f22c286680 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -620,7 +620,7 @@ static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, { size_t len = nelem * elem_size; void *s = NULL; - void *p = dma_zalloc_coherent(&pdev->dev, len, phys, GFP_KERNEL); + void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL); if (!p) return NULL; diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index b90188401d4a..fc0bc6458e84 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -694,7 +694,7 @@ static void *alloc_ring(struct device *dev, size_t nelem, size_t elem_size, { size_t len = nelem * elem_size + stat_size; void *s = NULL; - void *p = dma_zalloc_coherent(dev, len, phys, GFP_KERNEL); + void *p = dma_alloc_coherent(dev, len, phys, GFP_KERNEL); if (!p) return NULL; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index 3007e1ac1e61..1d534f0baa69 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -756,7 +756,7 @@ static void *alloc_ring(struct device *dev, size_t nelem, size_t hwsize, * Allocate the hardware ring and PCI DMA bus address space for said. */ size_t hwlen = nelem * hwsize + stat_size; - void *hwring = dma_zalloc_coherent(dev, hwlen, busaddrp, GFP_KERNEL); + void *hwring = dma_alloc_coherent(dev, hwlen, busaddrp, GFP_KERNEL); if (!hwring) return NULL; diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 1e9d882c04ef..59a7f0b99069 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1808,9 +1808,9 @@ int be_cmd_get_fat_dump(struct be_adapter *adapter, u32 buf_len, void *buf) total_size = buf_len; get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024; - get_fat_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, - get_fat_cmd.size, - &get_fat_cmd.dma, GFP_ATOMIC); + get_fat_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, + get_fat_cmd.size, + &get_fat_cmd.dma, GFP_ATOMIC); if (!get_fat_cmd.va) return -ENOMEM; @@ -2302,8 +2302,8 @@ int be_cmd_read_port_transceiver_data(struct be_adapter *adapter, return -EINVAL; cmd.size = sizeof(struct be_cmd_resp_port_type); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_ATOMIC); + cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, + GFP_ATOMIC); if (!cmd.va) { dev_err(&adapter->pdev->dev, "Memory allocation failed\n"); return -ENOMEM; @@ -3066,8 +3066,8 @@ int lancer_fw_download(struct be_adapter *adapter, flash_cmd.size = sizeof(struct lancer_cmd_req_write_object) + LANCER_FW_DOWNLOAD_CHUNK; - flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, - &flash_cmd.dma, GFP_KERNEL); + flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, + GFP_KERNEL); if (!flash_cmd.va) return -ENOMEM; @@ -3184,8 +3184,8 @@ int be_fw_download(struct be_adapter *adapter, const struct firmware *fw) } flash_cmd.size = sizeof(struct be_cmd_write_flashrom); - flash_cmd.va = dma_zalloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, - GFP_KERNEL); + flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size, &flash_cmd.dma, + GFP_KERNEL); if (!flash_cmd.va) return -ENOMEM; @@ -3435,8 +3435,8 @@ int be_cmd_get_phy_info(struct be_adapter *adapter) goto err; } cmd.size = sizeof(struct be_cmd_req_get_phy_info); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_ATOMIC); + cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, + GFP_ATOMIC); if (!cmd.va) { dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); status = -ENOMEM; @@ -3522,9 +3522,9 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) memset(&attribs_cmd, 0, sizeof(struct be_dma_mem)); attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs); - attribs_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, - attribs_cmd.size, - &attribs_cmd.dma, GFP_ATOMIC); + attribs_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, + attribs_cmd.size, + &attribs_cmd.dma, GFP_ATOMIC); if (!attribs_cmd.va) { dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); status = -ENOMEM; @@ -3699,10 +3699,10 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, memset(&get_mac_list_cmd, 0, sizeof(struct be_dma_mem)); get_mac_list_cmd.size = sizeof(struct be_cmd_resp_get_mac_list); - get_mac_list_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, - get_mac_list_cmd.size, - &get_mac_list_cmd.dma, - GFP_ATOMIC); + get_mac_list_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, + get_mac_list_cmd.size, + &get_mac_list_cmd.dma, + GFP_ATOMIC); if (!get_mac_list_cmd.va) { dev_err(&adapter->pdev->dev, @@ -3829,8 +3829,8 @@ int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, memset(&cmd, 0, sizeof(struct be_dma_mem)); cmd.size = sizeof(struct be_cmd_req_set_mac_list); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_KERNEL); + cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, + GFP_KERNEL); if (!cmd.va) return -ENOMEM; @@ -4035,8 +4035,8 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) memset(&cmd, 0, sizeof(struct be_dma_mem)); cmd.size = sizeof(struct be_cmd_resp_acpi_wol_magic_config_v1); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_ATOMIC); + cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, + GFP_ATOMIC); if (!cmd.va) { dev_err(&adapter->pdev->dev, "Memory allocation failure\n"); status = -ENOMEM; @@ -4089,9 +4089,9 @@ int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level) memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); - extfat_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, - extfat_cmd.size, &extfat_cmd.dma, - GFP_ATOMIC); + extfat_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, + extfat_cmd.size, &extfat_cmd.dma, + GFP_ATOMIC); if (!extfat_cmd.va) return -ENOMEM; @@ -4127,9 +4127,9 @@ int be_cmd_get_fw_log_level(struct be_adapter *adapter) memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); - extfat_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, - extfat_cmd.size, &extfat_cmd.dma, - GFP_ATOMIC); + extfat_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, + extfat_cmd.size, &extfat_cmd.dma, + GFP_ATOMIC); if (!extfat_cmd.va) { dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", @@ -4354,8 +4354,8 @@ int be_cmd_get_func_config(struct be_adapter *adapter, struct be_resources *res) memset(&cmd, 0, sizeof(struct be_dma_mem)); cmd.size = sizeof(struct be_cmd_resp_get_func_config); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_ATOMIC); + cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, + GFP_ATOMIC); if (!cmd.va) { dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); status = -ENOMEM; @@ -4452,8 +4452,8 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, memset(&cmd, 0, sizeof(struct be_dma_mem)); cmd.size = sizeof(struct be_cmd_resp_get_profile_config); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_ATOMIC); + cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, + GFP_ATOMIC); if (!cmd.va) return -ENOMEM; @@ -4539,8 +4539,8 @@ static int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc, memset(&cmd, 0, sizeof(struct be_dma_mem)); cmd.size = sizeof(struct be_cmd_req_set_profile_config); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_ATOMIC); + cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, + GFP_ATOMIC); if (!cmd.va) return -ENOMEM; diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 3f6749fc889f..4c218341c51b 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -274,8 +274,8 @@ static int lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name, int status = 0; read_cmd.size = LANCER_READ_FILE_CHUNK; - read_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, read_cmd.size, - &read_cmd.dma, GFP_ATOMIC); + read_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, read_cmd.size, + &read_cmd.dma, GFP_ATOMIC); if (!read_cmd.va) { dev_err(&adapter->pdev->dev, @@ -815,7 +815,7 @@ static int be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) } cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config); - cmd.va = dma_zalloc_coherent(dev, cmd.size, &cmd.dma, GFP_KERNEL); + cmd.va = dma_alloc_coherent(dev, cmd.size, &cmd.dma, GFP_KERNEL); if (!cmd.va) return -ENOMEM; @@ -851,9 +851,9 @@ static int be_test_ddr_dma(struct be_adapter *adapter) }; ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test); - ddrdma_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, - ddrdma_cmd.size, &ddrdma_cmd.dma, - GFP_KERNEL); + ddrdma_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, + ddrdma_cmd.size, &ddrdma_cmd.dma, + GFP_KERNEL); if (!ddrdma_cmd.va) return -ENOMEM; @@ -1014,9 +1014,9 @@ static int be_read_eeprom(struct net_device *netdev, memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem)); eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read); - eeprom_cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, - eeprom_cmd.size, &eeprom_cmd.dma, - GFP_KERNEL); + eeprom_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, + eeprom_cmd.size, &eeprom_cmd.dma, + GFP_KERNEL); if (!eeprom_cmd.va) return -ENOMEM; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 852f5bfe5f6d..d5026909dec5 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -167,8 +167,8 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, q->len = len; q->entry_size = entry_size; mem->size = len * entry_size; - mem->va = dma_zalloc_coherent(&adapter->pdev->dev, mem->size, &mem->dma, - GFP_KERNEL); + mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, + &mem->dma, GFP_KERNEL); if (!mem->va) return -ENOMEM; return 0; @@ -5766,9 +5766,9 @@ static int be_drv_init(struct be_adapter *adapter) int status = 0; mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16; - mbox_mem_alloc->va = dma_zalloc_coherent(dev, mbox_mem_alloc->size, - &mbox_mem_alloc->dma, - GFP_KERNEL); + mbox_mem_alloc->va = dma_alloc_coherent(dev, mbox_mem_alloc->size, + &mbox_mem_alloc->dma, + GFP_KERNEL); if (!mbox_mem_alloc->va) return -ENOMEM; @@ -5777,8 +5777,8 @@ static int be_drv_init(struct be_adapter *adapter) mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); rx_filter->size = sizeof(struct be_cmd_req_rx_filter); - rx_filter->va = dma_zalloc_coherent(dev, rx_filter->size, - &rx_filter->dma, GFP_KERNEL); + rx_filter->va = dma_alloc_coherent(dev, rx_filter->size, + &rx_filter->dma, GFP_KERNEL); if (!rx_filter->va) { status = -ENOMEM; goto free_mbox; @@ -5792,8 +5792,8 @@ static int be_drv_init(struct be_adapter *adapter) stats_cmd->size = sizeof(struct be_cmd_req_get_stats_v1); else stats_cmd->size = sizeof(struct be_cmd_req_get_stats_v2); - stats_cmd->va = dma_zalloc_coherent(dev, stats_cmd->size, - &stats_cmd->dma, GFP_KERNEL); + stats_cmd->va = dma_alloc_coherent(dev, stats_cmd->size, + &stats_cmd->dma, GFP_KERNEL); if (!stats_cmd->va) { status = -ENOMEM; goto free_rx_filter; diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 4d673225ed3e..3e5e97186fc4 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -935,16 +935,14 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv) return -ENOMEM; /* Allocate descriptors */ - priv->rxdes = dma_zalloc_coherent(priv->dev, - MAX_RX_QUEUE_ENTRIES * - sizeof(struct ftgmac100_rxdes), - &priv->rxdes_dma, GFP_KERNEL); + priv->rxdes = dma_alloc_coherent(priv->dev, + MAX_RX_QUEUE_ENTRIES * sizeof(struct ftgmac100_rxdes), + &priv->rxdes_dma, GFP_KERNEL); if (!priv->rxdes) return -ENOMEM; - priv->txdes = dma_zalloc_coherent(priv->dev, - MAX_TX_QUEUE_ENTRIES * - sizeof(struct ftgmac100_txdes), - &priv->txdes_dma, GFP_KERNEL); + priv->txdes = dma_alloc_coherent(priv->dev, + MAX_TX_QUEUE_ENTRIES * sizeof(struct ftgmac100_txdes), + &priv->txdes_dma, GFP_KERNEL); if (!priv->txdes) return -ENOMEM; diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index 084f24daf2b5..2a0e820526dc 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -734,10 +734,9 @@ static int ftmac100_alloc_buffers(struct ftmac100 *priv) { int i; - priv->descs = dma_zalloc_coherent(priv->dev, - sizeof(struct ftmac100_descs), - &priv->descs_dma_addr, - GFP_KERNEL); + priv->descs = dma_alloc_coherent(priv->dev, + sizeof(struct ftmac100_descs), + &priv->descs_dma_addr, GFP_KERNEL); if (!priv->descs) return -ENOMEM; diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index 471805ea363b..e5d853b7b454 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -1006,8 +1006,8 @@ static int hix5hd2_init_hw_desc_queue(struct hix5hd2_priv *priv) for (i = 0; i < QUEUE_NUMS; i++) { size = priv->pool[i].count * sizeof(struct hix5hd2_desc); - virt_addr = dma_zalloc_coherent(dev, size, &phys_addr, - GFP_KERNEL); + virt_addr = dma_alloc_coherent(dev, size, &phys_addr, + GFP_KERNEL); if (virt_addr == NULL) goto error_free_pool; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 07cd58798083..1bf7a5f116a0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2041,9 +2041,8 @@ static int hns3_alloc_desc(struct hns3_enet_ring *ring) { int size = ring->desc_num * sizeof(ring->desc[0]); - ring->desc = dma_zalloc_coherent(ring_to_dev(ring), size, - &ring->desc_dma_addr, - GFP_KERNEL); + ring->desc = dma_alloc_coherent(ring_to_dev(ring), size, + &ring->desc_dma_addr, GFP_KERNEL); if (!ring->desc) return -ENOMEM; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index 8af0cef5609b..e483a6e730e6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -39,9 +39,8 @@ static int hclge_alloc_cmd_desc(struct hclge_cmq_ring *ring) { int size = ring->desc_num * sizeof(struct hclge_desc); - ring->desc = dma_zalloc_coherent(cmq_ring_to_dev(ring), - size, &ring->desc_dma_addr, - GFP_KERNEL); + ring->desc = dma_alloc_coherent(cmq_ring_to_dev(ring), size, + &ring->desc_dma_addr, GFP_KERNEL); if (!ring->desc) return -ENOMEM; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c index d5765c8cf3a3..4e78e8812a04 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -115,9 +115,8 @@ static int hclgevf_alloc_cmd_desc(struct hclgevf_cmq_ring *ring) { int size = ring->desc_num * sizeof(struct hclgevf_desc); - ring->desc = dma_zalloc_coherent(cmq_ring_to_dev(ring), - size, &ring->desc_dma_addr, - GFP_KERNEL); + ring->desc = dma_alloc_coherent(cmq_ring_to_dev(ring), size, + &ring->desc_dma_addr, GFP_KERNEL); if (!ring->desc) return -ENOMEM; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.c index c40603a183df..b4fefb4c3064 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_api_cmd.c @@ -613,8 +613,8 @@ static int alloc_cmd_buf(struct hinic_api_cmd_chain *chain, u8 *cmd_vaddr; int err = 0; - cmd_vaddr = dma_zalloc_coherent(&pdev->dev, API_CMD_BUF_SIZE, - &cmd_paddr, GFP_KERNEL); + cmd_vaddr = dma_alloc_coherent(&pdev->dev, API_CMD_BUF_SIZE, + &cmd_paddr, GFP_KERNEL); if (!cmd_vaddr) { dev_err(&pdev->dev, "Failed to allocate API CMD DMA memory\n"); return -ENOMEM; @@ -663,8 +663,8 @@ static int api_cmd_create_cell(struct hinic_api_cmd_chain *chain, dma_addr_t node_paddr; int err; - node = dma_zalloc_coherent(&pdev->dev, chain->cell_size, - &node_paddr, GFP_KERNEL); + node = dma_alloc_coherent(&pdev->dev, chain->cell_size, &node_paddr, + GFP_KERNEL); if (!node) { dev_err(&pdev->dev, "Failed to allocate dma API CMD cell\n"); return -ENOMEM; @@ -821,10 +821,10 @@ static int api_chain_init(struct hinic_api_cmd_chain *chain, if (!chain->cell_ctxt) return -ENOMEM; - chain->wb_status = dma_zalloc_coherent(&pdev->dev, - sizeof(*chain->wb_status), - &chain->wb_status_paddr, - GFP_KERNEL); + chain->wb_status = dma_alloc_coherent(&pdev->dev, + sizeof(*chain->wb_status), + &chain->wb_status_paddr, + GFP_KERNEL); if (!chain->wb_status) { dev_err(&pdev->dev, "Failed to allocate DMA wb status\n"); return -ENOMEM; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c index 7cb8b9b94726..683e67515016 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c @@ -593,10 +593,10 @@ static int alloc_eq_pages(struct hinic_eq *eq) } for (pg = 0; pg < eq->num_pages; pg++) { - eq->virt_addr[pg] = dma_zalloc_coherent(&pdev->dev, - eq->page_size, - &eq->dma_addr[pg], - GFP_KERNEL); + eq->virt_addr[pg] = dma_alloc_coherent(&pdev->dev, + eq->page_size, + &eq->dma_addr[pg], + GFP_KERNEL); if (!eq->virt_addr[pg]) { err = -ENOMEM; goto err_dma_alloc; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c index 8e5897669a3a..a322a22d9357 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_io.c @@ -355,9 +355,9 @@ int hinic_io_create_qps(struct hinic_func_to_io *func_to_io, goto err_sq_db; } - ci_addr_base = dma_zalloc_coherent(&pdev->dev, CI_TABLE_SIZE(num_qps), - &func_to_io->ci_dma_base, - GFP_KERNEL); + ci_addr_base = dma_alloc_coherent(&pdev->dev, CI_TABLE_SIZE(num_qps), + &func_to_io->ci_dma_base, + GFP_KERNEL); if (!ci_addr_base) { dev_err(&pdev->dev, "Failed to allocate CI area\n"); err = -ENOMEM; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c index bbf9bdd0ee3e..d62cf509646a 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_qp.c @@ -336,9 +336,9 @@ static int alloc_rq_cqe(struct hinic_rq *rq) goto err_cqe_dma_arr_alloc; for (i = 0; i < wq->q_depth; i++) { - rq->cqe[i] = dma_zalloc_coherent(&pdev->dev, - sizeof(*rq->cqe[i]), - &rq->cqe_dma[i], GFP_KERNEL); + rq->cqe[i] = dma_alloc_coherent(&pdev->dev, + sizeof(*rq->cqe[i]), + &rq->cqe_dma[i], GFP_KERNEL); if (!rq->cqe[i]) goto err_cqe_alloc; } @@ -415,8 +415,8 @@ int hinic_init_rq(struct hinic_rq *rq, struct hinic_hwif *hwif, /* HW requirements: Must be at least 32 bit */ pi_size = ALIGN(sizeof(*rq->pi_virt_addr), sizeof(u32)); - rq->pi_virt_addr = dma_zalloc_coherent(&pdev->dev, pi_size, - &rq->pi_dma_addr, GFP_KERNEL); + rq->pi_virt_addr = dma_alloc_coherent(&pdev->dev, pi_size, + &rq->pi_dma_addr, GFP_KERNEL); if (!rq->pi_virt_addr) { dev_err(&pdev->dev, "Failed to allocate PI address\n"); err = -ENOMEM; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c index 1dfa7eb05c10..cb66e7024659 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wq.c @@ -114,8 +114,8 @@ static int queue_alloc_page(struct hinic_hwif *hwif, u64 **vaddr, u64 *paddr, struct pci_dev *pdev = hwif->pdev; dma_addr_t dma_addr; - *vaddr = dma_zalloc_coherent(&pdev->dev, page_sz, &dma_addr, - GFP_KERNEL); + *vaddr = dma_alloc_coherent(&pdev->dev, page_sz, &dma_addr, + GFP_KERNEL); if (!*vaddr) { dev_err(&pdev->dev, "Failed to allocate dma for wqs page\n"); return -ENOMEM; @@ -482,8 +482,8 @@ static int alloc_wq_pages(struct hinic_wq *wq, struct hinic_hwif *hwif, u64 *paddr = &wq->block_vaddr[i]; dma_addr_t dma_addr; - *vaddr = dma_zalloc_coherent(&pdev->dev, wq->wq_page_size, - &dma_addr, GFP_KERNEL); + *vaddr = dma_alloc_coherent(&pdev->dev, wq->wq_page_size, + &dma_addr, GFP_KERNEL); if (!*vaddr) { dev_err(&pdev->dev, "Failed to allocate wq page\n"); goto err_alloc_wq_pages; diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c index fff09dcf9e34..787d5aca5278 100644 --- a/drivers/net/ethernet/ibm/emac/mal.c +++ b/drivers/net/ethernet/ibm/emac/mal.c @@ -636,8 +636,8 @@ static int mal_probe(struct platform_device *ofdev) bd_size = sizeof(struct mal_descriptor) * (NUM_TX_BUFF * mal->num_tx_chans + NUM_RX_BUFF * mal->num_rx_chans); - mal->bd_virt = dma_zalloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma, - GFP_KERNEL); + mal->bd_virt = dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma, + GFP_KERNEL); if (mal->bd_virt == NULL) { err = -ENOMEM; goto fail_unmap; diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index 2569a168334c..a41008523c98 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -993,8 +993,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) txdr->size = txdr->count * sizeof(struct e1000_tx_desc); txdr->size = ALIGN(txdr->size, 4096); - txdr->desc = dma_zalloc_coherent(&pdev->dev, txdr->size, &txdr->dma, - GFP_KERNEL); + txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size, &txdr->dma, + GFP_KERNEL); if (!txdr->desc) { ret_val = 2; goto err_nomem; @@ -1051,8 +1051,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter) } rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); - rxdr->desc = dma_zalloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma, - GFP_KERNEL); + rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma, + GFP_KERNEL); if (!rxdr->desc) { ret_val = 6; goto err_nomem; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 308c006cb41d..189f231075c2 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -2305,8 +2305,8 @@ static int e1000_alloc_ring_dma(struct e1000_adapter *adapter, { struct pci_dev *pdev = adapter->pdev; - ring->desc = dma_zalloc_coherent(&pdev->dev, ring->size, &ring->dma, - GFP_KERNEL); + ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma, + GFP_KERNEL); if (!ring->desc) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 4d40878e395a..f52e2c46e6a7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -109,8 +109,8 @@ int i40e_allocate_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem, struct i40e_pf *pf = (struct i40e_pf *)hw->back; mem->size = ALIGN(size, alignment); - mem->va = dma_zalloc_coherent(&pf->pdev->dev, mem->size, - &mem->pa, GFP_KERNEL); + mem->va = dma_alloc_coherent(&pf->pdev->dev, mem->size, &mem->pa, + GFP_KERNEL); if (!mem->va) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index 1d4d1686909a..e5ac2d3fd816 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -680,8 +680,8 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter) txdr->size = txdr->count * sizeof(struct ixgb_tx_desc); txdr->size = ALIGN(txdr->size, 4096); - txdr->desc = dma_zalloc_coherent(&pdev->dev, txdr->size, &txdr->dma, - GFP_KERNEL); + txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size, &txdr->dma, + GFP_KERNEL); if (!txdr->desc) { vfree(txdr->buffer_info); return -ENOMEM; @@ -763,8 +763,8 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter) rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc); rxdr->size = ALIGN(rxdr->size, 4096); - rxdr->desc = dma_zalloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma, - GFP_KERNEL); + rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma, + GFP_KERNEL); if (!rxdr->desc) { vfree(rxdr->buffer_info); diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index e0875476a780..16066c2d5b3a 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -2044,9 +2044,9 @@ static int mvpp2_aggr_txq_init(struct platform_device *pdev, u32 txq_dma; /* Allocate memory for TX descriptors */ - aggr_txq->descs = dma_zalloc_coherent(&pdev->dev, - MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE, - &aggr_txq->descs_dma, GFP_KERNEL); + aggr_txq->descs = dma_alloc_coherent(&pdev->dev, + MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE, + &aggr_txq->descs_dma, GFP_KERNEL); if (!aggr_txq->descs) return -ENOMEM; diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 0bd4351b2a49..f8a6d6e3cb7a 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -557,9 +557,9 @@ static int init_hash_table(struct pxa168_eth_private *pep) * table is full. */ if (!pep->htpr) { - pep->htpr = dma_zalloc_coherent(pep->dev->dev.parent, - HASH_ADDR_TABLE_SIZE, - &pep->htpr_dma, GFP_KERNEL); + pep->htpr = dma_alloc_coherent(pep->dev->dev.parent, + HASH_ADDR_TABLE_SIZE, + &pep->htpr_dma, GFP_KERNEL); if (!pep->htpr) return -ENOMEM; } else { @@ -1044,9 +1044,9 @@ static int rxq_init(struct net_device *dev) pep->rx_desc_count = 0; size = pep->rx_ring_size * sizeof(struct rx_desc); pep->rx_desc_area_size = size; - pep->p_rx_desc_area = dma_zalloc_coherent(pep->dev->dev.parent, size, - &pep->rx_desc_dma, - GFP_KERNEL); + pep->p_rx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size, + &pep->rx_desc_dma, + GFP_KERNEL); if (!pep->p_rx_desc_area) goto out; @@ -1103,9 +1103,9 @@ static int txq_init(struct net_device *dev) pep->tx_desc_count = 0; size = pep->tx_ring_size * sizeof(struct tx_desc); pep->tx_desc_area_size = size; - pep->p_tx_desc_area = dma_zalloc_coherent(pep->dev->dev.parent, size, - &pep->tx_desc_dma, - GFP_KERNEL); + pep->p_tx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size, + &pep->tx_desc_dma, + GFP_KERNEL); if (!pep->p_tx_desc_area) goto out; /* Initialize the next_desc_ptr links in the Tx descriptors ring */ diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 399f565dd85a..fe9653fa8aea 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -598,10 +598,10 @@ static int mtk_init_fq_dma(struct mtk_eth *eth) dma_addr_t dma_addr; int i; - eth->scratch_ring = dma_zalloc_coherent(eth->dev, - cnt * sizeof(struct mtk_tx_dma), - ð->phy_scratch_ring, - GFP_ATOMIC); + eth->scratch_ring = dma_alloc_coherent(eth->dev, + cnt * sizeof(struct mtk_tx_dma), + ð->phy_scratch_ring, + GFP_ATOMIC); if (unlikely(!eth->scratch_ring)) return -ENOMEM; @@ -1213,8 +1213,8 @@ static int mtk_tx_alloc(struct mtk_eth *eth) if (!ring->buf) goto no_tx_mem; - ring->dma = dma_zalloc_coherent(eth->dev, MTK_DMA_SIZE * sz, - &ring->phys, GFP_ATOMIC); + ring->dma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz, + &ring->phys, GFP_ATOMIC); if (!ring->dma) goto no_tx_mem; @@ -1310,9 +1310,9 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) return -ENOMEM; } - ring->dma = dma_zalloc_coherent(eth->dev, - rx_dma_size * sizeof(*ring->dma), - &ring->phys, GFP_ATOMIC); + ring->dma = dma_alloc_coherent(eth->dev, + rx_dma_size * sizeof(*ring->dma), + &ring->phys, GFP_ATOMIC); if (!ring->dma) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c index 9af34e03892c..dbc483e4a2ef 100644 --- a/drivers/net/ethernet/mellanox/mlx4/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c @@ -584,8 +584,8 @@ static int mlx4_buf_direct_alloc(struct mlx4_dev *dev, int size, buf->npages = 1; buf->page_shift = get_order(size) + PAGE_SHIFT; buf->direct.buf = - dma_zalloc_coherent(&dev->persist->pdev->dev, - size, &t, GFP_KERNEL); + dma_alloc_coherent(&dev->persist->pdev->dev, size, &t, + GFP_KERNEL); if (!buf->direct.buf) return -ENOMEM; @@ -624,8 +624,8 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, for (i = 0; i < buf->nbufs; ++i) { buf->page_list[i].buf = - dma_zalloc_coherent(&dev->persist->pdev->dev, - PAGE_SIZE, &t, GFP_KERNEL); + dma_alloc_coherent(&dev->persist->pdev->dev, + PAGE_SIZE, &t, GFP_KERNEL); if (!buf->page_list[i].buf) goto err_free; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index 456f30007ad6..421b9c3c8bf7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -63,8 +63,8 @@ static void *mlx5_dma_zalloc_coherent_node(struct mlx5_core_dev *dev, mutex_lock(&priv->alloc_mutex); original_node = dev_to_node(&dev->pdev->dev); set_dev_node(&dev->pdev->dev, node); - cpu_handle = dma_zalloc_coherent(&dev->pdev->dev, size, - dma_handle, GFP_KERNEL); + cpu_handle = dma_alloc_coherent(&dev->pdev->dev, size, dma_handle, + GFP_KERNEL); set_dev_node(&dev->pdev->dev, original_node); mutex_unlock(&priv->alloc_mutex); return cpu_handle; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index d3125cdf69db..3e0fa8a8077b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1789,8 +1789,8 @@ static int alloc_cmd_page(struct mlx5_core_dev *dev, struct mlx5_cmd *cmd) { struct device *ddev = &dev->pdev->dev; - cmd->cmd_alloc_buf = dma_zalloc_coherent(ddev, MLX5_ADAPTER_PAGE_SIZE, - &cmd->alloc_dma, GFP_KERNEL); + cmd->cmd_alloc_buf = dma_alloc_coherent(ddev, MLX5_ADAPTER_PAGE_SIZE, + &cmd->alloc_dma, GFP_KERNEL); if (!cmd->cmd_alloc_buf) return -ENOMEM; @@ -1804,9 +1804,9 @@ static int alloc_cmd_page(struct mlx5_core_dev *dev, struct mlx5_cmd *cmd) dma_free_coherent(ddev, MLX5_ADAPTER_PAGE_SIZE, cmd->cmd_alloc_buf, cmd->alloc_dma); - cmd->cmd_alloc_buf = dma_zalloc_coherent(ddev, - 2 * MLX5_ADAPTER_PAGE_SIZE - 1, - &cmd->alloc_dma, GFP_KERNEL); + cmd->cmd_alloc_buf = dma_alloc_coherent(ddev, + 2 * MLX5_ADAPTER_PAGE_SIZE - 1, + &cmd->alloc_dma, GFP_KERNEL); if (!cmd->cmd_alloc_buf) return -ENOMEM; diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 5f384f73007d..19ce0e605096 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -3604,9 +3604,9 @@ static int myri10ge_alloc_slices(struct myri10ge_priv *mgp) for (i = 0; i < mgp->num_slices; i++) { ss = &mgp->ss[i]; bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry); - ss->rx_done.entry = dma_zalloc_coherent(&pdev->dev, bytes, - &ss->rx_done.bus, - GFP_KERNEL); + ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes, + &ss->rx_done.bus, + GFP_KERNEL); if (ss->rx_done.entry == NULL) goto abort; bytes = sizeof(*ss->fw_stats); diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index e97636d2e6ee..7d2d4241498f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2170,9 +2170,9 @@ nfp_net_tx_ring_alloc(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring) tx_ring->cnt = dp->txd_cnt; tx_ring->size = array_size(tx_ring->cnt, sizeof(*tx_ring->txds)); - tx_ring->txds = dma_zalloc_coherent(dp->dev, tx_ring->size, - &tx_ring->dma, - GFP_KERNEL | __GFP_NOWARN); + tx_ring->txds = dma_alloc_coherent(dp->dev, tx_ring->size, + &tx_ring->dma, + GFP_KERNEL | __GFP_NOWARN); if (!tx_ring->txds) { netdev_warn(dp->netdev, "failed to allocate TX descriptor ring memory, requested descriptor count: %d, consider lowering descriptor count\n", tx_ring->cnt); @@ -2328,9 +2328,9 @@ nfp_net_rx_ring_alloc(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring) rx_ring->cnt = dp->rxd_cnt; rx_ring->size = array_size(rx_ring->cnt, sizeof(*rx_ring->rxds)); - rx_ring->rxds = dma_zalloc_coherent(dp->dev, rx_ring->size, - &rx_ring->dma, - GFP_KERNEL | __GFP_NOWARN); + rx_ring->rxds = dma_alloc_coherent(dp->dev, rx_ring->size, + &rx_ring->dma, + GFP_KERNEL | __GFP_NOWARN); if (!rx_ring->rxds) { netdev_warn(dp->netdev, "failed to allocate RX descriptor ring memory, requested descriptor count: %d, consider lowering descriptor count\n", rx_ring->cnt); diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c index 0611f2335b4a..1e408d1a9b5f 100644 --- a/drivers/net/ethernet/ni/nixge.c +++ b/drivers/net/ethernet/ni/nixge.c @@ -287,9 +287,9 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev) priv->rx_bd_ci = 0; /* Allocate the Tx and Rx buffer descriptors. */ - priv->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent, - sizeof(*priv->tx_bd_v) * TX_BD_NUM, - &priv->tx_bd_p, GFP_KERNEL); + priv->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*priv->tx_bd_v) * TX_BD_NUM, + &priv->tx_bd_p, GFP_KERNEL); if (!priv->tx_bd_v) goto out; @@ -299,9 +299,9 @@ static int nixge_hw_dma_bd_init(struct net_device *ndev) if (!priv->tx_skb) goto out; - priv->rx_bd_v = dma_zalloc_coherent(ndev->dev.parent, - sizeof(*priv->rx_bd_v) * RX_BD_NUM, - &priv->rx_bd_p, GFP_KERNEL); + priv->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*priv->rx_bd_v) * RX_BD_NUM, + &priv->rx_bd_p, GFP_KERNEL); if (!priv->rx_bd_v) goto out; diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 43c0c10dfeb7..552d930e3940 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -1440,8 +1440,8 @@ pch_gbe_alloc_rx_buffers_pool(struct pch_gbe_adapter *adapter, size = rx_ring->count * bufsz + PCH_GBE_RESERVE_MEMORY; rx_ring->rx_buff_pool = - dma_zalloc_coherent(&pdev->dev, size, - &rx_ring->rx_buff_pool_logic, GFP_KERNEL); + dma_alloc_coherent(&pdev->dev, size, + &rx_ring->rx_buff_pool_logic, GFP_KERNEL); if (!rx_ring->rx_buff_pool) return -ENOMEM; @@ -1755,8 +1755,8 @@ int pch_gbe_setup_tx_resources(struct pch_gbe_adapter *adapter, tx_ring->size = tx_ring->count * (int)sizeof(struct pch_gbe_tx_desc); - tx_ring->desc = dma_zalloc_coherent(&pdev->dev, tx_ring->size, - &tx_ring->dma, GFP_KERNEL); + tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size, + &tx_ring->dma, GFP_KERNEL); if (!tx_ring->desc) { vfree(tx_ring->buffer_info); return -ENOMEM; @@ -1798,8 +1798,8 @@ int pch_gbe_setup_rx_resources(struct pch_gbe_adapter *adapter, return -ENOMEM; rx_ring->size = rx_ring->count * (int)sizeof(struct pch_gbe_rx_desc); - rx_ring->desc = dma_zalloc_coherent(&pdev->dev, rx_ring->size, - &rx_ring->dma, GFP_KERNEL); + rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size, + &rx_ring->dma, GFP_KERNEL); if (!rx_ring->desc) { vfree(rx_ring->buffer_info); return -ENOMEM; diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c index 8a31a02c9f47..d21041554507 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac.c @@ -401,9 +401,9 @@ static int pasemi_mac_setup_rx_resources(const struct net_device *dev) if (pasemi_dma_alloc_ring(&ring->chan, RX_RING_SIZE)) goto out_ring_desc; - ring->buffers = dma_zalloc_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * sizeof(u64), - &ring->buf_dma, GFP_KERNEL); + ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * sizeof(u64), + &ring->buf_dma, GFP_KERNEL); if (!ring->buffers) goto out_ring_desc; diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index dc1c1b616084..c2ad405b2f50 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -936,9 +936,9 @@ static int qed_cxt_src_t2_alloc(struct qed_hwfn *p_hwfn) u32 size = min_t(u32, total_size, psz); void **p_virt = &p_mngr->t2[i].p_virt; - *p_virt = dma_zalloc_coherent(&p_hwfn->cdev->pdev->dev, - size, &p_mngr->t2[i].p_phys, - GFP_KERNEL); + *p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, size, + &p_mngr->t2[i].p_phys, + GFP_KERNEL); if (!p_mngr->t2[i].p_virt) { rc = -ENOMEM; goto t2_fail; @@ -1054,8 +1054,8 @@ static int qed_ilt_blk_alloc(struct qed_hwfn *p_hwfn, u32 size; size = min_t(u32, sz_left, p_blk->real_size_in_page); - p_virt = dma_zalloc_coherent(&p_hwfn->cdev->pdev->dev, size, - &p_phys, GFP_KERNEL); + p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, size, + &p_phys, GFP_KERNEL); if (!p_virt) return -ENOMEM; @@ -2306,9 +2306,9 @@ qed_cxt_dynamic_ilt_alloc(struct qed_hwfn *p_hwfn, goto out0; } - p_virt = dma_zalloc_coherent(&p_hwfn->cdev->pdev->dev, - p_blk->real_size_in_page, &p_phys, - GFP_KERNEL); + p_virt = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev, + p_blk->real_size_in_page, &p_phys, + GFP_KERNEL); if (!p_virt) { rc = -ENOMEM; goto out1; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index d344e9d43832..af38d3d73291 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -434,14 +434,14 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter, *(tx_ring->hw_consumer) = 0; rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx); - rq_addr = dma_zalloc_coherent(&adapter->pdev->dev, rq_size, - &rq_phys_addr, GFP_KERNEL); + rq_addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size, + &rq_phys_addr, GFP_KERNEL); if (!rq_addr) return -ENOMEM; rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx); - rsp_addr = dma_zalloc_coherent(&adapter->pdev->dev, rsp_size, - &rsp_phys_addr, GFP_KERNEL); + rsp_addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size, + &rsp_phys_addr, GFP_KERNEL); if (!rsp_addr) { err = -ENOMEM; goto out_free_rq; @@ -855,8 +855,8 @@ int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args cmd; size_t nic_size = sizeof(struct qlcnic_info_le); - nic_info_addr = dma_zalloc_coherent(&adapter->pdev->dev, nic_size, - &nic_dma_t, GFP_KERNEL); + nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; @@ -909,8 +909,8 @@ int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter, if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC) return err; - nic_info_addr = dma_zalloc_coherent(&adapter->pdev->dev, nic_size, - &nic_dma_t, GFP_KERNEL); + nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size, + &nic_dma_t, GFP_KERNEL); if (!nic_info_addr) return -ENOMEM; @@ -964,8 +964,8 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter, void *pci_info_addr; int err = 0, i; - pci_info_addr = dma_zalloc_coherent(&adapter->pdev->dev, pci_size, - &pci_info_dma_t, GFP_KERNEL); + pci_info_addr = dma_alloc_coherent(&adapter->pdev->dev, pci_size, + &pci_info_dma_t, GFP_KERNEL); if (!pci_info_addr) return -ENOMEM; @@ -1078,8 +1078,8 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func, return -EIO; } - stats_addr = dma_zalloc_coherent(&adapter->pdev->dev, stats_size, - &stats_dma_t, GFP_KERNEL); + stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size, + &stats_dma_t, GFP_KERNEL); if (!stats_addr) return -ENOMEM; @@ -1134,8 +1134,8 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter, if (mac_stats == NULL) return -ENOMEM; - stats_addr = dma_zalloc_coherent(&adapter->pdev->dev, stats_size, - &stats_dma_t, GFP_KERNEL); + stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size, + &stats_dma_t, GFP_KERNEL); if (!stats_addr) return -ENOMEM; diff --git a/drivers/net/ethernet/qualcomm/emac/emac-mac.c b/drivers/net/ethernet/qualcomm/emac/emac-mac.c index 031f6e6ee9c1..8d790313ee3d 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-mac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-mac.c @@ -776,7 +776,7 @@ int emac_mac_rx_tx_rings_alloc_all(struct emac_adapter *adpt) 8 + 2 * 8; /* 8 byte per one Tx and two Rx rings */ ring_header->used = 0; - ring_header->v_addr = dma_zalloc_coherent(dev, ring_header->size, + ring_header->v_addr = dma_alloc_coherent(dev, ring_header->size, &ring_header->dma_addr, GFP_KERNEL); if (!ring_header->v_addr) diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 690aee88f0eb..6d22dd500790 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -400,9 +400,9 @@ static int init_tx_ring(struct device *dev, u8 queue_no, } /* allocate memory for TX descriptors */ - tx_ring->dma_tx = dma_zalloc_coherent(dev, - tx_rsize * sizeof(struct sxgbe_tx_norm_desc), - &tx_ring->dma_tx_phy, GFP_KERNEL); + tx_ring->dma_tx = dma_alloc_coherent(dev, + tx_rsize * sizeof(struct sxgbe_tx_norm_desc), + &tx_ring->dma_tx_phy, GFP_KERNEL); if (!tx_ring->dma_tx) return -ENOMEM; @@ -479,9 +479,9 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no, rx_ring->queue_no = queue_no; /* allocate memory for RX descriptors */ - rx_ring->dma_rx = dma_zalloc_coherent(priv->device, - rx_rsize * sizeof(struct sxgbe_rx_norm_desc), - &rx_ring->dma_rx_phy, GFP_KERNEL); + rx_ring->dma_rx = dma_alloc_coherent(priv->device, + rx_rsize * sizeof(struct sxgbe_rx_norm_desc), + &rx_ring->dma_rx_phy, GFP_KERNEL); if (rx_ring->dma_rx == NULL) return -ENOMEM; diff --git a/drivers/net/ethernet/sfc/falcon/nic.c b/drivers/net/ethernet/sfc/falcon/nic.c index a8ecb33390da..9c07b5175581 100644 --- a/drivers/net/ethernet/sfc/falcon/nic.c +++ b/drivers/net/ethernet/sfc/falcon/nic.c @@ -33,8 +33,8 @@ int ef4_nic_alloc_buffer(struct ef4_nic *efx, struct ef4_buffer *buffer, unsigned int len, gfp_t gfp_flags) { - buffer->addr = dma_zalloc_coherent(&efx->pci_dev->dev, len, - &buffer->dma_addr, gfp_flags); + buffer->addr = dma_alloc_coherent(&efx->pci_dev->dev, len, + &buffer->dma_addr, gfp_flags); if (!buffer->addr) return -ENOMEM; buffer->len = len; diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index aa1945a858d5..c2d45a40eb48 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -34,8 +34,8 @@ int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, unsigned int len, gfp_t gfp_flags) { - buffer->addr = dma_zalloc_coherent(&efx->pci_dev->dev, len, - &buffer->dma_addr, gfp_flags); + buffer->addr = dma_alloc_coherent(&efx->pci_dev->dev, len, + &buffer->dma_addr, gfp_flags); if (!buffer->addr) return -ENOMEM; buffer->len = len; diff --git a/drivers/net/ethernet/sgi/meth.c b/drivers/net/ethernet/sgi/meth.c index 703fbbefea44..0e1b7e960b98 100644 --- a/drivers/net/ethernet/sgi/meth.c +++ b/drivers/net/ethernet/sgi/meth.c @@ -211,8 +211,8 @@ static void meth_check_link(struct net_device *dev) static int meth_init_tx_ring(struct meth_private *priv) { /* Init TX ring */ - priv->tx_ring = dma_zalloc_coherent(NULL, TX_RING_BUFFER_SIZE, - &priv->tx_ring_dma, GFP_ATOMIC); + priv->tx_ring = dma_alloc_coherent(NULL, TX_RING_BUFFER_SIZE, + &priv->tx_ring_dma, GFP_ATOMIC); if (!priv->tx_ring) return -ENOMEM; diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index 05a0948ad929..a18149720aa2 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -1029,8 +1029,8 @@ static int netsec_alloc_dring(struct netsec_priv *priv, enum ring_id id) struct netsec_desc_ring *dring = &priv->desc_ring[id]; int i; - dring->vaddr = dma_zalloc_coherent(priv->dev, DESC_SZ * DESC_NUM, - &dring->desc_dma, GFP_KERNEL); + dring->vaddr = dma_alloc_coherent(priv->dev, DESC_SZ * DESC_NUM, + &dring->desc_dma, GFP_KERNEL); if (!dring->vaddr) goto err; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 0e0a0789c2ed..0c4ab3444cc3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1549,22 +1549,18 @@ static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv) goto err_dma; if (priv->extend_desc) { - rx_q->dma_erx = dma_zalloc_coherent(priv->device, - DMA_RX_SIZE * - sizeof(struct - dma_extended_desc), - &rx_q->dma_rx_phy, - GFP_KERNEL); + rx_q->dma_erx = dma_alloc_coherent(priv->device, + DMA_RX_SIZE * sizeof(struct dma_extended_desc), + &rx_q->dma_rx_phy, + GFP_KERNEL); if (!rx_q->dma_erx) goto err_dma; } else { - rx_q->dma_rx = dma_zalloc_coherent(priv->device, - DMA_RX_SIZE * - sizeof(struct - dma_desc), - &rx_q->dma_rx_phy, - GFP_KERNEL); + rx_q->dma_rx = dma_alloc_coherent(priv->device, + DMA_RX_SIZE * sizeof(struct dma_desc), + &rx_q->dma_rx_phy, + GFP_KERNEL); if (!rx_q->dma_rx) goto err_dma; } @@ -1612,21 +1608,17 @@ static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv) goto err_dma; if (priv->extend_desc) { - tx_q->dma_etx = dma_zalloc_coherent(priv->device, - DMA_TX_SIZE * - sizeof(struct - dma_extended_desc), - &tx_q->dma_tx_phy, - GFP_KERNEL); + tx_q->dma_etx = dma_alloc_coherent(priv->device, + DMA_TX_SIZE * sizeof(struct dma_extended_desc), + &tx_q->dma_tx_phy, + GFP_KERNEL); if (!tx_q->dma_etx) goto err_dma; } else { - tx_q->dma_tx = dma_zalloc_coherent(priv->device, - DMA_TX_SIZE * - sizeof(struct - dma_desc), - &tx_q->dma_tx_phy, - GFP_KERNEL); + tx_q->dma_tx = dma_alloc_coherent(priv->device, + DMA_TX_SIZE * sizeof(struct dma_desc), + &tx_q->dma_tx_phy, + GFP_KERNEL); if (!tx_q->dma_tx) goto err_dma; } diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c index edcd1e60b30d..37925a1d58de 100644 --- a/drivers/net/ethernet/tundra/tsi108_eth.c +++ b/drivers/net/ethernet/tundra/tsi108_eth.c @@ -1311,13 +1311,13 @@ static int tsi108_open(struct net_device *dev) data->id, dev->irq, dev->name); } - data->rxring = dma_zalloc_coherent(&data->pdev->dev, rxring_size, - &data->rxdma, GFP_KERNEL); + data->rxring = dma_alloc_coherent(&data->pdev->dev, rxring_size, + &data->rxdma, GFP_KERNEL); if (!data->rxring) return -ENOMEM; - data->txring = dma_zalloc_coherent(&data->pdev->dev, txring_size, - &data->txdma, GFP_KERNEL); + data->txring = dma_alloc_coherent(&data->pdev->dev, txring_size, + &data->txdma, GFP_KERNEL); if (!data->txring) { dma_free_coherent(&data->pdev->dev, rxring_size, data->rxring, data->rxdma); diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 2241f9897092..15bb058db392 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -243,15 +243,15 @@ static int temac_dma_bd_init(struct net_device *ndev) /* allocate the tx and rx ring buffer descriptors. */ /* returns a virtual address and a physical address. */ - lp->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent, - sizeof(*lp->tx_bd_v) * TX_BD_NUM, - &lp->tx_bd_p, GFP_KERNEL); + lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*lp->tx_bd_v) * TX_BD_NUM, + &lp->tx_bd_p, GFP_KERNEL); if (!lp->tx_bd_v) goto out; - lp->rx_bd_v = dma_zalloc_coherent(ndev->dev.parent, - sizeof(*lp->rx_bd_v) * RX_BD_NUM, - &lp->rx_bd_p, GFP_KERNEL); + lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*lp->rx_bd_v) * RX_BD_NUM, + &lp->rx_bd_p, GFP_KERNEL); if (!lp->rx_bd_v) goto out; diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 12a14609ec47..0789d8af7d72 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -199,15 +199,15 @@ static int axienet_dma_bd_init(struct net_device *ndev) lp->rx_bd_ci = 0; /* Allocate the Tx and Rx buffer descriptors. */ - lp->tx_bd_v = dma_zalloc_coherent(ndev->dev.parent, - sizeof(*lp->tx_bd_v) * TX_BD_NUM, - &lp->tx_bd_p, GFP_KERNEL); + lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*lp->tx_bd_v) * TX_BD_NUM, + &lp->tx_bd_p, GFP_KERNEL); if (!lp->tx_bd_v) goto out; - lp->rx_bd_v = dma_zalloc_coherent(ndev->dev.parent, - sizeof(*lp->rx_bd_v) * RX_BD_NUM, - &lp->rx_bd_p, GFP_KERNEL); + lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent, + sizeof(*lp->rx_bd_v) * RX_BD_NUM, + &lp->rx_bd_p, GFP_KERNEL); if (!lp->rx_bd_v) goto out; diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 61fceee73c1b..38ac8ef41f5f 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -1139,9 +1139,9 @@ static int dfx_driver_init(struct net_device *dev, const char *print_name, #endif sizeof(PI_CONSUMER_BLOCK) + (PI_ALIGN_K_DESC_BLK - 1); - bp->kmalloced = top_v = dma_zalloc_coherent(bp->bus_dev, alloc_size, - &bp->kmalloced_dma, - GFP_ATOMIC); + bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size, + &bp->kmalloced_dma, + GFP_ATOMIC); if (top_v == NULL) return DFX_K_FAILURE; diff --git a/drivers/net/fddi/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c index 72433f3efc74..5d661f60b101 100644 --- a/drivers/net/fddi/skfp/skfddi.c +++ b/drivers/net/fddi/skfp/skfddi.c @@ -409,10 +409,10 @@ static int skfp_driver_init(struct net_device *dev) if (bp->SharedMemSize > 0) { bp->SharedMemSize += 16; // for descriptor alignment - bp->SharedMemAddr = dma_zalloc_coherent(&bp->pdev.dev, - bp->SharedMemSize, - &bp->SharedMemDMA, - GFP_ATOMIC); + bp->SharedMemAddr = dma_alloc_coherent(&bp->pdev.dev, + bp->SharedMemSize, + &bp->SharedMemDMA, + GFP_ATOMIC); if (!bp->SharedMemAddr) { printk("could not allocate mem for "); printk("hardware module: %ld byte\n", diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index e454dfc9ad8f..89984fcab01e 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -535,8 +535,8 @@ vmxnet3_tq_create(struct vmxnet3_tx_queue *tq, } sz = tq->tx_ring.size * sizeof(tq->buf_info[0]); - tq->buf_info = dma_zalloc_coherent(&adapter->pdev->dev, sz, - &tq->buf_info_pa, GFP_KERNEL); + tq->buf_info = dma_alloc_coherent(&adapter->pdev->dev, sz, + &tq->buf_info_pa, GFP_KERNEL); if (!tq->buf_info) goto err; @@ -1815,8 +1815,8 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter) sz = sizeof(struct vmxnet3_rx_buf_info) * (rq->rx_ring[0].size + rq->rx_ring[1].size); - bi = dma_zalloc_coherent(&adapter->pdev->dev, sz, &rq->buf_info_pa, - GFP_KERNEL); + bi = dma_alloc_coherent(&adapter->pdev->dev, sz, &rq->buf_info_pa, + GFP_KERNEL); if (!bi) goto err; diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 839fa7715709..be6485428198 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -279,10 +279,9 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr4); /* Get BD buffer */ - bd_buffer = dma_zalloc_coherent(priv->dev, - (RX_BD_RING_LEN + TX_BD_RING_LEN) * - MAX_RX_BUF_LENGTH, - &bd_dma_addr, GFP_KERNEL); + bd_buffer = dma_alloc_coherent(priv->dev, + (RX_BD_RING_LEN + TX_BD_RING_LEN) * MAX_RX_BUF_LENGTH, + &bd_dma_addr, GFP_KERNEL); if (!bd_buffer) { dev_err(priv->dev, "Could not allocate buffer descriptors\n"); diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index f6d3ecbdd3a3..2a5668b4f6bc 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1553,10 +1553,9 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id, * coherent DMA are unsupported */ dest_ring->base_addr_owner_space_unaligned = - dma_zalloc_coherent(ar->dev, - (nentries * sizeof(struct ce_desc) + - CE_DESC_RING_ALIGN), - &base_addr, GFP_KERNEL); + dma_alloc_coherent(ar->dev, + (nentries * sizeof(struct ce_desc) + CE_DESC_RING_ALIGN), + &base_addr, GFP_KERNEL); if (!dest_ring->base_addr_owner_space_unaligned) { kfree(dest_ring); return ERR_PTR(-ENOMEM); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e49b36752ba2..49758490eaba 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5169,10 +5169,10 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_ADHOC || vif->type == NL80211_IFTYPE_MESH_POINT || vif->type == NL80211_IFTYPE_AP) { - arvif->beacon_buf = dma_zalloc_coherent(ar->dev, - IEEE80211_MAX_FRAME_LEN, - &arvif->beacon_paddr, - GFP_ATOMIC); + arvif->beacon_buf = dma_alloc_coherent(ar->dev, + IEEE80211_MAX_FRAME_LEN, + &arvif->beacon_paddr, + GFP_ATOMIC); if (!arvif->beacon_buf) { ret = -ENOMEM; ath10k_warn(ar, "failed to allocate beacon buffer: %d\n", diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 01b4edb00e9e..39e0b1cc2a12 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -936,8 +936,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, */ alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT); - data_buf = (unsigned char *)dma_zalloc_coherent(ar->dev, - alloc_nbytes, + data_buf = (unsigned char *)dma_alloc_coherent(ar->dev, alloc_nbytes, &ce_data_base, GFP_ATOMIC); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index ba837403e266..8e236d158ca6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5193,7 +5193,7 @@ static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id, void *vaddr; pool_size = num_units * round_up(unit_len, 4); - vaddr = dma_zalloc_coherent(ar->dev, pool_size, &paddr, GFP_KERNEL); + vaddr = dma_alloc_coherent(ar->dev, pool_size, &paddr, GFP_KERNEL); if (!vaddr) return -ENOMEM; diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 5ab3e31c9ffa..bab30f7a443c 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -174,9 +174,8 @@ static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn int i; size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc); - wcn_ch->cpu_addr = dma_zalloc_coherent(dev, size, - &wcn_ch->dma_addr, - GFP_KERNEL); + wcn_ch->cpu_addr = dma_alloc_coherent(dev, size, &wcn_ch->dma_addr, + GFP_KERNEL); if (!wcn_ch->cpu_addr) return -ENOMEM; @@ -627,9 +626,9 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn) 16 - (WCN36XX_BD_CHUNK_SIZE % 8); s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H; - cpu_addr = dma_zalloc_coherent(wcn->dev, s, - &wcn->mgmt_mem_pool.phy_addr, - GFP_KERNEL); + cpu_addr = dma_alloc_coherent(wcn->dev, s, + &wcn->mgmt_mem_pool.phy_addr, + GFP_KERNEL); if (!cpu_addr) goto out_err; @@ -642,9 +641,9 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn) 16 - (WCN36XX_BD_CHUNK_SIZE % 8); s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L; - cpu_addr = dma_zalloc_coherent(wcn->dev, s, - &wcn->data_mem_pool.phy_addr, - GFP_KERNEL); + cpu_addr = dma_alloc_coherent(wcn->dev, s, + &wcn->data_mem_pool.phy_addr, + GFP_KERNEL); if (!cpu_addr) goto out_err; diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 05a8348bd7b9..3380aaef456c 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -99,7 +99,7 @@ static int wil_sring_alloc(struct wil6210_priv *wil, /* Status messages are allocated and initialized to 0. This is necessary * since DR bit should be initialized to 0. */ - sring->va = dma_zalloc_coherent(dev, sz, &sring->pa, GFP_KERNEL); + sring->va = dma_alloc_coherent(dev, sz, &sring->pa, GFP_KERNEL); if (!sring->va) return -ENOMEM; @@ -381,15 +381,15 @@ static int wil_ring_alloc_desc_ring(struct wil6210_priv *wil, if (!ring->ctx) goto err; - ring->va = dma_zalloc_coherent(dev, sz, &ring->pa, GFP_KERNEL); + ring->va = dma_alloc_coherent(dev, sz, &ring->pa, GFP_KERNEL); if (!ring->va) goto err_free_ctx; if (ring->is_rx) { sz = sizeof(*ring->edma_rx_swtail.va); ring->edma_rx_swtail.va = - dma_zalloc_coherent(dev, sz, &ring->edma_rx_swtail.pa, - GFP_KERNEL); + dma_alloc_coherent(dev, sz, &ring->edma_rx_swtail.pa, + GFP_KERNEL); if (!ring->edma_rx_swtail.va) goto err_free_va; } diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index dfc4c34298d4..b34e51933257 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -431,9 +431,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring) u16 ring_mem_size = (ring->type == B43_DMA_64BIT) ? B43_DMA64_RINGMEMSIZE : B43_DMA32_RINGMEMSIZE; - ring->descbase = dma_zalloc_coherent(ring->dev->dev->dma_dev, - ring_mem_size, &(ring->dmabase), - GFP_KERNEL); + ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev, + ring_mem_size, &(ring->dmabase), + GFP_KERNEL); if (!ring->descbase) return -ENOMEM; diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c index 1b1da7d83652..2ce1537d983c 100644 --- a/drivers/net/wireless/broadcom/b43legacy/dma.c +++ b/drivers/net/wireless/broadcom/b43legacy/dma.c @@ -331,9 +331,9 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring, static int alloc_ringmemory(struct b43legacy_dmaring *ring) { /* GFP flags must match the flags in free_ringmemory()! */ - ring->descbase = dma_zalloc_coherent(ring->dev->dev->dma_dev, - B43legacy_DMA_RINGMEMSIZE, - &(ring->dmabase), GFP_KERNEL); + ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev, + B43legacy_DMA_RINGMEMSIZE, + &(ring->dmabase), GFP_KERNEL); if (!ring->descbase) return -ENOMEM; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 16d7dda965d8..0f69b3fa296e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1281,10 +1281,10 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) u32 addr; devinfo->shared.scratch = - dma_zalloc_coherent(&devinfo->pdev->dev, - BRCMF_DMA_D2H_SCRATCH_BUF_LEN, - &devinfo->shared.scratch_dmahandle, - GFP_KERNEL); + dma_alloc_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_SCRATCH_BUF_LEN, + &devinfo->shared.scratch_dmahandle, + GFP_KERNEL); if (!devinfo->shared.scratch) goto fail; @@ -1298,10 +1298,10 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo) brcmf_pcie_write_tcm32(devinfo, addr, BRCMF_DMA_D2H_SCRATCH_BUF_LEN); devinfo->shared.ringupd = - dma_zalloc_coherent(&devinfo->pdev->dev, - BRCMF_DMA_D2H_RINGUPD_BUF_LEN, - &devinfo->shared.ringupd_dmahandle, - GFP_KERNEL); + dma_alloc_coherent(&devinfo->pdev->dev, + BRCMF_DMA_D2H_RINGUPD_BUF_LEN, + &devinfo->shared.ringupd_dmahandle, + GFP_KERNEL); if (!devinfo->shared.ringupd) goto fail; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index e965cc588850..9e850c25877b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -711,30 +711,24 @@ static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, * Allocate the circular buffer of Read Buffer Descriptors * (RBDs) */ - rxq->bd = dma_zalloc_coherent(dev, - free_size * rxq->queue_size, - &rxq->bd_dma, GFP_KERNEL); + rxq->bd = dma_alloc_coherent(dev, free_size * rxq->queue_size, + &rxq->bd_dma, GFP_KERNEL); if (!rxq->bd) goto err; if (trans->cfg->mq_rx_supported) { - rxq->used_bd = dma_zalloc_coherent(dev, - (use_rx_td ? - sizeof(*rxq->cd) : - sizeof(__le32)) * - rxq->queue_size, - &rxq->used_bd_dma, - GFP_KERNEL); + rxq->used_bd = dma_alloc_coherent(dev, + (use_rx_td ? sizeof(*rxq->cd) : sizeof(__le32)) * rxq->queue_size, + &rxq->used_bd_dma, + GFP_KERNEL); if (!rxq->used_bd) goto err; } /* Allocate the driver's pointer to receive buffer status */ - rxq->rb_stts = dma_zalloc_coherent(dev, use_rx_td ? - sizeof(__le16) : - sizeof(struct iwl_rb_status), - &rxq->rb_stts_dma, - GFP_KERNEL); + rxq->rb_stts = dma_alloc_coherent(dev, + use_rx_td ? sizeof(__le16) : sizeof(struct iwl_rb_status), + &rxq->rb_stts_dma, GFP_KERNEL); if (!rxq->rb_stts) goto err; @@ -742,16 +736,14 @@ static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, return 0; /* Allocate the driver's pointer to TR tail */ - rxq->tr_tail = dma_zalloc_coherent(dev, sizeof(__le16), - &rxq->tr_tail_dma, - GFP_KERNEL); + rxq->tr_tail = dma_alloc_coherent(dev, sizeof(__le16), + &rxq->tr_tail_dma, GFP_KERNEL); if (!rxq->tr_tail) goto err; /* Allocate the driver's pointer to CR tail */ - rxq->cr_tail = dma_zalloc_coherent(dev, sizeof(__le16), - &rxq->cr_tail_dma, - GFP_KERNEL); + rxq->cr_tail = dma_alloc_coherent(dev, sizeof(__le16), + &rxq->cr_tail_dma, GFP_KERNEL); if (!rxq->cr_tail) goto err; /* @@ -1947,9 +1939,8 @@ int iwl_pcie_alloc_ict(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); trans_pcie->ict_tbl = - dma_zalloc_coherent(trans->dev, ICT_SIZE, - &trans_pcie->ict_tbl_dma, - GFP_KERNEL); + dma_alloc_coherent(trans->dev, ICT_SIZE, + &trans_pcie->ict_tbl_dma, GFP_KERNEL); if (!trans_pcie->ict_tbl) return -ENOMEM; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c index 528cb0401df1..4956a54151cb 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mmio.c @@ -119,9 +119,9 @@ static int rt2x00mmio_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, /* * Allocate DMA memory for descriptor and buffer. */ - addr = dma_zalloc_coherent(rt2x00dev->dev, - queue->limit * queue->desc_size, &dma, - GFP_KERNEL); + addr = dma_alloc_coherent(rt2x00dev->dev, + queue->limit * queue->desc_size, &dma, + GFP_KERNEL); if (!addr) return -ENOMEM; diff --git a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c index 5ee5f40b4dfc..f1eaa3c4d46a 100644 --- a/drivers/ntb/hw/mscc/ntb_hw_switchtec.c +++ b/drivers/ntb/hw/mscc/ntb_hw_switchtec.c @@ -1339,10 +1339,10 @@ static int switchtec_ntb_init_shared_mw(struct switchtec_ntb *sndev) int rc; sndev->nr_rsvd_luts++; - sndev->self_shared = dma_zalloc_coherent(&sndev->stdev->pdev->dev, - LUT_SIZE, - &sndev->self_shared_dma, - GFP_KERNEL); + sndev->self_shared = dma_alloc_coherent(&sndev->stdev->pdev->dev, + LUT_SIZE, + &sndev->self_shared_dma, + GFP_KERNEL); if (!sndev->self_shared) { dev_err(&sndev->stdev->dev, "unable to allocate memory for shared mw\n"); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 5a0bf6a24d50..e8d0942c9c92 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1485,8 +1485,8 @@ static int nvme_alloc_queue(struct nvme_dev *dev, int qid, int depth) if (dev->ctrl.queue_count > qid) return 0; - nvmeq->cqes = dma_zalloc_coherent(dev->dev, CQ_SIZE(depth), - &nvmeq->cq_dma_addr, GFP_KERNEL); + nvmeq->cqes = dma_alloc_coherent(dev->dev, CQ_SIZE(depth), + &nvmeq->cq_dma_addr, GFP_KERNEL); if (!nvmeq->cqes) goto free_nvmeq; @@ -1915,8 +1915,8 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred, if (dev->ctrl.hmmaxd && dev->ctrl.hmmaxd < max_entries) max_entries = dev->ctrl.hmmaxd; - descs = dma_zalloc_coherent(dev->dev, max_entries * sizeof(*descs), - &descs_dma, GFP_KERNEL); + descs = dma_alloc_coherent(dev->dev, max_entries * sizeof(*descs), + &descs_dma, GFP_KERNEL); if (!descs) goto out; diff --git a/drivers/pci/controller/pcie-iproc-msi.c b/drivers/pci/controller/pcie-iproc-msi.c index 9deb56989d72..cb3401a931f8 100644 --- a/drivers/pci/controller/pcie-iproc-msi.c +++ b/drivers/pci/controller/pcie-iproc-msi.c @@ -602,9 +602,9 @@ int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node) } /* Reserve memory for event queue and make sure memories are zeroed */ - msi->eq_cpu = dma_zalloc_coherent(pcie->dev, - msi->nr_eq_region * EQ_MEM_REGION_SIZE, - &msi->eq_dma, GFP_KERNEL); + msi->eq_cpu = dma_alloc_coherent(pcie->dev, + msi->nr_eq_region * EQ_MEM_REGION_SIZE, + &msi->eq_dma, GFP_KERNEL); if (!msi->eq_cpu) { ret = -ENOMEM; goto free_irqs; diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 6c5536d3d42a..e22766c79fe9 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -1373,10 +1373,10 @@ static int switchtec_init_pci(struct switchtec_dev *stdev, if (ioread32(&stdev->mmio_mrpc->dma_ver) == 0) return 0; - stdev->dma_mrpc = dma_zalloc_coherent(&stdev->pdev->dev, - sizeof(*stdev->dma_mrpc), - &stdev->dma_mrpc_dma_addr, - GFP_KERNEL); + stdev->dma_mrpc = dma_alloc_coherent(&stdev->pdev->dev, + sizeof(*stdev->dma_mrpc), + &stdev->dma_mrpc_dma_addr, + GFP_KERNEL); if (stdev->dma_mrpc == NULL) return -ENOMEM; diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index bb655854713d..b64c56c33c3b 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c @@ -1382,9 +1382,9 @@ static int tsi721_doorbell_init(struct tsi721_device *priv) INIT_WORK(&priv->idb_work, tsi721_db_dpc); /* Allocate buffer for inbound doorbells queue */ - priv->idb_base = dma_zalloc_coherent(&priv->pdev->dev, - IDB_QSIZE * TSI721_IDB_ENTRY_SIZE, - &priv->idb_dma, GFP_KERNEL); + priv->idb_base = dma_alloc_coherent(&priv->pdev->dev, + IDB_QSIZE * TSI721_IDB_ENTRY_SIZE, + &priv->idb_dma, GFP_KERNEL); if (!priv->idb_base) return -ENOMEM; @@ -1447,9 +1447,9 @@ static int tsi721_bdma_maint_init(struct tsi721_device *priv) regs = priv->regs + TSI721_DMAC_BASE(TSI721_DMACH_MAINT); /* Allocate space for DMA descriptors */ - bd_ptr = dma_zalloc_coherent(&priv->pdev->dev, - bd_num * sizeof(struct tsi721_dma_desc), - &bd_phys, GFP_KERNEL); + bd_ptr = dma_alloc_coherent(&priv->pdev->dev, + bd_num * sizeof(struct tsi721_dma_desc), + &bd_phys, GFP_KERNEL); if (!bd_ptr) return -ENOMEM; @@ -1464,7 +1464,7 @@ static int tsi721_bdma_maint_init(struct tsi721_device *priv) sts_size = (bd_num >= TSI721_DMA_MINSTSSZ) ? bd_num : TSI721_DMA_MINSTSSZ; sts_size = roundup_pow_of_two(sts_size); - sts_ptr = dma_zalloc_coherent(&priv->pdev->dev, + sts_ptr = dma_alloc_coherent(&priv->pdev->dev, sts_size * sizeof(struct tsi721_dma_sts), &sts_phys, GFP_KERNEL); if (!sts_ptr) { @@ -1939,10 +1939,10 @@ static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id, /* Outbound message descriptor status FIFO allocation */ priv->omsg_ring[mbox].sts_size = roundup_pow_of_two(entries + 1); - priv->omsg_ring[mbox].sts_base = dma_zalloc_coherent(&priv->pdev->dev, - priv->omsg_ring[mbox].sts_size * - sizeof(struct tsi721_dma_sts), - &priv->omsg_ring[mbox].sts_phys, GFP_KERNEL); + priv->omsg_ring[mbox].sts_base = dma_alloc_coherent(&priv->pdev->dev, + priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts), + &priv->omsg_ring[mbox].sts_phys, + GFP_KERNEL); if (priv->omsg_ring[mbox].sts_base == NULL) { tsi_debug(OMSG, &priv->pdev->dev, "ENOMEM for OB_MSG_%d status FIFO", mbox); diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c index 006ea5a45020..7f5d4436f594 100644 --- a/drivers/rapidio/devices/tsi721_dma.c +++ b/drivers/rapidio/devices/tsi721_dma.c @@ -90,9 +90,9 @@ static int tsi721_bdma_ch_init(struct tsi721_bdma_chan *bdma_chan, int bd_num) * Allocate space for DMA descriptors * (add an extra element for link descriptor) */ - bd_ptr = dma_zalloc_coherent(dev, - (bd_num + 1) * sizeof(struct tsi721_dma_desc), - &bd_phys, GFP_ATOMIC); + bd_ptr = dma_alloc_coherent(dev, + (bd_num + 1) * sizeof(struct tsi721_dma_desc), + &bd_phys, GFP_ATOMIC); if (!bd_ptr) return -ENOMEM; @@ -108,7 +108,7 @@ static int tsi721_bdma_ch_init(struct tsi721_bdma_chan *bdma_chan, int bd_num) sts_size = ((bd_num + 1) >= TSI721_DMA_MINSTSSZ) ? (bd_num + 1) : TSI721_DMA_MINSTSSZ; sts_size = roundup_pow_of_two(sts_size); - sts_ptr = dma_zalloc_coherent(dev, + sts_ptr = dma_alloc_coherent(dev, sts_size * sizeof(struct tsi721_dma_sts), &sts_phys, GFP_ATOMIC); if (!sts_ptr) { diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c index dcbf5c857743..ed8e58f09054 100644 --- a/drivers/s390/net/ism_drv.c +++ b/drivers/s390/net/ism_drv.c @@ -89,8 +89,8 @@ static int register_sba(struct ism_dev *ism) dma_addr_t dma_handle; struct ism_sba *sba; - sba = dma_zalloc_coherent(&ism->pdev->dev, PAGE_SIZE, - &dma_handle, GFP_KERNEL); + sba = dma_alloc_coherent(&ism->pdev->dev, PAGE_SIZE, &dma_handle, + GFP_KERNEL); if (!sba) return -ENOMEM; @@ -116,8 +116,8 @@ static int register_ieq(struct ism_dev *ism) dma_addr_t dma_handle; struct ism_eq *ieq; - ieq = dma_zalloc_coherent(&ism->pdev->dev, PAGE_SIZE, - &dma_handle, GFP_KERNEL); + ieq = dma_alloc_coherent(&ism->pdev->dev, PAGE_SIZE, &dma_handle, + GFP_KERNEL); if (!ieq) return -ENOMEM; @@ -234,10 +234,9 @@ static int ism_alloc_dmb(struct ism_dev *ism, struct smcd_dmb *dmb) test_and_set_bit(dmb->sba_idx, ism->sba_bitmap)) return -EINVAL; - dmb->cpu_addr = dma_zalloc_coherent(&ism->pdev->dev, dmb->dmb_len, - &dmb->dma_addr, GFP_KERNEL | - __GFP_NOWARN | __GFP_NOMEMALLOC | - __GFP_COMP | __GFP_NORETRY); + dmb->cpu_addr = dma_alloc_coherent(&ism->pdev->dev, dmb->dmb_len, + &dmb->dma_addr, + GFP_KERNEL | __GFP_NOWARN | __GFP_NOMEMALLOC | __GFP_COMP | __GFP_NORETRY); if (!dmb->cpu_addr) clear_bit(dmb->sba_idx, ism->sba_bitmap); diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index e8f5f7c63190..cd096104bcec 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -646,8 +646,9 @@ static int twl_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) unsigned long *cpu_addr; int retval = 1; - cpu_addr = dma_zalloc_coherent(&tw_dev->tw_pci_dev->dev, - size * TW_Q_LENGTH, &dma_handle, GFP_KERNEL); + cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, + size * TW_Q_LENGTH, &dma_handle, + GFP_KERNEL); if (!cpu_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); goto out; diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index ff53fd0d12f2..66c514310f3c 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -1123,8 +1123,8 @@ static int inia100_probe_one(struct pci_dev *pdev, /* Get total memory needed for SCB */ sz = ORC_MAXQUEUE * sizeof(struct orc_scb); - host->scb_virt = dma_zalloc_coherent(&pdev->dev, sz, &host->scb_phys, - GFP_KERNEL); + host->scb_virt = dma_alloc_coherent(&pdev->dev, sz, &host->scb_phys, + GFP_KERNEL); if (!host->scb_virt) { printk("inia100: SCB memory allocation error\n"); goto out_host_put; @@ -1132,8 +1132,8 @@ static int inia100_probe_one(struct pci_dev *pdev, /* Get total memory needed for ESCB */ sz = ORC_MAXQUEUE * sizeof(struct orc_extended_scb); - host->escb_virt = dma_zalloc_coherent(&pdev->dev, sz, &host->escb_phys, - GFP_KERNEL); + host->escb_virt = dma_alloc_coherent(&pdev->dev, sz, &host->escb_phys, + GFP_KERNEL); if (!host->escb_virt) { printk("inia100: ESCB memory allocation error\n"); goto out_free_scb_array; diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 0f6751b0a633..57c6fa388bf6 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -587,8 +587,10 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg; acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32); - dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize, - &dma_coherent_handle, GFP_KERNEL); + dma_coherent = dma_alloc_coherent(&pdev->dev, + acb->roundup_ccbsize, + &dma_coherent_handle, + GFP_KERNEL); if (!dma_coherent) { pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no); return false; @@ -617,8 +619,10 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) struct MessageUnit_D *reg; acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32); - dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize, - &dma_coherent_handle, GFP_KERNEL); + dma_coherent = dma_alloc_coherent(&pdev->dev, + acb->roundup_ccbsize, + &dma_coherent_handle, + GFP_KERNEL); if (!dma_coherent) { pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no); return false; @@ -659,8 +663,10 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) uint32_t completeQ_size; completeQ_size = sizeof(struct deliver_completeQ) * ARCMSR_MAX_HBE_DONEQUEUE + 128; acb->roundup_ccbsize = roundup(completeQ_size, 32); - dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize, - &dma_coherent_handle, GFP_KERNEL); + dma_coherent = dma_alloc_coherent(&pdev->dev, + acb->roundup_ccbsize, + &dma_coherent_handle, + GFP_KERNEL); if (!dma_coherent){ pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no); return false; diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 39f3820572b4..74e260027c7d 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3321,8 +3321,8 @@ static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q, q->len = len; q->entry_size = entry_size; mem->size = len * entry_size; - mem->va = dma_zalloc_coherent(&phba->pcidev->dev, mem->size, &mem->dma, - GFP_KERNEL); + mem->va = dma_alloc_coherent(&phba->pcidev->dev, mem->size, &mem->dma, + GFP_KERNEL); if (!mem->va) return -ENOMEM; return 0; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index ca7b7bbc8371..d4febaadfaa3 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -293,8 +293,8 @@ static int beiscsi_prep_nemb_cmd(struct beiscsi_hba *phba, struct be_dma_mem *cmd, u8 subsystem, u8 opcode, u32 size) { - cmd->va = dma_zalloc_coherent(&phba->ctrl.pdev->dev, size, &cmd->dma, - GFP_KERNEL); + cmd->va = dma_alloc_coherent(&phba->ctrl.pdev->dev, size, &cmd->dma, + GFP_KERNEL); if (!cmd->va) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG, "BG_%d : Failed to allocate memory for if info\n"); @@ -1510,10 +1510,9 @@ int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba, return -EINVAL; nonemb_cmd.size = sizeof(union be_invldt_cmds_params); - nonemb_cmd.va = dma_zalloc_coherent(&phba->ctrl.pdev->dev, - nonemb_cmd.size, - &nonemb_cmd.dma, - GFP_KERNEL); + nonemb_cmd.va = dma_alloc_coherent(&phba->ctrl.pdev->dev, + nonemb_cmd.size, &nonemb_cmd.dma, + GFP_KERNEL); if (!nonemb_cmd.va) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH, "BM_%d : invldt_cmds_params alloc failed\n"); diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 5d163ca1b366..d8e6d7480f35 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -3264,9 +3264,9 @@ bfad_fcxp_map_sg(struct bfad_s *bfad, void *payload_kbuf, /* Allocate dma coherent memory */ buf_info = buf_base; buf_info->size = payload_len; - buf_info->virt = dma_zalloc_coherent(&bfad->pcidev->dev, - buf_info->size, &buf_info->phys, - GFP_KERNEL); + buf_info->virt = dma_alloc_coherent(&bfad->pcidev->dev, + buf_info->size, &buf_info->phys, + GFP_KERNEL); if (!buf_info->virt) goto out_free_mem; diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index e8ae4d671d23..039328d9ef13 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -1857,10 +1857,10 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba) * entries. Hence the limit with one page is 8192 task context * entries. */ - hba->task_ctx_bd_tbl = dma_zalloc_coherent(&hba->pcidev->dev, - PAGE_SIZE, - &hba->task_ctx_bd_dma, - GFP_KERNEL); + hba->task_ctx_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, + PAGE_SIZE, + &hba->task_ctx_bd_dma, + GFP_KERNEL); if (!hba->task_ctx_bd_tbl) { printk(KERN_ERR PFX "unable to allocate task context BDT\n"); rc = -1; @@ -1894,10 +1894,10 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba) task_ctx_bdt = (struct regpair *)hba->task_ctx_bd_tbl; for (i = 0; i < task_ctx_arr_sz; i++) { - hba->task_ctx[i] = dma_zalloc_coherent(&hba->pcidev->dev, - PAGE_SIZE, - &hba->task_ctx_dma[i], - GFP_KERNEL); + hba->task_ctx[i] = dma_alloc_coherent(&hba->pcidev->dev, + PAGE_SIZE, + &hba->task_ctx_dma[i], + GFP_KERNEL); if (!hba->task_ctx[i]) { printk(KERN_ERR PFX "unable to alloc task context\n"); rc = -1; @@ -2031,19 +2031,19 @@ static int bnx2fc_allocate_hash_table(struct bnx2fc_hba *hba) } for (i = 0; i < segment_count; ++i) { - hba->hash_tbl_segments[i] = dma_zalloc_coherent(&hba->pcidev->dev, - BNX2FC_HASH_TBL_CHUNK_SIZE, - &dma_segment_array[i], - GFP_KERNEL); + hba->hash_tbl_segments[i] = dma_alloc_coherent(&hba->pcidev->dev, + BNX2FC_HASH_TBL_CHUNK_SIZE, + &dma_segment_array[i], + GFP_KERNEL); if (!hba->hash_tbl_segments[i]) { printk(KERN_ERR PFX "hash segment alloc failed\n"); goto cleanup_dma; } } - hba->hash_tbl_pbl = dma_zalloc_coherent(&hba->pcidev->dev, PAGE_SIZE, - &hba->hash_tbl_pbl_dma, - GFP_KERNEL); + hba->hash_tbl_pbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, + &hba->hash_tbl_pbl_dma, + GFP_KERNEL); if (!hba->hash_tbl_pbl) { printk(KERN_ERR PFX "hash table pbl alloc failed\n"); goto cleanup_dma; @@ -2104,10 +2104,9 @@ int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba) return -ENOMEM; mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct regpair); - hba->t2_hash_tbl_ptr = dma_zalloc_coherent(&hba->pcidev->dev, - mem_size, - &hba->t2_hash_tbl_ptr_dma, - GFP_KERNEL); + hba->t2_hash_tbl_ptr = dma_alloc_coherent(&hba->pcidev->dev, mem_size, + &hba->t2_hash_tbl_ptr_dma, + GFP_KERNEL); if (!hba->t2_hash_tbl_ptr) { printk(KERN_ERR PFX "unable to allocate t2 hash table ptr\n"); bnx2fc_free_fw_resc(hba); @@ -2116,9 +2115,9 @@ int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba) mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct fcoe_t2_hash_table_entry); - hba->t2_hash_tbl = dma_zalloc_coherent(&hba->pcidev->dev, mem_size, - &hba->t2_hash_tbl_dma, - GFP_KERNEL); + hba->t2_hash_tbl = dma_alloc_coherent(&hba->pcidev->dev, mem_size, + &hba->t2_hash_tbl_dma, + GFP_KERNEL); if (!hba->t2_hash_tbl) { printk(KERN_ERR PFX "unable to allocate t2 hash table\n"); bnx2fc_free_fw_resc(hba); @@ -2140,9 +2139,9 @@ int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba) return -ENOMEM; } - hba->stats_buffer = dma_zalloc_coherent(&hba->pcidev->dev, PAGE_SIZE, - &hba->stats_buf_dma, - GFP_KERNEL); + hba->stats_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, + &hba->stats_buf_dma, + GFP_KERNEL); if (!hba->stats_buffer) { printk(KERN_ERR PFX "unable to alloc Stats Buffer\n"); bnx2fc_free_fw_resc(hba); diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index e3d1c7c440c8..d735e87e416a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -672,8 +672,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, tgt->sq_mem_size = (tgt->sq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK; - tgt->sq = dma_zalloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size, - &tgt->sq_dma, GFP_KERNEL); + tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size, + &tgt->sq_dma, GFP_KERNEL); if (!tgt->sq) { printk(KERN_ERR PFX "unable to allocate SQ memory %d\n", tgt->sq_mem_size); @@ -685,8 +685,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, tgt->cq_mem_size = (tgt->cq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK; - tgt->cq = dma_zalloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size, - &tgt->cq_dma, GFP_KERNEL); + tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size, + &tgt->cq_dma, GFP_KERNEL); if (!tgt->cq) { printk(KERN_ERR PFX "unable to allocate CQ memory %d\n", tgt->cq_mem_size); @@ -698,8 +698,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, tgt->rq_mem_size = (tgt->rq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK; - tgt->rq = dma_zalloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size, - &tgt->rq_dma, GFP_KERNEL); + tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size, + &tgt->rq_dma, GFP_KERNEL); if (!tgt->rq) { printk(KERN_ERR PFX "unable to allocate RQ memory %d\n", tgt->rq_mem_size); @@ -710,8 +710,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, tgt->rq_pbl_size = (tgt->rq_pbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK; - tgt->rq_pbl = dma_zalloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size, - &tgt->rq_pbl_dma, GFP_KERNEL); + tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size, + &tgt->rq_pbl_dma, GFP_KERNEL); if (!tgt->rq_pbl) { printk(KERN_ERR PFX "unable to allocate RQ PBL %d\n", tgt->rq_pbl_size); @@ -735,9 +735,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, tgt->xferq_mem_size = (tgt->xferq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK; - tgt->xferq = dma_zalloc_coherent(&hba->pcidev->dev, - tgt->xferq_mem_size, &tgt->xferq_dma, - GFP_KERNEL); + tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, + tgt->xferq_mem_size, &tgt->xferq_dma, + GFP_KERNEL); if (!tgt->xferq) { printk(KERN_ERR PFX "unable to allocate XFERQ %d\n", tgt->xferq_mem_size); @@ -749,9 +749,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, tgt->confq_mem_size = (tgt->confq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK; - tgt->confq = dma_zalloc_coherent(&hba->pcidev->dev, - tgt->confq_mem_size, &tgt->confq_dma, - GFP_KERNEL); + tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, + tgt->confq_mem_size, &tgt->confq_dma, + GFP_KERNEL); if (!tgt->confq) { printk(KERN_ERR PFX "unable to allocate CONFQ %d\n", tgt->confq_mem_size); @@ -763,9 +763,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, tgt->confq_pbl_size = (tgt->confq_pbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK; - tgt->confq_pbl = dma_zalloc_coherent(&hba->pcidev->dev, - tgt->confq_pbl_size, - &tgt->confq_pbl_dma, GFP_KERNEL); + tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev, + tgt->confq_pbl_size, + &tgt->confq_pbl_dma, GFP_KERNEL); if (!tgt->confq_pbl) { printk(KERN_ERR PFX "unable to allocate CONFQ PBL %d\n", tgt->confq_pbl_size); @@ -787,9 +787,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, /* Allocate and map ConnDB */ tgt->conn_db_mem_size = sizeof(struct fcoe_conn_db); - tgt->conn_db = dma_zalloc_coherent(&hba->pcidev->dev, - tgt->conn_db_mem_size, - &tgt->conn_db_dma, GFP_KERNEL); + tgt->conn_db = dma_alloc_coherent(&hba->pcidev->dev, + tgt->conn_db_mem_size, + &tgt->conn_db_dma, GFP_KERNEL); if (!tgt->conn_db) { printk(KERN_ERR PFX "unable to allocate conn_db %d\n", tgt->conn_db_mem_size); @@ -802,8 +802,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, tgt->lcq_mem_size = (tgt->lcq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK; - tgt->lcq = dma_zalloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size, - &tgt->lcq_dma, GFP_KERNEL); + tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size, + &tgt->lcq_dma, GFP_KERNEL); if (!tgt->lcq) { printk(KERN_ERR PFX "unable to allocate lcq %d\n", diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 91f5316aa3ab..fae6f71e677d 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1070,8 +1070,8 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) /* Allocate memory area for actual SQ element */ ep->qp.sq_virt = - dma_zalloc_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size, - &ep->qp.sq_phys, GFP_KERNEL); + dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size, + &ep->qp.sq_phys, GFP_KERNEL); if (!ep->qp.sq_virt) { printk(KERN_ALERT "bnx2i: unable to alloc SQ BD memory %d\n", ep->qp.sq_mem_size); @@ -1106,8 +1106,8 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) /* Allocate memory area for actual CQ element */ ep->qp.cq_virt = - dma_zalloc_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size, - &ep->qp.cq_phys, GFP_KERNEL); + dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size, + &ep->qp.cq_phys, GFP_KERNEL); if (!ep->qp.cq_virt) { printk(KERN_ALERT "bnx2i: unable to alloc CQ BD memory %d\n", ep->qp.cq_mem_size); diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c index dc12933533d5..66bbd21819ae 100644 --- a/drivers/scsi/csiostor/csio_wr.c +++ b/drivers/scsi/csiostor/csio_wr.c @@ -233,8 +233,8 @@ csio_wr_alloc_q(struct csio_hw *hw, uint32_t qsize, uint32_t wrsize, q = wrm->q_arr[free_idx]; - q->vstart = dma_zalloc_coherent(&hw->pdev->dev, qsz, &q->pstart, - GFP_KERNEL); + q->vstart = dma_alloc_coherent(&hw->pdev->dev, qsz, &q->pstart, + GFP_KERNEL); if (!q->vstart) { csio_err(hw, "Failed to allocate DMA memory for " diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 8698af86485d..2dc564e59430 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -2730,8 +2730,8 @@ lpfc_bsg_dma_page_alloc(struct lpfc_hba *phba) INIT_LIST_HEAD(&dmabuf->list); /* now, allocate dma buffer */ - dmabuf->virt = dma_zalloc_coherent(&pcidev->dev, BSG_MBOX_SIZE, - &(dmabuf->phys), GFP_KERNEL); + dmabuf->virt = dma_alloc_coherent(&pcidev->dev, BSG_MBOX_SIZE, + &(dmabuf->phys), GFP_KERNEL); if (!dmabuf->virt) { kfree(dmabuf); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index c1c36812c3d2..bede11e16349 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -6973,9 +6973,9 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) if (!dmabuf) return NULL; - dmabuf->virt = dma_zalloc_coherent(&phba->pcidev->dev, - LPFC_HDR_TEMPLATE_SIZE, - &dmabuf->phys, GFP_KERNEL); + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + LPFC_HDR_TEMPLATE_SIZE, + &dmabuf->phys, GFP_KERNEL); if (!dmabuf->virt) { rpi_hdr = NULL; goto err_free_dmabuf; @@ -7397,8 +7397,8 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba) } /* Allocate memory for SLI-2 structures */ - phba->slim2p.virt = dma_zalloc_coherent(&pdev->dev, SLI2_SLIM_SIZE, - &phba->slim2p.phys, GFP_KERNEL); + phba->slim2p.virt = dma_alloc_coherent(&pdev->dev, SLI2_SLIM_SIZE, + &phba->slim2p.phys, GFP_KERNEL); if (!phba->slim2p.virt) goto out_iounmap; @@ -7816,8 +7816,8 @@ lpfc_create_bootstrap_mbox(struct lpfc_hba *phba) * plus an alignment restriction of 16 bytes. */ bmbx_size = sizeof(struct lpfc_bmbx_create) + (LPFC_ALIGN_16_BYTE - 1); - dmabuf->virt = dma_zalloc_coherent(&phba->pcidev->dev, bmbx_size, - &dmabuf->phys, GFP_KERNEL); + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, bmbx_size, + &dmabuf->phys, GFP_KERNEL); if (!dmabuf->virt) { kfree(dmabuf); return -ENOMEM; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index f6a5083a621e..4d3b94317515 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1827,9 +1827,9 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox, * page, this is used as a priori size of SLI4_PAGE_SIZE for * the later DMA memory free. */ - viraddr = dma_zalloc_coherent(&phba->pcidev->dev, - SLI4_PAGE_SIZE, &phyaddr, - GFP_KERNEL); + viraddr = dma_alloc_coherent(&phba->pcidev->dev, + SLI4_PAGE_SIZE, &phyaddr, + GFP_KERNEL); /* In case of malloc fails, proceed with whatever we have */ if (!viraddr) break; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 30734caf77e1..12fd74761ae0 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5362,8 +5362,8 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, * mailbox command. */ dma_size = *vpd_size; - dmabuf->virt = dma_zalloc_coherent(&phba->pcidev->dev, dma_size, - &dmabuf->phys, GFP_KERNEL); + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, dma_size, + &dmabuf->phys, GFP_KERNEL); if (!dmabuf->virt) { kfree(dmabuf); return -ENOMEM; @@ -6300,10 +6300,9 @@ lpfc_sli4_ras_dma_alloc(struct lpfc_hba *phba, goto free_mem; } - dmabuf->virt = dma_zalloc_coherent(&phba->pcidev->dev, + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, LPFC_RAS_MAX_ENTRY_SIZE, - &dmabuf->phys, - GFP_KERNEL); + &dmabuf->phys, GFP_KERNEL); if (!dmabuf->virt) { kfree(dmabuf); rc = -ENOMEM; @@ -14613,9 +14612,9 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size, dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (!dmabuf) goto out_fail; - dmabuf->virt = dma_zalloc_coherent(&phba->pcidev->dev, - hw_page_size, &dmabuf->phys, - GFP_KERNEL); + dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, + hw_page_size, &dmabuf->phys, + GFP_KERNEL); if (!dmabuf->virt) { kfree(dmabuf); goto out_fail; diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index e836392b75e8..f112458023ff 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -967,9 +967,10 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) * Allocate the common 16-byte aligned memory for the handshake * mailbox. */ - raid_dev->una_mbox64 = dma_zalloc_coherent(&adapter->pdev->dev, - sizeof(mbox64_t), &raid_dev->una_mbox64_dma, - GFP_KERNEL); + raid_dev->una_mbox64 = dma_alloc_coherent(&adapter->pdev->dev, + sizeof(mbox64_t), + &raid_dev->una_mbox64_dma, + GFP_KERNEL); if (!raid_dev->una_mbox64) { con_log(CL_ANN, (KERN_WARNING @@ -995,8 +996,8 @@ megaraid_alloc_cmd_packets(adapter_t *adapter) align; // Allocate memory for commands issued internally - adapter->ibuf = dma_zalloc_coherent(&pdev->dev, MBOX_IBUF_SIZE, - &adapter->ibuf_dma_h, GFP_KERNEL); + adapter->ibuf = dma_alloc_coherent(&pdev->dev, MBOX_IBUF_SIZE, + &adapter->ibuf_dma_h, GFP_KERNEL); if (!adapter->ibuf) { con_log(CL_ANN, (KERN_WARNING @@ -2897,8 +2898,8 @@ megaraid_mbox_product_info(adapter_t *adapter) * Issue an ENQUIRY3 command to find out certain adapter parameters, * e.g., max channels, max commands etc. */ - pinfo = dma_zalloc_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), - &pinfo_dma_h, GFP_KERNEL); + pinfo = dma_alloc_coherent(&adapter->pdev->dev, sizeof(mraid_pinfo_t), + &pinfo_dma_h, GFP_KERNEL); if (pinfo == NULL) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d\n", __func__, diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index f7bdd783360a..7eaa400f6328 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2273,9 +2273,9 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance, sizeof(struct MR_LD_VF_AFFILIATION_111)); else { new_affiliation_111 = - dma_zalloc_coherent(&instance->pdev->dev, - sizeof(struct MR_LD_VF_AFFILIATION_111), - &new_affiliation_111_h, GFP_KERNEL); + dma_alloc_coherent(&instance->pdev->dev, + sizeof(struct MR_LD_VF_AFFILIATION_111), + &new_affiliation_111_h, GFP_KERNEL); if (!new_affiliation_111) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " "memory for new affiliation for scsi%d\n", @@ -2380,10 +2380,9 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance, sizeof(struct MR_LD_VF_AFFILIATION)); else { new_affiliation = - dma_zalloc_coherent(&instance->pdev->dev, - (MAX_LOGICAL_DRIVES + 1) * - sizeof(struct MR_LD_VF_AFFILIATION), - &new_affiliation_h, GFP_KERNEL); + dma_alloc_coherent(&instance->pdev->dev, + (MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION), + &new_affiliation_h, GFP_KERNEL); if (!new_affiliation) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " "memory for new affiliation for scsi%d\n", @@ -2546,9 +2545,10 @@ int megasas_sriov_start_heartbeat(struct megasas_instance *instance, if (initial) { instance->hb_host_mem = - dma_zalloc_coherent(&instance->pdev->dev, - sizeof(struct MR_CTRL_HB_HOST_MEM), - &instance->hb_host_mem_h, GFP_KERNEL); + dma_alloc_coherent(&instance->pdev->dev, + sizeof(struct MR_CTRL_HB_HOST_MEM), + &instance->hb_host_mem_h, + GFP_KERNEL); if (!instance->hb_host_mem) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate" " memory for heartbeat host memory for scsi%d\n", @@ -5816,9 +5816,9 @@ megasas_get_seq_num(struct megasas_instance *instance, } dcmd = &cmd->frame->dcmd; - el_info = dma_zalloc_coherent(&instance->pdev->dev, - sizeof(struct megasas_evt_log_info), &el_info_h, - GFP_KERNEL); + el_info = dma_alloc_coherent(&instance->pdev->dev, + sizeof(struct megasas_evt_log_info), + &el_info_h, GFP_KERNEL); if (!el_info) { megasas_return_cmd(instance, cmd); return -ENOMEM; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 211c17c33aa0..a9a25f0eaf6f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -689,8 +689,9 @@ megasas_alloc_rdpq_fusion(struct megasas_instance *instance) array_size = sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION; - fusion->rdpq_virt = dma_zalloc_coherent(&instance->pdev->dev, - array_size, &fusion->rdpq_phys, GFP_KERNEL); + fusion->rdpq_virt = dma_alloc_coherent(&instance->pdev->dev, + array_size, &fusion->rdpq_phys, + GFP_KERNEL); if (!fusion->rdpq_virt) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index f3e182eb0970..c9dc7740e9e7 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1915,8 +1915,9 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) /* We use the PCI APIs for now until the generic one gets fixed * enough or until we get some macio-specific versions */ - dma_cmd_space = dma_zalloc_coherent(&macio_get_pci_dev(mdev)->dev, - ms->dma_cmd_size, &dma_cmd_bus, GFP_KERNEL); + dma_cmd_space = dma_alloc_coherent(&macio_get_pci_dev(mdev)->dev, + ms->dma_cmd_size, &dma_cmd_bus, + GFP_KERNEL); if (dma_cmd_space == NULL) { printk(KERN_ERR "mesh: can't allocate DMA table\n"); goto out_unmap; diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index dbe753fba486..36f64205ecfa 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -143,8 +143,9 @@ static struct mvumi_res *mvumi_alloc_mem_resource(struct mvumi_hba *mhba, case RESOURCE_UNCACHED_MEMORY: size = round_up(size, 8); - res->virt_addr = dma_zalloc_coherent(&mhba->pdev->dev, size, - &res->bus_addr, GFP_KERNEL); + res->virt_addr = dma_alloc_coherent(&mhba->pdev->dev, size, + &res->bus_addr, + GFP_KERNEL); if (!res->virt_addr) { dev_err(&mhba->pdev->dev, "unable to allocate consistent mem," @@ -246,8 +247,8 @@ static int mvumi_internal_cmd_sgl(struct mvumi_hba *mhba, struct mvumi_cmd *cmd, if (size == 0) return 0; - virt_addr = dma_zalloc_coherent(&mhba->pdev->dev, size, &phy_addr, - GFP_KERNEL); + virt_addr = dma_alloc_coherent(&mhba->pdev->dev, size, &phy_addr, + GFP_KERNEL); if (!virt_addr) return -1; diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index b3be49d41375..4c5a3d23e010 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -116,8 +116,8 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr, u64 align_offset = 0; if (align) align_offset = (dma_addr_t)align - 1; - mem_virt_alloc = dma_zalloc_coherent(&pdev->dev, mem_size + align, - &mem_dma_handle, GFP_KERNEL); + mem_virt_alloc = dma_alloc_coherent(&pdev->dev, mem_size + align, + &mem_dma_handle, GFP_KERNEL); if (!mem_virt_alloc) { pm8001_printk("memory allocation error\n"); return -1; diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index edcaf4b0cb0b..9bbc19fc190b 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -1050,16 +1050,17 @@ static int qedf_alloc_sq(struct qedf_ctx *qedf, struct qedf_rport *fcport) sizeof(void *); fcport->sq_pbl_size = fcport->sq_pbl_size + QEDF_PAGE_SIZE; - fcport->sq = dma_zalloc_coherent(&qedf->pdev->dev, - fcport->sq_mem_size, &fcport->sq_dma, GFP_KERNEL); + fcport->sq = dma_alloc_coherent(&qedf->pdev->dev, fcport->sq_mem_size, + &fcport->sq_dma, GFP_KERNEL); if (!fcport->sq) { QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate send queue.\n"); rval = 1; goto out; } - fcport->sq_pbl = dma_zalloc_coherent(&qedf->pdev->dev, - fcport->sq_pbl_size, &fcport->sq_pbl_dma, GFP_KERNEL); + fcport->sq_pbl = dma_alloc_coherent(&qedf->pdev->dev, + fcport->sq_pbl_size, + &fcport->sq_pbl_dma, GFP_KERNEL); if (!fcport->sq_pbl) { QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate send queue PBL.\n"); rval = 1; @@ -2680,8 +2681,10 @@ static int qedf_alloc_bdq(struct qedf_ctx *qedf) } /* Allocate list of PBL pages */ - qedf->bdq_pbl_list = dma_zalloc_coherent(&qedf->pdev->dev, - QEDF_PAGE_SIZE, &qedf->bdq_pbl_list_dma, GFP_KERNEL); + qedf->bdq_pbl_list = dma_alloc_coherent(&qedf->pdev->dev, + QEDF_PAGE_SIZE, + &qedf->bdq_pbl_list_dma, + GFP_KERNEL); if (!qedf->bdq_pbl_list) { QEDF_ERR(&(qedf->dbg_ctx), "Could not allocate list of PBL pages.\n"); return -ENOMEM; @@ -2770,9 +2773,10 @@ static int qedf_alloc_global_queues(struct qedf_ctx *qedf) ALIGN(qedf->global_queues[i]->cq_pbl_size, QEDF_PAGE_SIZE); qedf->global_queues[i]->cq = - dma_zalloc_coherent(&qedf->pdev->dev, - qedf->global_queues[i]->cq_mem_size, - &qedf->global_queues[i]->cq_dma, GFP_KERNEL); + dma_alloc_coherent(&qedf->pdev->dev, + qedf->global_queues[i]->cq_mem_size, + &qedf->global_queues[i]->cq_dma, + GFP_KERNEL); if (!qedf->global_queues[i]->cq) { QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate cq.\n"); @@ -2781,9 +2785,10 @@ static int qedf_alloc_global_queues(struct qedf_ctx *qedf) } qedf->global_queues[i]->cq_pbl = - dma_zalloc_coherent(&qedf->pdev->dev, - qedf->global_queues[i]->cq_pbl_size, - &qedf->global_queues[i]->cq_pbl_dma, GFP_KERNEL); + dma_alloc_coherent(&qedf->pdev->dev, + qedf->global_queues[i]->cq_pbl_size, + &qedf->global_queues[i]->cq_pbl_dma, + GFP_KERNEL); if (!qedf->global_queues[i]->cq_pbl) { QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate cq PBL.\n"); diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 5c53409a8cea..e74a62448ba4 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1394,10 +1394,9 @@ static int qedi_alloc_nvm_iscsi_cfg(struct qedi_ctx *qedi) { struct qedi_nvm_iscsi_image nvm_image; - qedi->iscsi_image = dma_zalloc_coherent(&qedi->pdev->dev, - sizeof(nvm_image), - &qedi->nvm_buf_dma, - GFP_KERNEL); + qedi->iscsi_image = dma_alloc_coherent(&qedi->pdev->dev, + sizeof(nvm_image), + &qedi->nvm_buf_dma, GFP_KERNEL); if (!qedi->iscsi_image) { QEDI_ERR(&qedi->dbg_ctx, "Could not allocate NVM BUF.\n"); return -ENOMEM; @@ -1510,10 +1509,10 @@ static int qedi_alloc_bdq(struct qedi_ctx *qedi) } /* Allocate list of PBL pages */ - qedi->bdq_pbl_list = dma_zalloc_coherent(&qedi->pdev->dev, - QEDI_PAGE_SIZE, - &qedi->bdq_pbl_list_dma, - GFP_KERNEL); + qedi->bdq_pbl_list = dma_alloc_coherent(&qedi->pdev->dev, + QEDI_PAGE_SIZE, + &qedi->bdq_pbl_list_dma, + GFP_KERNEL); if (!qedi->bdq_pbl_list) { QEDI_ERR(&qedi->dbg_ctx, "Could not allocate list of PBL pages.\n"); @@ -1609,10 +1608,10 @@ static int qedi_alloc_global_queues(struct qedi_ctx *qedi) (qedi->global_queues[i]->cq_pbl_size + (QEDI_PAGE_SIZE - 1)); - qedi->global_queues[i]->cq = dma_zalloc_coherent(&qedi->pdev->dev, - qedi->global_queues[i]->cq_mem_size, - &qedi->global_queues[i]->cq_dma, - GFP_KERNEL); + qedi->global_queues[i]->cq = dma_alloc_coherent(&qedi->pdev->dev, + qedi->global_queues[i]->cq_mem_size, + &qedi->global_queues[i]->cq_dma, + GFP_KERNEL); if (!qedi->global_queues[i]->cq) { QEDI_WARN(&qedi->dbg_ctx, @@ -1620,10 +1619,10 @@ static int qedi_alloc_global_queues(struct qedi_ctx *qedi) status = -ENOMEM; goto mem_alloc_failure; } - qedi->global_queues[i]->cq_pbl = dma_zalloc_coherent(&qedi->pdev->dev, - qedi->global_queues[i]->cq_pbl_size, - &qedi->global_queues[i]->cq_pbl_dma, - GFP_KERNEL); + qedi->global_queues[i]->cq_pbl = dma_alloc_coherent(&qedi->pdev->dev, + qedi->global_queues[i]->cq_pbl_size, + &qedi->global_queues[i]->cq_pbl_dma, + GFP_KERNEL); if (!qedi->global_queues[i]->cq_pbl) { QEDI_WARN(&qedi->dbg_ctx, @@ -1691,16 +1690,16 @@ int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep) ep->sq_pbl_size = (ep->sq_mem_size / QEDI_PAGE_SIZE) * sizeof(void *); ep->sq_pbl_size = ep->sq_pbl_size + QEDI_PAGE_SIZE; - ep->sq = dma_zalloc_coherent(&qedi->pdev->dev, ep->sq_mem_size, - &ep->sq_dma, GFP_KERNEL); + ep->sq = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_mem_size, + &ep->sq_dma, GFP_KERNEL); if (!ep->sq) { QEDI_WARN(&qedi->dbg_ctx, "Could not allocate send queue.\n"); rval = -ENOMEM; goto out; } - ep->sq_pbl = dma_zalloc_coherent(&qedi->pdev->dev, ep->sq_pbl_size, - &ep->sq_pbl_dma, GFP_KERNEL); + ep->sq_pbl = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_pbl_size, + &ep->sq_pbl_dma, GFP_KERNEL); if (!ep->sq_pbl) { QEDI_WARN(&qedi->dbg_ctx, "Could not allocate send queue PBL.\n"); diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 00444dc79756..ac504a1ff0ff 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -2415,8 +2415,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) if (qla2x00_chip_is_down(vha)) goto done; - stats = dma_zalloc_coherent(&ha->pdev->dev, sizeof(*stats), - &stats_dma, GFP_KERNEL); + stats = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stats), &stats_dma, + GFP_KERNEL); if (!stats) { ql_log(ql_log_warn, vha, 0x707d, "Failed to allocate memory for stats.\n"); diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 4a9fd8d944d6..17d42658ad9a 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -2312,8 +2312,8 @@ qla2x00_get_priv_stats(struct bsg_job *bsg_job) if (!IS_FWI2_CAPABLE(ha)) return -EPERM; - stats = dma_zalloc_coherent(&ha->pdev->dev, sizeof(*stats), - &stats_dma, GFP_KERNEL); + stats = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stats), &stats_dma, + GFP_KERNEL); if (!stats) { ql_log(ql_log_warn, vha, 0x70e2, "Failed to allocate memory for stats.\n"); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 90cfa394f942..cbc3bc49d4d1 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -4147,9 +4147,10 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) return rval; } - sp->u.iocb_cmd.u.ctarg.req = dma_zalloc_coherent( - &vha->hw->pdev->dev, sizeof(struct ct_sns_pkt), - &sp->u.iocb_cmd.u.ctarg.req_dma, GFP_KERNEL); + sp->u.iocb_cmd.u.ctarg.req = dma_alloc_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + &sp->u.iocb_cmd.u.ctarg.req_dma, + GFP_KERNEL); sp->u.iocb_cmd.u.ctarg.req_allocated_size = sizeof(struct ct_sns_pkt); if (!sp->u.iocb_cmd.u.ctarg.req) { ql_log(ql_log_warn, vha, 0xffff, @@ -4165,9 +4166,10 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) ((vha->hw->max_fibre_devices - 1) * sizeof(struct ct_sns_gpn_ft_data)); - sp->u.iocb_cmd.u.ctarg.rsp = dma_zalloc_coherent( - &vha->hw->pdev->dev, rspsz, - &sp->u.iocb_cmd.u.ctarg.rsp_dma, GFP_KERNEL); + sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev, + rspsz, + &sp->u.iocb_cmd.u.ctarg.rsp_dma, + GFP_KERNEL); sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = sizeof(struct ct_sns_pkt); if (!sp->u.iocb_cmd.u.ctarg.rsp) { ql_log(ql_log_warn, vha, 0xffff, diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 364bb52ed2a6..aeeb0144bd55 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3099,8 +3099,8 @@ qla2x00_alloc_offload_mem(scsi_qla_host_t *vha) FCE_SIZE, ha->fce, ha->fce_dma); /* Allocate memory for Fibre Channel Event Buffer. */ - tc = dma_zalloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, - GFP_KERNEL); + tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, + GFP_KERNEL); if (!tc) { ql_log(ql_log_warn, vha, 0x00be, "Unable to allocate (%d KB) for FCE.\n", @@ -3131,8 +3131,8 @@ try_eft: EFT_SIZE, ha->eft, ha->eft_dma); /* Allocate memory for Extended Trace Buffer. */ - tc = dma_zalloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, - GFP_KERNEL); + tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, + GFP_KERNEL); if (!tc) { ql_log(ql_log_warn, vha, 0x00c1, "Unable to allocate (%d KB) for EFT.\n", diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 1ef74aa2d00a..2bf5e3e639e1 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -153,8 +153,8 @@ int qla4xxx_get_sys_info(struct scsi_qla_host *ha) dma_addr_t sys_info_dma; int status = QLA_ERROR; - sys_info = dma_zalloc_coherent(&ha->pdev->dev, sizeof(*sys_info), - &sys_info_dma, GFP_KERNEL); + sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info), + &sys_info_dma, GFP_KERNEL); if (sys_info == NULL) { DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", ha->host_no, __func__)); diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 5d56904687b9..dac9a7013208 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -625,9 +625,9 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) uint32_t mbox_sts[MBOX_REG_COUNT]; int status = QLA_ERROR; - init_fw_cb = dma_zalloc_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - &init_fw_cb_dma, GFP_KERNEL); + init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct addr_ctrl_blk), + &init_fw_cb_dma, GFP_KERNEL); if (init_fw_cb == NULL) { DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, __func__)); @@ -709,9 +709,9 @@ int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha) uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; - init_fw_cb = dma_zalloc_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - &init_fw_cb_dma, GFP_KERNEL); + init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct addr_ctrl_blk), + &init_fw_cb_dma, GFP_KERNEL); if (init_fw_cb == NULL) { printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, __func__); @@ -1340,9 +1340,9 @@ int qla4xxx_about_firmware(struct scsi_qla_host *ha) uint32_t mbox_sts[MBOX_REG_COUNT]; int status = QLA_ERROR; - about_fw = dma_zalloc_coherent(&ha->pdev->dev, - sizeof(struct about_fw_info), - &about_fw_dma, GFP_KERNEL); + about_fw = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct about_fw_info), + &about_fw_dma, GFP_KERNEL); if (!about_fw) { DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Unable to alloc memory " "for about_fw\n", __func__)); diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index d2b333d629be..5a31877c9d04 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -4052,8 +4052,8 @@ int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha) dma_addr_t sys_info_dma; int status = QLA_ERROR; - sys_info = dma_zalloc_coherent(&ha->pdev->dev, sizeof(*sys_info), - &sys_info_dma, GFP_KERNEL); + sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info), + &sys_info_dma, GFP_KERNEL); if (sys_info == NULL) { DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", ha->host_no, __func__)); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 949e186cc5d7..cfdfcda28072 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -2704,9 +2704,9 @@ qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len) uint32_t rem = len; struct nlattr *attr; - init_fw_cb = dma_zalloc_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - &init_fw_cb_dma, GFP_KERNEL); + init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, + sizeof(struct addr_ctrl_blk), + &init_fw_cb_dma, GFP_KERNEL); if (!init_fw_cb) { ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n", __func__); @@ -4206,8 +4206,8 @@ static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) sizeof(struct shadow_regs) + MEM_ALIGN_VALUE + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); - ha->queues = dma_zalloc_coherent(&ha->pdev->dev, ha->queues_len, - &ha->queues_dma, GFP_KERNEL); + ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, + &ha->queues_dma, GFP_KERNEL); if (ha->queues == NULL) { ql4_printk(KERN_WARNING, ha, "Memory Allocation failed - queues.\n"); diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index e2fa3f476227..7bde6c809442 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -3576,9 +3576,9 @@ static int pqi_alloc_operational_queues(struct pqi_ctrl_info *ctrl_info) alloc_length += PQI_EXTRA_SGL_MEMORY; ctrl_info->queue_memory_base = - dma_zalloc_coherent(&ctrl_info->pci_dev->dev, - alloc_length, - &ctrl_info->queue_memory_base_dma_handle, GFP_KERNEL); + dma_alloc_coherent(&ctrl_info->pci_dev->dev, alloc_length, + &ctrl_info->queue_memory_base_dma_handle, + GFP_KERNEL); if (!ctrl_info->queue_memory_base) return -ENOMEM; @@ -3715,10 +3715,9 @@ static int pqi_alloc_admin_queues(struct pqi_ctrl_info *ctrl_info) PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT; ctrl_info->admin_queue_memory_base = - dma_zalloc_coherent(&ctrl_info->pci_dev->dev, - alloc_length, - &ctrl_info->admin_queue_memory_base_dma_handle, - GFP_KERNEL); + dma_alloc_coherent(&ctrl_info->pci_dev->dev, alloc_length, + &ctrl_info->admin_queue_memory_base_dma_handle, + GFP_KERNEL); if (!ctrl_info->admin_queue_memory_base) return -ENOMEM; @@ -4602,9 +4601,10 @@ static void pqi_free_all_io_requests(struct pqi_ctrl_info *ctrl_info) static inline int pqi_alloc_error_buffer(struct pqi_ctrl_info *ctrl_info) { - ctrl_info->error_buffer = dma_zalloc_coherent(&ctrl_info->pci_dev->dev, - ctrl_info->error_buffer_length, - &ctrl_info->error_buffer_dma_handle, GFP_KERNEL); + ctrl_info->error_buffer = dma_alloc_coherent(&ctrl_info->pci_dev->dev, + ctrl_info->error_buffer_length, + &ctrl_info->error_buffer_dma_handle, + GFP_KERNEL); if (!ctrl_info->error_buffer) return -ENOMEM; @@ -7487,8 +7487,8 @@ static int pqi_ofa_alloc_mem(struct pqi_ctrl_info *ctrl_info, dma_addr_t dma_handle; ctrl_info->pqi_ofa_chunk_virt_addr[i] = - dma_zalloc_coherent(dev, chunk_size, &dma_handle, - GFP_KERNEL); + dma_alloc_coherent(dev, chunk_size, &dma_handle, + GFP_KERNEL); if (!ctrl_info->pqi_ofa_chunk_virt_addr[i]) break; @@ -7545,10 +7545,10 @@ static void pqi_ofa_setup_host_buffer(struct pqi_ctrl_info *ctrl_info, struct device *dev; dev = &ctrl_info->pci_dev->dev; - pqi_ofa_memory = dma_zalloc_coherent(dev, - PQI_OFA_MEMORY_DESCRIPTOR_LENGTH, - &ctrl_info->pqi_ofa_mem_dma_handle, - GFP_KERNEL); + pqi_ofa_memory = dma_alloc_coherent(dev, + PQI_OFA_MEMORY_DESCRIPTOR_LENGTH, + &ctrl_info->pqi_ofa_mem_dma_handle, + GFP_KERNEL); if (!pqi_ofa_memory) return; diff --git a/drivers/soc/fsl/qbman/dpaa_sys.c b/drivers/soc/fsl/qbman/dpaa_sys.c index 9436aa83ff1b..e6d48dccb8d5 100644 --- a/drivers/soc/fsl/qbman/dpaa_sys.c +++ b/drivers/soc/fsl/qbman/dpaa_sys.c @@ -62,7 +62,7 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr, return -ENODEV; } - if (!dma_zalloc_coherent(dev, *size, addr, 0)) { + if (!dma_alloc_coherent(dev, *size, addr, 0)) { dev_err(dev, "DMA Alloc memory failed\n"); return -ENODEV; } diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index d7e4e18ec3df..1ae9af5f17ec 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -466,9 +466,9 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi) int i; /* allocate coherent DMAable memory for hardware buffer descriptors. */ - sqi->bd = dma_zalloc_coherent(&sqi->master->dev, - sizeof(*bd) * PESQI_BD_COUNT, - &sqi->bd_dma, GFP_KERNEL); + sqi->bd = dma_alloc_coherent(&sqi->master->dev, + sizeof(*bd) * PESQI_BD_COUNT, + &sqi->bd_dma, GFP_KERNEL); if (!sqi->bd) { dev_err(&sqi->master->dev, "failed allocating dma buffer\n"); return -ENOMEM; diff --git a/drivers/staging/mt7621-eth/mtk_eth_soc.c b/drivers/staging/mt7621-eth/mtk_eth_soc.c index 21a76a8ccc26..6027b19f7bc2 100644 --- a/drivers/staging/mt7621-eth/mtk_eth_soc.c +++ b/drivers/staging/mt7621-eth/mtk_eth_soc.c @@ -1396,8 +1396,7 @@ static int mtk_qdma_tx_alloc_tx(struct mtk_eth *eth) if (!ring->tx_buf) goto no_tx_mem; - ring->tx_dma = dma_zalloc_coherent(eth->dev, - ring->tx_ring_size * sz, + ring->tx_dma = dma_alloc_coherent(eth->dev, ring->tx_ring_size * sz, &ring->tx_phys, GFP_ATOMIC | __GFP_ZERO); if (!ring->tx_dma) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c index 338b6e952515..dd4898861b83 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c @@ -407,10 +407,8 @@ create_pagelist(char __user *buf, size_t count, unsigned short type) /* Allocate enough storage to hold the page pointers and the page * list */ - pagelist = dma_zalloc_coherent(g_dev, - pagelist_size, - &dma_addr, - GFP_KERNEL); + pagelist = dma_alloc_coherent(g_dev, pagelist_size, &dma_addr, + GFP_KERNEL); vchiq_log_trace(vchiq_arm_log_level, "%s - %pK", __func__, pagelist); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 1ab0e8562d40..c9097e7367d8 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -440,12 +440,9 @@ static bool device_init_rings(struct vnt_private *priv) void *vir_pool; /*allocate all RD/TD rings a single pool*/ - vir_pool = dma_zalloc_coherent(&priv->pcid->dev, - priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) + - priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) + - priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) + - priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc), - &priv->pool_dma, GFP_ATOMIC); + vir_pool = dma_alloc_coherent(&priv->pcid->dev, + priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) + priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) + priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) + priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc), + &priv->pool_dma, GFP_ATOMIC); if (!vir_pool) { dev_err(&priv->pcid->dev, "allocate desc dma memory failed\n"); return false; @@ -459,13 +456,9 @@ static bool device_init_rings(struct vnt_private *priv) priv->rd1_pool_dma = priv->rd0_pool_dma + priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc); - priv->tx0_bufs = dma_zalloc_coherent(&priv->pcid->dev, - priv->opts.tx_descs[0] * PKT_BUF_SZ + - priv->opts.tx_descs[1] * PKT_BUF_SZ + - CB_BEACON_BUF_SIZE + - CB_MAX_BUF_SIZE, - &priv->tx_bufs_dma0, - GFP_ATOMIC); + priv->tx0_bufs = dma_alloc_coherent(&priv->pcid->dev, + priv->opts.tx_descs[0] * PKT_BUF_SZ + priv->opts.tx_descs[1] * PKT_BUF_SZ + CB_BEACON_BUF_SIZE + CB_MAX_BUF_SIZE, + &priv->tx_bufs_dma0, GFP_ATOMIC); if (!priv->tx0_bufs) { dev_err(&priv->pcid->dev, "allocate buf dma memory failed\n"); diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index 01b44e159623..ccbd1d34eb2a 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -172,8 +172,9 @@ static int scratchpad_setup(struct bdc *bdc) /* Refer to BDC spec, Table 4 for description of SPB */ sp_buff_size = 1 << (sp_buff_size + 5); dev_dbg(bdc->dev, "Allocating %d bytes for scratchpad\n", sp_buff_size); - bdc->scratchpad.buff = dma_zalloc_coherent(bdc->dev, sp_buff_size, - &bdc->scratchpad.sp_dma, GFP_KERNEL); + bdc->scratchpad.buff = dma_alloc_coherent(bdc->dev, sp_buff_size, + &bdc->scratchpad.sp_dma, + GFP_KERNEL); if (!bdc->scratchpad.buff) goto fail; @@ -202,11 +203,9 @@ static int setup_srr(struct bdc *bdc, int interrupter) bdc_writel(bdc->regs, BDC_SRRINT(0), BDC_SRR_RWS | BDC_SRR_RST); bdc->srr.dqp_index = 0; /* allocate the status report descriptors */ - bdc->srr.sr_bds = dma_zalloc_coherent( - bdc->dev, - NUM_SR_ENTRIES * sizeof(struct bdc_bd), - &bdc->srr.dma_addr, - GFP_KERNEL); + bdc->srr.sr_bds = dma_alloc_coherent(bdc->dev, + NUM_SR_ENTRIES * sizeof(struct bdc_bd), + &bdc->srr.dma_addr, GFP_KERNEL); if (!bdc->srr.sr_bds) return -ENOMEM; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 6218bfe54f52..98deb5f64268 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -596,9 +596,9 @@ static int uhci_start(struct usb_hcd *hcd) &uhci_debug_operations); #endif - uhci->frame = dma_zalloc_coherent(uhci_dev(uhci), - UHCI_NUMFRAMES * sizeof(*uhci->frame), - &uhci->frame_dma_handle, GFP_KERNEL); + uhci->frame = dma_alloc_coherent(uhci_dev(uhci), + UHCI_NUMFRAMES * sizeof(*uhci->frame), + &uhci->frame_dma_handle, GFP_KERNEL); if (!uhci->frame) { dev_err(uhci_dev(uhci), "unable to allocate consistent memory for frame list\n"); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 36a3eb8849f1..8067f178fa84 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1672,8 +1672,8 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma); for (i = 0; i < num_sp; i++) { dma_addr_t dma; - void *buf = dma_zalloc_coherent(dev, xhci->page_size, &dma, - flags); + void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma, + flags); if (!buf) goto fail_sp4; @@ -1799,8 +1799,8 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, struct xhci_erst_entry *entry; size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs; - erst->entries = dma_zalloc_coherent(xhci_to_hcd(xhci)->self.sysdev, - size, &erst->erst_dma_addr, flags); + erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, + size, &erst->erst_dma_addr, flags); if (!erst->entries) return -ENOMEM; diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c index a74096c53cb5..43f2a4816860 100644 --- a/drivers/video/fbdev/da8xx-fb.c +++ b/drivers/video/fbdev/da8xx-fb.c @@ -1446,9 +1446,9 @@ static int fb_probe(struct platform_device *device) da8xx_fb_fix.line_length - 1; /* allocate palette buffer */ - par->v_palette_base = dma_zalloc_coherent(NULL, PALETTE_SIZE, - &par->p_palette_base, - GFP_KERNEL | GFP_DMA); + par->v_palette_base = dma_alloc_coherent(NULL, PALETTE_SIZE, + &par->p_palette_base, + GFP_KERNEL | GFP_DMA); if (!par->v_palette_base) { dev_err(&device->dev, "GLCD: kmalloc for palette buffer failed\n"); diff --git a/include/linux/pci-dma-compat.h b/include/linux/pci-dma-compat.h index cb1adf0b78a9..249d4d7fbf18 100644 --- a/include/linux/pci-dma-compat.h +++ b/include/linux/pci-dma-compat.h @@ -24,7 +24,7 @@ static inline void * pci_zalloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { - return dma_zalloc_coherent(&hwdev->dev, size, dma_handle, GFP_ATOMIC); + return dma_alloc_coherent(&hwdev->dev, size, dma_handle, GFP_ATOMIC); } static inline void diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index c3f57a3fb1a5..40ebde2e1ab1 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -47,8 +47,8 @@ static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, /* We use the PCI APIs for now until the generic one gets fixed * enough or until we get some macio-specific versions */ - r->space = dma_zalloc_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, - r->size, &r->bus_addr, GFP_KERNEL); + r->space = dma_alloc_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, + r->size, &r->bus_addr, GFP_KERNEL); if (!r->space) return -ENOMEM; diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 7609eceba1a2..9e71d7cda999 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2541,8 +2541,8 @@ static int snd_dbri_create(struct snd_card *card, dbri->op = op; dbri->irq = irq; - dbri->dma = dma_zalloc_coherent(&op->dev, sizeof(struct dbri_dma), - &dbri->dma_dvma, GFP_KERNEL); + dbri->dma = dma_alloc_coherent(&op->dev, sizeof(struct dbri_dma), + &dbri->dma_dvma, GFP_KERNEL); if (!dbri->dma) return -ENOMEM; -- cgit v1.2.3-58-ga151 From 07a85fe14254e01bcf37f4d2e0a13f093378620b Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Wed, 19 Dec 2018 12:24:08 -0800 Subject: cross-tree: phase out dma_zalloc_coherent() on headers The last few stragglers coccinelle doesn't pick up are on driver specific header files. Phase those out as well as dma_alloc_coherent() zeroes out the memory as well now too. Suggested-by: Christoph Hellwig Signed-off-by: Luis Chamberlain Signed-off-by: Christoph Hellwig --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 2 +- drivers/net/ethernet/marvell/octeontx2/af/common.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 5cd3135dfe30..03d131f777bc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -2081,7 +2081,7 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, bool is_pf); #define BNX2X_ILT_ZALLOC(x, y, size) \ - x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL) + x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL) #define BNX2X_ILT_FREE(x, y, size) \ do { \ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 142bc11b9fbb..2462e7aa0c5d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -52,7 +52,7 @@ extern int bnx2x_num_queues; #define BNX2X_PCI_ALLOC(y, size) \ ({ \ - void *x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ + void *x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ if (x) \ DP(NETIF_MSG_HW, \ "BNX2X_PCI_ALLOC: Physical %Lx Virtual %p\n", \ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index ec50a21c5aaf..e332e82fc066 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -64,7 +64,7 @@ static inline int qmem_alloc(struct device *dev, struct qmem **q, qmem->entry_sz = entry_sz; qmem->alloc_sz = (qsize * entry_sz) + OTX2_ALIGN; - qmem->base = dma_zalloc_coherent(dev, qmem->alloc_sz, + qmem->base = dma_alloc_coherent(dev, qmem->alloc_sz, &qmem->iova, GFP_KERNEL); if (!qmem->base) return -ENOMEM; -- cgit v1.2.3-58-ga151 From dfd32cad146e3624970eee9329e99d2c6ef751b3 Mon Sep 17 00:00:00 2001 From: Luis Chamberlain Date: Wed, 19 Dec 2018 12:30:34 -0800 Subject: dma-mapping: remove dma_zalloc_coherent() dma_zalloc_coherent() is no longer needed as it has no users because dma_alloc_coherent() already zeroes out memory for us. The Coccinelle grammar rule that used to check for dma_alloc_coherent() + memset() is modified so that it just tells the user that the memset is not needed anymore. Suggested-by: Christoph Hellwig Signed-off-by: Luis Chamberlain Signed-off-by: Christoph Hellwig --- include/linux/dma-mapping.h | 9 --------- scripts/coccinelle/api/alloc/alloc_cast.cocci | 8 ++++---- scripts/coccinelle/api/alloc/zalloc-simple.cocci | 11 +---------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index cef2127e1d70..f6ded992c183 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -717,15 +717,6 @@ static inline unsigned long dma_max_pfn(struct device *dev) } #endif -/* - * Please always use dma_alloc_coherent instead as it already zeroes the memory! - */ -static inline void *dma_zalloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - return dma_alloc_coherent(dev, size, dma_handle, flag); -} - static inline int dma_get_cache_alignment(void) { #ifdef ARCH_DMA_MINALIGN diff --git a/scripts/coccinelle/api/alloc/alloc_cast.cocci b/scripts/coccinelle/api/alloc/alloc_cast.cocci index 408ee3879f9b..18fedf7c60ed 100644 --- a/scripts/coccinelle/api/alloc/alloc_cast.cocci +++ b/scripts/coccinelle/api/alloc/alloc_cast.cocci @@ -32,7 +32,7 @@ type T; (T *) \(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\| kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|vmalloc\|vzalloc\| - dma_alloc_coherent\|dma_zalloc_coherent\|devm_kmalloc\|devm_kzalloc\| + dma_alloc_coherent\|devm_kmalloc\|devm_kzalloc\| kvmalloc\|kvzalloc\|kvmalloc_node\|kvzalloc_node\|pci_alloc_consistent\| pci_zalloc_consistent\|kmem_alloc\|kmem_zalloc\|kmem_zone_alloc\| kmem_zone_zalloc\|vmalloc_node\|vzalloc_node\)(...) @@ -55,7 +55,7 @@ type r1.T; * (T *) \(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\| kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|vmalloc\|vzalloc\| - dma_alloc_coherent\|dma_zalloc_coherent\|devm_kmalloc\|devm_kzalloc\| + dma_alloc_coherent\|devm_kmalloc\|devm_kzalloc\| kvmalloc\|kvzalloc\|kvmalloc_node\|kvzalloc_node\|pci_alloc_consistent\| pci_zalloc_consistent\|kmem_alloc\|kmem_zalloc\|kmem_zone_alloc\| kmem_zone_zalloc\|vmalloc_node\|vzalloc_node\)(...) @@ -78,7 +78,7 @@ type r1.T; - (T *) \(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\| kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|vmalloc\|vzalloc\| - dma_alloc_coherent\|dma_zalloc_coherent\|devm_kmalloc\|devm_kzalloc\| + dma_alloc_coherent\|devm_kmalloc\|devm_kzalloc\| kvmalloc\|kvzalloc\|kvmalloc_node\|kvzalloc_node\|pci_alloc_consistent\| pci_zalloc_consistent\|kmem_alloc\|kmem_zalloc\|kmem_zone_alloc\| kmem_zone_zalloc\|vmalloc_node\|vzalloc_node\)(...) @@ -95,7 +95,7 @@ position p; (T@p *) \(kmalloc\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\| kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|vmalloc\|vzalloc\| - dma_alloc_coherent\|dma_zalloc_coherent\|devm_kmalloc\|devm_kzalloc\| + dma_alloc_coherent\|devm_kmalloc\|devm_kzalloc\| kvmalloc\|kvzalloc\|kvmalloc_node\|kvzalloc_node\|pci_alloc_consistent\| pci_zalloc_consistent\|kmem_alloc\|kmem_zalloc\|kmem_zone_alloc\| kmem_zone_zalloc\|vmalloc_node\|vzalloc_node\)(...) diff --git a/scripts/coccinelle/api/alloc/zalloc-simple.cocci b/scripts/coccinelle/api/alloc/zalloc-simple.cocci index d819275b7fde..5cd1991c582e 100644 --- a/scripts/coccinelle/api/alloc/zalloc-simple.cocci +++ b/scripts/coccinelle/api/alloc/zalloc-simple.cocci @@ -69,15 +69,6 @@ statement S; - x = (T)vmalloc(E1); + x = (T)vzalloc(E1); | -- x = dma_alloc_coherent(E2,E1,E3,E4); -+ x = dma_zalloc_coherent(E2,E1,E3,E4); -| -- x = (T *)dma_alloc_coherent(E2,E1,E3,E4); -+ x = dma_zalloc_coherent(E2,E1,E3,E4); -| -- x = (T)dma_alloc_coherent(E2,E1,E3,E4); -+ x = (T)dma_zalloc_coherent(E2,E1,E3,E4); -| - x = kmalloc_node(E1,E2,E3); + x = kzalloc_node(E1,E2,E3); | @@ -225,7 +216,7 @@ p << r2.p; x << r2.x; @@ -msg="WARNING: dma_zalloc_coherent should be used for %s, instead of dma_alloc_coherent/memset" % (x) +msg="WARNING: dma_alloc_coherent use in %s already zeroes out memory, so memset is not needed" % (x) coccilib.report.print_report(p[0], msg) //----------------------------------------------------------------- -- cgit v1.2.3-58-ga151 From 7b57085a33ce55e28616f04fd9877ba2ca7e79de Mon Sep 17 00:00:00 2001 From: "Agrawal, Akshu" Date: Tue, 8 Jan 2019 10:24:40 +0000 Subject: ASoC: ADAU7002: Add optional delay before start of capture On capture through some of dmic we observe a glitch at the start of record. This is because we start capturing even before dmic is ready to send out data. The optional delay will be applied after enabling the mic. Signed-off-by: Akshu Agrawal Signed-off-by: Mark Brown --- sound/soc/codecs/adau7002.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c index fdff86878287..a8deb37fc78a 100644 --- a/sound/soc/codecs/adau7002.c +++ b/sound/soc/codecs/adau7002.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -15,12 +16,55 @@ #include +struct adau7002_priv { + int wakeup_delay; +}; + +static int adau7002_aif_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct adau7002_priv *adau7002 = + snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (adau7002->wakeup_delay) + msleep(adau7002->wakeup_delay); + break; + } + + return 0; +} + +static int adau7002_component_probe(struct snd_soc_component *component) +{ + struct adau7002_priv *adau7002; + + adau7002 = devm_kzalloc(component->dev, sizeof(*adau7002), + GFP_KERNEL); + if (!adau7002) + return -ENOMEM; + + device_property_read_u32(component->dev, "wakeup-delay-ms", + &adau7002->wakeup_delay); + + snd_soc_component_set_drvdata(component, adau7002); + + return 0; +} + static const struct snd_soc_dapm_widget adau7002_widgets[] = { + SND_SOC_DAPM_AIF_OUT_E("ADAU AIF", "Capture", 0, + SND_SOC_NOPM, 0, 0, adau7002_aif_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_INPUT("PDM_DAT"), SND_SOC_DAPM_REGULATOR_SUPPLY("IOVDD", 0, 0), }; static const struct snd_soc_dapm_route adau7002_routes[] = { + { "ADAU AIF", NULL, "PDM_DAT"}, { "Capture", NULL, "PDM_DAT" }, { "Capture", NULL, "IOVDD" }, }; @@ -40,6 +84,7 @@ static struct snd_soc_dai_driver adau7002_dai = { }; static const struct snd_soc_component_driver adau7002_component_driver = { + .probe = adau7002_component_probe, .dapm_widgets = adau7002_widgets, .num_dapm_widgets = ARRAY_SIZE(adau7002_widgets), .dapm_routes = adau7002_routes, -- cgit v1.2.3-58-ga151 From 4a8191aa9e057ea38279ef9e809265ba3966be40 Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Mon, 7 Jan 2019 12:12:32 -0800 Subject: ASoC: rt274: Variable "buf" in function rt274_jack_detect() could be uninitialized In function rt274_jack_detect(), local variable "buf" could be uninitialized if function regmap_read() returns -EINVAL. However, it will be used to calculate "hp" and "mic" and make their value unpredictable while those value are used in the caller. This is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: Mark Brown --- sound/soc/codecs/rt274.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 9e88f7b25d38..adf59039a3b6 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -353,6 +353,7 @@ static void rt274_index_sync(struct snd_soc_component *component) static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic) { unsigned int buf; + int ret; *hp = false; *mic = false; @@ -360,9 +361,15 @@ static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic) if (!rt274->component) return -EINVAL; - regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf); + ret = regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf); + if (ret) + return ret; + *hp = buf & 0x80000000; - regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf); + ret = regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf); + if (ret) + return ret; + *mic = buf & 0x80000000; pr_debug("*hp = %d *mic = %d\n", *hp, *mic); -- cgit v1.2.3-58-ga151 From 735df0ff6ece7b8759a744158f5d246fae4739f4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 21 Dec 2018 08:54:40 +0100 Subject: Documentation: driver core: remove use of BUS_ATTR We are getting rid of the "raw" BUS_ATTR() macro, so fix up the documentation to not refer to it anymore. Cc: "Rafael J. Wysocki" Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-model/bus.txt | 8 ++++---- Documentation/filesystems/sysfs.txt | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt index b577a45b93ea..c247b488a567 100644 --- a/Documentation/driver-model/bus.txt +++ b/Documentation/driver-model/bus.txt @@ -124,11 +124,11 @@ struct bus_attribute { ssize_t (*store)(struct bus_type *, const char * buf, size_t count); }; -Bus drivers can export attributes using the BUS_ATTR macro that works -similarly to the DEVICE_ATTR macro for devices. For example, a definition -like this: +Bus drivers can export attributes using the BUS_ATTR_RW macro that works +similarly to the DEVICE_ATTR_RW macro for devices. For example, a +definition like this: -static BUS_ATTR(debug,0644,show_debug,store_debug); +static BUS_ATTR_RW(debug); is equivalent to declaring: diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt index a1426cabcef1..41411b0c60a3 100644 --- a/Documentation/filesystems/sysfs.txt +++ b/Documentation/filesystems/sysfs.txt @@ -344,7 +344,9 @@ struct bus_attribute { Declaring: -BUS_ATTR(_name, _mode, _show, _store) +static BUS_ATTR_RW(name); +static BUS_ATTR_RO(name); +static BUS_ATTR_WO(name); Creation/Removal: -- cgit v1.2.3-58-ga151 From a3869d43c9800cf39496615361c83635fa3e7c82 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Mon, 7 Jan 2019 17:22:23 +0000 Subject: PCI: amlogic: Fix build failure due to missing gpio header Building the driver when GPIOLIB=n is not selected is causing the following compilation failure: drivers/pci/controller/dwc/pci-meson.c: In function 'meson_pcie_assert_reset': drivers/pci/controller/dwc/pci-meson.c:290:2: error: implicit declaration of function 'gpiod_set_value_cansleep'; did you mean 'gpio_set_value_cansleep'? [-Werror=implicit-function-declaration] gpiod_set_value_cansleep(mp->reset_gpio, 0); ^~~~~~~~~~~~~~~~~~~~~~~~ gpio_set_value_cansleep drivers/pci/controller/dwc/pci-meson.c: In function 'meson_pcie_probe': drivers/pci/controller/dwc/pci-meson.c:540:19: error: implicit declaration of function 'devm_gpiod_get'; did you mean 'devm_gpio_free'? [-Werror=implicit-function-declaration] mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); ^~~~~~~~~~~~~~ devm_gpio_free drivers/pci/controller/dwc/pci-meson.c:540:48: error: 'GPIOD_OUT_LOW' undeclared (first use in this function); did you mean 'GPIOF_INIT_LOW'? mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); ^~~~~~~~~~~~~ GPIOF_INIT_LOW Add the missing linux/gpio/consumer.h header to fix it. Fixes: 9c0ef6d34fdb ("PCI: amlogic: Add the Amlogic Meson PCIe controller driver") Signed-off-by: Corentin Labbe [lorenzo.pieralisi@arm.com: commit log] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas --- drivers/pci/controller/dwc/pci-meson.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 241ebe0c4505..e35e9eaa50ee 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3-58-ga151 From 3fdd94acd50d607cf6a971455307e711fd8ee16e Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 6 Jan 2019 15:05:40 +0100 Subject: binderfs: remove wrong kern_mount() call The binderfs filesystem never needs to be mounted by the kernel itself. This is conceptually wrong and should never have been done in the first place. Fixes: 3ad20fe393b ("binder: implement binderfs") Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 7496b10532aa..6f68d6217eb3 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -40,8 +40,6 @@ #define INTSTRLEN 21 #define BINDERFS_MAX_MINOR (1U << MINORBITS) -static struct vfsmount *binderfs_mnt; - static dev_t binderfs_dev; static DEFINE_MUTEX(binderfs_minors_mutex); static DEFINE_IDA(binderfs_minors); @@ -530,14 +528,6 @@ static int __init init_binderfs(void) return ret; } - binderfs_mnt = kern_mount(&binder_fs_type); - if (IS_ERR(binderfs_mnt)) { - ret = PTR_ERR(binderfs_mnt); - binderfs_mnt = NULL; - unregister_filesystem(&binder_fs_type); - unregister_chrdev_region(binderfs_dev, BINDERFS_MAX_MINOR); - } - return ret; } -- cgit v1.2.3-58-ga151 From b6c770d7c9dc7185b17d53a9d5ca1278c182d6fa Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 6 Jan 2019 15:05:41 +0100 Subject: binderfs: make each binderfs mount a new instance When currently mounting binderfs in the same ipc namespace twice: mount -t binder binder /A mount -t binder binder /B then the binderfs instances mounted on /A and /B will be the same, i.e. they will have the same superblock. This was the first approach that seemed reasonable. However, this leads to some problems and inconsistencies: /* private binderfs instance in same ipc namespace */ There is no way for a user to request a private binderfs instance in the same ipc namespace. This request has been made in a private mail to me by two independent people. /* bind-mounts */ If users want the same binderfs instance to appear in multiple places they can use bind mounts. So there is no value in having a request for a new binderfs mount giving them the same instance. /* unexpected behavior */ It's surprising that request to mount binderfs is not giving the user a new instance like tmpfs, devpts, ramfs, and others do. /* past mistakes */ Other pseudo-filesystems once made the same mistakes of giving back the same superblock when actually requesting a new mount (cf. devpts's deprecated "newinstance" option). We should not make the same mistake. Once we've committed to always giving back the same superblock in the same IPC namespace with the next kernel release we will not be able to make that change so better to do it now. /* kdbusfs */ It was pointed out to me that kdbusfs - which is conceptually closely related to binderfs - also allowed users to get a private kdbusfs instance in the same IPC namespace by making each mount of kdbusfs a separate instance. I think that makes a lot of sense. Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 41 ++--------------------------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 6f68d6217eb3..4990d65d4850 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -379,7 +379,7 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) struct binderfs_info *info; int ret = -ENOMEM; struct inode *inode = NULL; - struct ipc_namespace *ipc_ns = sb->s_fs_info; + struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; get_ipc_ns(ipc_ns); @@ -450,48 +450,11 @@ err_without_dentry: return ret; } -static int binderfs_test_super(struct super_block *sb, void *data) -{ - struct binderfs_info *info = sb->s_fs_info; - - if (info) - return info->ipc_ns == data; - - return 0; -} - -static int binderfs_set_super(struct super_block *sb, void *data) -{ - sb->s_fs_info = data; - return set_anon_super(sb, NULL); -} - static struct dentry *binderfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - struct super_block *sb; - struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; - - if (!ns_capable(ipc_ns->user_ns, CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); - - sb = sget_userns(fs_type, binderfs_test_super, binderfs_set_super, - flags, ipc_ns->user_ns, ipc_ns); - if (IS_ERR(sb)) - return ERR_CAST(sb); - - if (!sb->s_root) { - int ret = binderfs_fill_super(sb, data, flags & SB_SILENT ? 1 : 0); - if (ret) { - deactivate_locked_super(sb); - return ERR_PTR(ret); - } - - sb->s_flags |= SB_ACTIVE; - } - - return dget(sb->s_root); + return mount_nodev(fs_type, flags, data, binderfs_fill_super); } static void binderfs_kill_super(struct super_block *sb) -- cgit v1.2.3-58-ga151 From 96354ad79e2e59f9d620669c8e1ac2452440c260 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 8 Jan 2019 20:17:49 +0800 Subject: csky: fixup CACHEV1 store instruction fast retire For I/O access, 810/807 store instruction fast retire will cause wrong primitive. For example: stw (clear interrupt source) stw (unmask interrupt controller) enable interrupt stw is fast retire instruction. When PC is run at enable interrupt stage, the clear interrupt source hasn't finished. It will cause another wrong irq-enter. So use mb() to prevent above. Signed-off-by: Guo Ren Cc: Lu Baoquan --- arch/csky/include/asm/io.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/csky/include/asm/io.h b/arch/csky/include/asm/io.h index ecae6b358f95..c1dfa9c10e36 100644 --- a/arch/csky/include/asm/io.h +++ b/arch/csky/include/asm/io.h @@ -15,6 +15,31 @@ extern void iounmap(void *addr); extern int remap_area_pages(unsigned long address, phys_addr_t phys_addr, size_t size, unsigned long flags); +/* + * I/O memory access primitives. Reads are ordered relative to any + * following Normal memory access. Writes are ordered relative to any prior + * Normal memory access. + * + * For CACHEV1 (807, 810), store instruction could fast retire, so we need + * another mb() to prevent st fast retire. + * + * For CACHEV2 (860), store instruction with PAGE_ATTR_NO_BUFFERABLE won't + * fast retire. + */ +#define readb(c) ({ u8 __v = readb_relaxed(c); rmb(); __v; }) +#define readw(c) ({ u16 __v = readw_relaxed(c); rmb(); __v; }) +#define readl(c) ({ u32 __v = readl_relaxed(c); rmb(); __v; }) + +#ifdef CONFIG_CPU_HAS_CACHEV2 +#define writeb(v,c) ({ wmb(); writeb_relaxed((v),(c)); }) +#define writew(v,c) ({ wmb(); writew_relaxed((v),(c)); }) +#define writel(v,c) ({ wmb(); writel_relaxed((v),(c)); }) +#else +#define writeb(v,c) ({ wmb(); writeb_relaxed((v),(c)); mb(); }) +#define writew(v,c) ({ wmb(); writew_relaxed((v),(c)); mb(); }) +#define writel(v,c) ({ wmb(); writel_relaxed((v),(c)); mb(); }) +#endif + #define ioremap_nocache(phy, sz) ioremap(phy, sz) #define ioremap_wc ioremap_nocache #define ioremap_wt ioremap_nocache -- cgit v1.2.3-58-ga151 From b9fcb0e6b7052b7e2d18fed1d673f8247060c32c Mon Sep 17 00:00:00 2001 From: David Brown Date: Mon, 7 Jan 2019 12:15:03 -0700 Subject: usb: storage: Remove outdated URL from MAINTAINERS This website hasn't worked for quite some time. Signed-off-by: David Brown Cc: Matt Dharm Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 32d444476a90..8ab7948133bd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15802,7 +15802,6 @@ M: Alan Stern L: linux-usb@vger.kernel.org L: usb-storage@lists.one-eyed-alien.net S: Maintained -W: http://www.one-eyed-alien.net/~mdharm/linux-usb/ F: drivers/usb/storage/ USB MIDI DRIVER -- cgit v1.2.3-58-ga151 From d3a28a53630e1ca10f59562ef560e3f70785cb09 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 6 Jan 2019 19:50:37 +0100 Subject: serial: lantiq: Do not swap register read/writes The ltq_r32() and ltq_w32() macros use the __raw_readl() and __raw_writel() functions which do not swap the value to little endian. On the big endian vrx200 SoC the UART is operated in big endian IO mode, the readl() and write() functions convert the value to little endian first and then the driver does not work any more on this SoC. Currently the vrx200 SoC selects the CONFIG_SWAP_IO_SPACE option, without this option the serial driver would work, but PCI devices do not work any more. This patch makes the driver use the __raw_readl() and __raw_writel() functions which do not swap the endianness. On big endian system it is assumed that the device should be access in big endian IO mode and on a little endian system it would be access in little endian mode. Fixes: 89b8bd2082bb ("serial: lantiq: Use readl/writel instead of ltq_r32/ltq_w32") Signed-off-by: Hauke Mehrtens Acked-by: John Crispin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/lantiq.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index e052b69ceb98..9de9f0f239a1 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -114,9 +114,9 @@ struct ltq_uart_port { static inline void asc_update_bits(u32 clear, u32 set, void __iomem *reg) { - u32 tmp = readl(reg); + u32 tmp = __raw_readl(reg); - writel((tmp & ~clear) | set, reg); + __raw_writel((tmp & ~clear) | set, reg); } static inline struct @@ -144,7 +144,7 @@ lqasc_start_tx(struct uart_port *port) static void lqasc_stop_rx(struct uart_port *port) { - writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE); + __raw_writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE); } static int @@ -153,11 +153,12 @@ lqasc_rx_chars(struct uart_port *port) struct tty_port *tport = &port->state->port; unsigned int ch = 0, rsr = 0, fifocnt; - fifocnt = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK; + fifocnt = __raw_readl(port->membase + LTQ_ASC_FSTAT) & + ASCFSTAT_RXFFLMASK; while (fifocnt--) { u8 flag = TTY_NORMAL; ch = readb(port->membase + LTQ_ASC_RBUF); - rsr = (readl(port->membase + LTQ_ASC_STATE) + rsr = (__raw_readl(port->membase + LTQ_ASC_STATE) & ASCSTATE_ANY) | UART_DUMMY_UER_RX; tty_flip_buffer_push(tport); port->icount.rx++; @@ -217,7 +218,7 @@ lqasc_tx_chars(struct uart_port *port) return; } - while (((readl(port->membase + LTQ_ASC_FSTAT) & + while (((__raw_readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) { if (port->x_char) { writeb(port->x_char, port->membase + LTQ_ASC_TBUF); @@ -245,7 +246,7 @@ lqasc_tx_int(int irq, void *_port) unsigned long flags; struct uart_port *port = (struct uart_port *)_port; spin_lock_irqsave(<q_asc_lock, flags); - writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); + __raw_writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); spin_unlock_irqrestore(<q_asc_lock, flags); lqasc_start_tx(port); return IRQ_HANDLED; @@ -270,7 +271,7 @@ lqasc_rx_int(int irq, void *_port) unsigned long flags; struct uart_port *port = (struct uart_port *)_port; spin_lock_irqsave(<q_asc_lock, flags); - writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR); + __raw_writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR); lqasc_rx_chars(port); spin_unlock_irqrestore(<q_asc_lock, flags); return IRQ_HANDLED; @@ -280,7 +281,8 @@ static unsigned int lqasc_tx_empty(struct uart_port *port) { int status; - status = readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK; + status = __raw_readl(port->membase + LTQ_ASC_FSTAT) & + ASCFSTAT_TXFFLMASK; return status ? 0 : TIOCSER_TEMT; } @@ -313,12 +315,12 @@ lqasc_startup(struct uart_port *port) asc_update_bits(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), port->membase + LTQ_ASC_CLC); - writel(0, port->membase + LTQ_ASC_PISEL); - writel( + __raw_writel(0, port->membase + LTQ_ASC_PISEL); + __raw_writel( ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, port->membase + LTQ_ASC_TXFCON); - writel( + __raw_writel( ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, port->membase + LTQ_ASC_RXFCON); @@ -350,7 +352,7 @@ lqasc_startup(struct uart_port *port) goto err2; } - writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, + __raw_writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, port->membase + LTQ_ASC_IRNREN); return 0; @@ -369,7 +371,7 @@ lqasc_shutdown(struct uart_port *port) free_irq(ltq_port->rx_irq, port); free_irq(ltq_port->err_irq, port); - writel(0, port->membase + LTQ_ASC_CON); + __raw_writel(0, port->membase + LTQ_ASC_CON); asc_update_bits(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU, port->membase + LTQ_ASC_RXFCON); asc_update_bits(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, @@ -461,13 +463,13 @@ lqasc_set_termios(struct uart_port *port, asc_update_bits(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON); /* now we can write the new baudrate into the register */ - writel(divisor, port->membase + LTQ_ASC_BG); + __raw_writel(divisor, port->membase + LTQ_ASC_BG); /* turn the baudrate generator back on */ asc_update_bits(0, ASCCON_R, port->membase + LTQ_ASC_CON); /* enable rx */ - writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE); + __raw_writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE); spin_unlock_irqrestore(<q_asc_lock, flags); @@ -578,7 +580,7 @@ lqasc_console_putchar(struct uart_port *port, int ch) return; do { - fifofree = (readl(port->membase + LTQ_ASC_FSTAT) + fifofree = (__raw_readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF; } while (fifofree == 0); writeb(ch, port->membase + LTQ_ASC_TBUF); -- cgit v1.2.3-58-ga151 From d1fc1176c055c9ec9c6ec4d113a284e0bad9d09a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 8 Jan 2019 12:08:03 +0900 Subject: vfio/pci: set TRACE_INCLUDE_PATH to fix the build error drivers/vfio/pci/vfio_pci_nvlink2.c cannot be compiled for in-tree building. CC drivers/vfio/pci/vfio_pci_nvlink2.o In file included from drivers/vfio/pci/trace.h:102, from drivers/vfio/pci/vfio_pci_nvlink2.c:29: ./include/trace/define_trace.h:89:42: fatal error: ./trace.h: No such file or directory #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) ^ compilation terminated. make[1]: *** [scripts/Makefile.build;277: drivers/vfio/pci/vfio_pci_nvlink2.o] Error 1 To fix the build error, let's tell include/trace/define_trace.h the location of drivers/vfio/pci/trace.h Fixes: 7f92891778df ("vfio_pci: Add NVIDIA GV100GL [Tesla V100 SXM2] subdriver") Reported-by: Laura Abbott Signed-off-by: Masahiro Yamada Reviewed-by: Cornelia Huck Signed-off-by: Alex Williamson --- drivers/vfio/pci/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vfio/pci/trace.h b/drivers/vfio/pci/trace.h index 228ccdb8d1c8..4d13e510590e 100644 --- a/drivers/vfio/pci/trace.h +++ b/drivers/vfio/pci/trace.h @@ -94,7 +94,7 @@ TRACE_EVENT(vfio_pci_npu2_mmap, #endif /* _TRACE_VFIO_PCI_H */ #undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_PATH ../../drivers/vfio/pci #undef TRACE_INCLUDE_FILE #define TRACE_INCLUDE_FILE trace -- cgit v1.2.3-58-ga151 From 2a60aa14a9a0333b3eef58150bc1ef654f7321ef Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 8 Jan 2019 20:31:43 +0800 Subject: csky: fixup compile error with pte_alloc Commit: 4cf58924951e remove the address argument of pte_alloc without modify csky related code. linux-5.0-rc1 compile failed with csky. Remove the unnecessary address testing in pte_alloc(). Signed-off-by: Guo Ren Cc: Joel Fernandes (Google) Cc: Guenter Roeck Cc: Arnd Bergmann Cc: Linus Torvalds --- arch/csky/include/asm/pgalloc.h | 43 +++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/arch/csky/include/asm/pgalloc.h b/arch/csky/include/asm/pgalloc.h index bf4f4a0e140e..d213bb47b717 100644 --- a/arch/csky/include/asm/pgalloc.h +++ b/arch/csky/include/asm/pgalloc.h @@ -24,41 +24,34 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, extern void pgd_init(unsigned long *p); -static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, - unsigned long address) +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm) { pte_t *pte; - unsigned long *kaddr, i; + unsigned long i; - pte = (pte_t *) __get_free_pages(GFP_KERNEL | __GFP_RETRY_MAYFAIL, - PTE_ORDER); - kaddr = (unsigned long *)pte; - if (address & 0x80000000) - for (i = 0; i < (PAGE_SIZE/4); i++) - *(kaddr + i) = 0x1; - else - clear_page(kaddr); + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (!pte) + return NULL; + + for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) + (pte + i)->pte_low = _PAGE_GLOBAL; return pte; } -static inline struct page *pte_alloc_one(struct mm_struct *mm, - unsigned long address) +static inline struct page *pte_alloc_one(struct mm_struct *mm) { struct page *pte; - unsigned long *kaddr, i; - - pte = alloc_pages(GFP_KERNEL | __GFP_RETRY_MAYFAIL, PTE_ORDER); - if (pte) { - kaddr = kmap_atomic(pte); - if (address & 0x80000000) { - for (i = 0; i < (PAGE_SIZE/4); i++) - *(kaddr + i) = 0x1; - } else - clear_page(kaddr); - kunmap_atomic(kaddr); - pgtable_page_ctor(pte); + + pte = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0); + if (!pte) + return NULL; + + if (!pgtable_page_ctor(pte)) { + __free_page(pte); + return NULL; } + return pte; } -- cgit v1.2.3-58-ga151 From 56752b21755aef598709d143684cb363db98a7d2 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 8 Jan 2019 20:49:24 +0800 Subject: irqchip/csky: fixup handle_irq_perbit break irq The handle_irq_perbit function loop every bit in hwirq local variable. handle_irq_perbit(hwirq) { for_everyt_bit_in(hwirq) { handle_domain_irq() ->irq_exit() ->invoke_softirq() ->__do_softirq() ->local_irq_enable() // Here will cause new interrupt. } } When new interrupt coming at local_irq_enable, it will finish another interrupt handler and pull down the interrupt source. But hwirq is the local variable for handle_irq_perbit(), it can't get new interrupt controller pending reg status. So we need update hwirq with pending reg in every loop. Also change write_relax to writel could prevent stw from fast retire. When local_irq is enabled, intc regs is really set-in. Signed-off-by: Guo Ren Cc: Lu Baoquan --- drivers/irqchip/irq-csky-apb-intc.c | 77 ++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/drivers/irqchip/irq-csky-apb-intc.c b/drivers/irqchip/irq-csky-apb-intc.c index 2543baba8b1f..5a2ec43b7ddd 100644 --- a/drivers/irqchip/irq-csky-apb-intc.c +++ b/drivers/irqchip/irq-csky-apb-intc.c @@ -95,7 +95,7 @@ static inline void setup_irq_channel(u32 magic, void __iomem *reg_addr) /* Setup 64 channel slots */ for (i = 0; i < INTC_IRQS; i += 4) - writel_relaxed(build_channel_val(i, magic), reg_addr + i); + writel(build_channel_val(i, magic), reg_addr + i); } static int __init @@ -135,16 +135,10 @@ ck_intc_init_comm(struct device_node *node, struct device_node *parent) static inline bool handle_irq_perbit(struct pt_regs *regs, u32 hwirq, u32 irq_base) { - u32 irq; - if (hwirq == 0) return 0; - while (hwirq) { - irq = __ffs(hwirq); - hwirq &= ~BIT(irq); - handle_domain_irq(root_domain, irq_base + irq, regs); - } + handle_domain_irq(root_domain, irq_base + __fls(hwirq), regs); return 1; } @@ -154,12 +148,16 @@ static void gx_irq_handler(struct pt_regs *regs) { bool ret; - do { - ret = handle_irq_perbit(regs, - readl_relaxed(reg_base + GX_INTC_PEN31_00), 0); - ret |= handle_irq_perbit(regs, - readl_relaxed(reg_base + GX_INTC_PEN63_32), 32); - } while (ret); +retry: + ret = handle_irq_perbit(regs, + readl(reg_base + GX_INTC_PEN63_32), 32); + if (ret) + goto retry; + + ret = handle_irq_perbit(regs, + readl(reg_base + GX_INTC_PEN31_00), 0); + if (ret) + goto retry; } static int __init @@ -174,14 +172,14 @@ gx_intc_init(struct device_node *node, struct device_node *parent) /* * Initial enable reg to disable all interrupts */ - writel_relaxed(0x0, reg_base + GX_INTC_NEN31_00); - writel_relaxed(0x0, reg_base + GX_INTC_NEN63_32); + writel(0x0, reg_base + GX_INTC_NEN31_00); + writel(0x0, reg_base + GX_INTC_NEN63_32); /* * Initial mask reg with all unmasked, because we only use enalbe reg */ - writel_relaxed(0x0, reg_base + GX_INTC_NMASK31_00); - writel_relaxed(0x0, reg_base + GX_INTC_NMASK63_32); + writel(0x0, reg_base + GX_INTC_NMASK31_00); + writel(0x0, reg_base + GX_INTC_NMASK63_32); setup_irq_channel(0x03020100, reg_base + GX_INTC_SOURCE); @@ -204,20 +202,29 @@ static void ck_irq_handler(struct pt_regs *regs) void __iomem *reg_pen_lo = reg_base + CK_INTC_PEN31_00; void __iomem *reg_pen_hi = reg_base + CK_INTC_PEN63_32; - do { - /* handle 0 - 31 irqs */ - ret = handle_irq_perbit(regs, readl_relaxed(reg_pen_lo), 0); - ret |= handle_irq_perbit(regs, readl_relaxed(reg_pen_hi), 32); +retry: + /* handle 0 - 63 irqs */ + ret = handle_irq_perbit(regs, readl(reg_pen_hi), 32); + if (ret) + goto retry; - if (nr_irq == INTC_IRQS) - continue; + ret = handle_irq_perbit(regs, readl(reg_pen_lo), 0); + if (ret) + goto retry; + + if (nr_irq == INTC_IRQS) + return; - /* handle 64 - 127 irqs */ - ret |= handle_irq_perbit(regs, - readl_relaxed(reg_pen_lo + CK_INTC_DUAL_BASE), 64); - ret |= handle_irq_perbit(regs, - readl_relaxed(reg_pen_hi + CK_INTC_DUAL_BASE), 96); - } while (ret); + /* handle 64 - 127 irqs */ + ret = handle_irq_perbit(regs, + readl(reg_pen_hi + CK_INTC_DUAL_BASE), 96); + if (ret) + goto retry; + + ret = handle_irq_perbit(regs, + readl(reg_pen_lo + CK_INTC_DUAL_BASE), 64); + if (ret) + goto retry; } static int __init @@ -230,11 +237,11 @@ ck_intc_init(struct device_node *node, struct device_node *parent) return ret; /* Initial enable reg to disable all interrupts */ - writel_relaxed(0, reg_base + CK_INTC_NEN31_00); - writel_relaxed(0, reg_base + CK_INTC_NEN63_32); + writel(0, reg_base + CK_INTC_NEN31_00); + writel(0, reg_base + CK_INTC_NEN63_32); /* Enable irq intc */ - writel_relaxed(BIT(31), reg_base + CK_INTC_ICR); + writel(BIT(31), reg_base + CK_INTC_ICR); ck_set_gc(node, reg_base, CK_INTC_NEN31_00, 0); ck_set_gc(node, reg_base, CK_INTC_NEN63_32, 32); @@ -260,8 +267,8 @@ ck_dual_intc_init(struct device_node *node, struct device_node *parent) return ret; /* Initial enable reg to disable all interrupts */ - writel_relaxed(0, reg_base + CK_INTC_NEN31_00 + CK_INTC_DUAL_BASE); - writel_relaxed(0, reg_base + CK_INTC_NEN63_32 + CK_INTC_DUAL_BASE); + writel(0, reg_base + CK_INTC_NEN31_00 + CK_INTC_DUAL_BASE); + writel(0, reg_base + CK_INTC_NEN63_32 + CK_INTC_DUAL_BASE); ck_set_gc(node, reg_base + CK_INTC_DUAL_BASE, CK_INTC_NEN31_00, 64); ck_set_gc(node, reg_base + CK_INTC_DUAL_BASE, CK_INTC_NEN63_32, 96); -- cgit v1.2.3-58-ga151 From 172bf02d564bdb6df8410f64720fa2c68e755d1a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 7 Jan 2019 16:24:27 -0300 Subject: perf trace: Fix ')' placement in "interrupted" syscall lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we get the sys_enter for a syscall we check if the last one is still waiting for its matching sys_exit, if so we print this: 468.753 ( ): firefox/32382 poll(ufds: 0x7f3988d3dd00, nfds: 7, timeout_msecs: 4294967295) ... 449.575 ( 0.004 ms): Softwar~cThrea/32434 futex(uaddr: 0x7f39a18a9b70, op: WAKE|PRIVATE_FLAG, val: 1) = 0 At some point we'll get that poll sys_exit event and will print a "[continued]" line. While making the sizing of the alignment after the syscall arg list and its result configurable, so that we can mimic strace, which uses a smaller alingment by default, a bug was introduced where the closing parens appeared before the syscall name and its arg list, fix it. Fixes: 4b8a240ed5e0 ("perf trace: Add alignment spaces after the closing parens") Cc: Adrian Hunter Cc: Jiri Olsa Cc: Luis Cláudio Gonçalves Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-oi45i54s59h1w1kmgpzrfuum@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index adbf28183560..b8bf5d025563 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1758,6 +1758,7 @@ static int trace__printf_interrupted_entry(struct trace *trace) { struct thread_trace *ttrace; size_t printed; + int len; if (trace->failure_only || trace->current == NULL) return 0; @@ -1768,9 +1769,14 @@ static int trace__printf_interrupted_entry(struct trace *trace) return 0; printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output); - printed += fprintf(trace->output, ")%-*s ...\n", trace->args_alignment, ttrace->entry_str); - ttrace->entry_pending = false; + printed += len = fprintf(trace->output, "%s)", ttrace->entry_str); + + if (len < trace->args_alignment - 4) + printed += fprintf(trace->output, "%-*s", trace->args_alignment - 4 - len, " "); + printed += fprintf(trace->output, " ...\n"); + + ttrace->entry_pending = false; ++trace->nr_events_printed; return printed; -- cgit v1.2.3-58-ga151 From ac6e022cbfdce215ad545e91d9827060855da3d7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 7 Jan 2019 16:54:38 -0300 Subject: perf trace: Fix alignment for [continued] lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were not taking into account the "... [continued]" printed characters, fix it. Cc: Adrian Hunter Cc: Jiri Olsa Cc: Luis Cláudio Gonçalves Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-qt20y0acmf8k0bzisce8kw95@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b8bf5d025563..ed4583128b9c 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2032,9 +2032,10 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, if (ttrace->entry_pending) { printed = fprintf(trace->output, "%s", ttrace->entry_str); } else { - fprintf(trace->output, " ... ["); + printed += fprintf(trace->output, " ... ["); color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued"); - fprintf(trace->output, "]: %s()", sc->name); + printed += 9; + printed += fprintf(trace->output, "]: %s()", sc->name); } printed++; /* the closing ')' */ -- cgit v1.2.3-58-ga151 From 011532379b7c2de6757e129037bdfc8d704bce23 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Dec 2018 19:43:36 -0800 Subject: perf tools: Make find_vdso_map() more modular In preparation for checking that the vectors page on the ARM architecture, refactor the find_vdso_map() function to accept finding an arbitrary string and create a dedicated helper function for that under util/find-map.c and update the filename to find-map.c and all references to it: perf-read-vdso.c and util/vdso.c. Signed-off-by: Florian Fainelli Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Chris Healy Cc: Greg Kroah-Hartman Cc: Kim Phillips Cc: Lucas Stach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Russell King Cc: Thomas Gleixner Cc: Thomas Richter Link: http://lkml.kernel.org/r/20181221034337.26663-2-f.fainelli@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 4 ++-- tools/perf/perf-read-vdso.c | 6 +++--- tools/perf/util/find-map.c | 30 ++++++++++++++++++++++++++++++ tools/perf/util/find-vdso-map.c | 31 ------------------------------- tools/perf/util/vdso.c | 6 +++--- 5 files changed, 38 insertions(+), 39 deletions(-) create mode 100644 tools/perf/util/find-map.c delete mode 100644 tools/perf/util/find-vdso-map.c diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 2921f829a0f4..0ee6795d82cc 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -662,12 +662,12 @@ $(OUTPUT)perf-%: %.o $(PERFLIBS) $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS) ifndef NO_PERF_READ_VDSO32 -$(OUTPUT)perf-read-vdso32: perf-read-vdso.c util/find-vdso-map.c +$(OUTPUT)perf-read-vdso32: perf-read-vdso.c util/find-map.c $(QUIET_CC)$(CC) -m32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c endif ifndef NO_PERF_READ_VDSOX32 -$(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c +$(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-map.c $(QUIET_CC)$(CC) -mx32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c endif diff --git a/tools/perf/perf-read-vdso.c b/tools/perf/perf-read-vdso.c index 8c0ca0cc428f..aaa5210ea84a 100644 --- a/tools/perf/perf-read-vdso.c +++ b/tools/perf/perf-read-vdso.c @@ -5,17 +5,17 @@ #define VDSO__MAP_NAME "[vdso]" /* - * Include definition of find_vdso_map() also used in util/vdso.c for + * Include definition of find_map() also used in util/vdso.c for * building perf. */ -#include "util/find-vdso-map.c" +#include "util/find-map.c" int main(void) { void *start, *end; size_t size, written; - if (find_vdso_map(&start, &end)) + if (find_map(&start, &end, VDSO__MAP_NAME)) return 1; size = end - start; diff --git a/tools/perf/util/find-map.c b/tools/perf/util/find-map.c new file mode 100644 index 000000000000..7b2300588ece --- /dev/null +++ b/tools/perf/util/find-map.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +static int find_map(void **start, void **end, const char *name) +{ + FILE *maps; + char line[128]; + int found = 0; + + maps = fopen("/proc/self/maps", "r"); + if (!maps) { + fprintf(stderr, "cannot open maps\n"); + return -1; + } + + while (!found && fgets(line, sizeof(line), maps)) { + int m = -1; + + /* We care only about private r-x mappings. */ + if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n", + start, end, &m)) + continue; + if (m < 0) + continue; + + if (!strncmp(&line[m], name, strlen(name))) + found = 1; + } + + fclose(maps); + return !found; +} diff --git a/tools/perf/util/find-vdso-map.c b/tools/perf/util/find-vdso-map.c deleted file mode 100644 index d7823e3508fc..000000000000 --- a/tools/perf/util/find-vdso-map.c +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -static int find_vdso_map(void **start, void **end) -{ - FILE *maps; - char line[128]; - int found = 0; - - maps = fopen("/proc/self/maps", "r"); - if (!maps) { - fprintf(stderr, "vdso: cannot open maps\n"); - return -1; - } - - while (!found && fgets(line, sizeof(line), maps)) { - int m = -1; - - /* We care only about private r-x mappings. */ - if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n", - start, end, &m)) - continue; - if (m < 0) - continue; - - if (!strncmp(&line[m], VDSO__MAP_NAME, - sizeof(VDSO__MAP_NAME) - 1)) - found = 1; - } - - fclose(maps); - return !found; -} diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 741af209b19d..3702cba11d7d 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -18,10 +18,10 @@ #include "debug.h" /* - * Include definition of find_vdso_map() also used in perf-read-vdso.c for + * Include definition of find_map() also used in perf-read-vdso.c for * building perf-read-vdso32 and perf-read-vdsox32. */ -#include "find-vdso-map.c" +#include "find-map.c" #define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX" @@ -76,7 +76,7 @@ static char *get_file(struct vdso_file *vdso_file) if (vdso_file->found) return vdso_file->temp_file_name; - if (vdso_file->error || find_vdso_map(&start, &end)) + if (vdso_file->error || find_map(&start, &end, VDSO__MAP_NAME)) return NULL; size = end - start; -- cgit v1.2.3-58-ga151 From 21327c7843e9169d5e2e527713e60e6c9842a56c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 20 Dec 2018 19:43:37 -0800 Subject: perf tests: Add a test for the ARM 32-bit [vectors] page perf on ARM requires CONFIG_KUSER_HELPERS to be turned on to allow some independance with respect to the ARM CPU being used. Add a test which tries to locate the [vectors] page, created when CONFIG_KUSER_HELPERS is turned on to help asses the system's health. Signed-off-by: Florian Fainelli Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Chris Healy Cc: Greg Kroah-Hartman Cc: Kim Phillips Cc: Lucas Stach Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ravi Bangoria Cc: Russell King Cc: Thomas Gleixner Cc: Thomas Richter Link: http://lkml.kernel.org/r/20181221034337.26663-3-f.fainelli@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/tests/Build | 1 + tools/perf/arch/arm/tests/arch-tests.c | 4 ++++ tools/perf/arch/arm/tests/vectors-page.c | 24 ++++++++++++++++++++++++ tools/perf/tests/tests.h | 5 +++++ 4 files changed, 34 insertions(+) create mode 100644 tools/perf/arch/arm/tests/vectors-page.c diff --git a/tools/perf/arch/arm/tests/Build b/tools/perf/arch/arm/tests/Build index 883c57ff0c08..d9ae2733f9cc 100644 --- a/tools/perf/arch/arm/tests/Build +++ b/tools/perf/arch/arm/tests/Build @@ -1,4 +1,5 @@ libperf-y += regs_load.o libperf-y += dwarf-unwind.o +libperf-y += vectors-page.o libperf-y += arch-tests.o diff --git a/tools/perf/arch/arm/tests/arch-tests.c b/tools/perf/arch/arm/tests/arch-tests.c index 5b1543c98022..6848101a855f 100644 --- a/tools/perf/arch/arm/tests/arch-tests.c +++ b/tools/perf/arch/arm/tests/arch-tests.c @@ -10,6 +10,10 @@ struct test arch_tests[] = { .func = test__dwarf_unwind, }, #endif + { + .desc = "Vectors page", + .func = test__vectors_page, + }, { .func = NULL, }, diff --git a/tools/perf/arch/arm/tests/vectors-page.c b/tools/perf/arch/arm/tests/vectors-page.c new file mode 100644 index 000000000000..7ffdd79971c8 --- /dev/null +++ b/tools/perf/arch/arm/tests/vectors-page.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +#include "debug.h" +#include "tests/tests.h" +#include "util/find-map.c" + +#define VECTORS__MAP_NAME "[vectors]" + +int test__vectors_page(struct test *test __maybe_unused, + int subtest __maybe_unused) +{ + void *start, *end; + + if (find_map(&start, &end, VECTORS__MAP_NAME)) { + pr_err("%s not found, is CONFIG_KUSER_HELPERS enabled?\n", + VECTORS__MAP_NAME); + return TEST_FAIL; + } + + return TEST_OK; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index b82f55fcc294..399f18ca71a3 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -119,4 +119,9 @@ int test__arch_unwind_sample(struct perf_sample *sample, struct thread *thread); #endif #endif + +#if defined(__arm__) +int test__vectors_page(struct test *test, int subtest); +#endif + #endif /* TESTS_H */ -- cgit v1.2.3-58-ga151 From ca3958b1c0968a6f3105e211355f128ce871e796 Mon Sep 17 00:00:00 2001 From: Tzvetomir Stoyanov Date: Fri, 30 Nov 2018 10:44:11 -0500 Subject: tools lib traceevent: Introduce new libtracevent API: tep_override_comm() This patch adds a new API of tracevent library: tep_override_comm() It registers a pid / command mapping. If a mapping with the same pid already exists, the entry is updated with the new command. Signed-off-by: Tzvetomir Stoyanov Cc: Andrew Morton Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20181130154648.038915912@goodmis.org Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.c | 69 +++++++++++++++++++++++++++++--------- tools/lib/traceevent/event-parse.h | 1 + 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 69a96e39f0ab..156e513074b2 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -232,11 +232,13 @@ int tep_pid_is_registered(struct tep_handle *pevent, int pid) * we must add this pid. This is much slower than when cmdlines * are added before the array is initialized. */ -static int add_new_comm(struct tep_handle *pevent, const char *comm, int pid) +static int add_new_comm(struct tep_handle *pevent, + const char *comm, int pid, bool override) { struct cmdline *cmdlines = pevent->cmdlines; - const struct cmdline *cmdline; + struct cmdline *cmdline; struct cmdline key; + char *new_comm; if (!pid) return 0; @@ -247,8 +249,19 @@ static int add_new_comm(struct tep_handle *pevent, const char *comm, int pid) cmdline = bsearch(&key, pevent->cmdlines, pevent->cmdline_count, sizeof(*pevent->cmdlines), cmdline_cmp); if (cmdline) { - errno = EEXIST; - return -1; + if (!override) { + errno = EEXIST; + return -1; + } + new_comm = strdup(comm); + if (!new_comm) { + errno = ENOMEM; + return -1; + } + free(cmdline->comm); + cmdline->comm = new_comm; + + return 0; } cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (pevent->cmdline_count + 1)); @@ -275,21 +288,13 @@ static int add_new_comm(struct tep_handle *pevent, const char *comm, int pid) return 0; } -/** - * tep_register_comm - register a pid / comm mapping - * @pevent: handle for the pevent - * @comm: the command line to register - * @pid: the pid to map the command line to - * - * This adds a mapping to search for command line names with - * a given pid. The comm is duplicated. - */ -int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid) +static int _tep_register_comm(struct tep_handle *pevent, + const char *comm, int pid, bool override) { struct cmdline_list *item; if (pevent->cmdlines) - return add_new_comm(pevent, comm, pid); + return add_new_comm(pevent, comm, pid, override); item = malloc(sizeof(*item)); if (!item) @@ -312,6 +317,40 @@ int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid) return 0; } +/** + * tep_register_comm - register a pid / comm mapping + * @pevent: handle for the pevent + * @comm: the command line to register + * @pid: the pid to map the command line to + * + * This adds a mapping to search for command line names with + * a given pid. The comm is duplicated. If a command with the same pid + * already exist, -1 is returned and errno is set to EEXIST + */ +int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid) +{ + return _tep_register_comm(pevent, comm, pid, false); +} + +/** + * tep_override_comm - register a pid / comm mapping + * @pevent: handle for the pevent + * @comm: the command line to register + * @pid: the pid to map the command line to + * + * This adds a mapping to search for command line names with + * a given pid. The comm is duplicated. If a command with the same pid + * already exist, the command string is udapted with the new one + */ +int tep_override_comm(struct tep_handle *pevent, const char *comm, int pid) +{ + if (!pevent->cmdlines && cmdline_init(pevent)) { + errno = ENOMEM; + return -1; + } + return _tep_register_comm(pevent, comm, pid, true); +} + int tep_register_trace_clock(struct tep_handle *pevent, const char *trace_clock) { pevent->trace_clock = strdup(trace_clock); diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 35d37087d3c5..e6f4249910e6 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -432,6 +432,7 @@ int tep_set_function_resolver(struct tep_handle *pevent, tep_func_resolver_t *func, void *priv); void tep_reset_function_resolver(struct tep_handle *pevent); int tep_register_comm(struct tep_handle *pevent, const char *comm, int pid); +int tep_override_comm(struct tep_handle *pevent, const char *comm, int pid); int tep_register_trace_clock(struct tep_handle *pevent, const char *trace_clock); int tep_register_function(struct tep_handle *pevent, char *name, unsigned long long addr, char *mod); -- cgit v1.2.3-58-ga151 From eed14f4b075ec594ac09921b998bf3dd61f5886b Mon Sep 17 00:00:00 2001 From: Tzvetomir Stoyanov Date: Fri, 30 Nov 2018 23:08:08 -0500 Subject: tools lib traceevent: Initialize host_bigendian at tep_handle allocation This patch initializes the host_bigendian member of the tep_handle structure with the byte order of the current host, when this handler is created - in tep_alloc() API. We need this in order to remove the tep_set_host_bigendian() API. Signed-off-by: Tzvetomir Stoyanov Cc: Andrew Morton Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20181201040852.216292134@goodmis.org Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 156e513074b2..44b80471b024 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -6762,8 +6762,10 @@ struct tep_handle *tep_alloc(void) { struct tep_handle *pevent = calloc(1, sizeof(*pevent)); - if (pevent) + if (pevent) { pevent->ref_count = 1; + pevent->host_bigendian = tep_host_bigendian(); + } return pevent; } -- cgit v1.2.3-58-ga151 From 2e4318a287bdf815140462257ab8697f5289a12f Mon Sep 17 00:00:00 2001 From: Tzvetomir Stoyanov Date: Fri, 30 Nov 2018 23:08:09 -0500 Subject: tools lib traceevent: Rename struct cmdline to struct tep_cmdline In order to make libtraceevent a proper library, variables, data structures and functions should have a unique prefix to prevent name space conflicts. That prefix will be "tep_". This patch renames 'struct cmdline' to 'struct tep_cmdline'. Signed-off-by: Tzvetomir Stoyanov Cc: Andrew Morton Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20181201040852.358871851@goodmis.org Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse-local.h | 4 ++-- tools/lib/traceevent/event-parse.c | 36 ++++++++++++++++---------------- tools/lib/traceevent/event-parse.h | 8 +++---- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/tools/lib/traceevent/event-parse-local.h b/tools/lib/traceevent/event-parse-local.h index 9a092dd4a86d..35833ee32d6c 100644 --- a/tools/lib/traceevent/event-parse-local.h +++ b/tools/lib/traceevent/event-parse-local.h @@ -7,7 +7,7 @@ #ifndef _PARSE_EVENTS_INT_H #define _PARSE_EVENTS_INT_H -struct cmdline; +struct tep_cmdline; struct cmdline_list; struct func_map; struct func_list; @@ -36,7 +36,7 @@ struct tep_handle { int long_size; int page_size; - struct cmdline *cmdlines; + struct tep_cmdline *cmdlines; struct cmdline_list *cmdlist; int cmdline_count; diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 44b80471b024..a850342baf86 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -124,15 +124,15 @@ struct tep_print_arg *alloc_arg(void) return calloc(1, sizeof(struct tep_print_arg)); } -struct cmdline { +struct tep_cmdline { char *comm; int pid; }; static int cmdline_cmp(const void *a, const void *b) { - const struct cmdline *ca = a; - const struct cmdline *cb = b; + const struct tep_cmdline *ca = a; + const struct tep_cmdline *cb = b; if (ca->pid < cb->pid) return -1; @@ -152,7 +152,7 @@ static int cmdline_init(struct tep_handle *pevent) { struct cmdline_list *cmdlist = pevent->cmdlist; struct cmdline_list *item; - struct cmdline *cmdlines; + struct tep_cmdline *cmdlines; int i; cmdlines = malloc(sizeof(*cmdlines) * pevent->cmdline_count); @@ -179,8 +179,8 @@ static int cmdline_init(struct tep_handle *pevent) static const char *find_cmdline(struct tep_handle *pevent, int pid) { - const struct cmdline *comm; - struct cmdline key; + const struct tep_cmdline *comm; + struct tep_cmdline key; if (!pid) return ""; @@ -208,8 +208,8 @@ static const char *find_cmdline(struct tep_handle *pevent, int pid) */ int tep_pid_is_registered(struct tep_handle *pevent, int pid) { - const struct cmdline *comm; - struct cmdline key; + const struct tep_cmdline *comm; + struct tep_cmdline key; if (!pid) return 1; @@ -235,9 +235,9 @@ int tep_pid_is_registered(struct tep_handle *pevent, int pid) static int add_new_comm(struct tep_handle *pevent, const char *comm, int pid, bool override) { - struct cmdline *cmdlines = pevent->cmdlines; - struct cmdline *cmdline; - struct cmdline key; + struct tep_cmdline *cmdlines = pevent->cmdlines; + struct tep_cmdline *cmdline; + struct tep_cmdline key; char *new_comm; if (!pid) @@ -5331,8 +5331,8 @@ const char *tep_data_comm_from_pid(struct tep_handle *pevent, int pid) return comm; } -static struct cmdline * -pid_from_cmdlist(struct tep_handle *pevent, const char *comm, struct cmdline *next) +static struct tep_cmdline * +pid_from_cmdlist(struct tep_handle *pevent, const char *comm, struct tep_cmdline *next) { struct cmdline_list *cmdlist = (struct cmdline_list *)next; @@ -5344,7 +5344,7 @@ pid_from_cmdlist(struct tep_handle *pevent, const char *comm, struct cmdline *ne while (cmdlist && strcmp(cmdlist->comm, comm) != 0) cmdlist = cmdlist->next; - return (struct cmdline *)cmdlist; + return (struct tep_cmdline *)cmdlist; } /** @@ -5360,10 +5360,10 @@ pid_from_cmdlist(struct tep_handle *pevent, const char *comm, struct cmdline *ne * next pid. * Also, it does a linear search, so it may be slow. */ -struct cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm, - struct cmdline *next) +struct tep_cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm, + struct tep_cmdline *next) { - struct cmdline *cmdline; + struct tep_cmdline *cmdline; /* * If the cmdlines have not been converted yet, then use @@ -5402,7 +5402,7 @@ struct cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *co * Returns the pid for a give cmdline. If @cmdline is NULL, then * -1 is returned. */ -int tep_cmdline_pid(struct tep_handle *pevent, struct cmdline *cmdline) +int tep_cmdline_pid(struct tep_handle *pevent, struct tep_cmdline *cmdline) { struct cmdline_list *cmdlist = (struct cmdline_list *)cmdline; diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index e6f4249910e6..77a4a1dd4b4d 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -526,10 +526,10 @@ int tep_data_pid(struct tep_handle *pevent, struct tep_record *rec); int tep_data_preempt_count(struct tep_handle *pevent, struct tep_record *rec); int tep_data_flags(struct tep_handle *pevent, struct tep_record *rec); const char *tep_data_comm_from_pid(struct tep_handle *pevent, int pid); -struct cmdline; -struct cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm, - struct cmdline *next); -int tep_cmdline_pid(struct tep_handle *pevent, struct cmdline *cmdline); +struct tep_cmdline; +struct tep_cmdline *tep_data_pid_from_comm(struct tep_handle *pevent, const char *comm, + struct tep_cmdline *next); +int tep_cmdline_pid(struct tep_handle *pevent, struct tep_cmdline *cmdline); void tep_print_field(struct trace_seq *s, void *data, struct tep_format_field *field); -- cgit v1.2.3-58-ga151 From 6d2d6fd7e3ee0daf0d8308741792b3ec41aafd0c Mon Sep 17 00:00:00 2001 From: Tzvetomir Stoyanov Date: Fri, 30 Nov 2018 23:08:10 -0500 Subject: tools lib traceevent: Changed return logic of trace_seq_printf() and trace_seq_vprintf() APIs In order to make libtraceevent into a proper library, its API should be straightforward. The trace_seq_printf() and trace_seq_vprintf() APIs have inconsistent returned values with the other trace_seq_* APIs. This path changes the return logic of trace_seq_printf() and trace_seq_vprintf() to return the number of printed characters, as the other trace_seq_* related APIs. Signed-off-by: Tzvetomir Stoyanov Cc: Andrew Morton Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20181201040852.485792891@goodmis.org Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/trace-seq.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index 8ff1d55954d1..8d5ecd2bf877 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c @@ -100,7 +100,8 @@ static void expand_buffer(struct trace_seq *s) * @fmt: printf format string * * It returns 0 if the trace oversizes the buffer's free - * space, 1 otherwise. + * space, the number of characters printed, or a negative + * value in case of an error. * * The tracer may use either sequence operations or its own * copy to user routines. To simplify formating of a trace @@ -129,9 +130,10 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) goto try_again; } - s->len += ret; + if (ret > 0) + s->len += ret; - return 1; + return ret; } /** @@ -139,6 +141,10 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) * @s: trace sequence descriptor * @fmt: printf format string * + * It returns 0 if the trace oversizes the buffer's free + * space, the number of characters printed, or a negative + * value in case of an error. + * * * The tracer may use either sequence operations or its own * copy to user routines. To simplify formating of a trace * trace_seq_printf is used to store strings into a special @@ -163,9 +169,10 @@ trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) goto try_again; } - s->len += ret; + if (ret > 0) + s->len += ret; - return len; + return ret; } /** -- cgit v1.2.3-58-ga151 From f87ce7c43f36d4abff91b19edadd23939f99ff98 Mon Sep 17 00:00:00 2001 From: Tzvetomir Stoyanov Date: Fri, 30 Nov 2018 23:08:11 -0500 Subject: tools lib traceevent: Changed return logic of tep_register_event_handler() API In order to make libtraceevent into a proper library, its API should be straightforward. The tep_register_event_handler() functions returns -1 in case it successfully registers the new event handler. Such return code is used by the other library APIs in case of an error. To unify the return logic of tep_register_event_handler() with the other APIs, this patch introduces enum tep_reg_handler, which is used by this function as return value, to handle all possible successful return cases. Signed-off-by: Tzvetomir Stoyanov Cc: Andrew Morton Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20181201040852.628034497@goodmis.org Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.c | 10 ++++++++-- tools/lib/traceevent/event-parse.h | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index a850342baf86..54d94054eef0 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -6632,6 +6632,12 @@ static struct tep_event *search_event(struct tep_handle *pevent, int id, * * If @id is >= 0, then it is used to find the event. * else @sys_name and @event_name are used. + * + * Returns: + * TEP_REGISTER_SUCCESS_OVERWRITE if an existing handler is overwritten + * TEP_REGISTER_SUCCESS if a new handler is registered successfully + * negative TEP_ERRNO_... in case of an error + * */ int tep_register_event_handler(struct tep_handle *pevent, int id, const char *sys_name, const char *event_name, @@ -6649,7 +6655,7 @@ int tep_register_event_handler(struct tep_handle *pevent, int id, event->handler = func; event->context = context; - return 0; + return TEP_REGISTER_SUCCESS_OVERWRITE; not_found: /* Save for later use. */ @@ -6679,7 +6685,7 @@ int tep_register_event_handler(struct tep_handle *pevent, int id, pevent->handlers = handle; handle->context = context; - return -1; + return TEP_REGISTER_SUCCESS; } static int handle_matches(struct event_handler *handler, int id, diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 77a4a1dd4b4d..ac377ae99008 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -485,6 +485,11 @@ int tep_print_func_field(struct trace_seq *s, const char *fmt, struct tep_event *event, const char *name, struct tep_record *record, int err); +enum tep_reg_handler { + TEP_REGISTER_SUCCESS = 0, + TEP_REGISTER_SUCCESS_OVERWRITE, +}; + int tep_register_event_handler(struct tep_handle *pevent, int id, const char *sys_name, const char *event_name, tep_event_handler_func func, void *context); -- cgit v1.2.3-58-ga151 From 4104e604277016b3e6a7d120368054f9d2716953 Mon Sep 17 00:00:00 2001 From: Tzvetomir Stoyanov Date: Fri, 30 Nov 2018 23:08:12 -0500 Subject: tools lib traceevent: Rename tep_is_file_bigendian() to tep_file_bigendian() In order to make libtraceevent into a proper library, its API should be straightforward. After a discussion with Steven Rostedt, we decided to rename a few APIs, to have more intuitive names. This patch renames tep_is_file_bigendian() to tep_file_bigendian(). Signed-off-by: Tzvetomir Stoyanov Cc: Andrew Morton Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20181201040852.767549746@goodmis.org Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse-api.c | 4 ++-- tools/lib/traceevent/event-parse.h | 2 +- tools/lib/traceevent/plugin_kvm.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/lib/traceevent/event-parse-api.c b/tools/lib/traceevent/event-parse-api.c index 8b31c0e00ba3..d463761a58f4 100644 --- a/tools/lib/traceevent/event-parse-api.c +++ b/tools/lib/traceevent/event-parse-api.c @@ -194,13 +194,13 @@ void tep_set_page_size(struct tep_handle *pevent, int _page_size) } /** - * tep_is_file_bigendian - get if the file is in big endian order + * tep_file_bigendian - get if the file is in big endian order * @pevent: a handle to the tep_handle * * This returns if the file is in big endian order * If @pevent is NULL, 0 is returned. */ -int tep_is_file_bigendian(struct tep_handle *pevent) +int tep_file_bigendian(struct tep_handle *pevent) { if(pevent) return pevent->file_bigendian; diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index ac377ae99008..bd1bd9a27839 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -559,7 +559,7 @@ int tep_get_long_size(struct tep_handle *pevent); void tep_set_long_size(struct tep_handle *pevent, int long_size); int tep_get_page_size(struct tep_handle *pevent); void tep_set_page_size(struct tep_handle *pevent, int _page_size); -int tep_is_file_bigendian(struct tep_handle *pevent); +int tep_file_bigendian(struct tep_handle *pevent); void tep_set_file_bigendian(struct tep_handle *pevent, enum tep_endian endian); int tep_is_host_bigendian(struct tep_handle *pevent); void tep_set_host_bigendian(struct tep_handle *pevent, enum tep_endian endian); diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c index 754050eea467..64b9c25a1fd3 100644 --- a/tools/lib/traceevent/plugin_kvm.c +++ b/tools/lib/traceevent/plugin_kvm.c @@ -389,7 +389,7 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record, * We can only use the structure if file is of the same * endianness. */ - if (tep_is_file_bigendian(event->pevent) == + if (tep_file_bigendian(event->pevent) == tep_is_host_bigendian(event->pevent)) { trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s", -- cgit v1.2.3-58-ga151 From 9231967e2f515fce9e19687c0c40dfda416b3512 Mon Sep 17 00:00:00 2001 From: Tzvetomir Stoyanov Date: Fri, 30 Nov 2018 23:08:13 -0500 Subject: tools lib traceevent: Remove tep_data_event_from_type() API In order to make libtraceevent into a proper library, its API should be straightforward. After discussion with Steven Rostedt, we decided to remove the tep_data_event_from_type() API and to replace it with tep_find_event(), as it does the same. Signed-off-by: Tzvetomir Stoyanov Cc: Andrew Morton Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20181201040852.913841066@goodmis.org Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.c | 12 ------------ tools/lib/traceevent/event-parse.h | 1 - 2 files changed, 13 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 54d94054eef0..abd4fa5d3088 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -5265,18 +5265,6 @@ int tep_data_type(struct tep_handle *pevent, struct tep_record *rec) return trace_parse_common_type(pevent, rec->data); } -/** - * tep_data_event_from_type - find the event by a given type - * @pevent: a handle to the pevent - * @type: the type of the event. - * - * This returns the event form a given @type; - */ -struct tep_event *tep_data_event_from_type(struct tep_handle *pevent, int type) -{ - return tep_find_event(pevent, type); -} - /** * tep_data_pid - parse the PID from record * @pevent: a handle to the pevent diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index bd1bd9a27839..aec48f2aea8a 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -526,7 +526,6 @@ tep_find_event_by_record(struct tep_handle *pevent, struct tep_record *record); void tep_data_lat_fmt(struct tep_handle *pevent, struct trace_seq *s, struct tep_record *record); int tep_data_type(struct tep_handle *pevent, struct tep_record *rec); -struct tep_event *tep_data_event_from_type(struct tep_handle *pevent, int type); int tep_data_pid(struct tep_handle *pevent, struct tep_record *rec); int tep_data_preempt_count(struct tep_handle *pevent, struct tep_record *rec); int tep_data_flags(struct tep_handle *pevent, struct tep_record *rec); -- cgit v1.2.3-58-ga151 From f2e14cd2c93699aa0aeaa8240457ab359f1258ff Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Jan 2019 10:56:59 -0300 Subject: perf top: Lift restriction on using callchains without "sym" in --sort This restriction is not present in 'perf report' and since 'perf top' uses the same hists browser, remove it from it as well. With this we create per event buckets with callchain trees, so that # perf top --sort dso -g --no-children Bucketizes samples by DSO and below it shows the callchains leading to functions in this DSO. Try also: # perf top -e sched:*switch -g --no-children To see the callchains leading to sched switches, pressing 'E' to expand all one can quickly see the most common scheduler switches and what leads to them, for instance, calls to IO, futexes, etc. Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Jiri Olsa Link: https://lkml.kernel.org/r/20190107140854.GA28965@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index fe3ecfb2e64b..f64e312db787 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1028,12 +1028,7 @@ out_err: static int callchain_param__setup_sample_type(struct callchain_param *callchain) { - if (!perf_hpp_list.sym) { - if (callchain->enabled) { - ui__error("Selected -g but \"sym\" not present in --sort/-s."); - return -EINVAL; - } - } else if (callchain->mode != CHAIN_NONE) { + if (callchain->mode != CHAIN_NONE) { if (callchain_register_param(callchain) < 0) { ui__error("Can't register callchain params.\n"); return -EINVAL; -- cgit v1.2.3-58-ga151 From 58fec830fc19208354895d9832785505046d6c01 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 7 Jan 2019 22:13:22 -0700 Subject: vfio/type1: Fix unmap overflow off-by-one The below referenced commit adds a test for integer overflow, but in doing so prevents the unmap ioctl from ever including the last page of the address space. Subtract one to compare to the last address of the unmap to avoid the overflow and wrap-around. Fixes: 71a7d3d78e3c ("vfio/type1: silence integer overflow warning") Link: https://bugzilla.redhat.com/show_bug.cgi?id=1662291 Cc: stable@vger.kernel.org # v4.15+ Reported-by: Pei Zhang Debugged-by: Peter Xu Reviewed-by: Dan Carpenter Reviewed-by: Peter Xu Tested-by: Peter Xu Reviewed-by: Cornelia Huck Signed-off-by: Alex Williamson --- drivers/vfio/vfio_iommu_type1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 7651cfb14836..73652e21efec 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -878,7 +878,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu, return -EINVAL; if (!unmap->size || unmap->size & mask) return -EINVAL; - if (unmap->iova + unmap->size < unmap->iova || + if (unmap->iova + unmap->size - 1 < unmap->iova || unmap->size > SIZE_MAX) return -EINVAL; -- cgit v1.2.3-58-ga151 From 4429b668e0375206408617d6440e3bb76c56c7d2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 5 Jan 2019 16:06:07 +0300 Subject: xprtrdma: Fix error code in rpcrdma_buffer_create() This should return -ENOMEM if __alloc_workqueue_key() fails, but it returns success. Fixes: 6d2d0ee27c7a ("xprtrdma: Replace rpcrdma_receive_wq with a per-xprt workqueue") Signed-off-by: Dan Carpenter Reviewed-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/verbs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 7749a2bf6887..3dde05892c8e 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -1113,8 +1113,10 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) WQ_MEM_RECLAIM | WQ_HIGHPRI, 0, r_xprt->rx_xprt.address_strings[RPC_DISPLAY_ADDR]); - if (!buf->rb_completion_wq) + if (!buf->rb_completion_wq) { + rc = -ENOMEM; goto out; + } return 0; out: -- cgit v1.2.3-58-ga151 From 6e17f58c486d9554341f70aa5b63b8fbed07b3fa Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 5 Jan 2019 16:06:48 +0300 Subject: xprtrdma: Double free in rpcrdma_sendctxs_create() The clean up is handled by the caller, rpcrdma_buffer_create(), so this call to rpcrdma_sendctxs_destroy() leads to a double free. Fixes: ae72950abf99 ("xprtrdma: Add data structure to manage RDMA Send arguments") Signed-off-by: Dan Carpenter Reviewed-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprtrdma/verbs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 3dde05892c8e..4994e75945b8 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -845,17 +845,13 @@ static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt) for (i = 0; i <= buf->rb_sc_last; i++) { sc = rpcrdma_sendctx_create(&r_xprt->rx_ia); if (!sc) - goto out_destroy; + return -ENOMEM; sc->sc_xprt = r_xprt; buf->rb_sc_ctxs[i] = sc; } return 0; - -out_destroy: - rpcrdma_sendctxs_destroy(buf); - return -ENOMEM; } /* The sendctx queue is not guaranteed to have a size that is a -- cgit v1.2.3-58-ga151 From 250bfc87ddc427fa001bbc8bc1468ce5fc06645b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Jan 2019 13:42:37 -0300 Subject: tools include uapi: Grab a copy of linux/mount.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were using a copy of uapi/linux/fs.h to create the mount syscall 'flags' string table to use in 'perf trace', to convert from the number obtained via the raw_syscalls:sys_enter into a string, using tools/perf/trace/beauty/mount_flags.sh, but in e262e32d6bde ("vfs: Suppress MS_* flag defs within the kernel unless explicitly enabled") those defines got moved to linux/mount.h, so grab a copy of mount.h too. Keep the uapi/linux/fs.h as we'll use it for the SEEK_ constants. Cc: Adrian Hunter Cc: David Howells Cc: Jiri Olsa Cc: Luis Cláudio Gonçalves Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-i2ricmpwpdrpukfq3298jr1z@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/mount.h | 58 ++++++++++++++++++++++++++++++++++++++++ tools/perf/check-headers.sh | 1 + 2 files changed, 59 insertions(+) create mode 100644 tools/include/uapi/linux/mount.h diff --git a/tools/include/uapi/linux/mount.h b/tools/include/uapi/linux/mount.h new file mode 100644 index 000000000000..3f9ec42510b0 --- /dev/null +++ b/tools/include/uapi/linux/mount.h @@ -0,0 +1,58 @@ +#ifndef _UAPI_LINUX_MOUNT_H +#define _UAPI_LINUX_MOUNT_H + +/* + * These are the fs-independent mount-flags: up to 32 flags are supported + * + * Usage of these is restricted within the kernel to core mount(2) code and + * callers of sys_mount() only. Filesystems should be using the SB_* + * equivalent instead. + */ +#define MS_RDONLY 1 /* Mount read-only */ +#define MS_NOSUID 2 /* Ignore suid and sgid bits */ +#define MS_NODEV 4 /* Disallow access to device special files */ +#define MS_NOEXEC 8 /* Disallow program execution */ +#define MS_SYNCHRONOUS 16 /* Writes are synced at once */ +#define MS_REMOUNT 32 /* Alter flags of a mounted FS */ +#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ +#define MS_DIRSYNC 128 /* Directory modifications are synchronous */ +#define MS_NOATIME 1024 /* Do not update access times. */ +#define MS_NODIRATIME 2048 /* Do not update directory access times */ +#define MS_BIND 4096 +#define MS_MOVE 8192 +#define MS_REC 16384 +#define MS_VERBOSE 32768 /* War is peace. Verbosity is silence. + MS_VERBOSE is deprecated. */ +#define MS_SILENT 32768 +#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ +#define MS_UNBINDABLE (1<<17) /* change to unbindable */ +#define MS_PRIVATE (1<<18) /* change to private */ +#define MS_SLAVE (1<<19) /* change to slave */ +#define MS_SHARED (1<<20) /* change to shared */ +#define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */ +#define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ +#define MS_I_VERSION (1<<23) /* Update inode I_version field */ +#define MS_STRICTATIME (1<<24) /* Always perform atime updates */ +#define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */ + +/* These sb flags are internal to the kernel */ +#define MS_SUBMOUNT (1<<26) +#define MS_NOREMOTELOCK (1<<27) +#define MS_NOSEC (1<<28) +#define MS_BORN (1<<29) +#define MS_ACTIVE (1<<30) +#define MS_NOUSER (1<<31) + +/* + * Superblock flags that can be altered by MS_REMOUNT + */ +#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|\ + MS_LAZYTIME) + +/* + * Old magic mount flag and mask + */ +#define MS_MGC_VAL 0xC0ED0000 +#define MS_MGC_MSK 0xffff0000 + +#endif /* _UAPI_LINUX_MOUNT_H */ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 6cb98f8570a2..b51e952ab35f 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -10,6 +10,7 @@ include/uapi/linux/fs.h include/uapi/linux/kcmp.h include/uapi/linux/kvm.h include/uapi/linux/in.h +include/uapi/linux/mount.h include/uapi/linux/perf_event.h include/uapi/linux/prctl.h include/uapi/linux/sched.h -- cgit v1.2.3-58-ga151 From 1c23397d2a6a077ab32f01c01406c2fe61b7b3a4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Jan 2019 13:46:43 -0300 Subject: perf beauty: Switch from using uapi/linux/fs.h to uapi/linux/mount.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As now we'll update our fs.h copy and what tools/perf/trace/beauty/mount_flags.sh needs just got moved to mount.h, use that instead. Cc: Adrian Hunter Cc: David Howells Cc: Jiri Olsa Cc: Luis Cláudio Gonçalves Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-ls19h376xukeouxrw9dswkcn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/beauty/mount_flags.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/trace/beauty/mount_flags.sh b/tools/perf/trace/beauty/mount_flags.sh index 45547573a1db..847850b2ef6c 100755 --- a/tools/perf/trace/beauty/mount_flags.sh +++ b/tools/perf/trace/beauty/mount_flags.sh @@ -5,11 +5,11 @@ printf "static const char *mount_flags[] = {\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+([[:digit:]]+)[[:space:]]*.*' -egrep $regex ${header_dir}/fs.h | egrep -v '(MSK|VERBOSE|MGC_VAL)\>' | \ +egrep $regex ${header_dir}/mount.h | egrep -v '(MSK|VERBOSE|MGC_VAL)\>' | \ sed -r "s/$regex/\2 \2 \1/g" | sort -n | \ xargs printf "\t[%s ? (ilog2(%s) + 1) : 0] = \"%s\",\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+\(1<<([[:digit:]]+)\)[[:space:]]*.*' -egrep $regex ${header_dir}/fs.h | \ +egrep $regex ${header_dir}/mount.h | \ sed -r "s/$regex/\2 \1/g" | \ xargs printf "\t[%s + 1] = \"%s\",\n" printf "};\n" -- cgit v1.2.3-58-ga151 From fdc42ca190c7d8976f4f9240752f0bd008270b72 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Jan 2019 13:48:14 -0300 Subject: tools include uapi: Sync linux/fs.h copy with the kernel sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To get the changes in: e262e32d6bde ("vfs: Suppress MS_* flag defs within the kernel unless explicitly enabled") That made the mount flags string table generator to switch to using mount.h instead. This silences the following perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/fs.h' differs from latest version at 'include/uapi/linux/fs.h' diff -u tools/include/uapi/linux/fs.h include/uapi/linux/fs.h Cc: Adrian Hunter Cc: David Howells Cc: Jiri Olsa Cc: Luis Cláudio Gonçalves Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-mosz81pa6iwxko4p2owbm3ss@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/fs.h | 60 ++++++------------------------------------- 1 file changed, 8 insertions(+), 52 deletions(-) diff --git a/tools/include/uapi/linux/fs.h b/tools/include/uapi/linux/fs.h index a441ea1bfe6d..121e82ce296b 100644 --- a/tools/include/uapi/linux/fs.h +++ b/tools/include/uapi/linux/fs.h @@ -14,6 +14,11 @@ #include #include +/* Use of MS_* flags within the kernel is restricted to core mount(2) code. */ +#if !defined(__KERNEL__) +#include +#endif + /* * It's silly to have NR_OPEN bigger than NR_FILE, but you can change * the file limit at runtime and only root can increase the per-process @@ -101,57 +106,6 @@ struct inodes_stat_t { #define NR_FILE 8192 /* this can well be larger on a larger system */ - -/* - * These are the fs-independent mount-flags: up to 32 flags are supported - */ -#define MS_RDONLY 1 /* Mount read-only */ -#define MS_NOSUID 2 /* Ignore suid and sgid bits */ -#define MS_NODEV 4 /* Disallow access to device special files */ -#define MS_NOEXEC 8 /* Disallow program execution */ -#define MS_SYNCHRONOUS 16 /* Writes are synced at once */ -#define MS_REMOUNT 32 /* Alter flags of a mounted FS */ -#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ -#define MS_DIRSYNC 128 /* Directory modifications are synchronous */ -#define MS_NOATIME 1024 /* Do not update access times. */ -#define MS_NODIRATIME 2048 /* Do not update directory access times */ -#define MS_BIND 4096 -#define MS_MOVE 8192 -#define MS_REC 16384 -#define MS_VERBOSE 32768 /* War is peace. Verbosity is silence. - MS_VERBOSE is deprecated. */ -#define MS_SILENT 32768 -#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ -#define MS_UNBINDABLE (1<<17) /* change to unbindable */ -#define MS_PRIVATE (1<<18) /* change to private */ -#define MS_SLAVE (1<<19) /* change to slave */ -#define MS_SHARED (1<<20) /* change to shared */ -#define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */ -#define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ -#define MS_I_VERSION (1<<23) /* Update inode I_version field */ -#define MS_STRICTATIME (1<<24) /* Always perform atime updates */ -#define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */ - -/* These sb flags are internal to the kernel */ -#define MS_SUBMOUNT (1<<26) -#define MS_NOREMOTELOCK (1<<27) -#define MS_NOSEC (1<<28) -#define MS_BORN (1<<29) -#define MS_ACTIVE (1<<30) -#define MS_NOUSER (1<<31) - -/* - * Superblock flags that can be altered by MS_REMOUNT - */ -#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|\ - MS_LAZYTIME) - -/* - * Old magic mount flag and mask - */ -#define MS_MGC_VAL 0xC0ED0000 -#define MS_MGC_MSK 0xffff0000 - /* * Structure for FS_IOC_FSGETXATTR[A] and FS_IOC_FSSETXATTR. */ @@ -269,7 +223,8 @@ struct fsxattr { #define FS_POLICY_FLAGS_PAD_16 0x02 #define FS_POLICY_FLAGS_PAD_32 0x03 #define FS_POLICY_FLAGS_PAD_MASK 0x03 -#define FS_POLICY_FLAGS_VALID 0x03 +#define FS_POLICY_FLAG_DIRECT_KEY 0x04 /* use master key directly */ +#define FS_POLICY_FLAGS_VALID 0x07 /* Encryption algorithms */ #define FS_ENCRYPTION_MODE_INVALID 0 @@ -281,6 +236,7 @@ struct fsxattr { #define FS_ENCRYPTION_MODE_AES_128_CTS 6 #define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 /* Removed, do not use. */ #define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 /* Removed, do not use. */ +#define FS_ENCRYPTION_MODE_ADIANTUM 9 struct fscrypt_policy { __u8 version; -- cgit v1.2.3-58-ga151 From ee412f14693a3fe2645b3528603dfd37dd05118a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Jan 2019 13:53:23 -0300 Subject: tools include uapi: Sync linux/vhost.h with the kernel sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To get the changes in: 4b86713236e4 ("vhost: split structs into a separate header file") Silencing this perf build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/vhost.h' differs from latest version at 'include/uapi/linux/vhost.h' diff -u tools/include/uapi/linux/vhost.h include/uapi/linux/vhost.h Those didn't touch things used in tools, i.e. the following continues working: $ tools/perf/trace/beauty/vhost_virtio_ioctl.sh static const char *vhost_virtio_ioctl_cmds[] = { [0x00] = "SET_FEATURES", [0x01] = "SET_OWNER", [0x02] = "RESET_OWNER", [0x03] = "SET_MEM_TABLE", [0x04] = "SET_LOG_BASE", [0x07] = "SET_LOG_FD", [0x10] = "SET_VRING_NUM", [0x11] = "SET_VRING_ADDR", [0x12] = "SET_VRING_BASE", [0x13] = "SET_VRING_ENDIAN", [0x14] = "GET_VRING_ENDIAN", [0x20] = "SET_VRING_KICK", [0x21] = "SET_VRING_CALL", [0x22] = "SET_VRING_ERR", [0x23] = "SET_VRING_BUSYLOOP_TIMEOUT", [0x24] = "GET_VRING_BUSYLOOP_TIMEOUT", [0x25] = "SET_BACKEND_FEATURES", [0x30] = "NET_SET_BACKEND", [0x40] = "SCSI_SET_ENDPOINT", [0x41] = "SCSI_CLEAR_ENDPOINT", [0x42] = "SCSI_GET_ABI_VERSION", [0x43] = "SCSI_SET_EVENTS_MISSED", [0x44] = "SCSI_GET_EVENTS_MISSED", [0x60] = "VSOCK_SET_GUEST_CID", [0x61] = "VSOCK_SET_RUNNING", }; static const char *vhost_virtio_ioctl_read_cmds[] = { [0x00] = "GET_FEATURES", [0x12] = "GET_VRING_BASE", [0x26] = "GET_BACKEND_FEATURES", }; $ At some point in the eBPFication of perf, using something like: # perf trace -e ioctl(cmd=VHOST_VRING*) Will setup a BPF filter right at the raw_syscalls:sys_enter tracepoint, i.e. filtering at the origin. Cc: Adrian Hunter Cc: Jiri Olsa Cc: Luis Cláudio Gonçalves Cc: Michael S. Tsirkin Cc: Namhyung Kim Cc: Paolo Bonzini Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-g28usrt7l59lwq3wuh8vzbig@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/vhost.h | 113 +-------------------------------------- 1 file changed, 2 insertions(+), 111 deletions(-) diff --git a/tools/include/uapi/linux/vhost.h b/tools/include/uapi/linux/vhost.h index 84c3de89696a..40d028eed645 100644 --- a/tools/include/uapi/linux/vhost.h +++ b/tools/include/uapi/linux/vhost.h @@ -11,94 +11,9 @@ * device configuration. */ +#include #include -#include #include -#include -#include - -struct vhost_vring_state { - unsigned int index; - unsigned int num; -}; - -struct vhost_vring_file { - unsigned int index; - int fd; /* Pass -1 to unbind from file. */ - -}; - -struct vhost_vring_addr { - unsigned int index; - /* Option flags. */ - unsigned int flags; - /* Flag values: */ - /* Whether log address is valid. If set enables logging. */ -#define VHOST_VRING_F_LOG 0 - - /* Start of array of descriptors (virtually contiguous) */ - __u64 desc_user_addr; - /* Used structure address. Must be 32 bit aligned */ - __u64 used_user_addr; - /* Available structure address. Must be 16 bit aligned */ - __u64 avail_user_addr; - /* Logging support. */ - /* Log writes to used structure, at offset calculated from specified - * address. Address must be 32 bit aligned. */ - __u64 log_guest_addr; -}; - -/* no alignment requirement */ -struct vhost_iotlb_msg { - __u64 iova; - __u64 size; - __u64 uaddr; -#define VHOST_ACCESS_RO 0x1 -#define VHOST_ACCESS_WO 0x2 -#define VHOST_ACCESS_RW 0x3 - __u8 perm; -#define VHOST_IOTLB_MISS 1 -#define VHOST_IOTLB_UPDATE 2 -#define VHOST_IOTLB_INVALIDATE 3 -#define VHOST_IOTLB_ACCESS_FAIL 4 - __u8 type; -}; - -#define VHOST_IOTLB_MSG 0x1 -#define VHOST_IOTLB_MSG_V2 0x2 - -struct vhost_msg { - int type; - union { - struct vhost_iotlb_msg iotlb; - __u8 padding[64]; - }; -}; - -struct vhost_msg_v2 { - __u32 type; - __u32 reserved; - union { - struct vhost_iotlb_msg iotlb; - __u8 padding[64]; - }; -}; - -struct vhost_memory_region { - __u64 guest_phys_addr; - __u64 memory_size; /* bytes */ - __u64 userspace_addr; - __u64 flags_padding; /* No flags are currently specified. */ -}; - -/* All region addresses and sizes must be 4K aligned. */ -#define VHOST_PAGE_SIZE 0x1000 - -struct vhost_memory { - __u32 nregions; - __u32 padding; - struct vhost_memory_region regions[0]; -}; /* ioctls */ @@ -186,31 +101,7 @@ struct vhost_memory { * device. This can be used to stop the ring (e.g. for migration). */ #define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file) -/* Feature bits */ -/* Log all write descriptors. Can be changed while device is active. */ -#define VHOST_F_LOG_ALL 26 -/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */ -#define VHOST_NET_F_VIRTIO_NET_HDR 27 - -/* VHOST_SCSI specific definitions */ - -/* - * Used by QEMU userspace to ensure a consistent vhost-scsi ABI. - * - * ABI Rev 0: July 2012 version starting point for v3.6-rc merge candidate + - * RFC-v2 vhost-scsi userspace. Add GET_ABI_VERSION ioctl usage - * ABI Rev 1: January 2013. Ignore vhost_tpgt filed in struct vhost_scsi_target. - * All the targets under vhost_wwpn can be seen and used by guset. - */ - -#define VHOST_SCSI_ABI_VERSION 1 - -struct vhost_scsi_target { - int abi_version; - char vhost_wwpn[224]; /* TRANSPORT_IQN_LEN */ - unsigned short vhost_tpgt; - unsigned short reserved; -}; +/* VHOST_SCSI specific defines */ #define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target) #define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target) -- cgit v1.2.3-58-ga151 From 7b55851367136b1efd84d98fea81ba57a98304cf Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 8 Jan 2019 13:58:52 +0100 Subject: fork: record start_time late This changes the fork(2) syscall to record the process start_time after initializing the basic task structure but still before making the new process visible to user-space. Technically, we could record the start_time anytime during fork(2). But this might lead to scenarios where a start_time is recorded long before a process becomes visible to user-space. For instance, with userfaultfd(2) and TLS, user-space can delay the execution of fork(2) for an indefinite amount of time (and will, if this causes network access, or similar). By recording the start_time late, it much closer reflects the point in time where the process becomes live and can be observed by other processes. Lastly, this makes it much harder for user-space to predict and control the start_time they get assigned. Previously, user-space could fork a process and stall it in copy_thread_tls() before its pid is allocated, but after its start_time is recorded. This can be misused to later-on cycle through PIDs and resume the stalled fork(2) yielding a process that has the same pid and start_time as a process that existed before. This can be used to circumvent security systems that identify processes by their pid+start_time combination. Even though user-space was always aware that start_time recording is flaky (but several projects are known to still rely on start_time-based identification), changing the start_time to be recorded late will help mitigate existing attacks and make it much harder for user-space to control the start_time a process gets assigned. Reported-by: Jann Horn Signed-off-by: Tom Gundersen Signed-off-by: David Herrmann Signed-off-by: Linus Torvalds --- kernel/fork.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/kernel/fork.c b/kernel/fork.c index a60459947f18..7f49be94eba9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1833,8 +1833,6 @@ static __latent_entropy struct task_struct *copy_process( posix_cpu_timers_init(p); - p->start_time = ktime_get_ns(); - p->real_start_time = ktime_get_boot_ns(); p->io_context = NULL; audit_set_context(p, NULL); cgroup_fork(p); @@ -2000,6 +1998,17 @@ static __latent_entropy struct task_struct *copy_process( if (retval) goto bad_fork_free_pid; + /* + * From this point on we must avoid any synchronous user-space + * communication until we take the tasklist-lock. In particular, we do + * not want user-space to be able to predict the process start-time by + * stalling fork(2) after we recorded the start_time but before it is + * visible to the system. + */ + + p->start_time = ktime_get_ns(); + p->real_start_time = ktime_get_boot_ns(); + /* * Make it visible to the rest of the system, but dont wake it up yet. * Need tasklist lock for parent etc handling! -- cgit v1.2.3-58-ga151 From 6a829eb8619fbdde6d7d627ad582fe119805f39d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 3 Jan 2019 09:04:45 -0500 Subject: SUNRPC: Fix TCP receive code on archs with flush_dcache_page() After receiving data into the page cache, we need to call flush_dcache_page() for the architectures that define it. Fixes: 277e4ab7d530b ("SUNRPC: Simplify TCP receive code by switching...") Reported-by: Geert Uytterhoeven Signed-off-by: Trond Myklebust Cc: stable@vger.kernel.org # v4.20 Tested-by: Geert Uytterhoeven Signed-off-by: Anna Schumaker --- net/sunrpc/xprtsock.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 13559e6a460b..7754aa3e434f 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -376,6 +377,26 @@ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags, return sock_recvmsg(sock, msg, flags); } +#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE +static void +xs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek) +{ + struct bvec_iter bi = { + .bi_size = count, + }; + struct bio_vec bv; + + bvec_iter_advance(bvec, &bi, seek & PAGE_MASK); + for_each_bvec(bv, bvec, bi, bi) + flush_dcache_page(bv.bv_page); +} +#else +static inline void +xs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek) +{ +} +#endif + static ssize_t xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, struct xdr_buf *buf, size_t count, size_t seek, size_t *read) @@ -409,6 +430,7 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, seek + buf->page_base); if (ret <= 0) goto sock_err; + xs_flush_bvec(buf->bvec, ret, seek + buf->page_base); offset += ret - buf->page_base; if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) goto out; -- cgit v1.2.3-58-ga151 From 895ac1376d5abcb94ca1b70a595579f253237790 Mon Sep 17 00:00:00 2001 From: Eugene Syromiatnikov Date: Mon, 7 Jan 2019 16:22:29 +0100 Subject: ptp: check that rsv field is zero in struct ptp_sys_offset_extended Otherwise it is impossible to use it for something else, as it will break userspace that puts garbage there. The same check should be done in other structures, but the fact that data in reserved fields is ignored is already part of the kernel ABI. Signed-off-by: Eugene Syromiatnikov Signed-off-by: David S. Miller --- drivers/ptp/ptp_chardev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 797fab33bb98..7cbea796652a 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -224,7 +224,8 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) extoff = NULL; break; } - if (extoff->n_samples > PTP_MAX_SAMPLES) { + if (extoff->n_samples > PTP_MAX_SAMPLES + || extoff->rsv[0] || extoff->rsv[1] || extoff->rsv[2]) { err = -EINVAL; break; } -- cgit v1.2.3-58-ga151 From b7ea4894aa867aaf1c31bfb4b00a3c3e38eedf95 Mon Sep 17 00:00:00 2001 From: Eugene Syromiatnikov Date: Mon, 7 Jan 2019 16:22:38 +0100 Subject: ptp: uapi: change _IOW to IOWR in PTP_SYS_OFFSET_EXTENDED definition The ioctl command is read/write (or just read, if the fact that user space writes n_samples field is ignored). Signed-off-by: Eugene Syromiatnikov Signed-off-by: David S. Miller --- include/uapi/linux/ptp_clock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h index d73d83950265..1bc794ad957a 100644 --- a/include/uapi/linux/ptp_clock.h +++ b/include/uapi/linux/ptp_clock.h @@ -147,7 +147,7 @@ struct ptp_pin_desc { #define PTP_SYS_OFFSET_PRECISE \ _IOWR(PTP_CLK_MAGIC, 8, struct ptp_sys_offset_precise) #define PTP_SYS_OFFSET_EXTENDED \ - _IOW(PTP_CLK_MAGIC, 9, struct ptp_sys_offset_extended) + _IOWR(PTP_CLK_MAGIC, 9, struct ptp_sys_offset_extended) struct ptp_extts_event { struct ptp_clock_time t; /* Time event occured. */ -- cgit v1.2.3-58-ga151 From 8139d493daf1ef19d34192f95e92e19dc19b648a Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Mon, 7 Jan 2019 18:38:30 +0800 Subject: drm/amd/powerplay: update OD support flag for SKU with no OD capabilities For those ASICs with no overdrive capabilities, the OD support flag will be reset. Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index ea0b52d46fe9..74c9bdf6f79f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -980,6 +980,9 @@ static int vega20_od8_set_feature_capabilities( pp_table->FanZeroRpmEnable) od_settings->overdrive8_capabilities |= OD8_FAN_ZERO_RPM_CONTROL; + if (!od_settings->overdrive8_capabilities) + hwmgr->od_enabled = false; + return 0; } -- cgit v1.2.3-58-ga151 From a0071840d2040ea1b27e5a008182b09b88defc15 Mon Sep 17 00:00:00 2001 From: Bryan Whitehead Date: Mon, 7 Jan 2019 14:00:09 -0500 Subject: lan743x: Remove phy_read from link status change function It has been noticed that some phys do not have the registers required by the previous implementation. To fix this, instead of using phy_read, the required information is extracted from the phy_device structure. fixes: 23f0703c125b ("lan743x: Add main source files for new lan743x driver") Signed-off-by: Bryan Whitehead Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/lan743x_main.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index 20c9377e99cb..310807ef328b 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -962,13 +962,10 @@ static void lan743x_phy_link_status_change(struct net_device *netdev) memset(&ksettings, 0, sizeof(ksettings)); phy_ethtool_get_link_ksettings(netdev, &ksettings); - local_advertisement = phy_read(phydev, MII_ADVERTISE); - if (local_advertisement < 0) - return; - - remote_advertisement = phy_read(phydev, MII_LPA); - if (remote_advertisement < 0) - return; + local_advertisement = + linkmode_adv_to_mii_adv_t(phydev->advertising); + remote_advertisement = + linkmode_adv_to_mii_adv_t(phydev->lp_advertising); lan743x_phy_update_flowcontrol(adapter, ksettings.base.duplex, -- cgit v1.2.3-58-ga151 From 0624e145fb2ba87c752bec355af12f43cb52cd68 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Mon, 7 Jan 2019 18:56:14 +0800 Subject: drm/amd/powerplay: create pp_od_clk_voltage device file under OD support Since pp_od_clk_voltage device file is for OD related sysfs operations. Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 1f61ed95727c..6896dec97fc7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -2008,6 +2008,7 @@ void amdgpu_pm_print_power_states(struct amdgpu_device *adev) int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) { + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; int ret; if (adev->pm.sysfs_initialized) @@ -2091,12 +2092,14 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) "pp_power_profile_mode\n"); return ret; } - ret = device_create_file(adev->dev, - &dev_attr_pp_od_clk_voltage); - if (ret) { - DRM_ERROR("failed to create device file " - "pp_od_clk_voltage\n"); - return ret; + if (hwmgr->od_enabled) { + ret = device_create_file(adev->dev, + &dev_attr_pp_od_clk_voltage); + if (ret) { + DRM_ERROR("failed to create device file " + "pp_od_clk_voltage\n"); + return ret; + } } ret = device_create_file(adev->dev, &dev_attr_gpu_busy_percent); @@ -2118,6 +2121,8 @@ int amdgpu_pm_sysfs_init(struct amdgpu_device *adev) void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) { + struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + if (adev->pm.dpm_enabled == 0) return; @@ -2138,8 +2143,9 @@ void amdgpu_pm_sysfs_fini(struct amdgpu_device *adev) device_remove_file(adev->dev, &dev_attr_pp_mclk_od); device_remove_file(adev->dev, &dev_attr_pp_power_profile_mode); - device_remove_file(adev->dev, - &dev_attr_pp_od_clk_voltage); + if (hwmgr->od_enabled) + device_remove_file(adev->dev, + &dev_attr_pp_od_clk_voltage); device_remove_file(adev->dev, &dev_attr_gpu_busy_percent); } -- cgit v1.2.3-58-ga151 From fff0d3f7686942bd544b53a48d1b76bd62c46946 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Tue, 8 Jan 2019 10:33:35 +0800 Subject: drm/amd/powerplay: avoid possible buffer overflow Make sure the clock level enforced is within the allowed ranges. Signed-off-by: Evan Quan Reviewed-by: Alex Deucher Reviewed-by: Likun Gao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 74c9bdf6f79f..205fac8d2bc8 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -2241,6 +2241,13 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr, soft_min_level = mask ? (ffs(mask) - 1) : 0; soft_max_level = mask ? (fls(mask) - 1) : 0; + if (soft_max_level >= data->dpm_table.gfx_table.count) { + pr_err("Clock level specified %d is over max allowed %d\n", + soft_max_level, + data->dpm_table.gfx_table.count - 1); + return -EINVAL; + } + data->dpm_table.gfx_table.dpm_state.soft_min_level = data->dpm_table.gfx_table.dpm_levels[soft_min_level].value; data->dpm_table.gfx_table.dpm_state.soft_max_level = @@ -2261,6 +2268,13 @@ static int vega20_force_clock_level(struct pp_hwmgr *hwmgr, soft_min_level = mask ? (ffs(mask) - 1) : 0; soft_max_level = mask ? (fls(mask) - 1) : 0; + if (soft_max_level >= data->dpm_table.mem_table.count) { + pr_err("Clock level specified %d is over max allowed %d\n", + soft_max_level, + data->dpm_table.mem_table.count - 1); + return -EINVAL; + } + data->dpm_table.mem_table.dpm_state.soft_min_level = data->dpm_table.mem_table.dpm_levels[soft_min_level].value; data->dpm_table.mem_table.dpm_state.soft_max_level = -- cgit v1.2.3-58-ga151 From fadcb8f9fc89f7b517ce48f30e0b607b16d99d63 Mon Sep 17 00:00:00 2001 From: Evan Quan Date: Tue, 8 Jan 2019 12:22:24 +0800 Subject: drm/amd/powerplay: drop the unnecessary uclk hard min setting Since soft min setting is enough. Hard min setting is redundant. Reported-by: Likun Gao Signed-off-by: Evan Quan Acked-by: Alex Deucher Reviewed-by: Likun Gao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 205fac8d2bc8..5824213d5b50 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -1690,13 +1690,6 @@ static int vega20_upload_dpm_min_level(struct pp_hwmgr *hwmgr) (PPCLK_UCLK << 16) | (min_freq & 0xffff))), "Failed to set soft min memclk !", return ret); - - min_freq = data->dpm_table.mem_table.dpm_state.hard_min_level; - PP_ASSERT_WITH_CODE(!(ret = smum_send_msg_to_smc_with_parameter( - hwmgr, PPSMC_MSG_SetHardMinByFreq, - (PPCLK_UCLK << 16) | (min_freq & 0xffff))), - "Failed to set hard min memclk !", - return ret); } if (data->smu_features[GNLD_DPM_UVD].enabled) { -- cgit v1.2.3-58-ga151 From 89f23b6efef554766177bf51aa754bce14c3e7da Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Mon, 7 Jan 2019 15:51:14 -0700 Subject: drm/amdgpu: validate user pitch alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Userspace may request pitch alignment that is not supported by GPU. Some requests 32, but GPU ignores it and uses default 64 when cpp is 4. If GEM object is allocated based on the smaller alignment, GPU DMA will go out of bound. Cc: stable@vger.kernel.org # v4.2+ Reviewed-by: Michel Dänzer Signed-off-by: Yu Zhao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index b083b219b1a9..cb72d9675ab1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -531,6 +531,16 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev, struct drm_gem_object *obj; struct amdgpu_framebuffer *amdgpu_fb; int ret; + struct amdgpu_device *adev = dev->dev_private; + int cpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0); + int pitch = mode_cmd->pitches[0] / cpp; + + pitch = amdgpu_align_pitch(adev, pitch, cpp, false); + if (mode_cmd->pitches[0] != pitch) { + DRM_DEBUG_KMS("Invalid pitch: expecting %d but got %d\n", + pitch, mode_cmd->pitches[0]); + return ERR_PTR(-EINVAL); + } obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[0]); if (obj == NULL) { -- cgit v1.2.3-58-ga151 From c4a32b266da7bb702e60381ca0c35eaddbc89a6c Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Mon, 7 Jan 2019 15:51:15 -0700 Subject: drm/amdgpu: validate user GEM object size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When creating frame buffer, userspace may request to attach to a previously allocated GEM object that is smaller than what GPU requires. Validation must be done to prevent out-of-bound DMA, otherwise it could be exploited to reveal sensitive data. This fix is not done in a common code path because individual driver might have different requirement. Cc: stable@vger.kernel.org # v4.2+ Reviewed-by: Michel Dänzer Signed-off-by: Yu Zhao Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index cb72d9675ab1..dafc645b2e4e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -531,6 +531,7 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev, struct drm_gem_object *obj; struct amdgpu_framebuffer *amdgpu_fb; int ret; + int height; struct amdgpu_device *adev = dev->dev_private; int cpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0); int pitch = mode_cmd->pitches[0] / cpp; @@ -555,6 +556,13 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev, return ERR_PTR(-EINVAL); } + height = ALIGN(mode_cmd->height, 8); + if (obj->size < pitch * height) { + DRM_DEBUG_KMS("Invalid GEM size: expecting >= %d but got %zu\n", + pitch * height, obj->size); + return ERR_PTR(-EINVAL); + } + amdgpu_fb = kzalloc(sizeof(*amdgpu_fb), GFP_KERNEL); if (amdgpu_fb == NULL) { drm_gem_object_put_unlocked(obj); -- cgit v1.2.3-58-ga151 From 11287b693d03830010356339e4ceddf47dee34fa Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 7 Jan 2019 21:49:09 +0100 Subject: r8169: load Realtek PHY driver module before r8169 This soft dependency works around an issue where sometimes the genphy driver is used instead of the dedicated PHY driver. The root cause of the issue isn't clear yet. People reported the unloading/re-loading module r8169 helps, and also configuring this soft dependency in the modprobe config files. Important just seems to be that the realtek module is loaded before r8169. Once this has been applied preliminary fix 38af4b903210 ("net: phy: add workaround for issue where PHY driver doesn't bind to the device") will be removed. Fixes: f1e911d5d0df ("r8169: add basic phylib support") Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 784ae5001656..abb94c543aa2 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -708,6 +708,7 @@ module_param(use_dac, int, 0); MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot."); module_param_named(debug, debug.msg_enable, int, 0); MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); +MODULE_SOFTDEP("pre: realtek"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(FIRMWARE_8168D_1); MODULE_FIRMWARE(FIRMWARE_8168D_2); -- cgit v1.2.3-58-ga151 From ff0db43cd6c530ff944773ccf48ece55d32d0c22 Mon Sep 17 00:00:00 2001 From: Nir Dotan Date: Tue, 8 Jan 2019 16:48:03 +0000 Subject: mlxsw: spectrum_acl: Add cleanup after C-TCAM update error condition When writing to C-TCAM, mlxsw driver uses cregion->ops->entry_insert(). In case of C-TCAM HW insertion error, the opposite action should take place. Add error handling case in which the C-TCAM region entry is removed, by calling cregion->ops->entry_remove(). Fixes: a0a777b9409f ("mlxsw: spectrum_acl: Start using A-TCAM") Signed-off-by: Nir Dotan Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c index b0f2d8e8ded0..ac222833a5cf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c @@ -72,7 +72,15 @@ mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp, act_set = mlxsw_afa_block_first_set(rulei->act_block); mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); + if (err) + goto err_ptce2_write; + + return 0; + +err_ptce2_write: + cregion->ops->entry_remove(cregion, centry); + return err; } static void -- cgit v1.2.3-58-ga151 From 04d075b7aa8433dc3c98e14c571705effc318cd8 Mon Sep 17 00:00:00 2001 From: Nir Dotan Date: Tue, 8 Jan 2019 16:48:04 +0000 Subject: mlxsw: spectrum_acl: Remove ASSERT_RTNL()s in module removal flow Removal of the mlxsw driver on Spectrum-2 platforms hits an ASSERT_RTNL() in Spectrum-2 ACL Bloom filter and in ERP removal paths. This happens because the multicast router implementation in Spectrum-2 relies on ACLs. Taking the RTNL lock upon driver removal is useless since the driver first removes its ports and unregisters from notifiers so concurrent writes cannot happen at that time. The assertions were originally put as a reminder for future work involving ERP background optimization, but having these assertions only during addition serves this purpose as well. Therefore remove the ASSERT_RTNL() in both places related to ERP and Bloom filter removal. Fixes: cf7221a4f5a5 ("mlxsw: spectrum_router: Add Multicast routing support for Spectrum-2") Signed-off-by: Nir Dotan Reviewed-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c index 1c19feefa5f2..2941967e1cc5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c @@ -1022,7 +1022,6 @@ void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion, { struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask; - ASSERT_RTNL(); objagg_obj_put(aregion->erp_table->objagg, objagg_obj); } @@ -1054,7 +1053,6 @@ void mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj); unsigned int erp_bank; - ASSERT_RTNL(); if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table)) return; -- cgit v1.2.3-58-ga151 From 8adbe212a159d9c78a90fca1d854f6e63452426b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 8 Jan 2019 16:48:05 +0000 Subject: mlxsw: spectrum: Disable lag port TX before removing it Make sure that lag port TX is disabled before mlxsw_sp_port_lag_leave() is called and prevent from possible EMAD error. Fixes: 0d65fc13042f ("mlxsw: spectrum: Implement LAG port join/leave") Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index eed1045e4d96..32519c93df17 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -5005,12 +5005,15 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *lower_dev, lower_dev, upper_dev); } else if (netif_is_lag_master(upper_dev)) { - if (info->linking) + if (info->linking) { err = mlxsw_sp_port_lag_join(mlxsw_sp_port, upper_dev); - else + } else { + mlxsw_sp_port_lag_tx_en_set(mlxsw_sp_port, + false); mlxsw_sp_port_lag_leave(mlxsw_sp_port, upper_dev); + } } else if (netif_is_ovs_master(upper_dev)) { if (info->linking) err = mlxsw_sp_port_ovs_join(mlxsw_sp_port); -- cgit v1.2.3-58-ga151 From 143a8e038ac599ca73c6354c8af6a8fdeee9fa7d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Jan 2019 16:48:06 +0000 Subject: mlxsw: spectrum: Add VXLAN dependency for spectrum When VXLAN is a loadable module, MLXSW_SPECTRUM must not be built-in: drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c:2547: undefined reference to `vxlan_fdb_find_uc' Add Kconfig dependency to enforce usable configurations. Fixes: 1231e04f5bba ("mlxsw: spectrum_switchdev: Add support for VxLAN encapsulation") Signed-off-by: Ido Schimmel Reported-by: kbuild test robot Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig index 080ddd1942ec..b9a25aed5d11 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig @@ -78,6 +78,7 @@ config MLXSW_SPECTRUM depends on IPV6 || IPV6=n depends on NET_IPGRE || NET_IPGRE=n depends on IPV6_GRE || IPV6_GRE=n + depends on VXLAN || VXLAN=n select GENERIC_ALLOCATOR select PARMAN select OBJAGG -- cgit v1.2.3-58-ga151 From 457e20d659247a09524e276aed46f19d853701d0 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Jan 2019 16:48:07 +0000 Subject: mlxsw: spectrum_switchdev: Avoid returning errors in commit phase Drivers are not supposed to return errors in switchdev commit phase if they returned OK in prepare phase. Otherwise, a WARNING is emitted. However, when the offloading of a VXLAN tunnel is triggered by the addition of a VLAN on a local port, it is not possible to guarantee that the commit phase will succeed without doing a lot of work. In these cases, the artificial division between prepare and commit phase does not make sense, so simply do the work in the prepare phase. Fixes: d70e42b22dd4 ("mlxsw: spectrum: Enable VxLAN enslavement to VLAN-aware bridges") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 1bd2c6e15f8d..e8ce2307352b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1078,8 +1078,7 @@ static int mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port, struct mlxsw_sp_bridge_port *bridge_port, u16 vid, bool is_untagged, bool is_pvid, - struct netlink_ext_ack *extack, - struct switchdev_trans *trans) + struct netlink_ext_ack *extack) { u16 pvid = mlxsw_sp_port_pvid_determine(mlxsw_sp_port, vid, is_pvid); struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; @@ -1095,9 +1094,6 @@ mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port_vlan->bridge_port != bridge_port) return -EEXIST; - if (switchdev_trans_ph_prepare(trans)) - return 0; - if (!mlxsw_sp_port_vlan) { mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid); @@ -1188,6 +1184,9 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, return err; } + if (switchdev_trans_ph_commit(trans)) + return 0; + bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); if (WARN_ON(!bridge_port)) return -EINVAL; @@ -1200,7 +1199,7 @@ static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port, err = mlxsw_sp_bridge_port_vlan_add(mlxsw_sp_port, bridge_port, vid, flag_untagged, - flag_pvid, extack, trans); + flag_pvid, extack); if (err) return err; } @@ -3207,7 +3206,6 @@ mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_bridge_device *bridge_device, const struct net_device *vxlan_dev, u16 vid, bool flag_untagged, bool flag_pvid, - struct switchdev_trans *trans, struct netlink_ext_ack *extack) { struct vxlan_dev *vxlan = netdev_priv(vxlan_dev); @@ -3225,9 +3223,6 @@ mlxsw_sp_switchdev_vxlan_vlan_add(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_bridge_8021q_vxlan_dev_find(bridge_device->dev, vid)) return -EINVAL; - if (switchdev_trans_ph_prepare(trans)) - return 0; - if (!netif_running(vxlan_dev)) return 0; @@ -3345,6 +3340,9 @@ mlxsw_sp_switchdev_vxlan_vlans_add(struct net_device *vxlan_dev, port_obj_info->handled = true; + if (switchdev_trans_ph_commit(trans)) + return 0; + bridge_device = mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); if (!bridge_device) return -EINVAL; @@ -3358,8 +3356,7 @@ mlxsw_sp_switchdev_vxlan_vlans_add(struct net_device *vxlan_dev, err = mlxsw_sp_switchdev_vxlan_vlan_add(mlxsw_sp, bridge_device, vxlan_dev, vid, flag_untagged, - flag_pvid, trans, - extack); + flag_pvid, extack); if (err) return err; } -- cgit v1.2.3-58-ga151 From 412283eedc138381e24d8c1304a3c5b298c503c4 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Jan 2019 16:48:08 +0000 Subject: mlxsw: spectrum_nve: Replace error code with EINVAL Adding a VLAN on a port can trigger the offload of a VXLAN tunnel which is already a member in the VLAN. In case the configuration of the VXLAN is not supported, the driver would return -EOPNOTSUPP. This is problematic since bridge code does not interpret this as error, but rather that it should try to setup the VLAN using the 8021q driver instead of switchdev. Fixes: d70e42b22dd4 ("mlxsw: spectrum: Enable VxLAN enslavement to VLAN-aware bridges") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c index 0a31fff2516e..fb1c48c698f2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c @@ -816,14 +816,14 @@ int mlxsw_sp_nve_fid_enable(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fid *fid, ops = nve->nve_ops_arr[params->type]; if (!ops->can_offload(nve, params->dev, extack)) - return -EOPNOTSUPP; + return -EINVAL; memset(&config, 0, sizeof(config)); ops->nve_config(nve, params->dev, &config); if (nve->num_nve_tunnels && memcmp(&config, &nve->config, sizeof(config))) { NL_SET_ERR_MSG_MOD(extack, "Conflicting NVE tunnels configuration"); - return -EOPNOTSUPP; + return -EINVAL; } err = mlxsw_sp_nve_tunnel_init(mlxsw_sp, &config); -- cgit v1.2.3-58-ga151 From 16dc42e4511172aa3a4d49931597582c9ff78843 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Jan 2019 16:48:10 +0000 Subject: selftests: mlxsw: Add a test case for VLAN addition error flow Add a test case for the issue fixed by previous commit. In case the offloading of an unsupported VxLAN tunnel was triggered by adding the mapped VLAN to a local port, then error should be returned to the user. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- tools/testing/selftests/drivers/net/mlxsw/vxlan.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh b/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh index dcf9f4e913e0..ae6146ec5afd 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh @@ -847,6 +847,24 @@ sanitization_vlan_aware_test() log_test "vlan-aware - failed enslavement to vlan-aware bridge" + bridge vlan del vid 10 dev vxlan20 + bridge vlan add vid 20 dev vxlan20 pvid untagged + + # Test that offloading of an unsupported tunnel fails when it is + # triggered by addition of VLAN to a local port + RET=0 + + # TOS must be set to inherit + ip link set dev vxlan10 type vxlan tos 42 + + ip link set dev $swp1 master br0 + bridge vlan add vid 10 dev $swp1 &> /dev/null + check_fail $? + + log_test "vlan-aware - failed vlan addition to a local port" + + ip link set dev vxlan10 type vxlan tos inherit + ip link del dev vxlan20 ip link del dev vxlan10 ip link del dev br0 -- cgit v1.2.3-58-ga151 From 279737939a8194f02fa352ab4476a1b241f44ef4 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Jan 2019 16:48:11 +0000 Subject: net: bridge: Fix VLANs memory leak When adding / deleting VLANs to / from a bridge port, the bridge driver first tries to propagate the information via switchdev and falls back to the 8021q driver in case the underlying driver does not support switchdev. This can result in a memory leak [1] when VXLAN and mlxsw ports are enslaved to the bridge: $ ip link set dev vxlan0 master br0 # No mlxsw ports are enslaved to 'br0', so mlxsw ignores the switchdev # notification and the bridge driver adds the VLAN on 'vxlan0' via the # 8021q driver $ bridge vlan add vid 10 dev vxlan0 pvid untagged # mlxsw port is enslaved to the bridge $ ip link set dev swp1 master br0 # mlxsw processes the switchdev notification and the 8021q driver is # skipped $ bridge vlan del vid 10 dev vxlan0 This results in 'struct vlan_info' and 'struct vlan_vid_info' being leaked, as they were allocated by the 8021q driver during VLAN addition, but never freed as the 8021q driver was skipped during deletion. Fix this by introducing a new VLAN private flag that indicates whether the VLAN was added on the port by switchdev or the 8021q driver. If the VLAN was added by the 8021q driver, then we make sure to delete it via the 8021q driver as well. [1] unreferenced object 0xffff88822d20b1e8 (size 256): comm "bridge", pid 2532, jiffies 4295216998 (age 1188.830s) hex dump (first 32 bytes): e0 42 97 ce 81 88 ff ff 00 00 00 00 00 00 00 00 .B.............. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000f82d851d>] kmem_cache_alloc_trace+0x1be/0x330 [<00000000e0178b02>] vlan_vid_add+0x661/0x920 [<00000000218ebd5f>] __vlan_add+0x1be9/0x3a00 [<000000006eafa1ca>] nbp_vlan_add+0x8b3/0xd90 [<000000003535392c>] br_vlan_info+0x132/0x410 [<00000000aedaa9dc>] br_afspec+0x75c/0x870 [<00000000f5716133>] br_setlink+0x3dc/0x6d0 [<00000000aceca5e2>] rtnl_bridge_setlink+0x615/0xb30 [<00000000a2f2d23e>] rtnetlink_rcv_msg+0x3a3/0xa80 [<0000000064097e69>] netlink_rcv_skb+0x152/0x3c0 [<000000008be8d614>] rtnetlink_rcv+0x21/0x30 [<000000009ab2ca25>] netlink_unicast+0x52f/0x740 [<00000000e7d9ac96>] netlink_sendmsg+0x9c7/0xf50 [<000000005d1e2050>] sock_sendmsg+0xbe/0x120 [<00000000d51426bc>] ___sys_sendmsg+0x778/0x8f0 [<00000000b9d7b2cc>] __sys_sendmsg+0x112/0x270 unreferenced object 0xffff888227454308 (size 32): comm "bridge", pid 2532, jiffies 4295216998 (age 1188.882s) hex dump (first 32 bytes): 88 b2 20 2d 82 88 ff ff 88 b2 20 2d 82 88 ff ff .. -...... -.... 81 00 0a 00 01 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000f82d851d>] kmem_cache_alloc_trace+0x1be/0x330 [<0000000018050631>] vlan_vid_add+0x3e6/0x920 [<00000000218ebd5f>] __vlan_add+0x1be9/0x3a00 [<000000006eafa1ca>] nbp_vlan_add+0x8b3/0xd90 [<000000003535392c>] br_vlan_info+0x132/0x410 [<00000000aedaa9dc>] br_afspec+0x75c/0x870 [<00000000f5716133>] br_setlink+0x3dc/0x6d0 [<00000000aceca5e2>] rtnl_bridge_setlink+0x615/0xb30 [<00000000a2f2d23e>] rtnetlink_rcv_msg+0x3a3/0xa80 [<0000000064097e69>] netlink_rcv_skb+0x152/0x3c0 [<000000008be8d614>] rtnetlink_rcv+0x21/0x30 [<000000009ab2ca25>] netlink_unicast+0x52f/0x740 [<00000000e7d9ac96>] netlink_sendmsg+0x9c7/0xf50 [<000000005d1e2050>] sock_sendmsg+0xbe/0x120 [<00000000d51426bc>] ___sys_sendmsg+0x778/0x8f0 [<00000000b9d7b2cc>] __sys_sendmsg+0x112/0x270 Fixes: d70e42b22dd4 ("mlxsw: spectrum: Enable VxLAN enslavement to VLAN-aware bridges") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Cc: Roopa Prabhu Cc: Nikolay Aleksandrov Cc: bridge@lists.linux-foundation.org Acked-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_private.h | 1 + net/bridge/br_vlan.c | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d240b3e7919f..eabf8bf28a3f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -107,6 +107,7 @@ struct br_tunnel_info { /* private vlan flags */ enum { BR_VLFLAG_PER_PORT_STATS = BIT(0), + BR_VLFLAG_ADDED_BY_SWITCHDEV = BIT(1), }; /** diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 4a2f31157ef5..96abf8feb9dc 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -80,16 +80,18 @@ static bool __vlan_add_flags(struct net_bridge_vlan *v, u16 flags) } static int __vlan_vid_add(struct net_device *dev, struct net_bridge *br, - u16 vid, u16 flags, struct netlink_ext_ack *extack) + struct net_bridge_vlan *v, u16 flags, + struct netlink_ext_ack *extack) { int err; /* Try switchdev op first. In case it is not supported, fallback to * 8021q add. */ - err = br_switchdev_port_vlan_add(dev, vid, flags, extack); + err = br_switchdev_port_vlan_add(dev, v->vid, flags, extack); if (err == -EOPNOTSUPP) - return vlan_vid_add(dev, br->vlan_proto, vid); + return vlan_vid_add(dev, br->vlan_proto, v->vid); + v->priv_flags |= BR_VLFLAG_ADDED_BY_SWITCHDEV; return err; } @@ -121,19 +123,17 @@ static void __vlan_del_list(struct net_bridge_vlan *v) } static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, - u16 vid) + const struct net_bridge_vlan *v) { int err; /* Try switchdev op first. In case it is not supported, fallback to * 8021q del. */ - err = br_switchdev_port_vlan_del(dev, vid); - if (err == -EOPNOTSUPP) { - vlan_vid_del(dev, br->vlan_proto, vid); - return 0; - } - return err; + err = br_switchdev_port_vlan_del(dev, v->vid); + if (!(v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV)) + vlan_vid_del(dev, br->vlan_proto, v->vid); + return err == -EOPNOTSUPP ? 0 : err; } /* Returns a master vlan, if it didn't exist it gets created. In all cases a @@ -242,7 +242,7 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags, * This ensures tagged traffic enters the bridge when * promiscuous mode is disabled by br_manage_promisc(). */ - err = __vlan_vid_add(dev, br, v->vid, flags, extack); + err = __vlan_vid_add(dev, br, v, flags, extack); if (err) goto out; @@ -305,7 +305,7 @@ out_fdb_insert: out_filt: if (p) { - __vlan_vid_del(dev, br, v->vid); + __vlan_vid_del(dev, br, v); if (masterv) { if (v->stats && masterv->stats != v->stats) free_percpu(v->stats); @@ -338,7 +338,7 @@ static int __vlan_del(struct net_bridge_vlan *v) __vlan_delete_pvid(vg, v->vid); if (p) { - err = __vlan_vid_del(p->dev, p->br, v->vid); + err = __vlan_vid_del(p->dev, p->br, v); if (err) goto out; } else { -- cgit v1.2.3-58-ga151 From 289fb44df4e4c3fe977ee4b451e1d11e10227654 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Jan 2019 16:48:12 +0000 Subject: selftests: forwarding: Fix test for different devices When running the test on the Spectrum ASIC the generated packets are counted on the ingress filter and injected back to the pipeline because of the 'pass' action. The router block then drops the packets due to checksum error, as the test generates packets with zero checksum. When running the test on an emulator that is not as strict about checksum errors the test fails since packets are counted twice. Once by the emulated ASIC on its ingress filter and again by the kernel as the emulator does not perform checksum validation and allows the packets to be trapped by a matching host route. Fix this by changing the action to 'drop', which will prevent the packet from continuing further in the pipeline to the router block. For veth pairs this change is essentially a NOP given packets are only processed once (by the kernel). Fixes: a0b61f3d8ebf ("selftests: forwarding: vxlan_bridge_1d: Add an ECN decap test") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh index 56cef3b1c194..bb10e33690b2 100755 --- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh +++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh @@ -629,7 +629,7 @@ __test_ecn_decap() RET=0 tc filter add dev $h1 ingress pref 77 prot ip \ - flower ip_tos $decapped_tos action pass + flower ip_tos $decapped_tos action drop sleep 1 vxlan_encapped_ping_test v2 v1 192.0.2.17 \ $orig_inner_tos $orig_outer_tos \ -- cgit v1.2.3-58-ga151 From 674bed5df4cab8f96d04f7b99608883a48f9226b Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Jan 2019 16:48:13 +0000 Subject: mlxsw: spectrum_switchdev: Set PVID correctly during VLAN deletion When a VLAN is deleted from a bridge port we should not change the PVID unless the deleted VLAN is the PVID. Fixes: fe9ccc785de5 ("mlxsw: spectrum_switchdev: Don't batch VLAN operations") Signed-off-by: Ido Schimmel Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index e8ce2307352b..0abbaa0fbf14 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1807,7 +1807,7 @@ static void mlxsw_sp_bridge_port_vlan_del(struct mlxsw_sp_port *mlxsw_sp_port, struct mlxsw_sp_bridge_port *bridge_port, u16 vid) { - u16 pvid = mlxsw_sp_port->pvid == vid ? 0 : vid; + u16 pvid = mlxsw_sp_port->pvid == vid ? 0 : mlxsw_sp_port->pvid; struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); -- cgit v1.2.3-58-ga151 From 4fabf3bf93a194c7fa5288da3e0af37e4b943cf3 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 8 Jan 2019 16:48:14 +0000 Subject: selftests: forwarding: Add a test for VLAN deletion Add a VLAN on a bridge port, delete it and make sure the PVID VLAN is not affected. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../testing/selftests/net/forwarding/bridge_vlan_aware.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh index d8313d0438b7..04c6431b2bd8 100755 --- a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -1,7 +1,7 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 -ALL_TESTS="ping_ipv4 ping_ipv6 learning flooding" +ALL_TESTS="ping_ipv4 ping_ipv6 learning flooding vlan_deletion" NUM_NETIFS=4 CHECK_TC="yes" source lib.sh @@ -96,6 +96,19 @@ flooding() flood_test $swp2 $h1 $h2 } +vlan_deletion() +{ + # Test that the deletion of a VLAN on a bridge port does not affect + # the PVID VLAN + log_info "Add and delete a VLAN on bridge port $swp1" + + bridge vlan add vid 10 dev $swp1 + bridge vlan del vid 10 dev $swp1 + + ping_ipv4 + ping_ipv6 +} + trap cleanup EXIT setup_prepare -- cgit v1.2.3-58-ga151 From 310529e663ed975d564cf029f878583e70c3b8a3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 30 Dec 2018 17:27:43 +0100 Subject: netfilter: nf_tables: Fix for endless loop when dumping ruleset __nf_tables_dump_rules() stores the current idx value into cb->args[0] before returning to caller. With multiple chains present, cb->args[0] is therefore updated after each chain's rules have been traversed. This though causes the final nf_tables_dump_rules() run (which should return an skb->len of zero since no rules are left to dump) to continue dumping rules for each but the first chain. Fix this by moving the cb->args[0] update to nf_tables_dump_rules(). With no final action to be performed anymore in __nf_tables_dump_rules(), drop 'out_unfinished' jump label and 'rc' variable - instead return the appropriate value directly. Fixes: 241faeceb849c ("netfilter: nf_tables: Speed up selective rule dumps") Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 2b0a93300dd7..e3ddd8e95e58 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2304,7 +2304,6 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, struct net *net = sock_net(skb->sk); unsigned int s_idx = cb->args[0]; const struct nft_rule *rule; - int rc = 1; list_for_each_entry_rcu(rule, &chain->rules, list) { if (!nft_is_active(net, rule)) @@ -2321,16 +2320,13 @@ static int __nf_tables_dump_rules(struct sk_buff *skb, NLM_F_MULTI | NLM_F_APPEND, table->family, table, chain, rule) < 0) - goto out_unfinished; + return 1; nl_dump_check_consistent(cb, nlmsg_hdr(skb)); cont: (*idx)++; } - rc = 0; -out_unfinished: - cb->args[0] = *idx; - return rc; + return 0; } static int nf_tables_dump_rules(struct sk_buff *skb, @@ -2382,6 +2378,8 @@ static int nf_tables_dump_rules(struct sk_buff *skb, } done: rcu_read_unlock(); + + cb->args[0] = idx; return skb->len; } -- cgit v1.2.3-58-ga151 From b91d9036883793122cf6575ca4dfbfbdd201a83d Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Fri, 4 Jan 2019 17:56:16 +0900 Subject: netfilter: nf_tables: fix leaking object reference count There is no code that decreases the reference count of stateful objects in error path of the nft_add_set_elem(). this causes a leak of reference count of stateful objects. Test commands: $nft add table ip filter $nft add counter ip filter c1 $nft add map ip filter m1 { type ipv4_addr : counter \;} $nft add element ip filter m1 { 1 : c1 } $nft add element ip filter m1 { 1 : c1 } $nft delete element ip filter m1 { 1 } $nft delete counter ip filter c1 Result: Error: Could not process rule: Device or resource busy delete counter ip filter c1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ At the second 'nft add element ip filter m1 { 1 : c1 }', the reference count of the 'c1' is increased then it tries to insert into the 'm1'. but the 'm1' already has same element so it returns -EEXIST. But it doesn't decrease the reference count of the 'c1' in the error path. Due to a leak of the reference count of the 'c1', the 'c1' can't be removed by 'nft delete counter ip filter c1'. Fixes: 8aeff920dcc9 ("netfilter: nf_tables: add stateful object reference to set elements") Signed-off-by: Taehee Yoo Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index e3ddd8e95e58..dcea979423bc 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4506,6 +4506,8 @@ err6: err5: kfree(trans); err4: + if (obj) + obj->use--; kfree(elem.priv); err3: if (nla[NFTA_SET_ELEM_DATA] != NULL) -- cgit v1.2.3-58-ga151 From 715849ab31f8e57bbad84cc6c38912aeba6beb21 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 8 Jan 2019 23:18:58 +0100 Subject: netfilter: nf_tables: selective rule dump needs table to be specified Table needs to be specified for selective rule dumps per chain. Fixes: 241faeceb849c ("netfilter: nf_tables: Speed up selective rule dumps") Reported-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index dcea979423bc..fb07f6cfc719 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2350,7 +2350,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb, if (ctx && ctx->table && strcmp(ctx->table, table->name) != 0) continue; - if (ctx && ctx->chain) { + if (ctx && ctx->table && ctx->chain) { struct rhlist_head *list, *tmp; list = rhltable_lookup(&table->chains_ht, ctx->chain, -- cgit v1.2.3-58-ga151 From fe7553bef8d676d1d8b40666868b33ec39b9df5d Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 8 Jan 2019 16:11:27 -0500 Subject: drm/amdgpu: Don't ignore rc from drm_dp_mst_topology_mgr_resume() drm_dp_mst_topology_mgr_resume() returns whether or not it managed to find the topology in question after a suspend resume cycle, and the driver is supposed to check this value and disable MST accordingly if it's gone-in addition to sending a hotplug in order to notify userspace that something changed during suspend. Currently, amdgpu just makes the mistake of ignoring the return code from drm_dp_mst_topology_mgr_resume() which means that if a topology was removed in suspend, amdgpu never notices and assumes it's still connected which leads to all sorts of problems. So, fix this by actually checking the rc from drm_dp_mst_topology_mgr_resume(). Also, reformat the rest of the function while we're at it to fix the over-indenting. Signed-off-by: Lyude Paul Reviewed-by: Harry Wentland Cc: Jerry Zuo Cc: # v4.15+ Link: https://patchwork.freedesktop.org/patch/msgid/20190108211133.32564-2-lyude@redhat.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 32 ++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a9a28dbc3e24..127b1e8f58e6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -699,22 +699,36 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend) { struct amdgpu_dm_connector *aconnector; struct drm_connector *connector; + struct drm_dp_mst_topology_mgr *mgr; + int ret; + bool need_hotplug = false; drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - aconnector = to_amdgpu_dm_connector(connector); - if (aconnector->dc_link->type == dc_connection_mst_branch && - !aconnector->mst_port) { + list_for_each_entry(connector, &dev->mode_config.connector_list, + head) { + aconnector = to_amdgpu_dm_connector(connector); + if (aconnector->dc_link->type != dc_connection_mst_branch || + aconnector->mst_port) + continue; + + mgr = &aconnector->mst_mgr; - if (suspend) - drm_dp_mst_topology_mgr_suspend(&aconnector->mst_mgr); - else - drm_dp_mst_topology_mgr_resume(&aconnector->mst_mgr); - } + if (suspend) { + drm_dp_mst_topology_mgr_suspend(mgr); + } else { + ret = drm_dp_mst_topology_mgr_resume(mgr); + if (ret < 0) { + drm_dp_mst_topology_mgr_set_mst(mgr, false); + need_hotplug = true; + } + } } drm_modeset_unlock(&dev->mode_config.connection_mutex); + + if (need_hotplug) + drm_kms_helper_hotplug_event(dev); } /** -- cgit v1.2.3-58-ga151 From 2d1af6a11cb9d88e0e3dd10258904c437fe1b315 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 8 Jan 2019 16:11:28 -0500 Subject: drm/amdgpu: Don't fail resume process if resuming atomic state fails This is an ugly one unfortunately. Currently, all DRM drivers supporting atomic modesetting will save the state that userspace had set before suspending, then attempt to restore that state on resume. This probably worked very well at one point, like many other things, until DP MST came into the picture. While it's easy to restore state on normal display connectors that were disconnected during suspend regardless of their state post-resume, this can't really be done with MST because of the fact that setting up a downstream sink requires performing sideband transactions between the source and the MST hub, sending out the ACT packets, etc. Because of this, there isn't really a guarantee that we can restore the atomic state we had before suspend once we've resumed. This sucks pretty bad, but so far I haven't run into any compositors that this actually causes serious issues with. Most compositors will notice the hotplug we send afterwards, and then reprobe state. Since nouveau and i915 also don't fail the suspend/resume process due to failing to restore the atomic state, let's make amdgpu match this behavior. Better to resume the GPU properly, then to stop the process half way because of a potentially unavoidable atomic commit failure. Eventually, we'll have a real fix for this problem on the DRM level. But we've got some more important low-hanging fruit to deal with first. Signed-off-by: Lyude Paul Reviewed-by: Harry Wentland Cc: Jerry Zuo Cc: # v4.15+ Link: https://patchwork.freedesktop.org/patch/msgid/20190108211133.32564-3-lyude@redhat.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 127b1e8f58e6..34f35e9a3c46 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -912,7 +912,6 @@ static int dm_resume(void *handle) struct drm_plane_state *new_plane_state; struct dm_plane_state *dm_new_plane_state; enum dc_connection_type new_connection_type = dc_connection_none; - int ret; int i; /* power on hardware */ @@ -985,13 +984,13 @@ static int dm_resume(void *handle) } } - ret = drm_atomic_helper_resume(ddev, dm->cached_state); + drm_atomic_helper_resume(ddev, dm->cached_state); dm->cached_state = NULL; amdgpu_dm_irq_resume_late(adev); - return ret; + return 0; } /** -- cgit v1.2.3-58-ga151 From c235316d935a19deedc2fc48076798c9a56e1a7c Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 8 Jan 2019 16:11:29 -0500 Subject: drm/dp_mst: Add __must_check to drm_dp_mst_topology_mgr_resume() Since I've had to fix two cases of drivers not checking the return code from this function, let's make the compiler complain so this doesn't come up again in the future. Changes since v1: * Remove unneeded __must_check in function declaration - danvet Signed-off-by: Lyude Paul Cc: Jerry Zuo Reviewed-by: Daniel Vetter Reviewed-by: Harry Wentland Link: https://patchwork.freedesktop.org/patch/msgid/20190108211133.32564-4-lyude@redhat.com --- include/drm/drm_dp_mst_helper.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 59f005b419cf..727af08e5ea6 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -616,7 +616,8 @@ void drm_dp_mst_dump_topology(struct seq_file *m, struct drm_dp_mst_topology_mgr *mgr); void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); -int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); +int __must_check +drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, -- cgit v1.2.3-58-ga151 From 19a220dd1e8a1b1d8e5e2f8f4a25313c4b02d527 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 28 Aug 2018 14:27:35 +0200 Subject: arm64: defconfig: enable modules for amlogic s400 sound card Compile the necessary drivers as modules, including codecs, for the s400 sound card. Signed-off-by: Jerome Brunet Signed-off-by: Kevin Hilman --- arch/arm64/configs/defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 3ef443cfbab6..c8432e24207e 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -506,11 +506,15 @@ CONFIG_SND_SOC_ROCKCHIP=m CONFIG_SND_SOC_ROCKCHIP_SPDIF=m CONFIG_SND_SOC_ROCKCHIP_RT5645=m CONFIG_SND_SOC_RK3399_GRU_SOUND=m +CONFIG_SND_MESON_AXG_SOUND_CARD=m CONFIG_SND_SOC_SAMSUNG=y CONFIG_SND_SOC_RCAR=m CONFIG_SND_SOC_AK4613=m CONFIG_SND_SIMPLE_CARD=m CONFIG_SND_AUDIO_GRAPH_CARD=m +CONFIG_SND_SOC_ES7134=m +CONFIG_SND_SOC_ES7241=m +CONFIG_SND_SOC_TAS571X=m CONFIG_I2C_HID=m CONFIG_USB=y CONFIG_USB_OTG=y -- cgit v1.2.3-58-ga151 From 917cb8a72a94d198073ad1e087685f801292042d Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 7 Jan 2019 11:01:13 -0800 Subject: RDMA/cma: Add cm_id restrack resource based on kernel or user cm_id type A recent regression causes a null ptr crash when dumping cm_id resources. The cma is incorrectly adding all cm_id restrack resources as kernel mode. Fixes: af8d70375d56 ("RDMA/restrack: Resource-tracker should not use uobject pointers") Signed-off-by: Steve Wise Reviewed-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/core/cma.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 63a7cc00bae0..84f077b2b90a 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -494,7 +494,10 @@ static void _cma_attach_to_dev(struct rdma_id_private *id_priv, id_priv->id.route.addr.dev_addr.transport = rdma_node_get_transport(cma_dev->device->node_type); list_add_tail(&id_priv->list, &cma_dev->id_list); - rdma_restrack_kadd(&id_priv->res); + if (id_priv->res.kern_name) + rdma_restrack_kadd(&id_priv->res); + else + rdma_restrack_uadd(&id_priv->res); } static void cma_attach_to_dev(struct rdma_id_private *id_priv, -- cgit v1.2.3-58-ga151 From 1d69a3f8ae77e3dbfdc1356225cce5ea9c366aec Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Tue, 8 Jan 2019 15:22:53 -0800 Subject: zram: idle writeback fixes and cleanup This patch includes some fixes and cleanup for idle-page writeback. 1. writeback_limit interface Now writeback_limit interface is rather conusing. For example, once writeback limit budget is exausted, admin can see 0 from /sys/block/zramX/writeback_limit which is same semantic with disable writeback_limit at this moment. IOW, admin cannot tell that zero came from disable writeback limit or exausted writeback limit. To make the interface clear, let's sepatate enable of writeback limit to another knob - /sys/block/zram0/writeback_limit_enable * before: while true : # to re-enable writeback limit once previous one is used up echo 0 > /sys/block/zram0/writeback_limit echo $((200<<20)) > /sys/block/zram0/writeback_limit .. .. # used up the writeback limit budget * new # To enable writeback limit, from the beginning, admin should # enable it. echo $((200<<20)) > /sys/block/zram0/writeback_limit echo 1 > /sys/block/zram/0/writeback_limit_enable while true : echo $((200<<20)) > /sys/block/zram0/writeback_limit .. .. # used up the writeback limit budget It's much strightforward. 2. fix condition check idle/huge writeback mode check The mode in writeback_store is not bit opeartion any more so no need to use bit operations. Furthermore, current condition check is broken in that it does writeback every pages regardless of huge/idle. 3. clean up idle_store No need to use goto. [minchan@kernel.org: missed spin_lock_init] Link: http://lkml.kernel.org/r/20190103001601.GA255139@google.com Link: http://lkml.kernel.org/r/20181224033529.19450-1-minchan@kernel.org Signed-off-by: Minchan Kim Suggested-by: John Dias Cc: Sergey Senozhatsky Cc: John Dias Cc: Srinivas Paladugu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ABI/testing/sysfs-block-zram | 11 +++- Documentation/blockdev/zram.txt | 74 +++++++++++++++--------- drivers/block/zram/zram_drv.c | 90 ++++++++++++++++++++++-------- drivers/block/zram/zram_drv.h | 5 +- 4 files changed, 125 insertions(+), 55 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-block-zram b/Documentation/ABI/testing/sysfs-block-zram index 9d2339a485c8..14b2bf2e5105 100644 --- a/Documentation/ABI/testing/sysfs-block-zram +++ b/Documentation/ABI/testing/sysfs-block-zram @@ -122,11 +122,18 @@ Description: statistics (bd_count, bd_reads, bd_writes) in a format similar to block layer statistics file format. +What: /sys/block/zram/writeback_limit_enable +Date: November 2018 +Contact: Minchan Kim +Description: + The writeback_limit_enable file is read-write and specifies + eanbe of writeback_limit feature. "1" means eable the feature. + No limit "0" is the initial state. + What: /sys/block/zram/writeback_limit Date: November 2018 Contact: Minchan Kim Description: The writeback_limit file is read-write and specifies the maximum amount of writeback ZRAM can do. The limit could be changed - in run time and "0" means disable the limit. - No limit is the initial state. + in run time. diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt index 436c5e98e1b6..4df0ce271085 100644 --- a/Documentation/blockdev/zram.txt +++ b/Documentation/blockdev/zram.txt @@ -156,22 +156,23 @@ Per-device statistics are exported as various nodes under /sys/block/zram/ A brief description of exported device attributes. For more details please read Documentation/ABI/testing/sysfs-block-zram. -Name access description ----- ------ ----------- -disksize RW show and set the device's disk size -initstate RO shows the initialization state of the device -reset WO trigger device reset -mem_used_max WO reset the `mem_used_max' counter (see later) -mem_limit WO specifies the maximum amount of memory ZRAM can use - to store the compressed data -writeback_limit WO specifies the maximum amount of write IO zram can - write out to backing device as 4KB unit -max_comp_streams RW the number of possible concurrent compress operations -comp_algorithm RW show and change the compression algorithm -compact WO trigger memory compaction -debug_stat RO this file is used for zram debugging purposes -backing_dev RW set up backend storage for zram to write out -idle WO mark allocated slot as idle +Name access description +---- ------ ----------- +disksize RW show and set the device's disk size +initstate RO shows the initialization state of the device +reset WO trigger device reset +mem_used_max WO reset the `mem_used_max' counter (see later) +mem_limit WO specifies the maximum amount of memory ZRAM can use + to store the compressed data +writeback_limit WO specifies the maximum amount of write IO zram can + write out to backing device as 4KB unit +writeback_limit_enable RW show and set writeback_limit feature +max_comp_streams RW the number of possible concurrent compress operations +comp_algorithm RW show and change the compression algorithm +compact WO trigger memory compaction +debug_stat RO this file is used for zram debugging purposes +backing_dev RW set up backend storage for zram to write out +idle WO mark allocated slot as idle User space is advised to use the following files to read the device statistics. @@ -280,32 +281,51 @@ With the command, zram writeback idle pages from memory to the storage. If there are lots of write IO with flash device, potentially, it has flash wearout problem so that admin needs to design write limitation to guarantee storage health for entire product life. -To overcome the concern, zram supports "writeback_limit". -The "writeback_limit"'s default value is 0 so that it doesn't limit -any writeback. If admin want to measure writeback count in a certain -period, he could know it via /sys/block/zram0/bd_stat's 3rd column. + +To overcome the concern, zram supports "writeback_limit" feature. +The "writeback_limit_enable"'s default value is 0 so that it doesn't limit +any writeback. IOW, if admin want to apply writeback budget, he should +enable writeback_limit_enable via + + $ echo 1 > /sys/block/zramX/writeback_limit_enable + +Once writeback_limit_enable is set, zram doesn't allow any writeback +until admin set the budget via /sys/block/zramX/writeback_limit. + +(If admin doesn't enable writeback_limit_enable, writeback_limit's value +assigned via /sys/block/zramX/writeback_limit is meaninless.) If admin want to limit writeback as per-day 400M, he could do it like below. - MB_SHIFT=20 - 4K_SHIFT=12 - echo $((400<>4K_SHIFT)) > \ - /sys/block/zram0/writeback_limit. + $ MB_SHIFT=20 + $ 4K_SHIFT=12 + $ echo $((400<>4K_SHIFT)) > \ + /sys/block/zram0/writeback_limit. + $ echo 1 > /sys/block/zram0/writeback_limit_enable -If admin want to allow further write again, he could do it like below +If admin want to allow further write again once the bugdet is exausted, +he could do it like below - echo 0 > /sys/block/zram0/writeback_limit + $ echo $((400<>4K_SHIFT)) > \ + /sys/block/zram0/writeback_limit If admin want to see remaining writeback budget since he set, - cat /sys/block/zram0/writeback_limit + $ cat /sys/block/zramX/writeback_limit + +If admin want to disable writeback limit, he could do + + $ echo 0 > /sys/block/zramX/writeback_limit_enable The writeback_limit count will reset whenever you reset zram(e.g., system reboot, echo 1 > /sys/block/zramX/reset) so keeping how many of writeback happened until you reset the zram to allocate extra writeback budget in next setting is user's job. +If admin want to measure writeback count in a certain period, he could +know it via /sys/block/zram0/bd_stat's 3rd column. + = memory tracking With CONFIG_ZRAM_MEMORY_TRACKING, user can know information of the diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 33c5cc879f24..04ca65912638 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -316,11 +316,9 @@ static ssize_t idle_store(struct device *dev, * See the comment in writeback_store. */ zram_slot_lock(zram, index); - if (!zram_allocated(zram, index) || - zram_test_flag(zram, index, ZRAM_UNDER_WB)) - goto next; - zram_set_flag(zram, index, ZRAM_IDLE); -next: + if (zram_allocated(zram, index) && + !zram_test_flag(zram, index, ZRAM_UNDER_WB)) + zram_set_flag(zram, index, ZRAM_IDLE); zram_slot_unlock(zram, index); } @@ -330,6 +328,41 @@ next: } #ifdef CONFIG_ZRAM_WRITEBACK +static ssize_t writeback_limit_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct zram *zram = dev_to_zram(dev); + u64 val; + ssize_t ret = -EINVAL; + + if (kstrtoull(buf, 10, &val)) + return ret; + + down_read(&zram->init_lock); + spin_lock(&zram->wb_limit_lock); + zram->wb_limit_enable = val; + spin_unlock(&zram->wb_limit_lock); + up_read(&zram->init_lock); + ret = len; + + return ret; +} + +static ssize_t writeback_limit_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool val; + struct zram *zram = dev_to_zram(dev); + + down_read(&zram->init_lock); + spin_lock(&zram->wb_limit_lock); + val = zram->wb_limit_enable; + spin_unlock(&zram->wb_limit_lock); + up_read(&zram->init_lock); + + return scnprintf(buf, PAGE_SIZE, "%d\n", val); +} + static ssize_t writeback_limit_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -341,9 +374,9 @@ static ssize_t writeback_limit_store(struct device *dev, return ret; down_read(&zram->init_lock); - atomic64_set(&zram->stats.bd_wb_limit, val); - if (val == 0) - zram->stop_writeback = false; + spin_lock(&zram->wb_limit_lock); + zram->bd_wb_limit = val; + spin_unlock(&zram->wb_limit_lock); up_read(&zram->init_lock); ret = len; @@ -357,7 +390,9 @@ static ssize_t writeback_limit_show(struct device *dev, struct zram *zram = dev_to_zram(dev); down_read(&zram->init_lock); - val = atomic64_read(&zram->stats.bd_wb_limit); + spin_lock(&zram->wb_limit_lock); + val = zram->bd_wb_limit; + spin_unlock(&zram->wb_limit_lock); up_read(&zram->init_lock); return scnprintf(buf, PAGE_SIZE, "%llu\n", val); @@ -588,8 +623,8 @@ static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, return 1; } -#define HUGE_WRITEBACK 0x1 -#define IDLE_WRITEBACK 0x2 +#define HUGE_WRITEBACK 1 +#define IDLE_WRITEBACK 2 static ssize_t writeback_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -602,7 +637,7 @@ static ssize_t writeback_store(struct device *dev, struct page *page; ssize_t ret, sz; char mode_buf[8]; - unsigned long mode = -1UL; + int mode = -1; unsigned long blk_idx = 0; sz = strscpy(mode_buf, buf, sizeof(mode_buf)); @@ -618,7 +653,7 @@ static ssize_t writeback_store(struct device *dev, else if (!strcmp(mode_buf, "huge")) mode = HUGE_WRITEBACK; - if (mode == -1UL) + if (mode == -1) return -EINVAL; down_read(&zram->init_lock); @@ -645,10 +680,13 @@ static ssize_t writeback_store(struct device *dev, bvec.bv_len = PAGE_SIZE; bvec.bv_offset = 0; - if (zram->stop_writeback) { + spin_lock(&zram->wb_limit_lock); + if (zram->wb_limit_enable && !zram->bd_wb_limit) { + spin_unlock(&zram->wb_limit_lock); ret = -EIO; break; } + spin_unlock(&zram->wb_limit_lock); if (!blk_idx) { blk_idx = alloc_block_bdev(zram); @@ -667,10 +705,11 @@ static ssize_t writeback_store(struct device *dev, zram_test_flag(zram, index, ZRAM_UNDER_WB)) goto next; - if ((mode & IDLE_WRITEBACK && - !zram_test_flag(zram, index, ZRAM_IDLE)) && - (mode & HUGE_WRITEBACK && - !zram_test_flag(zram, index, ZRAM_HUGE))) + if (mode == IDLE_WRITEBACK && + !zram_test_flag(zram, index, ZRAM_IDLE)) + goto next; + if (mode == HUGE_WRITEBACK && + !zram_test_flag(zram, index, ZRAM_HUGE)) goto next; /* * Clearing ZRAM_UNDER_WB is duty of caller. @@ -732,11 +771,10 @@ static ssize_t writeback_store(struct device *dev, zram_set_element(zram, index, blk_idx); blk_idx = 0; atomic64_inc(&zram->stats.pages_stored); - if (atomic64_add_unless(&zram->stats.bd_wb_limit, - -1 << (PAGE_SHIFT - 12), 0)) { - if (atomic64_read(&zram->stats.bd_wb_limit) == 0) - zram->stop_writeback = true; - } + spin_lock(&zram->wb_limit_lock); + if (zram->wb_limit_enable && zram->bd_wb_limit > 0) + zram->bd_wb_limit -= 1UL << (PAGE_SHIFT - 12); + spin_unlock(&zram->wb_limit_lock); next: zram_slot_unlock(zram, index); } @@ -1812,6 +1850,7 @@ static DEVICE_ATTR_RW(comp_algorithm); static DEVICE_ATTR_RW(backing_dev); static DEVICE_ATTR_WO(writeback); static DEVICE_ATTR_RW(writeback_limit); +static DEVICE_ATTR_RW(writeback_limit_enable); #endif static struct attribute *zram_disk_attrs[] = { @@ -1828,6 +1867,7 @@ static struct attribute *zram_disk_attrs[] = { &dev_attr_backing_dev.attr, &dev_attr_writeback.attr, &dev_attr_writeback_limit.attr, + &dev_attr_writeback_limit_enable.attr, #endif &dev_attr_io_stat.attr, &dev_attr_mm_stat.attr, @@ -1867,7 +1907,9 @@ static int zram_add(void) device_id = ret; init_rwsem(&zram->init_lock); - +#ifdef CONFIG_ZRAM_WRITEBACK + spin_lock_init(&zram->wb_limit_lock); +#endif queue = blk_alloc_queue(GFP_KERNEL); if (!queue) { pr_err("Error allocating disk queue for device %d\n", diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index 4bd3afd15e83..f2fd46daa760 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -86,7 +86,6 @@ struct zram_stats { atomic64_t bd_count; /* no. of pages in backing device */ atomic64_t bd_reads; /* no. of reads from backing device */ atomic64_t bd_writes; /* no. of writes from backing device */ - atomic64_t bd_wb_limit; /* writeback limit of backing device */ #endif }; @@ -114,8 +113,10 @@ struct zram { */ bool claim; /* Protected by bdev->bd_mutex */ struct file *backing_dev; - bool stop_writeback; #ifdef CONFIG_ZRAM_WRITEBACK + spinlock_t wb_limit_lock; + bool wb_limit_enable; + u64 bd_wb_limit; struct block_device *bdev; unsigned int old_block_size; unsigned long *bitmap; -- cgit v1.2.3-58-ga151 From ba4a45746c362b665e245c50b870615f02f34781 Mon Sep 17 00:00:00 2001 From: Shakeel Butt Date: Tue, 8 Jan 2019 15:22:57 -0800 Subject: fork, memcg: fix cached_stacks case Commit 5eed6f1dff87 ("fork,memcg: fix crash in free_thread_stack on memcg charge fail") fixes a crash caused due to failed memcg charge of the kernel stack. However the fix misses the cached_stacks case which this patch fixes. So, the same crash can happen if the memcg charge of a cached stack is failed. Link: http://lkml.kernel.org/r/20190102180145.57406-1-shakeelb@google.com Fixes: 5eed6f1dff87 ("fork,memcg: fix crash in free_thread_stack on memcg charge fail") Signed-off-by: Shakeel Butt Acked-by: Michal Hocko Acked-by: Rik van Riel Cc: Rik van Riel Cc: Roman Gushchin Cc: Johannes Weiner Cc: Tejun Heo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/fork.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/fork.c b/kernel/fork.c index a60459947f18..5ad60d47f7e7 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -217,6 +217,7 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node) memset(s->addr, 0, THREAD_SIZE); tsk->stack_vm_area = s; + tsk->stack = s->addr; return s->addr; } -- cgit v1.2.3-58-ga151 From 09c2e76ed734a1d36470d257a778aaba28e86531 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Tue, 8 Jan 2019 15:23:00 -0800 Subject: slab: alien caches must not be initialized if the allocation of the alien cache failed Callers of __alloc_alien() check for NULL. We must do the same check in __alloc_alien_cache to avoid NULL pointer dereferences on allocation failures. Link: http://lkml.kernel.org/r/010001680f42f192-82b4e12e-1565-4ee0-ae1f-1e98974906aa-000000@email.amazonses.com Fixes: 49dfc304ba241 ("slab: use the lock on alien_cache, instead of the lock on array_cache") Fixes: c8522a3a5832b ("Slab: introduce alloc_alien") Signed-off-by: Christoph Lameter Reported-by: syzbot+d6ed4ec679652b4fd4e4@syzkaller.appspotmail.com Reviewed-by: Andrew Morton Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index 73fe23e649c9..78eb8c5bf4e4 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -666,8 +666,10 @@ static struct alien_cache *__alloc_alien_cache(int node, int entries, struct alien_cache *alc = NULL; alc = kmalloc_node(memsize, gfp, node); - init_arraycache(&alc->ac, entries, batch); - spin_lock_init(&alc->lock); + if (alc) { + init_arraycache(&alc->ac, entries, batch); + spin_lock_init(&alc->lock); + } return alc; } -- cgit v1.2.3-58-ga151 From 7bff3c06997374fb9b9991536a547b840549a813 Mon Sep 17 00:00:00 2001 From: Qian Cai Date: Tue, 8 Jan 2019 15:23:04 -0800 Subject: mm/usercopy.c: no check page span for stack objects It is easy to trigger this with CONFIG_HARDENED_USERCOPY_PAGESPAN=y, usercopy: Kernel memory overwrite attempt detected to spans multiple pages (offset 0, size 23)! kernel BUG at mm/usercopy.c:102! For example, print_worker_info char name[WQ_NAME_LEN] = { }; char desc[WORKER_DESC_LEN] = { }; probe_kernel_read(name, wq->name, sizeof(name) - 1); probe_kernel_read(desc, worker->desc, sizeof(desc) - 1); __copy_from_user_inatomic check_object_size check_heap_object check_page_span This is because on-stack variables could cross PAGE_SIZE boundary, and failed this check, if (likely(((unsigned long)ptr & (unsigned long)PAGE_MASK) == ((unsigned long)end & (unsigned long)PAGE_MASK))) ptr = FFFF889007D7EFF8 end = FFFF889007D7F00E Hence, fix it by checking if it is a stack object first. [keescook@chromium.org: improve comments after reorder] Link: http://lkml.kernel.org/r/20190103165151.GA32845@beast Link: http://lkml.kernel.org/r/20181231030254.99441-1-cai@lca.pw Signed-off-by: Qian Cai Signed-off-by: Kees Cook Acked-by: Kees Cook Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/usercopy.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mm/usercopy.c b/mm/usercopy.c index 852eb4e53f06..14faadcedd06 100644 --- a/mm/usercopy.c +++ b/mm/usercopy.c @@ -247,7 +247,8 @@ static DEFINE_STATIC_KEY_FALSE_RO(bypass_usercopy_checks); /* * Validates that the given object is: * - not bogus address - * - known-safe heap or stack object + * - fully contained by stack (or stack frame, when available) + * - fully within SLAB object (or object whitelist area, when available) * - not in kernel text */ void __check_object_size(const void *ptr, unsigned long n, bool to_user) @@ -262,9 +263,6 @@ void __check_object_size(const void *ptr, unsigned long n, bool to_user) /* Check for invalid addresses. */ check_bogus_address((const unsigned long)ptr, n, to_user); - /* Check for bad heap object. */ - check_heap_object(ptr, n, to_user); - /* Check for bad stack object. */ switch (check_stack_object(ptr, n)) { case NOT_STACK: @@ -282,6 +280,9 @@ void __check_object_size(const void *ptr, unsigned long n, bool to_user) usercopy_abort("process stack", NULL, to_user, 0, n); } + /* Check for bad heap object. */ + check_heap_object(ptr, n, to_user); + /* Check for object in kernel to avoid text exposure. */ check_kernel_text_object((const unsigned long)ptr, n, to_user); } -- cgit v1.2.3-58-ga151 From 63f3655f950186752236bb88a22f8252c11ce394 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 8 Jan 2019 15:23:07 -0800 Subject: mm, memcg: fix reclaim deadlock with writeback Liu Bo has experienced a deadlock between memcg (legacy) reclaim and the ext4 writeback task1: wait_on_page_bit+0x82/0xa0 shrink_page_list+0x907/0x960 shrink_inactive_list+0x2c7/0x680 shrink_node_memcg+0x404/0x830 shrink_node+0xd8/0x300 do_try_to_free_pages+0x10d/0x330 try_to_free_mem_cgroup_pages+0xd5/0x1b0 try_charge+0x14d/0x720 memcg_kmem_charge_memcg+0x3c/0xa0 memcg_kmem_charge+0x7e/0xd0 __alloc_pages_nodemask+0x178/0x260 alloc_pages_current+0x95/0x140 pte_alloc_one+0x17/0x40 __pte_alloc+0x1e/0x110 alloc_set_pte+0x5fe/0xc20 do_fault+0x103/0x970 handle_mm_fault+0x61e/0xd10 __do_page_fault+0x252/0x4d0 do_page_fault+0x30/0x80 page_fault+0x28/0x30 task2: __lock_page+0x86/0xa0 mpage_prepare_extent_to_map+0x2e7/0x310 [ext4] ext4_writepages+0x479/0xd60 do_writepages+0x1e/0x30 __writeback_single_inode+0x45/0x320 writeback_sb_inodes+0x272/0x600 __writeback_inodes_wb+0x92/0xc0 wb_writeback+0x268/0x300 wb_workfn+0xb4/0x390 process_one_work+0x189/0x420 worker_thread+0x4e/0x4b0 kthread+0xe6/0x100 ret_from_fork+0x41/0x50 He adds "task1 is waiting for the PageWriteback bit of the page that task2 has collected in mpd->io_submit->io_bio, and tasks2 is waiting for the LOCKED bit the page which tasks1 has locked" More precisely task1 is handling a page fault and it has a page locked while it charges a new page table to a memcg. That in turn hits a memory limit reclaim and the memcg reclaim for legacy controller is waiting on the writeback but that is never going to finish because the writeback itself is waiting for the page locked in the #PF path. So this is essentially ABBA deadlock: lock_page(A) SetPageWriteback(A) unlock_page(A) lock_page(B) lock_page(B) pte_alloc_pne shrink_page_list wait_on_page_writeback(A) SetPageWriteback(B) unlock_page(B) # flush A, B to clear the writeback This accumulating of more pages to flush is used by several filesystems to generate a more optimal IO patterns. Waiting for the writeback in legacy memcg controller is a workaround for pre-mature OOM killer invocations because there is no dirty IO throttling available for the controller. There is no easy way around that unfortunately. Therefore fix this specific issue by pre-allocating the page table outside of the page lock. We have that handy infrastructure for that already so simply reuse the fault-around pattern which already does this. There are probably other hidden __GFP_ACCOUNT | GFP_KERNEL allocations from under a fs page locked but they should be really rare. I am not aware of a better solution unfortunately. [akpm@linux-foundation.org: fix mm/memory.c:__do_fault()] [akpm@linux-foundation.org: coding-style fixes] [mhocko@kernel.org: enhance comment, per Johannes] Link: http://lkml.kernel.org/r/20181214084948.GA5624@dhcp22.suse.cz Link: http://lkml.kernel.org/r/20181213092221.27270-1-mhocko@kernel.org Fixes: c3b94f44fcb0 ("memcg: further prevent OOM with too many dirty pages") Signed-off-by: Michal Hocko Reported-by: Liu Bo Debugged-by: Liu Bo Acked-by: Kirill A. Shutemov Acked-by: Johannes Weiner Reviewed-by: Liu Bo Cc: Jan Kara Cc: Dave Chinner Cc: Theodore Ts'o Cc: Vladimir Davydov Cc: Shakeel Butt Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/mm/memory.c b/mm/memory.c index a52663c0612d..5e46836714dc 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2994,6 +2994,28 @@ static vm_fault_t __do_fault(struct vm_fault *vmf) struct vm_area_struct *vma = vmf->vma; vm_fault_t ret; + /* + * Preallocate pte before we take page_lock because this might lead to + * deadlocks for memcg reclaim which waits for pages under writeback: + * lock_page(A) + * SetPageWriteback(A) + * unlock_page(A) + * lock_page(B) + * lock_page(B) + * pte_alloc_pne + * shrink_page_list + * wait_on_page_writeback(A) + * SetPageWriteback(B) + * unlock_page(B) + * # flush A, B to clear the writeback + */ + if (pmd_none(*vmf->pmd) && !vmf->prealloc_pte) { + vmf->prealloc_pte = pte_alloc_one(vmf->vma->vm_mm); + if (!vmf->prealloc_pte) + return VM_FAULT_OOM; + smp_wmb(); /* See comment in __pte_alloc() */ + } + ret = vma->vm_ops->fault(vmf); if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY | VM_FAULT_DONE_COW))) -- cgit v1.2.3-58-ga151 From eb214f2dda31ffa989033b1e0f848ba0d3cb6188 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Tue, 8 Jan 2019 15:23:11 -0800 Subject: kasan, arm64: use ARCH_SLAB_MINALIGN instead of manual aligning Instead of changing cache->align to be aligned to KASAN_SHADOW_SCALE_SIZE in kasan_cache_create() we can reuse the ARCH_SLAB_MINALIGN macro. Link: http://lkml.kernel.org/r/52ddd881916bcc153a9924c154daacde78522227.1546540962.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov Suggested-by: Vincenzo Frascino Cc: Andrey Ryabinin Cc: Christoph Lameter Cc: Dmitry Vyukov Cc: Mark Rutland Cc: Vincenzo Frascino Cc: Will Deacon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm64/include/asm/cache.h | 6 ++++++ mm/kasan/common.c | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h index 13dd42c3ad4e..eb43e09c1980 100644 --- a/arch/arm64/include/asm/cache.h +++ b/arch/arm64/include/asm/cache.h @@ -58,6 +58,12 @@ */ #define ARCH_DMA_MINALIGN (128) +#ifdef CONFIG_KASAN_SW_TAGS +#define ARCH_SLAB_MINALIGN (1ULL << KASAN_SHADOW_SCALE_SHIFT) +#else +#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long) +#endif + #ifndef __ASSEMBLY__ #include diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 03d5d1374ca7..44390392d4c9 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -298,8 +298,6 @@ void kasan_cache_create(struct kmem_cache *cache, unsigned int *size, return; } - cache->align = round_up(cache->align, KASAN_SHADOW_SCALE_SIZE); - *flags |= SLAB_KASAN; } -- cgit v1.2.3-58-ga151 From 96fedce27e1356a2fff1c270710d9405848db562 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Tue, 8 Jan 2019 15:23:15 -0800 Subject: kasan: make tag based mode work with CONFIG_HARDENED_USERCOPY With CONFIG_HARDENED_USERCOPY enabled __check_heap_object() compares and then subtracts a potentially tagged pointer with a non-tagged address of the page that this pointer belongs to, which leads to unexpected behavior. Untag the pointer in __check_heap_object() before doing any of these operations. Link: http://lkml.kernel.org/r/7e756a298d514c4482f52aea6151db34818d395d.1546540962.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Christoph Lameter Cc: Dmitry Vyukov Cc: Mark Rutland Cc: Vincenzo Frascino Cc: Will Deacon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/slub.c b/mm/slub.c index 36c0befeebd8..1e3d0ec4e200 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -3846,6 +3846,8 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page, unsigned int offset; size_t object_size; + ptr = kasan_reset_tag(ptr); + /* Find object and usable object size. */ s = page->slab_cache; -- cgit v1.2.3-58-ga151 From a3fe7cdf02e318870fb71218726cc2321ff41f30 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Tue, 8 Jan 2019 15:23:18 -0800 Subject: kasan: fix krealloc handling for tag-based mode Right now tag-based KASAN can retag the memory that is reallocated via krealloc and return a differently tagged pointer even if the same slab object gets used and no reallocated technically happens. There are a few issues with this approach. One is that krealloc callers can't rely on comparing the return value with the passed argument to check whether reallocation happened. Another is that if a caller knows that no reallocation happened, that it can access object memory through the old pointer, which leads to false positives. Look at nf_ct_ext_add() to see an example. Fix this by keeping the same tag if the memory don't actually gets reallocated during krealloc. Link: http://lkml.kernel.org/r/bb2a71d17ed072bcc528cbee46fcbd71a6da3be4.1546540962.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov Cc: Andrey Ryabinin Cc: Christoph Lameter Cc: Dmitry Vyukov Cc: Mark Rutland Cc: Vincenzo Frascino Cc: Will Deacon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/kasan/common.c | 63 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 44390392d4c9..73c9cbfdedf4 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -347,28 +347,43 @@ void kasan_poison_object_data(struct kmem_cache *cache, void *object) } /* - * Since it's desirable to only call object contructors once during slab - * allocation, we preassign tags to all such objects. Also preassign tags for - * SLAB_TYPESAFE_BY_RCU slabs to avoid use-after-free reports. - * For SLAB allocator we can't preassign tags randomly since the freelist is - * stored as an array of indexes instead of a linked list. Assign tags based - * on objects indexes, so that objects that are next to each other get - * different tags. - * After a tag is assigned, the object always gets allocated with the same tag. - * The reason is that we can't change tags for objects with constructors on - * reallocation (even for non-SLAB_TYPESAFE_BY_RCU), because the constructor - * code can save the pointer to the object somewhere (e.g. in the object - * itself). Then if we retag it, the old saved pointer will become invalid. + * This function assigns a tag to an object considering the following: + * 1. A cache might have a constructor, which might save a pointer to a slab + * object somewhere (e.g. in the object itself). We preassign a tag for + * each object in caches with constructors during slab creation and reuse + * the same tag each time a particular object is allocated. + * 2. A cache might be SLAB_TYPESAFE_BY_RCU, which means objects can be + * accessed after being freed. We preassign tags for objects in these + * caches as well. + * 3. For SLAB allocator we can't preassign tags randomly since the freelist + * is stored as an array of indexes instead of a linked list. Assign tags + * based on objects indexes, so that objects that are next to each other + * get different tags. */ -static u8 assign_tag(struct kmem_cache *cache, const void *object, bool new) +static u8 assign_tag(struct kmem_cache *cache, const void *object, + bool init, bool krealloc) { + /* Reuse the same tag for krealloc'ed objects. */ + if (krealloc) + return get_tag(object); + + /* + * If the cache neither has a constructor nor has SLAB_TYPESAFE_BY_RCU + * set, assign a tag when the object is being allocated (init == false). + */ if (!cache->ctor && !(cache->flags & SLAB_TYPESAFE_BY_RCU)) - return new ? KASAN_TAG_KERNEL : random_tag(); + return init ? KASAN_TAG_KERNEL : random_tag(); + /* For caches that either have a constructor or SLAB_TYPESAFE_BY_RCU: */ #ifdef CONFIG_SLAB + /* For SLAB assign tags based on the object index in the freelist. */ return (u8)obj_to_index(cache, virt_to_page(object), (void *)object); #else - return new ? random_tag() : get_tag(object); + /* + * For SLUB assign a random tag during slab creation, otherwise reuse + * the already assigned tag. + */ + return init ? random_tag() : get_tag(object); #endif } @@ -384,7 +399,8 @@ void * __must_check kasan_init_slab_obj(struct kmem_cache *cache, __memset(alloc_info, 0, sizeof(*alloc_info)); if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) - object = set_tag(object, assign_tag(cache, object, true)); + object = set_tag(object, + assign_tag(cache, object, true, false)); return (void *)object; } @@ -450,8 +466,8 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object, unsigned long ip) return __kasan_slab_free(cache, object, ip, true); } -void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, - size_t size, gfp_t flags) +static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, + size_t size, gfp_t flags, bool krealloc) { unsigned long redzone_start; unsigned long redzone_end; @@ -469,7 +485,7 @@ void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, KASAN_SHADOW_SCALE_SIZE); if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) - tag = assign_tag(cache, object, false); + tag = assign_tag(cache, object, false, krealloc); /* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ kasan_unpoison_shadow(set_tag(object, tag), size); @@ -481,6 +497,12 @@ void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, return set_tag(object, tag); } + +void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, + size_t size, gfp_t flags) +{ + return __kasan_kmalloc(cache, object, size, flags, false); +} EXPORT_SYMBOL(kasan_kmalloc); void * __must_check kasan_kmalloc_large(const void *ptr, size_t size, @@ -520,7 +542,8 @@ void * __must_check kasan_krealloc(const void *object, size_t size, gfp_t flags) if (unlikely(!PageSlab(page))) return kasan_kmalloc_large(object, size, flags); else - return kasan_kmalloc(page->slab_cache, object, size, flags); + return __kasan_kmalloc(page->slab_cache, object, size, + flags, true); } void kasan_poison_kfree(void *ptr, unsigned long ip) -- cgit v1.2.3-58-ga151 From aff876dcf4461f311adbdf39ce48c134b3f99c49 Mon Sep 17 00:00:00 2001 From: Miles Chen Date: Tue, 8 Jan 2019 15:23:22 -0800 Subject: tools/vm/page_owner: use page_owner_sort in the use example The example in comment does not useable because the output binary is named "page_owner_sort", not "sort". Also add a reference to Documentation/vm/page_owner.rst Link: http://lkml.kernel.org/r/1546515361-8317-1-git-send-email-miles.chen@mediatek.com Signed-off-by: Miles Chen Reviewed-by: Andrew Morton Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/vm/page_owner_sort.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/vm/page_owner_sort.c b/tools/vm/page_owner_sort.c index 18fc112b65cd..d3a8755c039c 100644 --- a/tools/vm/page_owner_sort.c +++ b/tools/vm/page_owner_sort.c @@ -5,7 +5,9 @@ * Example use: * cat /sys/kernel/debug/page_owner > page_owner_full.txt * grep -v ^PFN page_owner_full.txt > page_owner.txt - * ./sort page_owner.txt sorted_page_owner.txt + * ./page_owner_sort page_owner.txt sorted_page_owner.txt + * + * See Documentation/vm/page_owner.rst */ #include -- cgit v1.2.3-58-ga151 From 1ed7293ac40c5b1950b8ab21b6bc1838578ae2ad Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Jan 2019 15:23:25 -0800 Subject: mm/memory.c: initialise mmu_notifier_range correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One of the paths in follow_pte_pmd() initialised the mmu_notifier_range incorrectly. Link: http://lkml.kernel.org/r/20190103002126.GM6310@bombadil.infradead.org Fixes: ac46d4f3c432 ("mm/mmu_notifier: use structure for invalidate_range_start/end calls v2") Signed-off-by: Matthew Wilcox Tested-by: Dave Chinner Reviewed-by: Jérôme Glisse Cc: John Hubbard Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 5e46836714dc..e11ca9dd823f 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4099,8 +4099,8 @@ static int __follow_pte_pmd(struct mm_struct *mm, unsigned long address, goto out; if (range) { - range->start = address & PAGE_MASK; - range->end = range->start + PAGE_SIZE; + mmu_notifier_range_init(range, mm, address & PAGE_MASK, + (address & PAGE_MASK) + PAGE_SIZE); mmu_notifier_invalidate_range_start(range); } ptep = pte_offset_map_lock(mm, pmd, address, ptlp); -- cgit v1.2.3-58-ga151 From 8ab88c7169b7fba98812ead6524b9d05bc76cf00 Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Tue, 8 Jan 2019 15:23:28 -0800 Subject: mm: page_mapped: don't assume compound page is huge or THP LTP proc01 testcase has been observed to rarely trigger crashes on arm64: page_mapped+0x78/0xb4 stable_page_flags+0x27c/0x338 kpageflags_read+0xfc/0x164 proc_reg_read+0x7c/0xb8 __vfs_read+0x58/0x178 vfs_read+0x90/0x14c SyS_read+0x60/0xc0 The issue is that page_mapped() assumes that if compound page is not huge, then it must be THP. But if this is 'normal' compound page (COMPOUND_PAGE_DTOR), then following loop can keep running (for HPAGE_PMD_NR iterations) until it tries to read from memory that isn't mapped and triggers a panic: for (i = 0; i < hpage_nr_pages(page); i++) { if (atomic_read(&page[i]._mapcount) >= 0) return true; } I could replicate this on x86 (v4.20-rc4-98-g60b548237fed) only with a custom kernel module [1] which: - allocates compound page (PAGEC) of order 1 - allocates 2 normal pages (COPY), which are initialized to 0xff (to satisfy _mapcount >= 0) - 2 PAGEC page structs are copied to address of first COPY page - second page of COPY is marked as not present - call to page_mapped(COPY) now triggers fault on access to 2nd COPY page at offset 0x30 (_mapcount) [1] https://github.com/jstancek/reproducers/blob/master/kernel/page_mapped_crash/repro.c Fix the loop to iterate for "1 << compound_order" pages. Kirrill said "IIRC, sound subsystem can producuce custom mapped compound pages". Link: http://lkml.kernel.org/r/c440d69879e34209feba21e12d236d06bc0a25db.1543577156.git.jstancek@redhat.com Fixes: e1534ae95004 ("mm: differentiate page_mapped() from page_mapcount() for compound pages") Signed-off-by: Jan Stancek Debugged-by: Laszlo Ersek Suggested-by: "Kirill A. Shutemov" Acked-by: Michal Hocko Acked-by: Kirill A. Shutemov Reviewed-by: David Hildenbrand Reviewed-by: Andrea Arcangeli Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/util.c b/mm/util.c index 4df23d64aac7..1ea055138043 100644 --- a/mm/util.c +++ b/mm/util.c @@ -478,7 +478,7 @@ bool page_mapped(struct page *page) return true; if (PageHuge(page)) return false; - for (i = 0; i < hpage_nr_pages(page); i++) { + for (i = 0; i < (1 << compound_order(page)); i++) { if (atomic_read(&page[i]._mapcount) >= 0) return true; } -- cgit v1.2.3-58-ga151 From e7c58097793ef15d58fadf190ee58738fbf447cd Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Jan 2019 15:23:32 -0800 Subject: hugetlbfs: revert "Use i_mmap_rwsem to fix page fault/truncate race" This reverts c86aa7bbfd5568ba8a82d3635d8f7b8a8e06fe54 The reverted commit caused ABBA deadlocks when file migration raced with file eviction for specific hugetlbfs files. This was discovered with a modified version of the LTP move_pages12 test. The purpose of the reverted patch was to close a long existing race between hugetlbfs file truncation and page faults. After more analysis of the patch and impacted code, it was determined that i_mmap_rwsem can not be used for all required synchronization. Therefore, revert this patch while working an another approach to the underlying issue. Link: http://lkml.kernel.org/r/20190103235452.29335-1-mike.kravetz@oracle.com Signed-off-by: Mike Kravetz Reported-by: Jan Stancek Cc: Michal Hocko Cc: Hugh Dickins Cc: Naoya Horiguchi Cc: "Aneesh Kumar K . V" Cc: Andrea Arcangeli Cc: "Kirill A . Shutemov" Cc: Davidlohr Bueso Cc: Prakash Sangappa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hugetlbfs/inode.c | 61 ++++++++++++++++++++++++++++------------------------ mm/hugetlb.c | 21 +++++++++--------- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index a2fcea5f8225..32920a10100e 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -383,16 +383,17 @@ hugetlb_vmdelete_list(struct rb_root_cached *root, pgoff_t start, pgoff_t end) * truncation is indicated by end of range being LLONG_MAX * In this case, we first scan the range and release found pages. * After releasing pages, hugetlb_unreserve_pages cleans up region/reserv - * maps and global counts. + * maps and global counts. Page faults can not race with truncation + * in this routine. hugetlb_no_page() prevents page faults in the + * truncated range. It checks i_size before allocation, and again after + * with the page table lock for the page held. The same lock must be + * acquired to unmap a page. * hole punch is indicated if end is not LLONG_MAX * In the hole punch case we scan the range and release found pages. * Only when releasing a page is the associated region/reserv map * deleted. The region/reserv map for ranges without associated - * pages are not modified. - * - * Callers of this routine must hold the i_mmap_rwsem in write mode to prevent - * races with page faults. - * + * pages are not modified. Page faults can race with hole punch. + * This is indicated if we find a mapped page. * Note: If the passed end of range value is beyond the end of file, but * not LLONG_MAX this routine still performs a hole punch operation. */ @@ -422,14 +423,32 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart, for (i = 0; i < pagevec_count(&pvec); ++i) { struct page *page = pvec.pages[i]; + u32 hash; index = page->index; + hash = hugetlb_fault_mutex_hash(h, current->mm, + &pseudo_vma, + mapping, index, 0); + mutex_lock(&hugetlb_fault_mutex_table[hash]); + /* - * A mapped page is impossible as callers should unmap - * all references before calling. And, i_mmap_rwsem - * prevents the creation of additional mappings. + * If page is mapped, it was faulted in after being + * unmapped in caller. Unmap (again) now after taking + * the fault mutex. The mutex will prevent faults + * until we finish removing the page. + * + * This race can only happen in the hole punch case. + * Getting here in a truncate operation is a bug. */ - VM_BUG_ON(page_mapped(page)); + if (unlikely(page_mapped(page))) { + BUG_ON(truncate_op); + + i_mmap_lock_write(mapping); + hugetlb_vmdelete_list(&mapping->i_mmap, + index * pages_per_huge_page(h), + (index + 1) * pages_per_huge_page(h)); + i_mmap_unlock_write(mapping); + } lock_page(page); /* @@ -451,6 +470,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart, } unlock_page(page); + mutex_unlock(&hugetlb_fault_mutex_table[hash]); } huge_pagevec_release(&pvec); cond_resched(); @@ -462,20 +482,9 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart, static void hugetlbfs_evict_inode(struct inode *inode) { - struct address_space *mapping = inode->i_mapping; struct resv_map *resv_map; - /* - * The vfs layer guarantees that there are no other users of this - * inode. Therefore, it would be safe to call remove_inode_hugepages - * without holding i_mmap_rwsem. We acquire and hold here to be - * consistent with other callers. Since there will be no contention - * on the semaphore, overhead is negligible. - */ - i_mmap_lock_write(mapping); remove_inode_hugepages(inode, 0, LLONG_MAX); - i_mmap_unlock_write(mapping); - resv_map = (struct resv_map *)inode->i_mapping->private_data; /* root inode doesn't have the resv_map, so we should check it */ if (resv_map) @@ -496,8 +505,8 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) i_mmap_lock_write(mapping); if (!RB_EMPTY_ROOT(&mapping->i_mmap.rb_root)) hugetlb_vmdelete_list(&mapping->i_mmap, pgoff, 0); - remove_inode_hugepages(inode, offset, LLONG_MAX); i_mmap_unlock_write(mapping); + remove_inode_hugepages(inode, offset, LLONG_MAX); return 0; } @@ -531,8 +540,8 @@ static long hugetlbfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) hugetlb_vmdelete_list(&mapping->i_mmap, hole_start >> PAGE_SHIFT, hole_end >> PAGE_SHIFT); - remove_inode_hugepages(inode, hole_start, hole_end); i_mmap_unlock_write(mapping); + remove_inode_hugepages(inode, hole_start, hole_end); inode_unlock(inode); } @@ -615,11 +624,7 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, /* addr is the offset within the file (zero based) */ addr = index * hpage_size; - /* - * fault mutex taken here, protects against fault path - * and hole punch. inode_lock previously taken protects - * against truncation. - */ + /* mutex taken here, fault path and hole punch */ hash = hugetlb_fault_mutex_hash(h, mm, &pseudo_vma, mapping, index, addr); mutex_lock(&hugetlb_fault_mutex_table[hash]); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 745088810965..aedc1b183cf9 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3755,16 +3755,16 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm, } /* - * We can not race with truncation due to holding i_mmap_rwsem. - * Check once here for faults beyond end of file. + * Use page lock to guard against racing truncation + * before we get page_table_lock. */ - size = i_size_read(mapping->host) >> huge_page_shift(h); - if (idx >= size) - goto out; - retry: page = find_lock_page(mapping, idx); if (!page) { + size = i_size_read(mapping->host) >> huge_page_shift(h); + if (idx >= size) + goto out; + /* * Check for page in userfault range */ @@ -3854,6 +3854,9 @@ retry: } ptl = huge_pte_lock(h, mm, ptep); + size = i_size_read(mapping->host) >> huge_page_shift(h); + if (idx >= size) + goto backout; ret = 0; if (!huge_pte_none(huge_ptep_get(ptep))) @@ -3956,10 +3959,8 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, /* * Acquire i_mmap_rwsem before calling huge_pte_alloc and hold - * until finished with ptep. This serves two purposes: - * 1) It prevents huge_pmd_unshare from being called elsewhere - * and making the ptep no longer valid. - * 2) It synchronizes us with file truncation. + * until finished with ptep. This prevents huge_pmd_unshare from + * being called elsewhere and making the ptep no longer valid. * * ptep could have already be assigned via huge_pte_offset. That * is OK, as huge_pte_alloc will return the same value unless -- cgit v1.2.3-58-ga151 From ddeaab32a89f04b7e2a2df8771583a719c4ac6b7 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Jan 2019 15:23:36 -0800 Subject: hugetlbfs: revert "use i_mmap_rwsem for more pmd sharing synchronization" This reverts b43a9990055958e70347c56f90ea2ae32c67334c The reverted commit caused issues with migration and poisoning of anon huge pages. The LTP move_pages12 test will cause an "unable to handle kernel NULL pointer" BUG would occur with stack similar to: RIP: 0010:down_write+0x1b/0x40 Call Trace: migrate_pages+0x81f/0xb90 __ia32_compat_sys_migrate_pages+0x190/0x190 do_move_pages_to_node.isra.53.part.54+0x2a/0x50 kernel_move_pages+0x566/0x7b0 __x64_sys_move_pages+0x24/0x30 do_syscall_64+0x5b/0x180 entry_SYSCALL_64_after_hwframe+0x44/0xa9 The purpose of the reverted patch was to fix some long existing races with huge pmd sharing. It used i_mmap_rwsem for this purpose with the idea that this could also be used to address truncate/page fault races with another patch. Further analysis has determined that i_mmap_rwsem can not be used to address all these hugetlbfs synchronization issues. Therefore, revert this patch while working an another approach to the underlying issues. Link: http://lkml.kernel.org/r/20190103235452.29335-2-mike.kravetz@oracle.com Signed-off-by: Mike Kravetz Reported-by: Jan Stancek Cc: Michal Hocko Cc: Hugh Dickins Cc: Naoya Horiguchi Cc: "Aneesh Kumar K . V" Cc: Andrea Arcangeli Cc: "Kirill A . Shutemov" Cc: Davidlohr Bueso Cc: Prakash Sangappa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hugetlb.c | 64 +++++++++++++---------------------------------------- mm/memory-failure.c | 16 ++------------ mm/migrate.c | 13 +---------- mm/rmap.c | 4 ---- mm/userfaultfd.c | 11 ++------- 5 files changed, 20 insertions(+), 88 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index aedc1b183cf9..df2e7dd5ff17 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3238,7 +3238,6 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, struct page *ptepage; unsigned long addr; int cow; - struct address_space *mapping = vma->vm_file->f_mapping; struct hstate *h = hstate_vma(vma); unsigned long sz = huge_page_size(h); struct mmu_notifier_range range; @@ -3250,23 +3249,13 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, mmu_notifier_range_init(&range, src, vma->vm_start, vma->vm_end); mmu_notifier_invalidate_range_start(&range); - } else { - /* - * For shared mappings i_mmap_rwsem must be held to call - * huge_pte_alloc, otherwise the returned ptep could go - * away if part of a shared pmd and another thread calls - * huge_pmd_unshare. - */ - i_mmap_lock_read(mapping); } for (addr = vma->vm_start; addr < vma->vm_end; addr += sz) { spinlock_t *src_ptl, *dst_ptl; - src_pte = huge_pte_offset(src, addr, sz); if (!src_pte) continue; - dst_pte = huge_pte_alloc(dst, addr, sz); if (!dst_pte) { ret = -ENOMEM; @@ -3337,8 +3326,6 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, if (cow) mmu_notifier_invalidate_range_end(&range); - else - i_mmap_unlock_read(mapping); return ret; } @@ -3784,18 +3771,14 @@ retry: }; /* - * hugetlb_fault_mutex and i_mmap_rwsem must be - * dropped before handling userfault. Reacquire - * after handling fault to make calling code simpler. + * hugetlb_fault_mutex must be dropped before + * handling userfault. Reacquire after handling + * fault to make calling code simpler. */ hash = hugetlb_fault_mutex_hash(h, mm, vma, mapping, idx, haddr); mutex_unlock(&hugetlb_fault_mutex_table[hash]); - i_mmap_unlock_read(mapping); - ret = handle_userfault(&vmf, VM_UFFD_MISSING); - - i_mmap_lock_read(mapping); mutex_lock(&hugetlb_fault_mutex_table[hash]); goto out; } @@ -3943,11 +3926,6 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, ptep = huge_pte_offset(mm, haddr, huge_page_size(h)); if (ptep) { - /* - * Since we hold no locks, ptep could be stale. That is - * OK as we are only making decisions based on content and - * not actually modifying content here. - */ entry = huge_ptep_get(ptep); if (unlikely(is_hugetlb_entry_migration(entry))) { migration_entry_wait_huge(vma, mm, ptep); @@ -3955,31 +3933,20 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, } else if (unlikely(is_hugetlb_entry_hwpoisoned(entry))) return VM_FAULT_HWPOISON_LARGE | VM_FAULT_SET_HINDEX(hstate_index(h)); + } else { + ptep = huge_pte_alloc(mm, haddr, huge_page_size(h)); + if (!ptep) + return VM_FAULT_OOM; } - /* - * Acquire i_mmap_rwsem before calling huge_pte_alloc and hold - * until finished with ptep. This prevents huge_pmd_unshare from - * being called elsewhere and making the ptep no longer valid. - * - * ptep could have already be assigned via huge_pte_offset. That - * is OK, as huge_pte_alloc will return the same value unless - * something changed. - */ mapping = vma->vm_file->f_mapping; - i_mmap_lock_read(mapping); - ptep = huge_pte_alloc(mm, haddr, huge_page_size(h)); - if (!ptep) { - i_mmap_unlock_read(mapping); - return VM_FAULT_OOM; - } + idx = vma_hugecache_offset(h, vma, haddr); /* * Serialize hugepage allocation and instantiation, so that we don't * get spurious allocation failures if two CPUs race to instantiate * the same page in the page cache. */ - idx = vma_hugecache_offset(h, vma, haddr); hash = hugetlb_fault_mutex_hash(h, mm, vma, mapping, idx, haddr); mutex_lock(&hugetlb_fault_mutex_table[hash]); @@ -4067,7 +4034,6 @@ out_ptl: } out_mutex: mutex_unlock(&hugetlb_fault_mutex_table[hash]); - i_mmap_unlock_read(mapping); /* * Generally it's safe to hold refcount during waiting page lock. But * here we just wait to defer the next page fault to avoid busy loop and @@ -4672,12 +4638,10 @@ void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma, * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc() * and returns the corresponding pte. While this is not necessary for the * !shared pmd case because we can allocate the pmd later as well, it makes the - * code much cleaner. - * - * This routine must be called with i_mmap_rwsem held in at least read mode. - * For hugetlbfs, this prevents removal of any page table entries associated - * with the address space. This is important as we are setting up sharing - * based on existing page table entries (mappings). + * code much cleaner. pmd allocation is essential for the shared case because + * pud has to be populated inside the same i_mmap_rwsem section - otherwise + * racing tasks could either miss the sharing (see huge_pte_offset) or select a + * bad pmd for sharing. */ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud) { @@ -4694,6 +4658,7 @@ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud) if (!vma_shareable(vma, addr)) return (pte_t *)pmd_alloc(mm, pud, addr); + i_mmap_lock_write(mapping); vma_interval_tree_foreach(svma, &mapping->i_mmap, idx, idx) { if (svma == vma) continue; @@ -4723,6 +4688,7 @@ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud) spin_unlock(ptl); out: pte = (pte_t *)pmd_alloc(mm, pud, addr); + i_mmap_unlock_write(mapping); return pte; } @@ -4733,7 +4699,7 @@ out: * indicated by page_count > 1, unmap is achieved by clearing pud and * decrementing the ref count. If count == 1, the pte page is not shared. * - * Called with page table lock held and i_mmap_rwsem held in write mode. + * called with page table lock held. * * returns: 1 successfully unmapped a shared pte page * 0 the underlying pte page is not shared, or it is the last user diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 6379fff1a5ff..7c72f2a95785 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -966,7 +966,7 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn, enum ttu_flags ttu = TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS; struct address_space *mapping; LIST_HEAD(tokill); - bool unmap_success = true; + bool unmap_success; int kill = 1, forcekill; struct page *hpage = *hpagep; bool mlocked = PageMlocked(hpage); @@ -1028,19 +1028,7 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn, if (kill) collect_procs(hpage, &tokill, flags & MF_ACTION_REQUIRED); - if (!PageHuge(hpage)) { - unmap_success = try_to_unmap(hpage, ttu); - } else if (mapping) { - /* - * For hugetlb pages, try_to_unmap could potentially call - * huge_pmd_unshare. Because of this, take semaphore in - * write mode here and set TTU_RMAP_LOCKED to indicate we - * have taken the lock at this higer level. - */ - i_mmap_lock_write(mapping); - unmap_success = try_to_unmap(hpage, ttu|TTU_RMAP_LOCKED); - i_mmap_unlock_write(mapping); - } + unmap_success = try_to_unmap(hpage, ttu); if (!unmap_success) pr_err("Memory failure: %#lx: failed to unmap page (mapcount=%d)\n", pfn, page_mapcount(hpage)); diff --git a/mm/migrate.c b/mm/migrate.c index ccf8966caf6f..a16b15090df3 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1324,19 +1324,8 @@ static int unmap_and_move_huge_page(new_page_t get_new_page, goto put_anon; if (page_mapped(hpage)) { - struct address_space *mapping = page_mapping(hpage); - - /* - * try_to_unmap could potentially call huge_pmd_unshare. - * Because of this, take semaphore in write mode here and - * set TTU_RMAP_LOCKED to let lower levels know we have - * taken the lock. - */ - i_mmap_lock_write(mapping); try_to_unmap(hpage, - TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS| - TTU_RMAP_LOCKED); - i_mmap_unlock_write(mapping); + TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS); page_was_mapped = 1; } diff --git a/mm/rmap.c b/mm/rmap.c index 21a26cf51114..68a1a5b869a5 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -25,7 +25,6 @@ * page->flags PG_locked (lock_page) * hugetlbfs_i_mmap_rwsem_key (in huge_pmd_share) * mapping->i_mmap_rwsem - * hugetlb_fault_mutex (hugetlbfs specific page fault mutex) * anon_vma->rwsem * mm->page_table_lock or pte_lock * zone_lru_lock (in mark_page_accessed, isolate_lru_page) @@ -1379,9 +1378,6 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma, /* * If sharing is possible, start and end will be adjusted * accordingly. - * - * If called for a huge page, caller must hold i_mmap_rwsem - * in write mode as it is possible to call huge_pmd_unshare. */ adjust_range_if_pmd_sharing_possible(vma, &range.start, &range.end); diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 065c1ce191c4..d59b5a73dfb3 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -267,14 +267,10 @@ retry: VM_BUG_ON(dst_addr & ~huge_page_mask(h)); /* - * Serialize via i_mmap_rwsem and hugetlb_fault_mutex. - * i_mmap_rwsem ensures the dst_pte remains valid even - * in the case of shared pmds. fault mutex prevents - * races with other faulting threads. + * Serialize via hugetlb_fault_mutex */ - mapping = dst_vma->vm_file->f_mapping; - i_mmap_lock_read(mapping); idx = linear_page_index(dst_vma, dst_addr); + mapping = dst_vma->vm_file->f_mapping; hash = hugetlb_fault_mutex_hash(h, dst_mm, dst_vma, mapping, idx, dst_addr); mutex_lock(&hugetlb_fault_mutex_table[hash]); @@ -283,7 +279,6 @@ retry: dst_pte = huge_pte_alloc(dst_mm, dst_addr, huge_page_size(h)); if (!dst_pte) { mutex_unlock(&hugetlb_fault_mutex_table[hash]); - i_mmap_unlock_read(mapping); goto out_unlock; } @@ -291,7 +286,6 @@ retry: dst_pteval = huge_ptep_get(dst_pte); if (!huge_pte_none(dst_pteval)) { mutex_unlock(&hugetlb_fault_mutex_table[hash]); - i_mmap_unlock_read(mapping); goto out_unlock; } @@ -299,7 +293,6 @@ retry: dst_addr, src_addr, &page); mutex_unlock(&hugetlb_fault_mutex_table[hash]); - i_mmap_unlock_read(mapping); vm_alloc_shared = vm_shared; cond_resched(); -- cgit v1.2.3-58-ga151 From 73444bc4d8f92e46a20cb6bd3342fc2ea75c6787 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Tue, 8 Jan 2019 15:23:39 -0800 Subject: mm, page_alloc: do not wake kswapd with zone lock held syzbot reported the following regression in the latest merge window and it was confirmed by Qian Cai that a similar bug was visible from a different context. ====================================================== WARNING: possible circular locking dependency detected 4.20.0+ #297 Not tainted ------------------------------------------------------ syz-executor0/8529 is trying to acquire lock: 000000005e7fb829 (&pgdat->kswapd_wait){....}, at: __wake_up_common_lock+0x19e/0x330 kernel/sched/wait.c:120 but task is already holding lock: 000000009bb7bae0 (&(&zone->lock)->rlock){-.-.}, at: spin_lock include/linux/spinlock.h:329 [inline] 000000009bb7bae0 (&(&zone->lock)->rlock){-.-.}, at: rmqueue_bulk mm/page_alloc.c:2548 [inline] 000000009bb7bae0 (&(&zone->lock)->rlock){-.-.}, at: __rmqueue_pcplist mm/page_alloc.c:3021 [inline] 000000009bb7bae0 (&(&zone->lock)->rlock){-.-.}, at: rmqueue_pcplist mm/page_alloc.c:3050 [inline] 000000009bb7bae0 (&(&zone->lock)->rlock){-.-.}, at: rmqueue mm/page_alloc.c:3072 [inline] 000000009bb7bae0 (&(&zone->lock)->rlock){-.-.}, at: get_page_from_freelist+0x1bae/0x52a0 mm/page_alloc.c:3491 It appears to be a false positive in that the only way the lock ordering should be inverted is if kswapd is waking itself and the wakeup allocates debugging objects which should already be allocated if it's kswapd doing the waking. Nevertheless, the possibility exists and so it's best to avoid the problem. This patch flags a zone as needing a kswapd using the, surprisingly, unused zone flag field. The flag is read without the lock held to do the wakeup. It's possible that the flag setting context is not the same as the flag clearing context or for small races to occur. However, each race possibility is harmless and there is no visible degredation in fragmentation treatment. While zone->flag could have continued to be unused, there is potential for moving some existing fields into the flags field instead. Particularly read-mostly ones like zone->initialized and zone->contiguous. Link: http://lkml.kernel.org/r/20190103225712.GJ31517@techsingularity.net Fixes: 1c30844d2dfe ("mm: reclaim small amounts of memory when an external fragmentation event occurs") Reported-by: syzbot+93d94a001cfbce9e60e1@syzkaller.appspotmail.com Signed-off-by: Mel Gorman Acked-by: Vlastimil Babka Tested-by: Qian Cai Cc: Dmitry Vyukov Cc: Vlastimil Babka Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 6 ++++++ mm/page_alloc.c | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index cc4a507d7ca4..842f9189537b 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -520,6 +520,12 @@ enum pgdat_flags { PGDAT_RECLAIM_LOCKED, /* prevents concurrent reclaim */ }; +enum zone_flags { + ZONE_BOOSTED_WATERMARK, /* zone recently boosted watermarks. + * Cleared when kswapd is woken. + */ +}; + static inline unsigned long zone_managed_pages(struct zone *zone) { return (unsigned long)atomic_long_read(&zone->managed_pages); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index cde5dac6229a..d295c9bc01a8 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2214,7 +2214,7 @@ static void steal_suitable_fallback(struct zone *zone, struct page *page, */ boost_watermark(zone); if (alloc_flags & ALLOC_KSWAPD) - wakeup_kswapd(zone, 0, 0, zone_idx(zone)); + set_bit(ZONE_BOOSTED_WATERMARK, &zone->flags); /* We are not allowed to try stealing from the whole block */ if (!whole_block) @@ -3102,6 +3102,12 @@ struct page *rmqueue(struct zone *preferred_zone, local_irq_restore(flags); out: + /* Separate test+clear to avoid unnecessary atomics */ + if (test_bit(ZONE_BOOSTED_WATERMARK, &zone->flags)) { + clear_bit(ZONE_BOOSTED_WATERMARK, &zone->flags); + wakeup_kswapd(zone, 0, 0, zone_idx(zone)); + } + VM_BUG_ON_PAGE(page && bad_range(zone, page), page); return page; -- cgit v1.2.3-58-ga151 From dadbcb450cb22acbc06bb53edf2bcc9261cb78f3 Mon Sep 17 00:00:00 2001 From: Xiaochun Lee Date: Mon, 7 Jan 2019 10:33:36 +0800 Subject: ACPI/nfit: delete the redundant header file The header file "intel.h" is repeated here, So delete one. Signed-off-by: Xiaochun Lee Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 011d3db19c80..328e464dd899 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -26,7 +26,6 @@ #include #include "intel.h" #include "nfit.h" -#include "intel.h" /* * For readq() and writeq() on 32-bit builds, the hi-lo, lo-hi order is -- cgit v1.2.3-58-ga151 From 8a7f02f67c395949c768ae1cf4f12905a81e3cde Mon Sep 17 00:00:00 2001 From: Xiaochun Lee Date: Sat, 5 Jan 2019 16:08:38 +0800 Subject: ACPI/nfit: delete the function to_acpi_nfit_desc The function to_acpi_nfit_desc and function to_acpi_desc do the same things,delete the function to_acpi_nfit_desc, and keep the inline function to_acpi_desc. Signed-off-by: Xiaochun Lee Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 328e464dd899..4ae953a5aebf 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -77,12 +77,6 @@ const guid_t *to_nfit_uuid(enum nfit_uuids id) } EXPORT_SYMBOL(to_nfit_uuid); -static struct acpi_nfit_desc *to_acpi_nfit_desc( - struct nvdimm_bus_descriptor *nd_desc) -{ - return container_of(nd_desc, struct acpi_nfit_desc, nd_desc); -} - static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc) { struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc; @@ -418,7 +412,7 @@ static bool payload_dumpable(struct nvdimm *nvdimm, unsigned int func) int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) { - struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); + struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); union acpi_object in_obj, in_buf, *out_obj; const struct nd_cmd_desc *desc = NULL; @@ -3366,7 +3360,7 @@ EXPORT_SYMBOL_GPL(acpi_nfit_init); static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) { - struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); + struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct device *dev = acpi_desc->dev; /* Bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */ @@ -3383,7 +3377,7 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) static int __acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd) { - struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); + struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); if (nvdimm) return 0; -- cgit v1.2.3-58-ga151 From 9cb2feb4d21d97386eb25c7b67e2793efcc1e70a Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Tue, 8 Jan 2019 22:15:15 +0900 Subject: arch/openrisc: Fix issues with access_ok() The commit 594cc251fdd0 ("make 'user_access_begin()' do 'access_ok()'") exposed incorrect implementations of access_ok() macro in several architectures. This change fixes 2 issues found in OpenRISC. OpenRISC was not properly using parenthesis for arguments and also using arguments twice. This patch fixes those 2 issues. I test booted this patch with v5.0-rc1 on qemu and it's working fine. Cc: Guenter Roeck Cc: Linus Torvalds Reported-by: Linus Torvalds Signed-off-by: Stafford Horne Signed-off-by: Linus Torvalds --- arch/openrisc/include/asm/uaccess.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/openrisc/include/asm/uaccess.h b/arch/openrisc/include/asm/uaccess.h index bc8191a34db7..a44682c8adc3 100644 --- a/arch/openrisc/include/asm/uaccess.h +++ b/arch/openrisc/include/asm/uaccess.h @@ -58,8 +58,12 @@ /* Ensure that addr is below task's addr_limit */ #define __addr_ok(addr) ((unsigned long) addr < get_fs()) -#define access_ok(addr, size) \ - __range_ok((unsigned long)addr, (unsigned long)size) +#define access_ok(addr, size) \ +({ \ + unsigned long __ao_addr = (unsigned long)(addr); \ + unsigned long __ao_size = (unsigned long)(size); \ + __range_ok(__ao_addr, __ao_size); \ +}) /* * These are the main single-value transfer routines. They automatically -- cgit v1.2.3-58-ga151 From d972f3dce8d161e2142da0ab1ef25df00e2f21a9 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 8 Jan 2019 23:27:06 +0000 Subject: packet: Do not leak dev refcounts on error exit 'dev' is non NULL when the addr_len check triggers so it must goto a label that does the dev_put otherwise dev will have a leaked refcount. This bug causes the ib_ipoib module to become unloadable when using systemd-network as it triggers this check on InfiniBand links. Fixes: 99137b7888f4 ("packet: validate address length") Reported-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- net/packet/af_packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index eedacdebcd4c..d0945253f43b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2628,7 +2628,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) addr = saddr->sll_halen ? saddr->sll_addr : NULL; dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex); if (addr && dev && saddr->sll_halen < dev->addr_len) - goto out; + goto out_put; } err = -ENXIO; @@ -2828,7 +2828,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) addr = saddr->sll_halen ? saddr->sll_addr : NULL; dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex); if (addr && dev && saddr->sll_halen < dev->addr_len) - goto out; + goto out_unlock; } err = -ENXIO; -- cgit v1.2.3-58-ga151 From 44759979a49bfd2d20d789add7fa81a21eb1a4ab Mon Sep 17 00:00:00 2001 From: Ivan Mironov Date: Sun, 23 Dec 2018 12:41:58 +0500 Subject: scsi: sd: Fix cache_type_store() Changing of caching mode via /sys/devices/.../scsi_disk/.../cache_type may fail if device responds to MODE SENSE command with DPOFUA flag set, and then checks this flag to be not set on MODE SELECT command. In this scenario, when trying to change cache_type, write always fails: # echo "none" >cache_type bash: echo: write error: Invalid argument And following appears in dmesg: [13007.865745] sd 1:0:1:0: [sda] Sense Key : Illegal Request [current] [13007.865753] sd 1:0:1:0: [sda] Add. Sense: Invalid field in parameter list From SBC-4 r15, 6.5.1 "Mode pages overview", description of DEVICE-SPECIFIC PARAMETER field in the mode parameter header: ... The write protect (WP) bit for mode data sent with a MODE SELECT command shall be ignored by the device server. ... The DPOFUA bit is reserved for mode data sent with a MODE SELECT command. ... The remaining bits in the DEVICE-SPECIFIC PARAMETER byte are also reserved and shall be set to zero. [mkp: shuffled commentary to commit description] Cc: stable@vger.kernel.org Signed-off-by: Ivan Mironov Signed-off-by: Martin K. Petersen --- drivers/scsi/sd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a1a44f52e0e8..b2da8a00ec33 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -206,6 +206,12 @@ cache_type_store(struct device *dev, struct device_attribute *attr, sp = buffer_data[0] & 0x80 ? 1 : 0; buffer_data[0] &= ~0x80; + /* + * Ensure WP, DPOFUA, and RESERVED fields are cleared in + * received mode parameter buffer before doing MODE SELECT. + */ + data.device_specific = 0; + if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT, SD_MAX_RETRIES, &data, &sshdr)) { if (scsi_sense_valid(&sshdr)) -- cgit v1.2.3-58-ga151 From 621a4367d69509f35abb4559a2dd7179ea5acada Mon Sep 17 00:00:00 2001 From: Leo Zhang Date: Mon, 24 Dec 2018 00:18:27 +0800 Subject: scsi: target/iscsi: fix error msg typo when create lio_qr_cache failed Signed-off-by: Leo Zhang Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 984941e036c8..bd15a564fe24 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -714,7 +714,7 @@ static int __init iscsi_target_init_module(void) sizeof(struct iscsi_queue_req), __alignof__(struct iscsi_queue_req), 0, NULL); if (!lio_qr_cache) { - pr_err("nable to kmem_cache_create() for" + pr_err("Unable to kmem_cache_create() for" " lio_qr_cache\n"); goto bitmap_out; } -- cgit v1.2.3-58-ga151 From d1f38d995e984db36449661fcbad1649c21883e7 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Wed, 2 Jan 2019 16:07:25 +0100 Subject: scsi: megaraid_sas: correct an info message This was apparently forgotten in 894169db1 ("scsi: megaraid_sas: Use 63-bit DMA addressing"). Signed-off-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index f7bdd783360a..a6b1824cc08a 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -6236,7 +6236,7 @@ megasas_set_dma_mask(struct megasas_instance *instance) instance->consistent_mask_64bit = true; dev_info(&pdev->dev, "%s bit DMA mask and %s bit consistent mask\n", - ((*pdev->dev.dma_mask == DMA_BIT_MASK(64)) ? "63" : "32"), + ((*pdev->dev.dma_mask == DMA_BIT_MASK(63)) ? "63" : "32"), (instance->consistent_mask_64bit ? "63" : "32")); return 0; -- cgit v1.2.3-58-ga151 From 72b4a0465f995175a2e22cf4a636bf781f1f28a7 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 20 Dec 2018 11:16:07 +0800 Subject: scsi: qla4xxx: check return code of qla4xxx_copy_from_fwddb_param The return code should be check while qla4xxx_copy_from_fwddb_param fails. Signed-off-by: YueHaibing Acked-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_os.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 949e186cc5d7..1bc4db6e6d16 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -7232,6 +7232,8 @@ static int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha, rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry); + if (rc) + goto free_sess; ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n", __func__, fnode_sess->dev.kobj.name); -- cgit v1.2.3-58-ga151 From 251f24e63fc291f288f765663e62cd575f048fd5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 30 Dec 2018 16:53:13 +0100 Subject: scsi: pm80xx: reduce indentation Delete tab aligning a statement with the right hand side of a preceding assignment rather than the left hand side. Found with the help of Coccinelle. [mkp: added space] Signed-off-by: Julia Lawall Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index b3be49d41375..1343bd89c25c 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -657,7 +657,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev) if (dev->dev_type == SAS_SATA_DEV) { pm8001_device->attached_phy = dev->rphy->identify.phy_identifier; - flag = 1; /* directly sata*/ + flag = 1; /* directly sata */ } } /*register this device to HBA*/ PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n")); -- cgit v1.2.3-58-ga151 From 3f7e62bba0003f9c68f599f5997c4647ef5b4f4e Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Thu, 3 Jan 2019 22:08:05 +0800 Subject: scsi: core: Synchronize request queue PM status only on successful resume The commit 356fd2663cff ("scsi: Set request queue runtime PM status back to active on resume") fixed up the inconsistent RPM status between request queue and device. However changing request queue RPM status shall be done only on successful resume, otherwise status may be still inconsistent as below, Request queue: RPM_ACTIVE Device: RPM_SUSPENDED This ends up soft lockup because requests can be submitted to underlying devices but those devices and their required resource are not resumed. For example, After above inconsistent status happens, IO request can be submitted to UFS device driver but required resource (like clock) is not resumed yet thus lead to warning as below call stack, WARN_ON(hba->clk_gating.state != CLKS_ON); ufshcd_queuecommand scsi_dispatch_cmd scsi_request_fn __blk_run_queue cfq_insert_request __elv_add_request blk_flush_plug_list blk_finish_plug jbd2_journal_commit_transaction kjournald2 We may see all behind IO requests hang because of no response from storage host or device and then soft lockup happens in system. In the end, system may crash in many ways. Fixes: 356fd2663cff (scsi: Set request queue runtime PM status back to active on resume) Cc: stable@vger.kernel.org Signed-off-by: Stanley Chu Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_pm.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index a2b4179bfdf7..7639df91b110 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -80,8 +80,22 @@ static int scsi_dev_type_resume(struct device *dev, if (err == 0) { pm_runtime_disable(dev); - pm_runtime_set_active(dev); + err = pm_runtime_set_active(dev); pm_runtime_enable(dev); + + /* + * Forcibly set runtime PM status of request queue to "active" + * to make sure we can again get requests from the queue + * (see also blk_pm_peek_request()). + * + * The resume hook will correct runtime PM status of the disk. + */ + if (!err && scsi_is_sdev_device(dev)) { + struct scsi_device *sdev = to_scsi_device(dev); + + if (sdev->request_queue->dev) + blk_set_runtime_active(sdev->request_queue); + } } return err; @@ -140,16 +154,6 @@ static int scsi_bus_resume_common(struct device *dev, else fn = NULL; - /* - * Forcibly set runtime PM status of request queue to "active" to - * make sure we can again get requests from the queue (see also - * blk_pm_peek_request()). - * - * The resume hook will correct runtime PM status of the disk. - */ - if (scsi_is_sdev_device(dev) && pm_runtime_suspended(dev)) - blk_set_runtime_active(to_scsi_device(dev)->request_queue); - if (fn) { async_schedule_domain(fn, dev, &scsi_sd_pm_domain); -- cgit v1.2.3-58-ga151 From 12de280b36f0e0599c7f170aa7f1058f3aeb6d9d Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 3 Jan 2019 10:47:44 -0600 Subject: scsi: smartpqi_init: fix boolean expression in pqi_device_remove_start Fix boolean expression by using logical AND operator '&&' instead of bitwise operator '&'. This issue was detected with the help of Coccinelle. Fixes: 1e46731efd9c ("scsi: smartpqi: check for null device pointers") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Gustavo A. R. Silva Acked-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index e2fa3f476227..40f58238ce4a 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -323,7 +323,7 @@ static inline void pqi_device_remove_start(struct pqi_scsi_dev *device) static inline bool pqi_device_in_remove(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device) { - return device->in_remove & !ctrl_info->in_shutdown; + return device->in_remove && !ctrl_info->in_shutdown; } static inline void pqi_schedule_rescan_worker_with_delay( -- cgit v1.2.3-58-ga151 From 5bd5f66cf142703e163459e1b36b73e265f0a0da Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 27 Nov 2018 22:32:18 -0600 Subject: scsi: lpfc: lpfc_sli: Mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. Notice that, in this particular case, I replaced "Drop thru" and "Fall Thru" with "fall through" annotations, which is what GCC is expecting to find. Also, in some cases a dash is added as a token in order to separate the "fall through" annotation from the rest of the comment on the same line, which is what GCC is expecting to find. Addresses-Coverity-ID: 114979 ("Missing break in switch") Addresses-Coverity-ID: 114980 ("Missing break in switch") Signed-off-by: Gustavo A. R. Silva Acked-by: Dick Kennedy Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 30734caf77e1..3ac5cc1a0cd9 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -9408,6 +9408,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, cmnd = CMD_XMIT_SEQUENCE64_CR; if (phba->link_flag & LS_LOOPBACK_MODE) bf_set(wqe_xo, &wqe->xmit_sequence.wge_ctl, 1); + /* fall through */ case CMD_XMIT_SEQUENCE64_CR: /* word3 iocb=io_tag32 wqe=reserved */ wqe->xmit_sequence.rsvd3 = 0; @@ -13529,6 +13530,7 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) case FC_STATUS_RQ_BUF_LEN_EXCEEDED: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2537 Receive Frame Truncated!!\n"); + /* fall through */ case FC_STATUS_RQ_SUCCESS: spin_lock_irqsave(&phba->hbalock, iflags); lpfc_sli4_rq_release(hrq, drq); @@ -13938,7 +13940,7 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, case FC_STATUS_RQ_BUF_LEN_EXCEEDED: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "6126 Receive Frame Truncated!!\n"); - /* Drop thru */ + /* fall through */ case FC_STATUS_RQ_SUCCESS: spin_lock_irqsave(&phba->hbalock, iflags); lpfc_sli4_rq_release(hrq, drq); @@ -14850,7 +14852,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) eq->entry_count); if (eq->entry_count < 256) return -EINVAL; - /* otherwise default to smallest count (drop through) */ + /* fall through - otherwise default to smallest count */ case 256: bf_set(lpfc_eq_context_count, &eq_create->u.request.context, LPFC_EQ_CNT_256); @@ -14981,7 +14983,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, LPFC_CQ_CNT_WORD7); break; } - /* Fall Thru */ + /* fall through */ default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0361 Unsupported CQ count: " @@ -14992,7 +14994,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, status = -EINVAL; goto out; } - /* otherwise default to smallest count (drop through) */ + /* fall through - otherwise default to smallest count */ case 256: bf_set(lpfc_cq_context_count, &cq_create->u.request.context, LPFC_CQ_CNT_256); @@ -15152,7 +15154,7 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, LPFC_CQ_CNT_WORD7); break; } - /* Fall Thru */ + /* fall through */ default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3118 Bad CQ count. (%d)\n", @@ -15161,7 +15163,7 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, status = -EINVAL; goto out; } - /* otherwise default to smallest (drop thru) */ + /* fall through - otherwise default to smallest */ case 256: bf_set(lpfc_mbx_cq_create_set_cqe_cnt, &cq_set->u.request, LPFC_CQ_CNT_256); @@ -15433,7 +15435,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, status = -EINVAL; goto out; } - /* otherwise default to smallest count (drop through) */ + /* fall through - otherwise default to smallest count */ case 16: bf_set(lpfc_mq_context_ring_size, &mq_create_ext->u.request.context, @@ -15852,7 +15854,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, status = -EINVAL; goto out; } - /* otherwise default to smallest count (drop through) */ + /* fall through - otherwise default to smallest count */ case 512: bf_set(lpfc_rq_context_rqe_count, &rq_create->u.request.context, @@ -15989,7 +15991,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, status = -EINVAL; goto out; } - /* otherwise default to smallest count (drop through) */ + /* fall through - otherwise default to smallest count */ case 512: bf_set(lpfc_rq_context_rqe_count, &rq_create->u.request.context, -- cgit v1.2.3-58-ga151 From cc29a1b0a3f2597ce887d339222fa85b9307706d Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Tue, 8 Jan 2019 13:50:43 -0700 Subject: scsi: isci: initialize shost fully before calling scsi_add_host() scsi_mq_setup_tags(), which is called by scsi_add_host(), calculates the command size to allocate based on the prot_capabilities. In the isci driver, scsi_host_set_prot() is called after scsi_add_host() so the command size gets calculated to be smaller than it needs to be. Eventually, scsi_mq_init_request() locates the 'prot_sdb' after the command assuming it was sized correctly and a buffer overrun may occur. However, seeing blk_mq_alloc_rqs() rounds up to the nearest cache line size, the mistake can go unnoticed. The bug was noticed after the struct request size was reduced by commit 9d037ad707ed ("block: remove req->timeout_list") Which likely reduced the allocated space for the request by an entire cache line, enough that the overflow could be hit and it caused a panic, on boot, at: RIP: 0010:t10_pi_complete+0x77/0x1c0 Call Trace: sd_done+0xf5/0x340 scsi_finish_command+0xc3/0x120 blk_done_softirq+0x83/0xb0 __do_softirq+0xa1/0x2e6 irq_exit+0xbc/0xd0 call_function_single_interrupt+0xf/0x20 sd_done() would call scsi_prot_sg_count() which reads the number of entities in 'prot_sdb', but seeing 'prot_sdb' is located after the end of the allocated space it reads a garbage number and erroneously calls t10_pi_complete(). To prevent this, the calls to scsi_host_set_prot() are moved into isci_host_alloc() before the call to scsi_add_host(). Out of caution, also move the similar call to scsi_host_set_guard(). Fixes: 3d2d75254915 ("[SCSI] isci: T10 DIF support") Link: http://lkml.kernel.org/r/da851333-eadd-163a-8c78-e1f4ec5ec857@deltatee.com Signed-off-by: Logan Gunthorpe Cc: Intel SCU Linux support Cc: Artur Paszkiewicz Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Christoph Hellwig Cc: Jens Axboe Cc: Jeff Moyer Reviewed-by: Jeff Moyer Reviewed-by: Jens Axboe Signed-off-by: Martin K. Petersen --- drivers/scsi/isci/init.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 68b90c4f79a3..1727d0c71b12 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -576,6 +576,13 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) shost->max_lun = ~0; shost->max_cmd_len = MAX_COMMAND_SIZE; + /* turn on DIF support */ + scsi_host_set_prot(shost, + SHOST_DIF_TYPE1_PROTECTION | + SHOST_DIF_TYPE2_PROTECTION | + SHOST_DIF_TYPE3_PROTECTION); + scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); + err = scsi_add_host(shost, &pdev->dev); if (err) goto err_shost; @@ -663,13 +670,6 @@ static int isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_host_alloc; } pci_info->hosts[i] = h; - - /* turn on DIF support */ - scsi_host_set_prot(to_shost(h), - SHOST_DIF_TYPE1_PROTECTION | - SHOST_DIF_TYPE2_PROTECTION | - SHOST_DIF_TYPE3_PROTECTION); - scsi_host_set_guard(to_shost(h), SHOST_DIX_GUARD_CRC); } err = isci_setup_interrupts(pdev); -- cgit v1.2.3-58-ga151 From 40405851af73c59678ffd8f490e6b288c7fbaf29 Mon Sep 17 00:00:00 2001 From: Jeff Moyer Date: Tue, 8 Jan 2019 16:57:34 -0500 Subject: block: clarify documentation for blk_{start|finish}_plug There was some confusion about what these functions did. Make it clear that this is a hint for upper layers to pass to the block layer, and that it does not guarantee that I/O will not be submitted between a start and finish plug. Reported-by: "Darrick J. Wong" Reviewed-by: Darrick J. Wong Reviewed-by: Ming Lei Signed-off-by: Jeff Moyer Signed-off-by: Jens Axboe --- block/blk-core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/block/blk-core.c b/block/blk-core.c index c78042975737..f2732f106a2e 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1683,6 +1683,15 @@ EXPORT_SYMBOL(kblockd_mod_delayed_work_on); * @plug: The &struct blk_plug that needs to be initialized * * Description: + * blk_start_plug() indicates to the block layer an intent by the caller + * to submit multiple I/O requests in a batch. The block layer may use + * this hint to defer submitting I/Os from the caller until blk_finish_plug() + * is called. However, the block layer may choose to submit requests + * before a call to blk_finish_plug() if the number of queued I/Os + * exceeds %BLK_MAX_REQUEST_COUNT, or if the size of the I/O is larger than + * %BLK_PLUG_FLUSH_SIZE. The queued I/Os may also be submitted early if + * the task schedules (see below). + * * Tracking blk_plug inside the task_struct will help with auto-flushing the * pending I/O should the task end up blocking between blk_start_plug() and * blk_finish_plug(). This is important from a performance perspective, but @@ -1765,6 +1774,16 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) blk_mq_flush_plug_list(plug, from_schedule); } +/** + * blk_finish_plug - mark the end of a batch of submitted I/O + * @plug: The &struct blk_plug passed to blk_start_plug() + * + * Description: + * Indicate that a batch of I/O submissions is complete. This function + * must be paired with an initial call to blk_start_plug(). The intent + * is to allow the block layer to optimize I/O submission. See the + * documentation for blk_start_plug() for more information. + */ void blk_finish_plug(struct blk_plug *plug) { if (plug != current->plug) -- cgit v1.2.3-58-ga151 From f0e9943725186ddbdc9718a559c26c5f507262f2 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Sat, 29 Dec 2018 11:13:10 +0800 Subject: drm/i915/gvt: Fix workload request allocation before request add In commit 6bb2a2af8b1b ("drm/i915/gvt: Fix crash after request->hw_context change"), forgot to handle workload scan path in ELSP handler case which was to optimize scanning earlier instead of in gvt submission thread, so request alloc and add was splitting then which is against right process. This trys to do a partial revert of that commit which still has workload request alloc helper and make sure shadow state population is handled after request alloc for target state buffer. v3: Fix missed workload status setting in request alloc error path v2: Fix dispatch workload err path that should add request after alloc anyway. Fixes: 6bb2a2af8b1b ("drm/i915/gvt: Fix crash after request->hw_context change") Cc: Bin Yang Cc: Chris Wilson Tested-by: Bin Yang Reviewed-by: Xiaolin Zhang Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/scheduler.c | 64 +++++++++++++++++++++++------------- drivers/gpu/drm/i915/gvt/scheduler.h | 1 + 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index 1ad8c5e1455d..5567ddc7760f 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -356,6 +356,33 @@ static int set_context_ppgtt_from_shadow(struct intel_vgpu_workload *workload, return 0; } +static int +intel_gvt_workload_req_alloc(struct intel_vgpu_workload *workload) +{ + struct intel_vgpu *vgpu = workload->vgpu; + struct intel_vgpu_submission *s = &vgpu->submission; + struct i915_gem_context *shadow_ctx = s->shadow_ctx; + struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; + struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id]; + struct i915_request *rq; + int ret = 0; + + lockdep_assert_held(&dev_priv->drm.struct_mutex); + + if (workload->req) + goto out; + + rq = i915_request_alloc(engine, shadow_ctx); + if (IS_ERR(rq)) { + gvt_vgpu_err("fail to allocate gem request\n"); + ret = PTR_ERR(rq); + goto out; + } + workload->req = i915_request_get(rq); +out: + return ret; +} + /** * intel_gvt_scan_and_shadow_workload - audit the workload by scanning and * shadow it as well, include ringbuffer,wa_ctx and ctx. @@ -372,12 +399,11 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload) struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id]; struct intel_context *ce; - struct i915_request *rq; int ret; lockdep_assert_held(&dev_priv->drm.struct_mutex); - if (workload->req) + if (workload->shadow) return 0; ret = set_context_ppgtt_from_shadow(workload, shadow_ctx); @@ -417,22 +443,8 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload) goto err_shadow; } - rq = i915_request_alloc(engine, shadow_ctx); - if (IS_ERR(rq)) { - gvt_vgpu_err("fail to allocate gem request\n"); - ret = PTR_ERR(rq); - goto err_shadow; - } - workload->req = i915_request_get(rq); - - ret = populate_shadow_context(workload); - if (ret) - goto err_req; - + workload->shadow = true; return 0; -err_req: - rq = fetch_and_zero(&workload->req); - i915_request_put(rq); err_shadow: release_shadow_wa_ctx(&workload->wa_ctx); err_unpin: @@ -671,23 +683,31 @@ static int dispatch_workload(struct intel_vgpu_workload *workload) mutex_lock(&vgpu->vgpu_lock); mutex_lock(&dev_priv->drm.struct_mutex); + ret = intel_gvt_workload_req_alloc(workload); + if (ret) + goto err_req; + ret = intel_gvt_scan_and_shadow_workload(workload); if (ret) goto out; - ret = prepare_workload(workload); + ret = populate_shadow_context(workload); + if (ret) { + release_shadow_wa_ctx(&workload->wa_ctx); + goto out; + } + ret = prepare_workload(workload); out: - if (ret) - workload->status = ret; - if (!IS_ERR_OR_NULL(workload->req)) { gvt_dbg_sched("ring id %d submit workload to i915 %p\n", ring_id, workload->req); i915_request_add(workload->req); workload->dispatched = true; } - +err_req: + if (ret) + workload->status = ret; mutex_unlock(&dev_priv->drm.struct_mutex); mutex_unlock(&vgpu->vgpu_lock); return ret; diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h index ca5529d0e48e..2065cba59aab 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.h +++ b/drivers/gpu/drm/i915/gvt/scheduler.h @@ -83,6 +83,7 @@ struct intel_vgpu_workload { struct i915_request *req; /* if this workload has been dispatched to i915? */ bool dispatched; + bool shadow; /* if workload has done shadow of guest request */ int status; struct intel_vgpu_mm *shadow_mm; -- cgit v1.2.3-58-ga151 From ccb7f15a8a3c0c7a35389e4c8e083c424b4df79d Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 8 Jan 2019 22:00:37 -0700 Subject: nfit: Mark some functions as __maybe_unused On arm64 little endian allyesconfig: drivers/acpi/nfit/intel.c:149:12: warning: unused function 'intel_security_unlock' [-Wunused-function] static int intel_security_unlock(struct nvdimm *nvdimm, ^ drivers/acpi/nfit/intel.c:230:12: warning: unused function 'intel_security_erase' [-Wunused-function] static int intel_security_erase(struct nvdimm *nvdimm, ^ drivers/acpi/nfit/intel.c:279:12: warning: unused function 'intel_security_query_overwrite' [-Wunused-function] static int intel_security_query_overwrite(struct nvdimm *nvdimm) ^ drivers/acpi/nfit/intel.c:316:12: warning: unused function 'intel_security_overwrite' [-Wunused-function] static int intel_security_overwrite(struct nvdimm *nvdimm, ^ 4 warnings generated. Mark these functions as __maybe_unused because they are only used when CONFIG_X86 is set. Fixes: 4c6926a23b76 ("acpi/nfit, libnvdimm: Add unlock of nvdimm support for Intel DIMMs") Suggested-by: Dan Williams Signed-off-by: Nathan Chancellor Signed-off-by: Dan Williams --- drivers/acpi/nfit/intel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index 850b2927b4e7..f70de71f79d6 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c @@ -146,7 +146,7 @@ static int intel_security_change_key(struct nvdimm *nvdimm, static void nvdimm_invalidate_cache(void); -static int intel_security_unlock(struct nvdimm *nvdimm, +static int __maybe_unused intel_security_unlock(struct nvdimm *nvdimm, const struct nvdimm_key_data *key_data) { struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); @@ -227,7 +227,7 @@ static int intel_security_disable(struct nvdimm *nvdimm, return 0; } -static int intel_security_erase(struct nvdimm *nvdimm, +static int __maybe_unused intel_security_erase(struct nvdimm *nvdimm, const struct nvdimm_key_data *key, enum nvdimm_passphrase_type ptype) { @@ -276,7 +276,7 @@ static int intel_security_erase(struct nvdimm *nvdimm, return 0; } -static int intel_security_query_overwrite(struct nvdimm *nvdimm) +static int __maybe_unused intel_security_query_overwrite(struct nvdimm *nvdimm) { int rc; struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); @@ -313,7 +313,7 @@ static int intel_security_query_overwrite(struct nvdimm *nvdimm) return 0; } -static int intel_security_overwrite(struct nvdimm *nvdimm, +static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm, const struct nvdimm_key_data *nkey) { int rc; -- cgit v1.2.3-58-ga151 From 1cb95e072ede5e3d6a54eefd520db21b45985896 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 8 Jan 2019 15:34:52 -0800 Subject: libnvdimm/dimm: Fix security capability detection for non-Intel NVDIMMs Kees reports a crash with the following signature... RIP: 0010:nvdimm_visible+0x79/0x80 [..] Call Trace: internal_create_group+0xf4/0x380 sysfs_create_groups+0x46/0xb0 device_add+0x331/0x680 nd_async_device_register+0x15/0x60 async_run_entry_fn+0x38/0x100 ...when starting a QEMU environment with "label-less" DIMM. Without labels QEMU does not publish any DSM methods. Without defined methods the NVDIMM_FAMILY type is not established and the nfit driver will skip registering security operations. In that case the security state should be initialized to a negative value in __nvdimm_create() and nvdimm_visible() should skip interrogating the specific ops. However, since 'enum nvdimm_security_state' was only defined to contain positive values the "if (nvdimm->sec.state < 0)" check always fails. Define a negative error state to allow negative state values to be handled as expected. Fixes: f2989396553a ("acpi/nfit, libnvdimm: Introduce nvdimm_security_ops") Reviewed-by: Dave Jiang Reported-by: Kees Cook Tested-by: Kees Cook Signed-off-by: Dan Williams --- include/linux/libnvdimm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 5440f11b0907..7315977b64da 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -160,6 +160,7 @@ static inline struct nd_blk_region_desc *to_blk_region_desc( } enum nvdimm_security_state { + NVDIMM_SECURITY_ERROR = -1, NVDIMM_SECURITY_DISABLED, NVDIMM_SECURITY_UNLOCKED, NVDIMM_SECURITY_LOCKED, -- cgit v1.2.3-58-ga151 From 90802938f7e88045ace123e105e22e8c3e7f9c7e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 8 Jan 2019 17:38:29 +0100 Subject: x86/cache: Rename config option to CONFIG_X86_RESCTRL CONFIG_RESCTRL is too generic. The final goal is to have a generic option called like this which is selected by the arch-specific ones CONFIG_X86_RESCTRL and CONFIG_ARM64_RESCTRL. The generic one will cover the resctrl filesystem and other generic and shared bits of functionality. Signed-off-by: Borislav Petkov Suggested-by: Ingo Molnar Requested-by: Linus Torvalds Cc: Babu Moger Cc: Fenghua Yu Cc: James Morse Cc: Reinette Chatre Cc: Tony Luck Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20190108171401.GC12235@zn.tnic --- Documentation/x86/resctrl_ui.txt | 2 +- arch/x86/Kconfig | 2 +- arch/x86/include/asm/resctrl_sched.h | 4 ++-- arch/x86/kernel/cpu/Makefile | 2 +- arch/x86/kernel/cpu/resctrl/Makefile | 4 ++-- include/linux/sched.h | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Documentation/x86/resctrl_ui.txt b/Documentation/x86/resctrl_ui.txt index d9aed8303984..e8e8d14d3c4e 100644 --- a/Documentation/x86/resctrl_ui.txt +++ b/Documentation/x86/resctrl_ui.txt @@ -9,7 +9,7 @@ Fenghua Yu Tony Luck Vikas Shivappa -This feature is enabled by the CONFIG_RESCTRL and the X86 /proc/cpuinfo +This feature is enabled by the CONFIG_X86_RESCTRL and the x86 /proc/cpuinfo flag bits: RDT (Resource Director Technology) Allocation - "rdt_a" CAT (Cache Allocation Technology) - "cat_l3", "cat_l2" diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6185d4f33296..15af091611e2 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -446,7 +446,7 @@ config RETPOLINE branches. Requires a compiler with -mindirect-branch=thunk-extern support for full protection. The kernel may run slower. -config RESCTRL +config X86_RESCTRL bool "Resource Control support" depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD) select KERNFS diff --git a/arch/x86/include/asm/resctrl_sched.h b/arch/x86/include/asm/resctrl_sched.h index 54990fe2a3ae..40ebddde6ac2 100644 --- a/arch/x86/include/asm/resctrl_sched.h +++ b/arch/x86/include/asm/resctrl_sched.h @@ -2,7 +2,7 @@ #ifndef _ASM_X86_RESCTRL_SCHED_H #define _ASM_X86_RESCTRL_SCHED_H -#ifdef CONFIG_RESCTRL +#ifdef CONFIG_X86_RESCTRL #include #include @@ -88,6 +88,6 @@ static inline void resctrl_sched_in(void) static inline void resctrl_sched_in(void) {} -#endif /* CONFIG_RESCTRL */ +#endif /* CONFIG_X86_RESCTRL */ #endif /* _ASM_X86_RESCTRL_SCHED_H */ diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index ac78f90aea56..b6fa0869f7aa 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -39,7 +39,7 @@ obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o obj-$(CONFIG_X86_MCE) += mce/ obj-$(CONFIG_MTRR) += mtrr/ obj-$(CONFIG_MICROCODE) += microcode/ -obj-$(CONFIG_RESCTRL) += resctrl/ +obj-$(CONFIG_X86_RESCTRL) += resctrl/ obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o diff --git a/arch/x86/kernel/cpu/resctrl/Makefile b/arch/x86/kernel/cpu/resctrl/Makefile index 6895049ceef7..1cabe6fd8e11 100644 --- a/arch/x86/kernel/cpu/resctrl/Makefile +++ b/arch/x86/kernel/cpu/resctrl/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_RESCTRL) += core.o rdtgroup.o monitor.o -obj-$(CONFIG_RESCTRL) += ctrlmondata.o pseudo_lock.o +obj-$(CONFIG_X86_RESCTRL) += core.o rdtgroup.o monitor.o +obj-$(CONFIG_X86_RESCTRL) += ctrlmondata.o pseudo_lock.o CFLAGS_pseudo_lock.o = -I$(src) diff --git a/include/linux/sched.h b/include/linux/sched.h index 89541d248893..224666226e87 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -995,7 +995,7 @@ struct task_struct { /* cg_list protected by css_set_lock and tsk->alloc_lock: */ struct list_head cg_list; #endif -#ifdef CONFIG_RESCTRL +#ifdef CONFIG_X86_RESCTRL u32 closid; u32 rmid; #endif -- cgit v1.2.3-58-ga151 From e4f358916d528d479c3c12bd2fd03f2d5a576380 Mon Sep 17 00:00:00 2001 From: WANG Chao Date: Tue, 11 Dec 2018 00:37:25 +0800 Subject: x86, modpost: Replace last remnants of RETPOLINE with CONFIG_RETPOLINE Commit 4cd24de3a098 ("x86/retpoline: Make CONFIG_RETPOLINE depend on compiler support") replaced the RETPOLINE define with CONFIG_RETPOLINE checks. Remove the remaining pieces. [ bp: Massage commit message. ] Fixes: 4cd24de3a098 ("x86/retpoline: Make CONFIG_RETPOLINE depend on compiler support") Signed-off-by: WANG Chao Signed-off-by: Borislav Petkov Reviewed-by: Zhenzhong Duan Reviewed-by: Masahiro Yamada Cc: "H. Peter Anvin" Cc: Andi Kleen Cc: Andrew Morton Cc: Andy Lutomirski Cc: Arnd Bergmann Cc: Daniel Borkmann Cc: David Woodhouse Cc: Geert Uytterhoeven Cc: Jessica Yu Cc: Jiri Kosina Cc: Kees Cook Cc: Konrad Rzeszutek Wilk Cc: Luc Van Oostenryck Cc: Michal Marek Cc: Miguel Ojeda Cc: Peter Zijlstra Cc: Tim Chen Cc: Vasily Gorbik Cc: linux-kbuild@vger.kernel.org Cc: srinivas.eeda@oracle.com Cc: stable Cc: x86-ml Link: https://lkml.kernel.org/r/20181210163725.95977-1-chao.wang@ucloud.cn --- arch/x86/kernel/cpu/bugs.c | 2 +- include/linux/compiler-gcc.h | 2 +- include/linux/module.h | 2 +- scripts/mod/modpost.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 8654b8b0c848..1de0f4170178 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -215,7 +215,7 @@ static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init = static enum spectre_v2_user_mitigation spectre_v2_user __ro_after_init = SPECTRE_V2_USER_NONE; -#ifdef RETPOLINE +#ifdef CONFIG_RETPOLINE static bool spectre_v2_bad_module; bool retpoline_module_ok(bool has_retpoline) diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 5776da43da97..dd8268f5f5f0 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -68,7 +68,7 @@ */ #define uninitialized_var(x) x = x -#ifdef RETPOLINE +#ifdef CONFIG_RETPOLINE #define __noretpoline __attribute__((__indirect_branch__("keep"))) #endif diff --git a/include/linux/module.h b/include/linux/module.h index 9a21fe3509af..8fa38d3e7538 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -828,7 +828,7 @@ static inline void module_bug_finalize(const Elf_Ehdr *hdr, static inline void module_bug_cleanup(struct module *mod) {} #endif /* CONFIG_GENERIC_BUG */ -#ifdef RETPOLINE +#ifdef CONFIG_RETPOLINE extern bool retpoline_module_ok(bool has_retpoline); #else static inline bool retpoline_module_ok(bool has_retpoline) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 0de2fb236640..26bf886bd168 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2185,7 +2185,7 @@ static void add_intree_flag(struct buffer *b, int is_intree) /* Cannot check for assembler */ static void add_retpoline(struct buffer *b) { - buf_printf(b, "\n#ifdef RETPOLINE\n"); + buf_printf(b, "\n#ifdef CONFIG_RETPOLINE\n"); buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n"); buf_printf(b, "#endif\n"); } -- cgit v1.2.3-58-ga151 From 4842379cbe6e851de914a7132f76f4e200b9a98b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:48 +0200 Subject: drm/bridge: tc358767: add bus flags tc358767 driver does not set DRM bus_flags, even if it does configures the polarity settings into its registers. This means that the DPI source can't configure the polarities correctly. Add sync flags accordingly. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-2-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 8e28e738cb52..29a7e33e8ae0 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1195,6 +1195,10 @@ static int tc_bridge_attach(struct drm_bridge *bridge) drm_display_info_set_bus_formats(&tc->connector.display_info, &bus_format, 1); + tc->connector.display_info.bus_flags = + DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_NEGEDGE | + DRM_BUS_FLAG_SYNC_NEGEDGE; drm_connector_attach_encoder(&tc->connector, tc->bridge.encoder); return 0; -- cgit v1.2.3-58-ga151 From adf4109896bbee27fd2ac3b48d22d6a0062fe517 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:49 +0200 Subject: drm/bridge: tc358767: add defines for DP1_SRCCTRL & PHY_2LANE DP1_SRCCTRL register and PHY_2LANE field did not have matching defines. Add these. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-3-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 29a7e33e8ae0..5f0a666db2fd 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -142,6 +142,8 @@ #define DP0_LTLOOPCTRL 0x06d8 #define DP0_SNKLTCTRL 0x06e4 +#define DP1_SRCCTRL 0x07a0 + /* PHY */ #define DP_PHY_CTRL 0x0800 #define DP_PHY_RST BIT(28) /* DP PHY Global Soft Reset */ @@ -150,6 +152,7 @@ #define PHY_M1_RST BIT(12) /* Reset PHY1 Main Channel */ #define PHY_RDY BIT(16) /* PHY Main Channels Ready */ #define PHY_M0_RST BIT(8) /* Reset PHY0 Main Channel */ +#define PHY_2LANE BIT(2) /* PHY Enable 2 lanes */ #define PHY_A0_EN BIT(1) /* PHY Aux Channel0 Enable */ #define PHY_M0_EN BIT(0) /* PHY Main Channel0 Enable */ @@ -564,7 +567,7 @@ static int tc_aux_link_setup(struct tc_data *tc) value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2; tc_write(SYS_PLLPARAM, value); - tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN); + tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_2LANE | PHY_A0_EN); /* * Initially PLLs are in bypass. Force PLL parameter update, @@ -834,7 +837,7 @@ static int tc_main_link_setup(struct tc_data *tc) DP0_SRCCTRL_LANESKEW | DP0_SRCCTRL_LANES_2 | DP0_SRCCTRL_BW27 | DP0_SRCCTRL_AUTOCORRECT); /* from excel file - DP1_SrcCtrl */ - tc_write(0x07a0, 0x00003083); + tc_write(DP1_SRCCTRL, 0x00003083); rate = clk_get_rate(tc->refclk); switch (rate) { @@ -855,8 +858,9 @@ static int tc_main_link_setup(struct tc_data *tc) } value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2; tc_write(SYS_PLLPARAM, value); + /* Setup Main Link */ - dp_phy_ctrl = BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN | PHY_M0_EN; + dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_2LANE | PHY_A0_EN | PHY_M0_EN; tc_write(DP_PHY_CTRL, dp_phy_ctrl); msleep(100); -- cgit v1.2.3-58-ga151 From 4d9d54a730434cc068dd3515ba6116697196f77b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:50 +0200 Subject: drm/bridge: tc358767: fix single lane configuration PHY_2LANE bit is always set in DP_PHY_CTRL, breaking 1 lane use. Set PHY_2LANE only when 2 lanes are used. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-4-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 5f0a666db2fd..fee53422c31f 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -543,6 +543,7 @@ static int tc_aux_link_setup(struct tc_data *tc) unsigned long rate; u32 value; int ret; + u32 dp_phy_ctrl; rate = clk_get_rate(tc->refclk); switch (rate) { @@ -567,7 +568,10 @@ static int tc_aux_link_setup(struct tc_data *tc) value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2; tc_write(SYS_PLLPARAM, value); - tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_2LANE | PHY_A0_EN); + dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN; + if (tc->link.base.num_lanes == 2) + dp_phy_ctrl |= PHY_2LANE; + tc_write(DP_PHY_CTRL, dp_phy_ctrl); /* * Initially PLLs are in bypass. Force PLL parameter update, @@ -860,7 +864,9 @@ static int tc_main_link_setup(struct tc_data *tc) tc_write(SYS_PLLPARAM, value); /* Setup Main Link */ - dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_2LANE | PHY_A0_EN | PHY_M0_EN; + dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN | PHY_M0_EN; + if (tc->link.base.num_lanes == 2) + dp_phy_ctrl |= PHY_2LANE; tc_write(DP_PHY_CTRL, dp_phy_ctrl); msleep(100); -- cgit v1.2.3-58-ga151 From 9a63bd6fe1b5590ffa42ae2ed22ee21363293e31 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:51 +0200 Subject: drm/bridge: tc358767: fix initial DP0/1_SRCCTRL value Initially DP0_SRCCTRL is set to a static value which includes DP0_SRCCTRL_LANES_2 and DP0_SRCCTRL_BW27, even when only 1 lane of 1.62Gbps speed is used. DP1_SRCCTRL is configured to a magic number. This patch changes the configuration as follows: Configure DP0_SRCCTRL by using tc_srcctrl() which provides the correct value. DP1_SRCCTRL needs two bits to be set to the same value as DP0_SRCCTRL: SSCG and BW27. All other bits can be zero. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-5-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index fee53422c31f..ab299f4debfa 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -836,12 +836,11 @@ static int tc_main_link_setup(struct tc_data *tc) if (!tc->mode) return -EINVAL; - /* from excel file - DP0_SrcCtrl */ - tc_write(DP0_SRCCTRL, DP0_SRCCTRL_SCRMBLDIS | DP0_SRCCTRL_EN810B | - DP0_SRCCTRL_LANESKEW | DP0_SRCCTRL_LANES_2 | - DP0_SRCCTRL_BW27 | DP0_SRCCTRL_AUTOCORRECT); - /* from excel file - DP1_SrcCtrl */ - tc_write(DP1_SRCCTRL, 0x00003083); + tc_write(DP0_SRCCTRL, tc_srcctrl(tc)); + /* SSCG and BW27 on DP1 must be set to the same as on DP0 */ + tc_write(DP1_SRCCTRL, + (tc->link.spread ? DP0_SRCCTRL_SSCG : 0) | + ((tc->link.base.rate != 162000) ? DP0_SRCCTRL_BW27 : 0)); rate = clk_get_rate(tc->refclk); switch (rate) { -- cgit v1.2.3-58-ga151 From 51b9e62eb6950c762162ab7eb8390990179be067 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:52 +0200 Subject: drm/bridge: tc358767: reject modes which require too much BW The current driver accepts any videomode with pclk < 154MHz. This is not correct, as with 1 lane and/or 1.62Mbps speed not all videomodes can be supported. Add code to reject modes that require more bandwidth that is available. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-6-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index ab299f4debfa..a1f3dd2afbb1 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1114,10 +1114,20 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, static enum drm_mode_status tc_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct tc_data *tc = connector_to_tc(connector); + u32 req, avail; + u32 bits_per_pixel = 24; + /* DPI interface clock limitation: upto 154 MHz */ if (mode->clock > 154000) return MODE_CLOCK_HIGH; + req = mode->clock * bits_per_pixel / 8; + avail = tc->link.base.num_lanes * tc->link.base.rate; + + if (req > avail) + return MODE_BAD; + return MODE_OK; } -- cgit v1.2.3-58-ga151 From 7923e09c7a766e2d58de7fc395bb84c18e5bc625 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:53 +0200 Subject: drm/bridge: tc358767: fix output H/V syncs The H and V syncs of the DP output are always set to active high. This patch fixes the syncs by configuring them according to the videomode. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-7-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index a1f3dd2afbb1..391547358756 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -98,6 +98,8 @@ #define DP0_STARTVAL 0x064c #define DP0_ACTIVEVAL 0x0650 #define DP0_SYNCVAL 0x0654 +#define SYNCVAL_HS_POL_ACTIVE_LOW (1 << 15) +#define SYNCVAL_VS_POL_ACTIVE_LOW (1 << 31) #define DP0_MISC 0x0658 #define TU_SIZE_RECOMMENDED (63) /* LSCLK cycles per TU */ #define BPC_6 (0 << 5) @@ -726,7 +728,9 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) tc_write(DP0_ACTIVEVAL, (mode->vdisplay << 16) | (mode->hdisplay)); - tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0)); + tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0) | + ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? SYNCVAL_HS_POL_ACTIVE_LOW : 0) | + ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? SYNCVAL_VS_POL_ACTIVE_LOW : 0)); tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW | DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888); -- cgit v1.2.3-58-ga151 From f8c15790e4d8bdf2d21a5e9d43b5f97983af1222 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:54 +0200 Subject: drm/bridge: tc358767: use DP connector if no panel set tc358767 driver sets the connector type always to eDP. This patch sets the type to DP if there is no panel defined, which implies that there's a DP connector on the board. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-8-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 391547358756..e6403b9549f1 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1209,7 +1209,8 @@ static int tc_bridge_attach(struct drm_bridge *bridge) /* Create eDP connector */ drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs); ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, - DRM_MODE_CONNECTOR_eDP); + tc->panel ? DRM_MODE_CONNECTOR_eDP : + DRM_MODE_CONNECTOR_DisplayPort); if (ret) return ret; -- cgit v1.2.3-58-ga151 From 3e2ffd655cc6a694608d997738989ff5572a8266 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 2 Jan 2019 15:57:49 -0500 Subject: include/linux/compiler*.h: fix OPTIMIZER_HIDE_VAR Since commit 815f0ddb346c ("include/linux/compiler*.h: make compiler-*.h mutually exclusive") clang no longer reuses the OPTIMIZER_HIDE_VAR macro from compiler-gcc - instead it gets the version in include/linux/compiler.h. Unfortunately that version doesn't actually prevent compiler from optimizing out the variable. Fix up by moving the macro out from compiler-gcc.h to compiler.h. Compilers without incline asm support will keep working since it's protected by an ifdef. Also fix up comments to match reality since we are no longer overriding any macros. Build-tested with gcc and clang. Fixes: 815f0ddb346c ("include/linux/compiler*.h: make compiler-*.h mutually exclusive") Cc: Eli Friedman Cc: Joe Perches Cc: Linus Torvalds Reviewed-by: Nick Desaulniers Signed-off-by: Michael S. Tsirkin Signed-off-by: Miguel Ojeda --- include/linux/compiler-clang.h | 5 ++--- include/linux/compiler-gcc.h | 4 ---- include/linux/compiler-intel.h | 4 +--- include/linux/compiler.h | 4 +++- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index 39f668d5066b..333a6695a918 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -3,9 +3,8 @@ #error "Please don't include directly, include instead." #endif -/* Some compiler specific definitions are overwritten here - * for Clang compiler - */ +/* Compiler specific definitions for Clang compiler */ + #define uninitialized_var(x) x = *(&(x)) /* same as gcc, this was present in clang-2.6 so we can assume it works diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 5776da43da97..7b834e37d0c0 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -58,10 +58,6 @@ (typeof(ptr)) (__ptr + (off)); \ }) -/* Make the optimizer believe the variable can be manipulated arbitrarily. */ -#define OPTIMIZER_HIDE_VAR(var) \ - __asm__ ("" : "=r" (var) : "0" (var)) - /* * A trick to suppress uninitialized variable warning without generating any * code diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index 517bd14e1222..b17f3cd18334 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -5,9 +5,7 @@ #ifdef __ECC -/* Some compiler specific definitions are overwritten here - * for Intel ECC compiler - */ +/* Compiler specific definitions for Intel ECC compiler */ #include diff --git a/include/linux/compiler.h b/include/linux/compiler.h index fc5004a4b07d..445348facea9 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -161,7 +161,9 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, #endif #ifndef OPTIMIZER_HIDE_VAR -#define OPTIMIZER_HIDE_VAR(var) barrier() +/* Make the optimizer believe the variable can be manipulated arbitrarily. */ +#define OPTIMIZER_HIDE_VAR(var) \ + __asm__ ("" : "=r" (var) : "0" (var)) #endif /* Not-quite-unique ID. */ -- cgit v1.2.3-58-ga151 From 7604bf0920985c9280c8b24e2f0c3e4ed47f502f Mon Sep 17 00:00:00 2001 From: Otto Sabart Date: Wed, 9 Jan 2019 00:56:51 +0100 Subject: doc: trace: fix reference to cpuidle documentation file Old cpuidle/sysfs.txt file was replaced in aa5eee355b46. So, refer to an updated file. Fixes: aa5eee355b46 (Documentation: admin-guide: PM: Add cpuidle document) Signed-off-by: Otto Sabart Signed-off-by: Rafael J. Wysocki --- Documentation/trace/coresight-cpu-debug.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/trace/coresight-cpu-debug.txt b/Documentation/trace/coresight-cpu-debug.txt index 89ab09e78e8d..f07e38094b40 100644 --- a/Documentation/trace/coresight-cpu-debug.txt +++ b/Documentation/trace/coresight-cpu-debug.txt @@ -165,7 +165,7 @@ Do some work... The same can also be done from an application program. Disable specific CPU's specific idle state from cpuidle sysfs (see -Documentation/cpuidle/sysfs.txt): +Documentation/admin-guide/pm/cpuidle.rst): # echo 1 > /sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable -- cgit v1.2.3-58-ga151 From 0e141d1c65c1dd31c914eb2e11651adcc1a15912 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Wed, 9 Jan 2019 10:42:36 +0000 Subject: cpufreq: scmi: Fix frequency invariance in slow path The scmi-cpufreq driver calls the arch_set_freq_scale() callback on frequency changes to provide scale-invariant load-tracking signals to the scheduler. However, in the slow path, it does so while specifying the current and max frequencies in different units, hence resulting in a broken freq_scale factor. Fix this by passing all frequencies in KHz, as stored in the CPUFreq frequency table. Fixes: 99d6bdf33877 (cpufreq: add support for CPU DVFS based on SCMI message protocol) Signed-off-by: Quentin Perret Acked-by: Viresh Kumar Acked-by: Sudeep Holla Cc: 4.17+ # v4.17+ Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/scmi-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index c2e66528f5ee..242c3370544e 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -52,9 +52,9 @@ scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) int ret; struct scmi_data *priv = policy->driver_data; struct scmi_perf_ops *perf_ops = handle->perf_ops; - u64 freq = policy->freq_table[index].frequency * 1000; + u64 freq = policy->freq_table[index].frequency; - ret = perf_ops->freq_set(handle, priv->domain_id, freq, false); + ret = perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false); if (!ret) arch_set_freq_scale(policy->related_cpus, freq, policy->cpuinfo.max_freq); -- cgit v1.2.3-58-ga151 From 498c203d855eaf6571b63ea860a53862c4fe91b7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Jan 2019 10:02:12 -0300 Subject: tools include uapi: Sync linux/if_link.h copy with the kernel sources To pick the changes from: a428afe82f98 ("net: bridge: add support for user-controlled bool options") a025fb5f49ad ("geneve: Allow configuration of DF behaviour") b4d3069783bc ("vxlan: Allow configuration of DF behaviour") Silencing this tools/ build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/if_link.h' differs from latest version at 'include/uapi/linux/if_link.h' Cc: Adrian Hunter Cc: David S. Miller Cc: Jiri Olsa Cc: Namhyung Kim Cc: Nikolay Aleksandrov Cc: Stefano Brivio Link: https://lkml.kernel.org/n/tip-wq410s2wuqv5k980bidw0ju8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/if_link.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index 1debfa42cba1..d6533828123a 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -288,6 +288,7 @@ enum { IFLA_BR_MCAST_IGMP_VERSION, IFLA_BR_MCAST_MLD_VERSION, IFLA_BR_VLAN_STATS_PER_PORT, + IFLA_BR_MULTI_BOOLOPT, __IFLA_BR_MAX, }; @@ -533,6 +534,7 @@ enum { IFLA_VXLAN_LABEL, IFLA_VXLAN_GPE, IFLA_VXLAN_TTL_INHERIT, + IFLA_VXLAN_DF, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) @@ -542,6 +544,14 @@ struct ifla_vxlan_port_range { __be16 high; }; +enum ifla_vxlan_df { + VXLAN_DF_UNSET = 0, + VXLAN_DF_SET, + VXLAN_DF_INHERIT, + __VXLAN_DF_END, + VXLAN_DF_MAX = __VXLAN_DF_END - 1, +}; + /* GENEVE section */ enum { IFLA_GENEVE_UNSPEC, @@ -557,10 +567,19 @@ enum { IFLA_GENEVE_UDP_ZERO_CSUM6_RX, IFLA_GENEVE_LABEL, IFLA_GENEVE_TTL_INHERIT, + IFLA_GENEVE_DF, __IFLA_GENEVE_MAX }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) +enum ifla_geneve_df { + GENEVE_DF_UNSET = 0, + GENEVE_DF_SET, + GENEVE_DF_INHERIT, + __GENEVE_DF_END, + GENEVE_DF_MAX = __GENEVE_DF_END - 1, +}; + /* PPP section */ enum { IFLA_PPP_UNSPEC, -- cgit v1.2.3-58-ga151 From f7fa1107f30e13255fb9a5359d357e07d3721b0b Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 8 Jan 2019 11:42:54 +0000 Subject: Btrfs: fix race between cloning range ending at eof and writeback The recent rework that makes btrfs' remap_file_range operation use the generic helper generic_remap_file_range_prep() introduced a race between writeback and cloning a range that covers the eof extent of the source file into a destination offset that is greater then the same file's size. This happens because we now wait for writeback to complete before doing the truncation of the eof block, while previously we did the truncation and then waited for writeback to complete. This leads to a race between writeback of the truncated block and cloning the file extents in the source range, because we copy each file extent item we find in the fs root into a buffer, then release the path and then increment the reference count for the extent referred in that file extent item we copied, which can no longer exist if writeback of the truncated eof block completes after we copied the file extent item into the buffer and before we incremented the reference count. This is illustrated by the following diagram: CPU 1 CPU 2 btrfs_clone_files() btrfs_cont_expand() btrfs_truncate_block() --> zeroes part of the page containg eof, marking it for delalloc btrfs_clone() --> finds extent item covering eof, points to extent at bytenr X --> copies it into a local buffer --> releases path writeback starts btrfs_finish_ordered_io() insert_reserved_file_extent() __btrfs_drop_extents() --> creates delayed reference to drop the extent at bytenr X --> starts transaction --> creates delayed reference to increment extent at bytenr X When this race is hit the running transaction ends up getting aborted with an -EIO error and a trace like the following is produced: [ 4382.553858] WARNING: CPU: 2 PID: 3648 at fs/btrfs/extent-tree.c:1552 lookup_inline_extent_backref+0x4f4/0x650 [btrfs] (...) [ 4382.556293] CPU: 2 PID: 3648 Comm: btrfs Tainted: G W 4.20.0-rc6-btrfs-next-41 #1 [ 4382.556294] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org 04/01/2014 [ 4382.556308] RIP: 0010:lookup_inline_extent_backref+0x4f4/0x650 [btrfs] (...) [ 4382.556310] RSP: 0018:ffffac784408f738 EFLAGS: 00010202 [ 4382.556311] RAX: 0000000000000001 RBX: ffff8980673c3a48 RCX: 0000000000000001 [ 4382.556312] RDX: 0000000000000008 RSI: 0000000000000000 RDI: 0000000000000000 [ 4382.556312] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000001 [ 4382.556313] R10: 0000000000000001 R11: ffff897f40000000 R12: 0000000000001000 [ 4382.556313] R13: 00000000c224f000 R14: ffff89805de9bd40 R15: ffff8980453f4548 [ 4382.556315] FS: 00007f5e759178c0(0000) GS:ffff89807b300000(0000) knlGS:0000000000000000 [ 4382.563130] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 4382.563562] CR2: 00007f2e9789fcbc CR3: 0000000120512001 CR4: 00000000003606e0 [ 4382.564005] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 4382.564451] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 4382.564887] Call Trace: [ 4382.565343] insert_inline_extent_backref+0x55/0xe0 [btrfs] [ 4382.565796] __btrfs_inc_extent_ref.isra.60+0x88/0x260 [btrfs] [ 4382.566249] ? __btrfs_run_delayed_refs+0x93/0x1650 [btrfs] [ 4382.566702] __btrfs_run_delayed_refs+0xa22/0x1650 [btrfs] [ 4382.567162] btrfs_run_delayed_refs+0x7e/0x1d0 [btrfs] [ 4382.567623] btrfs_commit_transaction+0x50/0x9c0 [btrfs] [ 4382.568112] ? _raw_spin_unlock+0x24/0x30 [ 4382.568557] ? block_rsv_release_bytes+0x14e/0x410 [btrfs] [ 4382.569006] create_subvol+0x3c8/0x830 [btrfs] [ 4382.569461] ? btrfs_mksubvol+0x317/0x600 [btrfs] [ 4382.569906] btrfs_mksubvol+0x317/0x600 [btrfs] [ 4382.570383] ? rcu_sync_lockdep_assert+0xe/0x60 [ 4382.570822] ? __sb_start_write+0xd4/0x1c0 [ 4382.571262] ? mnt_want_write_file+0x24/0x50 [ 4382.571712] btrfs_ioctl_snap_create_transid+0x117/0x1a0 [btrfs] [ 4382.572155] ? _copy_from_user+0x66/0x90 [ 4382.572602] btrfs_ioctl_snap_create+0x66/0x80 [btrfs] [ 4382.573052] btrfs_ioctl+0x7c1/0x30e0 [btrfs] [ 4382.573502] ? mem_cgroup_commit_charge+0x8b/0x570 [ 4382.573946] ? do_raw_spin_unlock+0x49/0xc0 [ 4382.574379] ? _raw_spin_unlock+0x24/0x30 [ 4382.574803] ? __handle_mm_fault+0xf29/0x12d0 [ 4382.575215] ? do_vfs_ioctl+0xa2/0x6f0 [ 4382.575622] ? btrfs_ioctl_get_supported_features+0x30/0x30 [btrfs] [ 4382.576020] do_vfs_ioctl+0xa2/0x6f0 [ 4382.576405] ksys_ioctl+0x70/0x80 [ 4382.576776] __x64_sys_ioctl+0x16/0x20 [ 4382.577137] do_syscall_64+0x60/0x1b0 [ 4382.577488] entry_SYSCALL_64_after_hwframe+0x49/0xbe (...) [ 4382.578837] RSP: 002b:00007ffe04bf64c8 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 [ 4382.579174] RAX: ffffffffffffffda RBX: 00005564136f3050 RCX: 00007f5e74724dd7 [ 4382.579505] RDX: 00007ffe04bf64d0 RSI: 000000005000940e RDI: 0000000000000003 [ 4382.579848] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000044 [ 4382.580164] R10: 0000000000000541 R11: 0000000000000202 R12: 00005564136f3010 [ 4382.580477] R13: 0000000000000003 R14: 00005564136f3035 R15: 00005564136f3050 [ 4382.580792] irq event stamp: 0 [ 4382.581106] hardirqs last enabled at (0): [<0000000000000000>] (null) [ 4382.581441] hardirqs last disabled at (0): [] copy_process.part.32+0x6e2/0x2320 [ 4382.581772] softirqs last enabled at (0): [] copy_process.part.32+0x6e2/0x2320 [ 4382.582095] softirqs last disabled at (0): [<0000000000000000>] (null) [ 4382.582413] ---[ end trace d3c188e3e9367382 ]--- [ 4382.623855] BTRFS: error (device sdc) in btrfs_run_delayed_refs:2981: errno=-5 IO failure [ 4382.624295] BTRFS info (device sdc): forced readonly Fix this by waiting for writeback to complete after truncating the eof block. Fixes: 34a28e3d7753 ("Btrfs: use generic_remap_file_range_prep() for cloning and deduplication") Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index fab9443f6a42..d0da86ac53bf 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -3905,9 +3905,24 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, len = ALIGN(src->i_size, bs) - off; if (destoff > inode->i_size) { + const u64 wb_start = ALIGN_DOWN(inode->i_size, bs); + ret = btrfs_cont_expand(inode, inode->i_size, destoff); if (ret) return ret; + /* + * We may have truncated the last block if the inode's size is + * not sector size aligned, so we need to wait for writeback to + * complete before proceeding further, otherwise we can race + * with cloning and attempt to increment a reference to an + * extent that no longer exists (writeback completed right after + * we found the previous extent covering eof and before we + * attempted to increment its reference count). + */ + ret = btrfs_wait_ordered_range(inode, wb_start, + destoff - wb_start); + if (ret) + return ret; } /* -- cgit v1.2.3-58-ga151 From d8b5524242108cb7d28c9b8b9aded7c1edd0e8a8 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 8 Jan 2019 11:43:07 +0000 Subject: Btrfs: fix race between reflink/dedupe and relocation The recent rework that makes btrfs' remap_file_range operation use the generic helper generic_remap_file_range_prep() introduced a race between relocation and reflinking (for both cloning and deduplication) the file extents between the source and destination inodes. This happens because we no longer lock the source range anymore, and we do not lock it anymore because we wait for direct IO writes and writeback to complete early on the code path right after locking the inodes, which guarantees no other file operations interfere with the reflinking. However there is one exception which is relocation, since it replaces the byte number of file extents items in the fs tree after locking the range the file extent items represent. This is a problem because after finding each file extent to clone in the fs tree, the reflink process copies the file extent item into a local buffer, releases the search path, inserts new file extent items in the destination range and then increments the reference count for the extent mentioned in the file extent item that it previously copied to the buffer. If right after copying the file extent item into the buffer and releasing the path the relocation process updates the file extent item to point to the new extent, the reflink process ends up creating a delayed reference to increment the reference count of the old extent, for which the relocation process already created a delayed reference to drop it. This results in failure to run delayed references because we will attempt to increment the count of a reference that was already dropped. This is illustrated by the following diagram: CPU 1 CPU 2 relocation is running btrfs_clone_files() btrfs_clone() --> finds extent item in source range point to extent at bytenr X --> copies it into a local buffer --> releases path replace_file_extents() --> successfully locks the range represented by the file extent item --> replaces disk_bytenr field in the file extent item with some other value Y --> creates delayed reference to increment reference count for extent at bytenr Y --> creates delayed reference to drop the extent at bytenr X --> starts transaction --> creates delayed reference to increment extent at bytenr X When this race is hit the running transaction ends up getting aborted with an -EIO error and a trace like the following is produced: [ 4382.553858] WARNING: CPU: 2 PID: 3648 at fs/btrfs/extent-tree.c:1552 lookup_inline_extent_backref+0x4f4/0x650 [btrfs] (...) [ 4382.556293] CPU: 2 PID: 3648 Comm: btrfs Tainted: G W 4.20.0-rc6-btrfs-next-41 #1 [ 4382.556294] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org 04/01/2014 [ 4382.556308] RIP: 0010:lookup_inline_extent_backref+0x4f4/0x650 [btrfs] (...) [ 4382.556310] RSP: 0018:ffffac784408f738 EFLAGS: 00010202 [ 4382.556311] RAX: 0000000000000001 RBX: ffff8980673c3a48 RCX: 0000000000000001 [ 4382.556312] RDX: 0000000000000008 RSI: 0000000000000000 RDI: 0000000000000000 [ 4382.556312] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000001 [ 4382.556313] R10: 0000000000000001 R11: ffff897f40000000 R12: 0000000000001000 [ 4382.556313] R13: 00000000c224f000 R14: ffff89805de9bd40 R15: ffff8980453f4548 [ 4382.556315] FS: 00007f5e759178c0(0000) GS:ffff89807b300000(0000) knlGS:0000000000000000 [ 4382.563130] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 4382.563562] CR2: 00007f2e9789fcbc CR3: 0000000120512001 CR4: 00000000003606e0 [ 4382.564005] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 4382.564451] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 4382.564887] Call Trace: [ 4382.565343] insert_inline_extent_backref+0x55/0xe0 [btrfs] [ 4382.565796] __btrfs_inc_extent_ref.isra.60+0x88/0x260 [btrfs] [ 4382.566249] ? __btrfs_run_delayed_refs+0x93/0x1650 [btrfs] [ 4382.566702] __btrfs_run_delayed_refs+0xa22/0x1650 [btrfs] [ 4382.567162] btrfs_run_delayed_refs+0x7e/0x1d0 [btrfs] [ 4382.567623] btrfs_commit_transaction+0x50/0x9c0 [btrfs] [ 4382.568112] ? _raw_spin_unlock+0x24/0x30 [ 4382.568557] ? block_rsv_release_bytes+0x14e/0x410 [btrfs] [ 4382.569006] create_subvol+0x3c8/0x830 [btrfs] [ 4382.569461] ? btrfs_mksubvol+0x317/0x600 [btrfs] [ 4382.569906] btrfs_mksubvol+0x317/0x600 [btrfs] [ 4382.570383] ? rcu_sync_lockdep_assert+0xe/0x60 [ 4382.570822] ? __sb_start_write+0xd4/0x1c0 [ 4382.571262] ? mnt_want_write_file+0x24/0x50 [ 4382.571712] btrfs_ioctl_snap_create_transid+0x117/0x1a0 [btrfs] [ 4382.572155] ? _copy_from_user+0x66/0x90 [ 4382.572602] btrfs_ioctl_snap_create+0x66/0x80 [btrfs] [ 4382.573052] btrfs_ioctl+0x7c1/0x30e0 [btrfs] [ 4382.573502] ? mem_cgroup_commit_charge+0x8b/0x570 [ 4382.573946] ? do_raw_spin_unlock+0x49/0xc0 [ 4382.574379] ? _raw_spin_unlock+0x24/0x30 [ 4382.574803] ? __handle_mm_fault+0xf29/0x12d0 [ 4382.575215] ? do_vfs_ioctl+0xa2/0x6f0 [ 4382.575622] ? btrfs_ioctl_get_supported_features+0x30/0x30 [btrfs] [ 4382.576020] do_vfs_ioctl+0xa2/0x6f0 [ 4382.576405] ksys_ioctl+0x70/0x80 [ 4382.576776] __x64_sys_ioctl+0x16/0x20 [ 4382.577137] do_syscall_64+0x60/0x1b0 [ 4382.577488] entry_SYSCALL_64_after_hwframe+0x49/0xbe (...) [ 4382.578837] RSP: 002b:00007ffe04bf64c8 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 [ 4382.579174] RAX: ffffffffffffffda RBX: 00005564136f3050 RCX: 00007f5e74724dd7 [ 4382.579505] RDX: 00007ffe04bf64d0 RSI: 000000005000940e RDI: 0000000000000003 [ 4382.579848] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000044 [ 4382.580164] R10: 0000000000000541 R11: 0000000000000202 R12: 00005564136f3010 [ 4382.580477] R13: 0000000000000003 R14: 00005564136f3035 R15: 00005564136f3050 [ 4382.580792] irq event stamp: 0 [ 4382.581106] hardirqs last enabled at (0): [<0000000000000000>] (null) [ 4382.581441] hardirqs last disabled at (0): [] copy_process.part.32+0x6e2/0x2320 [ 4382.581772] softirqs last enabled at (0): [] copy_process.part.32+0x6e2/0x2320 [ 4382.582095] softirqs last disabled at (0): [<0000000000000000>] (null) [ 4382.582413] ---[ end trace d3c188e3e9367382 ]--- [ 4382.623855] BTRFS: error (device sdc) in btrfs_run_delayed_refs:2981: errno=-5 IO failure [ 4382.624295] BTRFS info (device sdc): forced readonly Fix this by locking the source range before searching for the file extent items in the fs tree, since the relocation process will try to lock the range a file extent item represents before updating it with the new extent location. Fixes: 34a28e3d7753 ("Btrfs: use generic_remap_file_range_prep() for cloning and deduplication") Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/ioctl.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d0da86ac53bf..9c8e1734429c 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -3221,6 +3221,26 @@ static void btrfs_double_inode_lock(struct inode *inode1, struct inode *inode2) inode_lock_nested(inode2, I_MUTEX_CHILD); } +static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1, + struct inode *inode2, u64 loff2, u64 len) +{ + unlock_extent(&BTRFS_I(inode1)->io_tree, loff1, loff1 + len - 1); + unlock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1); +} + +static void btrfs_double_extent_lock(struct inode *inode1, u64 loff1, + struct inode *inode2, u64 loff2, u64 len) +{ + if (inode1 < inode2) { + swap(inode1, inode2); + swap(loff1, loff2); + } else if (inode1 == inode2 && loff2 < loff1) { + swap(loff1, loff2); + } + lock_extent(&BTRFS_I(inode1)->io_tree, loff1, loff1 + len - 1); + lock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1); +} + static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 olen, struct inode *dst, u64 dst_loff) { @@ -3242,11 +3262,12 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 olen, return -EINVAL; /* - * Lock destination range to serialize with concurrent readpages(). + * Lock destination range to serialize with concurrent readpages() and + * source range to serialize with relocation. */ - lock_extent(&BTRFS_I(dst)->io_tree, dst_loff, dst_loff + len - 1); + btrfs_double_extent_lock(src, loff, dst, dst_loff, len); ret = btrfs_clone(src, dst, loff, olen, len, dst_loff, 1); - unlock_extent(&BTRFS_I(dst)->io_tree, dst_loff, dst_loff + len - 1); + btrfs_double_extent_unlock(src, loff, dst, dst_loff, len); return ret; } @@ -3926,11 +3947,12 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, } /* - * Lock destination range to serialize with concurrent readpages(). + * Lock destination range to serialize with concurrent readpages() and + * source range to serialize with relocation. */ - lock_extent(&BTRFS_I(inode)->io_tree, destoff, destoff + len - 1); + btrfs_double_extent_lock(src, off, inode, destoff, len); ret = btrfs_clone(src, inode, off, olen, len, destoff, 0); - unlock_extent(&BTRFS_I(inode)->io_tree, destoff, destoff + len - 1); + btrfs_double_extent_unlock(src, off, inode, destoff, len); /* * Truncate page cache pages so that future reads will see the cloned * data immediately and not the previous data. -- cgit v1.2.3-58-ga151 From a6d8654d885d7d79a3fb82da64eaa489ca332a82 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 8 Jan 2019 11:44:41 +0000 Subject: Btrfs: fix deadlock when using free space tree due to block group creation When modifying the free space tree we can end up COWing one of its extent buffers which in turn might result in allocating a new chunk, which in turn can result in flushing (finish creation) of pending block groups. If that happens we can deadlock because creating a pending block group needs to update the free space tree, and if any of the updates tries to modify the same extent buffer that we are COWing, we end up in a deadlock since we try to write lock twice the same extent buffer. So fix this by skipping pending block group creation if we are COWing an extent buffer from the free space tree. This is a case missed by commit 5ce555578e091 ("Btrfs: fix deadlock when writing out free space caches"). Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=202173 Fixes: 5ce555578e091 ("Btrfs: fix deadlock when writing out free space caches") CC: stable@vger.kernel.org # 4.18+ Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/ctree.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index d92462fe66c8..f64aad613727 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1016,19 +1016,21 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, parent_start = parent->start; /* - * If we are COWing a node/leaf from the extent, chunk or device trees, - * make sure that we do not finish block group creation of pending block - * groups. We do this to avoid a deadlock. + * If we are COWing a node/leaf from the extent, chunk, device or free + * space trees, make sure that we do not finish block group creation of + * pending block groups. We do this to avoid a deadlock. * COWing can result in allocation of a new chunk, and flushing pending * block groups (btrfs_create_pending_block_groups()) can be triggered * when finishing allocation of a new chunk. Creation of a pending block - * group modifies the extent, chunk and device trees, therefore we could - * deadlock with ourselves since we are holding a lock on an extent - * buffer that btrfs_create_pending_block_groups() may try to COW later. + * group modifies the extent, chunk, device and free space trees, + * therefore we could deadlock with ourselves since we are holding a + * lock on an extent buffer that btrfs_create_pending_block_groups() may + * try to COW later. */ if (root == fs_info->extent_root || root == fs_info->chunk_root || - root == fs_info->dev_root) + root == fs_info->dev_root || + root == fs_info->free_space_root) trans->can_flush_pending_bgs = false; cow = btrfs_alloc_tree_block(trans, root, parent_start, -- cgit v1.2.3-58-ga151 From a6028cc60aad18d5d7c25d99b5cb8c24399387c3 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Mon, 7 Jan 2019 16:11:46 +0000 Subject: ASoC: da7219: MCLK should be enabled before DAI clocks For platforms using the Common Clock Framework to control the codec's DAI clocks, MCLK should be enabled prior to DAI clocks being turned on. For some platforms the codec is already provided with an MCLK reference and can therefore control MCLK itself as it needs to. To improve functionality MCLK is now added as a parent to the DAI clocks, if MCLK was provided, so that if they are enabled MCLK will automatically be enabled as a prerequisite by the CCF. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 513ec0368653..a20a610c7ee5 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1804,7 +1804,7 @@ static const struct clk_ops da7219_dai_clks_ops = { .is_prepared = da7219_dai_clks_is_prepared, }; -static void da7219_register_dai_clks(struct snd_soc_component *component) +static int da7219_register_dai_clks(struct snd_soc_component *component) { struct device *dev = component->dev; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); @@ -1812,9 +1812,17 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) struct clk_init_data init = {}; struct clk *dai_clks; struct clk_lookup *dai_clks_lookup; + const char *parent_name; + + if (da7219->mclk) { + parent_name = __clk_get_name(da7219->mclk); + init.parent_names = &parent_name; + init.num_parents = 1; + } else { + init.parent_names = NULL; + init.num_parents = 0; + } - init.parent_names = NULL; - init.num_parents = 0; init.name = pdata->dai_clks_name; init.ops = &da7219_dai_clks_ops; da7219->dai_clks_hw.init = &init; @@ -1823,7 +1831,7 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) if (IS_ERR(dai_clks)) { dev_warn(dev, "Failed to register DAI clocks: %ld\n", PTR_ERR(dai_clks)); - return; + return PTR_ERR(dai_clks); } da7219->dai_clks = dai_clks; @@ -1835,13 +1843,18 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) dai_clks_lookup = clkdev_create(dai_clks, pdata->dai_clks_name, "%s", dev_name(dev)); if (!dai_clks_lookup) - dev_warn(dev, "Failed to create DAI clkdev"); + return -ENOMEM; else da7219->dai_clks_lookup = dai_clks_lookup; } + + return 0; } #else -static inline void da7219_register_dai_clks(struct snd_soc_component *component) {} +static inline int da7219_register_dai_clks(struct snd_soc_component *component) +{ + return 0; +} #endif /* CONFIG_COMMON_CLK */ static void da7219_handle_pdata(struct snd_soc_component *component) @@ -1854,8 +1867,6 @@ static void da7219_handle_pdata(struct snd_soc_component *component) da7219->wakeup_source = pdata->wakeup_source; - da7219_register_dai_clks(component); - /* Mic Bias voltages */ switch (pdata->micbias_lvl) { case DA7219_MICBIAS_1_6V: @@ -1947,6 +1958,11 @@ static int da7219_probe(struct snd_soc_component *component) } } + /* Register CCF DAI clock control */ + ret = da7219_register_dai_clks(component); + if (ret) + return ret; + /* Default PC counter to free-running */ snd_soc_component_update_bits(component, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK, DA7219_PC_FREERUN_MASK); -- cgit v1.2.3-58-ga151 From 47cb393ee4815e10ab66f981fed581afdcc7caac Mon Sep 17 00:00:00 2001 From: John Pittman Date: Tue, 8 Jan 2019 16:56:13 -0500 Subject: block: doc: add slice_idle_us to bfq documentation Of the tunables available for the bfq I/O scheduler, the only one missing from the documentation in 'Documentation/block/bfq-iosched.txt' is slice_idle_us. Add this tunable to the documentation and a short explanation of its purpose. Acked-by: Paolo Valente Signed-off-by: John Pittman Signed-off-by: Jens Axboe --- Documentation/block/bfq-iosched.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/block/bfq-iosched.txt b/Documentation/block/bfq-iosched.txt index 8d8d8f06cab2..98a8dd5ee385 100644 --- a/Documentation/block/bfq-iosched.txt +++ b/Documentation/block/bfq-iosched.txt @@ -357,6 +357,13 @@ video playing/streaming, a very low drop rate may be more important than maximum throughput. In these cases, consider setting the strict_guarantees parameter. +slice_idle_us +------------- + +Controls the same tuning parameter as slice_idle, but in microseconds. +Either tunable can be used to set idling behavior. Afterwards, the +other tunable will reflect the newly set value in sysfs. + strict_guarantees ----------------- -- cgit v1.2.3-58-ga151 From a58943abcb08cfbe6c36648602d796c5834ee8a9 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 8 Jan 2019 09:13:28 +0000 Subject: ASoC: da7219: Add recalc_rate function to return DAI clock rate By making MCLK parent of DAI clocks, when querying the rate of the clock the rate returned is now given from the parent clock so gives the MCLK rate rather than 0 as previously returned. This is a bit misleading, and actually there's no major reason why we can't at least return the DAI WCLK rate, as set in HW, so that's what we now do. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/da7219.h | 1 + 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index a20a610c7ee5..b1df4bb36105 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1767,7 +1767,7 @@ static int da7219_dai_clks_prepare(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, @@ -1780,7 +1780,7 @@ static void da7219_dai_clks_unprepare(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, 0); @@ -1790,7 +1790,7 @@ static int da7219_dai_clks_is_prepared(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; u8 clk_reg; clk_reg = snd_soc_component_read32(component, DA7219_DAI_CLK_MODE); @@ -1798,10 +1798,47 @@ static int da7219_dai_clks_is_prepared(struct clk_hw *hw) return !!(clk_reg & DA7219_DAI_CLK_EN_MASK); } +static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct da7219_priv *da7219 = + container_of(hw, struct da7219_priv, dai_clks_hw); + struct snd_soc_component *component = da7219->component; + u8 fs = snd_soc_component_read32(component, DA7219_SR); + + switch (fs & DA7219_SR_MASK) { + case DA7219_SR_8000: + return 8000; + case DA7219_SR_11025: + return 11025; + case DA7219_SR_12000: + return 12000; + case DA7219_SR_16000: + return 16000; + case DA7219_SR_22050: + return 22050; + case DA7219_SR_24000: + return 24000; + case DA7219_SR_32000: + return 32000; + case DA7219_SR_44100: + return 44100; + case DA7219_SR_48000: + return 48000; + case DA7219_SR_88200: + return 88200; + case DA7219_SR_96000: + return 96000; + default: + return 0; + } +} + static const struct clk_ops da7219_dai_clks_ops = { .prepare = da7219_dai_clks_prepare, .unprepare = da7219_dai_clks_unprepare, .is_prepared = da7219_dai_clks_is_prepared, + .recalc_rate = da7219_dai_clks_recalc_rate, }; static int da7219_register_dai_clks(struct snd_soc_component *component) @@ -1825,6 +1862,7 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) init.name = pdata->dai_clks_name; init.ops = &da7219_dai_clks_ops; + init.flags = CLK_GET_RATE_NOCACHE; da7219->dai_clks_hw.init = &init; dai_clks = devm_clk_register(dev, &da7219->dai_clks_hw); @@ -1912,6 +1950,7 @@ static int da7219_probe(struct snd_soc_component *component) unsigned int rev; int ret; + da7219->component = component; mutex_init(&da7219->ctrl_lock); mutex_init(&da7219->pll_lock); diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 3a006862f0e7..366cf46118a0 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -809,6 +809,7 @@ struct da7219_aad_priv; /* Private data */ struct da7219_priv { + struct snd_soc_component *component; struct da7219_aad_priv *aad; struct da7219_pdata *pdata; -- cgit v1.2.3-58-ga151 From 48504619a65977fb2a4c7182eab637867f1e6548 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 18 Dec 2018 06:43:09 +0000 Subject: clk: imx: fix potential NULL dereference in imx8qxp_lpcg_clk_probe() platform_get_resource() may fail and return NULL, so we should better check it's return value to avoid a NULL pointer dereference a bit later in the code. This is detected by Coccinelle semantic patch. @@ expression pdev, res, n, t, e, e1, e2; @@ res = platform_get_resource(pdev, t, n); + if (!res) + return -EINVAL; ... when != res == NULL e = devm_ioremap(e1, res->start, e2); Fixes: 1e3121bfe51a ("clk: imx: add imx8qxp lpcg driver") Signed-off-by: Wei Yongjun Reviewed-by: Dong Aisheng Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx8qxp-lpcg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c index 99c2508de8e5..fb6edf1b8aa2 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -169,6 +169,8 @@ static int imx8qxp_lpcg_clk_probe(struct platform_device *pdev) return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; base = devm_ioremap(dev, res->start, resource_size(res)); if (!base) return -ENOMEM; -- cgit v1.2.3-58-ga151 From d39eca547f3ec67140a5d765a426eb157b978a59 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Dec 2018 11:22:41 +0300 Subject: clk: tegra: dfll: Fix a potential Oop in remove() If tegra_dfll_unregister() fails then "soc" is an error pointer. We should just return instead of dereferencing it. Fixes: 1752c9ee23fb ("clk: tegra: dfll: Fix drvdata overwriting issue") Signed-off-by: Dan Carpenter Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index 269d3595758b..edc31bb56674 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -133,9 +133,11 @@ static int tegra124_dfll_fcpu_remove(struct platform_device *pdev) struct tegra_dfll_soc_data *soc; soc = tegra_dfll_unregister(pdev); - if (IS_ERR(soc)) + if (IS_ERR(soc)) { dev_err(&pdev->dev, "failed to unregister DFLL: %ld\n", PTR_ERR(soc)); + return PTR_ERR(soc); + } tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq); -- cgit v1.2.3-58-ga151 From 4f340efcb21220b7a0afcea3884e66f79e6f2306 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sun, 23 Dec 2018 23:50:58 -0600 Subject: clk: zynqmp: Fix memory allocation in zynqmp_clk_setup Fix memory allocation and use struct_size() in kzalloc(). This also fixes the allocation size to be correct, and smaller, because before we were allocating a bunch of sizeof(struct clk_hw_onecell_data) structures for each struct clk_hw we needed. Fixes: 3fde0e16d016 ("drivers: clk: Add ZynqMP clock driver") Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Acked-by: Michal Simek [sboyd@kernel.org: Expand commit text] Signed-off-by: Stephen Boyd --- drivers/clk/zynqmp/clkc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/zynqmp/clkc.c b/drivers/clk/zynqmp/clkc.c index f65cc0ff76ab..b0908ec62f73 100644 --- a/drivers/clk/zynqmp/clkc.c +++ b/drivers/clk/zynqmp/clkc.c @@ -669,8 +669,8 @@ static int zynqmp_clk_setup(struct device_node *np) if (ret) return ret; - zynqmp_data = kzalloc(sizeof(*zynqmp_data) + sizeof(*zynqmp_data) * - clock_max_idx, GFP_KERNEL); + zynqmp_data = kzalloc(struct_size(zynqmp_data, hws, clock_max_idx), + GFP_KERNEL); if (!zynqmp_data) return -ENOMEM; -- cgit v1.2.3-58-ga151 From 04d979d7a7bac2f645cd827ea37e5ffa5b4e1f97 Mon Sep 17 00:00:00 2001 From: b-ak Date: Wed, 9 Jan 2019 22:41:21 +0530 Subject: ASoC: tlv320aic32x4: SND_SOC_DAPM_MICBIAS is deprecated SND_SOC_DAPM_MICBIAS is deprecated, replace it with SND_SOC_DAPM_SUPPLY. MICBIAS voltage wasn't supplied to the microphone with the older SND_SOC_DAPM_MICBIAS widget, hence the microphone wouldn't work. This patch fixes the problem. Signed-off-by: b-ak Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 30 +++++++++++++++++++++++++++++- sound/soc/codecs/tlv320aic32x4.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index e2b5a11b16d1..521663d8b585 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -79,6 +79,32 @@ struct aic32x4_priv { struct device *dev; }; +static int mic_bias_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Change Mic Bias Registor */ + snd_soc_component_update_bits(component, AIC32X4_MICBIAS, + AIC32x4_MICBIAS_MASK, + AIC32X4_MICBIAS_LDOIN | + AIC32X4_MICBIAS_2075V); + printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, AIC32X4_MICBIAS, + AIC32x4_MICBIAS_MASK, 0); + printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n", + __func__); + break; + } + + return 0; +} + + static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -450,7 +476,9 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, in3r_to_lmixer_controls), - SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index e9df49edbf19..c2d74025bf4b 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h @@ -195,6 +195,7 @@ int aic32x4_remove(struct device *dev); /* AIC32X4_MICBIAS */ #define AIC32X4_MICBIAS_LDOIN BIT(3) #define AIC32X4_MICBIAS_2075V 0x60 +#define AIC32x4_MICBIAS_MASK GENMASK(6, 3) /* AIC32X4_LMICPGANIN */ #define AIC32X4_LMICPGANIN_IN2R_10K 0x10 -- cgit v1.2.3-58-ga151 From 3d51e4d9de7dd4e495dfbc6f4803e0f99c120aff Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Thu, 3 Jan 2019 16:58:20 +0000 Subject: clk: imx: Remove Kconfig duplicate include Commit d360b130e210f2 ("clk: imx: Make the i.MX8MQ CCM clock driver CLK_IMX8MQ dependant") introduced this duplicate and incorrectly ordered kconfig include. Fixes: d360b130e210f2 ("clk: imx: Make the i.MX8MQ CCM clock driver CLK_IMX8MQ dependant") Signed-off-by: Abel Vesa Reviewed-by: Dong Aisheng Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e5b2fe80eab4..d2f0bb5ba47e 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -293,7 +293,6 @@ config COMMON_CLK_BD718XX source "drivers/clk/actions/Kconfig" source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" -source "drivers/clk/imx/Kconfig" source "drivers/clk/imgtec/Kconfig" source "drivers/clk/imx/Kconfig" source "drivers/clk/ingenic/Kconfig" -- cgit v1.2.3-58-ga151 From c6e909972ef87aa2a479269f46b84126f99ec6db Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Fri, 4 Jan 2019 23:05:49 +0100 Subject: clk: sysfs: fix invalid JSON in clk_dump Add a missing comma so that the output is valid JSON format again. Fixes: 9fba738a53dd ("clk: add duty cycle support") Signed-off-by: Lubomir Rintel Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 75d13c0eff12..6ccdbedb02f3 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2779,7 +2779,7 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) seq_printf(s, "\"protect_count\": %d,", c->protect_count); seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c)); seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c)); - seq_printf(s, "\"phase\": %d", clk_core_get_phase(c)); + seq_printf(s, "\"phase\": %d,", clk_core_get_phase(c)); seq_printf(s, "\"duty_cycle\": %u", clk_core_get_scaled_duty_cycle(c, 100000)); } -- cgit v1.2.3-58-ga151 From c61e678f30da733a1b7fdd5983d0770de2e6009c Mon Sep 17 00:00:00 2001 From: Jianchao Wang Date: Mon, 24 Dec 2018 11:15:53 +0800 Subject: nvme-pci: fix the wrong setting of nr_maps We only set the nr_maps to 3 if poll queues are supported. Signed-off-by: Jianchao Wang Signed-off-by: Christoph Hellwig --- drivers/nvme/host/pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 5a0bf6a24d50..cc65fa8a537b 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2294,7 +2294,6 @@ static int nvme_dev_add(struct nvme_dev *dev) dev->tagset.nr_maps = 2; /* default + read */ if (dev->io_queues[HCTX_TYPE_POLL]) dev->tagset.nr_maps++; - dev->tagset.nr_maps = HCTX_MAX_TYPES; dev->tagset.timeout = NVME_IO_TIMEOUT; dev->tagset.numa_node = dev_to_node(dev->dev); dev->tagset.queue_depth = -- cgit v1.2.3-58-ga151 From cc667f6d5de023ee131e96bb88e5cddca23272bd Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Sat, 29 Dec 2018 17:23:43 +0000 Subject: nvme-pci: use the same attributes when freeing host_mem_desc_bufs. When using HMB the PCIe host driver allocates host_mem_desc_bufs using dma_alloc_attrs() but frees them using dma_free_coherent(). Use the correct dma_free_attrs() function to free the buffers. Signed-off-by: Liviu Dudau Signed-off-by: Christoph Hellwig --- drivers/nvme/host/pci.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index cc65fa8a537b..efe46f518022 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1885,8 +1885,9 @@ static void nvme_free_host_mem(struct nvme_dev *dev) struct nvme_host_mem_buf_desc *desc = &dev->host_mem_descs[i]; size_t size = le32_to_cpu(desc->size) * dev->ctrl.page_size; - dma_free_coherent(dev->dev, size, dev->host_mem_desc_bufs[i], - le64_to_cpu(desc->addr)); + dma_free_attrs(dev->dev, size, dev->host_mem_desc_bufs[i], + le64_to_cpu(desc->addr), + DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_NO_WARN); } kfree(dev->host_mem_desc_bufs); @@ -1952,8 +1953,9 @@ out_free_bufs: while (--i >= 0) { size_t size = le32_to_cpu(descs[i].size) * dev->ctrl.page_size; - dma_free_coherent(dev->dev, size, bufs[i], - le64_to_cpu(descs[i].addr)); + dma_free_attrs(dev->dev, size, bufs[i], + le64_to_cpu(descs[i].addr), + DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_NO_WARN); } kfree(bufs); -- cgit v1.2.3-58-ga151 From 8fae268b40f5191227ae7050a99cb2cf1b914ddd Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Fri, 4 Jan 2019 15:04:33 -0700 Subject: nvme-pci: rerun irq setup on IO queue init errors If the driver is unable to create a subset of IO queues for any reason, the read/write and polled queue sets will not match the actual allocated hardware contexts. This leaves gaps in the CPU affinity mappings and causes the following kernel panic after blk_mq_map_queue_type() returns a NULL hctx. BUG: unable to handle kernel NULL pointer dereference at 0000000000000198 #PF error: [normal kernel read fault] PGD 0 P4D 0 Oops: 0000 [#1] SMP CPU: 64 PID: 1171 Comm: kworker/u259:1 Not tainted 4.20.0+ #241 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-2.fc27 04/01/2014 Workqueue: nvme-wq nvme_scan_work [nvme_core] RIP: 0010:blk_mq_init_allocated_queue+0x2d9/0x440 RSP: 0018:ffffb1bf0abc3cd0 EFLAGS: 00010286 RAX: 000000000000001f RBX: ffff8ea744cf0718 RCX: 0000000000000000 RDX: 0000000000000002 RSI: 000000000000007c RDI: ffffffff9109a820 RBP: ffff8ea7565f7008 R08: 000000000000001f R09: 000000000000003f R10: ffffb1bf0abc3c00 R11: 0000000000000000 R12: 000000000001d008 R13: ffff8ea7565f7008 R14: 000000000000003f R15: 0000000000000001 FS: 0000000000000000(0000) GS:ffff8ea757200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000198 CR3: 0000000013058000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: blk_mq_init_queue+0x35/0x60 nvme_validate_ns+0xc6/0x7c0 [nvme_core] ? nvme_identify_ctrl.isra.56+0x7e/0xc0 [nvme_core] nvme_scan_work+0xc8/0x340 [nvme_core] ? __wake_up_common+0x6d/0x120 ? try_to_wake_up+0x55/0x410 process_one_work+0x1e9/0x3d0 worker_thread+0x2d/0x3d0 ? process_one_work+0x3d0/0x3d0 kthread+0x111/0x130 ? kthread_park+0x90/0x90 ret_from_fork+0x1f/0x30 Modules linked in: nvme nvme_core serio_raw CR2: 0000000000000198 Fix by re-running the interrupt vector setup from scratch using a reduced count that may be successful until the created queues matches the irq affinity plus polling queue sets. Signed-off-by: Keith Busch Reviewed-by: Sagi Grimberg Reviewed-by: Ming Lei Signed-off-by: Christoph Hellwig --- drivers/nvme/host/pci.c | 50 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index efe46f518022..f891eb57f263 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -95,6 +95,7 @@ struct nvme_dev; struct nvme_queue; static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown); +static bool __nvme_disable_io_queues(struct nvme_dev *dev, u8 opcode); /* * Represents an NVM Express device. Each nvme_dev is a PCI function. @@ -1420,6 +1421,14 @@ static int nvme_suspend_queue(struct nvme_queue *nvmeq) return 0; } +static void nvme_suspend_io_queues(struct nvme_dev *dev) +{ + int i; + + for (i = dev->ctrl.queue_count - 1; i > 0; i--) + nvme_suspend_queue(&dev->queues[i]); +} + static void nvme_disable_admin_queue(struct nvme_dev *dev, bool shutdown) { struct nvme_queue *nvmeq = &dev->queues[0]; @@ -2134,6 +2143,12 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) return result; } +static void nvme_disable_io_queues(struct nvme_dev *dev) +{ + if (__nvme_disable_io_queues(dev, nvme_admin_delete_sq)) + __nvme_disable_io_queues(dev, nvme_admin_delete_cq); +} + static int nvme_setup_io_queues(struct nvme_dev *dev) { struct nvme_queue *adminq = &dev->queues[0]; @@ -2170,6 +2185,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) } while (1); adminq->q_db = dev->dbs; + retry: /* Deregister the admin queue's interrupt */ pci_free_irq(pdev, 0, adminq); @@ -2187,25 +2203,34 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) result = max(result - 1, 1); dev->max_qid = result + dev->io_queues[HCTX_TYPE_POLL]; - dev_info(dev->ctrl.device, "%d/%d/%d default/read/poll queues\n", - dev->io_queues[HCTX_TYPE_DEFAULT], - dev->io_queues[HCTX_TYPE_READ], - dev->io_queues[HCTX_TYPE_POLL]); - /* * Should investigate if there's a performance win from allocating * more queues than interrupt vectors; it might allow the submission * path to scale better, even if the receive path is limited by the * number of interrupts. */ - result = queue_request_irq(adminq); if (result) { adminq->cq_vector = -1; return result; } set_bit(NVMEQ_ENABLED, &adminq->flags); - return nvme_create_io_queues(dev); + + result = nvme_create_io_queues(dev); + if (result || dev->online_queues < 2) + return result; + + if (dev->online_queues - 1 < dev->max_qid) { + nr_io_queues = dev->online_queues - 1; + nvme_disable_io_queues(dev); + nvme_suspend_io_queues(dev); + goto retry; + } + dev_info(dev->ctrl.device, "%d/%d/%d default/read/poll queues\n", + dev->io_queues[HCTX_TYPE_DEFAULT], + dev->io_queues[HCTX_TYPE_READ], + dev->io_queues[HCTX_TYPE_POLL]); + return 0; } static void nvme_del_queue_end(struct request *req, blk_status_t error) @@ -2250,7 +2275,7 @@ static int nvme_delete_queue(struct nvme_queue *nvmeq, u8 opcode) return 0; } -static bool nvme_disable_io_queues(struct nvme_dev *dev, u8 opcode) +static bool __nvme_disable_io_queues(struct nvme_dev *dev, u8 opcode) { int nr_queues = dev->online_queues - 1, sent = 0; unsigned long timeout; @@ -2411,7 +2436,6 @@ static void nvme_pci_disable(struct nvme_dev *dev) static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) { - int i; bool dead = true; struct pci_dev *pdev = to_pci_dev(dev->dev); @@ -2438,13 +2462,11 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) nvme_stop_queues(&dev->ctrl); if (!dead && dev->ctrl.queue_count > 0) { - if (nvme_disable_io_queues(dev, nvme_admin_delete_sq)) - nvme_disable_io_queues(dev, nvme_admin_delete_cq); + nvme_disable_io_queues(dev); nvme_disable_admin_queue(dev, shutdown); } - for (i = dev->ctrl.queue_count - 1; i >= 0; i--) - nvme_suspend_queue(&dev->queues[i]); - + nvme_suspend_io_queues(dev); + nvme_suspend_queue(&dev->queues[0]); nvme_pci_disable(dev); blk_mq_tagset_busy_iter(&dev->tagset, nvme_cancel_request, &dev->ctrl); -- cgit v1.2.3-58-ga151 From dcca1662727220d18fa351097ddff33f95f516c5 Mon Sep 17 00:00:00 2001 From: Hongbo Yao Date: Mon, 7 Jan 2019 10:22:07 +0800 Subject: nvme-pci: fix out of bounds access in nvme_cqe_pending There is an out of bounds array access in nvme_cqe_peding(). When enable irq_thread for nvme interrupt, there is racing between the nvmeq->cq_head updating and reading. nvmeq->cq_head is updated in nvme_update_cq_head(), if nvmeq->cq_head equals nvmeq->q_depth and before its value set to zero, nvme_cqe_pending() uses its value as an array index, the index will be out of bounds. Signed-off-by: Hongbo Yao [hch: slight coding style update] Signed-off-by: Christoph Hellwig --- drivers/nvme/host/pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index f891eb57f263..3f53a2c3042d 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1020,9 +1020,11 @@ static void nvme_complete_cqes(struct nvme_queue *nvmeq, u16 start, u16 end) static inline void nvme_update_cq_head(struct nvme_queue *nvmeq) { - if (++nvmeq->cq_head == nvmeq->q_depth) { + if (nvmeq->cq_head == nvmeq->q_depth - 1) { nvmeq->cq_head = 0; nvmeq->cq_phase = !nvmeq->cq_phase; + } else { + nvmeq->cq_head++; } } -- cgit v1.2.3-58-ga151 From e9c2edc098921173920df370c69b5c38fe52df56 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 31 Dec 2018 23:58:29 -0800 Subject: nvme-tcp: remove dead code We should never touch the opal device from the transport driver. Signed-off-by: Sagi Grimberg Signed-off-by: Christoph Hellwig --- drivers/nvme/host/tcp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index de174912445e..7210b2d6df13 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1620,7 +1620,6 @@ static void nvme_tcp_destroy_admin_queue(struct nvme_ctrl *ctrl, bool remove) { nvme_tcp_stop_queue(ctrl, 0); if (remove) { - free_opal_dev(ctrl->opal_dev); blk_cleanup_queue(ctrl->admin_q); blk_mq_free_tag_set(ctrl->admin_tagset); } -- cgit v1.2.3-58-ga151 From e85037a2e90ac9aa448a08927d7a7436206c6000 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 31 Dec 2018 23:58:30 -0800 Subject: nvme-tcp: don't ask if controller is fabrics For sure we are a fabric driver. Signed-off-by: Sagi Grimberg Signed-off-by: Christoph Hellwig --- drivers/nvme/host/tcp.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 7210b2d6df13..265a0543b381 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1565,8 +1565,7 @@ static void nvme_tcp_destroy_io_queues(struct nvme_ctrl *ctrl, bool remove) { nvme_tcp_stop_io_queues(ctrl); if (remove) { - if (ctrl->ops->flags & NVME_F_FABRICS) - blk_cleanup_queue(ctrl->connect_q); + blk_cleanup_queue(ctrl->connect_q); blk_mq_free_tag_set(ctrl->tagset); } nvme_tcp_free_io_queues(ctrl); @@ -1587,12 +1586,10 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new) goto out_free_io_queues; } - if (ctrl->ops->flags & NVME_F_FABRICS) { - ctrl->connect_q = blk_mq_init_queue(ctrl->tagset); - if (IS_ERR(ctrl->connect_q)) { - ret = PTR_ERR(ctrl->connect_q); - goto out_free_tag_set; - } + ctrl->connect_q = blk_mq_init_queue(ctrl->tagset); + if (IS_ERR(ctrl->connect_q)) { + ret = PTR_ERR(ctrl->connect_q); + goto out_free_tag_set; } } else { blk_mq_update_nr_hw_queues(ctrl->tagset, @@ -1606,7 +1603,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new) return 0; out_cleanup_connect_q: - if (new && (ctrl->ops->flags & NVME_F_FABRICS)) + if (new) blk_cleanup_queue(ctrl->connect_q); out_free_tag_set: if (new) -- cgit v1.2.3-58-ga151 From 9846ac0143fe9872e92fe2a1ddff868ad05bdbb6 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 7 Jan 2019 23:54:23 -0800 Subject: nvme-fabrics: unset write/poll queues for discovery controllers Even if user-space sent it to us, it got it wrong so lets help by disallowing it. Signed-off-by: Sagi Grimberg Signed-off-by: Christoph Hellwig --- drivers/nvme/host/fabrics.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c index b2ab213f43de..3eb908c50e1a 100644 --- a/drivers/nvme/host/fabrics.c +++ b/drivers/nvme/host/fabrics.c @@ -874,6 +874,8 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts, if (opts->discovery_nqn) { opts->kato = 0; opts->nr_io_queues = 0; + opts->nr_write_queues = 0; + opts->nr_poll_queues = 0; opts->duplicate_connect = true; } if (ctrl_loss_tmo < 0) -- cgit v1.2.3-58-ga151 From c7055fd15ff46d92eb0dd1c16a4fe010d58224c8 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 8 Jan 2019 12:46:58 +0100 Subject: nvme-multipath: zero out ANA log buffer When nvme_init_identify() fails the ANA log buffer is deallocated but _not_ set to NULL. This can cause double free oops when this controller is deleted without ever being reconnected. Signed-off-by: Hannes Reinecke Signed-off-by: Christoph Hellwig --- drivers/nvme/host/multipath.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 183ec17ba067..df4b3a6db51b 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -570,6 +570,7 @@ int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) return 0; out_free_ana_log_buf: kfree(ctrl->ana_log_buf); + ctrl->ana_log_buf = NULL; out: return error; } @@ -577,5 +578,6 @@ out: void nvme_mpath_uninit(struct nvme_ctrl *ctrl) { kfree(ctrl->ana_log_buf); + ctrl->ana_log_buf = NULL; } -- cgit v1.2.3-58-ga151 From 3da584f57133e51aeb84aaefae5e3d69531a1e4f Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 8 Jan 2019 09:37:43 -0700 Subject: nvme: pad fake subsys NQN vid and ssvid with zeros We need to preserve the leading zeros in the vid and ssvid when generating a unique NQN. Truncating these may lead to naming collisions. Signed-off-by: Keith Busch Signed-off-by: Christoph Hellwig --- drivers/nvme/host/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 08f2c92602f4..f81fde164d37 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2184,7 +2184,7 @@ static void nvme_init_subnqn(struct nvme_subsystem *subsys, struct nvme_ctrl *ct /* Generate a "fake" NQN per Figure 254 in NVMe 1.3 + ECN 001 */ off = snprintf(subsys->subnqn, NVMF_NQN_SIZE, - "nqn.2014.08.org.nvmexpress:%4x%4x", + "nqn.2014.08.org.nvmexpress:%04x%04x", le16_to_cpu(id->vid), le16_to_cpu(id->ssvid)); memcpy(subsys->subnqn + off, id->sn, sizeof(id->sn)); off += sizeof(id->sn); -- cgit v1.2.3-58-ga151 From 6299358d198a0635da2dd3c4b3ec37789e811e44 Mon Sep 17 00:00:00 2001 From: James Dingwall Date: Tue, 8 Jan 2019 10:20:51 -0700 Subject: nvme: introduce NVME_QUIRK_IGNORE_DEV_SUBNQN If a device provides an NQN it is expected to be globally unique. Unfortunately some firmware revisions for Intel 760p/Pro 7600p devices did not satisfy this requirement. In these circumstances if a system has >1 affected device then only one device is enabled. If this quirk is enabled then the device supplied subnqn is ignored and we fallback to generating one as if the field was empty. In this case we also suppress the version check so we don't print a warning when the quirk is enabled. Reviewed-by: Keith Busch Signed-off-by: James Dingwall Signed-off-by: Christoph Hellwig --- drivers/nvme/host/core.c | 16 +++++++++------- drivers/nvme/host/nvme.h | 5 +++++ drivers/nvme/host/pci.c | 2 ++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f81fde164d37..8485be6bb895 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2173,14 +2173,16 @@ static void nvme_init_subnqn(struct nvme_subsystem *subsys, struct nvme_ctrl *ct size_t nqnlen; int off; - nqnlen = strnlen(id->subnqn, NVMF_NQN_SIZE); - if (nqnlen > 0 && nqnlen < NVMF_NQN_SIZE) { - strlcpy(subsys->subnqn, id->subnqn, NVMF_NQN_SIZE); - return; - } + if(!(ctrl->quirks & NVME_QUIRK_IGNORE_DEV_SUBNQN)) { + nqnlen = strnlen(id->subnqn, NVMF_NQN_SIZE); + if (nqnlen > 0 && nqnlen < NVMF_NQN_SIZE) { + strlcpy(subsys->subnqn, id->subnqn, NVMF_NQN_SIZE); + return; + } - if (ctrl->vs >= NVME_VS(1, 2, 1)) - dev_warn(ctrl->device, "missing or invalid SUBNQN field.\n"); + if (ctrl->vs >= NVME_VS(1, 2, 1)) + dev_warn(ctrl->device, "missing or invalid SUBNQN field.\n"); + } /* Generate a "fake" NQN per Figure 254 in NVMe 1.3 + ECN 001 */ off = snprintf(subsys->subnqn, NVMF_NQN_SIZE, diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 2b36ac922596..ab961bdeea89 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -90,6 +90,11 @@ enum nvme_quirks { * Set MEDIUM priority on SQ creation */ NVME_QUIRK_MEDIUM_PRIO_SQ = (1 << 7), + + /* + * Ignore device provided subnqn. + */ + NVME_QUIRK_IGNORE_DEV_SUBNQN = (1 << 8), }; /* diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 3f53a2c3042d..fc9d17c317b8 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2971,6 +2971,8 @@ static const struct pci_device_id nvme_id_table[] = { { PCI_VDEVICE(INTEL, 0xf1a5), /* Intel 600P/P3100 */ .driver_data = NVME_QUIRK_NO_DEEPEST_PS | NVME_QUIRK_MEDIUM_PRIO_SQ }, + { PCI_VDEVICE(INTEL, 0xf1a6), /* Intel 760p/Pro 7600p */ + .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, { PCI_VDEVICE(INTEL, 0x5845), /* Qemu emulated controller */ .driver_data = NVME_QUIRK_IDENTIFY_CNS, }, { PCI_DEVICE(0x1bb1, 0x0100), /* Seagate Nytro Flash Storage */ -- cgit v1.2.3-58-ga151 From b8a38ea64dc714a64f8fb76e311a4f15a3f67861 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 7 Jan 2019 19:08:49 -0800 Subject: nvme: don't initlialize ctrl->cntlid twice ctrl->cntlid will already be initialized from id->cntlid for non-NVME_F_FABRICS controllers few lines below. For NVME_F_FABRICS controllers this field should already be initialized, otherwise the check if (ctrl->cntlid != le16_to_cpu(id->cntlid)) below will always be a no-op. Signed-off-by: Andrey Smirnov Reviewed-by: Keith Busch Reviewed-by: Sagi Grimberg Signed-off-by: Christoph Hellwig --- drivers/nvme/host/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 8485be6bb895..150e49723c15 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2502,7 +2502,6 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) ctrl->oaes = le32_to_cpu(id->oaes); atomic_set(&ctrl->abort_limit, id->acl + 1); ctrl->vwc = id->vwc; - ctrl->cntlid = le16_to_cpup(&id->cntlid); if (id->mdts) max_hw_sectors = 1 << (id->mdts + page_shift - 9); else -- cgit v1.2.3-58-ga151 From 2137a109a5e39c2bdccfffe65230ed3fadbaac0e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Dec 2018 01:55:19 +0100 Subject: clk: vc5: Abort clock configuration without upstream clock In case the upstream clock are not set, which can happen in case the VC5 has no valid upstream clock, the $src variable is used uninited by regmap_update_bits(). Check for this condition and return -EINVAL in such case. Note that in case the VC5 has no valid upstream clock, the VC5 can not operate correctly. That is a hardware property of the VC5. The internal oscilator present in some VC5 models is also considered upstream clock. Signed-off-by: Marek Vasut Cc: Alexey Firago Cc: Laurent Pinchart Cc: Stephen Boyd Cc: linux-renesas-soc@vger.kernel.org [sboyd@kernel.org: Added comment about probe preventing this from happening in the first place] Signed-off-by: Stephen Boyd --- drivers/clk/clk-versaclock5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index 5b393e711e94..7d16ab0784ec 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -262,8 +262,10 @@ static int vc5_mux_set_parent(struct clk_hw *hw, u8 index) if (vc5->clk_mux_ins == VC5_MUX_IN_XIN) src = VC5_PRIM_SRC_SHDN_EN_XTAL; - if (vc5->clk_mux_ins == VC5_MUX_IN_CLKIN) + else if (vc5->clk_mux_ins == VC5_MUX_IN_CLKIN) src = VC5_PRIM_SRC_SHDN_EN_CLKIN; + else /* Invalid; should have been caught by vc5_probe() */ + return -EINVAL; } return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src); -- cgit v1.2.3-58-ga151 From ba50bf1ce9a51fc97db58b96d01306aa70bc3979 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 17 Dec 2018 20:16:09 +0000 Subject: Drivers: hv: vmbus: Check for ring when getting debug info fc96df16a1ce is good and can already fix the "return stack garbage" issue, but let's also improve hv_ringbuffer_get_debuginfo(), which would silently return stack garbage, if people forget to check channel->state or ring_info->ring_buffer, when using the function in the future. Having an error check in the function would eliminate the potential risk. Add a Fixes tag to indicate the patch depdendency. Fixes: fc96df16a1ce ("Drivers: hv: vmbus: Return -EINVAL for the sys files for unopened channels") Cc: stable@vger.kernel.org Cc: K. Y. Srinivasan Cc: Haiyang Zhang Signed-off-by: Stephen Hemminger Signed-off-by: Dexuan Cui Signed-off-by: Sasha Levin --- drivers/hv/ring_buffer.c | 31 ++++++++--------- drivers/hv/vmbus_drv.c | 91 ++++++++++++++++++++++++++++++++---------------- include/linux/hyperv.h | 5 +-- 3 files changed, 79 insertions(+), 48 deletions(-) diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 64d0c85d5161..1f1a55e07733 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -164,26 +164,25 @@ hv_get_ringbuffer_availbytes(const struct hv_ring_buffer_info *rbi, } /* Get various debug metrics for the specified ring buffer. */ -void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, - struct hv_ring_buffer_debug_info *debug_info) +int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, + struct hv_ring_buffer_debug_info *debug_info) { u32 bytes_avail_towrite; u32 bytes_avail_toread; - if (ring_info->ring_buffer) { - hv_get_ringbuffer_availbytes(ring_info, - &bytes_avail_toread, - &bytes_avail_towrite); - - debug_info->bytes_avail_toread = bytes_avail_toread; - debug_info->bytes_avail_towrite = bytes_avail_towrite; - debug_info->current_read_index = - ring_info->ring_buffer->read_index; - debug_info->current_write_index = - ring_info->ring_buffer->write_index; - debug_info->current_interrupt_mask = - ring_info->ring_buffer->interrupt_mask; - } + if (!ring_info->ring_buffer) + return -EINVAL; + + hv_get_ringbuffer_availbytes(ring_info, + &bytes_avail_toread, + &bytes_avail_towrite); + debug_info->bytes_avail_toread = bytes_avail_toread; + debug_info->bytes_avail_towrite = bytes_avail_towrite; + debug_info->current_read_index = ring_info->ring_buffer->read_index; + debug_info->current_write_index = ring_info->ring_buffer->write_index; + debug_info->current_interrupt_mask + = ring_info->ring_buffer->interrupt_mask; + return 0; } EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo); diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index d0ff65675292..403fee01572c 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -313,12 +313,16 @@ static ssize_t out_intr_mask_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info outbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, + &outbound); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", outbound.current_interrupt_mask); } static DEVICE_ATTR_RO(out_intr_mask); @@ -328,12 +332,15 @@ static ssize_t out_read_index_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info outbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, + &outbound); + if (ret < 0) + return ret; return sprintf(buf, "%d\n", outbound.current_read_index); } static DEVICE_ATTR_RO(out_read_index); @@ -344,12 +351,15 @@ static ssize_t out_write_index_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info outbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, + &outbound); + if (ret < 0) + return ret; return sprintf(buf, "%d\n", outbound.current_write_index); } static DEVICE_ATTR_RO(out_write_index); @@ -360,12 +370,15 @@ static ssize_t out_read_bytes_avail_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info outbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, + &outbound); + if (ret < 0) + return ret; return sprintf(buf, "%d\n", outbound.bytes_avail_toread); } static DEVICE_ATTR_RO(out_read_bytes_avail); @@ -376,12 +389,15 @@ static ssize_t out_write_bytes_avail_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info outbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, + &outbound); + if (ret < 0) + return ret; return sprintf(buf, "%d\n", outbound.bytes_avail_towrite); } static DEVICE_ATTR_RO(out_write_bytes_avail); @@ -391,12 +407,15 @@ static ssize_t in_intr_mask_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info inbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", inbound.current_interrupt_mask); } static DEVICE_ATTR_RO(in_intr_mask); @@ -406,12 +425,15 @@ static ssize_t in_read_index_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info inbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", inbound.current_read_index); } static DEVICE_ATTR_RO(in_read_index); @@ -421,12 +443,15 @@ static ssize_t in_write_index_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info inbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", inbound.current_write_index); } static DEVICE_ATTR_RO(in_write_index); @@ -437,12 +462,15 @@ static ssize_t in_read_bytes_avail_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info inbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", inbound.bytes_avail_toread); } static DEVICE_ATTR_RO(in_read_bytes_avail); @@ -453,12 +481,15 @@ static ssize_t in_write_bytes_avail_show(struct device *dev, { struct hv_device *hv_dev = device_to_hv_device(dev); struct hv_ring_buffer_debug_info inbound; + int ret; if (!hv_dev->channel) return -ENODEV; - if (hv_dev->channel->state != CHANNEL_OPENED_STATE) - return -EINVAL; - hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + + ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound); + if (ret < 0) + return ret; + return sprintf(buf, "%d\n", inbound.bytes_avail_towrite); } static DEVICE_ATTR_RO(in_write_bytes_avail); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index f0885cc01db6..dcb6977afce9 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1159,8 +1159,9 @@ struct hv_ring_buffer_debug_info { u32 bytes_avail_towrite; }; -void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, - struct hv_ring_buffer_debug_info *debug_info); + +int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info, + struct hv_ring_buffer_debug_info *debug_info); /* Vmbus interface */ #define vmbus_driver_register(driver) \ -- cgit v1.2.3-58-ga151 From da8ced360ca8ad72d8f41f5c8fcd5b0e63e1555f Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 4 Jan 2019 15:19:42 +0100 Subject: hv_balloon: avoid touching uninitialized struct page during tail onlining Hyper-V memory hotplug protocol has 2M granularity and in Linux x86 we use 128M. To deal with it we implement partial section onlining by registering custom page onlining callback (hv_online_page()). Later, when more memory arrives we try to online the 'tail' (see hv_bring_pgs_online()). It was found that in some cases this 'tail' onlining causes issues: BUG: Bad page state in process kworker/0:2 pfn:109e3a page:ffffe08344278e80 count:0 mapcount:1 mapping:0000000000000000 index:0x0 flags: 0xfffff80000000() raw: 000fffff80000000 dead000000000100 dead000000000200 0000000000000000 raw: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 page dumped because: nonzero mapcount ... Workqueue: events hot_add_req [hv_balloon] Call Trace: dump_stack+0x5c/0x80 bad_page.cold.112+0x7f/0xb2 free_pcppages_bulk+0x4b8/0x690 free_unref_page+0x54/0x70 hv_page_online_one+0x5c/0x80 [hv_balloon] hot_add_req.cold.24+0x182/0x835 [hv_balloon] ... Turns out that we now have deferred struct page initialization for memory hotplug so e.g. memory_block_action() in drivers/base/memory.c does pages_correctly_probed() check and in that check it avoids inspecting struct pages and checks sections instead. But in Hyper-V balloon driver we do PageReserved(pfn_to_page()) check and this is now wrong. Switch to checking online_section_nr() instead. Signed-off-by: Vitaly Kuznetsov Cc: stable@kernel.org Signed-off-by: Sasha Levin --- drivers/hv/hv_balloon.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 5301fef16c31..7c6349a50ef1 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -888,12 +888,14 @@ static unsigned long handle_pg_range(unsigned long pg_start, pfn_cnt -= pgs_ol; /* * Check if the corresponding memory block is already - * online by checking its last previously backed page. - * In case it is we need to bring rest (which was not - * backed previously) online too. + * online. It is possible to observe struct pages still + * being uninitialized here so check section instead. + * In case the section is online we need to bring the + * rest of pfns (which were not backed previously) + * online too. */ if (start_pfn > has->start_pfn && - !PageReserved(pfn_to_page(start_pfn - 1))) + online_section_nr(pfn_to_section_nr(start_pfn))) hv_bring_pgs_online(has, start_pfn, pgs_ol); } -- cgit v1.2.3-58-ga151 From 549aff770ccfec368aa8f0652dbce8b1e8e6715a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Jan 2019 16:19:24 -0300 Subject: perf symbols: Add 'arch_cpu_idle' to the list of kernel idle symbols When testing 'perf top' on a armhf system (32-bit, Orange Pi Zero), I noticed that 'arch_cpu_idle' dominated, add it to the list of idle symbols, so that we can see what is that being done when not idle. Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-4q2b5g4p2hrstrhp9t2mrlho@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 01f2c7385e38..48efad6d0f90 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -614,6 +614,7 @@ out: static bool symbol__is_idle(const char *name) { const char * const idle_symbols[] = { + "arch_cpu_idle", "cpu_idle", "cpu_startup_entry", "intel_idle", -- cgit v1.2.3-58-ga151 From 3e958fe67720b37d04ab8ef81b9d507a56a09bbc Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Tue, 8 Jan 2019 15:08:44 +0800 Subject: drm/amdgpu: fix CPDMA hang in PRT mode for VEGA20 Fix CPDMA hang in PRT mode for both VEGA10 and VEGA20 Signed-off-by: Tao Zhou Tested-by: Yukun.Li Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 618639b8775a..59a5d8f26595 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -113,7 +113,10 @@ static const struct soc15_reg_golden golden_settings_gc_9_0[] = SOC15_REG_GOLDEN_VALUE(GC, 0, mmTCP_CHAN_STEER_HI, 0xffffffff, 0x4a2c0e68), SOC15_REG_GOLDEN_VALUE(GC, 0, mmTCP_CHAN_STEER_LO, 0xffffffff, 0xb5d3f197), SOC15_REG_GOLDEN_VALUE(GC, 0, mmVGT_CACHE_INVALIDATION, 0x3fff3af3, 0x19200000), - SOC15_REG_GOLDEN_VALUE(GC, 0, mmVGT_GS_MAX_WAVE_ID, 0x00000fff, 0x000003ff) + SOC15_REG_GOLDEN_VALUE(GC, 0, mmVGT_GS_MAX_WAVE_ID, 0x00000fff, 0x000003ff), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_MEC1_F32_INT_DIS, 0x00000000, 0x00000800), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_MEC2_F32_INT_DIS, 0x00000000, 0x00000800), + SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_DEBUG, 0x00000000, 0x00008000) }; static const struct soc15_reg_golden golden_settings_gc_9_0_vg10[] = @@ -135,10 +138,7 @@ static const struct soc15_reg_golden golden_settings_gc_9_0_vg10[] = SOC15_REG_GOLDEN_VALUE(GC, 0, mmRMI_UTCL1_CNTL2, 0x00030000, 0x00020000), SOC15_REG_GOLDEN_VALUE(GC, 0, mmSPI_CONFIG_CNTL_1, 0x0000000f, 0x01000107), SOC15_REG_GOLDEN_VALUE(GC, 0, mmTD_CNTL, 0x00001800, 0x00000800), - SOC15_REG_GOLDEN_VALUE(GC, 0, mmWD_UTCL1_CNTL, 0x08000000, 0x08000080), - SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_MEC1_F32_INT_DIS, 0x00000000, 0x00000800), - SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_MEC2_F32_INT_DIS, 0x00000000, 0x00000800), - SOC15_REG_GOLDEN_VALUE(GC, 0, mmCP_DEBUG, 0x00000000, 0x00008000) + SOC15_REG_GOLDEN_VALUE(GC, 0, mmWD_UTCL1_CNTL, 0x08000000, 0x08000080) }; static const struct soc15_reg_golden golden_settings_gc_9_0_vg20[] = -- cgit v1.2.3-58-ga151 From 0c6c8125582714e1fd3544983eba3d750db0f5b8 Mon Sep 17 00:00:00 2001 From: Jim Qu Date: Mon, 17 Dec 2018 17:00:50 +0800 Subject: drm/amdgpu: set WRITE_BURST_LENGTH to 64B to workaround SDMA1 hang effect asics: VEGA10 and VEGA12 Signed-off-by: Jim Qu Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index fd0bfe140ee0..6811a5d05b27 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -78,7 +78,6 @@ static const struct soc15_reg_golden golden_settings_sdma_4[] = { SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_RLC1_RB_WPTR_POLL_CNTL, 0x0000fff0, 0x00403000), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_PAGE, 0x000003ff, 0x000003c0), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_UTCL1_WATERMK, 0xfc000000, 0x00000000), - SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_CHICKEN_BITS, 0xfe931f07, 0x02831f07), SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_CLK_CTRL, 0xffffffff, 0x3f000100), SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GFX_IB_CNTL, 0x800f0100, 0x00000100), SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GFX_RB_WPTR_POLL_CNTL, 0x0000fff0, 0x00403000), @@ -96,6 +95,7 @@ static const struct soc15_reg_golden golden_settings_sdma_4[] = { static const struct soc15_reg_golden golden_settings_sdma_vg10[] = { SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_GB_ADDR_CONFIG, 0x0018773f, 0x00104002), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_GB_ADDR_CONFIG_READ, 0x0018773f, 0x00104002), + SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_CHICKEN_BITS, 0xfe931f07, 0x02831d07), SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GB_ADDR_CONFIG, 0x0018773f, 0x00104002), SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GB_ADDR_CONFIG_READ, 0x0018773f, 0x00104002) }; @@ -103,6 +103,7 @@ static const struct soc15_reg_golden golden_settings_sdma_vg10[] = { static const struct soc15_reg_golden golden_settings_sdma_vg12[] = { SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_GB_ADDR_CONFIG, 0x0018773f, 0x00104001), SOC15_REG_GOLDEN_VALUE(SDMA0, 0, mmSDMA0_GB_ADDR_CONFIG_READ, 0x0018773f, 0x00104001), + SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_CHICKEN_BITS, 0xfe931f07, 0x02831d07), SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GB_ADDR_CONFIG, 0x0018773f, 0x00104001), SOC15_REG_GOLDEN_VALUE(SDMA1, 0, mmSDMA1_GB_ADDR_CONFIG_READ, 0x0018773f, 0x00104001) }; -- cgit v1.2.3-58-ga151 From 1c1eba86339c8517814863bc7dd21e2661a84e77 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 7 Jan 2019 14:43:55 +0100 Subject: drm/amdgpu: disable system memory page tables for now MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We hit a problem with IOMMU with that. Disable until we have time to debug further. Signed-off-by: Christian König Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index fc91f3e54a87..a0a11d399795 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -847,9 +847,6 @@ static void amdgpu_vm_bo_param(struct amdgpu_device *adev, struct amdgpu_vm *vm, bp->size = amdgpu_vm_bo_size(adev, level); bp->byte_align = AMDGPU_GPU_PAGE_SIZE; bp->domain = AMDGPU_GEM_DOMAIN_VRAM; - if (bp->size <= PAGE_SIZE && adev->asic_type >= CHIP_VEGA10 && - adev->flags & AMD_IS_APU) - bp->domain |= AMDGPU_GEM_DOMAIN_GTT; bp->domain = amdgpu_bo_get_preferred_pin_domain(adev, bp->domain); bp->flags = AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS | AMDGPU_GEM_CREATE_CPU_GTT_USWC; -- cgit v1.2.3-58-ga151 From 41af167fbc0032f9d7562854f58114eaa9270336 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Wed, 9 Jan 2019 18:12:16 +0100 Subject: MIPS: jazz: fix 64bit build 64bit JAZZ builds failed with linux-next/arch/mips/jazz/jazzdma.c: In function `vdma_init`: /linux-next/arch/mips/jazz/jazzdma.c:77:30: error: implicit declaration of function `KSEG1ADDR`; did you mean `CKSEG1ADDR`? [-Werror=implicit-function-declaration] pgtbl = (VDMA_PGTBL_ENTRY *)KSEG1ADDR(pgtbl); ^~~~~~~~~ CKSEG1ADDR /linux-next/arch/mips/jazz/jazzdma.c:77:10: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] pgtbl = (VDMA_PGTBL_ENTRY *)KSEG1ADDR(pgtbl); ^ In file included from /linux-next/arch/mips/include/asm/barrier.h:11:0, from /linux-next/include/linux/compiler.h:248, from /linux-next/include/linux/kernel.h:10, from /linux-next/arch/mips/jazz/jazzdma.c:11: /linux-next/arch/mips/include/asm/addrspace.h:41:29: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] #define _ACAST32_ (_ATYPE_)(_ATYPE32_) /* widen if necessary */ ^ /linux-next/arch/mips/include/asm/addrspace.h:53:25: note: in expansion of macro `_ACAST32_` #define CPHYSADDR(a) ((_ACAST32_(a)) & 0x1fffffff) ^~~~~~~~~ /linux-next/arch/mips/jazz/jazzdma.c:84:44: note: in expansion of macro `CPHYSADDR` r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE, CPHYSADDR(pgtbl)); Using correct casts and CKSEG1ADDR when dealing with the pgtbl setup fixes this. Signed-off-by: Thomas Bogendoerfer Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- arch/mips/jazz/jazzdma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/mips/jazz/jazzdma.c b/arch/mips/jazz/jazzdma.c index 6256d35dbf4d..bedb5047aff3 100644 --- a/arch/mips/jazz/jazzdma.c +++ b/arch/mips/jazz/jazzdma.c @@ -74,14 +74,15 @@ static int __init vdma_init(void) get_order(VDMA_PGTBL_SIZE)); BUG_ON(!pgtbl); dma_cache_wback_inv((unsigned long)pgtbl, VDMA_PGTBL_SIZE); - pgtbl = (VDMA_PGTBL_ENTRY *)KSEG1ADDR(pgtbl); + pgtbl = (VDMA_PGTBL_ENTRY *)CKSEG1ADDR((unsigned long)pgtbl); /* * Clear the R4030 translation table */ vdma_pgtbl_init(); - r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE, CPHYSADDR(pgtbl)); + r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE, + CPHYSADDR((unsigned long)pgtbl)); r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM, VDMA_PGTBL_SIZE); r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0); -- cgit v1.2.3-58-ga151 From 321c46b91550adc03054125fa7a1639390608e1a Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Thu, 3 Jan 2019 08:34:17 +0100 Subject: MIPS: BCM47XX: Setup struct device for the SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far we never had any device registered for the SoC. This resulted in some small issues that we kept ignoring like: 1) Not working GPIOLIB_IRQCHIP (gpiochip_irqchip_add_key() failing) 2) Lack of proper tree in the /sys/devices/ 3) mips_dma_alloc_coherent() silently handling empty coherent_dma_mask Kernel 4.19 came with a lot of DMA changes and caused a regression on bcm47xx. Starting with the commit f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms") DMA coherent allocations just fail. Example: [ 1.114914] bgmac_bcma bcma0:2: Allocation of TX ring 0x200 failed [ 1.121215] bgmac_bcma bcma0:2: Unable to alloc memory for DMA [ 1.127626] bgmac_bcma: probe of bcma0:2 failed with error -12 [ 1.133838] bgmac_bcma: Broadcom 47xx GBit MAC driver loaded The bgmac driver also triggers a WARNING: [ 0.959486] ------------[ cut here ]------------ [ 0.964387] WARNING: CPU: 0 PID: 1 at ./include/linux/dma-mapping.h:516 bgmac_enet_probe+0x1b4/0x5c4 [ 0.973751] Modules linked in: [ 0.976913] CPU: 0 PID: 1 Comm: swapper Not tainted 4.19.9 #0 [ 0.982750] Stack : 804a0000 804597c4 00000000 00000000 80458fd8 8381bc2c 838282d4 80481a47 [ 0.991367] 8042e3ec 00000001 804d38f0 00000204 83980000 00000065 8381bbe0 6f55b24f [ 0.999975] 00000000 00000000 80520000 00002018 00000000 00000075 00000007 00000000 [ 1.008583] 00000000 80480000 000ee811 00000000 00000000 00000000 80432c00 80248db8 [ 1.017196] 00000009 00000204 83980000 803ad7b0 00000000 801feeec 00000000 804d0000 [ 1.025804] ... [ 1.028325] Call Trace: [ 1.030875] [<8000aef8>] show_stack+0x58/0x100 [ 1.035513] [<8001f8b4>] __warn+0xe4/0x118 [ 1.039708] [<8001f9a4>] warn_slowpath_null+0x48/0x64 [ 1.044935] [<80248db8>] bgmac_enet_probe+0x1b4/0x5c4 [ 1.050101] [<802498e0>] bgmac_probe+0x558/0x590 [ 1.054906] [<80252fd0>] bcma_device_probe+0x38/0x70 [ 1.060017] [<8020e1e8>] really_probe+0x170/0x2e8 [ 1.064891] [<8020e714>] __driver_attach+0xa4/0xec [ 1.069784] [<8020c1e0>] bus_for_each_dev+0x58/0xb0 [ 1.074833] [<8020d590>] bus_add_driver+0xf8/0x218 [ 1.079731] [<8020ef24>] driver_register+0xcc/0x11c [ 1.084804] [<804b54cc>] bgmac_init+0x1c/0x44 [ 1.089258] [<8000121c>] do_one_initcall+0x7c/0x1a0 [ 1.094343] [<804a1d34>] kernel_init_freeable+0x150/0x218 [ 1.099886] [<803a082c>] kernel_init+0x10/0x104 [ 1.104583] [<80005878>] ret_from_kernel_thread+0x14/0x1c [ 1.110107] ---[ end trace f441c0d873d1fb5b ]--- This patch setups a "struct device" (and passes it to the bcma) which allows fixing all the mentioned problems. It'll also require a tiny bcma patch which will follow through the wireless tree & its maintainer. Fixes: f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms") Signed-off-by: Rafał Miłecki Signed-off-by: Paul Burton Acked-by: Hauke Mehrtens Cc: Christoph Hellwig Cc: Linus Walleij Cc: linux-wireless@vger.kernel.org Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org # v4.19+ --- arch/mips/bcm47xx/setup.c | 31 +++++++++++++++++++++++++++++++ include/linux/bcma/bcma_soc.h | 1 + 2 files changed, 32 insertions(+) diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 6054d49e608e..fe3773539eff 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -173,6 +173,31 @@ void __init plat_mem_setup(void) pm_power_off = bcm47xx_machine_halt; } +#ifdef CONFIG_BCM47XX_BCMA +static struct device * __init bcm47xx_setup_device(void) +{ + struct device *dev; + int err; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + err = dev_set_name(dev, "bcm47xx_soc"); + if (err) { + pr_err("Failed to set SoC device name: %d\n", err); + kfree(dev); + return NULL; + } + + err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (err) + pr_err("Failed to set SoC DMA mask: %d\n", err); + + return dev; +} +#endif + /* * This finishes bus initialization doing things that were not possible without * kmalloc. Make sure to call it late enough (after mm_init). @@ -183,6 +208,10 @@ void __init bcm47xx_bus_setup(void) if (bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA) { int err; + bcm47xx_bus.bcma.dev = bcm47xx_setup_device(); + if (!bcm47xx_bus.bcma.dev) + panic("Failed to setup SoC device\n"); + err = bcma_host_soc_init(&bcm47xx_bus.bcma); if (err) panic("Failed to initialize BCMA bus (err %d)", err); @@ -235,6 +264,8 @@ static int __init bcm47xx_register_bus_complete(void) #endif #ifdef CONFIG_BCM47XX_BCMA case BCM47XX_BUS_TYPE_BCMA: + if (device_register(bcm47xx_bus.bcma.dev)) + pr_err("Failed to register SoC device\n"); bcma_bus_register(&bcm47xx_bus.bcma.bus); break; #endif diff --git a/include/linux/bcma/bcma_soc.h b/include/linux/bcma/bcma_soc.h index 7cca5f859a90..f3c43519baa7 100644 --- a/include/linux/bcma/bcma_soc.h +++ b/include/linux/bcma/bcma_soc.h @@ -6,6 +6,7 @@ struct bcma_soc { struct bcma_bus bus; + struct device *dev; }; int __init bcma_host_soc_register(struct bcma_soc *soc); -- cgit v1.2.3-58-ga151 From e7f45099442a380f8e087b6a8aadc36e887df1cc Mon Sep 17 00:00:00 2001 From: Santosh kumar pradhan Date: Wed, 9 Jan 2019 22:08:26 +0530 Subject: sunrpc: kernel BUG at kernel/cred.c:825! Init missing debug member magic with CRED_MAGIC. Signed-off-by: Santosh kumar pradhan Reported-by: Dave Jones Signed-off-by: Anna Schumaker --- net/sunrpc/auth.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 1ff9768f5456..f3023bbc0b7f 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -41,6 +41,9 @@ static unsigned long number_cred_unused; static struct cred machine_cred = { .usage = ATOMIC_INIT(1), +#ifdef CONFIG_DEBUG_CREDENTIALS + .magic = CRED_MAGIC, +#endif }; /* -- cgit v1.2.3-58-ga151 From a799aea0988ea0d1b1f263e996fdad2f6133c680 Mon Sep 17 00:00:00 2001 From: wenxu Date: Wed, 9 Jan 2019 10:40:11 +0800 Subject: netfilter: nft_flow_offload: Fix reverse route lookup Using the following example: client 1.1.1.7 ---> 2.2.2.7 which dnat to 10.0.0.7 server The first reply packet (ie. syn+ack) uses an incorrect destination address for the reverse route lookup since it uses: daddr = ct->tuplehash[!dir].tuple.dst.u3.ip; which is 2.2.2.7 in the scenario that is described above, while this should be: daddr = ct->tuplehash[dir].tuple.src.u3.ip; that is 10.0.0.7. Signed-off-by: wenxu Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_flow_offload.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c index 974525eb92df..ccdb8f5ababb 100644 --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c @@ -29,10 +29,10 @@ static int nft_flow_route(const struct nft_pktinfo *pkt, memset(&fl, 0, sizeof(fl)); switch (nft_pf(pkt)) { case NFPROTO_IPV4: - fl.u.ip4.daddr = ct->tuplehash[!dir].tuple.dst.u3.ip; + fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip; break; case NFPROTO_IPV6: - fl.u.ip6.daddr = ct->tuplehash[!dir].tuple.dst.u3.in6; + fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6; break; } -- cgit v1.2.3-58-ga151 From 649d4968860ba708636ad643bd52b28027367042 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Wed, 9 Jan 2019 13:59:32 -0700 Subject: block: fix kerneldoc comment for blk_attempt_plug_merge() Commit 5f0ed774ed29 ("block: sum requests in the plug structure") removed the request_count parameter from block_attempt_plug_merge(), but did not remove the associated kerneldoc comment, introducing this warning to the docs build: ./block/blk-core.c:685: warning: Excess function parameter 'request_count' description in 'blk_attempt_plug_merge' Remove the obsolete description and make things a little quieter. Signed-off-by: Jonathan Corbet Signed-off-by: Jens Axboe --- block/blk-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/block/blk-core.c b/block/blk-core.c index f2732f106a2e..3c5f61ceeb67 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -661,7 +661,6 @@ no_merge: * blk_attempt_plug_merge - try to merge with %current's plugged list * @q: request_queue new bio is being queued at * @bio: new bio being queued - * @request_count: out parameter for number of traversed plugged requests * @same_queue_rq: pointer to &struct request that gets filled in when * another request associated with @q is found on the plug list * (optional, may be %NULL) -- cgit v1.2.3-58-ga151 From 27de1f541f1f911bc2242ae68ef7375247b36c7d Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Tue, 4 Dec 2018 19:25:05 +0530 Subject: tty/serial: Add RISC-V SBI earlycon support In RISC-V, the M-mode runtime firmware provide SBI calls for debug prints. This patch adds earlycon support using RISC-V SBI console calls. To enable it, just pass "earlycon=sbi" in kernel parameters. Signed-off-by: Anup Patel Acked-by: Greg Kroah-Hartman Reviewed-by: Palmer Dabbelt Signed-off-by: Palmer Dabbelt --- drivers/tty/serial/Kconfig | 12 ++++++++++++ drivers/tty/serial/Makefile | 1 + drivers/tty/serial/earlycon-riscv-sbi.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 drivers/tty/serial/earlycon-riscv-sbi.c diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 67b9bf3b500e..089a6f285d5e 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -85,6 +85,18 @@ config SERIAL_EARLYCON_ARM_SEMIHOST with "earlycon=smh" on the kernel command line. The console is enabled when early_param is processed. +config SERIAL_EARLYCON_RISCV_SBI + bool "Early console using RISC-V SBI" + depends on RISCV + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Support for early debug console using RISC-V SBI. This enables + the console before standard serial driver is probed. This is enabled + with "earlycon=sbi" on the kernel command line. The console is + enabled when early_param is processed. + config SERIAL_SB1250_DUART tristate "BCM1xxx on-chip DUART serial support" depends on SIBYTE_SB1xxx_SOC=y diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 8c303736b7e8..1511e8a9f856 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_CORE) += serial_core.o obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o +obj-$(CONFIG_SERIAL_EARLYCON_RISCV_SBI) += earlycon-riscv-sbi.o # These Sparc drivers have to appear before others such as 8250 # which share ttySx minor node space. Otherwise console device diff --git a/drivers/tty/serial/earlycon-riscv-sbi.c b/drivers/tty/serial/earlycon-riscv-sbi.c new file mode 100644 index 000000000000..e1a551aae336 --- /dev/null +++ b/drivers/tty/serial/earlycon-riscv-sbi.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RISC-V SBI based earlycon + * + * Copyright (C) 2018 Anup Patel + */ +#include +#include +#include +#include +#include + +static void sbi_console_write(struct console *con, + const char *s, unsigned int n) +{ + int i; + + for (i = 0; i < n; ++i) + sbi_console_putchar(s[i]); +} + +static int __init early_sbi_setup(struct earlycon_device *device, + const char *opt) +{ + device->con->write = sbi_console_write; + return 0; +} +EARLYCON_DECLARE(sbi, early_sbi_setup); -- cgit v1.2.3-58-ga151 From 31aa6503a15ba00182ea6dbbf51afb63bf9e851d Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Tue, 8 Jan 2019 18:12:24 -0800 Subject: bpf: correctly set initial window on active Fast Open sender The existing BPF TCP initial congestion window (TCP_BPF_IW) does not to work on (active) Fast Open sender. This is because it changes the (initial) window only if data_segs_out is zero -- but data_segs_out is also incremented on SYN-data. This patch fixes the issue by proerly accounting for SYN-data additionally. Fixes: fc7478103c84 ("bpf: Adds support for setting initial cwnd") Signed-off-by: Yuchung Cheng Reviewed-by: Neal Cardwell Acked-by: Lawrence Brakmo Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/filter.c b/net/core/filter.c index 447dd1bad31f..2b3b436ef545 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4203,7 +4203,7 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, /* Only some options are supported */ switch (optname) { case TCP_BPF_IW: - if (val <= 0 || tp->data_segs_out > 0) + if (val <= 0 || tp->data_segs_out > tp->syn_data) ret = -EINVAL; else tp->snd_cwnd = val; -- cgit v1.2.3-58-ga151 From b5679cebf780c6f1c2451a73bf1842a4409840e7 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 9 Jan 2019 20:56:06 +0000 Subject: vmbus: fix subchannel removal The changes to split ring allocation from open/close, broke the cleanup of subchannels. This resulted in problems using uio on network devices because the subchannel was left behind when the network device was unbound. The cause was in the disconnect logic which used list splice to move the subchannel list into a local variable. This won't work because the subchannel list is needed later during the process of the rescind messages (relid2channel). The fix is to just leave the subchannel list in place which is what the original code did. The list is cleaned up later when the host rescind is processed. Without the fix, we have a lot of "hang" issues in netvsc when we try to change the NIC's MTU, set the number of channels, etc. Fixes: ae6935ed7d42 ("vmbus: split ring buffer allocation from open") Cc: stable@vger.kernel.org Signed-off-by: Stephen Hemminger Signed-off-by: Dexuan Cui Signed-off-by: Sasha Levin --- drivers/hv/channel.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index ce0ba2062723..bea4c9850247 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -701,19 +701,12 @@ static int vmbus_close_internal(struct vmbus_channel *channel) int vmbus_disconnect_ring(struct vmbus_channel *channel) { struct vmbus_channel *cur_channel, *tmp; - unsigned long flags; - LIST_HEAD(list); int ret; if (channel->primary_channel != NULL) return -EINVAL; - /* Snapshot the list of subchannels */ - spin_lock_irqsave(&channel->lock, flags); - list_splice_init(&channel->sc_list, &list); - spin_unlock_irqrestore(&channel->lock, flags); - - list_for_each_entry_safe(cur_channel, tmp, &list, sc_list) { + list_for_each_entry_safe(cur_channel, tmp, &channel->sc_list, sc_list) { if (cur_channel->rescind) wait_for_completion(&cur_channel->rescind_event); -- cgit v1.2.3-58-ga151 From 5db470e229e22b7eda6e23b5566e532c96fb5bc3 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 9 Jan 2019 19:17:14 -0800 Subject: loop: drop caches if offset or block_size are changed If we don't drop caches used in old offset or block_size, we can get old data from new offset/block_size, which gives unexpected data to user. For example, Martijn found a loopback bug in the below scenario. 1) LOOP_SET_FD loads first two pages on loop file 2) LOOP_SET_STATUS64 changes the offset on the loop file 3) mount is failed due to the cached pages having wrong superblock Cc: Jens Axboe Cc: linux-block@vger.kernel.org Reported-by: Martijn Coenen Reviewed-by: Bart Van Assche Signed-off-by: Jaegeuk Kim Signed-off-by: Jens Axboe --- drivers/block/loop.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b8a0720d3653..cf5538942834 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1190,6 +1190,12 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) goto out_unlock; } + if (lo->lo_offset != info->lo_offset || + lo->lo_sizelimit != info->lo_sizelimit) { + sync_blockdev(lo->lo_device); + kill_bdev(lo->lo_device); + } + /* I/O need to be drained during transfer transition */ blk_mq_freeze_queue(lo->lo_queue); @@ -1218,6 +1224,14 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if (lo->lo_offset != info->lo_offset || lo->lo_sizelimit != info->lo_sizelimit) { + /* kill_bdev should have truncated all the pages */ + if (lo->lo_device->bd_inode->i_mapping->nrpages) { + err = -EAGAIN; + pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", + __func__, lo->lo_number, lo->lo_file_name, + lo->lo_device->bd_inode->i_mapping->nrpages); + goto out_unfreeze; + } if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) { err = -EFBIG; goto out_unfreeze; @@ -1443,22 +1457,39 @@ static int loop_set_dio(struct loop_device *lo, unsigned long arg) static int loop_set_block_size(struct loop_device *lo, unsigned long arg) { + int err = 0; + if (lo->lo_state != Lo_bound) return -ENXIO; if (arg < 512 || arg > PAGE_SIZE || !is_power_of_2(arg)) return -EINVAL; + if (lo->lo_queue->limits.logical_block_size != arg) { + sync_blockdev(lo->lo_device); + kill_bdev(lo->lo_device); + } + blk_mq_freeze_queue(lo->lo_queue); + /* kill_bdev should have truncated all the pages */ + if (lo->lo_queue->limits.logical_block_size != arg && + lo->lo_device->bd_inode->i_mapping->nrpages) { + err = -EAGAIN; + pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", + __func__, lo->lo_number, lo->lo_file_name, + lo->lo_device->bd_inode->i_mapping->nrpages); + goto out_unfreeze; + } + blk_queue_logical_block_size(lo->lo_queue, arg); blk_queue_physical_block_size(lo->lo_queue, arg); blk_queue_io_min(lo->lo_queue, arg); loop_update_dio(lo); - +out_unfreeze: blk_mq_unfreeze_queue(lo->lo_queue); - return 0; + return err; } static int lo_simple_ioctl(struct loop_device *lo, unsigned int cmd, -- cgit v1.2.3-58-ga151 From ee46967fc6e74d412fe1ec15f77fdb8624bde2b0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 9 Jan 2019 13:50:18 +1000 Subject: HID: core: replace the collection tree pointers with indices Previously, the pointer to the parent collection was stored. If a device exceeds 16 collections (HID_DEFAULT_NUM_COLLECTIONS), the array to store the collections is reallocated, the pointer to the parent collection becomes invalid. Replace the pointers with an index-based lookup into the collections array. Fixes: c53431eb696f3c ("HID: core: store the collections as a basic tree") Reported-by: Pandruvada, Srinivas Signed-off-by: Peter Hutterer Tested-by: Kyle Pelton Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 32 +++++++++++++++++++++----------- include/linux/hid.h | 4 ++-- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f41d5fe51abe..f9093dedf647 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -125,6 +125,7 @@ static int open_collection(struct hid_parser *parser, unsigned type) { struct hid_collection *collection; unsigned usage; + int collection_index; usage = parser->local.usage[0]; @@ -167,13 +168,13 @@ static int open_collection(struct hid_parser *parser, unsigned type) parser->collection_stack[parser->collection_stack_ptr++] = parser->device->maxcollection; - collection = parser->device->collection + - parser->device->maxcollection++; + collection_index = parser->device->maxcollection++; + collection = parser->device->collection + collection_index; collection->type = type; collection->usage = usage; collection->level = parser->collection_stack_ptr - 1; - collection->parent = parser->active_collection; - parser->active_collection = collection; + collection->parent_idx = parser->active_collection_idx; + parser->active_collection_idx = collection_index; if (type == HID_COLLECTION_APPLICATION) parser->device->maxapplication++; @@ -192,8 +193,13 @@ static int close_collection(struct hid_parser *parser) return -EINVAL; } parser->collection_stack_ptr--; - if (parser->active_collection) - parser->active_collection = parser->active_collection->parent; + if (parser->active_collection_idx != -1) { + struct hid_device *device = parser->device; + struct hid_collection *c; + + c = &device->collection[parser->active_collection_idx]; + parser->active_collection_idx = c->parent_idx; + } return 0; } @@ -819,6 +825,7 @@ static int hid_scan_report(struct hid_device *hid) return -ENOMEM; parser->device = hid; + parser->active_collection_idx = -1; hid->group = HID_GROUP_GENERIC; /* @@ -1006,10 +1013,12 @@ static void hid_apply_multiplier_to_field(struct hid_device *hid, usage = &field->usage[i]; collection = &hid->collection[usage->collection_index]; - while (collection && collection != multiplier_collection) - collection = collection->parent; + while (collection->parent_idx != -1 && + collection != multiplier_collection) + collection = &hid->collection[collection->parent_idx]; - if (collection || multiplier_collection == NULL) + if (collection->parent_idx != -1 || + multiplier_collection == NULL) usage->resolution_multiplier = effective_multiplier; } @@ -1044,9 +1053,9 @@ static void hid_apply_multiplier(struct hid_device *hid, * applicable fields later. */ multiplier_collection = &hid->collection[multiplier->usage->collection_index]; - while (multiplier_collection && + while (multiplier_collection->parent_idx != -1 && multiplier_collection->type != HID_COLLECTION_LOGICAL) - multiplier_collection = multiplier_collection->parent; + multiplier_collection = &hid->collection[multiplier_collection->parent_idx]; effective_multiplier = hid_calculate_multiplier(hid, multiplier); @@ -1170,6 +1179,7 @@ int hid_open_report(struct hid_device *device) } parser->device = device; + parser->active_collection_idx = -1; end = start + size; diff --git a/include/linux/hid.h b/include/linux/hid.h index d99287327ef2..992bbb7196df 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -430,7 +430,7 @@ struct hid_local { */ struct hid_collection { - struct hid_collection *parent; + int parent_idx; /* device->collection */ unsigned type; unsigned usage; unsigned level; @@ -658,7 +658,7 @@ struct hid_parser { unsigned int *collection_stack; unsigned int collection_stack_ptr; unsigned int collection_stack_size; - struct hid_collection *active_collection; + int active_collection_idx; /* device->collection */ struct hid_device *device; unsigned int scan_flags; }; -- cgit v1.2.3-58-ga151 From 62d85b3bf9d978ed4b6b2aeef5cf0ccf1423906e Mon Sep 17 00:00:00 2001 From: Ivan Mironov Date: Tue, 8 Jan 2019 12:23:52 +0500 Subject: drm/fb-helper: Partially bring back workaround for bugs of SDL 1.2 SDL 1.2 sets all fields related to the pixel format to zero in some cases[1]. Prior to commit db05c48197759 ("drm: fb-helper: Reject all pixel format changing requests"), there was an unintentional workaround for this that existed for more than a decade. First in device-specific DRM drivers, then here in drm_fb_helper.c. Previous code containing this workaround just ignores pixel format fields from userspace code. Not a good thing either, as this way, driver may silently use pixel format different from what client actually requested, and this in turn will lead to displaying garbage on the screen. I think that returning EINVAL to userspace in this particular case is the right option, so I decided to left code from problematic commit untouched instead of just reverting it entirely. Here is the steps required to reproduce this problem exactly: 1) Compile fceux[2] with SDL 1.2.15 and without GTK or OpenGL support. SDL should be compiled with fbdev support (which is on by default). 2) Create /etc/fb.modes with following contents (values seems not used, and just required to trigger problematic code in SDL): mode "test" geometry 1 1 1 1 1 timings 1 1 1 1 1 1 1 endmode 3) Create ~/.fceux/fceux.cfg with following contents: SDL.Hotkeys.Quit = 27 SDL.DoubleBuffering = 1 4) Ensure that screen resolution is at least 1280x960 (e.g. append "video=Virtual-1:1280x960-32" to the kernel cmdline for qemu/QXL). 5) Try to run fceux on VT with some ROM file[3]: # ./fceux color_test.nes [1] SDL 1.2.15 source code, src/video/fbcon/SDL_fbvideo.c, FB_SetVideoMode() [2] http://www.fceux.com [3] Example ROM: https://github.com/bokuweb/rustynes/blob/master/roms/color_test.nes Reported-by: saahriktu Suggested-by: saahriktu Cc: stable@vger.kernel.org Fixes: db05c48197759 ("drm: fb-helper: Reject all pixel format changing requests") Signed-off-by: Ivan Mironov [danvet: Delete misleading comment.] Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190108072353.28078-2-mironov.ivan@gmail.com Link: https://patchwork.freedesktop.org/patch/msgid/20190108072353.28078-2-mironov.ivan@gmail.com --- drivers/gpu/drm/drm_fb_helper.c | 126 +++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index d3af098b0922..2d7ce9d3143f 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1621,6 +1621,64 @@ static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1, var_1->transp.msb_right == var_2->transp.msb_right; } +static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var, + u8 depth) +{ + switch (depth) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 8; /* 8bit DAC */ + var->green.length = 8; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 15: + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.offset = 0; + break; + case 24: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + default: + break; + } +} + /** * drm_fb_helper_check_var - implementation for &fb_ops.fb_check_var * @var: screeninfo to check @@ -1654,6 +1712,20 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, return -EINVAL; } + /* + * Workaround for SDL 1.2, which is known to be setting all pixel format + * fields values to zero in some cases. We treat this situation as a + * kind of "use some reasonable autodetected values". + */ + if (!var->red.offset && !var->green.offset && + !var->blue.offset && !var->transp.offset && + !var->red.length && !var->green.length && + !var->blue.length && !var->transp.length && + !var->red.msb_right && !var->green.msb_right && + !var->blue.msb_right && !var->transp.msb_right) { + drm_fb_helper_fill_pixel_fmt(var, fb->format->depth); + } + /* * drm fbdev emulation doesn't support changing the pixel format at all, * so reject all pixel format changing requests. @@ -1967,59 +2039,7 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe info->var.yoffset = 0; info->var.activate = FB_ACTIVATE_NOW; - switch (fb->format->depth) { - case 8: - info->var.red.offset = 0; - info->var.green.offset = 0; - info->var.blue.offset = 0; - info->var.red.length = 8; /* 8bit DAC */ - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - break; - case 15: - info->var.red.offset = 10; - info->var.green.offset = 5; - info->var.blue.offset = 0; - info->var.red.length = 5; - info->var.green.length = 5; - info->var.blue.length = 5; - info->var.transp.offset = 15; - info->var.transp.length = 1; - break; - case 16: - info->var.red.offset = 11; - info->var.green.offset = 5; - info->var.blue.offset = 0; - info->var.red.length = 5; - info->var.green.length = 6; - info->var.blue.length = 5; - info->var.transp.offset = 0; - break; - case 24: - info->var.red.offset = 16; - info->var.green.offset = 8; - info->var.blue.offset = 0; - info->var.red.length = 8; - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - break; - case 32: - info->var.red.offset = 16; - info->var.green.offset = 8; - info->var.blue.offset = 0; - info->var.red.length = 8; - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 24; - info->var.transp.length = 8; - break; - default: - break; - } + drm_fb_helper_fill_pixel_fmt(&info->var, fb->format->depth); info->var.xres = fb_width; info->var.yres = fb_height; -- cgit v1.2.3-58-ga151 From 66a8d5bfb518f9f12d47e1d2dce1732279f9451e Mon Sep 17 00:00:00 2001 From: Ivan Mironov Date: Tue, 8 Jan 2019 12:23:53 +0500 Subject: drm/fb-helper: Ignore the value of fb_var_screeninfo.pixclock Strict requirement of pixclock to be zero breaks support of SDL 1.2 which contains hardcoded table of supported video modes with non-zero pixclock values[1]. To better understand which pixclock values are considered valid and how driver should handle these values, I briefly examined few existing fbdev drivers and documentation in Documentation/fb/. And it looks like there are no strict rules on that and actual behaviour varies: * some drivers treat (pixclock == 0) as "use defaults" (uvesafb.c); * some treat (pixclock == 0) as invalid value which leads to -EINVAL (clps711x-fb.c); * some pass converted pixclock value to hardware (uvesafb.c); * some are trying to find nearest value from predefined table (vga16fb.c, video_gx.c). Given this, I believe that it should be safe to just ignore this value if changing is not supported. It seems that any portable fbdev application which was not written only for one specific device working under one specific kernel version should not rely on any particular behaviour of pixclock anyway. However, while enabling SDL1 applications to work out of the box when there is no /etc/fb.modes with valid settings, this change affects the video mode choosing logic in SDL. Depending on current screen resolution, contents of /etc/fb.modes and resolution requested by application, this may lead to user-visible difference (not always): image will be displayed in a right way, but it will be aligned to the left instead of center. There is no "right behaviour" here as well, as emulated fbdev, opposing to old fbdev drivers, simply ignores any requsts of video mode changes with resolutions smaller than current. The easiest way to reproduce this problem is to install sdl-sopwith[2], remove /etc/fb.modes file if it exists, and then try to run sopwith from console without X. At least in Fedora 29, sopwith may be simply installed from standard repositories. [1] SDL 1.2.15 source code, src/video/fbcon/SDL_fbvideo.c, vesa_timings [2] http://sdl-sopwith.sourceforge.net/ Signed-off-by: Ivan Mironov Cc: stable@vger.kernel.org Fixes: 79e539453b34e ("DRM: i915: add mode setting support") Fixes: 771fe6b912fca ("drm/radeon: introduce kernel modesetting for radeon hardware") Fixes: 785b93ef8c309 ("drm/kms: move driver specific fb common code to helper functions (v2)") Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190108072353.28078-3-mironov.ivan@gmail.com --- drivers/gpu/drm/drm_fb_helper.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 2d7ce9d3143f..d73703a695e8 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1690,9 +1690,14 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, struct drm_fb_helper *fb_helper = info->par; struct drm_framebuffer *fb = fb_helper->fb; - if (var->pixclock != 0 || in_dbg_master()) + if (in_dbg_master()) return -EINVAL; + if (var->pixclock != 0) { + DRM_DEBUG("fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n"); + var->pixclock = 0; + } + if ((drm_format_info_block_width(fb->format, 0) > 1) || (drm_format_info_block_height(fb->format, 0) > 1)) return -EINVAL; -- cgit v1.2.3-58-ga151 From cc557afb4d10cba175fd08d51c557004a229eded Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 3 Jan 2019 16:11:00 +0100 Subject: ARM: davinci: da830-evm: fix label names in GPIO lookup entries Since commit 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") the gpiochip label no longer has an ID suffix. Update the GPIO lookup entries. Fixes: 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") Cc: stable@vger.kernel.org Signed-off-by: Bartosz Golaszewski Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/board-da830-evm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index e52ec1619b70..c4da635ee4ce 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -208,9 +208,9 @@ static struct gpiod_lookup_table mmc_gpios_table = { .dev_id = "da830-mmc.0", .table = { /* gpio chip 1 contains gpio range 32-63 */ - GPIO_LOOKUP("davinci_gpio.0", DA830_MMCSD_CD_PIN, "cd", + GPIO_LOOKUP("davinci_gpio", DA830_MMCSD_CD_PIN, "cd", GPIO_ACTIVE_LOW), - GPIO_LOOKUP("davinci_gpio.0", DA830_MMCSD_WP_PIN, "wp", + GPIO_LOOKUP("davinci_gpio", DA830_MMCSD_WP_PIN, "wp", GPIO_ACTIVE_LOW), }, }; -- cgit v1.2.3-58-ga151 From c3f08cceb6a59f328f1c847b002729d1584c7a32 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 3 Jan 2019 16:11:01 +0100 Subject: ARM: davinci: da850-evm: fix label names in GPIO lookup entries Since commit 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") the gpiochip label no longer has an ID suffix. Update the GPIO lookup entries. Fixes: 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") Cc: stable@vger.kernel.org Signed-off-by: Bartosz Golaszewski Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/board-da850-evm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 6a29baf0a289..44bca048dfd0 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -805,9 +805,9 @@ static struct gpiod_lookup_table mmc_gpios_table = { .dev_id = "da830-mmc.0", .table = { /* gpio chip 2 contains gpio range 64-95 */ - GPIO_LOOKUP("davinci_gpio.0", DA850_MMCSD_CD_PIN, "cd", + GPIO_LOOKUP("davinci_gpio", DA850_MMCSD_CD_PIN, "cd", GPIO_ACTIVE_LOW), - GPIO_LOOKUP("davinci_gpio.0", DA850_MMCSD_WP_PIN, "wp", + GPIO_LOOKUP("davinci_gpio", DA850_MMCSD_WP_PIN, "wp", GPIO_ACTIVE_HIGH), }, }; -- cgit v1.2.3-58-ga151 From 94777ed3b644a1af09843f729b2a3f25794bed0f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 3 Jan 2019 16:11:02 +0100 Subject: ARM: davinci: dm355-evm: fix label names in GPIO lookup entries Since commit 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") the gpiochip label no longer has an ID suffix. Update the GPIO lookup entries. Fixes: 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") Cc: stable@vger.kernel.org Signed-off-by: Bartosz Golaszewski Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/board-dm355-evm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index f53a461a606f..f7fa960c23e3 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -117,9 +117,9 @@ static struct platform_device davinci_nand_device = { static struct gpiod_lookup_table i2c_recovery_gpiod_table = { .dev_id = "i2c_davinci.1", .table = { - GPIO_LOOKUP("davinci_gpio.0", DM355_I2C_SDA_PIN, "sda", + GPIO_LOOKUP("davinci_gpio", DM355_I2C_SDA_PIN, "sda", GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), - GPIO_LOOKUP("davinci_gpio.0", DM355_I2C_SCL_PIN, "scl", + GPIO_LOOKUP("davinci_gpio", DM355_I2C_SCL_PIN, "scl", GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), }, }; -- cgit v1.2.3-58-ga151 From 7f1015b29d9b9eb1cd3c038d6c30d698c6d7782e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 3 Jan 2019 16:11:03 +0100 Subject: ARM: davinci: dm644x-evm: fix label names in GPIO lookup entries Since commit 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") the gpiochip label no longer has an ID suffix. Update the GPIO lookup entries. Fixes: 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") Cc: stable@vger.kernel.org Signed-off-by: Bartosz Golaszewski Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/board-dm644x-evm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index e1428115067f..b80c4ee76217 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -660,9 +660,9 @@ static struct i2c_board_info __initdata i2c_info[] = { static struct gpiod_lookup_table i2c_recovery_gpiod_table = { .dev_id = "i2c_davinci.1", .table = { - GPIO_LOOKUP("davinci_gpio.0", DM644X_I2C_SDA_PIN, "sda", + GPIO_LOOKUP("davinci_gpio", DM644X_I2C_SDA_PIN, "sda", GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), - GPIO_LOOKUP("davinci_gpio.0", DM644X_I2C_SCL_PIN, "scl", + GPIO_LOOKUP("davinci_gpio", DM644X_I2C_SCL_PIN, "scl", GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN), }, }; -- cgit v1.2.3-58-ga151 From 054b8dc381b1c784852ad3e109270d236a58b71d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 3 Jan 2019 16:11:04 +0100 Subject: ARM: davinci: omapl138-hawk: fix label names in GPIO lookup entries Since commit 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") the gpiochip label no longer has an ID suffix. Update the GPIO lookup entries. Fixes: 587f7a694f01 ("gpio: davinci: Use dev name for label and automatic base selection") Cc: stable@vger.kernel.org Signed-off-by: Bartosz Golaszewski Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/board-omapl138-hawk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c index 8e8d51f4a276..94c4f126ef86 100644 --- a/arch/arm/mach-davinci/board-omapl138-hawk.c +++ b/arch/arm/mach-davinci/board-omapl138-hawk.c @@ -134,9 +134,9 @@ static const short hawk_mmcsd0_pins[] = { static struct gpiod_lookup_table mmc_gpios_table = { .dev_id = "da830-mmc.0", .table = { - GPIO_LOOKUP("davinci_gpio.0", DA850_HAWK_MMCSD_CD_PIN, "cd", + GPIO_LOOKUP("davinci_gpio", DA850_HAWK_MMCSD_CD_PIN, "cd", GPIO_ACTIVE_LOW), - GPIO_LOOKUP("davinci_gpio.0", DA850_HAWK_MMCSD_WP_PIN, "wp", + GPIO_LOOKUP("davinci_gpio", DA850_HAWK_MMCSD_WP_PIN, "wp", GPIO_ACTIVE_LOW), }, }; -- cgit v1.2.3-58-ga151 From 706edaa88835e3d8de8920584ad5da76dd3d6666 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 19 Dec 2018 13:47:23 +0200 Subject: ARM: dts: da850-evm: Correct the audio codec regulators Add the board level fixed regulators for 3.3V and 1.8V which is used to power - among other things - the tlv320aic3106 codec. Apart from removing the following warning during boot: tlv320aic3x-codec 0-0018: Too high supply voltage(s) AVDD: 5000000, DVDD: 5000000 With the correct voltages the driver can select correct OCMV value to reduce pop noise. Signed-off-by: Peter Ujfalusi Signed-off-by: Sekhar Nori --- arch/arm/boot/dts/da850-evm.dts | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/da850-evm.dts b/arch/arm/boot/dts/da850-evm.dts index a3c9b346721d..482a54587b44 100644 --- a/arch/arm/boot/dts/da850-evm.dts +++ b/arch/arm/boot/dts/da850-evm.dts @@ -94,6 +94,28 @@ regulator-boot-on; }; + baseboard_3v3: fixedregulator-3v3 { + /* TPS73701DCQ */ + compatible = "regulator-fixed"; + regulator-name = "baseboard_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vbat>; + regulator-always-on; + regulator-boot-on; + }; + + baseboard_1v8: fixedregulator-1v8 { + /* TPS73701DCQ */ + compatible = "regulator-fixed"; + regulator-name = "baseboard_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vbat>; + regulator-always-on; + regulator-boot-on; + }; + backlight_lcd: backlight-regulator { compatible = "regulator-fixed"; regulator-name = "lcd_backlight_pwr"; @@ -210,10 +232,9 @@ /* Regulators */ IOVDD-supply = <&vdcdc2_reg>; - /* Derived from VBAT: Baseboard 3.3V / 1.8V */ - AVDD-supply = <&vbat>; - DRVDD-supply = <&vbat>; - DVDD-supply = <&vbat>; + AVDD-supply = <&baseboard_3v3>; + DRVDD-supply = <&baseboard_3v3>; + DVDD-supply = <&baseboard_1v8>; }; tca6416: gpio@20 { compatible = "ti,tca6416"; -- cgit v1.2.3-58-ga151 From 7fca69d4e43fa1ae9cb4f652772c132dc5a659c6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 19 Dec 2018 13:47:24 +0200 Subject: ARM: dts: da850-evm: Correct the sound card name To avoid the following error: asoc-simple-card sound: ASoC: Failed to create card debugfs directory Which is because the card name contains '/' character, which can not be used in file or directory names. Signed-off-by: Peter Ujfalusi Signed-off-by: Sekhar Nori --- arch/arm/boot/dts/da850-evm.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/da850-evm.dts b/arch/arm/boot/dts/da850-evm.dts index 482a54587b44..f04bc3e15332 100644 --- a/arch/arm/boot/dts/da850-evm.dts +++ b/arch/arm/boot/dts/da850-evm.dts @@ -127,7 +127,7 @@ sound { compatible = "simple-audio-card"; - simple-audio-card,name = "DA850/OMAP-L138 EVM"; + simple-audio-card,name = "DA850-OMAPL138 EVM"; simple-audio-card,widgets = "Line", "Line In", "Line", "Line Out"; -- cgit v1.2.3-58-ga151 From bd540ebe68c3017194a1caa38e075bbbc0832749 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 19 Dec 2018 13:47:25 +0200 Subject: ARM: dts: da850-lcdk: Correct the audio codec regulators Add the board level fixed regulators for 3.3V and 1.8V which is used to power - among other things - the tlv320aic3106 codec. Apart from removing the following warning during boot: tlv320aic3x-codec 0-0018: Invalid supply voltage(s) AVDD: -22, DVDD: -22 With the correct voltages the driver can select correct OCMV value to reduce pop noise. Signed-off-by: Peter Ujfalusi Signed-off-by: Sekhar Nori --- arch/arm/boot/dts/da850-lcdk.dts | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm/boot/dts/da850-lcdk.dts b/arch/arm/boot/dts/da850-lcdk.dts index 0177e3ed20fe..c196e37606c4 100644 --- a/arch/arm/boot/dts/da850-lcdk.dts +++ b/arch/arm/boot/dts/da850-lcdk.dts @@ -39,6 +39,36 @@ }; }; + vcc_5vd: fixedregulator-vcc_5vd { + compatible = "regulator-fixed"; + regulator-name = "vcc_5vd"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; + + vcc_3v3d: fixedregulator-vcc_3v3d { + /* TPS650250 - VDCDC1 */ + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3d"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_5vd>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_1v8d: fixedregulator-vcc_1v8d { + /* TPS650250 - VDCDC2 */ + compatible = "regulator-fixed"; + regulator-name = "vcc_1v8d"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_5vd>; + regulator-always-on; + regulator-boot-on; + }; + sound { compatible = "simple-audio-card"; simple-audio-card,name = "DA850/OMAP-L138 LCDK"; @@ -221,6 +251,12 @@ compatible = "ti,tlv320aic3106"; reg = <0x18>; status = "okay"; + + /* Regulators */ + IOVDD-supply = <&vcc_3v3d>; + AVDD-supply = <&vcc_3v3d>; + DRVDD-supply = <&vcc_3v3d>; + DVDD-supply = <&vcc_1v8d>; }; }; -- cgit v1.2.3-58-ga151 From c25748acc5c20786ecb7518bfeae8fcef93472d6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 19 Dec 2018 13:47:26 +0200 Subject: ARM: dts: da850-lcdk: Correct the sound card name To avoid the following error: asoc-simple-card sound: ASoC: Failed to create card debugfs directory Which is because the card name contains '/' character, which can not be used in file or directory names. Signed-off-by: Peter Ujfalusi Signed-off-by: Sekhar Nori --- arch/arm/boot/dts/da850-lcdk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/da850-lcdk.dts b/arch/arm/boot/dts/da850-lcdk.dts index c196e37606c4..3a2fa6e035a3 100644 --- a/arch/arm/boot/dts/da850-lcdk.dts +++ b/arch/arm/boot/dts/da850-lcdk.dts @@ -71,7 +71,7 @@ sound { compatible = "simple-audio-card"; - simple-audio-card,name = "DA850/OMAP-L138 LCDK"; + simple-audio-card,name = "DA850-OMAPL138 LCDK"; simple-audio-card,widgets = "Line", "Line In", "Line", "Line Out"; -- cgit v1.2.3-58-ga151 From 85f5a4d666fd9be73856ed16bb36c5af5b406b29 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 8 Jan 2019 19:47:38 +0100 Subject: rbd: don't return 0 on unmap if RBD_DEV_FLAG_REMOVING is set There is a window between when RBD_DEV_FLAG_REMOVING is set and when the device is removed from rbd_dev_list. During this window, we set "already" and return 0. Returning 0 from write(2) can confuse userspace tools because 0 indicates that nothing was written. In particular, "rbd unmap" will retry the write multiple times a second: 10:28:05.463299 write(4, "0", 1) = 0 10:28:05.463509 write(4, "0", 1) = 0 10:28:05.463720 write(4, "0", 1) = 0 10:28:05.463942 write(4, "0", 1) = 0 10:28:05.464155 write(4, "0", 1) = 0 Cc: stable@vger.kernel.org Signed-off-by: Ilya Dryomov Tested-by: Dongsheng Yang --- drivers/block/rbd.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 8e5140bbf241..1e92b61d0bd5 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -5986,7 +5986,6 @@ static ssize_t do_rbd_remove(struct bus_type *bus, struct list_head *tmp; int dev_id; char opt_buf[6]; - bool already = false; bool force = false; int ret; @@ -6019,13 +6018,13 @@ static ssize_t do_rbd_remove(struct bus_type *bus, spin_lock_irq(&rbd_dev->lock); if (rbd_dev->open_count && !force) ret = -EBUSY; - else - already = test_and_set_bit(RBD_DEV_FLAG_REMOVING, - &rbd_dev->flags); + else if (test_and_set_bit(RBD_DEV_FLAG_REMOVING, + &rbd_dev->flags)) + ret = -EINPROGRESS; spin_unlock_irq(&rbd_dev->lock); } spin_unlock(&rbd_dev_list_lock); - if (ret < 0 || already) + if (ret) return ret; if (force) { -- cgit v1.2.3-58-ga151 From 1f7b7081568bca281f4ef42096206180cfaced00 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 10 Jan 2019 00:19:44 +0100 Subject: PM-runtime: Fix 'jiffies' in comments after switch to hrtimers PM-runtime now uses the hrtimers infrastructure for autosuspend, however comments still reference 'jiffies'. Fixes: 8234f6734c5d (PM-runtime: Switch autosuspend over to using hrtimers) Signed-off-by: Ladislav Michl Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 70624695b6d5..a282e74d1a16 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -121,7 +121,7 @@ static void pm_runtime_cancel_pending(struct device *dev) * Compute the autosuspend-delay expiration time based on the device's * power.last_busy time. If the delay has already expired or is disabled * (negative) or the power.use_autosuspend flag isn't set, return 0. - * Otherwise return the expiration time in jiffies (adjusted to be nonzero). + * Otherwise return the expiration time in nanoseconds (adjusted to be nonzero). * * This function may be called either with or without dev->power.lock held. * Either way it can be racy, since power.last_busy may be updated at any time. @@ -905,7 +905,10 @@ static enum hrtimer_restart pm_suspend_timer_fn(struct hrtimer *timer) spin_lock_irqsave(&dev->power.lock, flags); expires = dev->power.timer_expires; - /* If 'expire' is after 'jiffies' we've been called too early. */ + /* + * If 'expires' is after the current time, we've been called + * too early. + */ if (expires > 0 && expires < ktime_to_ns(ktime_get())) { dev->power.timer_expires = 0; rpm_suspend(dev, dev->power.timer_autosuspends ? -- cgit v1.2.3-58-ga151 From ca27e4cd0bdd87e33fda38e6e3d18d36d54356d4 Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Thu, 10 Jan 2019 10:00:40 +0100 Subject: PM-runtime: Fix autosuspend_delay on 32bits arch Cast autosuspend_delay to u64 to make sure that the full computation of 'expires' or slack will be done in u64, even on 32bits arch. Otherwise, any delay greater than 2^31 nsec can overflow if signed 32bits is used when converting delay from msec to nsec. Fixes: 8234f6734c5d (PM-runtime: Switch autosuspend over to using hrtimers) Reported-by: Tony Lindgren Tested-by: Tony Lindgren Signed-off-by: Vincent Guittot Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index a282e74d1a16..457be03b744d 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -141,7 +141,7 @@ u64 pm_runtime_autosuspend_expiration(struct device *dev) last_busy = READ_ONCE(dev->power.last_busy); - expires = last_busy + autosuspend_delay * NSEC_PER_MSEC; + expires = last_busy + (u64)autosuspend_delay * NSEC_PER_MSEC; if (expires <= now) expires = 0; /* Already expired. */ @@ -525,7 +525,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) * We add a slack of 25% to gather wakeups * without sacrificing the granularity. */ - u64 slack = READ_ONCE(dev->power.autosuspend_delay) * + u64 slack = (u64)READ_ONCE(dev->power.autosuspend_delay) * (NSEC_PER_MSEC >> 2); dev->power.timer_expires = expires; -- cgit v1.2.3-58-ga151 From 4089e272ac61603931beb024d4d640de2cb390e0 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 10 Jan 2019 19:19:31 +0900 Subject: gpu/drm: Fix lock held when returning to user space. We need to call drm_modeset_acquire_fini() when drm_atomic_state_alloc() failed or call drm_modeset_acquire_init() after drm_atomic_state_alloc() succeeded. Signed-off-by: Tetsuo Handa Reported-by: syzbot Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1547115571-21219-1-git-send-email-penguin-kernel@I-love.SAKURA.ne.jp --- drivers/gpu/drm/drm_atomic_uapi.c | 3 +-- drivers/gpu/drm/drm_mode_object.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index c40889888a16..9a1f41adfc67 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -1296,12 +1296,11 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, (arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) return -EINVAL; - drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); - state = drm_atomic_state_alloc(dev); if (!state) return -ENOMEM; + drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); state->acquire_ctx = &ctx; state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET); diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index cd9bc0ce9be0..004191d01772 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -459,11 +459,11 @@ static int set_property_atomic(struct drm_mode_object *obj, struct drm_modeset_acquire_ctx ctx; int ret; - drm_modeset_acquire_init(&ctx, 0); - state = drm_atomic_state_alloc(dev); if (!state) return -ENOMEM; + + drm_modeset_acquire_init(&ctx, 0); state->acquire_ctx = &ctx; retry: if (prop == state->dev->mode_config.dpms_property) { -- cgit v1.2.3-58-ga151 From f833fe2056b3a6d69598ef029cede6e77dcc1b14 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 10 Jan 2019 01:43:09 +0000 Subject: ASoC: Intel: bytcht_es8316: use correct drvdata in snd_byt_cht_es8316_mc_remove() The snd_byt_cht_es8316_mc_remove() use the platform drvdata as a type of 'struct byt_cht_es8316_private', but snd_byt_cht_es8316_mc_probe() set it to 'struct snd_soc_card', as suggested by Dan Carpenter, fix the usage in snd_byt_cht_es8316_mc_remove(). Fixes: 0d3e91da0750 ("ASoC: Intel: bytcht_es8316: Add external speaker mux support") Signed-off-by: Wei Yongjun Acked-by: Pierre-Louis Bossart Reviewed-by: Hans de Goede Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index cdf2061e7613..fa9c4cf97686 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -544,7 +544,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) { - struct byt_cht_es8316_private *priv = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); gpiod_put(priv->speaker_en_gpio); return 0; -- cgit v1.2.3-58-ga151 From ba422731316dde1e22dcc84b83c7349dc0ce1c3c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 9 Jan 2019 16:51:17 -0800 Subject: mm/mmu_notifier: mm/rmap.c: Fix a mmu_notifier range bug in try_to_unmap_one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion to use a structure for mmu_notifier_invalidate_range_*() unintentionally changed the usage in try_to_unmap_one() to init the 'struct mmu_notifier_range' with vma->vm_start instead of @address, i.e. it invalidates the wrong address range. Revert to the correct address range. Manifests as KVM use-after-free WARNINGs and subsequent "BUG: Bad page state in process X" errors when reclaiming from a KVM guest due to KVM removing the wrong pages from its own mappings. Reported-by: leozinho29_eu@hotmail.com Reported-by: Mike Galbraith Reported-and-tested-by: Adam Borowski Reviewed-by: Jérôme Glisse Reviewed-by: Pankaj gupta Cc: Christian König Cc: Jan Kara Cc: Matthew Wilcox Cc: Ross Zwisler Cc: Dan Williams Cc: Paolo Bonzini Cc: Radim Krčmář Cc: Michal Hocko Cc: Felix Kuehling Cc: Ralph Campbell Cc: John Hubbard Cc: Andrew Morton Fixes: ac46d4f3c432 ("mm/mmu_notifier: use structure for invalidate_range_start/end calls v2") Signed-off-by: Sean Christopherson Signed-off-by: Linus Torvalds --- mm/rmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/rmap.c b/mm/rmap.c index 68a1a5b869a5..0454ecc29537 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -1371,8 +1371,8 @@ static bool try_to_unmap_one(struct page *page, struct vm_area_struct *vma, * Note that the page can not be free in this function as call of * try_to_unmap() must hold a reference on the page. */ - mmu_notifier_range_init(&range, vma->vm_mm, vma->vm_start, - min(vma->vm_end, vma->vm_start + + mmu_notifier_range_init(&range, vma->vm_mm, address, + min(vma->vm_end, address + (PAGE_SIZE << compound_order(page)))); if (PageHuge(page)) { /* -- cgit v1.2.3-58-ga151 From d9ed41962ee202f653a5fa8d2ea0f52924abe629 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 9 Jan 2019 10:34:49 +0000 Subject: arm64: asm-prototypes: Fix fat-fingered typo in comment Some of the right letters, not necessarily in the right order: CONFIG_MODEVERIONS -> CONFIG_MODVERSIONS Signed-off-by: Will Deacon --- arch/arm64/include/asm/asm-prototypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/asm-prototypes.h b/arch/arm64/include/asm/asm-prototypes.h index 2173ad32d550..1c9a3a0c5fa5 100644 --- a/arch/arm64/include/asm/asm-prototypes.h +++ b/arch/arm64/include/asm/asm-prototypes.h @@ -2,7 +2,7 @@ #ifndef __ASM_PROTOTYPES_H #define __ASM_PROTOTYPES_H /* - * CONFIG_MODEVERIONS requires a C declaration to generate the appropriate CRC + * CONFIG_MODVERSIONS requires a C declaration to generate the appropriate CRC * for each symbol. Since commit: * * 4efca4ed05cbdfd1 ("kbuild: modversions for EXPORT_SYMBOL() for asm") -- cgit v1.2.3-58-ga151 From 132ac39cffbcfed80ada38ef0fc6d34d95da7be6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 21 Dec 2018 17:45:03 +0100 Subject: arm64: dts: marvell: armada-ap806: reserve PSCI area The memory area [0x4000000-0x4200000[ is occupied by the PSCI firmware. Any attempt to access it from Linux leads to an immediate crash. So let's make the same memory reservation as the vendor kernel. [gregory: added as comment that this region matches the mainline U-boot] Signed-off-by: Heinrich Schuchardt Signed-off-by: Gregory CLEMENT --- arch/arm64/boot/dts/marvell/armada-ap806.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi index 7d94c1fa592a..7f799cb5668e 100644 --- a/arch/arm64/boot/dts/marvell/armada-ap806.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-ap806.dtsi @@ -28,6 +28,23 @@ method = "smc"; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* + * This area matches the mapping done with a + * mainline U-Boot, and should be updated by the + * bootloader. + */ + + psci-area@4000000 { + reg = <0x0 0x4000000 0x0 0x200000>; + no-map; + }; + }; + ap806 { #address-cells = <2>; #size-cells = <2>; -- cgit v1.2.3-58-ga151 From 59c4dccbc3676144091783c8b46bd51daa4f80bc Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 12 Dec 2018 08:43:26 +0200 Subject: arm64: dts: marvell: mcbin: fix PCIe reset signal The MPP52 signal is on the seconds GPIO instance of CP0, which corresponds to the &cp0_gpio2 handle. Rename the property name to the standard '-gpios' suffix while at it. Fixes: b83e1669adce6 ("arm64: dts: marvell: mcbin: add support for PCIe") Signed-off-by: Baruch Siach Signed-off-by: Gregory CLEMENT --- arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi index 29ea7e81ec4c..329f8ceeebea 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi @@ -183,7 +183,7 @@ pinctrl-0 = <&cp0_pcie_pins>; num-lanes = <4>; num-viewport = <8>; - reset-gpio = <&cp0_gpio1 20 GPIO_ACTIVE_LOW>; + reset-gpios = <&cp0_gpio2 20 GPIO_ACTIVE_LOW>; status = "okay"; }; -- cgit v1.2.3-58-ga151 From b5f034845e70916fd33e172fad5ad530a29c10ab Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 8 Jan 2019 00:08:18 +0100 Subject: ARM: dts: kirkwood: Fix polarity of GPIO fan lines These two lines are active high, not active low. The bug was found when we changed the kernel to respect the polarity defined in the device tree. Fixes: 1b90e06b1429 ("ARM: kirkwood: Use devicetree to define DNS-32[05] fan") Cc: Jamie Lentin Cc: Guenter Roeck Cc: Jason Cooper Cc: Andrew Lunn Cc: Gregory Clement Cc: Sebastian Hesselbarth Cc: Julien D'Ascenzio Reviewed-by: Andrew Lunn Tested-by: Jamie Lentin Reported-by: Julien D'Ascenzio Tested-by: Julien D'Ascenzio Signed-off-by: Linus Walleij Signed-off-by: Gregory CLEMENT --- arch/arm/boot/dts/kirkwood-dnskw.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/kirkwood-dnskw.dtsi b/arch/arm/boot/dts/kirkwood-dnskw.dtsi index cbaf06f2f78e..eb917462b219 100644 --- a/arch/arm/boot/dts/kirkwood-dnskw.dtsi +++ b/arch/arm/boot/dts/kirkwood-dnskw.dtsi @@ -36,8 +36,8 @@ compatible = "gpio-fan"; pinctrl-0 = <&pmx_fan_high_speed &pmx_fan_low_speed>; pinctrl-names = "default"; - gpios = <&gpio1 14 GPIO_ACTIVE_LOW - &gpio1 13 GPIO_ACTIVE_LOW>; + gpios = <&gpio1 14 GPIO_ACTIVE_HIGH + &gpio1 13 GPIO_ACTIVE_HIGH>; gpio-fan,speed-map = <0 0 3000 1 6000 2>; -- cgit v1.2.3-58-ga151 From 70c25259537c073584eb906865307687275b527f Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Thu, 10 Jan 2019 20:28:39 +0800 Subject: csky: fixup compile error with CPU 810. This bug is from commit f553aa1c13cb ("csky: fixup relocation error with 807 & 860"). I forgot to compile with 810 for that patch. Signed-off-by: Guo Ren Cc: Arnd Bergmann Signed-off-by: Linus Torvalds --- arch/csky/kernel/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/csky/kernel/module.c b/arch/csky/kernel/module.c index 0b028ee3c764..b5ad7d9de18c 100644 --- a/arch/csky/kernel/module.c +++ b/arch/csky/kernel/module.c @@ -28,7 +28,7 @@ static void jsri_2_lrw_jsr(uint32_t *location) { - uint16_t location_tmp = (uint16_t *)location; + uint16_t *location_tmp = (uint16_t *)location; if (IS_BSR32(*location_tmp, *(location_tmp + 1))) return; -- cgit v1.2.3-58-ga151 From 1035f4a65f58407951d8d2f54c289c2b252e499c Mon Sep 17 00:00:00 2001 From: José Roberto de Souza Date: Mon, 3 Dec 2018 16:33:55 -0800 Subject: drm/i915: Disable PSR in Apple panels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i915 yet don't support PSR in Apple panels, so lets keep it disabled while we work on that. v2: Renamed DP_DPCD_QUIRK_PSR_NOT_CURRENTLY_SUPPORTED to DP_DPCD_QUIRK_NO_PSR (Ville) v3: Adding documentation to DP_DPCD_QUIRK_NO_PSR(Dhinakaran and Jani) Fixed typo in comment of the new quirk entry(Jani) Fixes: 598c6cfe0690 (drm/i915/psr: Enable PSR1 on gen-9+ HW) Cc: Jani Nikula Cc: Ville Syrjälä Cc: Rodrigo Vivi Cc: Dhinakaran Pandiyan Reviewed-by: Dhinakaran Pandiyan Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20181204003403.23361-1-jose.souza@intel.com (cherry picked from commit 7c5c641a930ed06ca317ee39faee7d5824266348) Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_dp_helper.c | 2 ++ drivers/gpu/drm/i915/intel_psr.c | 6 ++++++ include/drm/drm_dp_helper.h | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 2d6c491a0542..516e82d0ed50 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1273,6 +1273,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = { { OUI(0x00, 0x22, 0xb9), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_CONSTANT_N) }, /* LG LP140WF6-SPM1 eDP panel */ { OUI(0x00, 0x22, 0xb9), DEVICE_ID('s', 'i', 'v', 'a', 'r', 'T'), false, BIT(DP_DPCD_QUIRK_CONSTANT_N) }, + /* Apple panels need some additional handling to support PSR */ + { OUI(0x00, 0x10, 0xfa), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_NO_PSR) } }; #undef OUI diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 419e56342523..f71970df9936 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -274,10 +274,16 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) DRM_DEBUG_KMS("eDP panel supports PSR version %x\n", intel_dp->psr_dpcd[0]); + if (drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_PSR)) { + DRM_DEBUG_KMS("PSR support not currently available for this panel\n"); + return; + } + if (!(intel_dp->edp_dpcd[1] & DP_EDP_SET_POWER_CAP)) { DRM_DEBUG_KMS("Panel lacks power state control, PSR cannot be enabled\n"); return; } + dev_priv->psr.sink_support = true; dev_priv->psr.sink_sync_latency = intel_dp_get_sink_sync_latency(intel_dp); diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 5736c942c85b..c33e89c51d9f 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1365,6 +1365,13 @@ enum drm_dp_quirk { * to 16 bits. So will give a constant value (0x8000) for compatability. */ DP_DPCD_QUIRK_CONSTANT_N, + /** + * @DP_DPCD_QUIRK_NO_PSR + * + * The device does not support PSR even if reports that it supports or + * driver still need to implement proper handling for such device. + */ + DP_DPCD_QUIRK_NO_PSR, }; /** -- cgit v1.2.3-58-ga151 From 107c595c2a277be65b28762f12e1dad243e05623 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 7 Dec 2018 11:05:54 +0000 Subject: drm/i915: Skip the ERR_PTR error state Although commit fb6f0b64e455 ("drm/i915: Prevent machine hang from Broxton's vtd w/a and error capture") applied cleanly after a 24 month hiatus, the code had moved on with new methods for peeking and fetching the captured gpu info. Make sure we catch all uses of the stashed error state and avoid dereferencing the error pointer. v2: Move error pointer determination into i915_gpu_capture_state v3: Restore early check to avoid capturing and then throwing away subsequent GPU error states. Fixes: fb6f0b64e455 ("drm/i915: Prevent machine hang from Broxton's vtd w/a and error capture") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20181207110554.19897-1-chris@chris-wilson.co.uk (cherry picked from commit e6154e4cb8b0d3692f84ca0d66b4e1ba0389b134) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 12 +++++++++--- drivers/gpu/drm/i915/i915_gpu_error.c | 23 ++++++++++++++--------- drivers/gpu/drm/i915/i915_sysfs.c | 4 +++- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 38dcee1ca062..40a61ef9aac1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -984,8 +984,8 @@ static int i915_gpu_info_open(struct inode *inode, struct file *file) intel_runtime_pm_get(i915); gpu = i915_capture_gpu_state(i915); intel_runtime_pm_put(i915); - if (!gpu) - return -ENOMEM; + if (IS_ERR(gpu)) + return PTR_ERR(gpu); file->private_data = gpu; return 0; @@ -1018,7 +1018,13 @@ i915_error_state_write(struct file *filp, static int i915_error_state_open(struct inode *inode, struct file *file) { - file->private_data = i915_first_error_state(inode->i_private); + struct i915_gpu_state *error; + + error = i915_first_error_state(inode->i_private); + if (IS_ERR(error)) + return PTR_ERR(error); + + file->private_data = error; return 0; } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 07465123c166..3f9ce403c755 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1907,9 +1907,16 @@ i915_capture_gpu_state(struct drm_i915_private *i915) { struct i915_gpu_state *error; + /* Check if GPU capture has been disabled */ + error = READ_ONCE(i915->gpu_error.first_error); + if (IS_ERR(error)) + return error; + error = kzalloc(sizeof(*error), GFP_ATOMIC); - if (!error) - return NULL; + if (!error) { + i915_disable_error_state(i915, -ENOMEM); + return ERR_PTR(-ENOMEM); + } kref_init(&error->ref); error->i915 = i915; @@ -1945,11 +1952,8 @@ void i915_capture_error_state(struct drm_i915_private *i915, return; error = i915_capture_gpu_state(i915); - if (!error) { - DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); - i915_disable_error_state(i915, -ENOMEM); + if (IS_ERR(error)) return; - } i915_error_capture_msg(i915, error, engine_mask, error_msg); DRM_INFO("%s\n", error->error_msg); @@ -1987,7 +1991,7 @@ i915_first_error_state(struct drm_i915_private *i915) spin_lock_irq(&i915->gpu_error.lock); error = i915->gpu_error.first_error; - if (error) + if (!IS_ERR_OR_NULL(error)) i915_gpu_state_get(error); spin_unlock_irq(&i915->gpu_error.lock); @@ -2000,10 +2004,11 @@ void i915_reset_error_state(struct drm_i915_private *i915) spin_lock_irq(&i915->gpu_error.lock); error = i915->gpu_error.first_error; - i915->gpu_error.first_error = NULL; + if (error != ERR_PTR(-ENODEV)) /* if disabled, always disabled */ + i915->gpu_error.first_error = NULL; spin_unlock_irq(&i915->gpu_error.lock); - if (!IS_ERR(error)) + if (!IS_ERR_OR_NULL(error)) i915_gpu_state_put(error); } diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 535caebd9813..c0cfe7ae2ba5 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -521,7 +521,9 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj, ssize_t ret; gpu = i915_first_error_state(i915); - if (gpu) { + if (IS_ERR(gpu)) { + ret = PTR_ERR(gpu); + } else if (gpu) { ret = i915_gpu_state_copy_to_buffer(gpu, buf, off, count); i915_gpu_state_put(gpu); } else { -- cgit v1.2.3-58-ga151 From 280d479b310298dfeb1d6f9a1617eca37beb6ce4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 22 Dec 2018 03:06:23 +0000 Subject: drm/i915: Unwind failure on pinning the gen7 ppgtt If we fail to pin the ggtt vma slot for the ppgtt page tables, we need to unwind the locals before reporting the error. Or else on subsequent attempts to bind the page tables into the ggtt, we will already believe that the vma has been pinned and continue on blithely. If something else should happen to be at that location, choas ensues. Fixes: a2bbf7148342 ("drm/i915/gtt: Only keep gen6 page directories pinned while active") Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Mika Kuoppala Cc: Matthew Auld Cc: # v4.19+ Reviewed-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20181222030623.21710-1-chris@chris-wilson.co.uk (cherry picked from commit d4de753526f4d99f541f1b6ed1d963005c09700c) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem_gtt.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index add1fe7aeb93..bd17dd1f5da5 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2075,6 +2075,7 @@ static struct i915_vma *pd_vma_create(struct gen6_hw_ppgtt *ppgtt, int size) int gen6_ppgtt_pin(struct i915_hw_ppgtt *base) { struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(base); + int err; /* * Workaround the limited maximum vma->pin_count and the aliasing_ppgtt @@ -2090,9 +2091,17 @@ int gen6_ppgtt_pin(struct i915_hw_ppgtt *base) * allocator works in address space sizes, so it's multiplied by page * size. We allocate at the top of the GTT to avoid fragmentation. */ - return i915_vma_pin(ppgtt->vma, - 0, GEN6_PD_ALIGN, - PIN_GLOBAL | PIN_HIGH); + err = i915_vma_pin(ppgtt->vma, + 0, GEN6_PD_ALIGN, + PIN_GLOBAL | PIN_HIGH); + if (err) + goto unpin; + + return 0; + +unpin: + ppgtt->pin_count = 0; + return err; } void gen6_ppgtt_unpin(struct i915_hw_ppgtt *base) -- cgit v1.2.3-58-ga151 From 70e31424eabe4923a2140eb86f704c75db6a5c87 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 9 Jan 2019 17:32:32 -0800 Subject: drm/i915: init per-engine WAs for all engines commit 4a15c75c4246 ("drm/i915: Introduce per-engine workarounds") refactored the workaround code to have functions per-engine, but didn't call any of them from logical_xcs_ring_init. Since we do have a non-RCS workaround for KBL (WaKBLVECSSemaphoreWaitPoll) we do need to call intel_engine_init_workarounds for non-RCS engines. Note that whitelist is still RCS-only. v2: move the call to logical_ring_init (Chris) Fixes: 4a15c75c4246 ("drm/i915: Introduce per-engine workarounds") Cc: Tvrtko Ursulin Cc: Chris Wilson Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: Chris Wilson Signed-off-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20190110013232.8972-2-daniele.ceraolospurio@intel.com (cherry picked from commit a60acb223fecc77531540196008ac2de89e2a162) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_lrc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 4be167dcd209..4796f40a6d4f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2244,6 +2244,8 @@ static int logical_ring_init(struct intel_engine_cs *engine) if (ret) return ret; + intel_engine_init_workarounds(engine); + if (HAS_LOGICAL_RING_ELSQ(i915)) { execlists->submit_reg = i915->regs + i915_mmio_reg_offset(RING_EXECLIST_SQ_CONTENTS(engine)); @@ -2310,7 +2312,6 @@ int logical_render_ring_init(struct intel_engine_cs *engine) } intel_engine_init_whitelist(engine); - intel_engine_init_workarounds(engine); return 0; } -- cgit v1.2.3-58-ga151 From f299e0bdbaeb60fd8829f42e53a7457cc5a6f4a2 Mon Sep 17 00:00:00 2001 From: José Roberto de Souza Date: Wed, 5 Dec 2018 10:48:50 -0800 Subject: drm: Fix documentation generation for DP_DPCD_QUIRK_NO_PSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DP_DPCD_QUIRK_NO_PSR comment is missing colon causing this warning when generating kernel documentation. ./include/drm/drm_dp_helper.h:1374: warning: Incorrect use of kernel-doc format: * @DP_DPCD_QUIRK_NO_PSR Fixes: 1035f4a65f58 ("drm/i915: Disable PSR in Apple panels") Cc: Dhinakaran Pandiyan Signed-off-by: José Roberto de Souza Reviewed-by: Dhinakaran Pandiyan Link: https://patchwork.freedesktop.org/patch/msgid/20181205184850.13218-1-jose.souza@intel.com (cherry picked from commit ed17b555303c74a35f226268523b1695dbd4617d) Signed-off-by: Jani Nikula --- include/drm/drm_dp_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c33e89c51d9f..2d4fc2d33810 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1366,7 +1366,7 @@ enum drm_dp_quirk { */ DP_DPCD_QUIRK_CONSTANT_N, /** - * @DP_DPCD_QUIRK_NO_PSR + * @DP_DPCD_QUIRK_NO_PSR: * * The device does not support PSR even if reports that it supports or * driver still need to implement proper handling for such device. -- cgit v1.2.3-58-ga151 From 0206131811fa6e4b3ed64b5f1c107e2815dcab42 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Thu, 10 Jan 2019 15:19:35 +0530 Subject: perf powerpc: Rework syscall table generation Commit aff850393200 ("powerpc: add system call table generation support") changed how systemcall table is generated for powerpc. Incorporate these changes into perf as well. Committer testing: $ podman run --entrypoint=/bin/sh --privileged -v /home/acme/git:/git --rm -ti docker.io/acmel/linux-perf-tools-build-ubuntu:18.04-x-powerpc64 perfbuilder@d7a7af166a80:/git/perf$ head -2 /etc/os-release NAME="Ubuntu" VERSION="18.04.1 LTS (Bionic Beaver)" perfbuilder@d7a7af166a80:/git/perf$ perfbuilder@d7a7af166a80:/git/perf$ make ARCH=powerpc CROSS_COMPILE=powerpc64-linux-gnu- EXTRA_CFLAGS= -C /git/linux/tools/perf O=/tmp/build/perf make: Entering directory '/git/linux/tools/perf' BUILD: Doing 'make -j8' parallel build HOSTCC /tmp/build/perf/fixdep.o HOSTLD /tmp/build/perf/fixdep-in.o LINK /tmp/build/perf/fixdep Warning: Kernel ABI header at 'tools/include/uapi/linux/mman.h' differs from latest version at 'include/uapi/linux/mman.h' diff -u tools/include/uapi/linux/mman.h include/uapi/linux/mman.h sh: 1: command: Illegal option -c Auto-detecting system features: ... dwarf: [ on ] ... dwarf_getlocations: [ on ] ... glibc: [ on ] ... gtk2: [ OFF ] ... libaudit: [ OFF ] ... libbfd: [ OFF ] ... libelf: [ on ] ... libnuma: [ OFF ] ... numa_num_possible_cpus: [ OFF ] ... libperl: [ OFF ] ... libpython: [ OFF ] ... libslang: [ OFF ] ... libcrypto: [ OFF ] ... libunwind: [ OFF ] ... libdw-dwarf-unwind: [ on ] ... zlib: [ on ] ... lzma: [ OFF ] ... get_cpuid: [ OFF ] ... bpf: [ on ] Makefile.config:445: No sys/sdt.h found, no SDT events are defined, please install systemtap-sdt-devel or systemtap-sdt-dev Makefile.config:491: No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR Makefile.config:583: No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev Makefile.config:598: slang not found, disables TUI support. Please install slang-devel, libslang-dev or libslang2-dev Makefile.config:612: GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev Makefile.config:639: Missing perl devel files. Disabling perl scripting support, please install perl-ExtUtils-Embed/libperl-dev Makefile.config:666: No python interpreter was found: disables Python support - please install python-devel/python-dev Makefile.config:721: No bfd.h/libbfd found, please install binutils-dev[el]/zlib-static/libiberty-dev to gain symbol demangling Makefile.config:750: No liblzma found, disables xz kernel module decompression, please install xz-devel/liblzma-dev Makefile.config:763: No numa.h found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev Makefile.config:814: No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev Makefile.config:840: No alternatives command found, you need to set JDIR= to point to the root of your Java directory GEN /tmp/build/perf/common-cmds.h CC /tmp/build/perf/util/syscalltbl.o LD /tmp/build/perf/libperf-in.o AR /tmp/build/perf/libperf.a LINK /tmp/build/perf/perf make: Leaving directory '/git/linux/tools/perf' perfbuilder@d7a7af166a80:/git/perf$ head /tmp/build/perf/arch/powerpc/include/generated/asm/syscalls_64.c static const char *syscalltbl_powerpc_64[] = { [0] = "restart_syscall", [1] = "exit", [2] = "fork", [3] = "read", [4] = "write", [5] = "open", [6] = "close", [7] = "waitpid", [8] = "creat", perfbuilder@d7a7af166a80:/git/perf$ tail /tmp/build/perf/arch/powerpc/include/generated/asm/syscalls_64.c [381] = "pwritev2", [382] = "kexec_file_load", [383] = "statx", [384] = "pkey_alloc", [385] = "pkey_free", [386] = "pkey_mprotect", [387] = "rseq", [388] = "io_pgetevents", }; #define SYSCALLTBL_POWERPC_64_MAX_ID 388 perfbuilder@d7a7af166a80:/git/perf$ head /tmp/build/perf/arch/powerpc/include/generated/asm/syscalls_32.c static const char *syscalltbl_powerpc_32[] = { [0] = "restart_syscall", [1] = "exit", [2] = "fork", [3] = "read", [4] = "write", [5] = "open", [6] = "close", [7] = "waitpid", [8] = "creat", perfbuilder@d7a7af166a80:/git/perf$ tail /tmp/build/perf/arch/powerpc/include/generated/asm/syscalls_32.c [381] = "pwritev2", [382] = "kexec_file_load", [383] = "statx", [384] = "pkey_alloc", [385] = "pkey_free", [386] = "pkey_mprotect", [387] = "rseq", [388] = "io_pgetevents", }; #define SYSCALLTBL_POWERPC_32_MAX_ID 388 perfbuilder@d7a7af166a80:/git/perf$ Signed-off-by: Ravi Bangoria Reported-by: Arnaldo Carvalho de Melo Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Michael Ellerman Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: http://lkml.kernel.org/r/20190110094936.3132-1-ravi.bangoria@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/powerpc/Makefile | 15 +- .../perf/arch/powerpc/entry/syscalls/mksyscalltbl | 22 +- tools/perf/arch/powerpc/entry/syscalls/syscall.tbl | 427 +++++++++++++++++++++ 3 files changed, 450 insertions(+), 14 deletions(-) create mode 100644 tools/perf/arch/powerpc/entry/syscalls/syscall.tbl diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile index a111239df182..e58d00d62f02 100644 --- a/tools/perf/arch/powerpc/Makefile +++ b/tools/perf/arch/powerpc/Makefile @@ -14,18 +14,25 @@ PERF_HAVE_JITDUMP := 1 out := $(OUTPUT)arch/powerpc/include/generated/asm header32 := $(out)/syscalls_32.c header64 := $(out)/syscalls_64.c -sysdef := $(srctree)/tools/arch/powerpc/include/uapi/asm/unistd.h -sysprf := $(srctree)/tools/perf/arch/powerpc/entry/syscalls/ +syskrn := $(srctree)/arch/powerpc/kernel/syscalls/syscall.tbl +sysprf := $(srctree)/tools/perf/arch/powerpc/entry/syscalls +sysdef := $(sysprf)/syscall.tbl systbl := $(sysprf)/mksyscalltbl # Create output directory if not already present _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') $(header64): $(sysdef) $(systbl) - $(Q)$(SHELL) '$(systbl)' '64' '$(CC)' $(sysdef) > $@ + @(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ + (diff -B $(sysdef) $(syskrn) >/dev/null) \ + || echo "Warning: Kernel ABI header at '$(sysdef)' differs from latest version at '$(syskrn)'" >&2 )) || true + $(Q)$(SHELL) '$(systbl)' '64' $(sysdef) > $@ $(header32): $(sysdef) $(systbl) - $(Q)$(SHELL) '$(systbl)' '32' '$(CC)' $(sysdef) > $@ + @(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ + (diff -B $(sysdef) $(syskrn) >/dev/null) \ + || echo "Warning: Kernel ABI header at '$(sysdef)' differs from latest version at '$(syskrn)'" >&2 )) || true + $(Q)$(SHELL) '$(systbl)' '32' $(sysdef) > $@ clean:: $(call QUIET_CLEAN, powerpc) $(RM) $(header32) $(header64) diff --git a/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl b/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl index ef52e1dd694b..6c58060aa03b 100755 --- a/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl +++ b/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl @@ -9,10 +9,9 @@ # Changed by: Ravi Bangoria wordsize=$1 -gcc=$2 -input=$3 +SYSCALL_TBL=$2 -if ! test -r $input; then +if ! test -r $SYSCALL_TBL; then echo "Could not read input file" >&2 exit 1 fi @@ -20,18 +19,21 @@ fi create_table() { local wordsize=$1 - local max_nr + local max_nr nr abi sc discard + max_nr=-1 + nr=0 echo "static const char *syscalltbl_powerpc_${wordsize}[] = {" - while read sc nr; do - printf '\t[%d] = "%s",\n' $nr $sc - max_nr=$nr + while read nr abi sc discard; do + if [ "$max_nr" -lt "$nr" ]; then + printf '\t[%d] = "%s",\n' $nr $sc + max_nr=$nr + fi done echo '};' echo "#define SYSCALLTBL_POWERPC_${wordsize}_MAX_ID $max_nr" } -$gcc -m${wordsize} -E -dM -x c $input \ - |sed -ne 's/^#define __NR_//p' \ - |sort -t' ' -k2 -nu \ +grep -E "^[[:digit:]]+[[:space:]]+(common|spu|nospu|${wordsize})" $SYSCALL_TBL \ + |sort -k1 -n \ |create_table ${wordsize} diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl new file mode 100644 index 000000000000..db3bbb8744af --- /dev/null +++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl @@ -0,0 +1,427 @@ +# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note +# +# system call numbers and entry vectors for powerpc +# +# The format is: +# +# +# The can be common, spu, nospu, 64, or 32 for this file. +# +0 nospu restart_syscall sys_restart_syscall +1 nospu exit sys_exit +2 nospu fork ppc_fork +3 common read sys_read +4 common write sys_write +5 common open sys_open compat_sys_open +6 common close sys_close +7 common waitpid sys_waitpid +8 common creat sys_creat +9 common link sys_link +10 common unlink sys_unlink +11 nospu execve sys_execve compat_sys_execve +12 common chdir sys_chdir +13 common time sys_time compat_sys_time +14 common mknod sys_mknod +15 common chmod sys_chmod +16 common lchown sys_lchown +17 common break sys_ni_syscall +18 32 oldstat sys_stat sys_ni_syscall +18 64 oldstat sys_ni_syscall +18 spu oldstat sys_ni_syscall +19 common lseek sys_lseek compat_sys_lseek +20 common getpid sys_getpid +21 nospu mount sys_mount compat_sys_mount +22 32 umount sys_oldumount +22 64 umount sys_ni_syscall +22 spu umount sys_ni_syscall +23 common setuid sys_setuid +24 common getuid sys_getuid +25 common stime sys_stime compat_sys_stime +26 nospu ptrace sys_ptrace compat_sys_ptrace +27 common alarm sys_alarm +28 32 oldfstat sys_fstat sys_ni_syscall +28 64 oldfstat sys_ni_syscall +28 spu oldfstat sys_ni_syscall +29 nospu pause sys_pause +30 nospu utime sys_utime compat_sys_utime +31 common stty sys_ni_syscall +32 common gtty sys_ni_syscall +33 common access sys_access +34 common nice sys_nice +35 common ftime sys_ni_syscall +36 common sync sys_sync +37 common kill sys_kill +38 common rename sys_rename +39 common mkdir sys_mkdir +40 common rmdir sys_rmdir +41 common dup sys_dup +42 common pipe sys_pipe +43 common times sys_times compat_sys_times +44 common prof sys_ni_syscall +45 common brk sys_brk +46 common setgid sys_setgid +47 common getgid sys_getgid +48 nospu signal sys_signal +49 common geteuid sys_geteuid +50 common getegid sys_getegid +51 nospu acct sys_acct +52 nospu umount2 sys_umount +53 common lock sys_ni_syscall +54 common ioctl sys_ioctl compat_sys_ioctl +55 common fcntl sys_fcntl compat_sys_fcntl +56 common mpx sys_ni_syscall +57 common setpgid sys_setpgid +58 common ulimit sys_ni_syscall +59 32 oldolduname sys_olduname +59 64 oldolduname sys_ni_syscall +59 spu oldolduname sys_ni_syscall +60 common umask sys_umask +61 common chroot sys_chroot +62 nospu ustat sys_ustat compat_sys_ustat +63 common dup2 sys_dup2 +64 common getppid sys_getppid +65 common getpgrp sys_getpgrp +66 common setsid sys_setsid +67 32 sigaction sys_sigaction compat_sys_sigaction +67 64 sigaction sys_ni_syscall +67 spu sigaction sys_ni_syscall +68 common sgetmask sys_sgetmask +69 common ssetmask sys_ssetmask +70 common setreuid sys_setreuid +71 common setregid sys_setregid +72 32 sigsuspend sys_sigsuspend +72 64 sigsuspend sys_ni_syscall +72 spu sigsuspend sys_ni_syscall +73 32 sigpending sys_sigpending compat_sys_sigpending +73 64 sigpending sys_ni_syscall +73 spu sigpending sys_ni_syscall +74 common sethostname sys_sethostname +75 common setrlimit sys_setrlimit compat_sys_setrlimit +76 32 getrlimit sys_old_getrlimit compat_sys_old_getrlimit +76 64 getrlimit sys_ni_syscall +76 spu getrlimit sys_ni_syscall +77 common getrusage sys_getrusage compat_sys_getrusage +78 common gettimeofday sys_gettimeofday compat_sys_gettimeofday +79 common settimeofday sys_settimeofday compat_sys_settimeofday +80 common getgroups sys_getgroups +81 common setgroups sys_setgroups +82 32 select ppc_select sys_ni_syscall +82 64 select sys_ni_syscall +82 spu select sys_ni_syscall +83 common symlink sys_symlink +84 32 oldlstat sys_lstat sys_ni_syscall +84 64 oldlstat sys_ni_syscall +84 spu oldlstat sys_ni_syscall +85 common readlink sys_readlink +86 nospu uselib sys_uselib +87 nospu swapon sys_swapon +88 nospu reboot sys_reboot +89 32 readdir sys_old_readdir compat_sys_old_readdir +89 64 readdir sys_ni_syscall +89 spu readdir sys_ni_syscall +90 common mmap sys_mmap +91 common munmap sys_munmap +92 common truncate sys_truncate compat_sys_truncate +93 common ftruncate sys_ftruncate compat_sys_ftruncate +94 common fchmod sys_fchmod +95 common fchown sys_fchown +96 common getpriority sys_getpriority +97 common setpriority sys_setpriority +98 common profil sys_ni_syscall +99 nospu statfs sys_statfs compat_sys_statfs +100 nospu fstatfs sys_fstatfs compat_sys_fstatfs +101 common ioperm sys_ni_syscall +102 common socketcall sys_socketcall compat_sys_socketcall +103 common syslog sys_syslog +104 common setitimer sys_setitimer compat_sys_setitimer +105 common getitimer sys_getitimer compat_sys_getitimer +106 common stat sys_newstat compat_sys_newstat +107 common lstat sys_newlstat compat_sys_newlstat +108 common fstat sys_newfstat compat_sys_newfstat +109 32 olduname sys_uname +109 64 olduname sys_ni_syscall +109 spu olduname sys_ni_syscall +110 common iopl sys_ni_syscall +111 common vhangup sys_vhangup +112 common idle sys_ni_syscall +113 common vm86 sys_ni_syscall +114 common wait4 sys_wait4 compat_sys_wait4 +115 nospu swapoff sys_swapoff +116 common sysinfo sys_sysinfo compat_sys_sysinfo +117 nospu ipc sys_ipc compat_sys_ipc +118 common fsync sys_fsync +119 32 sigreturn sys_sigreturn compat_sys_sigreturn +119 64 sigreturn sys_ni_syscall +119 spu sigreturn sys_ni_syscall +120 nospu clone ppc_clone +121 common setdomainname sys_setdomainname +122 common uname sys_newuname +123 common modify_ldt sys_ni_syscall +124 common adjtimex sys_adjtimex compat_sys_adjtimex +125 common mprotect sys_mprotect +126 32 sigprocmask sys_sigprocmask compat_sys_sigprocmask +126 64 sigprocmask sys_ni_syscall +126 spu sigprocmask sys_ni_syscall +127 common create_module sys_ni_syscall +128 nospu init_module sys_init_module +129 nospu delete_module sys_delete_module +130 common get_kernel_syms sys_ni_syscall +131 nospu quotactl sys_quotactl +132 common getpgid sys_getpgid +133 common fchdir sys_fchdir +134 common bdflush sys_bdflush +135 common sysfs sys_sysfs +136 32 personality sys_personality ppc64_personality +136 64 personality ppc64_personality +136 spu personality ppc64_personality +137 common afs_syscall sys_ni_syscall +138 common setfsuid sys_setfsuid +139 common setfsgid sys_setfsgid +140 common _llseek sys_llseek +141 common getdents sys_getdents compat_sys_getdents +142 common _newselect sys_select compat_sys_select +143 common flock sys_flock +144 common msync sys_msync +145 common readv sys_readv compat_sys_readv +146 common writev sys_writev compat_sys_writev +147 common getsid sys_getsid +148 common fdatasync sys_fdatasync +149 nospu _sysctl sys_sysctl compat_sys_sysctl +150 common mlock sys_mlock +151 common munlock sys_munlock +152 common mlockall sys_mlockall +153 common munlockall sys_munlockall +154 common sched_setparam sys_sched_setparam +155 common sched_getparam sys_sched_getparam +156 common sched_setscheduler sys_sched_setscheduler +157 common sched_getscheduler sys_sched_getscheduler +158 common sched_yield sys_sched_yield +159 common sched_get_priority_max sys_sched_get_priority_max +160 common sched_get_priority_min sys_sched_get_priority_min +161 common sched_rr_get_interval sys_sched_rr_get_interval compat_sys_sched_rr_get_interval +162 common nanosleep sys_nanosleep compat_sys_nanosleep +163 common mremap sys_mremap +164 common setresuid sys_setresuid +165 common getresuid sys_getresuid +166 common query_module sys_ni_syscall +167 common poll sys_poll +168 common nfsservctl sys_ni_syscall +169 common setresgid sys_setresgid +170 common getresgid sys_getresgid +171 common prctl sys_prctl +172 nospu rt_sigreturn sys_rt_sigreturn compat_sys_rt_sigreturn +173 nospu rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction +174 nospu rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask +175 nospu rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending +176 nospu rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait +177 nospu rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo +178 nospu rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend +179 common pread64 sys_pread64 compat_sys_pread64 +180 common pwrite64 sys_pwrite64 compat_sys_pwrite64 +181 common chown sys_chown +182 common getcwd sys_getcwd +183 common capget sys_capget +184 common capset sys_capset +185 nospu sigaltstack sys_sigaltstack compat_sys_sigaltstack +186 32 sendfile sys_sendfile compat_sys_sendfile +186 64 sendfile sys_sendfile64 +186 spu sendfile sys_sendfile64 +187 common getpmsg sys_ni_syscall +188 common putpmsg sys_ni_syscall +189 nospu vfork ppc_vfork +190 common ugetrlimit sys_getrlimit compat_sys_getrlimit +191 common readahead sys_readahead compat_sys_readahead +192 32 mmap2 sys_mmap2 compat_sys_mmap2 +193 32 truncate64 sys_truncate64 compat_sys_truncate64 +194 32 ftruncate64 sys_ftruncate64 compat_sys_ftruncate64 +195 32 stat64 sys_stat64 +196 32 lstat64 sys_lstat64 +197 32 fstat64 sys_fstat64 +198 nospu pciconfig_read sys_pciconfig_read +199 nospu pciconfig_write sys_pciconfig_write +200 nospu pciconfig_iobase sys_pciconfig_iobase +201 common multiplexer sys_ni_syscall +202 common getdents64 sys_getdents64 +203 common pivot_root sys_pivot_root +204 32 fcntl64 sys_fcntl64 compat_sys_fcntl64 +205 common madvise sys_madvise +206 common mincore sys_mincore +207 common gettid sys_gettid +208 common tkill sys_tkill +209 common setxattr sys_setxattr +210 common lsetxattr sys_lsetxattr +211 common fsetxattr sys_fsetxattr +212 common getxattr sys_getxattr +213 common lgetxattr sys_lgetxattr +214 common fgetxattr sys_fgetxattr +215 common listxattr sys_listxattr +216 common llistxattr sys_llistxattr +217 common flistxattr sys_flistxattr +218 common removexattr sys_removexattr +219 common lremovexattr sys_lremovexattr +220 common fremovexattr sys_fremovexattr +221 common futex sys_futex compat_sys_futex +222 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity +223 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity +# 224 unused +225 common tuxcall sys_ni_syscall +226 32 sendfile64 sys_sendfile64 compat_sys_sendfile64 +227 common io_setup sys_io_setup compat_sys_io_setup +228 common io_destroy sys_io_destroy +229 common io_getevents sys_io_getevents compat_sys_io_getevents +230 common io_submit sys_io_submit compat_sys_io_submit +231 common io_cancel sys_io_cancel +232 nospu set_tid_address sys_set_tid_address +233 common fadvise64 sys_fadvise64 ppc32_fadvise64 +234 nospu exit_group sys_exit_group +235 nospu lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie +236 common epoll_create sys_epoll_create +237 common epoll_ctl sys_epoll_ctl +238 common epoll_wait sys_epoll_wait +239 common remap_file_pages sys_remap_file_pages +240 common timer_create sys_timer_create compat_sys_timer_create +241 common timer_settime sys_timer_settime compat_sys_timer_settime +242 common timer_gettime sys_timer_gettime compat_sys_timer_gettime +243 common timer_getoverrun sys_timer_getoverrun +244 common timer_delete sys_timer_delete +245 common clock_settime sys_clock_settime compat_sys_clock_settime +246 common clock_gettime sys_clock_gettime compat_sys_clock_gettime +247 common clock_getres sys_clock_getres compat_sys_clock_getres +248 common clock_nanosleep sys_clock_nanosleep compat_sys_clock_nanosleep +249 32 swapcontext ppc_swapcontext ppc32_swapcontext +249 64 swapcontext ppc64_swapcontext +249 spu swapcontext sys_ni_syscall +250 common tgkill sys_tgkill +251 common utimes sys_utimes compat_sys_utimes +252 common statfs64 sys_statfs64 compat_sys_statfs64 +253 common fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 +254 32 fadvise64_64 ppc_fadvise64_64 +254 spu fadvise64_64 sys_ni_syscall +255 common rtas sys_rtas +256 32 sys_debug_setcontext sys_debug_setcontext sys_ni_syscall +256 64 sys_debug_setcontext sys_ni_syscall +256 spu sys_debug_setcontext sys_ni_syscall +# 257 reserved for vserver +258 nospu migrate_pages sys_migrate_pages compat_sys_migrate_pages +259 nospu mbind sys_mbind compat_sys_mbind +260 nospu get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy +261 nospu set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy +262 nospu mq_open sys_mq_open compat_sys_mq_open +263 nospu mq_unlink sys_mq_unlink +264 nospu mq_timedsend sys_mq_timedsend compat_sys_mq_timedsend +265 nospu mq_timedreceive sys_mq_timedreceive compat_sys_mq_timedreceive +266 nospu mq_notify sys_mq_notify compat_sys_mq_notify +267 nospu mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr +268 nospu kexec_load sys_kexec_load compat_sys_kexec_load +269 nospu add_key sys_add_key +270 nospu request_key sys_request_key +271 nospu keyctl sys_keyctl compat_sys_keyctl +272 nospu waitid sys_waitid compat_sys_waitid +273 nospu ioprio_set sys_ioprio_set +274 nospu ioprio_get sys_ioprio_get +275 nospu inotify_init sys_inotify_init +276 nospu inotify_add_watch sys_inotify_add_watch +277 nospu inotify_rm_watch sys_inotify_rm_watch +278 nospu spu_run sys_spu_run +279 nospu spu_create sys_spu_create +280 nospu pselect6 sys_pselect6 compat_sys_pselect6 +281 nospu ppoll sys_ppoll compat_sys_ppoll +282 common unshare sys_unshare +283 common splice sys_splice +284 common tee sys_tee +285 common vmsplice sys_vmsplice compat_sys_vmsplice +286 common openat sys_openat compat_sys_openat +287 common mkdirat sys_mkdirat +288 common mknodat sys_mknodat +289 common fchownat sys_fchownat +290 common futimesat sys_futimesat compat_sys_futimesat +291 32 fstatat64 sys_fstatat64 +291 64 newfstatat sys_newfstatat +291 spu newfstatat sys_newfstatat +292 common unlinkat sys_unlinkat +293 common renameat sys_renameat +294 common linkat sys_linkat +295 common symlinkat sys_symlinkat +296 common readlinkat sys_readlinkat +297 common fchmodat sys_fchmodat +298 common faccessat sys_faccessat +299 common get_robust_list sys_get_robust_list compat_sys_get_robust_list +300 common set_robust_list sys_set_robust_list compat_sys_set_robust_list +301 common move_pages sys_move_pages compat_sys_move_pages +302 common getcpu sys_getcpu +303 nospu epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait +304 common utimensat sys_utimensat compat_sys_utimensat +305 common signalfd sys_signalfd compat_sys_signalfd +306 common timerfd_create sys_timerfd_create +307 common eventfd sys_eventfd +308 common sync_file_range2 sys_sync_file_range2 compat_sys_sync_file_range2 +309 nospu fallocate sys_fallocate compat_sys_fallocate +310 nospu subpage_prot sys_subpage_prot +311 common timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime +312 common timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime +313 common signalfd4 sys_signalfd4 compat_sys_signalfd4 +314 common eventfd2 sys_eventfd2 +315 common epoll_create1 sys_epoll_create1 +316 common dup3 sys_dup3 +317 common pipe2 sys_pipe2 +318 nospu inotify_init1 sys_inotify_init1 +319 common perf_event_open sys_perf_event_open +320 common preadv sys_preadv compat_sys_preadv +321 common pwritev sys_pwritev compat_sys_pwritev +322 nospu rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo +323 nospu fanotify_init sys_fanotify_init +324 nospu fanotify_mark sys_fanotify_mark compat_sys_fanotify_mark +325 common prlimit64 sys_prlimit64 +326 common socket sys_socket +327 common bind sys_bind +328 common connect sys_connect +329 common listen sys_listen +330 common accept sys_accept +331 common getsockname sys_getsockname +332 common getpeername sys_getpeername +333 common socketpair sys_socketpair +334 common send sys_send +335 common sendto sys_sendto +336 common recv sys_recv compat_sys_recv +337 common recvfrom sys_recvfrom compat_sys_recvfrom +338 common shutdown sys_shutdown +339 common setsockopt sys_setsockopt compat_sys_setsockopt +340 common getsockopt sys_getsockopt compat_sys_getsockopt +341 common sendmsg sys_sendmsg compat_sys_sendmsg +342 common recvmsg sys_recvmsg compat_sys_recvmsg +343 common recvmmsg sys_recvmmsg compat_sys_recvmmsg +344 common accept4 sys_accept4 +345 common name_to_handle_at sys_name_to_handle_at +346 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at +347 common clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime +348 common syncfs sys_syncfs +349 common sendmmsg sys_sendmmsg compat_sys_sendmmsg +350 common setns sys_setns +351 nospu process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv +352 nospu process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev +353 nospu finit_module sys_finit_module +354 nospu kcmp sys_kcmp +355 common sched_setattr sys_sched_setattr +356 common sched_getattr sys_sched_getattr +357 common renameat2 sys_renameat2 +358 common seccomp sys_seccomp +359 common getrandom sys_getrandom +360 common memfd_create sys_memfd_create +361 common bpf sys_bpf +362 nospu execveat sys_execveat compat_sys_execveat +363 32 switch_endian sys_ni_syscall +363 64 switch_endian ppc_switch_endian +363 spu switch_endian sys_ni_syscall +364 common userfaultfd sys_userfaultfd +365 common membarrier sys_membarrier +378 nospu mlock2 sys_mlock2 +379 nospu copy_file_range sys_copy_file_range +380 common preadv2 sys_preadv2 compat_sys_preadv2 +381 common pwritev2 sys_pwritev2 compat_sys_pwritev2 +382 nospu kexec_file_load sys_kexec_file_load +383 nospu statx sys_statx +384 nospu pkey_alloc sys_pkey_alloc +385 nospu pkey_free sys_pkey_free +386 nospu pkey_mprotect sys_pkey_mprotect +387 nospu rseq sys_rseq +388 nospu io_pgetevents sys_io_pgetevents compat_sys_io_pgetevents -- cgit v1.2.3-58-ga151 From 8f9c469348487844328e162db57112f7d347c49f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 16 Dec 2018 23:23:22 -0800 Subject: crypto: authenc - fix parsing key with misaligned rta_len Keys for "authenc" AEADs are formatted as an rtattr containing a 4-byte 'enckeylen', followed by an authentication key and an encryption key. crypto_authenc_extractkeys() parses the key to find the inner keys. However, it fails to consider the case where the rtattr's payload is longer than 4 bytes but not 4-byte aligned, and where the key ends before the next 4-byte aligned boundary. In this case, 'keylen -= RTA_ALIGN(rta->rta_len);' underflows to a value near UINT_MAX. This causes a buffer overread and crash during crypto_ahash_setkey(). Fix it by restricting the rtattr payload to the expected size. Reproducer using AF_ALG: #include #include #include int main() { int fd; struct sockaddr_alg addr = { .salg_type = "aead", .salg_name = "authenc(hmac(sha256),cbc(aes))", }; struct { struct rtattr attr; __be32 enckeylen; char keys[1]; } __attribute__((packed)) key = { .attr.rta_len = sizeof(key), .attr.rta_type = 1 /* CRYPTO_AUTHENC_KEYA_PARAM */, }; fd = socket(AF_ALG, SOCK_SEQPACKET, 0); bind(fd, (void *)&addr, sizeof(addr)); setsockopt(fd, SOL_ALG, ALG_SET_KEY, &key, sizeof(key)); } It caused: BUG: unable to handle kernel paging request at ffff88007ffdc000 PGD 2e01067 P4D 2e01067 PUD 2e04067 PMD 2e05067 PTE 0 Oops: 0000 [#1] SMP CPU: 0 PID: 883 Comm: authenc Not tainted 4.20.0-rc1-00108-g00c9fe37a7f27 #13 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-20181126_142135-anatol 04/01/2014 RIP: 0010:sha256_ni_transform+0xb3/0x330 arch/x86/crypto/sha256_ni_asm.S:155 [...] Call Trace: sha256_ni_finup+0x10/0x20 arch/x86/crypto/sha256_ssse3_glue.c:321 crypto_shash_finup+0x1a/0x30 crypto/shash.c:178 shash_digest_unaligned+0x45/0x60 crypto/shash.c:186 crypto_shash_digest+0x24/0x40 crypto/shash.c:202 hmac_setkey+0x135/0x1e0 crypto/hmac.c:66 crypto_shash_setkey+0x2b/0xb0 crypto/shash.c:66 shash_async_setkey+0x10/0x20 crypto/shash.c:223 crypto_ahash_setkey+0x2d/0xa0 crypto/ahash.c:202 crypto_authenc_setkey+0x68/0x100 crypto/authenc.c:96 crypto_aead_setkey+0x2a/0xc0 crypto/aead.c:62 aead_setkey+0xc/0x10 crypto/algif_aead.c:526 alg_setkey crypto/af_alg.c:223 [inline] alg_setsockopt+0xfe/0x130 crypto/af_alg.c:256 __sys_setsockopt+0x6d/0xd0 net/socket.c:1902 __do_sys_setsockopt net/socket.c:1913 [inline] __se_sys_setsockopt net/socket.c:1910 [inline] __x64_sys_setsockopt+0x1f/0x30 net/socket.c:1910 do_syscall_64+0x4a/0x180 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe Fixes: e236d4a89a2f ("[CRYPTO] authenc: Move enckeylen into key itself") Cc: # v2.6.25+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/authenc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/crypto/authenc.c b/crypto/authenc.c index 37f54d1b2f66..4be293a4b5f0 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -58,14 +58,22 @@ int crypto_authenc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key, return -EINVAL; if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) return -EINVAL; - if (RTA_PAYLOAD(rta) < sizeof(*param)) + + /* + * RTA_OK() didn't align the rtattr's payload when validating that it + * fits in the buffer. Yet, the keys should start on the next 4-byte + * aligned boundary. To avoid confusion, require that the rtattr + * payload be exactly the param struct, which has a 4-byte aligned size. + */ + if (RTA_PAYLOAD(rta) != sizeof(*param)) return -EINVAL; + BUILD_BUG_ON(sizeof(*param) % RTA_ALIGNTO); param = RTA_DATA(rta); keys->enckeylen = be32_to_cpu(param->enckeylen); - key += RTA_ALIGN(rta->rta_len); - keylen -= RTA_ALIGN(rta->rta_len); + key += rta->rta_len; + keylen -= rta->rta_len; if (keylen < keys->enckeylen) return -EINVAL; -- cgit v1.2.3-58-ga151 From ab57b33525c3221afaebd391458fa0cbcd56903d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 16 Dec 2018 23:23:23 -0800 Subject: crypto: bcm - convert to use crypto_authenc_extractkeys() Convert the bcm crypto driver to use crypto_authenc_extractkeys() so that it picks up the fix for broken validation of rtattr::rta_len. This also fixes the DES weak key check to actually be done on the right key. (It was checking the authentication key, not the encryption key...) Fixes: 9d12ba86f818 ("crypto: brcm - Add Broadcom SPU driver") Cc: # v4.11+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 1 + drivers/crypto/bcm/cipher.c | 44 +++++++++++++------------------------------- 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 5a90075f719d..0be55fcc19ba 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -692,6 +692,7 @@ config CRYPTO_DEV_BCM_SPU depends on ARCH_BCM_IPROC depends on MAILBOX default m + select CRYPTO_AUTHENC select CRYPTO_DES select CRYPTO_MD5 select CRYPTO_SHA1 diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index c9393ffb70ed..5567cbda2798 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -2845,44 +2845,28 @@ static int aead_authenc_setkey(struct crypto_aead *cipher, struct spu_hw *spu = &iproc_priv.spu; struct iproc_ctx_s *ctx = crypto_aead_ctx(cipher); struct crypto_tfm *tfm = crypto_aead_tfm(cipher); - struct rtattr *rta = (void *)key; - struct crypto_authenc_key_param *param; - const u8 *origkey = key; - const unsigned int origkeylen = keylen; - - int ret = 0; + struct crypto_authenc_keys keys; + int ret; flow_log("%s() aead:%p key:%p keylen:%u\n", __func__, cipher, key, keylen); flow_dump(" key: ", key, keylen); - if (!RTA_OK(rta, keylen)) - goto badkey; - if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) - goto badkey; - if (RTA_PAYLOAD(rta) < sizeof(*param)) + ret = crypto_authenc_extractkeys(&keys, key, keylen); + if (ret) goto badkey; - param = RTA_DATA(rta); - ctx->enckeylen = be32_to_cpu(param->enckeylen); - - key += RTA_ALIGN(rta->rta_len); - keylen -= RTA_ALIGN(rta->rta_len); - - if (keylen < ctx->enckeylen) - goto badkey; - if (ctx->enckeylen > MAX_KEY_SIZE) + if (keys.enckeylen > MAX_KEY_SIZE || + keys.authkeylen > MAX_KEY_SIZE) goto badkey; - ctx->authkeylen = keylen - ctx->enckeylen; - - if (ctx->authkeylen > MAX_KEY_SIZE) - goto badkey; + ctx->enckeylen = keys.enckeylen; + ctx->authkeylen = keys.authkeylen; - memcpy(ctx->enckey, key + ctx->authkeylen, ctx->enckeylen); + memcpy(ctx->enckey, keys.enckey, keys.enckeylen); /* May end up padding auth key. So make sure it's zeroed. */ memset(ctx->authkey, 0, sizeof(ctx->authkey)); - memcpy(ctx->authkey, key, ctx->authkeylen); + memcpy(ctx->authkey, keys.authkey, keys.authkeylen); switch (ctx->alg->cipher_info.alg) { case CIPHER_ALG_DES: @@ -2890,7 +2874,7 @@ static int aead_authenc_setkey(struct crypto_aead *cipher, u32 tmp[DES_EXPKEY_WORDS]; u32 flags = CRYPTO_TFM_RES_WEAK_KEY; - if (des_ekey(tmp, key) == 0) { + if (des_ekey(tmp, keys.enckey) == 0) { if (crypto_aead_get_flags(cipher) & CRYPTO_TFM_REQ_WEAK_KEY) { crypto_aead_set_flags(cipher, flags); @@ -2905,7 +2889,7 @@ static int aead_authenc_setkey(struct crypto_aead *cipher, break; case CIPHER_ALG_3DES: if (ctx->enckeylen == (DES_KEY_SIZE * 3)) { - const u32 *K = (const u32 *)key; + const u32 *K = (const u32 *)keys.enckey; u32 flags = CRYPTO_TFM_RES_BAD_KEY_SCHED; if (!((K[0] ^ K[2]) | (K[1] ^ K[3])) || @@ -2956,9 +2940,7 @@ static int aead_authenc_setkey(struct crypto_aead *cipher, ctx->fallback_cipher->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; ctx->fallback_cipher->base.crt_flags |= tfm->crt_flags & CRYPTO_TFM_REQ_MASK; - ret = - crypto_aead_setkey(ctx->fallback_cipher, origkey, - origkeylen); + ret = crypto_aead_setkey(ctx->fallback_cipher, key, keylen); if (ret) { flow_log(" fallback setkey() returned:%d\n", ret); tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; -- cgit v1.2.3-58-ga151 From dc95b5350a8f07d73d6bde3a79ef87289698451d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 16 Dec 2018 23:23:24 -0800 Subject: crypto: ccree - convert to use crypto_authenc_extractkeys() Convert the ccree crypto driver to use crypto_authenc_extractkeys() so that it picks up the fix for broken validation of rtattr::rta_len. Fixes: ff27e85a85bb ("crypto: ccree - add AEAD support") Cc: # v4.17+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- drivers/crypto/ccree/cc_aead.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/crypto/ccree/cc_aead.c b/drivers/crypto/ccree/cc_aead.c index f2643cda45db..a3527c00b29a 100644 --- a/drivers/crypto/ccree/cc_aead.c +++ b/drivers/crypto/ccree/cc_aead.c @@ -549,13 +549,12 @@ static int cc_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct rtattr *rta = (struct rtattr *)key; struct cc_crypto_req cc_req = {}; - struct crypto_authenc_key_param *param; struct cc_hw_desc desc[MAX_AEAD_SETKEY_SEQ]; - int rc = -EINVAL; unsigned int seq_len = 0; struct device *dev = drvdata_to_dev(ctx->drvdata); + const u8 *enckey, *authkey; + int rc; dev_dbg(dev, "Setting key in context @%p for %s. key=%p keylen=%u\n", ctx, crypto_tfm_alg_name(crypto_aead_tfm(tfm)), key, keylen); @@ -563,35 +562,33 @@ static int cc_aead_setkey(struct crypto_aead *tfm, const u8 *key, /* STAT_PHASE_0: Init and sanity checks */ if (ctx->auth_mode != DRV_HASH_NULL) { /* authenc() alg. */ - if (!RTA_OK(rta, keylen)) - goto badkey; - if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) - goto badkey; - if (RTA_PAYLOAD(rta) < sizeof(*param)) - goto badkey; - param = RTA_DATA(rta); - ctx->enc_keylen = be32_to_cpu(param->enckeylen); - key += RTA_ALIGN(rta->rta_len); - keylen -= RTA_ALIGN(rta->rta_len); - if (keylen < ctx->enc_keylen) + struct crypto_authenc_keys keys; + + rc = crypto_authenc_extractkeys(&keys, key, keylen); + if (rc) goto badkey; - ctx->auth_keylen = keylen - ctx->enc_keylen; + enckey = keys.enckey; + authkey = keys.authkey; + ctx->enc_keylen = keys.enckeylen; + ctx->auth_keylen = keys.authkeylen; if (ctx->cipher_mode == DRV_CIPHER_CTR) { /* the nonce is stored in bytes at end of key */ + rc = -EINVAL; if (ctx->enc_keylen < (AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE)) goto badkey; /* Copy nonce from last 4 bytes in CTR key to * first 4 bytes in CTR IV */ - memcpy(ctx->ctr_nonce, key + ctx->auth_keylen + - ctx->enc_keylen - CTR_RFC3686_NONCE_SIZE, - CTR_RFC3686_NONCE_SIZE); + memcpy(ctx->ctr_nonce, enckey + ctx->enc_keylen - + CTR_RFC3686_NONCE_SIZE, CTR_RFC3686_NONCE_SIZE); /* Set CTR key size */ ctx->enc_keylen -= CTR_RFC3686_NONCE_SIZE; } } else { /* non-authenc - has just one key */ + enckey = key; + authkey = NULL; ctx->enc_keylen = keylen; ctx->auth_keylen = 0; } @@ -603,13 +600,14 @@ static int cc_aead_setkey(struct crypto_aead *tfm, const u8 *key, /* STAT_PHASE_1: Copy key to ctx */ /* Get key material */ - memcpy(ctx->enckey, key + ctx->auth_keylen, ctx->enc_keylen); + memcpy(ctx->enckey, enckey, ctx->enc_keylen); if (ctx->enc_keylen == 24) memset(ctx->enckey + 24, 0, CC_AES_KEY_SIZE_MAX - 24); if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { - memcpy(ctx->auth_state.xcbc.xcbc_keys, key, ctx->auth_keylen); + memcpy(ctx->auth_state.xcbc.xcbc_keys, authkey, + ctx->auth_keylen); } else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC */ - rc = cc_get_plain_hmac_key(tfm, key, ctx->auth_keylen); + rc = cc_get_plain_hmac_key(tfm, authkey, ctx->auth_keylen); if (rc) goto badkey; } -- cgit v1.2.3-58-ga151 From 04e6d25c5bb244c1a37eb9fe0b604cc11a04e8c5 Mon Sep 17 00:00:00 2001 From: Aymen Sghaier Date: Wed, 19 Dec 2018 16:36:44 +0200 Subject: crypto: caam - fix zero-length buffer DMA mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent changes - probably DMA API related (generic and/or arm64-specific) - exposed a case where driver maps a zero-length buffer: ahash_init()->ahash_update()->ahash_final() with a zero-length string to hash kernel BUG at kernel/dma/swiotlb.c:475! Internal error: Oops - BUG: 0 [#1] PREEMPT SMP Modules linked in: CPU: 2 PID: 1823 Comm: cryptomgr_test Not tainted 4.20.0-rc1-00108-g00c9fe37a7f2 #1 Hardware name: LS1046A RDB Board (DT) pstate: 80000005 (Nzcv daif -PAN -UAO) pc : swiotlb_tbl_map_single+0x170/0x2b8 lr : swiotlb_map_page+0x134/0x1f8 sp : ffff00000f79b8f0 x29: ffff00000f79b8f0 x28: 0000000000000000 x27: ffff0000093d0000 x26: 0000000000000000 x25: 00000000001f3ffe x24: 0000000000200000 x23: 0000000000000000 x22: 00000009f2c538c0 x21: ffff800970aeb410 x20: 0000000000000001 x19: ffff800970aeb410 x18: 0000000000000007 x17: 000000000000000e x16: 0000000000000001 x15: 0000000000000019 x14: c32cb8218a167fe8 x13: ffffffff00000000 x12: ffff80097fdae348 x11: 0000800976bca000 x10: 0000000000000010 x9 : 0000000000000000 x8 : ffff0000091fd6c8 x7 : 0000000000000000 x6 : 00000009f2c538bf x5 : 0000000000000000 x4 : 0000000000000001 x3 : 0000000000000000 x2 : 00000009f2c538c0 x1 : 00000000f9fff000 x0 : 0000000000000000 Process cryptomgr_test (pid: 1823, stack limit = 0x(____ptrval____)) Call trace: swiotlb_tbl_map_single+0x170/0x2b8 swiotlb_map_page+0x134/0x1f8 ahash_final_no_ctx+0xc4/0x6cc ahash_final+0x10/0x18 crypto_ahash_op+0x30/0x84 crypto_ahash_final+0x14/0x1c __test_hash+0x574/0xe0c test_hash+0x28/0x80 __alg_test_hash+0x84/0xd0 alg_test_hash+0x78/0x144 alg_test.part.30+0x12c/0x2b4 alg_test+0x3c/0x68 cryptomgr_test+0x44/0x4c kthread+0xfc/0x128 ret_from_fork+0x10/0x18 Code: d34bfc18 2a1a03f7 1a9f8694 35fff89a (d4210000) Cc: Signed-off-by: Aymen Sghaier Signed-off-by: Horia Geantă Reviewed-by: Christoph Hellwig Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 81712aa5d0f2..bb1a2cdf1951 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -1072,13 +1072,16 @@ static int ahash_final_no_ctx(struct ahash_request *req) desc = edesc->hw_desc; - state->buf_dma = dma_map_single(jrdev, buf, buflen, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, state->buf_dma)) { - dev_err(jrdev, "unable to map src\n"); - goto unmap; - } + if (buflen) { + state->buf_dma = dma_map_single(jrdev, buf, buflen, + DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, state->buf_dma)) { + dev_err(jrdev, "unable to map src\n"); + goto unmap; + } - append_seq_in_ptr(desc, state->buf_dma, buflen, 0); + append_seq_in_ptr(desc, state->buf_dma, buflen, 0); + } edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, digestsize); -- cgit v1.2.3-58-ga151 From 2dd3fde41bf3dc68e38de23da87e72a07719b708 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Fri, 21 Dec 2018 14:47:46 +0200 Subject: crypto: caam - fix SHA support detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The addition of Chacha20 + Poly1305 authenc support inadvertently broke detection of algorithms supported by MDHA (Message Digest Hardware Accelerator), fix it. Fixes: d6bbd4eea243 ("crypto: caam/jr - add support for Chacha20 + Poly1305") Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 2 +- drivers/crypto/caam/desc.h | 1 + drivers/crypto/caam/error.h | 9 +++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 92e593e2069a..80ae69f906fb 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -3476,7 +3476,7 @@ static int __init caam_algapi_init(void) * Skip algorithms requiring message digests * if MD or MD size is not supported by device. */ - if ((c2_alg_sel & ~OP_ALG_ALGSEL_SUBMASK) == 0x40 && + if (is_mdha(c2_alg_sel) && (!md_inst || t_alg->aead.maxauthsize > md_limit)) continue; diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h index ec10230178c5..4b6854bf896a 100644 --- a/drivers/crypto/caam/desc.h +++ b/drivers/crypto/caam/desc.h @@ -1155,6 +1155,7 @@ #define OP_ALG_ALGSEL_DES (0x20 << OP_ALG_ALGSEL_SHIFT) #define OP_ALG_ALGSEL_3DES (0x21 << OP_ALG_ALGSEL_SHIFT) #define OP_ALG_ALGSEL_ARC4 (0x30 << OP_ALG_ALGSEL_SHIFT) +#define OP_ALG_CHA_MDHA (0x40 << OP_ALG_ALGSEL_SHIFT) #define OP_ALG_ALGSEL_MD5 (0x40 << OP_ALG_ALGSEL_SHIFT) #define OP_ALG_ALGSEL_SHA1 (0x41 << OP_ALG_ALGSEL_SHIFT) #define OP_ALG_ALGSEL_SHA224 (0x42 << OP_ALG_ALGSEL_SHIFT) diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h index 67ea94079837..8c6b83e02a70 100644 --- a/drivers/crypto/caam/error.h +++ b/drivers/crypto/caam/error.h @@ -7,6 +7,9 @@ #ifndef CAAM_ERROR_H #define CAAM_ERROR_H + +#include "desc.h" + #define CAAM_ERROR_STR_MAX 302 void caam_strstatus(struct device *dev, u32 status, bool qi_v2); @@ -17,4 +20,10 @@ void caam_strstatus(struct device *dev, u32 status, bool qi_v2); void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, int rowsize, int groupsize, struct scatterlist *sg, size_t tlen, bool ascii); + +static inline bool is_mdha(u32 algtype) +{ + return (algtype & OP_ALG_ALGSEL_MASK & ~OP_ALG_ALGSEL_SUBMASK) == + OP_ALG_CHA_MDHA; +} #endif /* CAAM_ERROR_H */ -- cgit v1.2.3-58-ga151 From a7773363624b034ab198c738661253d20a8055c2 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Thu, 3 Jan 2019 14:21:05 +0530 Subject: crypto: authencesn - Avoid twice completion call in decrypt path Authencesn template in decrypt path unconditionally calls aead_request_complete after ahash_verify which leads to following kernel panic in after decryption. [ 338.539800] BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 [ 338.548372] PGD 0 P4D 0 [ 338.551157] Oops: 0000 [#1] SMP PTI [ 338.554919] CPU: 0 PID: 0 Comm: swapper/0 Kdump: loaded Tainted: G W I 4.19.7+ #13 [ 338.564431] Hardware name: Supermicro X8ST3/X8ST3, BIOS 2.0 07/29/10 [ 338.572212] RIP: 0010:esp_input_done2+0x350/0x410 [esp4] [ 338.578030] Code: ff 0f b6 68 10 48 8b 83 c8 00 00 00 e9 8e fe ff ff 8b 04 25 04 00 00 00 83 e8 01 48 98 48 8b 3c c5 10 00 00 00 e9 f7 fd ff ff <8b> 04 25 04 00 00 00 83 e8 01 48 98 4c 8b 24 c5 10 00 00 00 e9 3b [ 338.598547] RSP: 0018:ffff911c97803c00 EFLAGS: 00010246 [ 338.604268] RAX: 0000000000000002 RBX: ffff911c4469ee00 RCX: 0000000000000000 [ 338.612090] RDX: 0000000000000000 RSI: 0000000000000130 RDI: ffff911b87c20400 [ 338.619874] RBP: 0000000000000000 R08: ffff911b87c20498 R09: 000000000000000a [ 338.627610] R10: 0000000000000001 R11: 0000000000000004 R12: 0000000000000000 [ 338.635402] R13: ffff911c89590000 R14: ffff911c91730000 R15: 0000000000000000 [ 338.643234] FS: 0000000000000000(0000) GS:ffff911c97800000(0000) knlGS:0000000000000000 [ 338.652047] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 338.658299] CR2: 0000000000000004 CR3: 00000001ec20a000 CR4: 00000000000006f0 [ 338.666382] Call Trace: [ 338.669051] [ 338.671254] esp_input_done+0x12/0x20 [esp4] [ 338.675922] chcr_handle_resp+0x3b5/0x790 [chcr] [ 338.680949] cpl_fw6_pld_handler+0x37/0x60 [chcr] [ 338.686080] chcr_uld_rx_handler+0x22/0x50 [chcr] [ 338.691233] uldrx_handler+0x8c/0xc0 [cxgb4] [ 338.695923] process_responses+0x2f0/0x5d0 [cxgb4] [ 338.701177] ? bitmap_find_next_zero_area_off+0x3a/0x90 [ 338.706882] ? matrix_alloc_area.constprop.7+0x60/0x90 [ 338.712517] ? apic_update_irq_cfg+0x82/0xf0 [ 338.717177] napi_rx_handler+0x14/0xe0 [cxgb4] [ 338.722015] net_rx_action+0x2aa/0x3e0 [ 338.726136] __do_softirq+0xcb/0x280 [ 338.730054] irq_exit+0xde/0xf0 [ 338.733504] do_IRQ+0x54/0xd0 [ 338.736745] common_interrupt+0xf/0xf Fixes: 104880a6b470 ("crypto: authencesn - Convert to new AEAD...") Signed-off-by: Harsh Jain Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/authencesn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 80a25cc04aec..4741fe89ba2c 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -279,7 +279,7 @@ static void authenc_esn_verify_ahash_done(struct crypto_async_request *areq, struct aead_request *req = areq->data; err = err ?: crypto_authenc_esn_decrypt_tail(req, 0); - aead_request_complete(req, err); + authenc_esn_request_complete(req, err); } static int crypto_authenc_esn_decrypt(struct aead_request *req) -- cgit v1.2.3-58-ga151 From 06bbf753476dab23eb262cb5fbab6d6d277a0ba3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Jan 2019 09:46:11 +0300 Subject: crypto: cavium/nitrox - Use after free in process_response_list() We free "sr" and then dereference it on the next line. Fixes: c9613335bf4f ("crypto: cavium/nitrox - Added AEAD cipher support") Signed-off-by: Dan Carpenter Signed-off-by: Herbert Xu --- drivers/crypto/cavium/nitrox/nitrox_reqmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c index e34e4df8fd24..fe070d75c842 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c @@ -567,10 +567,10 @@ static void process_response_list(struct nitrox_cmdq *cmdq) /* ORH error code */ err = READ_ONCE(*sr->resp.orh) & 0xff; - softreq_destroy(sr); if (sr->callback) sr->callback(sr->cb_arg, err); + softreq_destroy(sr); req_completed++; } -- cgit v1.2.3-58-ga151 From 6db43410179bc40419a9859ebb333f178a49829d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 6 Jan 2019 12:46:05 -0800 Subject: crypto: adiantum - initialize crypto_spawn::inst crypto_grab_*() doesn't set crypto_spawn::inst, so templates must set it beforehand. Otherwise it will be left NULL, which causes a crash in certain cases where algorithms are dynamically loaded/unloaded. E.g. with CONFIG_CRYPTO_CHACHA20_X86_64=m, the following caused a crash: insmod chacha-x86_64.ko python -c 'import socket; socket.socket(socket.AF_ALG, 5, 0).bind(("skcipher", "adiantum(xchacha12,aes)"))' rmmod chacha-x86_64.ko python -c 'import socket; socket.socket(socket.AF_ALG, 5, 0).bind(("skcipher", "adiantum(xchacha12,aes)"))' Fixes: 059c2a4d8e16 ("crypto: adiantum - add Adiantum support") Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/adiantum.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/adiantum.c b/crypto/adiantum.c index 6651e713c45d..5564e73266a6 100644 --- a/crypto/adiantum.c +++ b/crypto/adiantum.c @@ -539,6 +539,8 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb) ictx = skcipher_instance_ctx(inst); /* Stream cipher, e.g. "xchacha12" */ + crypto_set_skcipher_spawn(&ictx->streamcipher_spawn, + skcipher_crypto_instance(inst)); err = crypto_grab_skcipher(&ictx->streamcipher_spawn, streamcipher_name, 0, crypto_requires_sync(algt->type, algt->mask)); @@ -547,6 +549,8 @@ static int adiantum_create(struct crypto_template *tmpl, struct rtattr **tb) streamcipher_alg = crypto_spawn_skcipher_alg(&ictx->streamcipher_spawn); /* Block cipher, e.g. "aes" */ + crypto_set_spawn(&ictx->blockcipher_spawn, + skcipher_crypto_instance(inst)); err = crypto_grab_spawn(&ictx->blockcipher_spawn, blockcipher_name, CRYPTO_ALG_TYPE_CIPHER, CRYPTO_ALG_TYPE_MASK); if (err) -- cgit v1.2.3-58-ga151 From c56c2e173773097a248fd3bace91ac8f6fc5386d Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 8 Jan 2019 06:56:46 +0000 Subject: crypto: talitos - reorder code in talitos_edesc_alloc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch moves the mapping of IV after the kmalloc(). This avoids having to unmap in case kmalloc() fails. Signed-off-by: Christophe Leroy Reviewed-by: Horia Geantă Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 45e20707cef8..54d80e7edb86 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1361,23 +1361,18 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, struct talitos_private *priv = dev_get_drvdata(dev); bool is_sec1 = has_ftr_sec1(priv); int max_len = is_sec1 ? TALITOS1_MAX_DATA_LEN : TALITOS2_MAX_DATA_LEN; - void *err; if (cryptlen + authsize > max_len) { dev_err(dev, "length exceeds h/w max limit\n"); return ERR_PTR(-EINVAL); } - if (ivsize) - iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE); - if (!dst || dst == src) { src_len = assoclen + cryptlen + authsize; src_nents = sg_nents_for_len(src, src_len); if (src_nents < 0) { dev_err(dev, "Invalid number of src SG.\n"); - err = ERR_PTR(-EINVAL); - goto error_sg; + return ERR_PTR(-EINVAL); } src_nents = (src_nents == 1) ? 0 : src_nents; dst_nents = dst ? src_nents : 0; @@ -1387,16 +1382,14 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, src_nents = sg_nents_for_len(src, src_len); if (src_nents < 0) { dev_err(dev, "Invalid number of src SG.\n"); - err = ERR_PTR(-EINVAL); - goto error_sg; + return ERR_PTR(-EINVAL); } src_nents = (src_nents == 1) ? 0 : src_nents; dst_len = assoclen + cryptlen + (encrypt ? authsize : 0); dst_nents = sg_nents_for_len(dst, dst_len); if (dst_nents < 0) { dev_err(dev, "Invalid number of dst SG.\n"); - err = ERR_PTR(-EINVAL); - goto error_sg; + return ERR_PTR(-EINVAL); } dst_nents = (dst_nents == 1) ? 0 : dst_nents; } @@ -1425,10 +1418,10 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, alloc_len += sizeof(struct talitos_desc); edesc = kmalloc(alloc_len, GFP_DMA | flags); - if (!edesc) { - err = ERR_PTR(-ENOMEM); - goto error_sg; - } + if (!edesc) + return ERR_PTR(-ENOMEM); + if (ivsize) + iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE); memset(&edesc->desc, 0, sizeof(edesc->desc)); edesc->src_nents = src_nents; @@ -1445,10 +1438,6 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, DMA_BIDIRECTIONAL); } return edesc; -error_sg: - if (iv_dma) - dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); - return err; } static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq, u8 *iv, -- cgit v1.2.3-58-ga151 From 1bea445b0a022ee126ca328b3705cd4df18ebc14 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 8 Jan 2019 06:56:48 +0000 Subject: crypto: talitos - fix ablkcipher for CONFIG_VMAP_STACK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ 2.364486] WARNING: CPU: 0 PID: 60 at ./arch/powerpc/include/asm/io.h:837 dma_nommu_map_page+0x44/0xd4 [ 2.373579] CPU: 0 PID: 60 Comm: cryptomgr_test Tainted: G W 4.20.0-rc5-00560-g6bfb52e23a00-dirty #531 [ 2.384740] NIP: c000c540 LR: c000c584 CTR: 00000000 [ 2.389743] REGS: c95abab0 TRAP: 0700 Tainted: G W (4.20.0-rc5-00560-g6bfb52e23a00-dirty) [ 2.400042] MSR: 00029032 CR: 24042204 XER: 00000000 [ 2.406669] [ 2.406669] GPR00: c02f2244 c95abb60 c6262990 c95abd80 0000256a 00000001 00000001 00000001 [ 2.406669] GPR08: 00000000 00002000 00000010 00000010 24042202 00000000 00000100 c95abd88 [ 2.406669] GPR16: 00000000 c05569d4 00000001 00000010 c95abc88 c0615664 00000004 00000000 [ 2.406669] GPR24: 00000010 c95abc88 c95abc88 00000000 c61ae210 c7ff6d40 c61ae210 00003d68 [ 2.441559] NIP [c000c540] dma_nommu_map_page+0x44/0xd4 [ 2.446720] LR [c000c584] dma_nommu_map_page+0x88/0xd4 [ 2.451762] Call Trace: [ 2.454195] [c95abb60] [82000808] 0x82000808 (unreliable) [ 2.459572] [c95abb80] [c02f2244] talitos_edesc_alloc+0xbc/0x3c8 [ 2.465493] [c95abbb0] [c02f2600] ablkcipher_edesc_alloc+0x4c/0x5c [ 2.471606] [c95abbd0] [c02f4ed0] ablkcipher_encrypt+0x20/0x64 [ 2.477389] [c95abbe0] [c02023b0] __test_skcipher+0x4bc/0xa08 [ 2.483049] [c95abe00] [c0204b60] test_skcipher+0x2c/0xcc [ 2.488385] [c95abe20] [c0204c48] alg_test_skcipher+0x48/0xbc [ 2.494064] [c95abe40] [c0205cec] alg_test+0x164/0x2e8 [ 2.499142] [c95abf00] [c0200dec] cryptomgr_test+0x48/0x50 [ 2.504558] [c95abf10] [c0039ff4] kthread+0xe4/0x110 [ 2.509471] [c95abf40] [c000e1d0] ret_from_kernel_thread+0x14/0x1c [ 2.515532] Instruction dump: [ 2.518468] 7c7e1b78 7c9d2378 7cbf2b78 41820054 3d20c076 8089c200 3d20c076 7c84e850 [ 2.526127] 8129c204 7c842e70 7f844840 419c0008 <0fe00000> 2f9e0000 54847022 7c84fa14 [ 2.533960] ---[ end trace bf78d94af73fe3b8 ]--- [ 2.539123] talitos ff020000.crypto: master data transfer error [ 2.544775] talitos ff020000.crypto: TEA error: ISR 0x20000000_00000040 [ 2.551625] alg: skcipher: encryption failed on test 1 for ecb-aes-talitos: ret=22 IV cannot be on stack when CONFIG_VMAP_STACK is selected because the stack cannot be DMA mapped anymore. This patch copies the IV into the extended descriptor. Fixes: 4de9d0b547b9 ("crypto: talitos - Add ablkcipher algorithms") Cc: stable@vger.kernel.org Signed-off-by: Christophe Leroy Reviewed-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 54d80e7edb86..f8e2c5c3f4eb 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -1416,12 +1416,15 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, /* if its a ahash, add space for a second desc next to the first one */ if (is_sec1 && !dst) alloc_len += sizeof(struct talitos_desc); + alloc_len += ivsize; edesc = kmalloc(alloc_len, GFP_DMA | flags); if (!edesc) return ERR_PTR(-ENOMEM); - if (ivsize) + if (ivsize) { + iv = memcpy(((u8 *)edesc) + alloc_len - ivsize, iv, ivsize); iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE); + } memset(&edesc->desc, 0, sizeof(edesc->desc)); edesc->src_nents = src_nents; -- cgit v1.2.3-58-ga151 From d45a90cb5d061fa7d411b974b950fe0b8bc5f265 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 8 Jan 2019 22:12:41 -0800 Subject: crypto: sm3 - fix undefined shift by >= width of value sm3_compress() calls rol32() with shift >= 32, which causes undefined behavior. This is easily detected by enabling CONFIG_UBSAN. Explicitly AND with 31 to make the behavior well defined. Fixes: 4f0fc1600edb ("crypto: sm3 - add OSCCA SM3 secure hash") Cc: # v4.15+ Cc: Gilad Ben-Yossef Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu --- crypto/sm3_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/sm3_generic.c b/crypto/sm3_generic.c index 9a5c60f08aad..c0cf87ae7ef6 100644 --- a/crypto/sm3_generic.c +++ b/crypto/sm3_generic.c @@ -100,7 +100,7 @@ static void sm3_compress(u32 *w, u32 *wt, u32 *m) for (i = 0; i <= 63; i++) { - ss1 = rol32((rol32(a, 12) + e + rol32(t(i), i)), 7); + ss1 = rol32((rol32(a, 12) + e + rol32(t(i), i & 31)), 7); ss2 = ss1 ^ rol32(a, 12); -- cgit v1.2.3-58-ga151 From 15c03092a9fbcdd041f58e5f832bf76c21c42e6a Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Thu, 10 Jan 2019 15:19:36 +0530 Subject: tools headers powerpc: Remove unistd.h We use syscall.tbl to generate system call table on powerpc. The unistd.h copy is no longer required now. Remove it. Signed-off-by: Ravi Bangoria Cc: Jiri Olsa Cc: Michael Ellerman Cc: Namhyung Kim Cc: linuxppc-dev@lists.ozlabs.org Link: http://lkml.kernel.org/r/20190110094936.3132-2-ravi.bangoria@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/powerpc/include/uapi/asm/unistd.h | 404 --------------------------- tools/perf/check-headers.sh | 1 - 2 files changed, 405 deletions(-) delete mode 100644 tools/arch/powerpc/include/uapi/asm/unistd.h diff --git a/tools/arch/powerpc/include/uapi/asm/unistd.h b/tools/arch/powerpc/include/uapi/asm/unistd.h deleted file mode 100644 index 985534d0b448..000000000000 --- a/tools/arch/powerpc/include/uapi/asm/unistd.h +++ /dev/null @@ -1,404 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -/* - * This file contains the system call numbers. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_ASM_POWERPC_UNISTD_H_ -#define _UAPI_ASM_POWERPC_UNISTD_H_ - - -#define __NR_restart_syscall 0 -#define __NR_exit 1 -#define __NR_fork 2 -#define __NR_read 3 -#define __NR_write 4 -#define __NR_open 5 -#define __NR_close 6 -#define __NR_waitpid 7 -#define __NR_creat 8 -#define __NR_link 9 -#define __NR_unlink 10 -#define __NR_execve 11 -#define __NR_chdir 12 -#define __NR_time 13 -#define __NR_mknod 14 -#define __NR_chmod 15 -#define __NR_lchown 16 -#define __NR_break 17 -#define __NR_oldstat 18 -#define __NR_lseek 19 -#define __NR_getpid 20 -#define __NR_mount 21 -#define __NR_umount 22 -#define __NR_setuid 23 -#define __NR_getuid 24 -#define __NR_stime 25 -#define __NR_ptrace 26 -#define __NR_alarm 27 -#define __NR_oldfstat 28 -#define __NR_pause 29 -#define __NR_utime 30 -#define __NR_stty 31 -#define __NR_gtty 32 -#define __NR_access 33 -#define __NR_nice 34 -#define __NR_ftime 35 -#define __NR_sync 36 -#define __NR_kill 37 -#define __NR_rename 38 -#define __NR_mkdir 39 -#define __NR_rmdir 40 -#define __NR_dup 41 -#define __NR_pipe 42 -#define __NR_times 43 -#define __NR_prof 44 -#define __NR_brk 45 -#define __NR_setgid 46 -#define __NR_getgid 47 -#define __NR_signal 48 -#define __NR_geteuid 49 -#define __NR_getegid 50 -#define __NR_acct 51 -#define __NR_umount2 52 -#define __NR_lock 53 -#define __NR_ioctl 54 -#define __NR_fcntl 55 -#define __NR_mpx 56 -#define __NR_setpgid 57 -#define __NR_ulimit 58 -#define __NR_oldolduname 59 -#define __NR_umask 60 -#define __NR_chroot 61 -#define __NR_ustat 62 -#define __NR_dup2 63 -#define __NR_getppid 64 -#define __NR_getpgrp 65 -#define __NR_setsid 66 -#define __NR_sigaction 67 -#define __NR_sgetmask 68 -#define __NR_ssetmask 69 -#define __NR_setreuid 70 -#define __NR_setregid 71 -#define __NR_sigsuspend 72 -#define __NR_sigpending 73 -#define __NR_sethostname 74 -#define __NR_setrlimit 75 -#define __NR_getrlimit 76 -#define __NR_getrusage 77 -#define __NR_gettimeofday 78 -#define __NR_settimeofday 79 -#define __NR_getgroups 80 -#define __NR_setgroups 81 -#define __NR_select 82 -#define __NR_symlink 83 -#define __NR_oldlstat 84 -#define __NR_readlink 85 -#define __NR_uselib 86 -#define __NR_swapon 87 -#define __NR_reboot 88 -#define __NR_readdir 89 -#define __NR_mmap 90 -#define __NR_munmap 91 -#define __NR_truncate 92 -#define __NR_ftruncate 93 -#define __NR_fchmod 94 -#define __NR_fchown 95 -#define __NR_getpriority 96 -#define __NR_setpriority 97 -#define __NR_profil 98 -#define __NR_statfs 99 -#define __NR_fstatfs 100 -#define __NR_ioperm 101 -#define __NR_socketcall 102 -#define __NR_syslog 103 -#define __NR_setitimer 104 -#define __NR_getitimer 105 -#define __NR_stat 106 -#define __NR_lstat 107 -#define __NR_fstat 108 -#define __NR_olduname 109 -#define __NR_iopl 110 -#define __NR_vhangup 111 -#define __NR_idle 112 -#define __NR_vm86 113 -#define __NR_wait4 114 -#define __NR_swapoff 115 -#define __NR_sysinfo 116 -#define __NR_ipc 117 -#define __NR_fsync 118 -#define __NR_sigreturn 119 -#define __NR_clone 120 -#define __NR_setdomainname 121 -#define __NR_uname 122 -#define __NR_modify_ldt 123 -#define __NR_adjtimex 124 -#define __NR_mprotect 125 -#define __NR_sigprocmask 126 -#define __NR_create_module 127 -#define __NR_init_module 128 -#define __NR_delete_module 129 -#define __NR_get_kernel_syms 130 -#define __NR_quotactl 131 -#define __NR_getpgid 132 -#define __NR_fchdir 133 -#define __NR_bdflush 134 -#define __NR_sysfs 135 -#define __NR_personality 136 -#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ -#define __NR_setfsuid 138 -#define __NR_setfsgid 139 -#define __NR__llseek 140 -#define __NR_getdents 141 -#define __NR__newselect 142 -#define __NR_flock 143 -#define __NR_msync 144 -#define __NR_readv 145 -#define __NR_writev 146 -#define __NR_getsid 147 -#define __NR_fdatasync 148 -#define __NR__sysctl 149 -#define __NR_mlock 150 -#define __NR_munlock 151 -#define __NR_mlockall 152 -#define __NR_munlockall 153 -#define __NR_sched_setparam 154 -#define __NR_sched_getparam 155 -#define __NR_sched_setscheduler 156 -#define __NR_sched_getscheduler 157 -#define __NR_sched_yield 158 -#define __NR_sched_get_priority_max 159 -#define __NR_sched_get_priority_min 160 -#define __NR_sched_rr_get_interval 161 -#define __NR_nanosleep 162 -#define __NR_mremap 163 -#define __NR_setresuid 164 -#define __NR_getresuid 165 -#define __NR_query_module 166 -#define __NR_poll 167 -#define __NR_nfsservctl 168 -#define __NR_setresgid 169 -#define __NR_getresgid 170 -#define __NR_prctl 171 -#define __NR_rt_sigreturn 172 -#define __NR_rt_sigaction 173 -#define __NR_rt_sigprocmask 174 -#define __NR_rt_sigpending 175 -#define __NR_rt_sigtimedwait 176 -#define __NR_rt_sigqueueinfo 177 -#define __NR_rt_sigsuspend 178 -#define __NR_pread64 179 -#define __NR_pwrite64 180 -#define __NR_chown 181 -#define __NR_getcwd 182 -#define __NR_capget 183 -#define __NR_capset 184 -#define __NR_sigaltstack 185 -#define __NR_sendfile 186 -#define __NR_getpmsg 187 /* some people actually want streams */ -#define __NR_putpmsg 188 /* some people actually want streams */ -#define __NR_vfork 189 -#define __NR_ugetrlimit 190 /* SuS compliant getrlimit */ -#define __NR_readahead 191 -#ifndef __powerpc64__ /* these are 32-bit only */ -#define __NR_mmap2 192 -#define __NR_truncate64 193 -#define __NR_ftruncate64 194 -#define __NR_stat64 195 -#define __NR_lstat64 196 -#define __NR_fstat64 197 -#endif -#define __NR_pciconfig_read 198 -#define __NR_pciconfig_write 199 -#define __NR_pciconfig_iobase 200 -#define __NR_multiplexer 201 -#define __NR_getdents64 202 -#define __NR_pivot_root 203 -#ifndef __powerpc64__ -#define __NR_fcntl64 204 -#endif -#define __NR_madvise 205 -#define __NR_mincore 206 -#define __NR_gettid 207 -#define __NR_tkill 208 -#define __NR_setxattr 209 -#define __NR_lsetxattr 210 -#define __NR_fsetxattr 211 -#define __NR_getxattr 212 -#define __NR_lgetxattr 213 -#define __NR_fgetxattr 214 -#define __NR_listxattr 215 -#define __NR_llistxattr 216 -#define __NR_flistxattr 217 -#define __NR_removexattr 218 -#define __NR_lremovexattr 219 -#define __NR_fremovexattr 220 -#define __NR_futex 221 -#define __NR_sched_setaffinity 222 -#define __NR_sched_getaffinity 223 -/* 224 currently unused */ -#define __NR_tuxcall 225 -#ifndef __powerpc64__ -#define __NR_sendfile64 226 -#endif -#define __NR_io_setup 227 -#define __NR_io_destroy 228 -#define __NR_io_getevents 229 -#define __NR_io_submit 230 -#define __NR_io_cancel 231 -#define __NR_set_tid_address 232 -#define __NR_fadvise64 233 -#define __NR_exit_group 234 -#define __NR_lookup_dcookie 235 -#define __NR_epoll_create 236 -#define __NR_epoll_ctl 237 -#define __NR_epoll_wait 238 -#define __NR_remap_file_pages 239 -#define __NR_timer_create 240 -#define __NR_timer_settime 241 -#define __NR_timer_gettime 242 -#define __NR_timer_getoverrun 243 -#define __NR_timer_delete 244 -#define __NR_clock_settime 245 -#define __NR_clock_gettime 246 -#define __NR_clock_getres 247 -#define __NR_clock_nanosleep 248 -#define __NR_swapcontext 249 -#define __NR_tgkill 250 -#define __NR_utimes 251 -#define __NR_statfs64 252 -#define __NR_fstatfs64 253 -#ifndef __powerpc64__ -#define __NR_fadvise64_64 254 -#endif -#define __NR_rtas 255 -#define __NR_sys_debug_setcontext 256 -/* Number 257 is reserved for vserver */ -#define __NR_migrate_pages 258 -#define __NR_mbind 259 -#define __NR_get_mempolicy 260 -#define __NR_set_mempolicy 261 -#define __NR_mq_open 262 -#define __NR_mq_unlink 263 -#define __NR_mq_timedsend 264 -#define __NR_mq_timedreceive 265 -#define __NR_mq_notify 266 -#define __NR_mq_getsetattr 267 -#define __NR_kexec_load 268 -#define __NR_add_key 269 -#define __NR_request_key 270 -#define __NR_keyctl 271 -#define __NR_waitid 272 -#define __NR_ioprio_set 273 -#define __NR_ioprio_get 274 -#define __NR_inotify_init 275 -#define __NR_inotify_add_watch 276 -#define __NR_inotify_rm_watch 277 -#define __NR_spu_run 278 -#define __NR_spu_create 279 -#define __NR_pselect6 280 -#define __NR_ppoll 281 -#define __NR_unshare 282 -#define __NR_splice 283 -#define __NR_tee 284 -#define __NR_vmsplice 285 -#define __NR_openat 286 -#define __NR_mkdirat 287 -#define __NR_mknodat 288 -#define __NR_fchownat 289 -#define __NR_futimesat 290 -#ifdef __powerpc64__ -#define __NR_newfstatat 291 -#else -#define __NR_fstatat64 291 -#endif -#define __NR_unlinkat 292 -#define __NR_renameat 293 -#define __NR_linkat 294 -#define __NR_symlinkat 295 -#define __NR_readlinkat 296 -#define __NR_fchmodat 297 -#define __NR_faccessat 298 -#define __NR_get_robust_list 299 -#define __NR_set_robust_list 300 -#define __NR_move_pages 301 -#define __NR_getcpu 302 -#define __NR_epoll_pwait 303 -#define __NR_utimensat 304 -#define __NR_signalfd 305 -#define __NR_timerfd_create 306 -#define __NR_eventfd 307 -#define __NR_sync_file_range2 308 -#define __NR_fallocate 309 -#define __NR_subpage_prot 310 -#define __NR_timerfd_settime 311 -#define __NR_timerfd_gettime 312 -#define __NR_signalfd4 313 -#define __NR_eventfd2 314 -#define __NR_epoll_create1 315 -#define __NR_dup3 316 -#define __NR_pipe2 317 -#define __NR_inotify_init1 318 -#define __NR_perf_event_open 319 -#define __NR_preadv 320 -#define __NR_pwritev 321 -#define __NR_rt_tgsigqueueinfo 322 -#define __NR_fanotify_init 323 -#define __NR_fanotify_mark 324 -#define __NR_prlimit64 325 -#define __NR_socket 326 -#define __NR_bind 327 -#define __NR_connect 328 -#define __NR_listen 329 -#define __NR_accept 330 -#define __NR_getsockname 331 -#define __NR_getpeername 332 -#define __NR_socketpair 333 -#define __NR_send 334 -#define __NR_sendto 335 -#define __NR_recv 336 -#define __NR_recvfrom 337 -#define __NR_shutdown 338 -#define __NR_setsockopt 339 -#define __NR_getsockopt 340 -#define __NR_sendmsg 341 -#define __NR_recvmsg 342 -#define __NR_recvmmsg 343 -#define __NR_accept4 344 -#define __NR_name_to_handle_at 345 -#define __NR_open_by_handle_at 346 -#define __NR_clock_adjtime 347 -#define __NR_syncfs 348 -#define __NR_sendmmsg 349 -#define __NR_setns 350 -#define __NR_process_vm_readv 351 -#define __NR_process_vm_writev 352 -#define __NR_finit_module 353 -#define __NR_kcmp 354 -#define __NR_sched_setattr 355 -#define __NR_sched_getattr 356 -#define __NR_renameat2 357 -#define __NR_seccomp 358 -#define __NR_getrandom 359 -#define __NR_memfd_create 360 -#define __NR_bpf 361 -#define __NR_execveat 362 -#define __NR_switch_endian 363 -#define __NR_userfaultfd 364 -#define __NR_membarrier 365 -#define __NR_mlock2 378 -#define __NR_copy_file_range 379 -#define __NR_preadv2 380 -#define __NR_pwritev2 381 -#define __NR_kexec_file_load 382 -#define __NR_statx 383 -#define __NR_pkey_alloc 384 -#define __NR_pkey_free 385 -#define __NR_pkey_mprotect 386 -#define __NR_rseq 387 -#define __NR_io_pgetevents 388 - -#endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index b51e952ab35f..7b55613924de 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -50,7 +50,6 @@ arch/parisc/include/uapi/asm/errno.h arch/powerpc/include/uapi/asm/errno.h arch/sparc/include/uapi/asm/errno.h arch/x86/include/uapi/asm/errno.h -arch/powerpc/include/uapi/asm/unistd.h include/asm-generic/bitops/arch_hweight.h include/asm-generic/bitops/const_hweight.h include/asm-generic/bitops/__fls.h -- cgit v1.2.3-58-ga151 From 9f51c05dc41a6d69423e3d03d18eb7ab22f9ec19 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Wed, 5 Dec 2018 10:35:50 +0800 Subject: pvcalls-front: Avoid get_free_pages(GFP_KERNEL) under spinlock The problem is that we call this with a spin lock held. The call tree is: pvcalls_front_accept() holds bedata->socket_lock. -> create_active() -> __get_free_pages() uses GFP_KERNEL The create_active() function is only called from pvcalls_front_accept() with a spin_lock held, The allocation is not allowed to sleep and GFP_KERNEL is not sufficient. This issue was detected by using the Coccinelle software. v2: Add a function doing the allocations which is called outside the lock and passing the allocated data to create_active(). v3: Use the matching deallocators i.e., free_page() and free_pages(), respectively. v4: It would be better to pre-populate map (struct sock_mapping), rather than introducing one more new struct. v5: Since allocating the data outside of this call it should also be freed outside, when create_active() fails. Move kzalloc(sizeof(*map2), GFP_ATOMIC) outside spinlock and use GFP_KERNEL instead. v6: Drop the superfluous calls. Suggested-by: Juergen Gross Suggested-by: Boris Ostrovsky Suggested-by: Stefano Stabellini Signed-off-by: Wen Yang Acked-by: Stefano Stabellini CC: Julia Lawall CC: Boris Ostrovsky CC: Juergen Gross CC: Stefano Stabellini CC: xen-devel@lists.xenproject.org CC: linux-kernel@vger.kernel.org Signed-off-by: Boris Ostrovsky --- drivers/xen/pvcalls-front.c | 81 +++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 1a893a164349..307861f9e485 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -341,6 +341,39 @@ int pvcalls_front_socket(struct socket *sock) return ret; } +static void free_active_ring(struct sock_mapping *map) +{ + free_pages((unsigned long)map->active.data.in, + map->active.ring->ring_order); + free_page((unsigned long)map->active.ring); +} + +static int alloc_active_ring(struct sock_mapping *map) +{ + void *bytes; + + map->active.ring = (struct pvcalls_data_intf *) + get_zeroed_page(GFP_KERNEL); + if (!map->active.ring) + goto out; + + map->active.ring->ring_order = PVCALLS_RING_ORDER; + bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + PVCALLS_RING_ORDER); + if (!bytes) + goto out; + + map->active.data.in = bytes; + map->active.data.out = bytes + + XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER); + + return 0; + +out: + free_active_ring(map); + return -ENOMEM; +} + static int create_active(struct sock_mapping *map, int *evtchn) { void *bytes; @@ -349,15 +382,7 @@ static int create_active(struct sock_mapping *map, int *evtchn) *evtchn = -1; init_waitqueue_head(&map->active.inflight_conn_req); - map->active.ring = (struct pvcalls_data_intf *) - __get_free_page(GFP_KERNEL | __GFP_ZERO); - if (map->active.ring == NULL) - goto out_error; - map->active.ring->ring_order = PVCALLS_RING_ORDER; - bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - PVCALLS_RING_ORDER); - if (bytes == NULL) - goto out_error; + bytes = map->active.data.in; for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++) map->active.ring->ref[i] = gnttab_grant_foreign_access( pvcalls_front_dev->otherend_id, @@ -367,10 +392,6 @@ static int create_active(struct sock_mapping *map, int *evtchn) pvcalls_front_dev->otherend_id, pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0); - map->active.data.in = bytes; - map->active.data.out = bytes + - XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER); - ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn); if (ret) goto out_error; @@ -391,8 +412,6 @@ static int create_active(struct sock_mapping *map, int *evtchn) out_error: if (*evtchn >= 0) xenbus_free_evtchn(pvcalls_front_dev, *evtchn); - free_pages((unsigned long)map->active.data.in, PVCALLS_RING_ORDER); - free_page((unsigned long)map->active.ring); return ret; } @@ -412,17 +431,24 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, return PTR_ERR(map); bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + ret = alloc_active_ring(map); + if (ret < 0) { + pvcalls_exit_sock(sock); + return ret; + } spin_lock(&bedata->socket_lock); ret = get_request(bedata, &req_id); if (ret < 0) { spin_unlock(&bedata->socket_lock); + free_active_ring(map); pvcalls_exit_sock(sock); return ret; } ret = create_active(map, &evtchn); if (ret < 0) { spin_unlock(&bedata->socket_lock); + free_active_ring(map); pvcalls_exit_sock(sock); return ret; } @@ -786,25 +812,36 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) } } - spin_lock(&bedata->socket_lock); - ret = get_request(bedata, &req_id); - if (ret < 0) { + map2 = kzalloc(sizeof(*map2), GFP_KERNEL); + if (map2 == NULL) { clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); - spin_unlock(&bedata->socket_lock); + pvcalls_exit_sock(sock); + return -ENOMEM; + } + ret = alloc_active_ring(map2); + if (ret < 0) { + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + kfree(map2); pvcalls_exit_sock(sock); return ret; } - map2 = kzalloc(sizeof(*map2), GFP_ATOMIC); - if (map2 == NULL) { + spin_lock(&bedata->socket_lock); + ret = get_request(bedata, &req_id); + if (ret < 0) { clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); spin_unlock(&bedata->socket_lock); + free_active_ring(map2); + kfree(map2); pvcalls_exit_sock(sock); - return -ENOMEM; + return ret; } + ret = create_active(map2, &evtchn); if (ret < 0) { + free_active_ring(map2); kfree(map2); clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); -- cgit v1.2.3-58-ga151 From 0b7959b6257322f7693b08a459c505d4938646f2 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 7 Jan 2019 13:38:38 -0800 Subject: tun: publish tfile after it's fully initialized BUG: unable to handle kernel NULL pointer dereference at 00000000000000d1 Call Trace: ? napi_gro_frags+0xa7/0x2c0 tun_get_user+0xb50/0xf20 tun_chr_write_iter+0x53/0x70 new_sync_write+0xff/0x160 vfs_write+0x191/0x1e0 __x64_sys_write+0x5e/0xd0 do_syscall_64+0x47/0xf0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 I think there is a subtle race between sending a packet via tap and attaching it: CPU0: CPU1: tun_chr_ioctl(TUNSETIFF) tun_set_iff tun_attach rcu_assign_pointer(tfile->tun, tun); tun_fops->write_iter() tun_chr_write_iter tun_napi_alloc_frags napi_get_frags napi->skb = napi_alloc_skb tun_napi_init netif_napi_add napi->skb = NULL napi->skb is NULL here napi_gro_frags napi_frags_skb skb = napi->skb skb_reset_mac_header(skb) panic() Move rcu_assign_pointer(tfile->tun) and rcu_assign_pointer(tun->tfiles) to be the last thing we do in tun_attach(); this should guarantee that when we call tun_get() we always get an initialized object. v2 changes: * remove extra napi_mutex locks/unlocks for napi operations Reported-by: syzbot Fixes: 90e33d459407 ("tun: enable napi_gro_frags() for TUN/TAP driver") Signed-off-by: Stanislav Fomichev Signed-off-by: David S. Miller --- drivers/net/tun.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index a4fdad475594..18656c4094b3 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -856,10 +856,6 @@ static int tun_attach(struct tun_struct *tun, struct file *file, err = 0; } - rcu_assign_pointer(tfile->tun, tun); - rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile); - tun->numqueues++; - if (tfile->detached) { tun_enable_queue(tfile); } else { @@ -876,6 +872,13 @@ static int tun_attach(struct tun_struct *tun, struct file *file, * refcnt. */ + /* Publish tfile->tun and tun->tfiles only after we've fully + * initialized tfile; otherwise we risk using half-initialized + * object. + */ + rcu_assign_pointer(tfile->tun, tun); + rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile); + tun->numqueues++; out: return err; } -- cgit v1.2.3-58-ga151 From 4a06fa67c4da20148803525151845276cdb995c1 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 7 Jan 2019 16:47:33 -0500 Subject: ip: on queued skb use skb_header_pointer instead of pskb_may_pull Commit 2efd4fca703a ("ip: in cmsg IP(V6)_ORIGDSTADDR call pskb_may_pull") avoided a read beyond the end of the skb linear segment by calling pskb_may_pull. That function can trigger a BUG_ON in pskb_expand_head if the skb is shared, which it is when when peeking. It can also return ENOMEM. Avoid both by switching to safer skb_header_pointer. Fixes: 2efd4fca703a ("ip: in cmsg IP(V6)_ORIGDSTADDR call pskb_may_pull") Reported-by: syzbot Suggested-by: Eric Dumazet Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- net/ipv4/ip_sockglue.c | 12 +++++------- net/ipv6/datagram.c | 10 ++++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index fffcc130900e..82f341e84fae 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -148,19 +148,17 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) { + __be16 _ports[2], *ports; struct sockaddr_in sin; - __be16 *ports; - int end; - - end = skb_transport_offset(skb) + 4; - if (end > 0 && !pskb_may_pull(skb, end)) - return; /* All current transport protocols have the port numbers in the * first four bytes of the transport header and this function is * written with this assumption in mind. */ - ports = (__be16 *)skb_transport_header(skb); + ports = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_ports), &_ports); + if (!ports) + return; sin.sin_family = AF_INET; sin.sin_addr.s_addr = ip_hdr(skb)->daddr; diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index bde08aa549f3..c2262a7e2088 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -700,17 +700,15 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, } if (np->rxopt.bits.rxorigdstaddr) { struct sockaddr_in6 sin6; - __be16 *ports; - int end; + __be16 _ports[2], *ports; - end = skb_transport_offset(skb) + 4; - if (end <= 0 || pskb_may_pull(skb, end)) { + ports = skb_header_pointer(skb, skb_transport_offset(skb), + sizeof(_ports), &_ports); + if (ports) { /* All current transport protocols have the port numbers in the * first four bytes of the transport header and this function is * written with this assumption in mind. */ - ports = (__be16 *)skb_transport_header(skb); - sin6.sin6_family = AF_INET6; sin6.sin6_addr = ipv6_hdr(skb)->daddr; sin6.sin6_port = ports[1]; -- cgit v1.2.3-58-ga151 From 2acc0abc882ac3be47719e189f3db006493ab640 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Jan 2019 23:39:24 +0000 Subject: net: cxgb3: fix various indentation issues There are handful of lines that have indentation issues, fix these. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb3/sge.c | 12 +++++++----- drivers/net/ethernet/chelsio/cxgb3/t3_hw.c | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index 20b6e1b3f5e3..6a80b44f2e71 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -2381,7 +2381,7 @@ no_mem: lro_add_page(adap, qs, fl, G_RSPD_LEN(len), flags & F_RSPD_EOP); - goto next_fl; + goto next_fl; } skb = get_packet_pg(adap, fl, q, @@ -3214,11 +3214,13 @@ void t3_start_sge_timers(struct adapter *adap) for (i = 0; i < SGE_QSETS; ++i) { struct sge_qset *q = &adap->sge.qs[i]; - if (q->tx_reclaim_timer.function) - mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); + if (q->tx_reclaim_timer.function) + mod_timer(&q->tx_reclaim_timer, + jiffies + TX_RECLAIM_PERIOD); - if (q->rx_reclaim_timer.function) - mod_timer(&q->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD); + if (q->rx_reclaim_timer.function) + mod_timer(&q->rx_reclaim_timer, + jiffies + RX_RECLAIM_PERIOD); } } diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c index 080918af773c..0a9f2c596624 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c @@ -1082,7 +1082,7 @@ int t3_check_fw_version(struct adapter *adapter) CH_WARN(adapter, "found newer FW version(%u.%u), " "driver compiled for version %u.%u\n", major, minor, FW_VERSION_MAJOR, FW_VERSION_MINOR); - return 0; + return 0; } return -EINVAL; } @@ -3619,7 +3619,7 @@ int t3_reset_adapter(struct adapter *adapter) static int init_parity(struct adapter *adap) { - int i, err, addr; + int i, err, addr; if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) return -EBUSY; @@ -3806,6 +3806,6 @@ int t3_replay_prep_adapter(struct adapter *adapter) p->phy.ops->power_down(&p->phy, 1); } -return 0; + return 0; } -- cgit v1.2.3-58-ga151 From fd21c89b876565df76051eca395018de2280f8e1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Jan 2019 23:48:09 +0000 Subject: net: cxgb4: fix various indentation issues There are some lines that have indentation issues, fix these. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c | 8 ++++---- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c index 9f9d6cae39d5..58a039c3224a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c @@ -378,10 +378,10 @@ static void cxgb4_init_ptp_timer(struct adapter *adapter) int err; memset(&c, 0, sizeof(c)); - c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | - FW_CMD_REQUEST_F | - FW_CMD_WRITE_F | - FW_PTP_CMD_PORTID_V(0)); + c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) | + FW_CMD_REQUEST_F | + FW_CMD_WRITE_F | + FW_PTP_CMD_PORTID_V(0)); c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16)); c.u.scmd.sc = FW_PTP_SC_INIT_TIMER; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index 9a6065a3fa46..c041f44324db 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -78,7 +78,7 @@ static void free_msix_idx_in_bmap(struct adapter *adap, unsigned int msix_idx) unsigned long flags; spin_lock_irqsave(&bmap->lock, flags); - __clear_bit(msix_idx, bmap->msix_bmap); + __clear_bit(msix_idx, bmap->msix_bmap); spin_unlock_irqrestore(&bmap->lock, flags); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index e8c34292a0ec..2b03f6187a24 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3794,7 +3794,7 @@ int t4_load_phy_fw(struct adapter *adap, /* If we have version number support, then check to see if the adapter * already has up-to-date PHY firmware loaded. */ - if (phy_fw_version) { + if (phy_fw_version) { new_phy_fw_vers = phy_fw_version(phy_fw_data, phy_fw_size); ret = t4_phy_fw_ver(adap, &cur_phy_fw_ver); if (ret < 0) -- cgit v1.2.3-58-ga151 From 85704cb8dcfd88d351bfc87faaeba1c8214f3177 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 8 Jan 2019 12:30:00 +0300 Subject: net/core/neighbour: tell kmemleak about hash tables This fixes false-positive kmemleak reports about leaked neighbour entries: unreferenced object 0xffff8885c6e4d0a8 (size 1024): comm "softirq", pid 0, jiffies 4294922664 (age 167640.804s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 20 2c f3 83 ff ff ff ff ........ ,...... 08 c0 ef 5f 84 88 ff ff 01 8c 7d 02 01 00 00 00 ..._......}..... backtrace: [<00000000748509fe>] ip6_finish_output2+0x887/0x1e40 [<0000000036d7a0d8>] ip6_output+0x1ba/0x600 [<0000000027ea7dba>] ip6_send_skb+0x92/0x2f0 [<00000000d6e2111d>] udp_v6_send_skb.isra.24+0x680/0x15e0 [<000000000668a8be>] udpv6_sendmsg+0x18c9/0x27a0 [<000000004bd5fa90>] sock_sendmsg+0xb3/0xf0 [<000000008227b29f>] ___sys_sendmsg+0x745/0x8f0 [<000000008698009d>] __sys_sendmsg+0xde/0x170 [<00000000889dacf1>] do_syscall_64+0x9b/0x400 [<0000000081cdb353>] entry_SYSCALL_64_after_hwframe+0x49/0xbe [<000000005767ed39>] 0xffffffffffffffff Signed-off-by: Konstantin Khlebnikov Signed-off-by: David S. Miller --- net/core/neighbour.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 763a7b08df67..3e27a779f288 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -18,6 +18,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -443,12 +444,14 @@ static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift) ret = kmalloc(sizeof(*ret), GFP_ATOMIC); if (!ret) return NULL; - if (size <= PAGE_SIZE) + if (size <= PAGE_SIZE) { buckets = kzalloc(size, GFP_ATOMIC); - else + } else { buckets = (struct neighbour __rcu **) __get_free_pages(GFP_ATOMIC | __GFP_ZERO, get_order(size)); + kmemleak_alloc(buckets, size, 0, GFP_ATOMIC); + } if (!buckets) { kfree(ret); return NULL; @@ -468,10 +471,12 @@ static void neigh_hash_free_rcu(struct rcu_head *head) size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *); struct neighbour __rcu **buckets = nht->hash_buckets; - if (size <= PAGE_SIZE) + if (size <= PAGE_SIZE) { kfree(buckets); - else + } else { + kmemleak_free(buckets); free_pages((unsigned long)buckets, get_order(size)); + } kfree(nht); } -- cgit v1.2.3-58-ga151 From 7d033c9f6a7fd3821af75620a0257db87c2b552a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 8 Jan 2019 04:06:14 -0800 Subject: ipv6: fix kernel-infoleak in ipv6_local_error() This patch makes sure the flow label in the IPv6 header forged in ipv6_local_error() is initialized. BUG: KMSAN: kernel-infoleak in _copy_to_user+0x16b/0x1f0 lib/usercopy.c:32 CPU: 1 PID: 24675 Comm: syz-executor1 Not tainted 4.20.0-rc7+ #4 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x173/0x1d0 lib/dump_stack.c:113 kmsan_report+0x12e/0x2a0 mm/kmsan/kmsan.c:613 kmsan_internal_check_memory+0x455/0xb00 mm/kmsan/kmsan.c:675 kmsan_copy_to_user+0xab/0xc0 mm/kmsan/kmsan_hooks.c:601 _copy_to_user+0x16b/0x1f0 lib/usercopy.c:32 copy_to_user include/linux/uaccess.h:177 [inline] move_addr_to_user+0x2e9/0x4f0 net/socket.c:227 ___sys_recvmsg+0x5d7/0x1140 net/socket.c:2284 __sys_recvmsg net/socket.c:2327 [inline] __do_sys_recvmsg net/socket.c:2337 [inline] __se_sys_recvmsg+0x2fa/0x450 net/socket.c:2334 __x64_sys_recvmsg+0x4a/0x70 net/socket.c:2334 do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 RIP: 0033:0x457ec9 Code: 6d b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 3b b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f8750c06c78 EFLAGS: 00000246 ORIG_RAX: 000000000000002f RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000457ec9 RDX: 0000000000002000 RSI: 0000000020000400 RDI: 0000000000000005 RBP: 000000000073bf00 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f8750c076d4 R13: 00000000004c4a60 R14: 00000000004d8140 R15: 00000000ffffffff Uninit was stored to memory at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:204 [inline] kmsan_save_stack mm/kmsan/kmsan.c:219 [inline] kmsan_internal_chain_origin+0x134/0x230 mm/kmsan/kmsan.c:439 __msan_chain_origin+0x70/0xe0 mm/kmsan/kmsan_instr.c:200 ipv6_recv_error+0x1e3f/0x1eb0 net/ipv6/datagram.c:475 udpv6_recvmsg+0x398/0x2ab0 net/ipv6/udp.c:335 inet_recvmsg+0x4fb/0x600 net/ipv4/af_inet.c:830 sock_recvmsg_nosec net/socket.c:794 [inline] sock_recvmsg+0x1d1/0x230 net/socket.c:801 ___sys_recvmsg+0x4d5/0x1140 net/socket.c:2278 __sys_recvmsg net/socket.c:2327 [inline] __do_sys_recvmsg net/socket.c:2337 [inline] __se_sys_recvmsg+0x2fa/0x450 net/socket.c:2334 __x64_sys_recvmsg+0x4a/0x70 net/socket.c:2334 do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:204 [inline] kmsan_internal_poison_shadow+0x92/0x150 mm/kmsan/kmsan.c:158 kmsan_kmalloc+0xa6/0x130 mm/kmsan/kmsan_hooks.c:176 kmsan_slab_alloc+0xe/0x10 mm/kmsan/kmsan_hooks.c:185 slab_post_alloc_hook mm/slab.h:446 [inline] slab_alloc_node mm/slub.c:2759 [inline] __kmalloc_node_track_caller+0xe18/0x1030 mm/slub.c:4383 __kmalloc_reserve net/core/skbuff.c:137 [inline] __alloc_skb+0x309/0xa20 net/core/skbuff.c:205 alloc_skb include/linux/skbuff.h:998 [inline] ipv6_local_error+0x1a7/0x9e0 net/ipv6/datagram.c:334 __ip6_append_data+0x129f/0x4fd0 net/ipv6/ip6_output.c:1311 ip6_make_skb+0x6cc/0xcf0 net/ipv6/ip6_output.c:1775 udpv6_sendmsg+0x3f8e/0x45d0 net/ipv6/udp.c:1384 inet_sendmsg+0x54a/0x720 net/ipv4/af_inet.c:798 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] __sys_sendto+0x8c4/0xac0 net/socket.c:1788 __do_sys_sendto net/socket.c:1800 [inline] __se_sys_sendto+0x107/0x130 net/socket.c:1796 __x64_sys_sendto+0x6e/0x90 net/socket.c:1796 do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 Bytes 4-7 of 28 are uninitialized Memory access of size 28 starts at ffff8881937bfce0 Data copied to user address 0000000020000000 Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller --- net/ipv6/datagram.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index c2262a7e2088..ee4a4e54d016 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -341,6 +341,7 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info) skb_reset_network_header(skb); iph = ipv6_hdr(skb); iph->daddr = fl6->daddr; + ip6_flow_hdr(iph, 0, 0); serr = SKB_EXT_ERR(skb); serr->ee.ee_errno = err; -- cgit v1.2.3-58-ga151 From 3fe931b31a4078395c1967f0495dcc9e5ec6b5e3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 17 Dec 2018 10:02:42 +0300 Subject: thermal: int340x_thermal: Fix a NULL vs IS_ERR() check The intel_soc_dts_iosf_init() function doesn't return NULL, it returns error pointers. Fixes: 4d0dd6c1576b ("Thermal/int340x/processor_thermal: Enable auxiliary DTS for Braswell") Signed-off-by: Dan Carpenter Signed-off-by: Zhang Rui --- drivers/thermal/intel/int340x_thermal/processor_thermal_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 284cf2c5a8fd..8e0f665cf06f 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -423,7 +423,7 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, proc_priv->soc_dts = intel_soc_dts_iosf_init( INTEL_SOC_DTS_INTERRUPT_MSI, 2, 0); - if (proc_priv->soc_dts && pdev->irq) { + if (!IS_ERR(proc_priv->soc_dts) && pdev->irq) { ret = pci_enable_msi(pdev); if (!ret) { ret = request_threaded_irq(pdev->irq, NULL, -- cgit v1.2.3-58-ga151 From e3ca63de8ade75757a067f6a5bd111d30cdcadb5 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Tue, 8 Jan 2019 16:07:28 -0800 Subject: selftests/bpf: add missing executables to .gitignore We build test_libbpf with CXX to make sure linking against C++ works. $ make -s -C tools/lib/bpf $ git status -sb ? tools/lib/bpf/test_libbpf $ make -s -C tools/testing/selftests/bpf $ git status -sb ? tools/lib/bpf/test_libbpf ? tools/testing/selftests/bpf/test_libbpf Fixes: 8c4905b995c6 ("libbpf: make sure bpf headers are c++ include-able") Signed-off-by: Stanislav Fomichev Signed-off-by: Daniel Borkmann --- tools/lib/bpf/.gitignore | 1 + tools/testing/selftests/bpf/.gitignore | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/lib/bpf/.gitignore b/tools/lib/bpf/.gitignore index f81e549ddfdb..4db74758c674 100644 --- a/tools/lib/bpf/.gitignore +++ b/tools/lib/bpf/.gitignore @@ -1,2 +1,3 @@ libbpf_version.h FEATURE-DUMP.libbpf +test_libbpf diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 4a9785043a39..dd093bd91aa9 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -28,3 +28,4 @@ flow_dissector_load test_netcnt test_section_names test_tcpnotify_user +test_libbpf -- cgit v1.2.3-58-ga151 From 11b36abc249f5e100d532c5271dae938fde85175 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Wed, 9 Jan 2019 17:06:55 +0000 Subject: samples: bpf: user proper argument index Use optind as index for argv instead of a hardcoded value. When the program has options this leads to improper parameter handling. Fixes: dc378a1ab5b6 ("samples: bpf: get ifindex from ifname") Signed-off-by: Ioana Ciornei Acked-by: Matteo Croce Signed-off-by: Daniel Borkmann --- samples/bpf/xdp1_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bpf/xdp1_user.c b/samples/bpf/xdp1_user.c index 0a197f86ac43..8bfda95c77ad 100644 --- a/samples/bpf/xdp1_user.c +++ b/samples/bpf/xdp1_user.c @@ -103,7 +103,7 @@ int main(int argc, char **argv) return 1; } - ifindex = if_nametoindex(argv[1]); + ifindex = if_nametoindex(argv[optind]); if (!ifindex) { perror("if_nametoindex"); return 1; -- cgit v1.2.3-58-ga151 From df209c43a0e8258e096fb722dfbdae4f0dd13fde Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 1 Dec 2018 12:57:18 +0100 Subject: gpio: pl061: handle failed allocations devm_kzalloc(), devm_kstrdup() and devm_kasprintf() all can fail internal allocation and return NULL. Using any of the assigned objects without checking is not safe. As this is early in the boot phase and these allocations really should not fail, any failure here is probably an indication of a more serious issue so it makes little sense to try and rollback the previous allocated resources or try to continue; but rather the probe function is simply exited with -ENOMEM. Signed-off-by: Nicholas Mc Guire Fixes: 684284b64aae ("ARM: integrator: add MMCI device to IM-PD1") Signed-off-by: Linus Walleij --- arch/arm/mach-integrator/impd1.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index a109f6482413..0f916c245a2e 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -393,7 +393,11 @@ static int __ref impd1_probe(struct lm_device *dev) sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup), GFP_KERNEL); chipname = devm_kstrdup(&dev->dev, devname, GFP_KERNEL); - mmciname = kasprintf(GFP_KERNEL, "lm%x:00700", dev->id); + mmciname = devm_kasprintf(&dev->dev, GFP_KERNEL, + "lm%x:00700", dev->id); + if (!lookup || !chipname || !mmciname) + return -ENOMEM; + lookup->dev_id = mmciname; /* * Offsets on GPIO block 1: -- cgit v1.2.3-58-ga151 From f98937c6bb73ae11717a15aec85c187d33ca5d34 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Tue, 8 Jan 2019 10:23:03 +0100 Subject: selftests: bpf: install files tcp_(server|client)*.py When test_tcpbpf_user runs it complains that it can't find files tcp_server.py and tcp_client.py. Rework so that tcp_server.py and tcp_client.py gets installed, added them to the variable TEST_PROGS_EXTENDED. Fixes: d6d4f60c3a09 ("bpf: add selftest for tcpbpf") Signed-off-by: Anders Roxell Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 73aa6d8f4a2f..70229de510f5 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -55,7 +55,9 @@ TEST_PROGS := test_kmod.sh \ test_flow_dissector.sh \ test_xdp_vlan.sh -TEST_PROGS_EXTENDED := with_addr.sh +TEST_PROGS_EXTENDED := with_addr.sh \ + tcp_client.py \ + tcp_server.py # Compile but not part of 'make run_tests' TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user \ -- cgit v1.2.3-58-ga151 From beaf3d1901f4ea46fbd5c9d857227d99751de469 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Tue, 8 Jan 2019 14:20:44 -0800 Subject: bpf: fix panic in stack_map_get_build_id() on i386 and arm32 As Naresh reported, test_stacktrace_build_id() causes panic on i386 and arm32 systems. This is caused by page_address() returns NULL in certain cases. This patch fixes this error by using kmap_atomic/kunmap_atomic instead of page_address. Fixes: 615755a77b24 (" bpf: extend stackmap to save binary_build_id+offset instead of address") Reported-by: Naresh Kamboju Signed-off-by: Song Liu Signed-off-by: Daniel Borkmann --- kernel/bpf/stackmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 90daf285de03..d9e2483669d0 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -260,7 +260,7 @@ static int stack_map_get_build_id(struct vm_area_struct *vma, return -EFAULT; /* page not mapped */ ret = -EINVAL; - page_addr = page_address(page); + page_addr = kmap_atomic(page); ehdr = (Elf32_Ehdr *)page_addr; /* compare magic x7f "ELF" */ @@ -276,6 +276,7 @@ static int stack_map_get_build_id(struct vm_area_struct *vma, else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) ret = stack_map_get_build_id_64(page_addr, build_id); out: + kunmap_atomic(page_addr); put_page(page); return ret; } -- cgit v1.2.3-58-ga151 From 1b3922a8bc74231f9a767d1be6d9a061a4d4eeab Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 8 Jan 2019 14:08:18 +0800 Subject: btrfs: Use real device structure to verify dev extent [BUG] Linux v5.0-rc1 will fail fstests/btrfs/163 with the following kernel message: BTRFS error (device dm-6): dev extent devid 1 physical offset 13631488 len 8388608 is beyond device boundary 0 BTRFS error (device dm-6): failed to verify dev extents against chunks: -117 BTRFS error (device dm-6): open_ctree failed [CAUSE] Commit cf90d884b347 ("btrfs: Introduce mount time chunk <-> dev extent mapping check") introduced strict check on dev extents. We use btrfs_find_device() with dev uuid and fs uuid set to NULL, and only dependent on @devid to find the real device. For seed devices, we call clone_fs_devices() in open_seed_devices() to allow us search seed devices directly. However clone_fs_devices() just populates devices with devid and dev uuid, without populating other essential members, like disk_total_bytes. This makes any device returned by btrfs_find_device(fs_info, devid, NULL, NULL) is just a dummy, with 0 disk_total_bytes, and any dev extents on the seed device will not pass the device boundary check. [FIX] This patch will try to verify the device returned by btrfs_find_device() and if it's a dummy then re-search in seed devices. Fixes: cf90d884b347 ("btrfs: Introduce mount time chunk <-> dev extent mapping check") CC: stable@vger.kernel.org # 4.19+ Reported-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 2576b1a379c9..3e4f8f88353e 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -7825,6 +7825,18 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info, ret = -EUCLEAN; goto out; } + + /* It's possible this device is a dummy for seed device */ + if (dev->disk_total_bytes == 0) { + dev = find_device(fs_info->fs_devices->seed, devid, NULL); + if (!dev) { + btrfs_err(fs_info, "failed to find seed devid %llu", + devid); + ret = -EUCLEAN; + goto out; + } + } + if (physical_offset + physical_len > dev->disk_total_bytes) { btrfs_err(fs_info, "dev extent devid %llu physical offset %llu len %llu is beyond device boundary %llu", -- cgit v1.2.3-58-ga151 From c2b8bd49d35a768d3966c5e14e8f6971f2a63439 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Jan 2019 17:23:54 +0000 Subject: afs: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: David Howells --- fs/afs/server_list.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/afs/server_list.c b/fs/afs/server_list.c index 95d0761cdb34..155dc14caef9 100644 --- a/fs/afs/server_list.c +++ b/fs/afs/server_list.c @@ -42,9 +42,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell, if (vldb->fs_mask[i] & type_mask) nr_servers++; - slist = kzalloc(sizeof(struct afs_server_list) + - sizeof(struct afs_server_entry) * nr_servers, - GFP_KERNEL); + slist = kzalloc(struct_size(slist, servers, nr_servers), GFP_KERNEL); if (!slist) goto error; -- cgit v1.2.3-58-ga151 From 5edc22cc1d33d6a88d175d25adc38d2a5cee134d Mon Sep 17 00:00:00 2001 From: Marc Dionne Date: Wed, 9 Jan 2019 17:23:54 +0000 Subject: afs: Set correct lock type for the yfs CreateFile A lock type of 0 is "LockRead", which makes the fileserver record an unintentional read lock on the new file. This will cause problems later on if the file is the subject of locking operations. The correct default value should be -1 ("LockNone"). Fix the operation marshalling code to set the value and provide an enum to symbolise the values whilst we're at it. Fixes: 30062bd13e36 ("afs: Implement YFS support in the fs client") Signed-off-by: Marc Dionne Signed-off-by: David Howells --- fs/afs/protocol_yfs.h | 11 +++++++++++ fs/afs/yfsclient.c | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/afs/protocol_yfs.h b/fs/afs/protocol_yfs.h index 07bc10f076aa..d443e2bfa094 100644 --- a/fs/afs/protocol_yfs.h +++ b/fs/afs/protocol_yfs.h @@ -161,3 +161,14 @@ struct yfs_xdr_YFSStoreVolumeStatus { struct yfs_xdr_u64 max_quota; struct yfs_xdr_u64 file_quota; } __packed; + +enum yfs_lock_type { + yfs_LockNone = -1, + yfs_LockRead = 0, + yfs_LockWrite = 1, + yfs_LockExtend = 2, + yfs_LockRelease = 3, + yfs_LockMandatoryRead = 0x100, + yfs_LockMandatoryWrite = 0x101, + yfs_LockMandatoryExtend = 0x102, +}; diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 12658c1363ae..5aa57929e8c2 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -803,7 +803,7 @@ int yfs_fs_create_file(struct afs_fs_cursor *fc, bp = xdr_encode_YFSFid(bp, &vnode->fid); bp = xdr_encode_string(bp, name, namesz); bp = xdr_encode_YFSStoreStatus_mode(bp, mode); - bp = xdr_encode_u32(bp, 0); /* ViceLockType */ + bp = xdr_encode_u32(bp, yfs_LockNone); /* ViceLockType */ yfs_check_req(call, bp); afs_use_fs_server(call, fc->cbi); -- cgit v1.2.3-58-ga151 From b89d82ef01b33bc50cbaa8ff05607879b40d0704 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 8 Jan 2019 16:19:01 +0000 Subject: arm64: kpti: Avoid rewriting early page tables when KASLR is enabled A side effect of commit c55191e96caa ("arm64: mm: apply r/o permissions of VM areas to its linear alias as well") is that the linear map is created with page granularity, which means that transitioning the early page table from global to non-global mappings when enabling kpti can take a significant amount of time during boot. Given that most CPU implementations do not require kpti, this mainly impacts KASLR builds where kpti is forcefully enabled. However, in these situations we know early on that non-global mappings are required and can avoid the use of global mappings from the beginning. The only gotcha is Cavium erratum #27456, which we must detect based on the MIDR value of the boot CPU. Reviewed-by: Ard Biesheuvel Reported-by: John Garry Signed-off-by: Will Deacon --- arch/arm64/include/asm/mmu.h | 41 +++++++++++++++++++++++++++++++++++ arch/arm64/include/asm/pgtable-prot.h | 4 ++-- arch/arm64/kernel/cpu_errata.c | 2 +- arch/arm64/kernel/cpufeature.c | 9 ++++++-- arch/arm64/kernel/head.S | 1 + 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 7689c7aa1d77..ac352accb3d9 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -16,6 +16,8 @@ #ifndef __ASM_MMU_H #define __ASM_MMU_H +#include + #define MMCF_AARCH32 0x1 /* mm context flag for AArch32 executables */ #define USER_ASID_BIT 48 #define USER_ASID_FLAG (UL(1) << USER_ASID_BIT) @@ -44,6 +46,45 @@ static inline bool arm64_kernel_unmapped_at_el0(void) cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0); } +static inline bool arm64_kernel_use_ng_mappings(void) +{ + bool tx1_bug; + + /* What's a kpti? Use global mappings if we don't know. */ + if (!IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0)) + return false; + + /* + * Note: this function is called before the CPU capabilities have + * been configured, so our early mappings will be global. If we + * later determine that kpti is required, then + * kpti_install_ng_mappings() will make them non-global. + */ + if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE)) + return arm64_kernel_unmapped_at_el0(); + + /* + * KASLR is enabled so we're going to be enabling kpti on non-broken + * CPUs regardless of their susceptibility to Meltdown. Rather + * than force everybody to go through the G -> nG dance later on, + * just put down non-global mappings from the beginning. + */ + if (!IS_ENABLED(CONFIG_CAVIUM_ERRATUM_27456)) { + tx1_bug = false; +#ifndef MODULE + } else if (!static_branch_likely(&arm64_const_caps_ready)) { + extern const struct midr_range cavium_erratum_27456_cpus[]; + + tx1_bug = is_midr_in_range_list(read_cpuid_id(), + cavium_erratum_27456_cpus); +#endif + } else { + tx1_bug = __cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_27456); + } + + return !tx1_bug && kaslr_offset() > 0; +} + typedef void (*bp_hardening_cb_t)(void); struct bp_hardening_data { diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h index 78b942c1bea4..986e41c4c32b 100644 --- a/arch/arm64/include/asm/pgtable-prot.h +++ b/arch/arm64/include/asm/pgtable-prot.h @@ -37,8 +37,8 @@ #define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) #define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) -#define PTE_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PTE_NG : 0) -#define PMD_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PMD_SECT_NG : 0) +#define PTE_MAYBE_NG (arm64_kernel_use_ng_mappings() ? PTE_NG : 0) +#define PMD_MAYBE_NG (arm64_kernel_use_ng_mappings() ? PMD_SECT_NG : 0) #define PROT_DEFAULT (_PROT_DEFAULT | PTE_MAYBE_NG) #define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_MAYBE_NG) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 09ac548c9d44..9950bb0cbd52 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -553,7 +553,7 @@ static const struct midr_range arm64_repeat_tlbi_cpus[] = { #endif #ifdef CONFIG_CAVIUM_ERRATUM_27456 -static const struct midr_range cavium_erratum_27456_cpus[] = { +const struct midr_range cavium_erratum_27456_cpus[] = { /* Cavium ThunderX, T88 pass 1.x - 2.1 */ MIDR_RANGE(MIDR_THUNDERX, 0, 0, 1, 1), /* Cavium ThunderX, T81 pass 1.0 */ diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 4f272399de89..f6d84e2c92fe 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -983,7 +983,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, /* Useful for KASLR robustness */ if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) - return true; + return kaslr_offset() > 0; /* Don't force KPTI for CPUs that are not vulnerable */ if (is_midr_in_range_list(read_cpuid_id(), kpti_safe_list)) @@ -1003,7 +1003,12 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused) static bool kpti_applied = false; int cpu = smp_processor_id(); - if (kpti_applied) + /* + * We don't need to rewrite the page-tables if either we've done + * it already or we have KASLR enabled and therefore have not + * created any global mappings at all. + */ + if (kpti_applied || kaslr_offset() > 0) return; remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings); diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index c7213674cb24..15d79a8e5e5e 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -475,6 +475,7 @@ ENDPROC(__primary_switched) ENTRY(kimage_vaddr) .quad _text - TEXT_OFFSET +EXPORT_SYMBOL(kimage_vaddr) /* * If we're fortunate enough to boot at EL2, ensure that the world is -- cgit v1.2.3-58-ga151 From a214720cbf50cd8c3f76bbb9c3f5c283910e9d33 Mon Sep 17 00:00:00 2001 From: YunQiang Su Date: Tue, 8 Jan 2019 13:45:10 +0800 Subject: Disable MSI also when pcie-octeon.pcie_disable on Octeon has an boot-time option to disable pcie. Since MSI depends on PCI-E, we should also disable MSI also with this option is on in order to avoid inadvertently accessing PCIe registers. Signed-off-by: YunQiang Su Signed-off-by: Paul Burton Cc: pburton@wavecomp.com Cc: linux-mips@vger.kernel.org Cc: aaro.koskinen@iki.fi Cc: stable@vger.kernel.org # v3.3+ --- arch/mips/pci/msi-octeon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index 2a5bb849b10e..288b58b00dc8 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -369,7 +369,9 @@ int __init octeon_msi_initialize(void) int irq; struct irq_chip *msi; - if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE) { + if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_INVALID) { + return 0; + } else if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_PCIE) { msi_rcv_reg[0] = CVMX_PEXP_NPEI_MSI_RCV0; msi_rcv_reg[1] = CVMX_PEXP_NPEI_MSI_RCV1; msi_rcv_reg[2] = CVMX_PEXP_NPEI_MSI_RCV2; -- cgit v1.2.3-58-ga151 From 1856b9f7bcc8e9bdcccc360aabb56fbd4dd6c565 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Wed, 9 Jan 2019 11:57:14 +0100 Subject: dm crypt: fix parsing of extended IV arguments The dm-crypt cipher specification in a mapping table is defined as: cipher[:keycount]-chainmode-ivmode[:ivopts] or (new crypt API format): capi:cipher_api_spec-ivmode[:ivopts] For ESSIV, the parameter includes hash specification, for example: aes-cbc-essiv:sha256 The implementation expected that additional IV option to never include another dash '-' character. But, with SHA3, there are names like sha3-256; so the mapping table parser fails: dmsetup create test --table "0 8 crypt aes-cbc-essiv:sha3-256 9c1185a5c5e9fc54612808977ee8f5b9e 0 /dev/sdb 0" or (new crypt API format) dmsetup create test --table "0 8 crypt capi:cbc(aes)-essiv:sha3-256 9c1185a5c5e9fc54612808977ee8f5b9e 0 /dev/sdb 0" device-mapper: crypt: Ignoring unexpected additional cipher options device-mapper: table: 253:0: crypt: Error creating IV device-mapper: ioctl: error adding target to table Fix the dm-crypt constructor to ignore additional dash in IV options and also remove a bogus warning (that is ignored anyway). Cc: stable@vger.kernel.org # 4.12+ Signed-off-by: Milan Broz Signed-off-by: Mike Snitzer --- drivers/md/dm-crypt.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 0ff22159a0ca..47d4e0d30bf0 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2414,9 +2414,21 @@ static int crypt_ctr_cipher_new(struct dm_target *ti, char *cipher_in, char *key * capi:cipher_api_spec-iv:ivopts */ tmp = &cipher_in[strlen("capi:")]; - cipher_api = strsep(&tmp, "-"); - *ivmode = strsep(&tmp, ":"); - *ivopts = tmp; + + /* Separate IV options if present, it can contain another '-' in hash name */ + *ivopts = strrchr(tmp, ':'); + if (*ivopts) { + **ivopts = '\0'; + (*ivopts)++; + } + /* Parse IV mode */ + *ivmode = strrchr(tmp, '-'); + if (*ivmode) { + **ivmode = '\0'; + (*ivmode)++; + } + /* The rest is crypto API spec */ + cipher_api = tmp; if (*ivmode && !strcmp(*ivmode, "lmk")) cc->tfms_count = 64; @@ -2486,11 +2498,8 @@ static int crypt_ctr_cipher_old(struct dm_target *ti, char *cipher_in, char *key goto bad_mem; chainmode = strsep(&tmp, "-"); - *ivopts = strsep(&tmp, "-"); - *ivmode = strsep(&*ivopts, ":"); - - if (tmp) - DMWARN("Ignoring unexpected additional cipher options"); + *ivmode = strsep(&tmp, ":"); + *ivopts = tmp; /* * For compatibility with the original dm-crypt mapping format, if -- cgit v1.2.3-58-ga151 From 8428817dc40006dca0a531cfa06e89cb3b41790d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 5 Jan 2019 15:25:29 +0300 Subject: cifs: Fix a debug message This debug message was never shown because it was checking for NULL returns but extract_hostname() returns error pointers. Fixes: 93d5cb517db3 ("cifs: Add support for failover in cifs_reconnect()") Signed-off-by: Dan Carpenter Signed-off-by: Steve French Reviewed-by: Paulo Alcantara --- fs/cifs/connect.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f66529679ca2..683310f26171 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -433,9 +433,10 @@ static void reconn_inval_dfs_target(struct TCP_Server_Info *server, kfree(server->hostname); server->hostname = extract_hostname(name); - if (!server->hostname) { - cifs_dbg(FYI, "%s: failed to extract hostname from target: %d\n", - __func__, -ENOMEM); + if (IS_ERR(server->hostname)) { + cifs_dbg(FYI, + "%s: failed to extract hostname from target: %ld\n", + __func__, PTR_ERR(server->hostname)); } } -- cgit v1.2.3-58-ga151 From c715f89c4dab76317c773df2611af2dac4dea2b7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 5 Jan 2019 21:18:03 +0300 Subject: cifs: Fix a tiny potential memory leak The most recent "it" allocation is leaked on this error path. I believe that small allocations always succeed in current kernels so this doesn't really affect run time. Fixes: 54be1f6c1c37 ("cifs: Add DFS cache routines") Signed-off-by: Dan Carpenter Signed-off-by: Steve French --- fs/cifs/dfs_cache.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c index cd63c4a70875..09b7d0d4f6e4 100644 --- a/fs/cifs/dfs_cache.c +++ b/fs/cifs/dfs_cache.c @@ -776,6 +776,7 @@ static int get_tgt_list(const struct dfs_cache_entry *ce, it->it_name = kstrndup(t->t_name, strlen(t->t_name), GFP_KERNEL); if (!it->it_name) { + kfree(it); rc = -ENOMEM; goto err_free_it; } -- cgit v1.2.3-58-ga151 From b983f7e92348d7e7d091db1b78b7915e9dd3d63a Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Wed, 19 Dec 2018 22:49:09 +0000 Subject: CIFS: Fix adjustment of credits for MTU requests Currently for MTU requests we allocate maximum possible credits in advance and then adjust them according to the request size. While we were adjusting the number of credits belonging to the server, we were skipping adjustment of credits belonging to the request. This patch fixes it by setting request credits to CreditCharge field value of SMB2 packet header. Also ask 1 credit more for async read and write operations to increase parallelism and match the behavior of other operations. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French CC: Stable --- fs/cifs/smb2pdu.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index e57f6aa1d638..b9d7891edaa1 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -3278,12 +3278,14 @@ smb2_async_readv(struct cifs_readdata *rdata) if (rdata->credits) { shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, SMB2_MAX_BUFFER_SIZE)); - shdr->CreditRequest = shdr->CreditCharge; + shdr->CreditRequest = + cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); spin_lock(&server->req_lock); server->credits += rdata->credits - le16_to_cpu(shdr->CreditCharge); spin_unlock(&server->req_lock); wake_up(&server->request_q); + rdata->credits = le16_to_cpu(shdr->CreditCharge); flags |= CIFS_HAS_CREDITS; } @@ -3555,12 +3557,14 @@ smb2_async_writev(struct cifs_writedata *wdata, if (wdata->credits) { shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, SMB2_MAX_BUFFER_SIZE)); - shdr->CreditRequest = shdr->CreditCharge; + shdr->CreditRequest = + cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); spin_lock(&server->req_lock); server->credits += wdata->credits - le16_to_cpu(shdr->CreditCharge); spin_unlock(&server->req_lock); wake_up(&server->request_q); + wdata->credits = le16_to_cpu(shdr->CreditCharge); flags |= CIFS_HAS_CREDITS; } -- cgit v1.2.3-58-ga151 From 33fa5c8b8a7dbe6353a56eaa654b790348890d42 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 3 Jan 2019 16:45:13 -0800 Subject: CIFS: Do not set credits to 1 if the server didn't grant anything Currently we reset the number of total credits granted by the server to 1 if the server didn't grant us anything int the response. This violates the SMB3 protocol - we need to trust the server and use the credit values from the response. Fix this by removing the corresponding code. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French CC: Stable --- fs/cifs/transport.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 5be7302853b6..8e75d689be46 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -894,8 +894,6 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, for (i = 0; i < num_rqst; i++) if (midQ[i]->resp_buf) credits += ses->server->ops->get_credits(midQ[i]); - if (!credits) - credits = 1; for (i = 0; i < num_rqst; i++) { if (rc < 0) -- cgit v1.2.3-58-ga151 From 8544f4aa9dd19a04d1244dae10feecc813ccf175 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Sat, 22 Dec 2018 12:40:05 -0800 Subject: CIFS: Fix credit computation for compounded requests In SMB3 protocol every part of the compound chain consumes credits individually, so we need to call wait_for_free_credits() for each of the PDUs in the chain. If an operation is interrupted, we must ensure we return all credits taken from the server structure back. Without this patch server can sometimes disconnect the session due to credit mismatches, especially when first operation(s) are large writes. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French CC: Stable --- fs/cifs/transport.c | 59 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 8e75d689be46..e047f06c9b4f 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -795,7 +795,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, int i, j, rc = 0; int timeout, optype; struct mid_q_entry *midQ[MAX_COMPOUND]; - unsigned int credits = 0; + bool cancelled_mid[MAX_COMPOUND] = {false}; + unsigned int credits[MAX_COMPOUND] = {0}; char *buf; timeout = flags & CIFS_TIMEOUT_MASK; @@ -813,13 +814,31 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, return -ENOENT; /* - * Ensure that we do not send more than 50 overlapping requests - * to the same server. We may make this configurable later or - * use ses->maxReq. + * Ensure we obtain 1 credit per request in the compound chain. + * It can be optimized further by waiting for all the credits + * at once but this can wait long enough if we don't have enough + * credits due to some heavy operations in progress or the server + * not granting us much, so a fallback to the current approach is + * needed anyway. */ - rc = wait_for_free_request(ses->server, timeout, optype); - if (rc) - return rc; + for (i = 0; i < num_rqst; i++) { + rc = wait_for_free_request(ses->server, timeout, optype); + if (rc) { + /* + * We haven't sent an SMB packet to the server yet but + * we already obtained credits for i requests in the + * compound chain - need to return those credits back + * for future use. Note that we need to call add_credits + * multiple times to match the way we obtained credits + * in the first place and to account for in flight + * requests correctly. + */ + for (j = 0; j < i; j++) + add_credits(ses->server, 1, optype); + return rc; + } + credits[i] = 1; + } /* * Make sure that we sign in the same order that we send on this socket @@ -835,8 +854,10 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, for (j = 0; j < i; j++) cifs_delete_mid(midQ[j]); mutex_unlock(&ses->server->srv_mutex); + /* Update # of requests on wire to server */ - add_credits(ses->server, 1, optype); + for (j = 0; j < num_rqst; j++) + add_credits(ses->server, credits[j], optype); return PTR_ERR(midQ[i]); } @@ -883,17 +904,16 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) { midQ[i]->mid_flags |= MID_WAIT_CANCELLED; midQ[i]->callback = DeleteMidQEntry; - spin_unlock(&GlobalMid_Lock); - add_credits(ses->server, 1, optype); - return rc; + cancelled_mid[i] = true; } spin_unlock(&GlobalMid_Lock); } } for (i = 0; i < num_rqst; i++) - if (midQ[i]->resp_buf) - credits += ses->server->ops->get_credits(midQ[i]); + if (!cancelled_mid[i] && midQ[i]->resp_buf + && (midQ[i]->mid_state == MID_RESPONSE_RECEIVED)) + credits[i] = ses->server->ops->get_credits(midQ[i]); for (i = 0; i < num_rqst; i++) { if (rc < 0) @@ -901,8 +921,9 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ[i], ses->server); if (rc != 0) { - add_credits(ses->server, credits, optype); - return rc; + /* mark this mid as cancelled to not free it below */ + cancelled_mid[i] = true; + goto out; } if (!midQ[i]->resp_buf || @@ -949,9 +970,11 @@ out: * This is prevented above by using a noop callback that will not * wake this thread except for the very last PDU. */ - for (i = 0; i < num_rqst; i++) - cifs_delete_mid(midQ[i]); - add_credits(ses->server, credits, optype); + for (i = 0; i < num_rqst; i++) { + if (!cancelled_mid[i]) + cifs_delete_mid(midQ[i]); + add_credits(ses->server, credits[i], optype); + } return rc; } -- cgit v1.2.3-58-ga151 From 001e465f09a18857443489a57e74314a3368c805 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 8 Jan 2019 12:32:42 -0500 Subject: bonding: update nest level on unlink A network device stack with multiple layers of bonding devices can trigger a false positive lockdep warning. Adding lockdep nest levels fixes this. Update the level on both enslave and unlink, to avoid the following series of events .. ip netns add test ip netns exec test bash ip link set dev lo addr 00:11:22:33:44:55 ip link set dev lo down ip link add dev bond1 type bond ip link add dev bond2 type bond ip link set dev lo master bond1 ip link set dev bond1 master bond2 ip link set dev bond1 nomaster ip link set dev bond2 master bond1 .. from still generating a splat: [ 193.652127] ====================================================== [ 193.658231] WARNING: possible circular locking dependency detected [ 193.664350] 4.20.0 #8 Not tainted [ 193.668310] ------------------------------------------------------ [ 193.674417] ip/15577 is trying to acquire lock: [ 193.678897] 00000000a40e3b69 (&(&bond->stats_lock)->rlock#3/3){+.+.}, at: bond_get_stats+0x58/0x290 [ 193.687851] but task is already holding lock: [ 193.693625] 00000000807b9d9f (&(&bond->stats_lock)->rlock#2/2){+.+.}, at: bond_get_stats+0x58/0x290 [..] [ 193.851092] lock_acquire+0xa7/0x190 [ 193.855138] _raw_spin_lock_nested+0x2d/0x40 [ 193.859878] bond_get_stats+0x58/0x290 [ 193.864093] dev_get_stats+0x5a/0xc0 [ 193.868140] bond_get_stats+0x105/0x290 [ 193.872444] dev_get_stats+0x5a/0xc0 [ 193.876493] rtnl_fill_stats+0x40/0x130 [ 193.880797] rtnl_fill_ifinfo+0x6c5/0xdc0 [ 193.885271] rtmsg_ifinfo_build_skb+0x86/0xe0 [ 193.890091] rtnetlink_event+0x5b/0xa0 [ 193.894320] raw_notifier_call_chain+0x43/0x60 [ 193.899225] netdev_change_features+0x50/0xa0 [ 193.904044] bond_compute_features.isra.46+0x1ab/0x270 [ 193.909640] bond_enslave+0x141d/0x15b0 [ 193.913946] do_set_master+0x89/0xa0 [ 193.918016] do_setlink+0x37c/0xda0 [ 193.921980] __rtnl_newlink+0x499/0x890 [ 193.926281] rtnl_newlink+0x48/0x70 [ 193.930238] rtnetlink_rcv_msg+0x171/0x4b0 [ 193.934801] netlink_rcv_skb+0xd1/0x110 [ 193.939103] rtnetlink_rcv+0x15/0x20 [ 193.943151] netlink_unicast+0x3b5/0x520 [ 193.947544] netlink_sendmsg+0x2fd/0x3f0 [ 193.951942] sock_sendmsg+0x38/0x50 [ 193.955899] ___sys_sendmsg+0x2ba/0x2d0 [ 193.960205] __x64_sys_sendmsg+0xad/0x100 [ 193.964687] do_syscall_64+0x5a/0x460 [ 193.968823] entry_SYSCALL_64_after_hwframe+0x49/0xbe Fixes: 7e2556e40026 ("bonding: avoid lockdep confusion in bond_get_stats()") Reported-by: syzbot Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a9d597f28023..485462d3087f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1963,6 +1963,9 @@ static int __bond_release_one(struct net_device *bond_dev, if (!bond_has_slaves(bond)) { bond_set_carrier(bond); eth_hw_addr_random(bond_dev); + bond->nest_level = SINGLE_DEPTH_NESTING; + } else { + bond->nest_level = dev_get_nest_level(bond_dev) + 1; } unblock_netpoll_tx(); -- cgit v1.2.3-58-ga151 From ea89098ef9a574bceca00d3b5df14aaf0b3f9ccf Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 9 Jan 2019 00:24:03 +0100 Subject: net: dsa: mv88x6xxx: mv88e6390 errata The 6390 copper ports have an errata which require poking magic values into undocumented magic registers and then performing a software reset. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 113 +++++++++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 5 ++ drivers/net/dsa/mv88e6xxx/port.h | 10 ++++ 3 files changed, 128 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 8a517d8fb9d1..8dca2c949e73 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2403,6 +2403,107 @@ static int mv88e6xxx_stats_setup(struct mv88e6xxx_chip *chip) return mv88e6xxx_g1_stats_clear(chip); } +/* The mv88e6390 has some hidden registers used for debug and + * development. The errata also makes use of them. + */ +static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port, + int reg, u16 val) +{ + u16 ctrl; + int err; + + err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_DATA_PORT, + PORT_RESERVED_1A, val); + if (err) + return err; + + ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_WRITE | + PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | + reg; + + return mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, + PORT_RESERVED_1A, ctrl); +} + +static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip) +{ + return mv88e6xxx_wait(chip, PORT_RESERVED_1A_CTRL_PORT, + PORT_RESERVED_1A, PORT_RESERVED_1A_BUSY); +} + + +static int mv88e6390_hidden_read(struct mv88e6xxx_chip *chip, int port, + int reg, u16 *val) +{ + u16 ctrl; + int err; + + ctrl = PORT_RESERVED_1A_BUSY | PORT_RESERVED_1A_READ | + PORT_RESERVED_1A_BLOCK | port << PORT_RESERVED_1A_PORT_SHIFT | + reg; + + err = mv88e6xxx_port_write(chip, PORT_RESERVED_1A_CTRL_PORT, + PORT_RESERVED_1A, ctrl); + if (err) + return err; + + err = mv88e6390_hidden_wait(chip); + if (err) + return err; + + return mv88e6xxx_port_read(chip, PORT_RESERVED_1A_DATA_PORT, + PORT_RESERVED_1A, val); +} + +/* Check if the errata has already been applied. */ +static bool mv88e6390_setup_errata_applied(struct mv88e6xxx_chip *chip) +{ + int port; + int err; + u16 val; + + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { + err = mv88e6390_hidden_read(chip, port, 0, &val); + if (err) { + dev_err(chip->dev, + "Error reading hidden register: %d\n", err); + return false; + } + if (val != 0x01c0) + return false; + } + + return true; +} + +/* The 6390 copper ports have an errata which require poking magic + * values into undocumented hidden registers and then performing a + * software reset. + */ +static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) +{ + int port; + int err; + + if (mv88e6390_setup_errata_applied(chip)) + return 0; + + /* Set the ports into blocking mode */ + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { + err = mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED); + if (err) + return err; + } + + for (port = 0; port < mv88e6xxx_num_ports(chip); port++) { + err = mv88e6390_hidden_write(chip, port, 0, 0x01c0); + if (err) + return err; + } + + return mv88e6xxx_software_reset(chip); +} + static int mv88e6xxx_setup(struct dsa_switch *ds) { struct mv88e6xxx_chip *chip = ds->priv; @@ -2415,6 +2516,12 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) mutex_lock(&chip->reg_lock); + if (chip->info->ops->setup_errata) { + err = chip->info->ops->setup_errata(chip); + if (err) + goto unlock; + } + /* Cache the cmode of each port. */ for (i = 0; i < mv88e6xxx_num_ports(chip); i++) { if (chip->info->ops->port_get_cmode) { @@ -3226,6 +3333,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { static const struct mv88e6xxx_ops mv88e6190_ops = { /* MV88E6XXX_FAMILY_6390 */ + .setup_errata = mv88e6390_setup_errata, .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, @@ -3269,6 +3377,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { static const struct mv88e6xxx_ops mv88e6190x_ops = { /* MV88E6XXX_FAMILY_6390 */ + .setup_errata = mv88e6390_setup_errata, .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, @@ -3312,6 +3421,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { static const struct mv88e6xxx_ops mv88e6191_ops = { /* MV88E6XXX_FAMILY_6390 */ + .setup_errata = mv88e6390_setup_errata, .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, @@ -3404,6 +3514,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { static const struct mv88e6xxx_ops mv88e6290_ops = { /* MV88E6XXX_FAMILY_6390 */ + .setup_errata = mv88e6390_setup_errata, .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, @@ -3709,6 +3820,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { static const struct mv88e6xxx_ops mv88e6390_ops = { /* MV88E6XXX_FAMILY_6390 */ + .setup_errata = mv88e6390_setup_errata, .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, @@ -3756,6 +3868,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { static const struct mv88e6xxx_ops mv88e6390x_ops = { /* MV88E6XXX_FAMILY_6390 */ + .setup_errata = mv88e6390_setup_errata, .irl_init_all = mv88e6390_g2_irl_init_all, .get_eeprom = mv88e6xxx_g2_get_eeprom8, .set_eeprom = mv88e6xxx_g2_set_eeprom8, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index f9ecb7872d32..546651d8c3e1 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -300,6 +300,11 @@ struct mv88e6xxx_mdio_bus { }; struct mv88e6xxx_ops { + /* Switch Setup Errata, called early in the switch setup to + * allow any errata actions to be performed + */ + int (*setup_errata)(struct mv88e6xxx_chip *chip); + int (*ieee_pri_map)(struct mv88e6xxx_chip *chip); int (*ip_pri_map)(struct mv88e6xxx_chip *chip); diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 0d81866d0e4a..e583641de758 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -251,6 +251,16 @@ /* Offset 0x19: Port IEEE Priority Remapping Registers (4-7) */ #define MV88E6095_PORT_IEEE_PRIO_REMAP_4567 0x19 +/* Offset 0x1a: Magic undocumented errata register */ +#define PORT_RESERVED_1A 0x1a +#define PORT_RESERVED_1A_BUSY BIT(15) +#define PORT_RESERVED_1A_WRITE BIT(14) +#define PORT_RESERVED_1A_READ 0 +#define PORT_RESERVED_1A_PORT_SHIFT 5 +#define PORT_RESERVED_1A_BLOCK (0xf << 10) +#define PORT_RESERVED_1A_CTRL_PORT 4 +#define PORT_RESERVED_1A_DATA_PORT 5 + int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg, u16 *val); int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg, -- cgit v1.2.3-58-ga151 From c5715b8fabfca0ef85903f8bad2189940ed41cc8 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Tue, 8 Jan 2019 18:14:28 -0800 Subject: tcp: change txhash on SYN-data timeout Previously upon SYN timeouts the sender recomputes the txhash to try a different path. However this does not apply on the initial timeout of SYN-data (active Fast Open). Therefore an active IPv6 Fast Open connection may incur one second RTO penalty to take on a new path after the second SYN retransmission uses a new flow label. This patch removes this undesirable behavior so Fast Open changes the flow label just like the regular connections. This also helps avoid falsely disabling Fast Open on the sender which triggers after two consecutive SYN timeouts on Fast Open. Signed-off-by: Yuchung Cheng Reviewed-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index f87dbc78b6bc..71a29e9c0620 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -226,7 +226,7 @@ static int tcp_write_timeout(struct sock *sk) if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { if (icsk->icsk_retransmits) { dst_negative_advice(sk); - } else if (!tp->syn_data && !tp->syn_fastopen) { + } else { sk_rethink_txhash(sk); } retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; -- cgit v1.2.3-58-ga151 From b19bce0335e25b9069ddb10d234e673bbd46d2f4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 9 Jan 2019 08:20:28 +0100 Subject: net: ethernet: mediatek: fix warning in phy_start_aneg linux 5.0-rc1 shows following warning on bpi-r2/mt7623 bootup: [ 5.170597] WARNING: CPU: 3 PID: 1 at drivers/net/phy/phy.c:548 phy_start_aneg+0x110/0x144 [ 5.178826] called from state READY .... [ 5.264111] [] (phy_start_aneg) from [] (mtk_init+0x414/0x47c) [ 5.271630] r7:df5f5eec r6:c0f08c48 r5:00000000 r4:dea67800 [ 5.277256] [] (mtk_init) from [] (register_netdevice+0x98/0x51c) [ 5.285035] r8:00000000 r7:00000000 r6:c0f97080 r5:c0f08c48 r4:dea67800 [ 5.291693] [] (register_netdevice) from [] (register_netdev+0x2c/0x44) [ 5.299989] r8:00000000 r7:dea2e608 r6:deacea00 r5:dea2e604 r4:dea67800 [ 5.306646] [] (register_netdev) from [] (mtk_probe+0x668/0x7ac) [ 5.314336] r5:dea2e604 r4:dea2e040 [ 5.317890] [] (mtk_probe) from [] (platform_drv_probe+0x58/0xa8) [ 5.325670] r10:c0f86bac r9:00000000 r8:c0fbe578 r7:00000000 r6:c0f86bac r5:00000000 [ 5.333445] r4:deacea10 [ 5.335963] [] (platform_drv_probe) from [] (really_probe+0x2d8/0x424) maybe other boards using this generic driver are affected v2: optimization: - phy_set_max_speed() is only needed if you want to reduce the max speed, typically if the PHY supports 1Gbps but the MAC supports 100Mbps only. - The pause parameters are autonegotiated. Except you have a specific need you normally don't need to manually fiddle with this. - phy_start_aneg() is called implicitly by the phylib state machine, you shouldn't call it manually except you have a good excuse. - netif_carrier_on/netif_carrier_off in mtk_phy_link_adjust() isn't needed. It's done by phy_link_change() in phylib. Signed-off-by: Frank Wunderlich Reviewed-by: Heiner Kallweit Acked-by: Sean Wang Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 399f565dd85a..2968d29a992f 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -258,11 +258,6 @@ static void mtk_phy_link_adjust(struct net_device *dev) mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); - if (dev->phydev->link) - netif_carrier_on(dev); - else - netif_carrier_off(dev); - if (!of_phy_is_fixed_link(mac->of_node)) phy_print_status(dev->phydev); } @@ -347,17 +342,6 @@ static int mtk_phy_connect(struct net_device *dev) if (mtk_phy_connect_node(eth, mac, np)) goto err_phy; - dev->phydev->autoneg = AUTONEG_ENABLE; - dev->phydev->speed = 0; - dev->phydev->duplex = 0; - - phy_set_max_speed(dev->phydev, SPEED_1000); - phy_support_asym_pause(dev->phydev); - linkmode_copy(dev->phydev->advertising, dev->phydev->supported); - linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - dev->phydev->advertising); - phy_start_aneg(dev->phydev); - of_node_put(np); return 0; -- cgit v1.2.3-58-ga151 From 8ce5f84157530ffa64b3e0acf00b9261f41c8da8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 11 Dec 2018 14:31:05 -0600 Subject: of: Remove struct device_node.type pointer Now that all users of device_node.type pointer have been removed in favor of accessor functions, we can remove it. Cc: Frank Rowand Cc: devicetree@vger.kernel.org Signed-off-by: Rob Herring --- drivers/of/dynamic.c | 3 --- drivers/of/fdt.c | 4 ---- drivers/of/overlay.c | 3 --- drivers/of/pdt.c | 1 - include/linux/of.h | 1 - 5 files changed, 12 deletions(-) diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index a09c1c3cf831..49b16f76d78e 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -207,11 +207,8 @@ static void __of_attach_node(struct device_node *np) if (!of_node_check_flag(np, OF_OVERLAY)) { np->name = __of_get_property(np, "name", NULL); - np->type = __of_get_property(np, "device_type", NULL); if (!np->name) np->name = ""; - if (!np->type) - np->type = ""; phandle = __of_get_property(np, "phandle", &sz); if (!phandle) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 7099c652c6a5..9cc1461aac7d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -314,12 +314,8 @@ static bool populate_node(const void *blob, populate_properties(blob, offset, mem, np, pathp, dryrun); if (!dryrun) { np->name = of_get_property(np, "name", NULL); - np->type = of_get_property(np, "device_type", NULL); - if (!np->name) np->name = ""; - if (!np->type) - np->type = ""; } *pnp = np; diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 2b5ac43a5690..c423e94baf0f 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -423,12 +423,9 @@ static int add_changeset_node(struct overlay_changeset *ovcs, tchild->parent = target->np; tchild->name = __of_get_property(node, "name", NULL); - tchild->type = __of_get_property(node, "device_type", NULL); if (!tchild->name) tchild->name = ""; - if (!tchild->type) - tchild->type = ""; /* ignore obsolete "linux,phandle" */ phandle = __of_get_property(node, "phandle", &size); diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c index d3185063d369..7eda43c66c91 100644 --- a/drivers/of/pdt.c +++ b/drivers/of/pdt.c @@ -155,7 +155,6 @@ static struct device_node * __init of_pdt_create_node(phandle node, dp->parent = parent; dp->name = of_pdt_get_one_property(node, "name"); - dp->type = of_pdt_get_one_property(node, "device_type"); dp->phandle = node; dp->properties = of_pdt_build_prop_list(node); diff --git a/include/linux/of.h b/include/linux/of.h index fe472e5195a9..e240992e5cb6 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -50,7 +50,6 @@ struct of_irq_controller; struct device_node { const char *name; - const char *type; phandle phandle; const char *full_name; struct fwnode_handle fwnode; -- cgit v1.2.3-58-ga151 From 2076607a20bd4dfba699185616cbbbce06d3fa59 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 26 Dec 2018 10:06:19 -0200 Subject: qcom-scm: Include header Since commit e6f6d63ed14c ("drm/msm: add headless gpu device for imx5") the DRM_MSM symbol can be selected by SOC_IMX5 causing the following error when building imx_v6_v7_defconfig: In file included from ../drivers/gpu/drm/msm/adreno/a5xx_gpu.c:17:0: ../include/linux/qcom_scm.h: In function 'qcom_scm_set_cold_boot_addr': ../include/linux/qcom_scm.h:73:10: error: 'ENODEV' undeclared (first use in this function) return -ENODEV; Include the header file to fix this problem. Reported-by: kernelci.org bot Fixes: e6f6d63ed14c ("drm/msm: add headless gpu device for imx5") Signed-off-by: Fabio Estevam Reviewed-by: Bjorn Andersson Tested-by: Guenter Roeck Signed-off-by: Andy Gross --- include/linux/qcom_scm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 1637385bcc17..d0aecc04c54b 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -13,6 +13,7 @@ #ifndef __QCOM_SCM_H #define __QCOM_SCM_H +#include #include #include -- cgit v1.2.3-58-ga151 From 6ebec961d59bccf65d08b13fc1ad4e6272a89338 Mon Sep 17 00:00:00 2001 From: Yi Zeng Date: Wed, 9 Jan 2019 15:33:07 +0800 Subject: i2c: dev: prevent adapter retries and timeout being set as minus value If adapter->retries is set to a minus value from user space via ioctl, it will make __i2c_transfer and __i2c_smbus_xfer skip the calling to adapter->algo->master_xfer and adapter->algo->smbus_xfer that is registered by the underlying bus drivers, and return value 0 to all the callers. The bus driver will never be accessed anymore by all users, besides, the users may still get successful return value without any error or information log print out. If adapter->timeout is set to minus value from user space via ioctl, it will make the retrying loop in __i2c_transfer and __i2c_smbus_xfer always break after the the first try, due to the time_after always returns true. Signed-off-by: Yi Zeng [wsa: minor grammar updates to commit message] Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/i2c-dev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 1aca742fde4a..ccd76c71af09 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -470,9 +470,15 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) data_arg.data); } case I2C_RETRIES: + if (arg > INT_MAX) + return -EINVAL; + client->adapter->retries = arg; break; case I2C_TIMEOUT: + if (arg > INT_MAX) + return -EINVAL; + /* For historical reasons, user-space sets the timeout * value in units of 10 ms. */ -- cgit v1.2.3-58-ga151 From b67d4530cdade7ebfafa2c6b46f2a0dad3e41bcb Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Tue, 8 Jan 2019 13:59:10 -0800 Subject: i2c: tegra: Fix Maximum transfer size Tegra194 supports maximum 64K Bytes transfer per packet. Tegra186 and prior supports maximum 4K Bytes transfer per packet. This patch fixes this payload difference between Tegra194 and prior Tegra chipsets using separate i2c_adapter_quirks. Signed-off-by: Sowjanya Komatineni Acked-by: Thierry Reding Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index e417ebf7628c..c77adbbea0c7 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -155,6 +155,8 @@ enum msg_end_type { * @has_mst_fifo: The I2C controller contains the new MST FIFO interface that * provides additional features and allows for longer messages to * be transferred in one go. + * @quirks: i2c adapter quirks for limiting write/read transfer size and not + * allowing 0 length transfers. */ struct tegra_i2c_hw_feature { bool has_continue_xfer_support; @@ -167,6 +169,7 @@ struct tegra_i2c_hw_feature { bool has_multi_master_mode; bool has_slcg_override_reg; bool has_mst_fifo; + const struct i2c_adapter_quirks *quirks; }; /** @@ -837,6 +840,10 @@ static const struct i2c_adapter_quirks tegra_i2c_quirks = { .max_write_len = 4096, }; +static const struct i2c_adapter_quirks tegra194_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_continue_xfer_support = false, .has_per_pkt_xfer_complete_irq = false, @@ -848,6 +855,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = false, .has_mst_fifo = false, + .quirks = &tegra_i2c_quirks, }; static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { @@ -861,6 +869,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = false, .has_mst_fifo = false, + .quirks = &tegra_i2c_quirks, }; static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { @@ -874,6 +883,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = false, .has_mst_fifo = false, + .quirks = &tegra_i2c_quirks, }; static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { @@ -887,6 +897,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = true, .has_mst_fifo = false, + .quirks = &tegra_i2c_quirks, }; static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { @@ -900,6 +911,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { .has_multi_master_mode = true, .has_slcg_override_reg = true, .has_mst_fifo = false, + .quirks = &tegra_i2c_quirks, }; static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { @@ -913,6 +925,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { .has_multi_master_mode = true, .has_slcg_override_reg = true, .has_mst_fifo = true, + .quirks = &tegra194_i2c_quirks, }; /* Match table for of_platform binding */ @@ -964,7 +977,6 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->base = base; i2c_dev->div_clk = div_clk; i2c_dev->adapter.algo = &tegra_i2c_algo; - i2c_dev->adapter.quirks = &tegra_i2c_quirks; i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; @@ -980,6 +992,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->hw = of_device_get_match_data(&pdev->dev); i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, "nvidia,tegra20-i2c-dvc"); + i2c_dev->adapter.quirks = i2c_dev->hw->quirks; init_completion(&i2c_dev->msg_complete); spin_lock_init(&i2c_dev->xfer_lock); -- cgit v1.2.3-58-ga151 From e2c8d550a973bb34fc28bc8d0ec996f84562fb8a Mon Sep 17 00:00:00 2001 From: Shakeel Butt Date: Wed, 2 Jan 2019 19:14:31 -0800 Subject: netfilter: ebtables: account ebt_table_info to kmemcg The [ip,ip6,arp]_tables use x_tables_info internally and the underlying memory is already accounted to kmemcg. Do the same for ebtables. The syzbot, by using setsockopt(EBT_SO_SET_ENTRIES), was able to OOM the whole system from a restricted memcg, a potential DoS. By accounting the ebt_table_info, the memory used for ebt_table_info can be contained within the memcg of the allocating process. However the lifetime of ebt_table_info is independent of the allocating process and is tied to the network namespace. So, the oom-killer will not be able to relieve the memory pressure due to ebt_table_info memory. The memory for ebt_table_info is allocated through vmalloc. Currently vmalloc does not handle the oom-killed allocating process correctly and one large allocation can bypass memcg limit enforcement. So, with this patch, at least the small allocations will be contained. For large allocations, we need to fix vmalloc. Reported-by: syzbot+7713f3aa67be76b1552c@syzkaller.appspotmail.com Signed-off-by: Shakeel Butt Reviewed-by: Kirill Tkhai Signed-off-by: Pablo Neira Ayuso --- net/bridge/netfilter/ebtables.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 491828713e0b..5e55cef0cec3 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1137,14 +1137,16 @@ static int do_replace(struct net *net, const void __user *user, tmp.name[sizeof(tmp.name) - 1] = 0; countersize = COUNTER_OFFSET(tmp.nentries) * nr_cpu_ids; - newinfo = vmalloc(sizeof(*newinfo) + countersize); + newinfo = __vmalloc(sizeof(*newinfo) + countersize, GFP_KERNEL_ACCOUNT, + PAGE_KERNEL); if (!newinfo) return -ENOMEM; if (countersize) memset(newinfo->counters, 0, countersize); - newinfo->entries = vmalloc(tmp.entries_size); + newinfo->entries = __vmalloc(tmp.entries_size, GFP_KERNEL_ACCOUNT, + PAGE_KERNEL); if (!newinfo->entries) { ret = -ENOMEM; goto free_newinfo; -- cgit v1.2.3-58-ga151 From 10f4e765879e514e1ce7f52ed26603047af196e2 Mon Sep 17 00:00:00 2001 From: wenxu Date: Thu, 10 Jan 2019 14:51:35 +0800 Subject: netfilter: nft_flow_offload: fix interaction with vrf slave device In the forward chain, the iif is changed from slave device to master vrf device. Thus, flow offload does not find a match on the lower slave device. This patch uses the cached route, ie. dst->dev, to update the iif and oif fields in the flow entry. After this patch, the following example works fine: # ip addr add dev eth0 1.1.1.1/24 # ip addr add dev eth1 10.0.0.1/24 # ip link add user1 type vrf table 1 # ip l set user1 up # ip l set dev eth0 master user1 # ip l set dev eth1 master user1 # nft add table firewall # nft add flowtable f fb1 { hook ingress priority 0 \; devices = { eth0, eth1 } \; } # nft add chain f ftb-all {type filter hook forward priority 0 \; policy accept \; } # nft add rule f ftb-all ct zone 1 ip protocol tcp flow offload @fb1 # nft add rule f ftb-all ct zone 1 ip protocol udp flow offload @fb1 Signed-off-by: wenxu Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_flow_table.h | 1 - net/netfilter/nf_flow_table_core.c | 5 +++-- net/netfilter/nft_flow_offload.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index 7d5cda7ce32a..3e370cb36263 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -84,7 +84,6 @@ struct flow_offload { struct nf_flow_route { struct { struct dst_entry *dst; - int ifindex; } tuple[FLOW_OFFLOAD_DIR_MAX]; }; diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index fa0844e2a68d..c0c72ae9df42 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -28,6 +28,7 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct, { struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple; struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple; + struct dst_entry *other_dst = route->tuple[!dir].dst; struct dst_entry *dst = route->tuple[dir].dst; ft->dir = dir; @@ -50,8 +51,8 @@ flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct, ft->src_port = ctt->src.u.tcp.port; ft->dst_port = ctt->dst.u.tcp.port; - ft->iifidx = route->tuple[dir].ifindex; - ft->oifidx = route->tuple[!dir].ifindex; + ft->iifidx = other_dst->dev->ifindex; + ft->oifidx = dst->dev->ifindex; ft->dst_cache = dst; } diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c index ccdb8f5ababb..188c6bbf4e16 100644 --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c @@ -30,9 +30,11 @@ static int nft_flow_route(const struct nft_pktinfo *pkt, switch (nft_pf(pkt)) { case NFPROTO_IPV4: fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip; + fl.u.ip4.flowi4_oif = nft_in(pkt)->ifindex; break; case NFPROTO_IPV6: fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6; + fl.u.ip6.flowi6_oif = nft_in(pkt)->ifindex; break; } @@ -41,9 +43,7 @@ static int nft_flow_route(const struct nft_pktinfo *pkt, return -ENOENT; route->tuple[dir].dst = this_dst; - route->tuple[dir].ifindex = nft_in(pkt)->ifindex; route->tuple[!dir].dst = other_dst; - route->tuple[!dir].ifindex = nft_out(pkt)->ifindex; return 0; } -- cgit v1.2.3-58-ga151 From 6325e01b6cdf4636b721cf7259c1616e3cf28ce2 Mon Sep 17 00:00:00 2001 From: Adit Ranadive Date: Wed, 9 Jan 2019 23:08:49 +0000 Subject: RDMA/vmw_pvrdma: Return the correct opcode when creating WR Since the IB_WR_REG_MR opcode value changed, let's set the PVRDMA device opcodes explicitly. Reported-by: Ruishuang Wang Fixes: 9a59739bd01f ("IB/rxe: Revise the ib_wr_opcode enum") Cc: stable@vger.kernel.org Reviewed-by: Bryan Tan Reviewed-by: Ruishuang Wang Reviewed-by: Vishnu Dasa Signed-off-by: Adit Ranadive Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/vmw_pvrdma/pvrdma.h | 35 +++++++++++++++++++++++++++- drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c | 6 +++++ include/uapi/rdma/vmw_pvrdma-abi.h | 1 + 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h index 42b8685c997e..3c633ab58052 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h @@ -427,7 +427,40 @@ static inline enum ib_qp_state pvrdma_qp_state_to_ib(enum pvrdma_qp_state state) static inline enum pvrdma_wr_opcode ib_wr_opcode_to_pvrdma(enum ib_wr_opcode op) { - return (enum pvrdma_wr_opcode)op; + switch (op) { + case IB_WR_RDMA_WRITE: + return PVRDMA_WR_RDMA_WRITE; + case IB_WR_RDMA_WRITE_WITH_IMM: + return PVRDMA_WR_RDMA_WRITE_WITH_IMM; + case IB_WR_SEND: + return PVRDMA_WR_SEND; + case IB_WR_SEND_WITH_IMM: + return PVRDMA_WR_SEND_WITH_IMM; + case IB_WR_RDMA_READ: + return PVRDMA_WR_RDMA_READ; + case IB_WR_ATOMIC_CMP_AND_SWP: + return PVRDMA_WR_ATOMIC_CMP_AND_SWP; + case IB_WR_ATOMIC_FETCH_AND_ADD: + return PVRDMA_WR_ATOMIC_FETCH_AND_ADD; + case IB_WR_LSO: + return PVRDMA_WR_LSO; + case IB_WR_SEND_WITH_INV: + return PVRDMA_WR_SEND_WITH_INV; + case IB_WR_RDMA_READ_WITH_INV: + return PVRDMA_WR_RDMA_READ_WITH_INV; + case IB_WR_LOCAL_INV: + return PVRDMA_WR_LOCAL_INV; + case IB_WR_REG_MR: + return PVRDMA_WR_FAST_REG_MR; + case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: + return PVRDMA_WR_MASKED_ATOMIC_CMP_AND_SWP; + case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: + return PVRDMA_WR_MASKED_ATOMIC_FETCH_AND_ADD; + case IB_WR_REG_SIG_MR: + return PVRDMA_WR_REG_SIG_MR; + default: + return PVRDMA_WR_ERROR; + } } static inline enum ib_wc_status pvrdma_wc_status_to_ib( diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c index 3acf74cbe266..1ec3646087ba 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c @@ -721,6 +721,12 @@ int pvrdma_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) wqe_hdr->ex.imm_data = wr->ex.imm_data; + if (unlikely(wqe_hdr->opcode == PVRDMA_WR_ERROR)) { + *bad_wr = wr; + ret = -EINVAL; + goto out; + } + switch (qp->ibqp.qp_type) { case IB_QPT_GSI: case IB_QPT_UD: diff --git a/include/uapi/rdma/vmw_pvrdma-abi.h b/include/uapi/rdma/vmw_pvrdma-abi.h index d13fd490b66d..6e73f0274e41 100644 --- a/include/uapi/rdma/vmw_pvrdma-abi.h +++ b/include/uapi/rdma/vmw_pvrdma-abi.h @@ -78,6 +78,7 @@ enum pvrdma_wr_opcode { PVRDMA_WR_MASKED_ATOMIC_FETCH_AND_ADD, PVRDMA_WR_BIND_MW, PVRDMA_WR_REG_SIG_MR, + PVRDMA_WR_ERROR, }; enum pvrdma_wc_status { -- cgit v1.2.3-58-ga151 From 9d9f59b4204bc41896c866b3e5856e5b416aa199 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 10 Jan 2019 08:15:45 +0200 Subject: RDMA/mthca: Clear QP objects during their allocation As part of audit process to update drivers to use rdma_restrack_add() ensure that QP objects is cleared before access. Such change fixes the crash observed with uninitialized non zero sgid attr accessed by ib_destroy_qp(). CPU: 3 PID: 74 Comm: kworker/u16:1 Not tainted 4.19.10-300.fc29.x86_64 Workqueue: ipoib_wq ipoib_cm_tx_reap [ib_ipoib] RIP: 0010:rdma_put_gid_attr+0x9/0x30 [ib_core] RSP: 0018:ffffb7ad819dbde8 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ffff8d1bdf5a2e00 RCX: 0000000000002699 RDX: 206c656e72656af8 RSI: ffff8d1bf7ae6160 RDI: 206c656e72656b20 RBP: 0000000000000000 R08: 0000000000026160 R09: ffffffffc06b45bf R10: ffffe849887da000 R11: 0000000000000002 R12: ffff8d1be30cb400 R13: ffff8d1bdf681800 R14: ffff8d1be2272400 R15: ffff8d1be30ca000 FS: 0000000000000000(0000) GS:ffff8d1bf7ac0000(0000) knlGS:0000000000000000 Trace: ib_destroy_qp+0xc9/0x240 [ib_core] ipoib_cm_tx_reap+0x1f9/0x4e0 [ib_ipoib] process_one_work+0x1a1/0x3a0 worker_thread+0x30/0x380 ? pwq_unbound_release_workfn+0xd0/0xd0 kthread+0x112/0x130 ? kthread_create_worker_on_cpu+0x70/0x70 ret_from_fork+0x22/0x40 Reported-by: Alexander Murashkin Tested-by: Alexander Murashkin Fixes: 1a1f460ff151 ("RDMA: Hold the sgid_attr inside the struct ib_ah/qp") Signed-off-by: Parav Pandit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe --- drivers/infiniband/hw/mthca/mthca_provider.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 82cb6b71ac7c..e3e9dd54caa2 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -534,7 +534,7 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd, { struct mthca_ucontext *context; - qp = kmalloc(sizeof *qp, GFP_KERNEL); + qp = kzalloc(sizeof(*qp), GFP_KERNEL); if (!qp) return ERR_PTR(-ENOMEM); @@ -600,7 +600,7 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd, if (udata) return ERR_PTR(-EINVAL); - qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL); + qp = kzalloc(sizeof(struct mthca_sqp), GFP_KERNEL); if (!qp) return ERR_PTR(-ENOMEM); -- cgit v1.2.3-58-ga151 From 5b0e7310a2a33c06edc7eb81ffc521af9b2c5610 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Wed, 9 Jan 2019 10:55:10 -0500 Subject: selinux: fix GPF on invalid policy levdatum->level can be NULL if we encounter an error while loading the policy during sens_read prior to initializing it. Make sure sens_destroy handles that case correctly. Reported-by: syzbot+6664500f0f18f07a5c0e@syzkaller.appspotmail.com Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index a50d625e7946..c1c31e33657a 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -732,7 +732,8 @@ static int sens_destroy(void *key, void *datum, void *p) kfree(key); if (datum) { levdatum = datum; - ebitmap_destroy(&levdatum->level->cat); + if (levdatum->level) + ebitmap_destroy(&levdatum->level->cat); kfree(levdatum->level); } kfree(datum); -- cgit v1.2.3-58-ga151 From 15f77c4ade3364106a3a397f0a8d6fce9d6a6326 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 11 Jan 2019 16:08:20 +1000 Subject: drm/nouveau: register backlight on pascal and newer Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_backlight.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 5f5be6368aed..c7a94c94dbf3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -253,6 +253,9 @@ nouveau_backlight_init(struct drm_connector *connector) case NV_DEVICE_INFO_V0_FERMI: case NV_DEVICE_INFO_V0_KEPLER: case NV_DEVICE_INFO_V0_MAXWELL: + case NV_DEVICE_INFO_V0_PASCAL: + case NV_DEVICE_INFO_V0_VOLTA: + case NV_DEVICE_INFO_V0_TURING: ret = nv50_backlight_init(nv_encoder, &props, &ops); break; default: -- cgit v1.2.3-58-ga151 From 118780066e30c34de3d9349710b51780bfa0ba83 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 12 Sep 2018 12:58:43 +0200 Subject: drm/nouveau: Don't disable polling in fallback mode When a fan is controlled via linear fallback without cstate, we shouldn't stop polling. Otherwise it won't be adjusted again and keeps running at an initial crazy pace. Fixes: 800efb4c2857 ("drm/nouveau/drm/therm/fan: add a fallback if no fan control is specified in the vbios") Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1103356 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=107447 Reported-by: Thomas Blume Signed-off-by: Takashi Iwai Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index 3695cde669f8..07914e36939e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -132,11 +132,12 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) duty = nvkm_therm_update_linear(therm); break; case NVBIOS_THERM_FAN_OTHER: - if (therm->cstate) + if (therm->cstate) { duty = therm->cstate; - else + poll = false; + } else { duty = nvkm_therm_update_linear_fallback(therm); - poll = false; + } break; } immd = false; -- cgit v1.2.3-58-ga151 From a5176a4cb85bb6213daadf691097cf411da35df2 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Thu, 13 Dec 2018 22:44:08 -0500 Subject: drm/nouveau/falcon: avoid touching registers if engine is off Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=108980 Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 816ccaedfc73..8675613e142b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -107,8 +108,10 @@ nvkm_falcon_fini(struct nvkm_engine *engine, bool suspend) } } - nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000); - nvkm_wr32(device, base + 0x014, 0xffffffff); + if (nvkm_mc_enabled(device, engine->subdev.index)) { + nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000); + nvkm_wr32(device, base + 0x014, 0xffffffff); + } return 0; } -- cgit v1.2.3-58-ga151 From d04e779fb1dbeedf8a60b66d0d0048be4e65d366 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 10 Jan 2019 14:07:42 +0000 Subject: gpio: pca953x: Make symbol 'pca953x_i2c_regmap' static Fixes the following sparse warning: drivers/gpio/gpio-pca953x.c:292:28: warning: symbol 'pca953x_i2c_regmap' was not declared. Should it be static? Fixes: 49427232764d ("gpio: pca953x: Perform basic regmap conversion") Signed-off-by: Wei Yongjun Reviewed-by: Marek Vasut Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 83617fdc661d..0dc96419efe3 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -289,7 +289,7 @@ static bool pca953x_volatile_register(struct device *dev, unsigned int reg) return pca953x_check_register(chip, reg, bank); } -const struct regmap_config pca953x_i2c_regmap = { +static const struct regmap_config pca953x_i2c_regmap = { .reg_bits = 8, .val_bits = 8, -- cgit v1.2.3-58-ga151 From 849d540ddfcd4f232f3b2cf40a2e07eccbd6212c Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 2 Jan 2019 12:32:18 +0100 Subject: binderfs: implement "max" mount option Since binderfs can be mounted by userns root in non-initial user namespaces some precautions are in order. First, a way to set a maximum on the number of binder devices that can be allocated per binderfs instance and second, a way to reserve a reasonable chunk of binderfs devices for the initial ipc namespace. A first approach as seen in [1] used sysctls similiar to devpts but was shown to be flawed (cf. [2] and [3]) since some aspects were unneeded. This is an alternative approach which avoids sysctls completely and instead switches to a single mount option. Starting with this commit binderfs instances can be mounted with a limit on the number of binder devices that can be allocated. The max= mount option serves as a per-instance limit. If max= is set then only number of binder devices can be allocated in this binderfs instance. This allows to safely bind-mount binderfs instances into unprivileged user namespaces since userns root in a non-initial user namespace cannot change the mount option as long as it does not own the mount namespace the binderfs mount was created in and hence cannot drain the host of minor device numbers [1]: https://lore.kernel.org/lkml/20181221133909.18794-1-christian@brauner.io/ [2]; https://lore.kernel.org/lkml/20181221163316.GA8517@kroah.com/ [3]: https://lore.kernel.org/lkml/CAHRSSEx+gDVW4fKKK8oZNAir9G5icJLyodO8hykv3O0O1jt2FQ@mail.gmail.com/ [4]: https://lore.kernel.org/lkml/20181221192044.5yvfnuri7gdop4rs@brauner.io/ Cc: Todd Kjos Cc: Greg Kroah-Hartman Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 104 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 6 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 4990d65d4850..89788969bc04 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,24 @@ static dev_t binderfs_dev; static DEFINE_MUTEX(binderfs_minors_mutex); static DEFINE_IDA(binderfs_minors); +/** + * binderfs_mount_opts - mount options for binderfs + * @max: maximum number of allocatable binderfs binder devices + */ +struct binderfs_mount_opts { + int max; +}; + +enum { + Opt_max, + Opt_err +}; + +static const match_table_t tokens = { + { Opt_max, "max=%d" }, + { Opt_err, NULL } +}; + /** * binderfs_info - information about a binderfs mount * @ipc_ns: The ipc namespace the binderfs mount belongs to. @@ -53,13 +72,16 @@ static DEFINE_IDA(binderfs_minors); * created. * @root_gid: gid that needs to be used when a new binder device is * created. + * @mount_opts: The mount options in use. + * @device_count: The current number of allocated binder devices. */ struct binderfs_info { struct ipc_namespace *ipc_ns; struct dentry *control_dentry; kuid_t root_uid; kgid_t root_gid; - + struct binderfs_mount_opts mount_opts; + int device_count; }; static inline struct binderfs_info *BINDERFS_I(const struct inode *inode) @@ -108,10 +130,17 @@ static int binderfs_binder_device_create(struct inode *ref_inode, /* Reserve new minor number for the new device. */ mutex_lock(&binderfs_minors_mutex); - minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, GFP_KERNEL); - mutex_unlock(&binderfs_minors_mutex); - if (minor < 0) + if (++info->device_count <= info->mount_opts.max) + minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, + GFP_KERNEL); + else + minor = -ENOSPC; + if (minor < 0) { + --info->device_count; + mutex_unlock(&binderfs_minors_mutex); return minor; + } + mutex_unlock(&binderfs_minors_mutex); ret = -ENOMEM; device = kzalloc(sizeof(*device), GFP_KERNEL); @@ -185,6 +214,7 @@ err: kfree(name); kfree(device); mutex_lock(&binderfs_minors_mutex); + --info->device_count; ida_free(&binderfs_minors, minor); mutex_unlock(&binderfs_minors_mutex); iput(inode); @@ -230,6 +260,7 @@ static long binder_ctl_ioctl(struct file *file, unsigned int cmd, static void binderfs_evict_inode(struct inode *inode) { struct binder_device *device = inode->i_private; + struct binderfs_info *info = BINDERFS_I(inode); clear_inode(inode); @@ -237,6 +268,7 @@ static void binderfs_evict_inode(struct inode *inode) return; mutex_lock(&binderfs_minors_mutex); + --info->device_count; ida_free(&binderfs_minors, device->miscdev.minor); mutex_unlock(&binderfs_minors_mutex); @@ -244,9 +276,65 @@ static void binderfs_evict_inode(struct inode *inode) kfree(device); } +/** + * binderfs_parse_mount_opts - parse binderfs mount options + * @data: options to set (can be NULL in which case defaults are used) + */ +static int binderfs_parse_mount_opts(char *data, + struct binderfs_mount_opts *opts) +{ + char *p; + opts->max = BINDERFS_MAX_MINOR; + + while ((p = strsep(&data, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + int token; + int max_devices; + + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case Opt_max: + if (match_int(&args[0], &max_devices) || + (max_devices < 0 || + (max_devices > BINDERFS_MAX_MINOR))) + return -EINVAL; + + opts->max = max_devices; + break; + default: + pr_err("Invalid mount options\n"); + return -EINVAL; + } + } + + return 0; +} + +static int binderfs_remount(struct super_block *sb, int *flags, char *data) +{ + struct binderfs_info *info = sb->s_fs_info; + return binderfs_parse_mount_opts(data, &info->mount_opts); +} + +static int binderfs_show_mount_opts(struct seq_file *seq, struct dentry *root) +{ + struct binderfs_info *info; + + info = root->d_sb->s_fs_info; + if (info->mount_opts.max <= BINDERFS_MAX_MINOR) + seq_printf(seq, ",max=%d", info->mount_opts.max); + + return 0; +} + static const struct super_operations binderfs_super_ops = { - .statfs = simple_statfs, - .evict_inode = binderfs_evict_inode, + .evict_inode = binderfs_evict_inode, + .remount_fs = binderfs_remount, + .show_options = binderfs_show_mount_opts, + .statfs = simple_statfs, }; static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry, @@ -407,6 +495,10 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) if (!info) goto err_without_dentry; + ret = binderfs_parse_mount_opts(data, &info->mount_opts); + if (ret) + goto err_without_dentry; + info->ipc_ns = ipc_ns; info->root_gid = make_kgid(sb->s_user_ns, 0); if (!gid_valid(info->root_gid)) -- cgit v1.2.3-58-ga151 From c13295ad219d8bb0e47942d4cfc8251de449a67e Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 11 Jan 2019 00:25:41 +0100 Subject: binderfs: rename header to binderfs.h It doesn't make sense to call the header binder_ctl.h when its sole existence is tied to binderfs. So give it a sensible name. Users will far more easily remember binderfs.h than binder_ctl.h. Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 2 +- include/uapi/linux/android/binder_ctl.h | 35 --------------------------------- include/uapi/linux/android/binderfs.h | 35 +++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 36 deletions(-) delete mode 100644 include/uapi/linux/android/binder_ctl.h create mode 100644 include/uapi/linux/android/binderfs.h diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 89788969bc04..f6341893b5ba 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "binder_internal.h" diff --git a/include/uapi/linux/android/binder_ctl.h b/include/uapi/linux/android/binder_ctl.h deleted file mode 100644 index 65b2efd1a0a5..000000000000 --- a/include/uapi/linux/android/binder_ctl.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright (C) 2018 Canonical Ltd. - * - */ - -#ifndef _UAPI_LINUX_BINDER_CTL_H -#define _UAPI_LINUX_BINDER_CTL_H - -#include -#include -#include - -#define BINDERFS_MAX_NAME 255 - -/** - * struct binderfs_device - retrieve information about a new binder device - * @name: the name to use for the new binderfs binder device - * @major: major number allocated for binderfs binder devices - * @minor: minor number allocated for the new binderfs binder device - * - */ -struct binderfs_device { - char name[BINDERFS_MAX_NAME + 1]; - __u8 major; - __u8 minor; -}; - -/** - * Allocate a new binder device. - */ -#define BINDER_CTL_ADD _IOWR('b', 1, struct binderfs_device) - -#endif /* _UAPI_LINUX_BINDER_CTL_H */ - diff --git a/include/uapi/linux/android/binderfs.h b/include/uapi/linux/android/binderfs.h new file mode 100644 index 000000000000..65b2efd1a0a5 --- /dev/null +++ b/include/uapi/linux/android/binderfs.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2018 Canonical Ltd. + * + */ + +#ifndef _UAPI_LINUX_BINDER_CTL_H +#define _UAPI_LINUX_BINDER_CTL_H + +#include +#include +#include + +#define BINDERFS_MAX_NAME 255 + +/** + * struct binderfs_device - retrieve information about a new binder device + * @name: the name to use for the new binderfs binder device + * @major: major number allocated for binderfs binder devices + * @minor: minor number allocated for the new binderfs binder device + * + */ +struct binderfs_device { + char name[BINDERFS_MAX_NAME + 1]; + __u8 major; + __u8 minor; +}; + +/** + * Allocate a new binder device. + */ +#define BINDER_CTL_ADD _IOWR('b', 1, struct binderfs_device) + +#endif /* _UAPI_LINUX_BINDER_CTL_H */ + -- cgit v1.2.3-58-ga151 From 06382deac2b8a49bbc5aaa3c9118fed6da4a1ac1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 11 Jan 2019 10:40:13 +0100 Subject: Revert "staging: rtl8723bs: Mark ACPI table declaration as used" This reverts commit e6d093719e22a09e778edde192dfd89a0cd77b5c. Turns out it is not needed at all, a fix for clang was made and accepted upstream in that project that makes this change unnecessary. So revert it. Reported-by: Nick Desaulniers Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c index 7c03b69b8ed3..6d02904de63f 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c @@ -22,7 +22,7 @@ static const struct sdio_device_id sdio_ids[] = { SDIO_DEVICE(0x024c, 0xb723), }, { /* end: all zeroes */ }, }; -static const struct acpi_device_id acpi_ids[] __used = { +static const struct acpi_device_id acpi_ids[] = { {"OBDA8723", 0x0000}, {} }; -- cgit v1.2.3-58-ga151 From 17e3ac812541f73224299d8958ddb420c2d5bbd8 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 10 Jan 2019 11:14:00 -0800 Subject: bpf: fix bpffs bitfield pretty print Commit 9d5f9f701b18 ("bpf: btf: fix struct/union/fwd types with kind_flag") introduced kind_flag and used bitfield_size in the btf_member to directly pretty print member values. The commit contained a bug where the incorrect parameters could be passed to function btf_bitfield_seq_show(). The bits_offset parameter in the function expects a value less than 8. Instead, the member offset in the structure is passed. The below is btf_bitfield_seq_show() func signature: void btf_bitfield_seq_show(void *data, u8 bits_offset, u8 nr_bits, struct seq_file *m) both bits_offset and nr_bits are u8 type. If the bitfield member offset is greater than 256, incorrect value will be printed. This patch fixed the issue by calculating correct proper data offset and bits_offset similar to non kind_flag case. Fixes: 9d5f9f701b18 ("bpf: btf: fix struct/union/fwd types with kind_flag") Acked-by: Martin KaFai Lau Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- kernel/bpf/btf.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 715f9fcf4712..a2f53642592b 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -1219,8 +1219,6 @@ static void btf_bitfield_seq_show(void *data, u8 bits_offset, u8 nr_copy_bits; u64 print_num; - data += BITS_ROUNDDOWN_BYTES(bits_offset); - bits_offset = BITS_PER_BYTE_MASKED(bits_offset); nr_copy_bits = nr_bits + bits_offset; nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits); @@ -1255,7 +1253,9 @@ static void btf_int_bits_seq_show(const struct btf *btf, * BTF_INT_OFFSET() cannot exceed 64 bits. */ total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data); - btf_bitfield_seq_show(data, total_bits_offset, nr_bits, m); + data += BITS_ROUNDDOWN_BYTES(total_bits_offset); + bits_offset = BITS_PER_BYTE_MASKED(total_bits_offset); + btf_bitfield_seq_show(data, bits_offset, nr_bits, m); } static void btf_int_seq_show(const struct btf *btf, const struct btf_type *t, @@ -2001,12 +2001,12 @@ static void btf_struct_seq_show(const struct btf *btf, const struct btf_type *t, member_offset = btf_member_bit_offset(t, member); bitfield_size = btf_member_bitfield_size(t, member); + bytes_offset = BITS_ROUNDDOWN_BYTES(member_offset); + bits8_offset = BITS_PER_BYTE_MASKED(member_offset); if (bitfield_size) { - btf_bitfield_seq_show(data, member_offset, + btf_bitfield_seq_show(data + bytes_offset, bits8_offset, bitfield_size, m); } else { - bytes_offset = BITS_ROUNDDOWN_BYTES(member_offset); - bits8_offset = BITS_PER_BYTE_MASKED(member_offset); ops = btf_type_ops(member_type); ops->seq_show(btf, member_type, member->type, data + bytes_offset, bits8_offset, m); -- cgit v1.2.3-58-ga151 From e43207fa2e6130e39e3aca4c55e2ee21cfb46828 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 10 Jan 2019 11:14:01 -0800 Subject: tools/bpf: test btf bitfield with >=256 struct member offset This patch modified test_btf pretty print test to cover the bitfield with struct member equal to or greater 256. Without the previous kernel patch fix, the modified test will fail: $ test_btf -p ...... BTF pretty print array(#1)......unexpected pprint output expected: 0: {0,0,0,0x3,0x0,0x3,{0|[0,0,0,0,0,0,0,0]},ENUM_ZERO,4,0x1} read: 0: {0,0,0,0x3,0x0,0x3,{0|[0,0,0,0,0,0,0,0]},ENUM_ZERO,4,0x0} BTF pretty print array(#2)......unexpected pprint output expected: 0: {0,0,0,0x3,0x0,0x3,{0|[0,0,0,0,0,0,0,0]},ENUM_ZERO,4,0x1} read: 0: {0,0,0,0x3,0x0,0x3,{0|[0,0,0,0,0,0,0,0]},ENUM_ZERO,4,0x0} PASS:6 SKIP:0 FAIL:2 With the kernel fix, the modified test will succeed: $ test_btf -p ...... BTF pretty print array(#1)......OK BTF pretty print array(#2)......OK PASS:8 SKIP:0 FAIL:0 Fixes: 9d5f9f701b18 ("bpf: btf: fix struct/union/fwd types with kind_flag") Acked-by: Martin KaFai Lau Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_btf.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index 8bcd38010582..a0bd04befe87 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c @@ -3526,6 +3526,8 @@ struct pprint_mapv { ENUM_TWO, ENUM_THREE, } aenum; + uint32_t ui32b; + uint32_t bits2c:2; }; static struct btf_raw_test pprint_test_template[] = { @@ -3568,7 +3570,7 @@ static struct btf_raw_test pprint_test_template[] = { BTF_ENUM_ENC(NAME_TBD, 2), BTF_ENUM_ENC(NAME_TBD, 3), /* struct pprint_mapv */ /* [16] */ - BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 8), 32), + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 10), 40), BTF_MEMBER_ENC(NAME_TBD, 11, 0), /* uint32_t ui32 */ BTF_MEMBER_ENC(NAME_TBD, 10, 32), /* uint16_t ui16 */ BTF_MEMBER_ENC(NAME_TBD, 12, 64), /* int32_t si32 */ @@ -3577,9 +3579,11 @@ static struct btf_raw_test pprint_test_template[] = { BTF_MEMBER_ENC(NAME_TBD, 6, 126), /* unused_bits2b */ BTF_MEMBER_ENC(0, 14, 128), /* union (anon) */ BTF_MEMBER_ENC(NAME_TBD, 15, 192), /* aenum */ + BTF_MEMBER_ENC(NAME_TBD, 11, 224), /* uint32_t ui32b */ + BTF_MEMBER_ENC(NAME_TBD, 6, 256), /* bits2c */ BTF_END_RAW, }, - BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"), + BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c"), .key_size = sizeof(unsigned int), .value_size = sizeof(struct pprint_mapv), .key_type_id = 3, /* unsigned int */ @@ -3628,7 +3632,7 @@ static struct btf_raw_test pprint_test_template[] = { BTF_ENUM_ENC(NAME_TBD, 2), BTF_ENUM_ENC(NAME_TBD, 3), /* struct pprint_mapv */ /* [16] */ - BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 8), 32), + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 10), 40), BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)), /* uint32_t ui32 */ BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* uint16_t ui16 */ BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* int32_t si32 */ @@ -3637,9 +3641,11 @@ static struct btf_raw_test pprint_test_template[] = { BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 126)), /* unused_bits2b */ BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)), /* union (anon) */ BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)), /* aenum */ + BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 224)), /* uint32_t ui32b */ + BTF_MEMBER_ENC(NAME_TBD, 6, BTF_MEMBER_OFFSET(2, 256)), /* bits2c */ BTF_END_RAW, }, - BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"), + BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c"), .key_size = sizeof(unsigned int), .value_size = sizeof(struct pprint_mapv), .key_type_id = 3, /* unsigned int */ @@ -3690,7 +3696,7 @@ static struct btf_raw_test pprint_test_template[] = { BTF_ENUM_ENC(NAME_TBD, 2), BTF_ENUM_ENC(NAME_TBD, 3), /* struct pprint_mapv */ /* [16] */ - BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 8), 32), + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 10), 40), BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 0)), /* uint32_t ui32 */ BTF_MEMBER_ENC(NAME_TBD, 10, BTF_MEMBER_OFFSET(0, 32)), /* uint16_t ui16 */ BTF_MEMBER_ENC(NAME_TBD, 12, BTF_MEMBER_OFFSET(0, 64)), /* int32_t si32 */ @@ -3699,13 +3705,15 @@ static struct btf_raw_test pprint_test_template[] = { BTF_MEMBER_ENC(NAME_TBD, 19, BTF_MEMBER_OFFSET(2, 126)),/* unused_bits2b */ BTF_MEMBER_ENC(0, 14, BTF_MEMBER_OFFSET(0, 128)), /* union (anon) */ BTF_MEMBER_ENC(NAME_TBD, 15, BTF_MEMBER_OFFSET(0, 192)), /* aenum */ + BTF_MEMBER_ENC(NAME_TBD, 11, BTF_MEMBER_OFFSET(0, 224)), /* uint32_t ui32b */ + BTF_MEMBER_ENC(NAME_TBD, 17, BTF_MEMBER_OFFSET(2, 256)), /* bits2c */ /* typedef unsigned int ___int */ /* [17] */ BTF_TYPEDEF_ENC(NAME_TBD, 18), BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_VOLATILE, 0, 0), 6), /* [18] */ BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 15), /* [19] */ BTF_END_RAW, }, - BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0___int"), + BTF_STR_SEC("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum\0ui32b\0bits2c\0___int"), .key_size = sizeof(unsigned int), .value_size = sizeof(struct pprint_mapv), .key_type_id = 3, /* unsigned int */ @@ -3793,6 +3801,8 @@ static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i, v->unused_bits2b = 3; v->ui64 = i; v->aenum = i & 0x03; + v->ui32b = 4; + v->bits2c = 1; v = (void *)v + rounded_value_size; } } @@ -3955,7 +3965,8 @@ static int do_test_pprint(int test_num) nexpected_line = snprintf(expected_line, sizeof(expected_line), "%s%u: {%u,0,%d,0x%x,0x%x,0x%x," - "{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n", + "{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s," + "%u,0x%x}\n", percpu_map ? "\tcpu" : "", percpu_map ? cpu : next_key, cmapv->ui32, cmapv->si32, @@ -3967,7 +3978,9 @@ static int do_test_pprint(int test_num) cmapv->ui8a[2], cmapv->ui8a[3], cmapv->ui8a[4], cmapv->ui8a[5], cmapv->ui8a[6], cmapv->ui8a[7], - pprint_enum_str[cmapv->aenum]); + pprint_enum_str[cmapv->aenum], + cmapv->ui32b, + cmapv->bits2c); err = check_line(expected_line, nexpected_line, sizeof(expected_line), line); -- cgit v1.2.3-58-ga151 From 298e59d322954e89ed2a556c601a04a4c007d1b3 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 10 Jan 2019 11:14:02 -0800 Subject: tools/bpf: fix bpftool map dump with bitfields Commit 8772c8bc093b ("tools: bpftool: support pretty print with kind_flag set") added bpftool map dump with kind_flag support. When bitfield_size can be retrieved directly from btf_member, function btf_dumper_bitfield() is called to dump the bitfield. The implementation passed the wrong parameter "bit_offset" to the function. The excepted value is the bit_offset within a byte while the passed-in value is the struct member offset. This commit fixed the bug with passing correct "bit_offset" with adjusted data pointer. Fixes: 8772c8bc093b ("tools: bpftool: support pretty print with kind_flag set") Acked-by: Martin KaFai Lau Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/btf_dumper.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c index 3f0629edbca5..6ba5f567a9d8 100644 --- a/tools/bpf/bpftool/btf_dumper.c +++ b/tools/bpf/bpftool/btf_dumper.c @@ -82,8 +82,6 @@ static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset, int bits_to_copy; __u64 print_num; - data += BITS_ROUNDDOWN_BYTES(bit_offset); - bit_offset = BITS_PER_BYTE_MASKED(bit_offset); bits_to_copy = bit_offset + nr_bits; bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy); @@ -118,7 +116,9 @@ static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset, * BTF_INT_OFFSET() cannot exceed 64 bits. */ total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type); - btf_dumper_bitfield(nr_bits, total_bits_offset, data, jw, + data += BITS_ROUNDDOWN_BYTES(total_bits_offset); + bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset); + btf_dumper_bitfield(nr_bits, bit_offset, data, jw, is_plain_text); } @@ -216,11 +216,12 @@ static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id, } jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off)); + data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset); if (bitfield_size) { - btf_dumper_bitfield(bitfield_size, bit_offset, - data, d->jw, d->is_plain_text); + btf_dumper_bitfield(bitfield_size, + BITS_PER_BYTE_MASKED(bit_offset), + data_off, d->jw, d->is_plain_text); } else { - data_off = data + BITS_ROUNDDOWN_BYTES(bit_offset); ret = btf_dumper_do_type(d, m[i].type, BITS_PER_BYTE_MASKED(bit_offset), data_off); -- cgit v1.2.3-58-ga151 From c7777236dd8f587f6a8d6800c03df318fd4d2627 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Thu, 10 Jan 2019 18:41:51 +0000 Subject: ACPI/IORT: Fix rc_dma_get_range() When executed for a PCI_ROOT_COMPLEX type, iort_match_node_callback() expects the opaque pointer argument to be a PCI bus device. At the moment rc_dma_get_range() passes the PCI endpoint instead of the bus, and we've been lucky to have pci_domain_nr(ptr) return 0 instead of crashing. Pass the bus device to iort_scan_node(). Fixes: 5ac65e8c8941 ("ACPI/IORT: Support address size limit for root complexes") Reported-by: Eric Auger Signed-off-by: Jean-Philippe Brucker Signed-off-by: Lorenzo Pieralisi Reviewed-by: Eric Auger Acked-by: Robin Murphy Cc: stable@vger.kernel.org Cc: Will Deacon Cc: Hanjun Guo Cc: Sudeep Holla Cc: Catalin Marinas Cc: "Rafael J. Wysocki" Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 5d29783ee5bd..e48894e002ba 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -952,9 +952,10 @@ static int rc_dma_get_range(struct device *dev, u64 *size) { struct acpi_iort_node *node; struct acpi_iort_root_complex *rc; + struct pci_bus *pbus = to_pci_dev(dev)->bus; node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX, - iort_match_node_callback, dev); + iort_match_node_callback, &pbus->dev); if (!node || node->revision < 1) return -ENODEV; -- cgit v1.2.3-58-ga151 From 279667212ab2a4f36c3b0347657ddcc11f9cfa25 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 11 Jan 2019 16:40:21 +0900 Subject: arm64: kexec_file: return successfully even if kaslr-seed doesn't exist In kexec_file_load, kaslr-seed property of the current dtb will be deleted any way before setting a new value if possible. It doesn't matter whether it exists in the current dtb. So "ret" should be reset to 0 here. Fixes: commit 884143f60c89 ("arm64: kexec_file: add kaslr support") Signed-off-by: AKASHI Takahiro Signed-off-by: Will Deacon --- arch/arm64/kernel/machine_kexec_file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c index 10e33860e47a..f2c211a6229b 100644 --- a/arch/arm64/kernel/machine_kexec_file.c +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -87,7 +87,9 @@ static int setup_dtb(struct kimage *image, /* add kaslr-seed */ ret = fdt_delprop(dtb, off, FDT_PROP_KASLR_SEED); - if (ret && (ret != -FDT_ERR_NOTFOUND)) + if (ret == -FDT_ERR_NOTFOUND) + ret = 0; + else if (ret) goto out; if (rng_is_initialized()) { -- cgit v1.2.3-58-ga151 From e8e683ae9a736407a20135df7809090a446db707 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 7 Jan 2019 17:04:50 +0000 Subject: iommu/of: Fix probe-deferral Whilst iommu_probe_device() does check for non-NULL ops as the previous code did, it does not do so in the same order relative to the other checks, and as a result means that -EPROBE_DEFER returned by of_xlate() (plus any real error condition too) gets overwritten with -EINVAL and leads to various misbehaviour. Reinstate the original logic, but without implicitly relying on ops being set to infer !err as the initial condition (now that the validity of ops for its own sake is checked elsewhere). Fixes: 641fb0efbff0 ("iommu/of: Don't call iommu_ops->add_device directly") Signed-off-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/of_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index d8947b28db2d..f04a6df65eb8 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -224,7 +224,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev, * If we have reason to believe the IOMMU driver missed the initial * probe for dev, replay it to get things in order. */ - if (dev->bus && !device_iommu_mapped(dev)) + if (!err && dev->bus && !device_iommu_mapped(dev)) err = iommu_probe_device(dev); /* Ignore all other errors apart from EPROBE_DEFER */ -- cgit v1.2.3-58-ga151 From 21face6f0d4d033d949d5517f307a15f76a9d9f2 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 4 Jan 2019 23:55:27 -0600 Subject: ARM: integrator: impd1: use struct_size() in devm_kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = devm_kzalloc(dev, sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva --- arch/arm/mach-integrator/impd1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index 0f916c245a2e..8dfad012dfae 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -390,7 +390,7 @@ static int __ref impd1_probe(struct lm_device *dev) char *mmciname; lookup = devm_kzalloc(&dev->dev, - sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup), + struct_size(lookup, table, 3), GFP_KERNEL); chipname = devm_kstrdup(&dev->dev, devname, GFP_KERNEL); mmciname = devm_kasprintf(&dev->dev, GFP_KERNEL, -- cgit v1.2.3-58-ga151 From 36bdf3cae09df891b191f3955c8e54a2e05d67d0 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 11 Jan 2019 11:19:40 +0100 Subject: binderfs: reserve devices for initial mount The binderfs instance in the initial ipc namespace will always have a reserve of 4 binder devices unless explicitly capped by specifying a lower value via the "max" mount option. This ensures when binder devices are removed (on accident or on purpose) they can always be recreated without risking that all minor numbers have already been used up. Cc: Todd Kjos Cc: Greg Kroah-Hartman Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index f6341893b5ba..ad3ad2f7f9f4 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -40,6 +40,8 @@ #define INODE_OFFSET 3 #define INTSTRLEN 21 #define BINDERFS_MAX_MINOR (1U << MINORBITS) +/* Ensure that the initial ipc namespace always has devices available. */ +#define BINDERFS_MAX_MINOR_CAPPED (BINDERFS_MAX_MINOR - 4) static dev_t binderfs_dev; static DEFINE_MUTEX(binderfs_minors_mutex); @@ -127,11 +129,14 @@ static int binderfs_binder_device_create(struct inode *ref_inode, struct inode *inode = NULL; struct super_block *sb = ref_inode->i_sb; struct binderfs_info *info = sb->s_fs_info; + bool use_reserve = (info->ipc_ns == &init_ipc_ns); /* Reserve new minor number for the new device. */ mutex_lock(&binderfs_minors_mutex); if (++info->device_count <= info->mount_opts.max) - minor = ida_alloc_max(&binderfs_minors, BINDERFS_MAX_MINOR, + minor = ida_alloc_max(&binderfs_minors, + use_reserve ? BINDERFS_MAX_MINOR : + BINDERFS_MAX_MINOR_CAPPED, GFP_KERNEL); else minor = -ENOSPC; -- cgit v1.2.3-58-ga151 From d7b6cc199b2dea602b4a2a681cf6d3223a61e2be Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 9 Jan 2019 13:23:29 +0300 Subject: powerpc/powernv/npu: Allocate enough memory in pnv_try_setup_npu_table_group() There is a typo so we accidentally allocate enough memory for a pointer when we wanted to allocate enough for a struct. Fixes: 0bd971676e68 ("powerpc/powernv/npu: Add compound IOMMU groups") Signed-off-by: Dan Carpenter Reviewed-by: Alexey Kardashevskiy Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/npu-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c index d7f742ed48ba..3f58c7dbd581 100644 --- a/arch/powerpc/platforms/powernv/npu-dma.c +++ b/arch/powerpc/platforms/powernv/npu-dma.c @@ -564,7 +564,7 @@ struct iommu_table_group *pnv_try_setup_npu_table_group(struct pnv_ioda_pe *pe) } } else { /* Create a group for 1 GPU and attached NPUs for POWER8 */ - pe->npucomp = kzalloc(sizeof(pe->npucomp), GFP_KERNEL); + pe->npucomp = kzalloc(sizeof(*pe->npucomp), GFP_KERNEL); table_group = &pe->npucomp->table_group; table_group->ops = &pnv_npu_peers_ops; iommu_register_group(table_group, hose->global_number, -- cgit v1.2.3-58-ga151 From fb0bdec51a4901b7dd088de0a1e365e1b9f5cd21 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 9 Jan 2019 20:30:07 +0000 Subject: powerpc/8xx: fix setting of pagetable for Abatron BDI debug tool. Commit 8c8c10b90d88 ("powerpc/8xx: fix handling of early NULL pointer dereference") moved the loading of r6 earlier in the code. As some functions are called inbetween, r6 needs to be loaded again with the address of swapper_pg_dir in order to set PTE pointers for the Abatron BDI. Fixes: 8c8c10b90d88 ("powerpc/8xx: fix handling of early NULL pointer dereference") Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/head_8xx.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 57deb1e9ffea..20cc816b3508 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S @@ -852,11 +852,12 @@ start_here: /* set up the PTE pointers for the Abatron bdiGDB. */ - tovirt(r6,r6) lis r5, abatron_pteptrs@h ori r5, r5, abatron_pteptrs@l stw r5, 0xf0(0) /* Must match your Abatron config file */ tophys(r5,r5) + lis r6, swapper_pg_dir@h + ori r6, r6, swapper_pg_dir@l stw r6, 0(r5) /* Now turn on the MMU for real! */ -- cgit v1.2.3-58-ga151 From 897bc3df8c5aebb54c32d831f917592e873d0559 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 9 Jan 2019 11:16:45 -0200 Subject: powerpc/tm: Limit TM code inside PPC_TRANSACTIONAL_MEM Commit e1c3743e1a20 ("powerpc/tm: Set MSR[TS] just prior to recheckpoint") moved a code block around and this block uses a 'msr' variable outside of the CONFIG_PPC_TRANSACTIONAL_MEM, however the 'msr' variable is declared inside a CONFIG_PPC_TRANSACTIONAL_MEM block, causing a possible error when CONFIG_PPC_TRANSACTION_MEM is not defined. error: 'msr' undeclared (first use in this function) This is not causing a compilation error in the mainline kernel, because 'msr' is being used as an argument of MSR_TM_ACTIVE(), which is defined as the following when CONFIG_PPC_TRANSACTIONAL_MEM is *not* set: #define MSR_TM_ACTIVE(x) 0 This patch just fixes this issue avoiding the 'msr' variable usage outside the CONFIG_PPC_TRANSACTIONAL_MEM block, avoiding trusting in the MSR_TM_ACTIVE() definition. Cc: stable@vger.kernel.org Reported-by: Christoph Biedl Fixes: e1c3743e1a20 ("powerpc/tm: Set MSR[TS] just prior to recheckpoint") Signed-off-by: Breno Leitao Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/signal_64.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index bd5e6834ca69..6794466f6420 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -755,11 +755,12 @@ SYSCALL_DEFINE0(rt_sigreturn) if (restore_tm_sigcontexts(current, &uc->uc_mcontext, &uc_transact->uc_mcontext)) goto badframe; - } + } else #endif - /* Fall through, for non-TM restore */ - if (!MSR_TM_ACTIVE(msr)) { + { /* + * Fall through, for non-TM restore + * * Unset MSR[TS] on the thread regs since MSR from user * context does not have MSR active, and recheckpoint was * not called since restore_tm_sigcontexts() was not called -- cgit v1.2.3-58-ga151 From 6bca515917515b66b7e1dfc1d1d3b7bd8058315c Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Wed, 9 Jan 2019 16:13:42 +0100 Subject: powerpc/powernv/npu: Fix oops in pnv_try_setup_npu_table_group() With a recent change around IOMMU group, a system with an opencapi adapter is no longer booting and we get a kernel oops: BUG: Kernel NULL pointer dereference at 0x00000028 Faulting instruction address: 0xc0000000000aa38c ... NIP pnv_try_setup_npu_table_group+0x1c/0x1a0 LR pnv_pci_ioda_fixup+0x1f8/0x660 Call Trace: pnv_try_setup_npu_table_group+0x60/0x pnv_pci_ioda_fixup+0x20c/0x660 pcibios_resource_survey+0x2c8/0x31c pcibios_init+0xb0/0xe4 do_one_initcall+0x64/0x264 kernel_init_freeable+0x36c/0x468 kernel_init+0x2c/0x148 ret_from_kernel_thread+0x5c/0x68 An opencapi device is using a device PE, so the current code breaks because pe->pbus is not defined. More generally, there's no need to define an IOMMU group for opencapi, as the device sends real addresses directly (admittedly, the virtualization story is yet to be written). So let's fix it by skipping the IOMMU group setup for opencapi PHBs. Fixes: 0bd971676e68 ("powerpc/powernv/npu: Add compound IOMMU groups") Signed-off-by: Frederic Barrat Reviewed-by: Greg Kurz Reviewed-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-ioda.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 1d6406a051f1..7db3119f8a5b 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -2681,7 +2681,8 @@ static void pnv_pci_ioda_setup_iommu_api(void) list_for_each_entry(hose, &hose_list, list_node) { phb = hose->private_data; - if (phb->type == PNV_PHB_NPU_NVLINK) + if (phb->type == PNV_PHB_NPU_NVLINK || + phb->type == PNV_PHB_NPU_OCAPI) continue; list_for_each_entry(pe, &phb->ioda.pe_list, list) { -- cgit v1.2.3-58-ga151 From fcf5036f09694d09d946c0455f329894a6482a4d Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 11 Jan 2019 23:53:46 +1100 Subject: powerpc/4xx/ocm: Fix fix for phys_addr_t printf warnings My recent commit to fix the printf warnings in ocm.c got the format specifier wrong, because I copied it from the documentation without realising the square brackets are not meant as literals. This results in the address being suffixed with a literal "[p]". Actually tested this time: # cat info /sys/kernel/debug/ppc4xx_ocm PhysAddr : 0x0000000400040000 ... NC.PhysAddr : 0x0000000400040000 ... C.PhysAddr : 0x0000000000000000 Fixes: 52b88fa1e8c7 ("powerpc/4xx/ocm: Fix phys_addr_t printf warnings") Reported-by: Christian Lamparter Tested-by: Christian Lamparter Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/4xx/ocm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/4xx/ocm.c b/arch/powerpc/platforms/4xx/ocm.c index a1aaa1569d7c..f0e488d97567 100644 --- a/arch/powerpc/platforms/4xx/ocm.c +++ b/arch/powerpc/platforms/4xx/ocm.c @@ -237,12 +237,12 @@ static int ocm_debugfs_show(struct seq_file *m, void *v) continue; seq_printf(m, "PPC4XX OCM : %d\n", ocm->index); - seq_printf(m, "PhysAddr : %pa[p]\n", &(ocm->phys)); + seq_printf(m, "PhysAddr : %pa\n", &(ocm->phys)); seq_printf(m, "MemTotal : %d Bytes\n", ocm->memtotal); seq_printf(m, "MemTotal(NC) : %d Bytes\n", ocm->nc.memtotal); seq_printf(m, "MemTotal(C) : %d Bytes\n\n", ocm->c.memtotal); - seq_printf(m, "NC.PhysAddr : %pa[p]\n", &(ocm->nc.phys)); + seq_printf(m, "NC.PhysAddr : %pa\n", &(ocm->nc.phys)); seq_printf(m, "NC.VirtAddr : 0x%p\n", ocm->nc.virt); seq_printf(m, "NC.MemTotal : %d Bytes\n", ocm->nc.memtotal); seq_printf(m, "NC.MemFree : %d Bytes\n", ocm->nc.memfree); @@ -252,7 +252,7 @@ static int ocm_debugfs_show(struct seq_file *m, void *v) blk->size, blk->owner); } - seq_printf(m, "\nC.PhysAddr : %pa[p]\n", &(ocm->c.phys)); + seq_printf(m, "\nC.PhysAddr : %pa\n", &(ocm->c.phys)); seq_printf(m, "C.VirtAddr : 0x%p\n", ocm->c.virt); seq_printf(m, "C.MemTotal : %d Bytes\n", ocm->c.memtotal); seq_printf(m, "C.MemFree : %d Bytes\n", ocm->c.memfree); -- cgit v1.2.3-58-ga151 From ee13919c2e8d1f904e035ad4b4239029a8994131 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 10 Jan 2019 11:27:28 -0800 Subject: CIFS: Do not hide EINTR after sending network packets Currently we hide EINTR code returned from sock_sendmsg() and return 0 instead. This makes a caller think that we successfully completed the network operation which is not true. Fix this by properly returning EINTR to callers. Cc: Signed-off-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e047f06c9b4f..aaff9c5aab3d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -387,7 +387,7 @@ smbd_done: if (rc < 0 && rc != -EINTR) cifs_dbg(VFS, "Error %d sending data on socket to server\n", rc); - else + else if (rc > 0) rc = 0; return rc; -- cgit v1.2.3-58-ga151 From 15bc77f94e9f0e3cfd6972f3b84bb7aaa4c36b1b Mon Sep 17 00:00:00 2001 From: Aurelien Aptel Date: Tue, 8 Jan 2019 13:41:00 +0100 Subject: cifs: move large array from stack to heap This addresses some compile warnings that you can see depending on configuration settings. Signed-off-by: Aurelien Aptel Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 23 ++++++++++++++++------- fs/cifs/smb2pdu.c | 23 ++++++++++++++++------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b1f49c1c543a..332f88d753d1 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -128,24 +128,31 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc, int rc; struct dfs_cache_tgt_list tl; struct dfs_cache_tgt_iterator *it = NULL; - char tree[MAX_TREE_SIZE + 1]; + char *tree; const char *tcp_host; size_t tcp_host_len; const char *dfs_host; size_t dfs_host_len; + tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL); + if (!tree) + return -ENOMEM; + if (tcon->ipc) { - snprintf(tree, sizeof(tree), "\\\\%s\\IPC$", + snprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", tcon->ses->server->hostname); - return CIFSTCon(0, tcon->ses, tree, tcon, nlsc); + rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc); + goto out; } - if (!tcon->dfs_path) - return CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc); + if (!tcon->dfs_path) { + rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc); + goto out; + } rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl); if (rc) - return rc; + goto out; extract_unc_hostname(tcon->ses->server->hostname, &tcp_host, &tcp_host_len); @@ -165,7 +172,7 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc, continue; } - snprintf(tree, sizeof(tree), "\\%s", tgt); + snprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc); if (!rc) @@ -182,6 +189,8 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc, rc = -ENOENT; } dfs_cache_free_tgts(&tl); +out: + kfree(tree); return rc; } #else diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index b9d7891edaa1..50811a7dc0e0 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -162,24 +162,31 @@ static int __smb2_reconnect(const struct nls_table *nlsc, int rc; struct dfs_cache_tgt_list tl; struct dfs_cache_tgt_iterator *it = NULL; - char tree[MAX_TREE_SIZE + 1]; + char *tree; const char *tcp_host; size_t tcp_host_len; const char *dfs_host; size_t dfs_host_len; + tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL); + if (!tree) + return -ENOMEM; + if (tcon->ipc) { - snprintf(tree, sizeof(tree), "\\\\%s\\IPC$", + snprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", tcon->ses->server->hostname); - return SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); + rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); + goto out; } - if (!tcon->dfs_path) - return SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc); + if (!tcon->dfs_path) { + rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc); + goto out; + } rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl); if (rc) - return rc; + goto out; extract_unc_hostname(tcon->ses->server->hostname, &tcp_host, &tcp_host_len); @@ -199,7 +206,7 @@ static int __smb2_reconnect(const struct nls_table *nlsc, continue; } - snprintf(tree, sizeof(tree), "\\%s", tgt); + snprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); if (!rc) @@ -216,6 +223,8 @@ static int __smb2_reconnect(const struct nls_table *nlsc, rc = -ENOENT; } dfs_cache_free_tgts(&tl); +out: + kfree(tree); return rc; } #else -- cgit v1.2.3-58-ga151 From 92a8109e4d3a34fb6b115c9098b51767dc933444 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Tue, 8 Jan 2019 18:30:56 +0000 Subject: cifs: Limit memory used by lock request calls to a page The code tries to allocate a contiguous buffer with a size supplied by the server (maxBuf). This could fail if memory is fragmented since it results in high order allocations for commonly used server implementations. It is also wasteful since there are probably few locks in the usual case. Limit the buffer to be no larger than a page to avoid memory allocation failures due to fragmentation. Signed-off-by: Ross Lagerwall Signed-off-by: Steve French --- fs/cifs/file.c | 8 ++++++++ fs/cifs/smb2file.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e3e3a7550205..673f948e4760 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1140,6 +1140,10 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) return -EINVAL; } + BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) > + PAGE_SIZE); + max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr), + PAGE_SIZE); max_num = (max_buf - sizeof(struct smb_hdr)) / sizeof(LOCKING_ANDX_RANGE); buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); @@ -1478,6 +1482,10 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, if (!max_buf) return -EINVAL; + BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) > + PAGE_SIZE); + max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr), + PAGE_SIZE); max_num = (max_buf - sizeof(struct smb_hdr)) / sizeof(LOCKING_ANDX_RANGE); buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index 4ed10dd086e6..eff01ed6db0a 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -128,6 +128,8 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, if (!max_buf) return -EINVAL; + BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE); + max_buf = min_t(unsigned int, max_buf, PAGE_SIZE); max_num = max_buf / sizeof(struct smb2_lock_element); buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL); if (!buf) @@ -264,6 +266,8 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile) return -EINVAL; } + BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE); + max_buf = min_t(unsigned int, max_buf, PAGE_SIZE); max_num = max_buf / sizeof(struct smb2_lock_element); buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL); if (!buf) { -- cgit v1.2.3-58-ga151 From b9a74cde94957d82003fb9f7ab4777938ca851cd Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Tue, 8 Jan 2019 18:30:57 +0000 Subject: cifs: Fix potential OOB access of lock element array If maxBuf is small but non-zero, it could result in a zero sized lock element array which we would then try and access OOB. Signed-off-by: Ross Lagerwall Signed-off-by: Steve French CC: Stable --- fs/cifs/file.c | 8 ++++---- fs/cifs/smb2file.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 673f948e4760..5b6f8392d9db 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1132,10 +1132,10 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) /* * Accessing maxBuf is racy with cifs_reconnect - need to store value - * and check it for zero before using. + * and check it before using. */ max_buf = tcon->ses->server->maxBuf; - if (!max_buf) { + if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE))) { free_xid(xid); return -EINVAL; } @@ -1476,10 +1476,10 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, /* * Accessing maxBuf is racy with cifs_reconnect - need to store value - * and check it for zero before using. + * and check it before using. */ max_buf = tcon->ses->server->maxBuf; - if (!max_buf) + if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE))) return -EINVAL; BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) > diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index eff01ed6db0a..b204e84b87fb 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -122,10 +122,10 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, /* * Accessing maxBuf is racy with cifs_reconnect - need to store value - * and check it for zero before using. + * and check it before using. */ max_buf = tcon->ses->server->maxBuf; - if (!max_buf) + if (max_buf < sizeof(struct smb2_lock_element)) return -EINVAL; BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE); -- cgit v1.2.3-58-ga151 From 8a26f0f781f56d3016b34a2217e346973d067e7b Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 3 Jan 2019 16:45:27 -0800 Subject: CIFS: Fix credits calculation for cancelled requests If a request is cancelled, we can't assume that the server returns 1 credit back. Instead we need to wait for a response and process the number of credits granted by the server. Create a separate mid callback for cancelled request, parse the number of credits in a response buffer and add them to the client's credits. If the didn't get a response (no response buffer available) assume 0 credits granted. The latter most probably happens together with session reconnect, so the client's credits are adjusted anyway. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 1 + fs/cifs/transport.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 01ded7038b19..770926877b7c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1438,6 +1438,7 @@ struct mid_q_entry { int mid_state; /* wish this were enum but can not pass to wait_event */ unsigned int mid_flags; __le16 command; /* smb command code */ + unsigned int optype; /* operation type */ bool large_buf:1; /* if valid response, is pointer to large buf */ bool multiRsp:1; /* multiple trans2 responses for one request */ bool multiEnd:1; /* both received */ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index aaff9c5aab3d..450c43494324 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -787,6 +787,24 @@ cifs_noop_callback(struct mid_q_entry *mid) { } +static void +cifs_cancelled_callback(struct mid_q_entry *mid) +{ + struct TCP_Server_Info *server = mid->server; + unsigned int optype = mid->optype; + unsigned int credits_received = 0; + + if (mid->mid_state == MID_RESPONSE_RECEIVED) { + if (mid->resp_buf) + credits_received = server->ops->get_credits(mid); + else + cifs_dbg(FYI, "Bad state for cancelled MID\n"); + } + + DeleteMidQEntry(mid); + add_credits(server, credits_received, optype); +} + int compound_send_recv(const unsigned int xid, struct cifs_ses *ses, const int flags, const int num_rqst, struct smb_rqst *rqst, @@ -862,6 +880,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, } midQ[i]->mid_state = MID_REQUEST_SUBMITTED; + midQ[i]->optype = optype; /* * We don't invoke the callback compounds unless it is the last * request. @@ -896,15 +915,20 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, for (i = 0; i < num_rqst; i++) { rc = wait_for_response(ses->server, midQ[i]); - if (rc != 0) { + if (rc != 0) + break; + } + if (rc != 0) { + for (; i < num_rqst; i++) { cifs_dbg(VFS, "Cancelling wait for mid %llu cmd: %d\n", midQ[i]->mid, le16_to_cpu(midQ[i]->command)); send_cancel(ses->server, &rqst[i], midQ[i]); spin_lock(&GlobalMid_Lock); if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED) { midQ[i]->mid_flags |= MID_WAIT_CANCELLED; - midQ[i]->callback = DeleteMidQEntry; + midQ[i]->callback = cifs_cancelled_callback; cancelled_mid[i] = true; + credits[i] = 0; } spin_unlock(&GlobalMid_Lock); } -- cgit v1.2.3-58-ga151 From ee258d79159afed52ca9372aeb9c1a51e89b32ee Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 3 Jan 2019 15:53:10 -0800 Subject: CIFS: Move credit processing to mid callbacks for SMB3 Currently we account for credits in the thread initiating a request and waiting for a response. The demultiplex thread receives the response, wakes up the thread and the latter collects credits from the response buffer and add them to the server structure on the client. This approach is not accurate, because it may race with reconnect events in the demultiplex thread which resets the number of credits. Fix this by moving credit processing to new mid callbacks that collect credits granted by the server from the response in the demultiplex thread. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/transport.c | 51 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 450c43494324..202e0e84efdd 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -783,12 +783,7 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) } static void -cifs_noop_callback(struct mid_q_entry *mid) -{ -} - -static void -cifs_cancelled_callback(struct mid_q_entry *mid) +cifs_compound_callback(struct mid_q_entry *mid) { struct TCP_Server_Info *server = mid->server; unsigned int optype = mid->optype; @@ -801,10 +796,23 @@ cifs_cancelled_callback(struct mid_q_entry *mid) cifs_dbg(FYI, "Bad state for cancelled MID\n"); } - DeleteMidQEntry(mid); add_credits(server, credits_received, optype); } +static void +cifs_compound_last_callback(struct mid_q_entry *mid) +{ + cifs_compound_callback(mid); + cifs_wake_up_task(mid); +} + +static void +cifs_cancelled_callback(struct mid_q_entry *mid) +{ + cifs_compound_callback(mid); + DeleteMidQEntry(mid); +} + int compound_send_recv(const unsigned int xid, struct cifs_ses *ses, const int flags, const int num_rqst, struct smb_rqst *rqst, @@ -882,11 +890,14 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, midQ[i]->mid_state = MID_REQUEST_SUBMITTED; midQ[i]->optype = optype; /* - * We don't invoke the callback compounds unless it is the last - * request. + * Invoke callback for every part of the compound chain + * to calculate credits properly. Wake up this thread only when + * the last element is received. */ if (i < num_rqst - 1) - midQ[i]->callback = cifs_noop_callback; + midQ[i]->callback = cifs_compound_callback; + else + midQ[i]->callback = cifs_compound_last_callback; } cifs_in_send_inc(ses->server); rc = smb_send_rqst(ses->server, num_rqst, rqst, flags); @@ -900,8 +911,20 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, mutex_unlock(&ses->server->srv_mutex); - if (rc < 0) + if (rc < 0) { + /* Sending failed for some reason - return credits back */ + for (i = 0; i < num_rqst; i++) + add_credits(ses->server, credits[i], optype); goto out; + } + + /* + * At this point the request is passed to the network stack - we assume + * that any credits taken from the server structure on the client have + * been spent and we can't return them back. Once we receive responses + * we will collect credits granted by the server in the mid callbacks + * and add those credits to the server structure. + */ /* * Compounding is never used during session establish. @@ -934,11 +957,6 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, } } - for (i = 0; i < num_rqst; i++) - if (!cancelled_mid[i] && midQ[i]->resp_buf - && (midQ[i]->mid_state == MID_RESPONSE_RECEIVED)) - credits[i] = ses->server->ops->get_credits(midQ[i]); - for (i = 0; i < num_rqst; i++) { if (rc < 0) goto out; @@ -997,7 +1015,6 @@ out: for (i = 0; i < num_rqst; i++) { if (!cancelled_mid[i]) cifs_delete_mid(midQ[i]); - add_credits(ses->server, credits[i], optype); } return rc; -- cgit v1.2.3-58-ga151 From 9a66396f1857cc1de06f4f4771797315e1a4ea56 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 8 Jan 2019 11:15:28 -0800 Subject: CIFS: Fix error paths in writeback code This patch aims to address writeback code problems related to error paths. In particular it respects EINTR and related error codes and stores and returns the first error occurred during writeback. Signed-off-by: Pavel Shilovsky Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 19 +++++++++++++++++++ fs/cifs/cifssmb.c | 7 ++++--- fs/cifs/file.c | 29 +++++++++++++++++++++++------ fs/cifs/inode.c | 10 ++++++++++ 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 770926877b7c..94dbdbe5be34 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1575,6 +1575,25 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, kfree(param); } +static inline bool is_interrupt_error(int error) +{ + switch (error) { + case -EINTR: + case -ERESTARTSYS: + case -ERESTARTNOHAND: + case -ERESTARTNOINTR: + return true; + } + return false; +} + +static inline bool is_retryable_error(int error) +{ + if (is_interrupt_error(error) || error == -EAGAIN) + return true; + return false; +} + #define MID_FREE 0 #define MID_REQUEST_ALLOCATED 1 #define MID_REQUEST_SUBMITTED 2 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 332f88d753d1..e18915415e13 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2123,7 +2123,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata) for (j = 0; j < nr_pages; j++) { unlock_page(wdata2->pages[j]); - if (rc != 0 && rc != -EAGAIN) { + if (rc != 0 && !is_retryable_error(rc)) { SetPageError(wdata2->pages[j]); end_page_writeback(wdata2->pages[j]); put_page(wdata2->pages[j]); @@ -2132,7 +2132,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata) if (rc) { kref_put(&wdata2->refcount, cifs_writedata_release); - if (rc == -EAGAIN) + if (is_retryable_error(rc)) continue; break; } @@ -2141,7 +2141,8 @@ cifs_writev_requeue(struct cifs_writedata *wdata) i += nr_pages; } while (i < wdata->nr_pages); - mapping_set_error(inode->i_mapping, rc); + if (rc != 0 && !is_retryable_error(rc)) + mapping_set_error(inode->i_mapping, rc); kref_put(&wdata->refcount, cifs_writedata_release); } diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5b6f8392d9db..2c7689f3998d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -733,7 +733,8 @@ reopen_success: if (can_flush) { rc = filemap_write_and_wait(inode->i_mapping); - mapping_set_error(inode->i_mapping, rc); + if (!is_interrupt_error(rc)) + mapping_set_error(inode->i_mapping, rc); if (tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, @@ -2118,6 +2119,7 @@ static int cifs_writepages(struct address_space *mapping, pgoff_t end, index; struct cifs_writedata *wdata; int rc = 0; + int saved_rc = 0; unsigned int xid; /* @@ -2146,8 +2148,10 @@ retry: rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, &wsize, &credits); - if (rc) + if (rc != 0) { + done = true; break; + } tofind = min((wsize / PAGE_SIZE) - 1, end - index) + 1; @@ -2155,6 +2159,7 @@ retry: &found_pages); if (!wdata) { rc = -ENOMEM; + done = true; add_credits_and_wake_if(server, credits, 0); break; } @@ -2183,7 +2188,7 @@ retry: if (rc != 0) { add_credits_and_wake_if(server, wdata->credits, 0); for (i = 0; i < nr_pages; ++i) { - if (rc == -EAGAIN) + if (is_retryable_error(rc)) redirty_page_for_writepage(wbc, wdata->pages[i]); else @@ -2191,7 +2196,7 @@ retry: end_page_writeback(wdata->pages[i]); put_page(wdata->pages[i]); } - if (rc != -EAGAIN) + if (!is_retryable_error(rc)) mapping_set_error(mapping, rc); } kref_put(&wdata->refcount, cifs_writedata_release); @@ -2201,6 +2206,15 @@ retry: continue; } + /* Return immediately if we received a signal during writing */ + if (is_interrupt_error(rc)) { + done = true; + break; + } + + if (rc != 0 && saved_rc == 0) + saved_rc = rc; + wbc->nr_to_write -= nr_pages; if (wbc->nr_to_write <= 0) done = true; @@ -2218,6 +2232,9 @@ retry: goto retry; } + if (saved_rc != 0) + rc = saved_rc; + if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) mapping->writeback_index = index; @@ -2250,8 +2267,8 @@ cifs_writepage_locked(struct page *page, struct writeback_control *wbc) set_page_writeback(page); retry_write: rc = cifs_partialpagewrite(page, 0, PAGE_SIZE); - if (rc == -EAGAIN) { - if (wbc->sync_mode == WB_SYNC_ALL) + if (is_retryable_error(rc)) { + if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN) goto retry_write; redirty_page_for_writepage(wbc, page); } else if (rc != 0) { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 13fb59aadebc..478003644916 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -2257,6 +2257,11 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) * the flush returns error? */ rc = filemap_write_and_wait(inode->i_mapping); + if (is_interrupt_error(rc)) { + rc = -ERESTARTSYS; + goto out; + } + mapping_set_error(inode->i_mapping, rc); rc = 0; @@ -2400,6 +2405,11 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) * the flush returns error? */ rc = filemap_write_and_wait(inode->i_mapping); + if (is_interrupt_error(rc)) { + rc = -ERESTARTSYS; + goto cifs_setattr_exit; + } + mapping_set_error(inode->i_mapping, rc); rc = 0; -- cgit v1.2.3-58-ga151 From 48d2ba6257013676e57ff69444d5212031aee763 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 5 Jan 2019 19:46:35 -0600 Subject: cifs: update internal module version number To 2.16 Signed-off-by: Steve French --- fs/cifs/cifsfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 26776eddd85d..d1f9c2f3f575 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -150,5 +150,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ -#define CIFS_VERSION "2.15" +#define CIFS_VERSION "2.16" #endif /* _CIFSFS_H */ -- cgit v1.2.3-58-ga151 From a01421e4484327fe44f8e126793ed5a48a221e24 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich Date: Fri, 11 Jan 2019 14:34:38 +0100 Subject: omap2fb: Fix stack memory disclosure Using [1] for static analysis I found that the OMAPFB_QUERY_PLANE, OMAPFB_GET_COLOR_KEY, OMAPFB_GET_DISPLAY_INFO, and OMAPFB_GET_VRAM_INFO cases could all leak uninitialized stack memory--either due to uninitialized padding or 'reserved' fields. Fix them by clearing the shared union used to store copied out data. [1] https://github.com/vlad902/kernel-uninitialized-memory-checker Signed-off-by: Vlad Tsyrklevich Reviewed-by: Kees Cook Fixes: b39a982ddecf ("OMAP: DSS2: omapfb driver") Cc: security@kernel.org [b.zolnierkie: prefix patch subject with "omap2fb: "] Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c index a3edb20ea4c3..a846d32ee653 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c @@ -609,6 +609,8 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) int r = 0; + memset(&p, 0, sizeof(p)); + switch (cmd) { case OMAPFB_SYNC_GFX: DBG("ioctl SYNC_GFX\n"); -- cgit v1.2.3-58-ga151 From 00257e0cc550c4a8df5f99c0a4fc74fec0656144 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 11 Jan 2019 14:34:39 +0100 Subject: fbdev: offb: Fix OF node name handling Commit 5c63e407aaab ("fbdev: Convert to using %pOFn instead of device_node.name") changed how the OF FB driver handles the OF node name. This missed the case where the node name is passed to offb_init_palette_hacks(). This results in a NULL ptr dereference in strncmp and breaks any system except ones using bootx with no display node. Fix this by making offb_init_palette_hacks() use the OF node pointer and use of_node_name_prefix() helper function instead for node name comparisons. This helps in moving all OF node name accesses to helper functions in preparation to remove struct device_node.name pointer. Fixes: 5c63e407aaab ("fbdev: Convert to using %pOFn instead of device_node.name") Reported-by: Mathieu Malaterre Tested-by: Mathieu Malaterre Cc: stable@vger.kernel.org # v4.19+ Cc: Elimar Riesebieter Signed-off-by: Rob Herring Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/video/fbdev/offb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/video/fbdev/offb.c b/drivers/video/fbdev/offb.c index 31f769d67195..057d3cdef92e 100644 --- a/drivers/video/fbdev/offb.c +++ b/drivers/video/fbdev/offb.c @@ -318,28 +318,28 @@ static void __iomem *offb_map_reg(struct device_node *np, int index, } static void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp, - const char *name, unsigned long address) + unsigned long address) { struct offb_par *par = (struct offb_par *) info->par; - if (dp && !strncmp(name, "ATY,Rage128", 11)) { + if (of_node_name_prefix(dp, "ATY,Rage128")) { par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); if (par->cmap_adr) par->cmap_type = cmap_r128; - } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) - || !strncmp(name, "ATY,RageM3p12A", 14))) { + } else if (of_node_name_prefix(dp, "ATY,RageM3pA") || + of_node_name_prefix(dp, "ATY,RageM3p12A")) { par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); if (par->cmap_adr) par->cmap_type = cmap_M3A; - } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) { + } else if (of_node_name_prefix(dp, "ATY,RageM3pB")) { par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); if (par->cmap_adr) par->cmap_type = cmap_M3B; - } else if (dp && !strncmp(name, "ATY,Rage6", 9)) { + } else if (of_node_name_prefix(dp, "ATY,Rage6")) { par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff); if (par->cmap_adr) par->cmap_type = cmap_radeon; - } else if (!strncmp(name, "ATY,", 4)) { + } else if (of_node_name_prefix(dp, "ATY,")) { unsigned long base = address & 0xff000000UL; par->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0; @@ -350,7 +350,7 @@ static void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000); if (par->cmap_adr) par->cmap_type = cmap_gxt2000; - } else if (dp && !strncmp(name, "vga,Display-", 12)) { + } else if (of_node_name_prefix(dp, "vga,Display-")) { /* Look for AVIVO initialized by SLOF */ struct device_node *pciparent = of_get_parent(dp); const u32 *vid, *did; @@ -438,7 +438,7 @@ static void __init offb_init_fb(const char *name, par->cmap_type = cmap_unknown; if (depth == 8) - offb_init_palette_hacks(info, dp, name, address); + offb_init_palette_hacks(info, dp, address); else fix->visual = FB_VISUAL_TRUECOLOR; -- cgit v1.2.3-58-ga151 From e3e4767bd550b3f19278e42bcce143e0d2316ba2 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Tue, 1 Jan 2019 20:44:14 +0100 Subject: mmc: core: don't override the CD GPIO level when "cd-inverted" is set Since commit 89a5e15bcba87d ("gpio/mmc/of: Respect polarity in the device tree") gpiolib-of parses the "cd-gpios" property and flips the polarity if "cd-inverted" is also set. This results in the "cd-inverted" property being evaluated twice, which effectively makes it a no-op: - first in drivers/gpio/gpiolib-of.c (of_xlate_and_get_gpiod_flags) when setting up the CD GPIO - then again in drivers/mmc/core/slot-gpio.c (mmc_gpio_get_cd) when reading the CD GPIO value at runtime On boards which are using device-tree with the "cd-inverted" property being set any inserted card are not detected anymore. This is due to the MMC core treating the CD GPIO with the wrong polarity. Disable "override_cd_active_level" for the card detection GPIO which is parsed using mmc_of_parse. This fixes SD card detection on the boards which are currently using the "cd-inverted" device-tree property (tested on Meson8b Odroid-C1 and Meson8b EC-100). This does not remove the CD GPIO inversion logic from the MMC core because there's at least one driver (sdhci-pci-core for Intel BayTrail based boards) which still passes "override_cd_active_level = true" to mmc_gpiod_request_cd(). Due to lack of hardware for testing this is left untouched. In the future the GPIO inversion logic for both, card and read-only detection can be removed once no driver is using it anymore. Fixes: 89a5e15bcba87d ("gpio/mmc/of: Respect polarity in the device tree") Signed-off-by: Martin Blumenstingl Tested-by: Anand Moon Tested-by: Loys Ollivier Acked-by: Ulf Hansson Signed-off-by: Linus Walleij --- drivers/mmc/core/host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index f57f5de54206..cf58ccaf22d5 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -234,7 +234,7 @@ int mmc_of_parse(struct mmc_host *host) if (device_property_read_bool(dev, "broken-cd")) host->caps |= MMC_CAP_NEEDS_POLL; - ret = mmc_gpiod_request_cd(host, "cd", 0, true, + ret = mmc_gpiod_request_cd(host, "cd", 0, false, cd_debounce_delay_ms * 1000, &cd_gpio_invert); if (!ret) -- cgit v1.2.3-58-ga151 From d3736d82e8169768218ee0ef68718875918091a0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Wed, 9 Jan 2019 01:17:40 +0000 Subject: tty: Don't hold ldisc lock in tty_reopen() if ldisc present Try to get reference for ldisc during tty_reopen(). If ldisc present, we don't need to do tty_ldisc_reinit() and lock the write side for line discipline semaphore. Effectively, it optimizes fast-path for tty_reopen(), but more importantly it won't interrupt ongoing IO on the tty as no ldisc change is needed. Fixes user-visible issue when tty_reopen() interrupted login process for user with a long password, observed and reported by Lukas. Fixes: c96cf923a98d ("tty: Don't block on IO when ldisc change is pending") Fixes: 83d817f41070 ("tty: Hold tty_ldisc_lock() during tty_reopen()") Cc: Jiri Slaby Reported-by: Lukas F. Hartmann Tested-by: Lukas F. Hartmann Cc: stable Signed-off-by: Dmitry Safonov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index bfe9ad85b362..23c6fd238422 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1256,7 +1256,8 @@ static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct * static int tty_reopen(struct tty_struct *tty) { struct tty_driver *driver = tty->driver; - int retval; + struct tty_ldisc *ld; + int retval = 0; if (driver->type == TTY_DRIVER_TYPE_PTY && driver->subtype == PTY_TYPE_MASTER) @@ -1268,13 +1269,18 @@ static int tty_reopen(struct tty_struct *tty) if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) return -EBUSY; - retval = tty_ldisc_lock(tty, 5 * HZ); - if (retval) - return retval; + ld = tty_ldisc_ref_wait(tty); + if (ld) { + tty_ldisc_deref(ld); + } else { + retval = tty_ldisc_lock(tty, 5 * HZ); + if (retval) + return retval; - if (!tty->ldisc) - retval = tty_ldisc_reinit(tty, tty->termios.c_line); - tty_ldisc_unlock(tty); + if (!tty->ldisc) + retval = tty_ldisc_reinit(tty, tty->termios.c_line); + tty_ldisc_unlock(tty); + } if (retval == 0) tty->count++; -- cgit v1.2.3-58-ga151 From 03aa047ef2db4985e444af6ee1c1dd084ad9fb4c Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Fri, 9 Nov 2018 09:21:47 +0100 Subject: s390/early: improve machine detection Right now the early machine detection code check stsi 3.2.2 for "KVM" and set MACHINE_IS_VM if this is different. As the console detection uses diagnose 8 if MACHINE_IS_VM returns true this will crash Linux early for any non z/VM system that sets a different value than KVM. So instead of assuming z/VM, do not set any of MACHINE_IS_LPAR, MACHINE_IS_VM, or MACHINE_IS_KVM. CC: stable@vger.kernel.org Reviewed-by: Heiko Carstens Signed-off-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/early.c | 4 ++-- arch/s390/kernel/setup.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index af5c2b3f7065..a8c7789b246b 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -63,10 +63,10 @@ static noinline __init void detect_machine_type(void) if (stsi(vmms, 3, 2, 2) || !vmms->count) return; - /* Running under KVM? If not we assume z/VM */ + /* Detect known hypervisors */ if (!memcmp(vmms->vm[0].cpi, "\xd2\xe5\xd4", 3)) S390_lowcore.machine_flags |= MACHINE_FLAG_KVM; - else + else if (!memcmp(vmms->vm[0].cpi, "\xa9\x61\xe5\xd4", 4)) S390_lowcore.machine_flags |= MACHINE_FLAG_VM; } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 72dd23ef771b..7ed90a759135 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -1006,6 +1006,8 @@ void __init setup_arch(char **cmdline_p) pr_info("Linux is running under KVM in 64-bit mode\n"); else if (MACHINE_IS_LPAR) pr_info("Linux is running natively in 64-bit mode\n"); + else + pr_info("Linux is running as a guest in 64-bit mode\n"); /* Have one command line that is parsed and saved in /proc/cmdline */ /* boot_command_line has been already set up in early.c */ -- cgit v1.2.3-58-ga151 From a38662084c8bdb829ff486468c7ea801c13fcc34 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 8 Jan 2019 12:44:57 +0100 Subject: s390/mm: always force a load of the primary ASCE on context switch The ASCE of an mm_struct can be modified after a task has been created, e.g. via crst_table_downgrade for a compat process. The active_mm logic to avoid the switch_mm call if the next task is a kernel thread can lead to a situation where switch_mm is called where 'prev == next' is true but 'prev->context.asce == next->context.asce' is not. This can lead to a situation where a CPU uses the outdated ASCE to run a task. The result can be a crash, endless loops and really subtle problem due to TLBs being created with an invalid ASCE. Cc: stable@kernel.org # v3.15+ Fixes: 53e857f30867 ("s390/mm,tlb: race of lazy TLB flush vs. recreation") Reported-by: Heiko Carstens Reviewed-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/mmu_context.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index ccbb53e22024..e4462202200d 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -90,8 +90,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, { int cpu = smp_processor_id(); - if (prev == next) - return; S390_lowcore.user_asce = next->context.asce; cpumask_set_cpu(cpu, &next->context.cpu_attach_mask); /* Clear previous user-ASCE from CR1 and CR7 */ @@ -103,7 +101,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, __ctl_load(S390_lowcore.vdso_asce, 7, 7); clear_cpu_flag(CIF_ASCE_SECONDARY); } - cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask); + if (prev != next) + cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask); } #define finish_arch_post_lock_switch finish_arch_post_lock_switch -- cgit v1.2.3-58-ga151 From b7cb707c373094ce4008d4a6ac9b6b366ec52da5 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Wed, 9 Jan 2019 13:00:03 +0100 Subject: s390/smp: fix CPU hotplug deadlock with CPU rescan smp_rescan_cpus() is called without the device_hotplug_lock, which can lead to a dedlock when a new CPU is found and immediately set online by a udev rule. This was observed on an older kernel version, where the cpu_hotplug_begin() loop was still present, and it resulted in hanging chcpu and systemd-udev processes. This specific deadlock will not show on current kernels. However, there may be other possible deadlocks, and since smp_rescan_cpus() can still trigger a CPU hotplug operation, the device_hotplug_lock should be held. For reference, this was the deadlock with the old cpu_hotplug_begin() loop: chcpu (rescan) systemd-udevd echo 1 > /sys/../rescan -> smp_rescan_cpus() -> (*) get_online_cpus() (increases refcount) -> smp_add_present_cpu() (new CPU found) -> register_cpu() -> device_add() -> udev "add" event triggered -----------> udev rule sets CPU online -> echo 1 > /sys/.../online -> lock_device_hotplug_sysfs() (this is missing in rescan path) -> device_online() -> (**) device_lock(new CPU dev) -> cpu_up() -> cpu_hotplug_begin() (loops until refcount == 0) -> deadlock with (*) -> bus_probe_device() -> device_attach() -> device_lock(new CPU dev) -> deadlock with (**) Fix this by taking the device_hotplug_lock in the CPU rescan path. Cc: Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/smp.c | 4 ++++ drivers/s390/char/sclp_config.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index f82b3d3c36e2..307a1c86ea21 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -1166,7 +1166,11 @@ static ssize_t __ref rescan_store(struct device *dev, { int rc; + rc = lock_device_hotplug_sysfs(); + if (rc) + return rc; rc = smp_rescan_cpus(); + unlock_device_hotplug(); return rc ? rc : count; } static DEVICE_ATTR_WO(rescan); diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 194ffd5c8580..039b2074db7e 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -60,7 +60,9 @@ static void sclp_cpu_capability_notify(struct work_struct *work) static void __ref sclp_cpu_change_notify(struct work_struct *work) { + lock_device_hotplug(); smp_rescan_cpus(); + unlock_device_hotplug(); } static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) -- cgit v1.2.3-58-ga151 From 190f056fba230abee80712eb810939ef9a8c462f Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Wed, 2 Jan 2019 13:43:22 +0100 Subject: s390/vdso: correct vdso mapping for compat tasks While "s390/vdso: avoid 64-bit vdso mapping for compat tasks" fixed 64-bit vdso mapping for compat tasks under gdb it introduced another problem. "compat_mm" flag is not inherited during fork and when 31-bit process forks a child (but does not perform exec) it ends up with 64-bit vdso. To address that, init_new_context (which is called during fork and exec) now initialize compat_mm based on thread TIF_31BIT flag. Later compat_mm is adjusted in arch_setup_additional_pages, which is called during exec. Fixes: d1befa65823e ("s390/vdso: avoid 64-bit vdso mapping for compat tasks") Reported-by: Stefan Liebler Reviewed-by: Heiko Carstens Cc: # v4.20+ Signed-off-by: Vasily Gorbik Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/mmu_context.h | 2 +- arch/s390/kernel/vdso.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index e4462202200d..8d04e6f3f796 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -25,7 +25,7 @@ static inline int init_new_context(struct task_struct *tsk, atomic_set(&mm->context.flush_count, 0); mm->context.gmap_asce = 0; mm->context.flush_mm = 0; - mm->context.compat_mm = 0; + mm->context.compat_mm = test_thread_flag(TIF_31BIT); #ifdef CONFIG_PGSTE mm->context.alloc_pgste = page_table_allocate_pgste || test_thread_flag(TIF_PGSTE) || diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index ebe748a9f472..4ff354887db4 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -224,10 +224,9 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) vdso_pages = vdso64_pages; #ifdef CONFIG_COMPAT - if (is_compat_task()) { + mm->context.compat_mm = is_compat_task(); + if (mm->context.compat_mm) vdso_pages = vdso32_pages; - mm->context.compat_mm = 1; - } #endif /* * vDSO has a problem and was disabled, just don't "enable" it for -- cgit v1.2.3-58-ga151 From 60f1bf29c0b2519989927cae640cd1f50f59dc7f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 11 Jan 2019 15:18:22 +0100 Subject: s390/smp: Fix calling smp_call_ipl_cpu() from ipl CPU When calling smp_call_ipl_cpu() from the IPL CPU, we will try to read from pcpu_devices->lowcore. However, due to prefixing, that will result in reading from absolute address 0 on that CPU. We have to go via the actual lowcore instead. This means that right now, we will read lc->nodat_stack == 0 and therfore work on a very wrong stack. This BUG essentially broke rebooting under QEMU TCG (which will report a low address protection exception). And checking under KVM, it is also broken under KVM. With 1 VCPU it can be easily triggered. :/# echo 1 > /proc/sys/kernel/sysrq :/# echo b > /proc/sysrq-trigger [ 28.476745] sysrq: SysRq : Resetting [ 28.476793] Kernel stack overflow. [ 28.476817] CPU: 0 PID: 424 Comm: sh Not tainted 5.0.0-rc1+ #13 [ 28.476820] Hardware name: IBM 2964 NE1 716 (KVM/Linux) [ 28.476826] Krnl PSW : 0400c00180000000 0000000000115c0c (pcpu_delegate+0x12c/0x140) [ 28.476861] R:0 T:1 IO:0 EX:0 Key:0 M:0 W:0 P:0 AS:3 CC:0 PM:0 RI:0 EA:3 [ 28.476863] Krnl GPRS: ffffffffffffffff 0000000000000000 000000000010dff8 0000000000000000 [ 28.476864] 0000000000000000 0000000000000000 0000000000ab7090 000003e0006efbf0 [ 28.476864] 000000000010dff8 0000000000000000 0000000000000000 0000000000000000 [ 28.476865] 000000007fffc000 0000000000730408 000003e0006efc58 0000000000000000 [ 28.476887] Krnl Code: 0000000000115bfe: 4170f000 la %r7,0(%r15) [ 28.476887] 0000000000115c02: 41f0a000 la %r15,0(%r10) [ 28.476887] #0000000000115c06: e370f0980024 stg %r7,152(%r15) [ 28.476887] >0000000000115c0c: c0e5fffff86e brasl %r14,114ce8 [ 28.476887] 0000000000115c12: 41f07000 la %r15,0(%r7) [ 28.476887] 0000000000115c16: a7f4ffa8 brc 15,115b66 [ 28.476887] 0000000000115c1a: 0707 bcr 0,%r7 [ 28.476887] 0000000000115c1c: 0707 bcr 0,%r7 [ 28.476901] Call Trace: [ 28.476902] Last Breaking-Event-Address: [ 28.476920] [<0000000000a01c4a>] arch_call_rest_init+0x22/0x80 [ 28.476927] Kernel panic - not syncing: Corrupt kernel stack, can't continue. [ 28.476930] CPU: 0 PID: 424 Comm: sh Not tainted 5.0.0-rc1+ #13 [ 28.476932] Hardware name: IBM 2964 NE1 716 (KVM/Linux) [ 28.476932] Call Trace: Fixes: 2f859d0dad81 ("s390/smp: reduce size of struct pcpu") Cc: stable@vger.kernel.org # 4.0+ Reported-by: Cornelia Huck Signed-off-by: David Hildenbrand Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/smp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 307a1c86ea21..b198ece2aad6 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -381,8 +381,13 @@ void smp_call_online_cpu(void (*func)(void *), void *data) */ void smp_call_ipl_cpu(void (*func)(void *), void *data) { + struct lowcore *lc = pcpu_devices->lowcore; + + if (pcpu_devices[0].address == stap()) + lc = &S390_lowcore; + pcpu_delegate(&pcpu_devices[0], func, data, - pcpu_devices->lowcore->nodat_stack); + lc->nodat_stack); } int smp_find_processor_id(u16 address) -- cgit v1.2.3-58-ga151 From d14eff1bc53e6a268c3b48da5cdb469f26832d1a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 26 Dec 2018 14:40:59 -0600 Subject: KVM: x86: Fix bit shifting in update_intel_pt_cfg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ctl_bitmask in pt_desc is of type u64. When an integer like 0xf is being left shifted more than 32 bits, the behavior is undefined. Fix this by adding suffix ULL to integer 0xf. Addresses-Coverity-ID: 1476095 ("Bad bit shift operation") Fixes: 6c0f0bba85a0 ("KVM: x86: Introduce a function to initialize the PT configuration") Signed-off-by: Gustavo A. R. Silva Reviewed-by: Wei Yang Reviewed-by: Luwei Kang Signed-off-by: Radim Krčmář --- arch/x86/kvm/vmx/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 4d39f731bc33..e344dc8626d0 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7044,7 +7044,7 @@ static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) /* unmask address range configure area */ for (i = 0; i < vmx->pt_desc.addr_range; i++) - vmx->pt_desc.ctl_bitmask &= ~(0xf << (32 + i * 4)); + vmx->pt_desc.ctl_bitmask &= ~(0xfULL << (32 + i * 4)); } static void vmx_cpuid_update(struct kvm_vcpu *vcpu) -- cgit v1.2.3-58-ga151 From 98938aa8edd66dc95024d7c936a4bc315f6615ff Mon Sep 17 00:00:00 2001 From: Tomas Bortoli Date: Wed, 2 Jan 2019 18:29:37 +0100 Subject: KVM: validate userspace input in kvm_clear_dirty_log_protect() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function at issue does not fully validate the content of the structure pointed by the log parameter, though its content has just been copied from userspace and lacks validation. Fix that. Moreover, change the type of n to unsigned long as that is the type returned by kvm_dirty_bitmap_bytes(). Signed-off-by: Tomas Bortoli Reported-by: syzbot+028366e52c9ace67deb3@syzkaller.appspotmail.com [Squashed the fix from Paolo. - Radim.] Signed-off-by: Radim Krčmář --- virt/kvm/kvm_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 1f888a103f78..5ecea812cb6a 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1227,9 +1227,9 @@ int kvm_clear_dirty_log_protect(struct kvm *kvm, { struct kvm_memslots *slots; struct kvm_memory_slot *memslot; - int as_id, id, n; + int as_id, id; gfn_t offset; - unsigned long i; + unsigned long i, n; unsigned long *dirty_bitmap; unsigned long *dirty_bitmap_buffer; @@ -1249,6 +1249,11 @@ int kvm_clear_dirty_log_protect(struct kvm *kvm, return -ENOENT; n = kvm_dirty_bitmap_bytes(memslot); + + if (log->first_page > memslot->npages || + log->num_pages > memslot->npages - log->first_page) + return -EINVAL; + *flush = false; dirty_bitmap_buffer = kvm_second_dirty_bitmap(memslot); if (copy_from_user(dirty_bitmap_buffer, log->dirty_bitmap, n)) -- cgit v1.2.3-58-ga151 From 3f14a89d1132dcae3c8ce6721c6ef51f6e6d9b5f Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Wed, 2 Jan 2019 12:56:33 -0800 Subject: kvm: sev: Fail KVM_SEV_INIT if already initialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By code inspection, it was found that multiple calls to KVM_SEV_INIT could deplete asid bits and overwrite kvm_sev_info's regions_list. Multiple calls to KVM_SVM_INIT is not likely to occur with QEMU, but this should likely be fixed anyway. This code is serialized by kvm->lock. Fixes: 1654efcbc431 ("KVM: SVM: Add KVM_SEV_INIT command") Reported-by: Cfir Cohen Signed-off-by: David Rientjes Signed-off-by: Radim Krčmář --- arch/x86/kvm/svm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 307e5bddb6d9..a157ca5b6869 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -6278,6 +6278,9 @@ static int sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp) int asid, ret; ret = -EBUSY; + if (unlikely(sev->active)) + return ret; + asid = sev_asid_new(); if (asid < 0) return ret; -- cgit v1.2.3-58-ga151 From b7c1c226f9403c52bf58b0bceef24501429c7351 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Fri, 4 Jan 2019 15:20:44 +0800 Subject: KVM/VMX: Avoid return error when flush tlb successfully in the hv_remote_flush_tlb_with_range() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "ret" is initialized to be ENOTSUPP. The return value of __hv_remote_flush_tlb_with_range() will be Or with "ret" when ept table potiners are mismatched. This will cause return ENOTSUPP even if flush tlb successfully. This patch is to fix the issue and set "ret" to 0. Fixes: a5c214dad198 ("KVM/VMX: Change hv flush logic when ept tables are mismatched.") Signed-off-by: Lan Tianyu Signed-off-by: Radim Krčmář --- arch/x86/kvm/vmx/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e344dc8626d0..f6915f10e584 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -453,7 +453,7 @@ static int hv_remote_flush_tlb_with_range(struct kvm *kvm, struct kvm_tlb_range *range) { struct kvm_vcpu *vcpu; - int ret = -ENOTSUPP, i; + int ret = 0, i; spin_lock(&to_kvm_vmx(kvm)->ept_pointer_lock); -- cgit v1.2.3-58-ga151 From cf1754c2a1d6e92688f7353aa7f598f5ad6d8f78 Mon Sep 17 00:00:00 2001 From: Christophe de Dinechin Date: Mon, 7 Jan 2019 18:52:38 +0100 Subject: Documentation/virtual/kvm: Update URL for AMD SEV API specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The URL of [api-spec] in Documentation/virtual/kvm/amd-memory-encryption.rst is no longer valid, replaced space with underscore. Signed-off-by: Christophe de Dinechin Reviewed-by: Brijesh Singh Signed-off-by: Radim Krčmář --- Documentation/virtual/kvm/amd-memory-encryption.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst index 71d6d257074f..659bbc093b52 100644 --- a/Documentation/virtual/kvm/amd-memory-encryption.rst +++ b/Documentation/virtual/kvm/amd-memory-encryption.rst @@ -242,6 +242,6 @@ References ========== .. [white-paper] http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf -.. [api-spec] http://support.amd.com/TechDocs/55766_SEV-KM%20API_Specification.pdf +.. [api-spec] http://support.amd.com/TechDocs/55766_SEV-KM_API_Specification.pdf .. [amd-apm] http://support.amd.com/TechDocs/24593.pdf (section 15.34) .. [kvm-forum] http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf -- cgit v1.2.3-58-ga151 From 826c1362e79abcd36f99092acd083b5a2d576676 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 9 Jan 2019 18:22:56 +0100 Subject: x86/kvm/nVMX: don't skip emulated instruction twice when vmptr address is not backed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 09abb5e3e5e50 ("KVM: nVMX: call kvm_skip_emulated_instruction in nested_vmx_{fail,succeed}") nested_vmx_failValid() results in kvm_skip_emulated_instruction() so doing it again in handle_vmptrld() when vmptr address is not backed is wrong, we end up advancing RIP twice. Fixes: fca91f6d60b6e ("kvm: nVMX: Set VM instruction error for VMPTRLD of unbacked page") Reported-by: Cornelia Huck Signed-off-by: Vitaly Kuznetsov Reviewed-by: Sean Christopherson Reviewed-by: Cornelia Huck Signed-off-by: Radim Krčmář --- arch/x86/kvm/vmx/nested.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 3170e291215d..2616bd2c7f2c 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4540,9 +4540,8 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) * given physical address won't match the required * VMCS12_REVISION identifier. */ - nested_vmx_failValid(vcpu, + return nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID); - return kvm_skip_emulated_instruction(vcpu); } new_vmcs12 = kmap(page); if (new_vmcs12->hdr.revision_id != VMCS12_REVISION || -- cgit v1.2.3-58-ga151 From 5962dd22f0ff6f7d72fff974b3c637d52586643e Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 2 Jan 2019 18:10:37 +0000 Subject: x86/intel/lpss: Make PCI dependency explicit After commit 5d32a66541c4 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. LPSS code relies on PCI infrastructure but this dependency has not been explicitly called out so do that. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Signed-off-by: Borislav Petkov Cc: "H. Peter Anvin" Cc: linux-acpi@vger.kernel.org Cc: x86-ml Link: https://lkml.kernel.org/r/20190102181038.4418-11-okaya@kernel.org --- arch/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 15af091611e2..4b4a7f32b68e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -617,7 +617,7 @@ config X86_INTEL_QUARK config X86_INTEL_LPSS bool "Intel Low Power Subsystem Support" - depends on X86 && ACPI + depends on X86 && ACPI && PCI select COMMON_CLK select PINCTRL select IOSF_MBI -- cgit v1.2.3-58-ga151 From 83b4c147967b20b9140e38f7b1a79258a8e9fa6f Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Fri, 11 Jan 2019 14:37:43 +0100 Subject: clk: qcom: Select QCOM_GDSC with MSM_GCC_8998 If QCOM_GDSC is disabled, gdsc_register() returns -ENOSYS, which causes gcc_msm8998_probe() to fail. Select QCOM_GDSC to solve the problem. gcc-msm8998: probe of 100000.clock-controller failed with error -38 Signed-off-by: Marc Gonzalez Fixes: b5f5f525c547 ("clk: qcom: Add MSM8998 Global Clock Control (GCC) driver") Signed-off-by: Stephen Boyd --- drivers/clk/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 1b1ba54e33dd..1c04575c118f 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -215,6 +215,7 @@ config MSM_MMCC_8996 config MSM_GCC_8998 tristate "MSM8998 Global Clock Controller" + select QCOM_GDSC help Support for the global clock controller on msm8998 devices. Say Y if you want to use peripheral devices such as UART, SPI, -- cgit v1.2.3-58-ga151 From 5a9372f751b5350e0ce3d2ee91832f1feae2c2e5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 10 Jan 2019 17:24:31 +0100 Subject: mips: fix n32 compat_ipc_parse_version While reading through the sysvipc implementation, I noticed that the n32 semctl/shmctl/msgctl system calls behave differently based on whether o32 support is enabled or not: Without o32, the IPC_64 flag passed by user space is rejected but calls without that flag get IPC_64 behavior. As far as I can tell, this was inadvertently changed by a cleanup patch but never noticed by anyone, possibly nobody has tried using sysvipc on n32 after linux-3.19. Change it back to the old behavior now. Fixes: 78aaf956ba3a ("MIPS: Compat: Fix build error if CONFIG_MIPS32_COMPAT but no compat ABI.") Signed-off-by: Arnd Bergmann Signed-off-by: Paul Burton Cc: linux-mips@vger.kernel.org Cc: stable@vger.kernel.org # 3.19+ --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 787290781b8c..0d14f51d0002 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -3155,6 +3155,7 @@ config MIPS32_O32 config MIPS32_N32 bool "Kernel support for n32 binaries" depends on 64BIT + select ARCH_WANT_COMPAT_IPC_PARSE_VERSION select COMPAT select MIPS32_COMPAT select SYSVIPC_COMPAT if SYSVIPC -- cgit v1.2.3-58-ga151 From ef4efa14560adf7cdc77022c86e659d910c5c6fc Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Fri, 4 Jan 2019 22:56:56 +0100 Subject: dt-bindings: marvell,mmp2: fix typos in bindings doc A pair of rather trivial ones. Signed-off-by: Lubomir Rintel Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/clock/marvell,mmp2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/clock/marvell,mmp2.txt b/Documentation/devicetree/bindings/clock/marvell,mmp2.txt index af376a01f2b7..23b52dc02266 100644 --- a/Documentation/devicetree/bindings/clock/marvell,mmp2.txt +++ b/Documentation/devicetree/bindings/clock/marvell,mmp2.txt @@ -18,4 +18,4 @@ Required Properties: Each clock is assigned an identifier and client nodes use this identifier to specify the clock which they consume. -All these identifier could be found in . +All these identifiers could be found in . -- cgit v1.2.3-58-ga151 From 7e6fc2f50a3197d0e82d1c0e86282976c9e6c8a4 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 7 Jan 2019 11:40:24 +0800 Subject: x86/kaslr: Fix incorrect i8254 outb() parameters The outb() function takes parameters value and port, in that order. Fix the parameters used in the kalsr i8254 fallback code. Fixes: 5bfce5ef55cb ("x86, kaslr: Provide randomness functions") Signed-off-by: Daniel Drake Signed-off-by: Thomas Gleixner Cc: bp@alien8.de Cc: hpa@zytor.com Cc: linux@endlessm.com Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20190107034024.15005-1-drake@endlessm.com --- arch/x86/lib/kaslr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/lib/kaslr.c b/arch/x86/lib/kaslr.c index 79778ab200e4..a53665116458 100644 --- a/arch/x86/lib/kaslr.c +++ b/arch/x86/lib/kaslr.c @@ -36,8 +36,8 @@ static inline u16 i8254(void) u16 status, timer; do { - outb(I8254_PORT_CONTROL, - I8254_CMD_READBACK | I8254_SELECT_COUNTER0); + outb(I8254_CMD_READBACK | I8254_SELECT_COUNTER0, + I8254_PORT_CONTROL); status = inb(I8254_PORT_COUNTER0); timer = inb(I8254_PORT_COUNTER0); timer |= inb(I8254_PORT_COUNTER0) << 8; -- cgit v1.2.3-58-ga151 From 49e54187ae0b2f9b5c0760e568a103baf4481610 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 4 Dec 2018 20:28:25 +0100 Subject: ata: libahci_platform: comply to PHY framework Current implementation of the libahci does not take into account the new PHY framework. Correct the situation by adding a call to phy_set_mode() before phy_power_on(). PHYs should also be handled at suspend/resume time. For this, call ahci_platform_enable/disable_phys() at suspend/resume_host() time. These calls are guarded by a HFLAG (AHCI_HFLAG_SUSPEND_PHYS) that the user of the libahci driver must set manually in hpriv->flags at probe time. This is to avoid breaking users that have not been tested with this change. Reviewed-by: Hans de Goede Suggested-by: Grzegorz Jaszczyk Signed-off-by: Miquel Raynal Signed-off-by: Jens Axboe --- drivers/ata/ahci.h | 2 ++ drivers/ata/libahci_platform.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index ef356e70e6de..8810475f307a 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -254,6 +254,8 @@ enum { AHCI_HFLAG_IS_MOBILE = (1 << 25), /* mobile chipset, use SATA_MOBILE_LPM_POLICY as default lpm_policy */ + AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during + suspend/resume */ /* ap->flags bits */ diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 4b900fc659f7..81b1a3332ed6 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -56,6 +56,12 @@ static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv) if (rc) goto disable_phys; + rc = phy_set_mode(hpriv->phys[i], PHY_MODE_SATA); + if (rc) { + phy_exit(hpriv->phys[i]); + goto disable_phys; + } + rc = phy_power_on(hpriv->phys[i]); if (rc) { phy_exit(hpriv->phys[i]); @@ -738,6 +744,9 @@ int ahci_platform_suspend_host(struct device *dev) writel(ctl, mmio + HOST_CTL); readl(mmio + HOST_CTL); /* flush */ + if (hpriv->flags & AHCI_HFLAG_SUSPEND_PHYS) + ahci_platform_disable_phys(hpriv); + return ata_host_suspend(host, PMSG_SUSPEND); } EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); @@ -756,6 +765,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); int ahci_platform_resume_host(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); + struct ahci_host_priv *hpriv = host->private_data; int rc; if (dev->power.power_state.event == PM_EVENT_SUSPEND) { @@ -766,6 +776,9 @@ int ahci_platform_resume_host(struct device *dev) ahci_init_controller(host); } + if (hpriv->flags & AHCI_HFLAG_SUSPEND_PHYS) + ahci_platform_enable_phys(hpriv); + ata_host_resume(host); return 0; -- cgit v1.2.3-58-ga151 From c9bc136791ba0eefe07ed57d3850b8c5cee6471b Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 4 Dec 2018 20:28:26 +0100 Subject: ata: ahci: mvebu: remove stale comment For Armada-38x (32-bit) SoCs, PM platform support has been added since: commit 32f9494c9dfd ("ARM: mvebu: prepare pm-board.c for the introduction of Armada 38x support") commit 3cbd6a6ca81c ("ARM: mvebu: Add standby support") For Armada 64-bit SoCs, like the A3700 also using this AHCI driver, PM platform support has always existed. There are even suspend/resume hooks in this driver since: commit d6ecf15814888 ("ata: ahci_mvebu: add suspend/resume support") Remove the stale comment at the end of this driver stating that all the above does not exist yet. Fixes: d6ecf15814888 ("ata: ahci_mvebu: add suspend/resume support") Signed-off-by: Miquel Raynal Signed-off-by: Jens Axboe --- drivers/ata/ahci_mvebu.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index f9cb51be38eb..128d6f22926d 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -197,11 +197,6 @@ static const struct of_device_id ahci_mvebu_of_match[] = { }; MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match); -/* - * We currently don't provide power management related operations, - * since there is no suspend/resume support at the platform level for - * Armada 38x for the moment. - */ static struct platform_driver ahci_mvebu_driver = { .probe = ahci_mvebu_probe, .remove = ata_platform_remove_one, -- cgit v1.2.3-58-ga151 From 96dbcb40e4b1a387cdb9b21f43638c759aebb5a4 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 4 Dec 2018 20:28:27 +0100 Subject: ata: ahci: mvebu: do Armada 38x configuration only on relevant SoCs At the beginning, only Armada 38x SoCs where supported by the ahci_mvebu.c driver. Commit 15d3ce7b63bd ("ata: ahci_mvebu: add support for Armada 3700 variant") introduced Armada 3700 support. As opposed to Armada 38x SoCs, the 3700 variants do not have to configure mbus and the regret option. This patch took care of avoiding such configuration when not needed in the probe function, but failed to do the same in the resume path. While doing so looks harmless by experience, let's clean the driver logic and avoid doing this useless configuration with Armada 3700 SoCs. Because the logic is very similar between these two places, it has been decided to factorize this code and put it in a "Armada 38x configuration function". This function is part of a new (per-compatible) platform data structure, so that the addition of such configuration function for Armada 3700 will be eased. Fixes: 15d3ce7b63bd ("ata: ahci_mvebu: add support for Armada 3700 variant") Signed-off-by: Miquel Raynal Signed-off-by: Jens Axboe --- drivers/ata/ahci_mvebu.c | 68 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index 128d6f22926d..7839a5df1fd2 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -28,6 +28,10 @@ #define AHCI_WINDOW_BASE(win) (0x64 + ((win) << 4)) #define AHCI_WINDOW_SIZE(win) (0x68 + ((win) << 4)) +struct ahci_mvebu_plat_data { + int (*plat_config)(struct ahci_host_priv *hpriv); +}; + static void ahci_mvebu_mbus_config(struct ahci_host_priv *hpriv, const struct mbus_dram_target_info *dram) { @@ -62,6 +66,22 @@ static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv) writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); } +static int ahci_mvebu_armada_380_config(struct ahci_host_priv *hpriv) +{ + const struct mbus_dram_target_info *dram; + int rc = 0; + + dram = mv_mbus_dram_info(); + if (dram) + ahci_mvebu_mbus_config(hpriv, dram); + else + rc = -ENODEV; + + ahci_mvebu_regret_option(hpriv); + + return rc; +} + /** * ahci_mvebu_stop_engine * @@ -126,13 +146,10 @@ static int ahci_mvebu_resume(struct platform_device *pdev) { struct ata_host *host = platform_get_drvdata(pdev); struct ahci_host_priv *hpriv = host->private_data; - const struct mbus_dram_target_info *dram; + const struct ahci_mvebu_plat_data *pdata = hpriv->plat_data; - dram = mv_mbus_dram_info(); - if (dram) - ahci_mvebu_mbus_config(hpriv, dram); - - ahci_mvebu_regret_option(hpriv); + if (pdata->plat_config) + pdata->plat_config(hpriv); return ahci_platform_resume_host(&pdev->dev); } @@ -154,28 +171,31 @@ static struct scsi_host_template ahci_platform_sht = { static int ahci_mvebu_probe(struct platform_device *pdev) { + const struct ahci_mvebu_plat_data *pdata; struct ahci_host_priv *hpriv; - const struct mbus_dram_target_info *dram; int rc; + pdata = of_device_get_match_data(&pdev->dev); + if (!pdata) + return -EINVAL; + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); + hpriv->plat_data = (void *)pdata; + rc = ahci_platform_enable_resources(hpriv); if (rc) return rc; hpriv->stop_engine = ahci_mvebu_stop_engine; - if (of_device_is_compatible(pdev->dev.of_node, - "marvell,armada-380-ahci")) { - dram = mv_mbus_dram_info(); - if (!dram) - return -ENODEV; - - ahci_mvebu_mbus_config(hpriv, dram); - ahci_mvebu_regret_option(hpriv); + pdata = hpriv->plat_data; + if (pdata->plat_config) { + rc = pdata->plat_config(hpriv); + if (rc) + goto disable_resources; } rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info, @@ -190,9 +210,23 @@ disable_resources: return rc; } +static const struct ahci_mvebu_plat_data ahci_mvebu_armada_380_plat_data = { + .plat_config = ahci_mvebu_armada_380_config, +}; + +static const struct ahci_mvebu_plat_data ahci_mvebu_armada_3700_plat_data = { + .plat_config = NULL, +}; + static const struct of_device_id ahci_mvebu_of_match[] = { - { .compatible = "marvell,armada-380-ahci", }, - { .compatible = "marvell,armada-3700-ahci", }, + { + .compatible = "marvell,armada-380-ahci", + .data = &ahci_mvebu_armada_380_plat_data, + }, + { + .compatible = "marvell,armada-3700-ahci", + .data = &ahci_mvebu_armada_3700_plat_data, + }, { }, }; MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match); -- cgit v1.2.3-58-ga151 From 2f558bc3f33ca344489cec2218545741028b6a70 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 4 Dec 2018 20:28:28 +0100 Subject: ata: ahci: mvebu: add Armada 3700 initialization needed for S2RAM A3700 comphy initialization is done in the firmware (TF-A). Looking at the SATA PHY initialization routine, there is a comment about "vendor specific" registers. Two registers are mentioned. They are not initialized there in the firmware because they are AHCI related, while the firmware at this location does only PHY configuration. The solution to avoid doing such initialization is relying on U-Boot. While this work at boot time, U-Boot is definitely not going to run during a resume after suspending to RAM. Two possible solutions were considered: * Fixing the firmware. * Fixing the kernel driver. The first solution would take ages to propagate, while the second solution is easy to implement as the driver as been a little bit reworked to prepare for such platform configuration. Hence, this patch adds an Armada 3700 configuration function to set these two registers both at boot time (in the probe) and after a suspend (in the resume path). Signed-off-by: Miquel Raynal Signed-off-by: Jens Axboe --- drivers/ata/ahci_mvebu.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index 7839a5df1fd2..bbab688d3c34 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -82,6 +82,19 @@ static int ahci_mvebu_armada_380_config(struct ahci_host_priv *hpriv) return rc; } +static int ahci_mvebu_armada_3700_config(struct ahci_host_priv *hpriv) +{ + u32 reg; + + writel(0, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_ADDR); + + reg = readl(hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); + reg |= BIT(6); + writel(reg, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA); + + return 0; +} + /** * ahci_mvebu_stop_engine * @@ -148,8 +161,7 @@ static int ahci_mvebu_resume(struct platform_device *pdev) struct ahci_host_priv *hpriv = host->private_data; const struct ahci_mvebu_plat_data *pdata = hpriv->plat_data; - if (pdata->plat_config) - pdata->plat_config(hpriv); + pdata->plat_config(hpriv); return ahci_platform_resume_host(&pdev->dev); } @@ -191,12 +203,9 @@ static int ahci_mvebu_probe(struct platform_device *pdev) hpriv->stop_engine = ahci_mvebu_stop_engine; - pdata = hpriv->plat_data; - if (pdata->plat_config) { - rc = pdata->plat_config(hpriv); - if (rc) - goto disable_resources; - } + rc = pdata->plat_config(hpriv); + if (rc) + goto disable_resources; rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info, &ahci_platform_sht); @@ -215,7 +224,7 @@ static const struct ahci_mvebu_plat_data ahci_mvebu_armada_380_plat_data = { }; static const struct ahci_mvebu_plat_data ahci_mvebu_armada_3700_plat_data = { - .plat_config = NULL, + .plat_config = ahci_mvebu_armada_3700_config, }; static const struct of_device_id ahci_mvebu_of_match[] = { -- cgit v1.2.3-58-ga151 From bde0b5c109e8b22b57745e3b9914f9e87ad857ea Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Tue, 4 Dec 2018 20:28:29 +0100 Subject: ata: ahci: mvebu: request PHY suspend/resume for Armada 3700 A feature has been added in the libahci driver: the possibility to set a new flag in hpriv->flags to let the core handle PHY suspend/resume automatically. Make use of this feature to make suspend to RAM work with SATA drives on A3700. Signed-off-by: Miquel Raynal Signed-off-by: Jens Axboe --- drivers/ata/ahci_mvebu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index bbab688d3c34..d4bba3ace45d 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -30,6 +30,7 @@ struct ahci_mvebu_plat_data { int (*plat_config)(struct ahci_host_priv *hpriv); + unsigned int flags; }; static void ahci_mvebu_mbus_config(struct ahci_host_priv *hpriv, @@ -195,6 +196,7 @@ static int ahci_mvebu_probe(struct platform_device *pdev) if (IS_ERR(hpriv)) return PTR_ERR(hpriv); + hpriv->flags |= pdata->flags; hpriv->plat_data = (void *)pdata; rc = ahci_platform_enable_resources(hpriv); @@ -225,6 +227,7 @@ static const struct ahci_mvebu_plat_data ahci_mvebu_armada_380_plat_data = { static const struct ahci_mvebu_plat_data ahci_mvebu_armada_3700_plat_data = { .plat_config = ahci_mvebu_armada_3700_config, + .flags = AHCI_HFLAG_SUSPEND_PHYS, }; static const struct of_device_id ahci_mvebu_of_match[] = { -- cgit v1.2.3-58-ga151 From 0919871ac37fdcf46c7657da0f1742efe096b399 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Fri, 11 Jan 2019 14:46:37 -0800 Subject: acpi/nfit: Fix race accessing memdev in nfit_get_smbios_id() Possible race accessing memdev structures after dropping the mutex. Dan Williams says this could race against another thread that is doing: # echo "ACPI0012:00" > /sys/bus/acpi/drivers/nfit/unbind Reported-by: Jane Chu Fixes: 23222f8f8dce ("acpi, nfit: Add function to look up nvdimm...") Signed-off-by: Tony Luck Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 4ae953a5aebf..790691d9a982 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -714,6 +714,7 @@ int nfit_get_smbios_id(u32 device_handle, u16 *flags) struct acpi_nfit_memory_map *memdev; struct acpi_nfit_desc *acpi_desc; struct nfit_mem *nfit_mem; + u16 physical_id; mutex_lock(&acpi_desc_lock); list_for_each_entry(acpi_desc, &acpi_descs, list) { @@ -721,10 +722,11 @@ int nfit_get_smbios_id(u32 device_handle, u16 *flags) list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) { memdev = __to_nfit_memdev(nfit_mem); if (memdev->device_handle == device_handle) { + *flags = memdev->flags; + physical_id = memdev->physical_id; mutex_unlock(&acpi_desc->init_mutex); mutex_unlock(&acpi_desc_lock); - *flags = memdev->flags; - return memdev->physical_id; + return physical_id; } } mutex_unlock(&acpi_desc->init_mutex); -- cgit v1.2.3-58-ga151 From 8217724eb7c51bbec351b23cbc924577b2f4b8e6 Mon Sep 17 00:00:00 2001 From: Otto Sabart Date: Wed, 9 Jan 2019 00:46:55 +0100 Subject: doc: bindings: fix bad reference to ARM CPU bindings The primecell.txt and cpus.txt files were converted into YAML. This patch updates old references with new ones. Fixes: d3c207eeb905 ("dt-bindings: arm: Convert primecell binding to json-schema") Fixes: 672951cbd1b7 ("dt-bindings: arm: Convert cpu binding to json-schema") Signed-off-by: Otto Sabart Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/arm/cpu-capacity.txt | 2 +- Documentation/devicetree/bindings/arm/idle-states.txt | 2 +- Documentation/devicetree/bindings/arm/sp810.txt | 2 +- Documentation/devicetree/bindings/arm/topology.txt | 2 +- Documentation/devicetree/bindings/display/arm,pl11x.txt | 2 +- Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/cpu-capacity.txt b/Documentation/devicetree/bindings/arm/cpu-capacity.txt index 84262cdb8d29..96fa46cb133c 100644 --- a/Documentation/devicetree/bindings/arm/cpu-capacity.txt +++ b/Documentation/devicetree/bindings/arm/cpu-capacity.txt @@ -235,4 +235,4 @@ cpus { =========================================== [1] ARM Linux Kernel documentation - CPUs bindings - Documentation/devicetree/bindings/arm/cpus.txt + Documentation/devicetree/bindings/arm/cpus.yaml diff --git a/Documentation/devicetree/bindings/arm/idle-states.txt b/Documentation/devicetree/bindings/arm/idle-states.txt index 8f0937db55c5..45730ba60af5 100644 --- a/Documentation/devicetree/bindings/arm/idle-states.txt +++ b/Documentation/devicetree/bindings/arm/idle-states.txt @@ -684,7 +684,7 @@ cpus { =========================================== [1] ARM Linux Kernel documentation - CPUs bindings - Documentation/devicetree/bindings/arm/cpus.txt + Documentation/devicetree/bindings/arm/cpus.yaml [2] ARM Linux Kernel documentation - PSCI bindings Documentation/devicetree/bindings/arm/psci.txt diff --git a/Documentation/devicetree/bindings/arm/sp810.txt b/Documentation/devicetree/bindings/arm/sp810.txt index 1b2ab1ff5587..46652bf65147 100644 --- a/Documentation/devicetree/bindings/arm/sp810.txt +++ b/Documentation/devicetree/bindings/arm/sp810.txt @@ -4,7 +4,7 @@ SP810 System Controller Required properties: - compatible: standard compatible string for a Primecell peripheral, - see Documentation/devicetree/bindings/arm/primecell.txt + see Documentation/devicetree/bindings/arm/primecell.yaml for more details should be: "arm,sp810", "arm,primecell" diff --git a/Documentation/devicetree/bindings/arm/topology.txt b/Documentation/devicetree/bindings/arm/topology.txt index de9eb0486630..b0d80c0fb265 100644 --- a/Documentation/devicetree/bindings/arm/topology.txt +++ b/Documentation/devicetree/bindings/arm/topology.txt @@ -472,4 +472,4 @@ cpus { =============================================================================== [1] ARM Linux kernel documentation - Documentation/devicetree/bindings/arm/cpus.txt + Documentation/devicetree/bindings/arm/cpus.yaml diff --git a/Documentation/devicetree/bindings/display/arm,pl11x.txt b/Documentation/devicetree/bindings/display/arm,pl11x.txt index ef89ab46b2c9..572fa2773ec4 100644 --- a/Documentation/devicetree/bindings/display/arm,pl11x.txt +++ b/Documentation/devicetree/bindings/display/arm,pl11x.txt @@ -1,6 +1,6 @@ * ARM PrimeCell Color LCD Controller PL110/PL111 -See also Documentation/devicetree/bindings/arm/primecell.txt +See also Documentation/devicetree/bindings/arm/primecell.yaml Required properties: diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt index b83bb8249074..a3be5298a5eb 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt @@ -78,7 +78,7 @@ Sub-nodes: PPI affinity can be expressed as a single "ppi-partitions" node, containing a set of sub-nodes, each with the following property: - affinity: Should be a list of phandles to CPU nodes (as described in -Documentation/devicetree/bindings/arm/cpus.txt). + Documentation/devicetree/bindings/arm/cpus.yaml). GICv3 has one or more Interrupt Translation Services (ITS) that are used to route Message Signalled Interrupts (MSI) to the CPUs. -- cgit v1.2.3-58-ga151 From 6dea7e1881fd86b80da64e476ac398008daed857 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Wed, 9 Jan 2019 10:05:56 +0100 Subject: net: stmmac: Fix PCI module removal leak Since commit b7d0f08e9129, the enable / disable of PCI device is not managed which will result in IO regions not being automatically unmapped. As regions continue mapped it is currently not possible to remove and then probe again the PCI module of stmmac. Fix this by manually unmapping regions on remove callback. Changes from v1: - Fix build error Cc: Joao Pinto Cc: David S. Miller Cc: Giuseppe Cavallaro Cc: Alexandre Torgue Fixes: b7d0f08e9129 ("net: stmmac: Fix WoL for PCI-based setups") Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index c54a50dbd5ac..d819e8eaba12 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -299,7 +299,17 @@ static int stmmac_pci_probe(struct pci_dev *pdev, */ static void stmmac_pci_remove(struct pci_dev *pdev) { + int i; + stmmac_dvr_remove(&pdev->dev); + + for (i = 0; i <= PCI_STD_RESOURCE_END; i++) { + if (pci_resource_len(pdev, i) == 0) + continue; + pcim_iounmap_regions(pdev, BIT(i)); + break; + } + pci_disable_device(pdev); } -- cgit v1.2.3-58-ga151 From fcc509eb10ff4794641e6ad3082118287a750d0a Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Wed, 9 Jan 2019 10:05:57 +0100 Subject: net: stmmac: dwxgmac2: Only clear interrupts that are active In DMA interrupt handler we were clearing all interrupts status, even the ones that were not active. Fix this and only clear the active interrupts. Cc: Joao Pinto Cc: David S. Miller Cc: Giuseppe Cavallaro Cc: Alexandre Torgue Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index 6c5092e7771c..c5e25580a43f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -263,6 +263,7 @@ static int dwxgmac2_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x, u32 chan) { u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan)); + u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); int ret = 0; /* ABNORMAL interrupts */ @@ -282,8 +283,7 @@ static int dwxgmac2_dma_interrupt(void __iomem *ioaddr, x->normal_irq_n++; if (likely(intr_status & XGMAC_RI)) { - u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); - if (likely(value & XGMAC_RIE)) { + if (likely(intr_en & XGMAC_RIE)) { x->rx_normal_irq_n++; ret |= handle_rx; } @@ -295,7 +295,7 @@ static int dwxgmac2_dma_interrupt(void __iomem *ioaddr, } /* Clear interrupts */ - writel(~0x0, ioaddr + XGMAC_DMA_CH_STATUS(chan)); + writel(intr_en & intr_status, ioaddr + XGMAC_DMA_CH_STATUS(chan)); return ret; } -- cgit v1.2.3-58-ga151 From 0650d4017f4d2eee67230a02285a7ae5204240c2 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Wed, 9 Jan 2019 10:05:58 +0100 Subject: net: stmmac: Check if CBS is supported before configuring Check if CBS is currently supported before trying to configure it in HW. Cc: Joao Pinto Cc: David S. Miller Cc: Giuseppe Cavallaro Cc: Alexandre Torgue Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 531294f4978b..58ea18af9813 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -301,6 +301,8 @@ static int tc_setup_cbs(struct stmmac_priv *priv, /* Queue 0 is not AVB capable */ if (queue <= 0 || queue >= tx_queues_count) return -EINVAL; + if (!priv->dma_cap.av) + return -EOPNOTSUPP; if (priv->speed != SPEED_100 && priv->speed != SPEED_1000) return -EOPNOTSUPP; -- cgit v1.2.3-58-ga151 From 3b5094665e273c4a2a99f7f5f16977c0f1e19095 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Wed, 9 Jan 2019 10:05:59 +0100 Subject: net: stmmac: Fix the logic of checking if RX Watchdog must be enabled RX Watchdog can be disabled by platform definitions but currently we are initializing the descriptors before checking if Watchdog must be disabled or not. Fix this by checking earlier if user wants Watchdog disabled or not. Cc: Joao Pinto Cc: David S. Miller Cc: Giuseppe Cavallaro Cc: Alexandre Torgue Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 0e0a0789c2ed..83ceb1a12e77 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4168,6 +4168,18 @@ static int stmmac_hw_init(struct stmmac_priv *priv) return ret; } + /* Rx Watchdog is available in the COREs newer than the 3.40. + * In some case, for example on bugged HW this feature + * has to be disable and this can be done by passing the + * riwt_off field from the platform. + */ + if (((priv->synopsys_id >= DWMAC_CORE_3_50) || + (priv->plat->has_xgmac)) && (!priv->plat->riwt_off)) { + priv->use_riwt = 1; + dev_info(priv->device, + "Enable RX Mitigation via HW Watchdog Timer\n"); + } + return 0; } @@ -4300,18 +4312,6 @@ int stmmac_dvr_probe(struct device *device, if (flow_ctrl) priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */ - /* Rx Watchdog is available in the COREs newer than the 3.40. - * In some case, for example on bugged HW this feature - * has to be disable and this can be done by passing the - * riwt_off field from the platform. - */ - if (((priv->synopsys_id >= DWMAC_CORE_3_50) || - (priv->plat->has_xgmac)) && (!priv->plat->riwt_off)) { - priv->use_riwt = 1; - dev_info(priv->device, - "Enable RX Mitigation via HW Watchdog Timer\n"); - } - /* Setup channels NAPI */ maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use); -- cgit v1.2.3-58-ga151 From fa0be0a43f101888ac677dba31b590963eafeaa1 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Wed, 9 Jan 2019 10:06:00 +0100 Subject: net: stmmac: Prevent RX starvation in stmmac_napi_poll() Currently, TX is given a budget which is consumed by stmmac_tx_clean() and stmmac_rx() is given the remaining non-consumed budget. This is wrong and in case we are sending a large number of packets this can starve RX because remaining budget will be low. Let's give always the same budget for RX and TX clean. While at it, check if we missed any interrupts while we were in NAPI callback by looking at DMA interrupt status. Cc: Joao Pinto Cc: David S. Miller Cc: Giuseppe Cavallaro Cc: Alexandre Torgue Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 27 ++++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 83ceb1a12e77..3f23e14891df 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3525,27 +3525,28 @@ static int stmmac_napi_poll(struct napi_struct *napi, int budget) struct stmmac_channel *ch = container_of(napi, struct stmmac_channel, napi); struct stmmac_priv *priv = ch->priv_data; - int work_done = 0, work_rem = budget; + int work_done, rx_done = 0, tx_done = 0; u32 chan = ch->index; priv->xstats.napi_poll++; - if (ch->has_tx) { - int done = stmmac_tx_clean(priv, work_rem, chan); + if (ch->has_tx) + tx_done = stmmac_tx_clean(priv, budget, chan); + if (ch->has_rx) + rx_done = stmmac_rx(priv, budget, chan); - work_done += done; - work_rem -= done; - } - - if (ch->has_rx) { - int done = stmmac_rx(priv, work_rem, chan); + work_done = max(rx_done, tx_done); + work_done = min(work_done, budget); - work_done += done; - work_rem -= done; - } + if (work_done < budget && napi_complete_done(napi, work_done)) { + int stat; - if (work_done < budget && napi_complete_done(napi, work_done)) stmmac_enable_dma_irq(priv, priv->ioaddr, chan); + stat = stmmac_dma_interrupt_status(priv, priv->ioaddr, + &priv->xstats, chan); + if (stat && napi_reschedule(napi)) + stmmac_disable_dma_irq(priv, priv->ioaddr, chan); + } return work_done; } -- cgit v1.2.3-58-ga151 From c0a636e4cc2eb39244d23c0417c117be4c96a7fe Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 17 Dec 2018 18:06:14 -0600 Subject: clk: socfpga: stratix10: fix rate calculation for pll clocks The main PLL calculation has a mistake. We should be using the multiplying the VCO frequency, not the parent clock frequency. Fixes: 07afb8db7340 ("clk: socfpga: stratix10: add clock driver for Stratix10 platform") Cc: linux-stable@vger.kernel.org Signed-off-by: Dinh Nguyen Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-pll-s10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/socfpga/clk-pll-s10.c b/drivers/clk/socfpga/clk-pll-s10.c index 2d5d8b43727e..c4d0b6f6abf2 100644 --- a/drivers/clk/socfpga/clk-pll-s10.c +++ b/drivers/clk/socfpga/clk-pll-s10.c @@ -43,7 +43,7 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk, /* Read mdiv and fdiv from the fdbck register */ reg = readl(socfpgaclk->hw.reg + 0x4); mdiv = (reg & SOCFPGA_PLL_MDIV_MASK) >> SOCFPGA_PLL_MDIV_SHIFT; - vco_freq = (unsigned long long)parent_rate * (mdiv + 6); + vco_freq = (unsigned long long)vco_freq * (mdiv + 6); return (unsigned long)vco_freq; } -- cgit v1.2.3-58-ga151 From 7fbe078c37aba3088359c9256c1a1d0c3e39ee81 Mon Sep 17 00:00:00 2001 From: Zha Bin Date: Tue, 8 Jan 2019 16:07:03 +0800 Subject: vhost/vsock: fix vhost vsock cid hashing inconsistent The vsock core only supports 32bit CID, but the Virtio-vsock spec define CID (dst_cid and src_cid) as u64 and the upper 32bits is reserved as zero. This inconsistency causes one bug in vhost vsock driver. The scenarios is: 0. A hash table (vhost_vsock_hash) is used to map an CID to a vsock object. And hash_min() is used to compute the hash key. hash_min() is defined as: (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits)). That means the hash algorithm has dependency on the size of macro argument 'val'. 0. In function vhost_vsock_set_cid(), a 64bit CID is passed to hash_min() to compute the hash key when inserting a vsock object into the hash table. 0. In function vhost_vsock_get(), a 32bit CID is passed to hash_min() to compute the hash key when looking up a vsock for an CID. Because the different size of the CID, hash_min() returns different hash key, thus fails to look up the vsock object for an CID. To fix this bug, we keep CID as u64 in the IOCTLs and virtio message headers, but explicitly convert u64 to u32 when deal with the hash table and vsock core. Fixes: 834e772c8db0 ("vhost/vsock: fix use-after-free in network stack callers") Link: https://github.com/stefanha/virtio/blob/vsock/trunk/content.tex Signed-off-by: Zha Bin Reviewed-by: Liu Jiang Reviewed-by: Stefan Hajnoczi Acked-by: Jason Wang Signed-off-by: David S. Miller --- drivers/vhost/vsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index bc42d38ae031..3fbc068eaa9b 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -642,7 +642,7 @@ static int vhost_vsock_set_cid(struct vhost_vsock *vsock, u64 guest_cid) hash_del_rcu(&vsock->hash); vsock->guest_cid = guest_cid; - hash_add_rcu(vhost_vsock_hash, &vsock->hash, guest_cid); + hash_add_rcu(vhost_vsock_hash, &vsock->hash, vsock->guest_cid); mutex_unlock(&vhost_vsock_mutex); return 0; -- cgit v1.2.3-58-ga151 From 2ff33d6637393fe9348357285931811b76e1402f Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Tue, 8 Jan 2019 21:04:48 +0800 Subject: isdn: i4l: isdn_tty: Fix some concurrency double-free bugs The functions isdn_tty_tiocmset() and isdn_tty_set_termios() may be concurrently executed. isdn_tty_tiocmset isdn_tty_modem_hup line 719: kfree(info->dtmf_state); line 721: kfree(info->silence_state); line 723: kfree(info->adpcms); line 725: kfree(info->adpcmr); isdn_tty_set_termios isdn_tty_modem_hup line 719: kfree(info->dtmf_state); line 721: kfree(info->silence_state); line 723: kfree(info->adpcms); line 725: kfree(info->adpcmr); Thus, some concurrency double-free bugs may occur. These possible bugs are found by a static tool written by myself and my manual code review. To fix these possible bugs, the mutex lock "modem_info_mutex" used in isdn_tty_tiocmset() is added in isdn_tty_set_termios(). Signed-off-by: Jia-Ju Bai Signed-off-by: David S. Miller --- drivers/isdn/i4l/isdn_tty.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 1b2239c1d569..dc1cded716c1 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1437,15 +1437,19 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { modem_info *info = (modem_info *) tty->driver_data; + mutex_lock(&modem_info_mutex); if (!old_termios) isdn_tty_change_speed(info); else { if (tty->termios.c_cflag == old_termios->c_cflag && tty->termios.c_ispeed == old_termios->c_ispeed && - tty->termios.c_ospeed == old_termios->c_ospeed) + tty->termios.c_ospeed == old_termios->c_ospeed) { + mutex_unlock(&modem_info_mutex); return; + } isdn_tty_change_speed(info); } + mutex_unlock(&modem_info_mutex); } /* -- cgit v1.2.3-58-ga151 From a94a2572b97744d3a35a1996df0e5cf6b2461a4a Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Fri, 23 Nov 2018 09:15:30 +0800 Subject: scsi: tcmu: avoid cmd/qfull timers updated whenever a new cmd comes Currently there is one cmd timeout timer and one qfull timer for each udev, and whenever any new command is coming in we will update the cmd timer or qfull timer. For some corner cases the timers are always working only for the ringbuffer's and full queue's newest cmd. That's to say the timer won't be fired even if one cmd has been stuck for a very long time and the deadline is reached. This fix will keep the cmd/qfull timers to be pended for the oldest cmd in ringbuffer and full queue, and will update them with the next cmd's deadline only when the old cmd's deadline is reached or removed from the ringbuffer and full queue. Signed-off-by: Xiubo Li Acked-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 88 +++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 1e6d24943565..c34c88ef3319 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -148,7 +148,7 @@ struct tcmu_dev { size_t ring_size; struct mutex cmdr_lock; - struct list_head cmdr_queue; + struct list_head qfull_queue; uint32_t dbi_max; uint32_t dbi_thresh; @@ -159,6 +159,7 @@ struct tcmu_dev { struct timer_list cmd_timer; unsigned int cmd_time_out; + struct list_head inflight_queue; struct timer_list qfull_timer; int qfull_time_out; @@ -179,7 +180,7 @@ struct tcmu_dev { struct tcmu_cmd { struct se_cmd *se_cmd; struct tcmu_dev *tcmu_dev; - struct list_head cmdr_queue_entry; + struct list_head queue_entry; uint16_t cmd_id; @@ -192,6 +193,7 @@ struct tcmu_cmd { unsigned long deadline; #define TCMU_CMD_BIT_EXPIRED 0 +#define TCMU_CMD_BIT_INFLIGHT 1 unsigned long flags; }; /* @@ -586,7 +588,7 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd) if (!tcmu_cmd) return NULL; - INIT_LIST_HEAD(&tcmu_cmd->cmdr_queue_entry); + INIT_LIST_HEAD(&tcmu_cmd->queue_entry); tcmu_cmd->se_cmd = se_cmd; tcmu_cmd->tcmu_dev = udev; @@ -915,11 +917,13 @@ setup_timer: return 0; tcmu_cmd->deadline = round_jiffies_up(jiffies + msecs_to_jiffies(tmo)); - mod_timer(timer, tcmu_cmd->deadline); + if (!timer_pending(timer)) + mod_timer(timer, tcmu_cmd->deadline); + return 0; } -static int add_to_cmdr_queue(struct tcmu_cmd *tcmu_cmd) +static int add_to_qfull_queue(struct tcmu_cmd *tcmu_cmd) { struct tcmu_dev *udev = tcmu_cmd->tcmu_dev; unsigned int tmo; @@ -942,7 +946,7 @@ static int add_to_cmdr_queue(struct tcmu_cmd *tcmu_cmd) if (ret) return ret; - list_add_tail(&tcmu_cmd->cmdr_queue_entry, &udev->cmdr_queue); + list_add_tail(&tcmu_cmd->queue_entry, &udev->qfull_queue); pr_debug("adding cmd %u on dev %s to ring space wait queue\n", tcmu_cmd->cmd_id, udev->name); return 0; @@ -999,7 +1003,7 @@ static int queue_cmd_ring(struct tcmu_cmd *tcmu_cmd, sense_reason_t *scsi_err) base_command_size = tcmu_cmd_get_base_cmd_size(tcmu_cmd->dbi_cnt); command_size = tcmu_cmd_get_cmd_size(tcmu_cmd, base_command_size); - if (!list_empty(&udev->cmdr_queue)) + if (!list_empty(&udev->qfull_queue)) goto queue; mb = udev->mb_addr; @@ -1096,13 +1100,16 @@ static int queue_cmd_ring(struct tcmu_cmd *tcmu_cmd, sense_reason_t *scsi_err) UPDATE_HEAD(mb->cmd_head, command_size, udev->cmdr_size); tcmu_flush_dcache_range(mb, sizeof(*mb)); + list_add_tail(&tcmu_cmd->queue_entry, &udev->inflight_queue); + set_bit(TCMU_CMD_BIT_INFLIGHT, &tcmu_cmd->flags); + /* TODO: only if FLUSH and FUA? */ uio_event_notify(&udev->uio_info); return 0; queue: - if (add_to_cmdr_queue(tcmu_cmd)) { + if (add_to_qfull_queue(tcmu_cmd)) { *scsi_err = TCM_OUT_OF_RESOURCES; return -1; } @@ -1145,6 +1152,8 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) goto out; + list_del_init(&cmd->queue_entry); + tcmu_cmd_reset_dbi_cur(cmd); if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) { @@ -1194,9 +1203,29 @@ out: tcmu_free_cmd(cmd); } +static void tcmu_set_next_deadline(struct list_head *queue, + struct timer_list *timer) +{ + struct tcmu_cmd *tcmu_cmd, *tmp_cmd; + unsigned long deadline = 0; + + list_for_each_entry_safe(tcmu_cmd, tmp_cmd, queue, queue_entry) { + if (!time_after(jiffies, tcmu_cmd->deadline)) { + deadline = tcmu_cmd->deadline; + break; + } + } + + if (deadline) + mod_timer(timer, deadline); + else + del_timer(timer); +} + static unsigned int tcmu_handle_completions(struct tcmu_dev *udev) { struct tcmu_mailbox *mb; + struct tcmu_cmd *cmd; int handled = 0; if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) { @@ -1210,7 +1239,6 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev) while (udev->cmdr_last_cleaned != READ_ONCE(mb->cmd_tail)) { struct tcmu_cmd_entry *entry = (void *) mb + CMDR_OFF + udev->cmdr_last_cleaned; - struct tcmu_cmd *cmd; tcmu_flush_dcache_range(entry, sizeof(*entry)); @@ -1243,7 +1271,7 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev) /* no more pending commands */ del_timer(&udev->cmd_timer); - if (list_empty(&udev->cmdr_queue)) { + if (list_empty(&udev->qfull_queue)) { /* * no more pending or waiting commands so try to * reclaim blocks if needed. @@ -1252,6 +1280,8 @@ static unsigned int tcmu_handle_completions(struct tcmu_dev *udev) tcmu_global_max_blocks) schedule_delayed_work(&tcmu_unmap_work, 0); } + } else if (udev->cmd_time_out) { + tcmu_set_next_deadline(&udev->inflight_queue, &udev->cmd_timer); } return handled; @@ -1271,7 +1301,7 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data) if (!time_after(jiffies, cmd->deadline)) return 0; - is_running = list_empty(&cmd->cmdr_queue_entry); + is_running = test_bit(TCMU_CMD_BIT_INFLIGHT, &cmd->flags); se_cmd = cmd->se_cmd; if (is_running) { @@ -1288,12 +1318,11 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data) */ scsi_status = SAM_STAT_CHECK_CONDITION; } else { - list_del_init(&cmd->cmdr_queue_entry); - idr_remove(&udev->commands, id); tcmu_free_cmd(cmd); scsi_status = SAM_STAT_TASK_SET_FULL; } + list_del_init(&cmd->queue_entry); pr_debug("Timing out cmd %u on dev %s that is %s.\n", id, udev->name, is_running ? "inflight" : "queued"); @@ -1372,7 +1401,8 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) INIT_LIST_HEAD(&udev->node); INIT_LIST_HEAD(&udev->timedout_entry); - INIT_LIST_HEAD(&udev->cmdr_queue); + INIT_LIST_HEAD(&udev->qfull_queue); + INIT_LIST_HEAD(&udev->inflight_queue); idr_init(&udev->commands); timer_setup(&udev->qfull_timer, tcmu_qfull_timedout, 0); @@ -1383,7 +1413,7 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) return &udev->se_dev; } -static bool run_cmdr_queue(struct tcmu_dev *udev, bool fail) +static bool run_qfull_queue(struct tcmu_dev *udev, bool fail) { struct tcmu_cmd *tcmu_cmd, *tmp_cmd; LIST_HEAD(cmds); @@ -1391,15 +1421,15 @@ static bool run_cmdr_queue(struct tcmu_dev *udev, bool fail) sense_reason_t scsi_ret; int ret; - if (list_empty(&udev->cmdr_queue)) + if (list_empty(&udev->qfull_queue)) return true; pr_debug("running %s's cmdr queue forcefail %d\n", udev->name, fail); - list_splice_init(&udev->cmdr_queue, &cmds); + list_splice_init(&udev->qfull_queue, &cmds); - list_for_each_entry_safe(tcmu_cmd, tmp_cmd, &cmds, cmdr_queue_entry) { - list_del_init(&tcmu_cmd->cmdr_queue_entry); + list_for_each_entry_safe(tcmu_cmd, tmp_cmd, &cmds, queue_entry) { + list_del_init(&tcmu_cmd->queue_entry); pr_debug("removing cmd %u on dev %s from queue\n", tcmu_cmd->cmd_id, udev->name); @@ -1437,14 +1467,13 @@ static bool run_cmdr_queue(struct tcmu_dev *udev, bool fail) * cmd was requeued, so just put all cmds back in * the queue */ - list_splice_tail(&cmds, &udev->cmdr_queue); + list_splice_tail(&cmds, &udev->qfull_queue); drained = false; - goto done; + break; } } - if (list_empty(&udev->cmdr_queue)) - del_timer(&udev->qfull_timer); -done: + + tcmu_set_next_deadline(&udev->qfull_queue, &udev->qfull_timer); return drained; } @@ -1454,7 +1483,7 @@ static int tcmu_irqcontrol(struct uio_info *info, s32 irq_on) mutex_lock(&udev->cmdr_lock); tcmu_handle_completions(udev); - run_cmdr_queue(udev, false); + run_qfull_queue(udev, false); mutex_unlock(&udev->cmdr_lock); return 0; @@ -1982,7 +2011,7 @@ static void tcmu_block_dev(struct tcmu_dev *udev) /* complete IO that has executed successfully */ tcmu_handle_completions(udev); /* fail IO waiting to be queued */ - run_cmdr_queue(udev, true); + run_qfull_queue(udev, true); unlock: mutex_unlock(&udev->cmdr_lock); @@ -1997,7 +2026,7 @@ static void tcmu_reset_ring(struct tcmu_dev *udev, u8 err_level) mutex_lock(&udev->cmdr_lock); idr_for_each_entry(&udev->commands, cmd, i) { - if (!list_empty(&cmd->cmdr_queue_entry)) + if (!test_bit(TCMU_CMD_BIT_INFLIGHT, &cmd->flags)) continue; pr_debug("removing cmd %u on dev %s from ring (is expired %d)\n", @@ -2006,6 +2035,7 @@ static void tcmu_reset_ring(struct tcmu_dev *udev, u8 err_level) idr_remove(&udev->commands, i); if (!test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { + list_del_init(&cmd->queue_entry); if (err_level == 1) { /* * Userspace was not able to start the @@ -2666,6 +2696,10 @@ static void check_timedout_devices(void) mutex_lock(&udev->cmdr_lock); idr_for_each(&udev->commands, tcmu_check_expired_cmd, NULL); + + tcmu_set_next_deadline(&udev->inflight_queue, &udev->cmd_timer); + tcmu_set_next_deadline(&udev->qfull_queue, &udev->qfull_timer); + mutex_unlock(&udev->cmdr_lock); spin_lock_bh(&timed_out_udevs_lock); -- cgit v1.2.3-58-ga151 From 73ab1cb2de9e3efe7f818d5453de271e5371df1d Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Wed, 9 Jan 2019 02:23:56 +0900 Subject: umh: add exit routine for UMH process A UMH process which is created by the fork_usermode_blob() such as bpfilter needs to release members of the umh_info when process is terminated. But the do_exit() does not release members of the umh_info. hence module which uses UMH needs own code to detect whether UMH process is terminated or not. But this implementation needs extra code for checking the status of UMH process. it eventually makes the code more complex. The new PF_UMH flag is added and it is used to identify UMH processes. The exit_umh() does not release members of the umh_info. Hence umh_info->cleanup callback should release both members of the umh_info and the private data. Suggested-by: David S. Miller Signed-off-by: Taehee Yoo Signed-off-by: David S. Miller --- include/linux/sched.h | 9 +++++++++ include/linux/umh.h | 2 ++ kernel/exit.c | 1 + kernel/umh.c | 33 +++++++++++++++++++++++++++++++-- 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 89541d248893..e35e35b9fc48 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1406,6 +1406,7 @@ extern struct pid *cad_pid; #define PF_RANDOMIZE 0x00400000 /* Randomize virtual address space */ #define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */ #define PF_MEMSTALL 0x01000000 /* Stalled due to lack of memory */ +#define PF_UMH 0x02000000 /* I'm an Usermodehelper process */ #define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */ #define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */ #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ @@ -1904,6 +1905,14 @@ static inline void rseq_execve(struct task_struct *t) #endif +void __exit_umh(struct task_struct *tsk); + +static inline void exit_umh(struct task_struct *tsk) +{ + if (unlikely(tsk->flags & PF_UMH)) + __exit_umh(tsk); +} + #ifdef CONFIG_DEBUG_RSEQ void rseq_syscall(struct pt_regs *regs); diff --git a/include/linux/umh.h b/include/linux/umh.h index 235f51b62c71..0c08de356d0d 100644 --- a/include/linux/umh.h +++ b/include/linux/umh.h @@ -47,6 +47,8 @@ struct umh_info { const char *cmdline; struct file *pipe_to_umh; struct file *pipe_from_umh; + struct list_head list; + void (*cleanup)(struct umh_info *info); pid_t pid; }; int fork_usermode_blob(void *data, size_t len, struct umh_info *info); diff --git a/kernel/exit.c b/kernel/exit.c index 8a01b671dc1f..dad70419195c 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -866,6 +866,7 @@ void __noreturn do_exit(long code) exit_task_namespaces(tsk); exit_task_work(tsk); exit_thread(tsk); + exit_umh(tsk); /* * Flush inherited counters to the parent - before the parent diff --git a/kernel/umh.c b/kernel/umh.c index 0baa672e023c..d937cbad903a 100644 --- a/kernel/umh.c +++ b/kernel/umh.c @@ -37,6 +37,8 @@ static kernel_cap_t usermodehelper_bset = CAP_FULL_SET; static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET; static DEFINE_SPINLOCK(umh_sysctl_lock); static DECLARE_RWSEM(umhelper_sem); +static LIST_HEAD(umh_list); +static DEFINE_MUTEX(umh_list_lock); static void call_usermodehelper_freeinfo(struct subprocess_info *info) { @@ -100,10 +102,12 @@ static int call_usermodehelper_exec_async(void *data) commit_creds(new); sub_info->pid = task_pid_nr(current); - if (sub_info->file) + if (sub_info->file) { retval = do_execve_file(sub_info->file, sub_info->argv, sub_info->envp); - else + if (!retval) + current->flags |= PF_UMH; + } else retval = do_execve(getname_kernel(sub_info->path), (const char __user *const __user *)sub_info->argv, (const char __user *const __user *)sub_info->envp); @@ -517,6 +521,11 @@ int fork_usermode_blob(void *data, size_t len, struct umh_info *info) goto out; err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC); + if (!err) { + mutex_lock(&umh_list_lock); + list_add(&info->list, &umh_list); + mutex_unlock(&umh_list_lock); + } out: fput(file); return err; @@ -679,6 +688,26 @@ static int proc_cap_handler(struct ctl_table *table, int write, return 0; } +void __exit_umh(struct task_struct *tsk) +{ + struct umh_info *info; + pid_t pid = tsk->pid; + + mutex_lock(&umh_list_lock); + list_for_each_entry(info, &umh_list, list) { + if (info->pid == pid) { + list_del(&info->list); + mutex_unlock(&umh_list_lock); + goto out; + } + } + mutex_unlock(&umh_list_lock); + return; +out: + if (info->cleanup) + info->cleanup(info); +} + struct ctl_table usermodehelper_table[] = { { .procname = "bset", -- cgit v1.2.3-58-ga151 From 5b4cb650e569db2e6a09d2fa0ef8eb789a0ac5d8 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Wed, 9 Jan 2019 02:24:34 +0900 Subject: net: bpfilter: use cleanup callback to release umh_info Now, UMH process is killed, do_exit() calls the umh_info->cleanup callback to release members of the umh_info. This patch makes bpfilter_umh's cleanup routine to use the umh_info->cleanup callback. Signed-off-by: Taehee Yoo Signed-off-by: David S. Miller --- include/linux/bpfilter.h | 11 ++++++++--- net/bpfilter/bpfilter_kern.c | 23 ++++++++++------------- net/ipv4/bpfilter/sockopt.c | 33 ++++++++++++++++++++++++++------- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/include/linux/bpfilter.h b/include/linux/bpfilter.h index f02cee0225d4..70ffeed280e9 100644 --- a/include/linux/bpfilter.h +++ b/include/linux/bpfilter.h @@ -3,13 +3,18 @@ #define _LINUX_BPFILTER_H #include +#include struct sock; int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen); int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen); -extern int (*bpfilter_process_sockopt)(struct sock *sk, int optname, - char __user *optval, - unsigned int optlen, bool is_set); +struct bpfilter_umh_ops { + struct umh_info info; + int (*sockopt)(struct sock *sk, int optname, + char __user *optval, + unsigned int optlen, bool is_set); +}; +extern struct bpfilter_umh_ops bpfilter_ops; #endif diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c index 7acfc83087d5..a68940b74c01 100644 --- a/net/bpfilter/bpfilter_kern.c +++ b/net/bpfilter/bpfilter_kern.c @@ -13,7 +13,6 @@ extern char bpfilter_umh_start; extern char bpfilter_umh_end; -static struct umh_info info; /* since ip_getsockopt() can run in parallel, serialize access to umh */ static DEFINE_MUTEX(bpfilter_lock); @@ -28,16 +27,13 @@ static void shutdown_umh(struct umh_info *info) force_sig(SIGKILL, tsk); put_task_struct(tsk); } - fput(info->pipe_to_umh); - fput(info->pipe_from_umh); - info->pid = 0; } static void __stop_umh(void) { if (IS_ENABLED(CONFIG_INET)) { - bpfilter_process_sockopt = NULL; - shutdown_umh(&info); + bpfilter_ops.sockopt = NULL; + shutdown_umh(&bpfilter_ops.info); } } @@ -64,9 +60,10 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname, req.addr = (long __force __user)optval; req.len = optlen; mutex_lock(&bpfilter_lock); - if (!info.pid) + if (!bpfilter_ops.info.pid) goto out; - n = __kernel_write(info.pipe_to_umh, &req, sizeof(req), &pos); + n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req), + &pos); if (n != sizeof(req)) { pr_err("write fail %zd\n", n); __stop_umh(); @@ -74,7 +71,8 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname, goto out; } pos = 0; - n = kernel_read(info.pipe_from_umh, &reply, sizeof(reply), &pos); + n = kernel_read(bpfilter_ops.info.pipe_from_umh, &reply, sizeof(reply), + &pos); if (n != sizeof(reply)) { pr_err("read fail %zd\n", n); __stop_umh(); @@ -92,13 +90,12 @@ static int __init load_umh(void) int err; /* fork usermode process */ - info.cmdline = "bpfilter_umh"; err = fork_usermode_blob(&bpfilter_umh_start, &bpfilter_umh_end - &bpfilter_umh_start, - &info); + &bpfilter_ops.info); if (err) return err; - pr_info("Loaded bpfilter_umh pid %d\n", info.pid); + pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid); /* health check that usermode process started correctly */ if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) { @@ -106,7 +103,7 @@ static int __init load_umh(void) return -EFAULT; } if (IS_ENABLED(CONFIG_INET)) - bpfilter_process_sockopt = &__bpfilter_process_sockopt; + bpfilter_ops.sockopt = &__bpfilter_process_sockopt; return 0; } diff --git a/net/ipv4/bpfilter/sockopt.c b/net/ipv4/bpfilter/sockopt.c index 5e04ed25bc0e..c326cfbc0f62 100644 --- a/net/ipv4/bpfilter/sockopt.c +++ b/net/ipv4/bpfilter/sockopt.c @@ -1,28 +1,37 @@ // SPDX-License-Identifier: GPL-2.0 +#include +#include #include #include #include #include #include +#include +#include -int (*bpfilter_process_sockopt)(struct sock *sk, int optname, - char __user *optval, - unsigned int optlen, bool is_set); -EXPORT_SYMBOL_GPL(bpfilter_process_sockopt); +struct bpfilter_umh_ops bpfilter_ops; +EXPORT_SYMBOL_GPL(bpfilter_ops); + +static void bpfilter_umh_cleanup(struct umh_info *info) +{ + fput(info->pipe_to_umh); + fput(info->pipe_from_umh); + info->pid = 0; +} static int bpfilter_mbox_request(struct sock *sk, int optname, char __user *optval, unsigned int optlen, bool is_set) { - if (!bpfilter_process_sockopt) { + if (!bpfilter_ops.sockopt) { int err = request_module("bpfilter"); if (err) return err; - if (!bpfilter_process_sockopt) + if (!bpfilter_ops.sockopt) return -ECHILD; } - return bpfilter_process_sockopt(sk, optname, optval, optlen, is_set); + return bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set); } int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval, @@ -41,3 +50,13 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, return bpfilter_mbox_request(sk, optname, optval, len, false); } + +static int __init bpfilter_sockopt_init(void) +{ + bpfilter_ops.info.cmdline = "bpfilter_umh"; + bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup; + + return 0; +} + +module_init(bpfilter_sockopt_init); -- cgit v1.2.3-58-ga151 From 61fbf5933d42b02f552123af5a87a06335a3b4db Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Wed, 9 Jan 2019 02:24:53 +0900 Subject: net: bpfilter: restart bpfilter_umh when error occurred The bpfilter_umh will be stopped via __stop_umh() when the bpfilter error occurred. The bpfilter_umh() couldn't start again because there is no restart routine. The section of the bpfilter_umh_{start/end} is no longer .init.rodata because these area should be reused in the restart routine. hence the section name is changed to .bpfilter_umh. The bpfilter_ops->start() is restart callback. it will be called when bpfilter_umh is stopped. The stop bit means bpfilter_umh is stopped. this bit is set by both start and stop routine. Before this patch, Test commands: $ iptables -vnL $ kill -9 $ iptables -vnL [ 480.045136] bpfilter: write fail -32 $ iptables -vnL All iptables commands will fail. After this patch, Test commands: $ iptables -vnL $ kill -9 $ iptables -vnL $ iptables -vnL Now, all iptables commands will work. Fixes: d2ba09c17a06 ("net: add skeleton of bpfilter kernel module") Signed-off-by: Taehee Yoo Signed-off-by: David S. Miller --- include/linux/bpfilter.h | 2 ++ net/bpfilter/bpfilter_kern.c | 37 +++++++++++++++++++++++++++---------- net/bpfilter/bpfilter_umh_blob.S | 2 +- net/ipv4/bpfilter/sockopt.c | 11 ++++++++++- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/include/linux/bpfilter.h b/include/linux/bpfilter.h index 70ffeed280e9..8ebcbdd70bdc 100644 --- a/include/linux/bpfilter.h +++ b/include/linux/bpfilter.h @@ -15,6 +15,8 @@ struct bpfilter_umh_ops { int (*sockopt)(struct sock *sk, int optname, char __user *optval, unsigned int optlen, bool is_set); + int (*start)(void); + bool stop; }; extern struct bpfilter_umh_ops bpfilter_ops; #endif diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c index a68940b74c01..c0fcde910a7a 100644 --- a/net/bpfilter/bpfilter_kern.c +++ b/net/bpfilter/bpfilter_kern.c @@ -16,13 +16,14 @@ extern char bpfilter_umh_end; /* since ip_getsockopt() can run in parallel, serialize access to umh */ static DEFINE_MUTEX(bpfilter_lock); -static void shutdown_umh(struct umh_info *info) +static void shutdown_umh(void) { struct task_struct *tsk; - if (!info->pid) + if (bpfilter_ops.stop) return; - tsk = get_pid_task(find_vpid(info->pid), PIDTYPE_PID); + + tsk = get_pid_task(find_vpid(bpfilter_ops.info.pid), PIDTYPE_PID); if (tsk) { force_sig(SIGKILL, tsk); put_task_struct(tsk); @@ -31,10 +32,8 @@ static void shutdown_umh(struct umh_info *info) static void __stop_umh(void) { - if (IS_ENABLED(CONFIG_INET)) { - bpfilter_ops.sockopt = NULL; - shutdown_umh(&bpfilter_ops.info); - } + if (IS_ENABLED(CONFIG_INET)) + shutdown_umh(); } static void stop_umh(void) @@ -85,7 +84,7 @@ out: return ret; } -static int __init load_umh(void) +static int start_umh(void) { int err; @@ -95,6 +94,7 @@ static int __init load_umh(void) &bpfilter_ops.info); if (err) return err; + bpfilter_ops.stop = false; pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid); /* health check that usermode process started correctly */ @@ -102,14 +102,31 @@ static int __init load_umh(void) stop_umh(); return -EFAULT; } - if (IS_ENABLED(CONFIG_INET)) - bpfilter_ops.sockopt = &__bpfilter_process_sockopt; return 0; } +static int __init load_umh(void) +{ + int err; + + if (!bpfilter_ops.stop) + return -EFAULT; + err = start_umh(); + if (!err && IS_ENABLED(CONFIG_INET)) { + bpfilter_ops.sockopt = &__bpfilter_process_sockopt; + bpfilter_ops.start = &start_umh; + } + + return err; +} + static void __exit fini_umh(void) { + if (IS_ENABLED(CONFIG_INET)) { + bpfilter_ops.start = NULL; + bpfilter_ops.sockopt = NULL; + } stop_umh(); } module_init(load_umh); diff --git a/net/bpfilter/bpfilter_umh_blob.S b/net/bpfilter/bpfilter_umh_blob.S index 40311d10d2f2..7f1c521dcc2f 100644 --- a/net/bpfilter/bpfilter_umh_blob.S +++ b/net/bpfilter/bpfilter_umh_blob.S @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ - .section .init.rodata, "a" + .section .bpfilter_umh, "a" .global bpfilter_umh_start bpfilter_umh_start: .incbin "net/bpfilter/bpfilter_umh" diff --git a/net/ipv4/bpfilter/sockopt.c b/net/ipv4/bpfilter/sockopt.c index c326cfbc0f62..de84ede4e765 100644 --- a/net/ipv4/bpfilter/sockopt.c +++ b/net/ipv4/bpfilter/sockopt.c @@ -14,6 +14,7 @@ EXPORT_SYMBOL_GPL(bpfilter_ops); static void bpfilter_umh_cleanup(struct umh_info *info) { + bpfilter_ops.stop = true; fput(info->pipe_to_umh); fput(info->pipe_from_umh); info->pid = 0; @@ -23,14 +24,21 @@ static int bpfilter_mbox_request(struct sock *sk, int optname, char __user *optval, unsigned int optlen, bool is_set) { + int err; + if (!bpfilter_ops.sockopt) { - int err = request_module("bpfilter"); + err = request_module("bpfilter"); if (err) return err; if (!bpfilter_ops.sockopt) return -ECHILD; } + if (bpfilter_ops.stop) { + err = bpfilter_ops.start(); + if (err) + return err; + } return bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set); } @@ -53,6 +61,7 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, static int __init bpfilter_sockopt_init(void) { + bpfilter_ops.stop = true; bpfilter_ops.info.cmdline = "bpfilter_umh"; bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup; -- cgit v1.2.3-58-ga151 From 71a8508402b570127d6500c1ad456bbd33ccf187 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Wed, 9 Jan 2019 02:25:10 +0900 Subject: net: bpfilter: disallow to remove bpfilter module while being used The bpfilter.ko module can be removed while functions of the bpfilter.ko are executing. so panic can occurred. in order to protect that, locks can be used. a bpfilter_lock protects routines in the __bpfilter_process_sockopt() but it's not enough because __exit routine can be executed concurrently. Now, the bpfilter_umh can not run in parallel. So, the module do not removed while it's being used and it do not double-create UMH process. The members of the umh_info and the bpfilter_umh_ops are protected by the bpfilter_umh_ops.lock. test commands: while : do iptables -I FORWARD -m string --string ap --algo kmp & modprobe -rv bpfilter & done splat looks like: [ 298.623435] BUG: unable to handle kernel paging request at fffffbfff807440b [ 298.628512] #PF error: [normal kernel read fault] [ 298.633018] PGD 124327067 P4D 124327067 PUD 11c1a3067 PMD 119eb2067 PTE 0 [ 298.638859] Oops: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN PTI [ 298.638859] CPU: 0 PID: 2997 Comm: iptables Not tainted 4.20.0+ #154 [ 298.638859] RIP: 0010:__mutex_lock+0x6b9/0x16a0 [ 298.638859] Code: c0 00 00 e8 89 82 ff ff 80 bd 8f fc ff ff 00 0f 85 d9 05 00 00 48 8b 85 80 fc ff ff 48 bf 00 00 00 00 00 fc ff df 48 c1 e8 03 <80> 3c 38 00 0f 85 1d 0e 00 00 48 8b 85 c8 fc ff ff 49 39 47 58 c6 [ 298.638859] RSP: 0018:ffff88810e7777a0 EFLAGS: 00010202 [ 298.638859] RAX: 1ffffffff807440b RBX: ffff888111bd4d80 RCX: 0000000000000000 [ 298.638859] RDX: 1ffff110235ff806 RSI: ffff888111bd5538 RDI: dffffc0000000000 [ 298.638859] RBP: ffff88810e777b30 R08: 0000000080000002 R09: 0000000000000000 [ 298.638859] R10: 0000000000000000 R11: 0000000000000000 R12: fffffbfff168a42c [ 298.638859] R13: ffff888111bd4d80 R14: ffff8881040e9a05 R15: ffffffffc03a2000 [ 298.638859] FS: 00007f39e3758700(0000) GS:ffff88811ae00000(0000) knlGS:0000000000000000 [ 298.638859] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 298.638859] CR2: fffffbfff807440b CR3: 000000011243e000 CR4: 00000000001006f0 [ 298.638859] Call Trace: [ 298.638859] ? mutex_lock_io_nested+0x1560/0x1560 [ 298.638859] ? kasan_kmalloc+0xa0/0xd0 [ 298.638859] ? kmem_cache_alloc+0x1c2/0x260 [ 298.638859] ? __alloc_file+0x92/0x3c0 [ 298.638859] ? alloc_empty_file+0x43/0x120 [ 298.638859] ? alloc_file_pseudo+0x220/0x330 [ 298.638859] ? sock_alloc_file+0x39/0x160 [ 298.638859] ? __sys_socket+0x113/0x1d0 [ 298.638859] ? __x64_sys_socket+0x6f/0xb0 [ 298.638859] ? do_syscall_64+0x138/0x560 [ 298.638859] ? entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 298.638859] ? __alloc_file+0x92/0x3c0 [ 298.638859] ? init_object+0x6b/0x80 [ 298.638859] ? cyc2ns_read_end+0x10/0x10 [ 298.638859] ? cyc2ns_read_end+0x10/0x10 [ 298.638859] ? hlock_class+0x140/0x140 [ 298.638859] ? sched_clock_local+0xd4/0x140 [ 298.638859] ? sched_clock_local+0xd4/0x140 [ 298.638859] ? check_flags.part.37+0x440/0x440 [ 298.638859] ? __lock_acquire+0x4f90/0x4f90 [ 298.638859] ? set_rq_offline.part.89+0x140/0x140 [ ... ] Fixes: d2ba09c17a06 ("net: add skeleton of bpfilter kernel module") Signed-off-by: Taehee Yoo Signed-off-by: David S. Miller --- include/linux/bpfilter.h | 2 ++ net/bpfilter/bpfilter_kern.c | 28 +++++++++++----------------- net/ipv4/bpfilter/sockopt.c | 22 ++++++++++++++++------ 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/include/linux/bpfilter.h b/include/linux/bpfilter.h index 8ebcbdd70bdc..d815622cd31e 100644 --- a/include/linux/bpfilter.h +++ b/include/linux/bpfilter.h @@ -12,6 +12,8 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen); struct bpfilter_umh_ops { struct umh_info info; + /* since ip_getsockopt() can run in parallel, serialize access to umh */ + struct mutex lock; int (*sockopt)(struct sock *sk, int optname, char __user *optval, unsigned int optlen, bool is_set); diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c index c0fcde910a7a..7ee4fea93637 100644 --- a/net/bpfilter/bpfilter_kern.c +++ b/net/bpfilter/bpfilter_kern.c @@ -13,9 +13,6 @@ extern char bpfilter_umh_start; extern char bpfilter_umh_end; -/* since ip_getsockopt() can run in parallel, serialize access to umh */ -static DEFINE_MUTEX(bpfilter_lock); - static void shutdown_umh(void) { struct task_struct *tsk; @@ -36,13 +33,6 @@ static void __stop_umh(void) shutdown_umh(); } -static void stop_umh(void) -{ - mutex_lock(&bpfilter_lock); - __stop_umh(); - mutex_unlock(&bpfilter_lock); -} - static int __bpfilter_process_sockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen, bool is_set) @@ -58,7 +48,6 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname, req.cmd = optname; req.addr = (long __force __user)optval; req.len = optlen; - mutex_lock(&bpfilter_lock); if (!bpfilter_ops.info.pid) goto out; n = __kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req), @@ -80,7 +69,6 @@ static int __bpfilter_process_sockopt(struct sock *sk, int optname, } ret = reply.status; out: - mutex_unlock(&bpfilter_lock); return ret; } @@ -99,7 +87,7 @@ static int start_umh(void) /* health check that usermode process started correctly */ if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) { - stop_umh(); + shutdown_umh(); return -EFAULT; } @@ -110,24 +98,30 @@ static int __init load_umh(void) { int err; - if (!bpfilter_ops.stop) - return -EFAULT; + mutex_lock(&bpfilter_ops.lock); + if (!bpfilter_ops.stop) { + err = -EFAULT; + goto out; + } err = start_umh(); if (!err && IS_ENABLED(CONFIG_INET)) { bpfilter_ops.sockopt = &__bpfilter_process_sockopt; bpfilter_ops.start = &start_umh; } - +out: + mutex_unlock(&bpfilter_ops.lock); return err; } static void __exit fini_umh(void) { + mutex_lock(&bpfilter_ops.lock); if (IS_ENABLED(CONFIG_INET)) { + shutdown_umh(); bpfilter_ops.start = NULL; bpfilter_ops.sockopt = NULL; } - stop_umh(); + mutex_unlock(&bpfilter_ops.lock); } module_init(load_umh); module_exit(fini_umh); diff --git a/net/ipv4/bpfilter/sockopt.c b/net/ipv4/bpfilter/sockopt.c index de84ede4e765..1e976bb93d99 100644 --- a/net/ipv4/bpfilter/sockopt.c +++ b/net/ipv4/bpfilter/sockopt.c @@ -14,10 +14,12 @@ EXPORT_SYMBOL_GPL(bpfilter_ops); static void bpfilter_umh_cleanup(struct umh_info *info) { + mutex_lock(&bpfilter_ops.lock); bpfilter_ops.stop = true; fput(info->pipe_to_umh); fput(info->pipe_from_umh); info->pid = 0; + mutex_unlock(&bpfilter_ops.lock); } static int bpfilter_mbox_request(struct sock *sk, int optname, @@ -25,21 +27,28 @@ static int bpfilter_mbox_request(struct sock *sk, int optname, unsigned int optlen, bool is_set) { int err; - + mutex_lock(&bpfilter_ops.lock); if (!bpfilter_ops.sockopt) { + mutex_unlock(&bpfilter_ops.lock); err = request_module("bpfilter"); + mutex_lock(&bpfilter_ops.lock); if (err) - return err; - if (!bpfilter_ops.sockopt) - return -ECHILD; + goto out; + if (!bpfilter_ops.sockopt) { + err = -ECHILD; + goto out; + } } if (bpfilter_ops.stop) { err = bpfilter_ops.start(); if (err) - return err; + goto out; } - return bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set); + err = bpfilter_ops.sockopt(sk, optname, optval, optlen, is_set); +out: + mutex_unlock(&bpfilter_ops.lock); + return err; } int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval, @@ -61,6 +70,7 @@ int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, static int __init bpfilter_sockopt_init(void) { + mutex_init(&bpfilter_ops.lock); bpfilter_ops.stop = true; bpfilter_ops.info.cmdline = "bpfilter_umh"; bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup; -- cgit v1.2.3-58-ga151 From 41d1c8839e5f8cb781cc635f12791decee8271b7 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 8 Jan 2019 18:45:05 +0100 Subject: net: clear skb->tstamp in bridge forwarding path Matteo reported forwarding issues inside the linux bridge, if the enslaved interfaces use the fq qdisc. Similar to commit 8203e2d844d3 ("net: clear skb->tstamp in forwarding paths"), we need to clear the tstamp field in the bridge forwarding path. Fixes: 80b14dee2bea ("net: Add a new socket option for a future transmit time.") Fixes: fb420d5d91c1 ("tcp/fq: move back to CLOCK_MONOTONIC") Reported-and-tested-by: Matteo Croce Signed-off-by: Paolo Abeni Acked-by: Nikolay Aleksandrov Acked-by: Roopa Prabhu Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/bridge/br_forward.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 5372e2042adf..2cb8da465b98 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -65,6 +65,7 @@ EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit); int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { + skb->tstamp = 0; return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, net, sk, skb, NULL, skb->dev, br_dev_queue_push_xmit); -- cgit v1.2.3-58-ga151 From 7bb25a89aad2cc96de188c9ecc89a175360f6fb4 Mon Sep 17 00:00:00 2001 From: John Garry Date: Thu, 10 Jan 2019 21:32:41 +0800 Subject: scsi: hisi_sas: Set protection parameters prior to adding SCSI host Currently we set the protection parameters after calling scsi_add_host() for v3 hw. They should be set beforehand, so make this change. Appearantly this fixes our DIX issue (not mainline yet) also, but more testing required. Fixes: d6a9000b81be ("scsi: hisi_sas: Add support for DIF feature for v2 hw") Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index e2420a810e99..c92b3822c408 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -2507,6 +2507,12 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) sha->sas_port[i] = &hisi_hba->port[i].sas_port; } + if (hisi_hba->prot_mask) { + dev_info(dev, "Registering for DIF/DIX prot_mask=0x%x\n", + prot_mask); + scsi_host_set_prot(hisi_hba->shost, prot_mask); + } + rc = scsi_add_host(shost, dev); if (rc) goto err_out_ha; @@ -2519,12 +2525,6 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) goto err_out_register_ha; - if (hisi_hba->prot_mask) { - dev_info(dev, "Registering for DIF/DIX prot_mask=0x%x\n", - prot_mask); - scsi_host_set_prot(hisi_hba->shost, prot_mask); - } - scsi_scan_host(shost); return 0; -- cgit v1.2.3-58-ga151 From 8d008e64a2ebe6567c3f5e048b05842a0297350b Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Jan 2019 15:27:05 -0600 Subject: mISDN: hfcsusb: Use struct_size() in kzalloc() One of the more common cases of allocation size calculations is finding the size of a structure that has a zero-sized array at the end, along with memory for some number of elements for that array. For example: struct foo { int stuff; void *entry[]; }; instance = kzalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL); Instead of leaving these open-coded and prone to type mistakes, we can now use the new struct_size() helper: instance = kzalloc(struct_size(instance, entry, count), GFP_KERNEL); This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/hfcsusb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 6d05946b445e..124ff530da82 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -262,8 +262,7 @@ hfcsusb_ph_info(struct hfcsusb *hw) struct dchannel *dch = &hw->dch; int i; - phi = kzalloc(sizeof(struct ph_info) + - dch->dev.nrbchan * sizeof(struct ph_info_ch), GFP_ATOMIC); + phi = kzalloc(struct_size(phi, bch, dch->dev.nrbchan), GFP_ATOMIC); phi->dch.ch.protocol = hw->protocol; phi->dch.ch.Flags = dch->Flags; phi->dch.state = dch->state; -- cgit v1.2.3-58-ga151 From f0783d43dde4bb349fcd667df0afabbdbab8b477 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 11 Jan 2019 09:40:47 -0800 Subject: scsi: qla2xxx: Use correct number of vectors for online CPUs When SCSI-MQ is enabled, in some case system would present nr_possible_cpus() which is greater than requested vectors by the driver. This results into driver being able to get larger number of MSI-X vectors than actual online CPUs. Driver then uses pci_alloc_irq_vectors_affinity() to assign 1:1 mapping and affinity for each MSI-x vector to CPUs. When the command is submitted using MSI-x vector, assigned to offline CPU, it results in an ABTS and system hang. This hang is result of a driver not being able to process interrupt on a vector assigned to an Off-line CPUs This patch fixes this issue by setting irq_offset value for the blk_mq_pci_map_queues() to use only those CPUs which has CPU mask affinity assigned and are online. By using the irq_offset value, driver will allow online cpumask to decide which vectors are used in blk_mq_pci_map_queues(). Fixes: 5601236b6f794 ("scsi: qla2xxx: Add Block Multi Queue functionality.") Cc: #4.19 Signed-off-by: Ming Lei Reviewed-by: Himanshu Madhani Tested-by: Himanshu Madhani Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 2 ++ drivers/scsi/qla2xxx/qla_isr.c | 1 + drivers/scsi/qla2xxx/qla_os.c | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 26b93c563f92..d1fc4958222a 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -4394,6 +4394,8 @@ typedef struct scsi_qla_host { uint16_t n2n_id; struct list_head gpnid_list; struct fab_scan scan; + + unsigned int irq_offset; } scsi_qla_host_t; struct qla27xx_image_status { diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 30d3090842f8..8507c43b918c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3446,6 +3446,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) "Adjusted Max no of queues pairs: %d.\n", ha->max_qpairs); } } + vha->irq_offset = desc.pre_vectors; ha->msix_entries = kcalloc(ha->msix_count, sizeof(struct qla_msix_entry), GFP_KERNEL); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ea69dafc9774..c6ef83d0d99b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -6939,7 +6939,7 @@ static int qla2xxx_map_queues(struct Scsi_Host *shost) if (USER_CTRL_IRQ(vha->hw)) rc = blk_mq_map_queues(qmap); else - rc = blk_mq_pci_map_queues(qmap, vha->hw->pdev, 0); + rc = blk_mq_pci_map_queues(qmap, vha->hw->pdev, vha->irq_offset); return rc; } -- cgit v1.2.3-58-ga151 From ce9e7bce43526626f7cffe2e657953997870197e Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Mon, 7 Jan 2019 22:19:34 +0800 Subject: scsi: ufs: Fix system suspend status hba->is_sys_suspended is set after successful system suspend but not clear after successful system resume. According to current behavior, hba->is_sys_suspended will not be set if host is runtime-suspended but not system-suspended. Thus we shall aligh the same policy: clear this flag even if host remains runtime-suspended after ufshcd_system_resume is successfully returned. Simply fix this flag to correct host status logs. Signed-off-by: Stanley Chu Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 9ba7671b84f8..71334aaf1447 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8001,6 +8001,8 @@ out: trace_ufshcd_system_resume(dev_name(hba->dev), ret, ktime_to_us(ktime_sub(ktime_get(), start)), hba->curr_dev_pwr_mode, hba->uic_link_state); + if (!ret) + hba->is_sys_suspended = false; return ret; } EXPORT_SYMBOL(ufshcd_system_resume); -- cgit v1.2.3-58-ga151 From 34a2ce887668db9dda4b56e6f155c49ac13f3e54 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Wed, 9 Jan 2019 01:39:07 -0800 Subject: scsi: qedi: Add ep_state for login completion on un-reachable targets When the driver finds invalid destination MAC for the first un-reachable target, and before completes the PATH_REQ operation, set new ep_state to OFFLDCONN_NONE so that as part of driver ep_poll mechanism, the upper open-iscsi layer is notified to complete the login process on the first un-reachable target and thus proceed login to other reachable targets. Signed-off-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/qedi_iscsi.c | 3 +++ drivers/scsi/qedi/qedi_iscsi.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c index 4da660c1c431..6d6d6013e35b 100644 --- a/drivers/scsi/qedi/qedi_iscsi.c +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -953,6 +953,7 @@ static int qedi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) qedi_ep = ep->dd_data; if (qedi_ep->state == EP_STATE_IDLE || + qedi_ep->state == EP_STATE_OFLDCONN_NONE || qedi_ep->state == EP_STATE_OFLDCONN_FAILED) return -1; @@ -1035,6 +1036,7 @@ static void qedi_ep_disconnect(struct iscsi_endpoint *ep) switch (qedi_ep->state) { case EP_STATE_OFLDCONN_START: + case EP_STATE_OFLDCONN_NONE: goto ep_release_conn; case EP_STATE_OFLDCONN_FAILED: break; @@ -1225,6 +1227,7 @@ static int qedi_set_path(struct Scsi_Host *shost, struct iscsi_path *path_data) if (!is_valid_ether_addr(&path_data->mac_addr[0])) { QEDI_NOTICE(&qedi->dbg_ctx, "dst mac NOT VALID\n"); + qedi_ep->state = EP_STATE_OFLDCONN_NONE; ret = -EIO; goto set_path_exit; } diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h index 11260776212f..892d70d54553 100644 --- a/drivers/scsi/qedi/qedi_iscsi.h +++ b/drivers/scsi/qedi/qedi_iscsi.h @@ -59,6 +59,7 @@ enum { EP_STATE_OFLDCONN_FAILED = 0x2000, EP_STATE_CONNECT_FAILED = 0x4000, EP_STATE_DISCONN_TIMEDOUT = 0x8000, + EP_STATE_OFLDCONN_NONE = 0x10000, }; struct qedi_conn; -- cgit v1.2.3-58-ga151 From c65bfc8163696dd171e081488b0321beb630b708 Mon Sep 17 00:00:00 2001 From: Shivasharan S Date: Wed, 9 Jan 2019 05:08:37 -0800 Subject: scsi: megaraid_sas: Retry reads of outbound_intr_status reg commit 272652fcbf1a ("scsi: megaraid_sas: add retry logic in megasas_readl") missed changing readl to megasas_readl in megasas_clear_intr_fusion(). For Aero controllers, reads of outbound_intr_status register needs to be retried. Reported-by: Tomas Henzl Signed-off-by: Shivasharan S Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fusion.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 211c17c33aa0..2665dbdcf2f8 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -175,7 +175,8 @@ megasas_clear_intr_fusion(struct megasas_instance *instance) /* * Check if it is our interrupt */ - status = readl(®s->outbound_intr_status); + status = megasas_readl(instance, + ®s->outbound_intr_status); if (status & 1) { writel(status, ®s->outbound_intr_status); -- cgit v1.2.3-58-ga151 From 9be9db9f78f52ef03ee90063730cb9d730e7032b Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 10 Jan 2019 13:31:26 +0200 Subject: scsi: ufs: Fix geometry descriptor size Albeit we no longer rely on those hard-coded descriptor sizes, we still use them as our defaults, so better get it right. While adding its sysfs entries, we forgot to update the geometry descriptor size. It is 0x48 according to UFS2.1, and wasn't changed in UFS3.0. [mkp: typo] Fixes: c720c091222e (scsi: ufs: sysfs: geometry descriptor) Signed-off-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index dd65fea07687..6d176815e6ce 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -195,7 +195,7 @@ enum ufs_desc_def_size { QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90, QUERY_DESC_UNIT_DEF_SIZE = 0x23, QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, - QUERY_DESC_GEOMETRY_DEF_SIZE = 0x44, + QUERY_DESC_GEOMETRY_DEF_SIZE = 0x48, QUERY_DESC_POWER_DEF_SIZE = 0x62, QUERY_DESC_HEALTH_DEF_SIZE = 0x25, }; -- cgit v1.2.3-58-ga151 From 4a01ab60f55041b1ccc760e43258a5b3aeeca1bc Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Wed, 9 Jan 2019 15:09:02 +0100 Subject: scsi: qla1280: set 64bit coherent mask After Commit 54aed4dd3526 ("MIPS: IP27: use dma_direct_ops") qla1280 driver failed on SGI IP27 machines with qla1280: QLA1040 found on PCI bus 0, dev 0 qla1280 0000:00:00.0: enabling device (0006 -> 0007) qla1280: Failed to get request memory qla1280: probe of 0000:00:00.0 failed with error -12 Reason is that SGI IP27 always generates 64bit DMA addresses and has no fallback mode for 32bit DMA addresses implemented. QLA1280 supports 64bit addressing for all DMA accesses so setting coherent mask to 64bit fixes the issue. Signed-off-by: Thomas Bogendoerfer Signed-off-by: Martin K. Petersen --- drivers/scsi/qla1280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index a414f51302b7..6856dfdfa473 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4248,7 +4248,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->devnum = devnum; /* specifies microcode load address */ #ifdef QLA_64BIT_PTR - if (dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(64))) { + if (dma_set_mask_and_coherent(&ha->pdev->dev, DMA_BIT_MASK(64))) { if (dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_WARNING "scsi(%li): Unable to set a " "suitable DMA mask - aborting\n", ha->host_no); -- cgit v1.2.3-58-ga151 From 9e8f1c79831424d30c0e3df068be7f4a244157c9 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Thu, 10 Jan 2019 23:29:28 +0530 Subject: scsi: cxgb4i: add wait_for_completion() In case of ->set_param() and ->bind_conn() cxgb4i driver does not wait for cmd completion, this can create race conditions, to avoid this add wait_for_completion(). Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 9 ++++----- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 28 ++++++++++++++++++++-------- drivers/scsi/cxgbi/libcxgbi.c | 7 ++++--- drivers/scsi/cxgbi/libcxgbi.h | 5 +++-- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index 8a20411699d9..75e1273a44b3 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -1144,7 +1144,7 @@ static void ddp_clear_map(struct cxgbi_device *cdev, struct cxgbi_ppm *ppm, } static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, - unsigned int tid, int pg_idx, bool reply) + unsigned int tid, int pg_idx) { struct sk_buff *skb = alloc_wr(sizeof(struct cpl_set_tcb_field), 0, GFP_KERNEL); @@ -1160,7 +1160,7 @@ static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, req = (struct cpl_set_tcb_field *)skb->head; req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); - req->reply = V_NO_REPLY(reply ? 0 : 1); + req->reply = V_NO_REPLY(1); req->cpu_idx = 0; req->word = htons(31); req->mask = cpu_to_be64(0xF0000000); @@ -1177,11 +1177,10 @@ static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, * @tid: connection id * @hcrc: header digest enabled * @dcrc: data digest enabled - * @reply: request reply from h/w * set up the iscsi digest settings for a connection identified by tid */ static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, - int hcrc, int dcrc, int reply) + int hcrc, int dcrc) { struct sk_buff *skb = alloc_wr(sizeof(struct cpl_set_tcb_field), 0, GFP_KERNEL); @@ -1197,7 +1196,7 @@ static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, req = (struct cpl_set_tcb_field *)skb->head; req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); - req->reply = V_NO_REPLY(reply ? 0 : 1); + req->reply = V_NO_REPLY(1); req->cpu_idx = 0; req->word = htons(31); req->mask = cpu_to_be64(0x0F000000); diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 49f8028ac524..d26f50af00ea 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1548,16 +1548,22 @@ static void do_set_tcb_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) struct cxgbi_sock *csk; csk = lookup_tid(t, tid); - if (!csk) + if (!csk) { pr_err("can't find conn. for tid %u.\n", tid); + return; + } log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,%lx,%u, status 0x%x.\n", csk, csk->state, csk->flags, csk->tid, rpl->status); - if (rpl->status != CPL_ERR_NONE) + if (rpl->status != CPL_ERR_NONE) { pr_err("csk 0x%p,%u, SET_TCB_RPL status %u.\n", csk, tid, rpl->status); + csk->err = -EINVAL; + } + + complete(&csk->cmpl); __kfree_skb(skb); } @@ -1983,7 +1989,7 @@ static int ddp_set_map(struct cxgbi_ppm *ppm, struct cxgbi_sock *csk, } static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid, - int pg_idx, bool reply) + int pg_idx) { struct sk_buff *skb; struct cpl_set_tcb_field *req; @@ -1999,7 +2005,7 @@ static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid, req = (struct cpl_set_tcb_field *)skb->head; INIT_TP_WR(req, csk->tid); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid)); - req->reply_ctrl = htons(NO_REPLY_V(reply) | QUEUENO_V(csk->rss_qid)); + req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid)); req->word_cookie = htons(0); req->mask = cpu_to_be64(0x3 << 8); req->val = cpu_to_be64(pg_idx << 8); @@ -2008,12 +2014,15 @@ static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid, log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, "csk 0x%p, tid 0x%x, pg_idx %u.\n", csk, csk->tid, pg_idx); + reinit_completion(&csk->cmpl); cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); - return 0; + wait_for_completion(&csk->cmpl); + + return csk->err; } static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, - int hcrc, int dcrc, int reply) + int hcrc, int dcrc) { struct sk_buff *skb; struct cpl_set_tcb_field *req; @@ -2031,7 +2040,7 @@ static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, req = (struct cpl_set_tcb_field *)skb->head; INIT_TP_WR(req, tid); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); - req->reply_ctrl = htons(NO_REPLY_V(reply) | QUEUENO_V(csk->rss_qid)); + req->reply_ctrl = htons(NO_REPLY_V(0) | QUEUENO_V(csk->rss_qid)); req->word_cookie = htons(0); req->mask = cpu_to_be64(0x3 << 4); req->val = cpu_to_be64(((hcrc ? ULP_CRC_HEADER : 0) | @@ -2041,8 +2050,11 @@ static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, "csk 0x%p, tid 0x%x, crc %d,%d.\n", csk, csk->tid, hcrc, dcrc); + reinit_completion(&csk->cmpl); cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); - return 0; + wait_for_completion(&csk->cmpl); + + return csk->err; } static struct cxgbi_ppm *cdev2ppm(struct cxgbi_device *cdev) diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 75f876409fb9..245742557c03 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -573,6 +573,7 @@ static struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev) skb_queue_head_init(&csk->receive_queue); skb_queue_head_init(&csk->write_queue); timer_setup(&csk->retry_timer, NULL, 0); + init_completion(&csk->cmpl); rwlock_init(&csk->callback_lock); csk->cdev = cdev; csk->flags = 0; @@ -2251,14 +2252,14 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, if (!err && conn->hdrdgst_en) err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, conn->hdrdgst_en, - conn->datadgst_en, 0); + conn->datadgst_en); break; case ISCSI_PARAM_DATADGST_EN: err = iscsi_set_param(cls_conn, param, buf, buflen); if (!err && conn->datadgst_en) err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, conn->hdrdgst_en, - conn->datadgst_en, 0); + conn->datadgst_en); break; case ISCSI_PARAM_MAX_R2T: return iscsi_tcp_set_max_r2t(conn, buf); @@ -2384,7 +2385,7 @@ int cxgbi_bind_conn(struct iscsi_cls_session *cls_session, ppm = csk->cdev->cdev2ppm(csk->cdev); err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid, - ppm->tformat.pgsz_idx_dflt, 0); + ppm->tformat.pgsz_idx_dflt); if (err < 0) return err; diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index 5d5d8b50d842..1917ff57651d 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -149,6 +149,7 @@ struct cxgbi_sock { struct sk_buff_head receive_queue; struct sk_buff_head write_queue; struct timer_list retry_timer; + struct completion cmpl; int err; rwlock_t callback_lock; void *user_data; @@ -490,9 +491,9 @@ struct cxgbi_device { struct cxgbi_ppm *, struct cxgbi_task_tag_info *); int (*csk_ddp_setup_digest)(struct cxgbi_sock *, - unsigned int, int, int, int); + unsigned int, int, int); int (*csk_ddp_setup_pgidx)(struct cxgbi_sock *, - unsigned int, int, bool); + unsigned int, int); void (*csk_release_offload_resources)(struct cxgbi_sock *); int (*csk_rx_pdu_ready)(struct cxgbi_sock *, struct sk_buff *); -- cgit v1.2.3-58-ga151 From 7fefaadd6a962987baac50e7b3c4c3d5ef9b55c6 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sat, 12 Jan 2019 01:06:03 +0100 Subject: binderfs: handle !CONFIG_IPC_NS builds kbuild reported a build faile in [1]. This is triggered when CONFIG_IPC_NS is not set. So let's make the use of init_ipc_ns conditional on CONFIG_IPC_NS being set. [1]: https://lists.01.org/pipermail/kbuild-all/2019-January/056903.html Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index ad3ad2f7f9f4..9518e2e7da05 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -129,7 +129,11 @@ static int binderfs_binder_device_create(struct inode *ref_inode, struct inode *inode = NULL; struct super_block *sb = ref_inode->i_sb; struct binderfs_info *info = sb->s_fs_info; +#if defined(CONFIG_IPC_NS) bool use_reserve = (info->ipc_ns == &init_ipc_ns); +#else + bool use_reserve = true; +#endif /* Reserve new minor number for the new device. */ mutex_lock(&binderfs_minors_mutex); -- cgit v1.2.3-58-ga151 From 0b815023a1d479aa8f8851ee880d5388e53b7ae5 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 12 Jan 2019 00:13:04 -0500 Subject: bnxt_en: Fix ring checking logic on 57500 chips. In bnxt_hwrm_check_pf_rings(), add the proper flag to test the NQ resources. Without the proper flag, the firmware will change the NQ resource allocation and remap the IRQ, causing missing IRQs. This issue shows up when adding MQPRIO TX queues, for example. Fixes: 36d65be9a880 ("bnxt_en: Disable MSIX before re-reserving NQs/CMPL rings.") Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 ++- drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 3aa80da973d7..a125fbe5183f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5601,7 +5601,8 @@ static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings, FUNC_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST | FUNC_CFG_REQ_FLAGS_VNIC_ASSETS_TEST; if (bp->flags & BNXT_FLAG_CHIP_P5) - flags |= FUNC_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST; + flags |= FUNC_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST | + FUNC_CFG_REQ_FLAGS_NQ_ASSETS_TEST; else flags |= FUNC_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index f1aaac8e6268..0a0995894ddb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -386,8 +386,8 @@ struct hwrm_err_output { #define HWRM_VERSION_MAJOR 1 #define HWRM_VERSION_MINOR 10 #define HWRM_VERSION_UPDATE 0 -#define HWRM_VERSION_RSVD 33 -#define HWRM_VERSION_STR "1.10.0.33" +#define HWRM_VERSION_RSVD 35 +#define HWRM_VERSION_STR "1.10.0.35" /* hwrm_ver_get_input (size:192b/24B) */ struct hwrm_ver_get_input { @@ -1184,6 +1184,7 @@ struct hwrm_func_cfg_input { #define FUNC_CFG_REQ_FLAGS_L2_CTX_ASSETS_TEST 0x100000UL #define FUNC_CFG_REQ_FLAGS_TRUSTED_VF_ENABLE 0x200000UL #define FUNC_CFG_REQ_FLAGS_DYNAMIC_TX_RING_ALLOC 0x400000UL + #define FUNC_CFG_REQ_FLAGS_NQ_ASSETS_TEST 0x800000UL __le32 enables; #define FUNC_CFG_REQ_ENABLES_MTU 0x1UL #define FUNC_CFG_REQ_ENABLES_MRU 0x2UL -- cgit v1.2.3-58-ga151 From 6ef982dec7eda9affa81a2bb84f75441deb56d06 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 12 Jan 2019 00:13:05 -0500 Subject: bnxt_en: Fix context memory allocation. When allocating memory pages for context memory, if the last page table should be fully populated, the current code will set nr_pages to 0 when calling bnxt_alloc_ctx_mem_blk(). This will cause the last page table to be completely blank and causing some RDMA failures. Fix it by setting the last page table's nr_pages to the remainder only if it is non-zero. Fixes: 08fe9d181606 ("bnxt_en: Add Level 2 context memory paging support.") Reported-by: Eric Davis Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a125fbe5183f..9499d01632ff 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6222,9 +6222,12 @@ static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp, rmem->pg_tbl_map = ctx_pg->ctx_dma_arr[i]; rmem->depth = 1; rmem->nr_pages = MAX_CTX_PAGES; - if (i == (nr_tbls - 1)) - rmem->nr_pages = ctx_pg->nr_pages % - MAX_CTX_PAGES; + if (i == (nr_tbls - 1)) { + int rem = ctx_pg->nr_pages % MAX_CTX_PAGES; + + if (rem) + rmem->nr_pages = rem; + } rc = bnxt_alloc_ctx_mem_blk(bp, pg_tbl); if (rc) break; -- cgit v1.2.3-58-ga151 From e1706720408e72fb883f6b151c2b3b23d8e7e5b2 Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Sat, 12 Jan 2019 17:29:09 -0800 Subject: phy: fix build breakage: add PHY_MODE_SATA Commit 49e54187ae0b ("ata: libahci_platform: comply to PHY framework") uses the PHY_MODE_SATA, but that enum had not yet been added. This caused a build failure for me, with today's linux.git. Also, there is a potentially conflicting (mis-named) PHY_MODE_SATA, hiding in the Marvell Berlin SATA PHY driver. Fix the build by: 1) Renaming Marvell's defined value to a more scoped name, in order to avoid any potential conflicts: PHY_BERLIN_MODE_SATA. 2) Adding the missing enum, which was going to be added anyway as part of [1]. [1] https://lkml.kernel.org/r/20190108163124.6409-3-miquel.raynal@bootlin.com Fixes: 49e54187ae0b ("ata: libahci_platform: comply to PHY framework") Signed-off-by: John Hubbard Acked-by: Jens Axboe Acked-by: Olof Johansson Cc: Grzegorz Jaszczyk Cc: Miquel Raynal Cc: Hans de Goede Signed-off-by: Linus Torvalds --- drivers/phy/marvell/phy-berlin-sata.c | 5 +++-- include/linux/phy/phy.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/phy/marvell/phy-berlin-sata.c b/drivers/phy/marvell/phy-berlin-sata.c index a91fc67fc4e0..d70ba9bc42d9 100644 --- a/drivers/phy/marvell/phy-berlin-sata.c +++ b/drivers/phy/marvell/phy-berlin-sata.c @@ -32,7 +32,7 @@ /* register 0x01 */ #define REF_FREF_SEL_25 BIT(0) -#define PHY_MODE_SATA (0x0 << 5) +#define PHY_BERLIN_MODE_SATA (0x0 << 5) /* register 0x02 */ #define USE_MAX_PLL_RATE BIT(12) @@ -102,7 +102,8 @@ static int phy_berlin_sata_power_on(struct phy *phy) /* set PHY mode and ref freq to 25 MHz */ phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x01, - 0x00ff, REF_FREF_SEL_25 | PHY_MODE_SATA); + 0x00ff, + REF_FREF_SEL_25 | PHY_BERLIN_MODE_SATA); /* set PHY up to 6 Gbps */ phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x25, diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index e8e118d70fd7..3f350e2749fe 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -42,6 +42,7 @@ enum phy_mode { PHY_MODE_PCIE, PHY_MODE_ETHERNET, PHY_MODE_MIPI_DPHY, + PHY_MODE_SATA }; /** -- cgit v1.2.3-58-ga151 From 82e59cbe5fdc0d521f9037861af21af6d5814afd Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 13 Jan 2019 14:24:46 +0200 Subject: mei: dma: silent the reject message Not all FW versions support DMA on their first release, hence it is normal behavior to receive a reject response upon DMA setup request. In order to prevent confusion, the DMA setup reject message is printed only in debug level. Cc: #v5.0+ Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hbm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 78c26cebf5d4..8f7616557c97 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -1187,9 +1187,15 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) dma_setup_res = (struct hbm_dma_setup_response *)mei_msg; if (dma_setup_res->status) { - dev_info(dev->dev, "hbm: dma setup response: failure = %d %s\n", - dma_setup_res->status, - mei_hbm_status_str(dma_setup_res->status)); + u8 status = dma_setup_res->status; + + if (status == MEI_HBMS_NOT_ALLOWED) { + dev_dbg(dev->dev, "hbm: dma setup not allowed\n"); + } else { + dev_info(dev->dev, "hbm: dma setup response: failure = %d %s\n", + status, + mei_hbm_status_str(status)); + } dev->hbm_f_dr_supported = 0; mei_dmam_ring_free(dev); } -- cgit v1.2.3-58-ga151 From 173436ba800d01178a8b19e5de4a8cb02c0db760 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 13 Jan 2019 14:24:47 +0200 Subject: mei: me: mark LBG devices as having dma support The LBG server platform sports DMA support. Cc: #v5.0+ Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/pci-me.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 73ace2d59dea..c2bf3e99955e 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -88,7 +88,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, MEI_ME_PCH8_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, MEI_ME_PCH8_CFG)}, -- cgit v1.2.3-58-ga151 From f7ee8ead151f9d0b8dac6ab6c3ff49bbe809c564 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 13 Jan 2019 14:24:48 +0200 Subject: mei: me: add denverton innovation engine device IDs Add the Denverton innovation engine (IE) device ids. The IE is an ME-like device which provides HW security offloading. Cc: Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 2 ++ drivers/misc/mei/pci-me.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index e4b10b2d1a08..23739a60517f 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -127,6 +127,8 @@ #define MEI_DEV_ID_BXT_M 0x1A9A /* Broxton M */ #define MEI_DEV_ID_APL_I 0x5A9A /* Apollo Lake I */ +#define MEI_DEV_ID_DNV_IE 0x19E5 /* Denverton IE */ + #define MEI_DEV_ID_GLK 0x319A /* Gemini Lake */ #define MEI_DEV_ID_KBP 0xA2BA /* Kaby Point */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index c2bf3e99955e..e89497f858ae 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -93,6 +93,8 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, MEI_ME_PCH8_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_DNV_IE, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_GLK, MEI_ME_PCH8_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, MEI_ME_PCH8_CFG)}, -- cgit v1.2.3-58-ga151 From a17ce9960b3628b9f546c454741a1cad551d5695 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Jan 2019 09:47:43 +0100 Subject: drm/rockchip: add missing of_node_put The device node iterators perform an of_node_get on each iteration, so a jump out of the loop requires an of_node_put. The semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr): // @@ expression root,e; local idexpression child; iterator name for_each_child_of_node; @@ for_each_child_of_node(root, child) { ... when != of_node_put(child) when != e = child + of_node_put(child); ? break; ... } ... when != child // Fixes: 1f0f01515172 ("drm/rockchip: Add support for Rockchip Soc RGB output interface") Cc: stable@vger.kernel.org Signed-off-by: Julia Lawall [added fixes and cc-stable] Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/1547369264-24831-4-git-send-email-Julia.Lawall@lip6.fr --- drivers/gpu/drm/rockchip/rockchip_rgb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c index 96ac1458a59c..37f93022a106 100644 --- a/drivers/gpu/drm/rockchip/rockchip_rgb.c +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c @@ -113,8 +113,10 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev, child_count++; ret = drm_of_find_panel_or_bridge(dev->of_node, 0, endpoint_id, &panel, &bridge); - if (!ret) + if (!ret) { + of_node_put(endpoint); break; + } } of_node_put(port); -- cgit v1.2.3-58-ga151 From b7285b425318331c2de4af2a784a18e6dccef484 Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Sat, 12 Jan 2019 18:14:30 +0100 Subject: kernel/sys.c: Clarify that UNAME26 does not generate unique versions anymore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UNAME26 is a mechanism to report Linux's version as 2.6.x, for compatibility with old/broken software. Due to the way it is implemented, it would have to be updated after 5.0, to keep the resulting versions unique. Linus Torvalds argued: "Do we actually need this? I'd rather let it bitrot, and just let it return random versions. It will just start again at 2.4.60, won't it? Anybody who uses UNAME26 for a 5.x kernel might as well think it's still 4.x. The user space is so old that it can't possibly care about differences between 4.x and 5.x, can it? The only thing that matters is that it shows "2.4.", which it will do regardless" Signed-off-by: Jonathan Neuschäfer Signed-off-by: Linus Torvalds --- kernel/sys.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sys.c b/kernel/sys.c index a48cbf1414b8..f7eb62eceb24 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1207,7 +1207,8 @@ DECLARE_RWSEM(uts_sem); /* * Work around broken programs that cannot handle "Linux 3.0". * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40 - * And we map 4.x to 2.6.60+x, so 4.0 would be 2.6.60. + * And we map 4.x and later versions to 2.6.60+x, so 4.0/5.0/6.0/... would be + * 2.6.60. */ static int override_release(char __user *release, size_t len) { -- cgit v1.2.3-58-ga151 From 1c7fc5cbc33980acd13d668f1c8f0313d6ae9fd8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 14 Jan 2019 10:41:12 +1200 Subject: Linux 5.0-rc2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8c55b6404e19..499b96810995 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 5 PATCHLEVEL = 0 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Shy Crocodile # *DOCUMENTATION* -- cgit v1.2.3-58-ga151 From 2648ca1859bb48cacdbbaf60bbc0bfef74f13330 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 11 Jan 2019 11:51:48 +0900 Subject: kconfig: clean generated *conf-cfg files I accidentally dropped '*' in the previous renaming patch. Revive it so that 'make mrproper' can clean the generated files. Fixes: d86271af6460 ("kconfig: rename generated .*conf-cfg to *conf-cfg") Signed-off-by: Masahiro Yamada --- scripts/kconfig/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index c05ab001b54c..181973509a05 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -206,4 +206,4 @@ filechk_conf_cfg = $(CONFIG_SHELL) $< $(obj)/%conf-cfg: $(src)/%conf-cfg.sh FORCE $(call filechk,conf_cfg) -clean-files += conf-cfg +clean-files += *conf-cfg -- cgit v1.2.3-58-ga151 From 16fd20aa98080c2fa666dc384036ec08c80af710 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 11 Jan 2019 19:06:44 +0000 Subject: kbuild: Disable LD_DEAD_CODE_DATA_ELIMINATION with ftrace & GCC <= 4.7 When building using GCC 4.7 or older, -ffunction-sections & the -pg flag used by ftrace are incompatible. This causes warnings or build failures (where -Werror applies) such as the following: arch/mips/generic/init.c: error: -ffunction-sections disabled; it makes profiling impossible This used to be taken into account by the ordering of calls to cc-option from within the top-level Makefile, which was introduced by commit 90ad4052e85c ("kbuild: avoid conflict between -ffunction-sections and -pg on gcc-4.7"). Unfortunately this was broken when the CONFIG_LD_DEAD_CODE_DATA_ELIMINATION cc-option check was moved to Kconfig in commit e85d1d65cd8a ("kbuild: test dead code/data elimination support in Kconfig"), because the flags used by this check no longer include -pg. Fix this by not allowing CONFIG_LD_DEAD_CODE_DATA_ELIMINATION to be enabled at the same time as ftrace/CONFIG_FUNCTION_TRACER when building using GCC 4.7 or older. Signed-off-by: Paul Burton Fixes: e85d1d65cd8a ("kbuild: test dead code/data elimination support in Kconfig") Reported-by: Geert Uytterhoeven Cc: Nicholas Piggin Cc: stable@vger.kernel.org # v4.19+ Signed-off-by: Masahiro Yamada --- init/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/init/Kconfig b/init/Kconfig index d47cb77a220e..513fa544a134 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1124,6 +1124,7 @@ config LD_DEAD_CODE_DATA_ELIMINATION bool "Dead code and data elimination (EXPERIMENTAL)" depends on HAVE_LD_DEAD_CODE_DATA_ELIMINATION depends on EXPERT + depends on !(FUNCTION_TRACER && CC_IS_GCC && GCC_VERSION < 40800) depends on $(cc-option,-ffunction-sections -fdata-sections) depends on $(ld-option,--gc-sections) help -- cgit v1.2.3-58-ga151 From bd352a739fde9834d48379e8eca428fe897144ac Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 14 Jan 2019 12:16:45 +0900 Subject: kbuild: remove unused baseprereq Commit eea199b445f6 ("kbuild: remove unnecessary LEX_PREFIX and YACC_PREFIX") removed the last users of this macro. Signed-off-by: Masahiro Yamada --- scripts/Kbuild.include | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 525bff667a52..30816037036e 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -23,10 +23,6 @@ depfile = $(subst $(comma),_,$(dot-target).d) # filename of target with directory and extension stripped basetarget = $(basename $(notdir $@)) -### -# filename of first prerequisite with directory and extension stripped -baseprereq = $(basename $(notdir $<)) - ### # Escape single quote for use in echo statements escsq = $(subst $(squote),'\$(squote)',$1) -- cgit v1.2.3-58-ga151 From ba0a64bcf8fc491f73e4646069d97abb4374beb3 Mon Sep 17 00:00:00 2001 From: Colin Xu Date: Fri, 11 Jan 2019 14:25:54 +0800 Subject: drm/i915/gvt: Allow F_CMD_ACCESS on mmio 0x21f0 The newly updated guest driver could program 0x21f0 via lri and srm, without F_CMD_ACCESS flag cmd parser will stop parser reset cmd. 0x21f0 applies to BDW, SKL, KBL, BXT and CFL. Reviewed-by: Yan Zhao Signed-off-by: Colin Xu Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/handlers.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index b5475c91e2ef..e9f343b124b0 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -2799,6 +2799,7 @@ static int init_broadwell_mmio_info(struct intel_gvt *gvt) MMIO_DFH(_MMIO(0xe2a0), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL); MMIO_DFH(_MMIO(0xe2b0), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL); MMIO_DFH(_MMIO(0xe2c0), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL); + MMIO_DFH(_MMIO(0x21f0), D_BDW_PLUS, F_CMD_ACCESS, NULL, NULL); return 0; } -- cgit v1.2.3-58-ga151 From 2e746942ebacf1565caa72cf980745e5ce297c48 Mon Sep 17 00:00:00 2001 From: Deepa Dinamani Date: Sun, 13 Jan 2019 22:28:05 -0800 Subject: Input: input_event - provide override for sparc64 The usec part of the timeval is defined as __kernel_suseconds_t tv_usec; /* microseconds */ Arnd noticed that sparc64 is the only architecture that defines __kernel_suseconds_t as int rather than long. This breaks the current y2038 fix for kernel as we only access and define the timeval struct for non-kernel use cases. But, this was hidden by an another typo in the use of __KERNEL__ qualifier. Fix the typo, and provide an override for sparc64. Fixes: 152194fe9c3f ("Input: extend usable life of event timestamps to 2106 on 32 bit systems") Reported-by: Arnd Bergmann Signed-off-by: Deepa Dinamani Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- include/uapi/linux/input.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index 7288a7c573cc..551866a4f658 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -26,13 +26,17 @@ */ struct input_event { -#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL) +#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__) struct timeval time; #define input_event_sec time.tv_sec #define input_event_usec time.tv_usec #else __kernel_ulong_t __sec; +#ifdef CONFIG_SPARC64 + unsigned int __usec; +#else __kernel_ulong_t __usec; +#endif #define input_event_sec __sec #define input_event_usec __usec #endif -- cgit v1.2.3-58-ga151 From f4c34b1e2a37d5676180901fa6ff188bcb6371f8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 10 Jan 2019 09:17:50 +0100 Subject: drm/qxl: drop prime import/export callbacks Also set prime_handle_to_fd and prime_fd_to_handle to NULL, so drm will not advertive DRM_PRIME_CAP_{IMPORT,EXPORT} to userspace. Signed-off-by: Gerd Hoffmann Reviewed-by: Dave Airlie Link: http://patchwork.freedesktop.org/patch/msgid/20190110081750.11358-1-kraxel@redhat.com --- drivers/gpu/drm/qxl/qxl_drv.c | 4 ---- drivers/gpu/drm/qxl/qxl_prime.c | 14 -------------- 2 files changed, 18 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c index 13c8a662f9b4..ccb090f3ab30 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.c +++ b/drivers/gpu/drm/qxl/qxl_drv.c @@ -250,14 +250,10 @@ static struct drm_driver qxl_driver = { #if defined(CONFIG_DEBUG_FS) .debugfs_init = qxl_debugfs_init, #endif - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = drm_gem_prime_export, .gem_prime_import = drm_gem_prime_import, .gem_prime_pin = qxl_gem_prime_pin, .gem_prime_unpin = qxl_gem_prime_unpin, - .gem_prime_get_sg_table = qxl_gem_prime_get_sg_table, - .gem_prime_import_sg_table = qxl_gem_prime_import_sg_table, .gem_prime_vmap = qxl_gem_prime_vmap, .gem_prime_vunmap = qxl_gem_prime_vunmap, .gem_prime_mmap = qxl_gem_prime_mmap, diff --git a/drivers/gpu/drm/qxl/qxl_prime.c b/drivers/gpu/drm/qxl/qxl_prime.c index a55dece118b2..df65d3c1a7b8 100644 --- a/drivers/gpu/drm/qxl/qxl_prime.c +++ b/drivers/gpu/drm/qxl/qxl_prime.c @@ -38,20 +38,6 @@ void qxl_gem_prime_unpin(struct drm_gem_object *obj) WARN_ONCE(1, "not implemented"); } -struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj) -{ - WARN_ONCE(1, "not implemented"); - return ERR_PTR(-ENOSYS); -} - -struct drm_gem_object *qxl_gem_prime_import_sg_table( - struct drm_device *dev, struct dma_buf_attachment *attach, - struct sg_table *table) -{ - WARN_ONCE(1, "not implemented"); - return ERR_PTR(-ENOSYS); -} - void *qxl_gem_prime_vmap(struct drm_gem_object *obj) { WARN_ONCE(1, "not implemented"); -- cgit v1.2.3-58-ga151 From b318e3ff7ca065d6b107e424c85a63d7a6798a69 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 10 Jan 2019 12:15:45 +0100 Subject: drm/virtio: drop prime import/export callbacks Also set prime_handle_to_fd and prime_fd_to_handle to NULL, so drm will not advertive DRM_PRIME_CAP_{IMPORT,EXPORT} to userspace. Signed-off-by: Gerd Hoffmann Reviewed-by: Oleksandr Andrushchenko Reviewed-by: Dave Airlie Link: http://patchwork.freedesktop.org/patch/msgid/20190110111545.26768-1-kraxel@redhat.com --- drivers/gpu/drm/virtio/virtgpu_drv.c | 4 ---- drivers/gpu/drm/virtio/virtgpu_drv.h | 4 ---- drivers/gpu/drm/virtio/virtgpu_prime.c | 14 -------------- 3 files changed, 22 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index f7f32a885af7..2d1aaca49105 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -127,14 +127,10 @@ static struct drm_driver driver = { #if defined(CONFIG_DEBUG_FS) .debugfs_init = virtio_gpu_debugfs_init, #endif - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = drm_gem_prime_export, .gem_prime_import = drm_gem_prime_import, .gem_prime_pin = virtgpu_gem_prime_pin, .gem_prime_unpin = virtgpu_gem_prime_unpin, - .gem_prime_get_sg_table = virtgpu_gem_prime_get_sg_table, - .gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table, .gem_prime_vmap = virtgpu_gem_prime_vmap, .gem_prime_vunmap = virtgpu_gem_prime_vunmap, .gem_prime_mmap = virtgpu_gem_prime_mmap, diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 1deb41d42ea4..0c15000f926e 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -372,10 +372,6 @@ int virtio_gpu_object_wait(struct virtio_gpu_object *bo, bool no_wait); /* virtgpu_prime.c */ int virtgpu_gem_prime_pin(struct drm_gem_object *obj); void virtgpu_gem_prime_unpin(struct drm_gem_object *obj); -struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj); -struct drm_gem_object *virtgpu_gem_prime_import_sg_table( - struct drm_device *dev, struct dma_buf_attachment *attach, - struct sg_table *sgt); void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj); void virtgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); int virtgpu_gem_prime_mmap(struct drm_gem_object *obj, diff --git a/drivers/gpu/drm/virtio/virtgpu_prime.c b/drivers/gpu/drm/virtio/virtgpu_prime.c index 86ce0ae93f59..c59ec34c80a5 100644 --- a/drivers/gpu/drm/virtio/virtgpu_prime.c +++ b/drivers/gpu/drm/virtio/virtgpu_prime.c @@ -39,20 +39,6 @@ void virtgpu_gem_prime_unpin(struct drm_gem_object *obj) WARN_ONCE(1, "not implemented"); } -struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj) -{ - WARN_ONCE(1, "not implemented"); - return ERR_PTR(-ENODEV); -} - -struct drm_gem_object *virtgpu_gem_prime_import_sg_table( - struct drm_device *dev, struct dma_buf_attachment *attach, - struct sg_table *table) -{ - WARN_ONCE(1, "not implemented"); - return ERR_PTR(-ENODEV); -} - void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj) { struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj); -- cgit v1.2.3-58-ga151 From fe2bfd0d40c935763812973ce15f5764f1c12833 Mon Sep 17 00:00:00 2001 From: Tom Panfil Date: Fri, 11 Jan 2019 17:49:40 -0800 Subject: Input: xpad - add support for SteelSeries Stratus Duo Add support for the SteelSeries Stratus Duo, a wireless Xbox 360 controller. The Stratus Duo ships with a USB dongle to enable wireless connectivity, but it can also function as a wired controller by connecting it directly to a PC via USB, hence the need for two USD PIDs. 0x1430 is the dongle, and 0x1431 is the controller. Signed-off-by: Tom Panfil Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index cfc8b94527b9..aa4e431cbcd3 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -252,6 +252,8 @@ static const struct xpad_device { { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, + { 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, + { 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, { 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 }, { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 }, @@ -428,6 +430,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */ XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */ + XPAD_XBOX360_VENDOR(0x1038), /* SteelSeries Controllers */ XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */ XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */ XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ -- cgit v1.2.3-58-ga151 From 01c10880d24291a96a4ab0da773e3c5ce4d12da8 Mon Sep 17 00:00:00 2001 From: Bo He Date: Mon, 14 Jan 2019 09:48:32 +0200 Subject: usb: dwc3: gadget: synchronize_irq dwc irq in suspend We see dwc3 endpoint stopped by unwanted irq during suspend resume test, which is caused dwc3 ep can't be started with error "No Resource". Here, add synchronize_irq before suspend to sync the pending IRQ handlers complete. Signed-off-by: Bo He Signed-off-by: Yu Wang Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 07bd31bb2f8a..851fd44d56ad 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3379,6 +3379,8 @@ int dwc3_gadget_suspend(struct dwc3 *dwc) dwc3_disconnect_gadget(dwc); __dwc3_gadget_stop(dwc); + synchronize_irq(dwc->irq_gadget); + return 0; } -- cgit v1.2.3-58-ga151 From bd6742249b9ca918565e4e3abaa06665e587f4b5 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Thu, 10 Jan 2019 12:39:55 -0800 Subject: usb: dwc3: gadget: Clear req->needs_extra_trb flag on cleanup OUT endpoint requests may somtimes have this flag set when preparing to be submitted to HW indicating that there is an additional TRB chained to the request for alignment purposes. If that request is removed before the controller can execute the transfer (e.g. ep_dequeue/ep_disable), the request will not go through the dwc3_gadget_ep_cleanup_completed_request() handler and will not have its needs_extra_trb flag cleared when dwc3_gadget_giveback() is called. This same request could be later requeued for a new transfer that does not require an extra TRB and if it is successfully completed, the cleanup and TRB reclamation will incorrectly process the additional TRB which belongs to the next request, and incorrectly advances the TRB dequeue pointer, thereby messing up calculation of the next requeust's actual/remaining count when it completes. The right thing to do here is to ensure that the flag is cleared before it is given back to the function driver. A good place to do that is in dwc3_gadget_del_and_unmap_request(). Fixes: c6267a51639b ("usb: dwc3: gadget: align transfers to wMaxPacketSize") Cc: stable@vger.kernel.org Signed-off-by: Jack Pham Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 851fd44d56ad..6e2b6d6369aa 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -177,6 +177,7 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, req->started = false; list_del(&req->list); req->remaining = 0; + req->needs_extra_trb = false; if (req->request.status == -EINPROGRESS) req->request.status = status; -- cgit v1.2.3-58-ga151 From 88b1bb1f3b88e0bf20b05d543a53a5b99bd7ceb6 Mon Sep 17 00:00:00 2001 From: Zeng Tao Date: Wed, 26 Dec 2018 19:22:00 +0800 Subject: usb: dwc3: gadget: Fix the uninitialized link_state when udc starts Currently the link_state is uninitialized and the default value is 0(U0) before the first time we start the udc, and after we start the udc then stop the udc, the link_state will be undefined. We may have the following warnings if we start the udc again with an undefined link_state: WARNING: CPU: 0 PID: 327 at drivers/usb/dwc3/gadget.c:294 dwc3_send_gadget_ep_cmd+0x304/0x308 dwc3 100e0000.hidwc3_0: wakeup failed --> -22 [...] Call Trace: [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x84/0x98) [] (dump_stack) from [] (__warn+0xe8/0x100) [] (__warn) from [](warn_slowpath_fmt+0x38/0x48) [] (warn_slowpath_fmt) from [](dwc3_send_gadget_ep_cmd+0x304/0x308) [] (dwc3_send_gadget_ep_cmd) from [](dwc3_ep0_start_trans+0x48/0xf4) [] (dwc3_ep0_start_trans) from [](dwc3_ep0_out_start+0x64/0x80) [] (dwc3_ep0_out_start) from [](__dwc3_gadget_start+0x1e0/0x278) [] (__dwc3_gadget_start) from [](dwc3_gadget_start+0x88/0x10c) [] (dwc3_gadget_start) from [](udc_bind_to_driver+0x88/0xbc) [] (udc_bind_to_driver) from [](usb_gadget_probe_driver+0xf8/0x140) [] (usb_gadget_probe_driver) from [](gadget_dev_desc_UDC_store+0xac/0xc4 [libcomposite]) [] (gadget_dev_desc_UDC_store [libcomposite]) from[] (configfs_write_file+0xd4/0x160) [] (configfs_write_file) from [] (__vfs_write+0x1c/0x114) [] (__vfs_write) from [] (vfs_write+0xa4/0x168) [] (vfs_write) from [] (SyS_write+0x3c/0x90) [] (SyS_write) from [] (ret_fast_syscall+0x0/0x3c) Signed-off-by: Zeng Tao Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6e2b6d6369aa..bed2ff42780b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1985,6 +1985,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) /* begin to receive SETUP packets */ dwc->ep0state = EP0_SETUP_PHASE; + dwc->link_state = DWC3_LINK_STATE_SS_DIS; dwc3_ep0_out_start(dwc); dwc3_gadget_enable_irq(dwc); -- cgit v1.2.3-58-ga151 From df28169e1538e4a8bcd8b779b043e5aa6524545c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Dec 2018 23:42:52 +0300 Subject: usb: gadget: Potential NULL dereference on allocation error The source_sink_alloc_func() function is supposed to return error pointers on error. The function is called from usb_get_function() which doesn't check for NULL returns so it would result in an Oops. Of course, in the current kernel, small allocations always succeed so this doesn't affect runtime. Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_sourcesink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index 9cdef108fb1b..ed68a4860b7d 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -838,7 +838,7 @@ static struct usb_function *source_sink_alloc_func( ss = kzalloc(sizeof(*ss), GFP_KERNEL); if (!ss) - return NULL; + return ERR_PTR(-ENOMEM); ss_opts = container_of(fi, struct f_ss_opts, func_inst); -- cgit v1.2.3-58-ga151 From c2eda8ab2e2d52e2d618aa4d858126cebf9c7de2 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 5 Jan 2019 10:06:04 +0000 Subject: mmc: sdhci-acpi: Make PCI dependency explicit After 'commit 5d32a66541c4 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set")' dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. This driver relies on IOSF_MBI and IOSF_MBI depends on PCI. For this reason, add a direct dependency to CONFIG_PCI here. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Acked-by: Arnd Bergmann Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index e26b8145efb3..1b9401fe94c0 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -116,7 +116,7 @@ config MMC_RICOH_MMC config MMC_SDHCI_ACPI tristate "SDHCI support for ACPI enumerated SDHCI controllers" - depends on MMC_SDHCI && ACPI + depends on MMC_SDHCI && ACPI && PCI select IOSF_MBI if X86 help This selects support for ACPI enumerated SDHCI controllers, -- cgit v1.2.3-58-ga151 From 287b1da6a458a30da2e5be745498d31092ebb001 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Wed, 9 Jan 2019 18:13:12 +0530 Subject: mmc: host: Fix Kconfig warnings on keystone_defconfig Commit 961de0a856e3 ("mmc: sdhci-omap: Workaround errata regarding SDR104/HS200 tuning failures (i929)") added a select on TI_SOC_THERMAL for the driver to get temperature for tuning. However, this causes the following warning on keystone_defconfig because keystone does not support TI_SOC_THERMAL: "WARNING: unmet direct dependencies detected for TI_SOC_THERMAL" Fix this by changing the select to imply. Fixes: 961de0a856e3 ("mmc: sdhci-omap: Workaround errata regarding SDR104/HS200 tuning failures (i929)") Signed-off-by: Faiz Abbas Tested-by: Borislav Petkov Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 1b9401fe94c0..a44ec8bb5418 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -978,7 +978,7 @@ config MMC_SDHCI_OMAP tristate "TI SDHCI Controller Support" depends on MMC_SDHCI_PLTFM && OF select THERMAL - select TI_SOC_THERMAL + imply TI_SOC_THERMAL help This selects the Secure Digital Host Controller Interface (SDHCI) support present in TI's DRA7 SOCs. The controller supports -- cgit v1.2.3-58-ga151 From bb364890323cca6e43f13e86d190ebf34a7d8cea Mon Sep 17 00:00:00 2001 From: Remi Pommarel Date: Fri, 11 Jan 2019 00:01:35 +0100 Subject: mmc: meson-gx: Free irq in release() callback Because the irq was requested through device managed resources API (devm_request_threaded_irq()) it was freed after meson_mmc_remove() completion, thus after mmc_free_host() has reclaimed meson_host memory. As this irq is IRQF_SHARED, while using CONFIG_DEBUG_SHIRQ, its handler get called by free_irq(). So meson_mmc_irq() was called after the meson_host memory reclamation and was using invalid memory. We ended up with the following scenario: device_release_driver() meson_mmc_remove() mmc_free_host() /* Freeing host memory */ ... devres_release_all() devm_irq_release() __free_irq() meson_mmc_irq() /* Uses freed memory */ To avoid this, the irq is released in meson_mmc_remove() and in mseon_mmc_probe() error path before mmc_free_host() gets called. Reported-by: Elie Roudninski Signed-off-by: Remi Pommarel Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index c2690c1a50ff..f115d7c63ffe 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -179,6 +179,8 @@ struct meson_host { struct sd_emmc_desc *descs; dma_addr_t descs_dma_addr; + int irq; + bool vqmmc_enabled; }; @@ -1231,7 +1233,7 @@ static int meson_mmc_probe(struct platform_device *pdev) struct resource *res; struct meson_host *host; struct mmc_host *mmc; - int ret, irq; + int ret; mmc = mmc_alloc_host(sizeof(struct meson_host), &pdev->dev); if (!mmc) @@ -1276,8 +1278,8 @@ static int meson_mmc_probe(struct platform_device *pdev) goto free_host; } - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { + host->irq = platform_get_irq(pdev, 0); + if (host->irq <= 0) { dev_err(&pdev->dev, "failed to get interrupt resource.\n"); ret = -EINVAL; goto free_host; @@ -1331,9 +1333,8 @@ static int meson_mmc_probe(struct platform_device *pdev) writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN, host->regs + SD_EMMC_IRQ_EN); - ret = devm_request_threaded_irq(&pdev->dev, irq, meson_mmc_irq, - meson_mmc_irq_thread, IRQF_SHARED, - NULL, host); + ret = request_threaded_irq(host->irq, meson_mmc_irq, + meson_mmc_irq_thread, IRQF_SHARED, NULL, host); if (ret) goto err_init_clk; @@ -1351,7 +1352,7 @@ static int meson_mmc_probe(struct platform_device *pdev) if (host->bounce_buf == NULL) { dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n"); ret = -ENOMEM; - goto err_init_clk; + goto err_free_irq; } host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN, @@ -1370,6 +1371,8 @@ static int meson_mmc_probe(struct platform_device *pdev) err_bounce_buf: dma_free_coherent(host->dev, host->bounce_buf_size, host->bounce_buf, host->bounce_dma_addr); +err_free_irq: + free_irq(host->irq, host); err_init_clk: clk_disable_unprepare(host->mmc_clk); err_core_clk: @@ -1387,6 +1390,7 @@ static int meson_mmc_remove(struct platform_device *pdev) /* disable interrupts */ writel(0, host->regs + SD_EMMC_IRQ_EN); + free_irq(host->irq, host); dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN, host->descs, host->descs_dma_addr); -- cgit v1.2.3-58-ga151 From 77ae0d8e401f083ca69c202502da4fc0e38cb1b7 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Mon, 14 Jan 2019 16:47:34 +0800 Subject: HID: i2c-hid: Disable runtime PM on Goodix touchpad A Goodix touchpad doesn't work. Touching the touchpad can trigger IRQ but there's no input event from HID subsystem. Turns out it reports some invalid data: [ 22.136630] i2c_hid i2c-DELL091F:00: input: 0b 00 01 00 00 00 00 00 00 00 00 After some trial and error, it's another device that doesn't work well with ON/SLEEP commands. Disable runtime PM to fix the issue. Signed-off-by: Kai-Heng Feng Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/i2c-hid/i2c-hid-core.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 518fa76414f5..24f846d67478 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -461,6 +461,9 @@ #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A 0x010a #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100 0xe100 +#define I2C_VENDOR_ID_GOODIX 0x27c6 +#define I2C_DEVICE_ID_GOODIX_01F0 0x01f0 + #define USB_VENDOR_ID_GOODTOUCH 0x1aad #define USB_DEVICE_ID_GOODTOUCH_000f 0x000f diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 8555ce7e737b..c5edfa966343 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -179,6 +179,8 @@ static const struct i2c_hid_quirks { I2C_HID_QUIRK_DELAY_AFTER_SLEEP }, { USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_8001, I2C_HID_QUIRK_NO_RUNTIME_PM }, + { I2C_VENDOR_ID_GOODIX, I2C_DEVICE_ID_GOODIX_01F0, + I2C_HID_QUIRK_NO_RUNTIME_PM }, { 0, 0 } }; -- cgit v1.2.3-58-ga151 From 2314e879747e82896f51cce4488f6a00f3e1af7b Mon Sep 17 00:00:00 2001 From: Henry Yen Date: Mon, 14 Jan 2019 17:59:43 +0800 Subject: netfilter: nft_flow_offload: fix checking method of conntrack helper This patch uses nfct_help() to detect whether an established connection needs conntrack helper instead of using test_bit(IPS_HELPER_BIT, &ct->status). The reason is that IPS_HELPER_BIT is only set when using explicit CT target. However, in the case that a device enables conntrack helper via command "echo 1 > /proc/sys/net/netfilter/nf_conntrack_helper", the status of IPS_HELPER_BIT will not present any change, and consequently it loses the checking ability in the context. Signed-off-by: Henry Yen Reviewed-by: Ryder Lee Tested-by: John Crispin Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_flow_offload.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c index 188c6bbf4e16..6e6b9adf7d38 100644 --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c @@ -12,6 +12,7 @@ #include #include #include +#include struct nft_flow_offload { struct nft_flowtable *flowtable; @@ -66,6 +67,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, { struct nft_flow_offload *priv = nft_expr_priv(expr); struct nf_flowtable *flowtable = &priv->flowtable->data; + const struct nf_conn_help *help; enum ip_conntrack_info ctinfo; struct nf_flow_route route; struct flow_offload *flow; @@ -88,7 +90,8 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, goto out; } - if (test_bit(IPS_HELPER_BIT, &ct->status)) + help = nfct_help(ct); + if (help) goto out; if (ctinfo == IP_CT_NEW || -- cgit v1.2.3-58-ga151 From 2bd44dadd5bfb4135162322fd0b45a174d4ad5bf Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 23 Dec 2018 21:59:17 +0100 Subject: mmc: sdhci-iproc: handle mmc_of_parse() errors during probe We need to handle mmc_of_parse() errors during probe. This finally fixes the wifi regression on Raspberry Pi 3 series. In error case the wifi chip was permanently in reset because of the power sequence depending on the deferred probe of the GPIO expander. Fixes: b580c52d58d9 ("mmc: sdhci-iproc: add IPROC SDHCI driver") Cc: stable@vger.kernel.org Signed-off-by: Stefan Wahren Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-iproc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 0db99057c44f..9d12c06c7fd6 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -296,7 +296,10 @@ static int sdhci_iproc_probe(struct platform_device *pdev) iproc_host->data = iproc_data; - mmc_of_parse(host->mmc); + ret = mmc_of_parse(host->mmc); + if (ret) + goto err; + sdhci_get_property(pdev); host->mmc->caps |= iproc_host->data->mmc_caps; -- cgit v1.2.3-58-ga151 From 5bf859081f6a7575a3f7509d7a70d0a9baa88ce3 Mon Sep 17 00:00:00 2001 From: Paolo Valente Date: Thu, 6 Dec 2018 19:18:19 +0100 Subject: block, bfq: fix comments on __bfq_deactivate_entity Comments on function __bfq_deactivate_entity contains two imprecise or wrong statements: 1) The function performs the deactivation of the entity. 2) The function must be invoked only if the entity is on a service tree. This commits replaces both statements with the correct ones: 1) The functions updates sched_data and service trees for the entity, so as to represent entity as inactive (which is only part of the steps needed for the deactivation of the entity). 2) The function must be invoked on every entity being deactivated. Signed-off-by: Paolo Valente Signed-off-by: Jens Axboe --- block/bfq-wf2q.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/block/bfq-wf2q.c b/block/bfq-wf2q.c index 63e0f12be7c9..72adbbe975d5 100644 --- a/block/bfq-wf2q.c +++ b/block/bfq-wf2q.c @@ -1154,15 +1154,14 @@ static void bfq_activate_requeue_entity(struct bfq_entity *entity, } /** - * __bfq_deactivate_entity - deactivate an entity from its service tree. - * @entity: the entity to deactivate. + * __bfq_deactivate_entity - update sched_data and service trees for + * entity, so as to represent entity as inactive + * @entity: the entity being deactivated. * @ins_into_idle_tree: if false, the entity will not be put into the * idle tree. * - * Deactivates an entity, independently of its previous state. Must - * be invoked only if entity is on a service tree. Extracts the entity - * from that tree, and if necessary and allowed, puts it into the idle - * tree. + * If necessary and allowed, puts entity into the idle tree. NOTE: + * entity may be on no tree if in service. */ bool __bfq_deactivate_entity(struct bfq_entity *entity, bool ins_into_idle_tree) { -- cgit v1.2.3-58-ga151 From 6251691a92170d3a781aaf7b5f2c31b50d669809 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Mon, 14 Jan 2019 06:31:56 -0700 Subject: md: Make bio_alloc_mddev use bio_alloc_bioset bio_alloc_bioset returns a bio pointer or NULL, so we can avoid storing the returned data into a new variable. Acked-by: Guoqing Jiang Acked-by: Artur Paszkiewicz Signed-off-by: Marcos Paulo de Souza Signed-off-by: Jens Axboe --- drivers/md/md.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index fd4af4de03b4..05ffffb8b769 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -207,15 +207,10 @@ static bool create_on_open = true; struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, struct mddev *mddev) { - struct bio *b; - if (!mddev || !bioset_initialized(&mddev->bio_set)) return bio_alloc(gfp_mask, nr_iovecs); - b = bio_alloc_bioset(gfp_mask, nr_iovecs, &mddev->bio_set); - if (!b) - return NULL; - return b; + return bio_alloc_bioset(gfp_mask, nr_iovecs, &mddev->bio_set); } EXPORT_SYMBOL_GPL(bio_alloc_mddev); -- cgit v1.2.3-58-ga151 From a8eda9fa1bd84065b75bfa81bf675a7af9055478 Mon Sep 17 00:00:00 2001 From: Karoly Pados Date: Mon, 14 Jan 2019 13:30:03 +0100 Subject: USB: serial: ftdi_sio: fix GPIO not working in autosuspend There is a bug in the current GPIO code for ftdi_sio: it failed to take USB autosuspend into account. If the device is in autosuspend, calls to usb_control_msg() fail with -EHOSTUNREACH. Because the standard value for autosuspend timeout is usually 2-5 seconds, this made it almost impossible to use the GPIOs on machines that have USB autosuspend enabled. This patch fixes the issue by acquiring a PM lock on the device for the duration of the USB transfers. Tested on an FT231X device. Signed-off-by: Karoly Pados [ johan: simplify code somewhat ] Fixes: ba93cc7da896 ("USB: serial: ftdi_sio: implement GPIO support for FT-X devices") Cc: stable # 4.20 Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1ab2a6191013..77ef4c481f3c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1783,6 +1783,10 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) int result; u16 val; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value; result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -1795,6 +1799,8 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) val, result); } + usb_autopm_put_interface(serial->interface); + return result; } @@ -1846,9 +1852,15 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) unsigned char *buf; int result; + result = usb_autopm_get_interface(serial->interface); + if (result) + return result; + buf = kmalloc(1, GFP_KERNEL); - if (!buf) + if (!buf) { + usb_autopm_put_interface(serial->interface); return -ENOMEM; + } result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -1863,6 +1875,7 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) } kfree(buf); + usb_autopm_put_interface(serial->interface); return result; } -- cgit v1.2.3-58-ga151 From 5268c8f39e0efef81af2aaed160272d9eb507beb Mon Sep 17 00:00:00 2001 From: Talons Lee Date: Mon, 10 Dec 2018 18:03:00 +0800 Subject: always clear the X2APIC_ENABLE bit for PV guest Commit e657fcc clears cpu capability bit instead of using fake cpuid value, the EXTD should always be off for PV guest without depending on cpuid value. So remove the cpuid check in xen_read_msr_safe() to always clear the X2APIC_ENABLE bit. Signed-off-by: Talons Lee Reviewed-by: Juergen Gross Signed-off-by: Boris Ostrovsky --- arch/x86/xen/enlighten_pv.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index 2f6787fc7106..c54a493e139a 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -898,10 +898,7 @@ static u64 xen_read_msr_safe(unsigned int msr, int *err) val = native_read_msr_safe(msr, err); switch (msr) { case MSR_IA32_APICBASE: -#ifdef CONFIG_X86_X2APIC - if (!(cpuid_ecx(1) & (1 << (X86_FEATURE_X2APIC & 31)))) -#endif - val &= ~X2APIC_ENABLE; + val &= ~X2APIC_ENABLE; break; } return val; -- cgit v1.2.3-58-ga151 From f672b93e4a0a4947d2e1103ed8780e01e13eadb6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Jan 2019 10:44:51 +0100 Subject: drm/meson: add missing of_node_put Add an of_node_put when the result of of_graph_get_remote_port_parent is not available. An of_node_put is also needed when meson_probe_remote completes. This was present at the recursive call, but not in the call from meson_drv_probe. The semantic match that finds this problem is as follows (http://coccinelle.lip6.fr): // @r exists@ local idexpression e; expression x; @@ e = of_graph_get_remote_port_parent(...); ... when != x = e when != true e == NULL when != of_node_put(e) when != of_fwnode_handle(e) ( return e; | *return ...; ) // Signed-off-by: Julia Lawall Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/1547372691-28324-4-git-send-email-Julia.Lawall@lip6.fr --- drivers/gpu/drm/meson/meson_drv.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 3ee4d4a4ecba..b59c7570f4cb 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -388,8 +388,10 @@ static int meson_probe_remote(struct platform_device *pdev, remote_node = of_graph_get_remote_port_parent(ep); if (!remote_node || remote_node == parent || /* Ignore parent endpoint */ - !of_device_is_available(remote_node)) + !of_device_is_available(remote_node)) { + of_node_put(remote_node); continue; + } count += meson_probe_remote(pdev, match, remote, remote_node); @@ -408,10 +410,13 @@ static int meson_drv_probe(struct platform_device *pdev) for_each_endpoint_of_node(np, ep) { remote = of_graph_get_remote_port_parent(ep); - if (!remote || !of_device_is_available(remote)) + if (!remote || !of_device_is_available(remote)) { + of_node_put(remote); continue; + } count += meson_probe_remote(pdev, &match, np, remote); + of_node_put(remote); } if (count && !match) -- cgit v1.2.3-58-ga151 From 19ba9ecf24189bd74d070aa1b1c4bcb9fe4ae849 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Mon, 14 Jan 2019 11:40:47 +0300 Subject: XArray: Fix typo in comment Seems copy and paste typo, not a big deal but still for consistency sake better to fix. Signed-off-by: Cyrill Gorcunov Signed-off-by: Matthew Wilcox --- include/linux/xarray.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/xarray.h b/include/linux/xarray.h index 12244aa98a69..7da665f5cb20 100644 --- a/include/linux/xarray.h +++ b/include/linux/xarray.h @@ -496,7 +496,7 @@ static inline void *xa_store_bh(struct xarray *xa, unsigned long index, } /** - * xa_store_irq() - Erase this entry from the XArray. + * xa_store_irq() - Store this entry in the XArray. * @xa: XArray. * @index: Index into array. * @entry: New entry. -- cgit v1.2.3-58-ga151 From 4add635b4e00dd7d6aad83a937afdf1957196da6 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Mon, 14 Jan 2019 10:30:04 -0800 Subject: Input: raspberrypi-ts - fix link error Fix link error when TOUCHSCREEN_RASPBERRYPI_FW is enabled as a module and the dependent module is built-in. The 'depends on RASPBERRYPI_FIRMWARE' by itself prevents the touchscreen driver from being built-in when the firmware is configured as a module. However, the '|| COMPILE_TEST' still allows it unless we explicitly prevent that configuration with '|| (RASPBERRYPI_FIRMWARE=n && COMPILE_TEST)'. ld: drivers/input/touchscreen/raspberrypi-ts.o: in function `rpi_ts_probe': raspberrypi-ts.c:(.text+0x3a8): undefined reference to `rpi_firmware_get' ld: raspberrypi-ts.c:(.text+0x3a8): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `rpi_firmware_get' ld: raspberrypi-ts.c:(.text+0x4c8): undefined reference to `rpi_firmware_property' ld: raspberrypi-ts.c:(.text+0x4c8): relocation truncated to fit: R_AARCH64_CALL26 against undefined symbol `rpi_firmware_property' Rework so that TOUCHSCREEN_RASPBERRYPI_FW depends on RASPBERRYPI_FIRMWARE=n if COMPILE_TEST is enabled. Fixes: 0b9f28fed3f7 ("Input: add official Raspberry Pi's touchscreen driver") Suggested-by: Arnd Bergmann Signed-off-by: Anders Roxell Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a391eacf8cf6..d171e39485d1 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -685,7 +685,7 @@ config TOUCHSCREEN_EDT_FT5X06 config TOUCHSCREEN_RASPBERRYPI_FW tristate "Raspberry Pi's firmware base touch screen support" - depends on RASPBERRYPI_FIRMWARE || COMPILE_TEST + depends on RASPBERRYPI_FIRMWARE || (RASPBERRYPI_FIRMWARE=n && COMPILE_TEST) help Say Y here if you have the official Raspberry Pi 7 inch screen on your system. -- cgit v1.2.3-58-ga151 From 3719876809e745b9db5293d418600c194bbf5c23 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Mon, 14 Jan 2019 12:25:40 -0500 Subject: sbitmap: Protect swap_lock from softirqs The swap_lock used by sbitmap has a chain with locks taken from softirq, but the swap_lock is not protected from being preempted by softirqs. A chain exists of: sbq->ws[i].wait -> dispatch_wait_lock -> swap_lock Where the sbq->ws[i].wait lock can be taken from softirq context, which means all locks below it in the chain must also be protected from softirqs. Reported-by: Clark Williams Fixes: 58ab5e32e6fd ("sbitmap: silence bogus lockdep IRQ warning") Fixes: ea86ea2cdced ("sbitmap: amortize cost of clearing bits") Cc: Jens Axboe Cc: Ming Lei Cc: Guenter Roeck Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Linus Torvalds --- lib/sbitmap.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/sbitmap.c b/lib/sbitmap.c index 65c2d06250a6..864354000e04 100644 --- a/lib/sbitmap.c +++ b/lib/sbitmap.c @@ -26,14 +26,9 @@ static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index) { unsigned long mask, val; - unsigned long __maybe_unused flags; bool ret = false; - /* Silence bogus lockdep warning */ -#if defined(CONFIG_LOCKDEP) - local_irq_save(flags); -#endif - spin_lock(&sb->map[index].swap_lock); + spin_lock_bh(&sb->map[index].swap_lock); if (!sb->map[index].cleared) goto out_unlock; @@ -54,10 +49,7 @@ static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index) ret = true; out_unlock: - spin_unlock(&sb->map[index].swap_lock); -#if defined(CONFIG_LOCKDEP) - local_irq_restore(flags); -#endif + spin_unlock_bh(&sb->map[index].swap_lock); return ret; } -- cgit v1.2.3-58-ga151 From d69d287a9002b70bdbe2975660b97241ccefc071 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 14 Jan 2019 13:57:31 -0500 Subject: XArray tests: Check mark 2 gets squashed We do not currently check that the loop in xas_squash_marks() doesn't have an off-by-one error in it. It didn't, but a patch which introduced an off-by-one error wasn't caught by any existing test. Switch the roles of XA_MARK_1 and XA_MARK_2 to catch that bug. Reported-by: Cyrill Gorcunov Signed-off-by: Matthew Wilcox --- lib/test_xarray.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/test_xarray.c b/lib/test_xarray.c index 3cf17338b0a4..c596a957f764 100644 --- a/lib/test_xarray.c +++ b/lib/test_xarray.c @@ -199,7 +199,7 @@ static noinline void check_xa_mark_1(struct xarray *xa, unsigned long index) XA_BUG_ON(xa, xa_store_index(xa, index + 1, GFP_KERNEL)); xa_set_mark(xa, index + 1, XA_MARK_0); XA_BUG_ON(xa, xa_store_index(xa, index + 2, GFP_KERNEL)); - xa_set_mark(xa, index + 2, XA_MARK_1); + xa_set_mark(xa, index + 2, XA_MARK_2); XA_BUG_ON(xa, xa_store_index(xa, next, GFP_KERNEL)); xa_store_order(xa, index, order, xa_mk_index(index), GFP_KERNEL); @@ -209,8 +209,8 @@ static noinline void check_xa_mark_1(struct xarray *xa, unsigned long index) void *entry; XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_0)); - XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_1)); - XA_BUG_ON(xa, xa_get_mark(xa, i, XA_MARK_2)); + XA_BUG_ON(xa, xa_get_mark(xa, i, XA_MARK_1)); + XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_2)); /* We should see two elements in the array */ rcu_read_lock(); -- cgit v1.2.3-58-ga151 From d1c234e2cd1091b816c990a1848d88a8697f97b4 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Wed, 2 Jan 2019 14:52:13 -0500 Subject: drm/amdkfd: Allow building KFD on ARM64 (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ifdef x86_64 specific code. Allow enabling CONFIG_HSA_AMD on ARM64. v2: Fixed a compiler warning due to an unused variable CC: Mark Nutter Signed-off-by: Felix Kuehling Tested-by: Mark Nutter Acked-by: Alex Deucher Acked-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/Kconfig | 4 ++-- drivers/gpu/drm/amd/amdkfd/kfd_crat.c | 8 ++++++++ drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 9 +++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/Kconfig b/drivers/gpu/drm/amd/amdkfd/Kconfig index fbf0ee5201c3..c3613604a4f8 100644 --- a/drivers/gpu/drm/amd/amdkfd/Kconfig +++ b/drivers/gpu/drm/amd/amdkfd/Kconfig @@ -4,8 +4,8 @@ config HSA_AMD bool "HSA kernel driver for AMD GPU devices" - depends on DRM_AMDGPU && X86_64 - imply AMD_IOMMU_V2 + depends on DRM_AMDGPU && (X86_64 || ARM64) + imply AMD_IOMMU_V2 if X86_64 select MMU_NOTIFIER help Enable this if you want to use HSA features on AMD GPU devices. diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index b7bc7d7d048f..5d85ff341385 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -863,6 +863,7 @@ static int kfd_fill_mem_info_for_cpu(int numa_node_id, int *avail_size, return 0; } +#if CONFIG_X86_64 static int kfd_fill_iolink_info_for_cpu(int numa_node_id, int *avail_size, uint32_t *num_entries, struct crat_subtype_iolink *sub_type_hdr) @@ -905,6 +906,7 @@ static int kfd_fill_iolink_info_for_cpu(int numa_node_id, int *avail_size, return 0; } +#endif /* kfd_create_vcrat_image_cpu - Create Virtual CRAT for CPU * @@ -920,7 +922,9 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size) struct crat_subtype_generic *sub_type_hdr; int avail_size = *size; int numa_node_id; +#ifdef CONFIG_X86_64 uint32_t entries = 0; +#endif int ret = 0; if (!pcrat_image || avail_size < VCRAT_SIZE_FOR_CPU) @@ -982,6 +986,7 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size) sub_type_hdr->length); /* Fill in Subtype: IO Link */ +#ifdef CONFIG_X86_64 ret = kfd_fill_iolink_info_for_cpu(numa_node_id, &avail_size, &entries, (struct crat_subtype_iolink *)sub_type_hdr); @@ -992,6 +997,9 @@ static int kfd_create_vcrat_image_cpu(void *pcrat_image, size_t *size) sub_type_hdr = (typeof(sub_type_hdr))((char *)sub_type_hdr + sub_type_hdr->length * entries); +#else + pr_info("IO link not available for non x86 platforms\n"); +#endif crat_table->num_domains++; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 5f5b2acedbac..4734f1a35516 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1392,7 +1392,6 @@ int kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_dev **kdev) static int kfd_cpumask_to_apic_id(const struct cpumask *cpumask) { - const struct cpuinfo_x86 *cpuinfo; int first_cpu_of_numa_node; if (!cpumask || cpumask == cpu_none_mask) @@ -1400,9 +1399,11 @@ static int kfd_cpumask_to_apic_id(const struct cpumask *cpumask) first_cpu_of_numa_node = cpumask_first(cpumask); if (first_cpu_of_numa_node >= nr_cpu_ids) return -1; - cpuinfo = &cpu_data(first_cpu_of_numa_node); - - return cpuinfo->apicid; +#ifdef CONFIG_X86_64 + return cpu_data(first_cpu_of_numa_node).apicid; +#else + return first_cpu_of_numa_node; +#endif } /* kfd_numa_node_to_apic_id - Returns the APIC ID of the first logical processor -- cgit v1.2.3-58-ga151 From bbdf514fe5648566b0754476cbcb92ac3422dde2 Mon Sep 17 00:00:00 2001 From: Felix Kuehling Date: Wed, 2 Jan 2019 17:47:39 -0500 Subject: drm/amdkfd: Don't assign dGPUs to APU topology devices dGPUs need their own topology devices. Don't assign them to APU topology devices with CPU cores. Bug: https://github.com/RadeonOpenCompute/ROCK-Kernel-Driver/issues/66 Signed-off-by: Felix Kuehling Tested-by: Elias Konstantinidis Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 4734f1a35516..09da91644f9f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1093,8 +1093,6 @@ static uint32_t kfd_generate_gpu_id(struct kfd_dev *gpu) * the GPU device is not already present in the topology device * list then return NULL. This means a new topology device has to * be created for this GPU. - * TODO: Rather than assiging @gpu to first topology device withtout - * gpu attached, it will better to have more stringent check. */ static struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu) { @@ -1102,12 +1100,20 @@ static struct kfd_topology_device *kfd_assign_gpu(struct kfd_dev *gpu) struct kfd_topology_device *out_dev = NULL; down_write(&topology_lock); - list_for_each_entry(dev, &topology_device_list, list) + list_for_each_entry(dev, &topology_device_list, list) { + /* Discrete GPUs need their own topology device list + * entries. Don't assign them to CPU/APU nodes. + */ + if (!gpu->device_info->needs_iommu_device && + dev->node_props.cpu_cores_count) + continue; + if (!dev->gpu && (dev->node_props.simd_count > 0)) { dev->gpu = gpu; out_dev = dev; break; } + } up_write(&topology_lock); return out_dev; } -- cgit v1.2.3-58-ga151 From a29b01a1313d20a6d45c0f25858f31701cee625d Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Wed, 9 Jan 2019 14:39:48 +0800 Subject: drm/amd/powerplay: run acg btc for Vega12 acg btc was added to Vega12 Signed-off-by: Kenneth Feng Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index 54364444ecd1..0c8212902275 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -753,6 +753,22 @@ static int vega12_init_smc_table(struct pp_hwmgr *hwmgr) return 0; } +static int vega12_run_acg_btc(struct pp_hwmgr *hwmgr) +{ + uint32_t result; + + PP_ASSERT_WITH_CODE( + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_RunAcgBtc) == 0, + "[Run_ACG_BTC] Attempt to run ACG BTC failed!", + return -EINVAL); + + result = smum_get_argument(hwmgr); + PP_ASSERT_WITH_CODE(result == 1, + "Failed to run ACG BTC!", return -EINVAL); + + return 0; +} + static int vega12_set_allowed_featuresmask(struct pp_hwmgr *hwmgr) { struct vega12_hwmgr *data = @@ -931,6 +947,11 @@ static int vega12_enable_dpm_tasks(struct pp_hwmgr *hwmgr) "Failed to initialize SMC table!", result = tmp_result); + tmp_result = vega12_run_acg_btc(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to run ACG BTC!", + result = tmp_result); + result = vega12_enable_all_smu_features(hwmgr); PP_ASSERT_WITH_CODE(!result, "Failed to enable all smu features!", -- cgit v1.2.3-58-ga151 From 099139bef026faefebc508ddb77d397cf55f1b15 Mon Sep 17 00:00:00 2001 From: Josip Pavic Date: Tue, 11 Dec 2018 15:13:08 -0500 Subject: drm/amd/display: Pack DMCU iRAM alignment [Why] When the DMCU's iRAM definition was moved to the newly created power_helpers, a #pragma pack was lost, causing the iRAM to be misaligned [How] Restore the #pragma pack Signed-off-by: Josip Pavic Reviewed-by: Anthony Koo Acked-by: Leo Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/modules/power/power_helpers.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index 00f63b7dd32f..c11a443dcbc8 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -57,6 +57,7 @@ static const unsigned char abm_config[abm_defines_max_config][abm_defines_max_le #define NUM_POWER_FN_SEGS 8 #define NUM_BL_CURVE_SEGS 16 +#pragma pack(push, 1) /* NOTE: iRAM is 256B in size */ struct iram_table_v_2 { /* flags */ @@ -100,6 +101,7 @@ struct iram_table_v_2 { uint8_t dummy8; /* 0xfe */ uint8_t dummy9; /* 0xff */ }; +#pragma pack(pop) static uint16_t backlight_8_to_16(unsigned int backlight_8bit) { -- cgit v1.2.3-58-ga151 From dddce8b490051018f8d5d1457af47483064c7e09 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Thu, 10 Jan 2019 15:12:48 -0500 Subject: drm/amd/display: Only get the connector state for VRR when toggled [Why] This fixes a stuttering issue that occurs when moving a hardware cursor when VRR is enabled. Previously when VRR is enabled atomic check will grab the connector state for every atomic update. This has to lock the connector in order to do so. The locking is bad enough by itself for performance, but it gets worse with what we do just below that - add all the planes for the CRTC to the commit. This prevents the cursor fast path from working - there's more than one plane now. With state->allow_modeset = true on top of this, it also adds and removes all the planes from the DC context triggering a full (very slow) update in DC. [How] We need the connector state to get the VRR min/max capbilities, but we only need them when there's a CRTC mode change or when VRR is toggled. The condition has been updated accordingly. Fixes: 3cc22f281318 ("drm/amdgpu: Set FreeSync state using drm VRR properties") Signed-off-by: Nicholas Kazlauskas Reviewed-by: Leo Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 34f35e9a3c46..903dbafc144d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5933,7 +5933,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && !new_crtc_state->color_mgmt_changed && - !new_crtc_state->vrr_enabled) + old_crtc_state->vrr_enabled == new_crtc_state->vrr_enabled) continue; if (!new_crtc_state->enable) -- cgit v1.2.3-58-ga151 From 20300db4aec5ba5edf6f0ad6f7111a51fbea7e10 Mon Sep 17 00:00:00 2001 From: Charlene Liu Date: Wed, 12 Dec 2018 18:09:16 -0500 Subject: drm/amd/display: fix PME notification not working in RV desktop [Why] PPLIB not receive the PME when unplug. Signed-off-by: Charlene Liu Reviewed-by: Chris Park Acked-by: Leo Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 4bf24758217f..8f09b8625c5d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1000,7 +1000,7 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio); - if (num_audio == 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) + if (num_audio >= 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); /* un-mute audio */ @@ -1017,6 +1017,8 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( pipe_ctx->stream_res.stream_enc, true); if (pipe_ctx->stream_res.audio) { + struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; + if (option != KEEP_ACQUIRED_RESOURCE || !dc->debug.az_endpoint_mute_only) { /*only disalbe az_endpoint if power down or free*/ @@ -1036,6 +1038,9 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, pipe_ctx->stream_res.audio, false); pipe_ctx->stream_res.audio = NULL; } + if (pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) + /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ + pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); /* TODO: notify audio driver for if audio modes list changed * add audio mode list change flag */ -- cgit v1.2.3-58-ga151 From f5c412ac596fbe1508514257fef3d48e263f40a7 Mon Sep 17 00:00:00 2001 From: Roman Li Date: Wed, 19 Dec 2018 09:24:06 -0500 Subject: drm/amd/display: fix warning on raven hotplug [Why] Hotplug on raven results in REG_WAIT_TIMEOUT warning due to failing attempt to lock disabled otg for the hubp interdependent pipes programming. [How] Don't setup pipe interdependencies for disabled otg. Also removed the unnecessary duplicate logic checks. Signed-off-by: Roman Li Reviewed-by: Dmytro Laktyushkin Acked-by: Leo Li Signed-off-by: Alex Deucher --- .../gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 91e015e14355..58a12ddf12f3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -2355,29 +2355,22 @@ static void dcn10_apply_ctx_for_surface( top_pipe_to_program->plane_state->update_flags.bits.full_update) for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - + tg = pipe_ctx->stream_res.tg; /* Skip inactive pipes and ones already updated */ if (!pipe_ctx->stream || pipe_ctx->stream == stream - || !pipe_ctx->plane_state) + || !pipe_ctx->plane_state + || !tg->funcs->is_tg_enabled(tg)) continue; - pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); + tg->funcs->lock(tg); pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent( pipe_ctx->plane_res.hubp, &pipe_ctx->dlg_regs, &pipe_ctx->ttu_regs); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - if (!pipe_ctx->stream || pipe_ctx->stream == stream - || !pipe_ctx->plane_state) - continue; - - dcn10_pipe_control_lock(dc, pipe_ctx, false); - } + tg->funcs->unlock(tg); + } if (num_planes == 0) false_optc_underflow_wa(dc, stream, tg); -- cgit v1.2.3-58-ga151 From ae1cf20df7a9c60ff5ef41c3315c33c1a5fafd77 Mon Sep 17 00:00:00 2001 From: Nicholas Kazlauskas Date: Tue, 11 Dec 2018 12:35:56 -0500 Subject: drm/amd/display: Fix disabled cursor on top screen edge [Why] The cursor vanishes when touching the top of edge of the screen for Raven on Linux. This occurs because the cursor height is not taken into account when deciding to disable the cursor. [How] Factor in the cursor height into the cursor calculations - and mimic the existing x position calculations. Fixes: 94a4ffd1d40b ("drm/amd/display: fix PIP bugs on Dal3") Signed-off-by: Nicholas Kazlauskas Reviewed-by: Harry Wentland Acked-by: Leo Li Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c | 2 +- drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index dcb3c5530236..cd1ebe57ed59 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -463,7 +463,7 @@ void dpp1_set_cursor_position( if (src_y_offset >= (int)param->viewport.height) cur_en = 0; /* not visible beyond bottom edge*/ - if (src_y_offset < 0) + if (src_y_offset + (int)height <= 0) cur_en = 0; /* not visible beyond top edge*/ REG_UPDATE(CURSOR0_CONTROL, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index 345af015d061..d1acd7165bc8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -1140,7 +1140,7 @@ void hubp1_cursor_set_position( if (src_y_offset >= (int)param->viewport.height) cur_en = 0; /* not visible beyond bottom edge*/ - if (src_y_offset < 0) //+ (int)hubp->curs_attr.height + if (src_y_offset + (int)hubp->curs_attr.height <= 0) cur_en = 0; /* not visible beyond top edge*/ if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0) -- cgit v1.2.3-58-ga151 From d6f4a21f309dfe10a5693ad236358dd6fcc46f7a Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 11 Jan 2019 08:21:44 +0200 Subject: RDMA/uverbs: Mark ioctl responses with UVERBS_ATTR_F_VALID_OUTPUT When the ioctl interface for the write commands was introduced it did not mark the core response with UVERBS_ATTR_F_VALID_OUTPUT. This causes rdma-core in userspace to not mark the buffers as written for valgrind. Along the same lines it turns out we have always missed marking the driver data. Fixing both of these makes valgrind work properly with rdma-core and ioctl. Fixes: 4785860e04bc ("RDMA/uverbs: Implement an ioctl that can call write and write_ex handlers") Signed-off-by: Jason Gunthorpe Reviewed-by: Artemy Kovalyov Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/rdma_core.h | 2 ++ drivers/infiniband/core/uverbs_cmd.c | 7 ++++ drivers/infiniband/core/uverbs_ioctl.c | 62 +++++++++++++++++++++++++++------- drivers/infiniband/core/uverbs_main.c | 1 + 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h index be6b8e1257d0..69f8db66925e 100644 --- a/drivers/infiniband/core/rdma_core.h +++ b/drivers/infiniband/core/rdma_core.h @@ -106,6 +106,8 @@ int uverbs_finalize_object(struct ib_uobject *uobj, enum uverbs_obj_access access, bool commit); +int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx); + void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile); void release_ufile_idr_uobject(struct ib_uverbs_file *ufile); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 1b82cb74276c..3317300ab036 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -60,6 +60,10 @@ static int uverbs_response(struct uverbs_attr_bundle *attrs, const void *resp, { int ret; + if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT)) + return uverbs_copy_to_struct_or_zero( + attrs, UVERBS_ATTR_CORE_OUT, resp, resp_len); + if (copy_to_user(attrs->ucore.outbuf, resp, min(attrs->ucore.outlen, resp_len))) return -EFAULT; @@ -1181,6 +1185,9 @@ static int ib_uverbs_poll_cq(struct uverbs_attr_bundle *attrs) goto out_put; } + if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_CORE_OUT)) + ret = uverbs_output_written(attrs, UVERBS_ATTR_CORE_OUT); + ret = 0; out_put: diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index 8c81ff698052..0ca04d224015 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -144,6 +144,21 @@ static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr, 0, uattr->len - len); } +static int uverbs_set_output(const struct uverbs_attr_bundle *bundle, + const struct uverbs_attr *attr) +{ + struct bundle_priv *pbundle = + container_of(bundle, struct bundle_priv, bundle); + u16 flags; + + flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags | + UVERBS_ATTR_F_VALID_OUTPUT; + if (put_user(flags, + &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags)) + return -EFAULT; + return 0; +} + static int uverbs_process_idrs_array(struct bundle_priv *pbundle, const struct uverbs_api_attr *attr_uapi, struct uverbs_objs_arr_attr *attr, @@ -455,6 +470,19 @@ static int ib_uverbs_run_method(struct bundle_priv *pbundle, ret = handler(&pbundle->bundle); } + /* + * Until the drivers are revised to use the bundle directly we have to + * assume that the driver wrote to its UHW_OUT and flag userspace + * appropriately. + */ + if (!ret && pbundle->method_elm->has_udata) { + const struct uverbs_attr *attr = + uverbs_attr_get(&pbundle->bundle, UVERBS_ATTR_UHW_OUT); + + if (!IS_ERR(attr)) + ret = uverbs_set_output(&pbundle->bundle, attr); + } + /* * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can * not invoke the method because the request is not supported. No @@ -706,10 +734,7 @@ void uverbs_fill_udata(struct uverbs_attr_bundle *bundle, int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx, const void *from, size_t size) { - struct bundle_priv *pbundle = - container_of(bundle, struct bundle_priv, bundle); const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx); - u16 flags; size_t min_size; if (IS_ERR(attr)) @@ -719,16 +744,25 @@ int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx, if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size)) return -EFAULT; - flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags | - UVERBS_ATTR_F_VALID_OUTPUT; - if (put_user(flags, - &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags)) - return -EFAULT; - - return 0; + return uverbs_set_output(bundle, attr); } EXPORT_SYMBOL(uverbs_copy_to); + +/* + * This is only used if the caller has directly used copy_to_use to write the + * data. It signals to user space that the buffer is filled in. + */ +int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx) +{ + const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx); + + if (IS_ERR(attr)) + return PTR_ERR(attr); + + return uverbs_set_output(bundle, attr); +} + int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle, size_t idx, s64 lower_bound, u64 upper_bound, s64 *def_val) @@ -757,8 +791,10 @@ int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle, { const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx); - if (clear_user(u64_to_user_ptr(attr->ptr_attr.data), - attr->ptr_attr.len)) - return -EFAULT; + if (size < attr->ptr_attr.len) { + if (clear_user(u64_to_user_ptr(attr->ptr_attr.data) + size, + attr->ptr_attr.len - size)) + return -EFAULT; + } return uverbs_copy_to(bundle, idx, from, size); } diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index fb0007aa0c27..2890a77339e1 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -690,6 +690,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, buf += sizeof(hdr); + memset(bundle.attr_present, 0, sizeof(bundle.attr_present)); bundle.ufile = file; if (!method_elm->is_ex) { size_t in_len = hdr.in_words * 4 - sizeof(hdr); -- cgit v1.2.3-58-ga151 From 8a644c64a9f1aefb99fdc4413e6b7fee17809e38 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 12 Jan 2019 20:37:28 +0100 Subject: MIPS: OCTEON: fix kexec support Commit 62cac480f33f ("MIPS: kexec: Make a framework for both jumping and halting on nonboot CPUs") broke the build of the OCTEON platform as the relocated_kexec_smp_wait() is now static and not longer exported in kexec.h. Replace it by kexec_reboot() like it has been done in other places. Fixes: 62cac480f33f ("MIPS: kexec: Make a framework for both jumping and halting on nonboot CPUs") Signed-off-by: Aurelien Jarno Signed-off-by: Paul Burton Cc: linux-mips@vger.kernel.org Cc: Dengcheng Zhu Cc: ralf@linux-mips.org Cc: stable@vger.kernel.org # 4.20+ --- arch/mips/cavium-octeon/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 2c79ab52977a..8bf43c5a7bc7 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -98,7 +98,7 @@ static void octeon_kexec_smp_down(void *ignored) " sync \n" " synci ($0) \n"); - relocated_kexec_smp_wait(NULL); + kexec_reboot(); } #endif -- cgit v1.2.3-58-ga151 From 7151449fe7fa5962c6153355f9779d6be99e8e97 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Mon, 14 Jan 2019 17:32:58 +0800 Subject: regmap-irq: do not write mask register if mask_base is zero If client have not provided the mask base register then do not write into the mask register. Signed-off-by: Laxman Dewangan Signed-off-by: Jinyoung Park Signed-off-by: Venkat Reddy Talla Signed-off-by: Mark Zhang Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-irq.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index d2d0014b0d23..330c1f7e9665 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -108,6 +108,9 @@ static void regmap_irq_sync_unlock(struct irq_data *data) * suppress pointless writes. */ for (i = 0; i < d->chip->num_regs; i++) { + if (!d->chip->mask_base) + continue; + reg = d->chip->mask_base + (i * map->reg_stride * d->irq_reg_stride); if (d->chip->mask_invert) { @@ -588,6 +591,9 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, /* Mask all the interrupts by default */ for (i = 0; i < chip->num_regs; i++) { d->mask_buf[i] = d->mask_buf_def[i]; + if (!chip->mask_base) + continue; + reg = chip->mask_base + (i * map->reg_stride * d->irq_reg_stride); if (chip->mask_invert) -- cgit v1.2.3-58-ga151 From 3e8c45f57a90585cfc0b07ae81de8960a8366c1c Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Mon, 14 Jan 2019 10:55:40 +0100 Subject: ASoC: cs4341: fix waring unused-function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver cs4341 can be built with SPI and/or I2C, but it has to be one of them at least. When I2C is set as a module we see the warning below: sound/soc/codecs/cs4341.c:213:12: warning: ‘cs4341_probe’ defined but not used [-Wunused-function] static int cs4341_probe(struct device *dev) ^~~~~~~~~~~~ Rework so that we use IS_ENABLED instead of defined. Also change so SND_SOC_CS4341 depends on SND_SOC_I2C_AND_SPI to we dont' get a link error when SND_SOC_CS4341=y, I2C=m and REGMAP_I2C=m is set. Suggested-by: Arnd Bergmann Signed-off-by: Anders Roxell Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/cs4341.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 87cb9c51e6f5..87ecb38e57f4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -546,7 +546,7 @@ config SND_SOC_CS43130 config SND_SOC_CS4341 tristate "Cirrus Logic CS4341 CODEC" - depends on I2C || SPI_MASTER + depends on SND_SOC_I2C_AND_SPI select REGMAP_I2C if I2C select REGMAP_SPI if SPI_MASTER diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c index d2e616a89fd4..ade7477d04f1 100644 --- a/sound/soc/codecs/cs4341.c +++ b/sound/soc/codecs/cs4341.c @@ -223,7 +223,7 @@ static int cs4341_probe(struct device *dev) &cs4341_dai, 1); } -#if defined(CONFIG_I2C) +#if IS_ENABLED(CONFIG_I2C) static int cs4341_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -317,7 +317,7 @@ static int __init cs4341_init(void) { int ret = 0; -#if defined(CONFIG_I2C) +#if IS_ENABLED(CONFIG_I2C) ret = i2c_add_driver(&cs4341_i2c_driver); if (ret) return ret; @@ -332,7 +332,7 @@ module_init(cs4341_init); static void __exit cs4341_exit(void) { -#if defined(CONFIG_I2C) +#if IS_ENABLED(CONFIG_I2C) i2c_del_driver(&cs4341_i2c_driver); #endif #if defined(CONFIG_SPI_MASTER) -- cgit v1.2.3-58-ga151 From fecd5c09ddf8711c0b17087cc7a40ac57680f8ed Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 14 Jan 2019 14:36:40 +0000 Subject: ASoC: msm8916-wcd-digital: remove few unused variables This patch removes unused variables which also fixes below warnings: msm8916-wcd-digital.c:245:30: warning: 'rx2_mix2_inp1_chain_enum' defined but not used [-Wunused-const-variable=] static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( ^~~~~~~~~~~~~~~~~~~~~~~~ msm8916-wcd-digital.c:234:30: warning: 'rx_mix2_inp1_chain_enum' defined but not used [-Wunused-const-variable=] static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( ^~~~~~~~~~~~~~~~~~~~~~~ msm8916-wcd-digital.c:224:26: warning: 'adc2_mux_text' defined but not used [-Wunused-const-variable=] static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; ^~~~~~~~~~~~~ msm8916-wcd-digital.c:223:26: warning: 'rx_mix2_text' defined but not used [-Wunused-const-variable=] Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-digital.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index 3063dedd21cf..423bfebabed4 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -220,8 +220,6 @@ static const char *const dec_mux_text[] = { }; static const char *const cic_mux_text[] = { "AMIC", "DMIC" }; -static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" }; -static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; /* RX1 MIX1 */ static const struct soc_enum rx_mix1_inp_enum[] = { @@ -230,10 +228,6 @@ static const struct soc_enum rx_mix1_inp_enum[] = { SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text), }; -/* RX1 MIX2 */ -static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( - LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text); - /* RX2 MIX1 */ static const struct soc_enum rx2_mix1_inp_enum[] = { SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), @@ -241,10 +235,6 @@ static const struct soc_enum rx2_mix1_inp_enum[] = { SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B2_CTL, 0, 6, rx_mix1_text), }; -/* RX2 MIX2 */ -static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( - LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text); - /* RX3 MIX1 */ static const struct soc_enum rx3_mix1_inp_enum[] = { SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), -- cgit v1.2.3-58-ga151 From 5b86fa6d2903c41c3c3dbff4def76a5b8bbe0660 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 11 Jan 2019 18:20:40 +0800 Subject: ASoC: msm8916-wcd-digital: Select REGMAP_MMIO to fix build error Fix below build error: ERROR: "__devm_regmap_init_mmio_clk" [sound/soc/codecs/snd-soc-msm8916-digital.ko] undefined! Signed-off-by: Axel Lin Acked-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 87ecb38e57f4..71e6e123a115 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -706,6 +706,7 @@ config SND_SOC_MSM8916_WCD_ANALOG config SND_SOC_MSM8916_WCD_DIGITAL tristate "Qualcomm MSM8916 WCD DIGITAL Codec" + select REGMAP_MMIO config SND_SOC_PCM1681 tristate "Texas Instruments PCM1681 CODEC" -- cgit v1.2.3-58-ga151 From c284d4e31a0b66e6fe3734b36080afd237ff9fb0 Mon Sep 17 00:00:00 2001 From: Maruthi Srinivas Bayyavarapu Date: Thu, 10 Jan 2019 18:44:43 +0530 Subject: ASoC: xlnx: parse AES audio parameters AES channel status carries various audio parameters. If channel status is detected, current patch extracts sample rate and bit depth parameters of the incoming stream during capture. Signed-off-by: Maruthi Srinivas Bayyavarapu Signed-off-by: Mark Brown --- sound/soc/xilinx/xlnx_formatter_pcm.c | 143 ++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c index d2194da928e7..97177d35652e 100644 --- a/sound/soc/xilinx/xlnx_formatter_pcm.c +++ b/sound/soc/xilinx/xlnx_formatter_pcm.c @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -63,6 +64,7 @@ #define PERIODS_MAX 6 #define PERIOD_BYTES_MIN 192 #define PERIOD_BYTES_MAX (50 * 1024) +#define XLNX_PARAM_UNKNOWN 0 enum bit_depth { BIT_DEPTH_8, @@ -117,6 +119,129 @@ static const struct snd_pcm_hardware xlnx_pcm_hardware = { .periods_max = PERIODS_MAX, }; +enum { + AES_TO_AES, + AES_TO_PCM, + PCM_TO_PCM, + PCM_TO_AES +}; + +static void xlnx_parse_aes_params(u32 chsts_reg1_val, u32 chsts_reg2_val, + struct device *dev) +{ + u32 padded, srate, bit_depth, status[2]; + + if (chsts_reg1_val & IEC958_AES0_PROFESSIONAL) { + status[0] = chsts_reg1_val & 0xff; + status[1] = (chsts_reg1_val >> 16) & 0xff; + + switch (status[0] & IEC958_AES0_PRO_FS) { + case IEC958_AES0_PRO_FS_44100: + srate = 44100; + break; + case IEC958_AES0_PRO_FS_48000: + srate = 48000; + break; + case IEC958_AES0_PRO_FS_32000: + srate = 32000; + break; + case IEC958_AES0_PRO_FS_NOTID: + default: + srate = XLNX_PARAM_UNKNOWN; + break; + } + + switch (status[1] & IEC958_AES2_PRO_SBITS) { + case IEC958_AES2_PRO_WORDLEN_NOTID: + case IEC958_AES2_PRO_SBITS_20: + padded = 0; + break; + case IEC958_AES2_PRO_SBITS_24: + padded = 4; + break; + default: + bit_depth = XLNX_PARAM_UNKNOWN; + goto log_params; + } + + switch (status[1] & IEC958_AES2_PRO_WORDLEN) { + case IEC958_AES2_PRO_WORDLEN_20_16: + bit_depth = 16 + padded; + break; + case IEC958_AES2_PRO_WORDLEN_22_18: + bit_depth = 18 + padded; + break; + case IEC958_AES2_PRO_WORDLEN_23_19: + bit_depth = 19 + padded; + break; + case IEC958_AES2_PRO_WORDLEN_24_20: + bit_depth = 20 + padded; + break; + case IEC958_AES2_PRO_WORDLEN_NOTID: + default: + bit_depth = XLNX_PARAM_UNKNOWN; + break; + } + + } else { + status[0] = (chsts_reg1_val >> 24) & 0xff; + status[1] = chsts_reg2_val & 0xff; + + switch (status[0] & IEC958_AES3_CON_FS) { + case IEC958_AES3_CON_FS_44100: + srate = 44100; + break; + case IEC958_AES3_CON_FS_48000: + srate = 48000; + break; + case IEC958_AES3_CON_FS_32000: + srate = 32000; + break; + default: + srate = XLNX_PARAM_UNKNOWN; + break; + } + + if (status[1] & IEC958_AES4_CON_MAX_WORDLEN_24) + padded = 4; + else + padded = 0; + + switch (status[1] & IEC958_AES4_CON_WORDLEN) { + case IEC958_AES4_CON_WORDLEN_20_16: + bit_depth = 16 + padded; + break; + case IEC958_AES4_CON_WORDLEN_22_18: + bit_depth = 18 + padded; + break; + case IEC958_AES4_CON_WORDLEN_23_19: + bit_depth = 19 + padded; + break; + case IEC958_AES4_CON_WORDLEN_24_20: + bit_depth = 20 + padded; + break; + case IEC958_AES4_CON_WORDLEN_21_17: + bit_depth = 17 + padded; + break; + case IEC958_AES4_CON_WORDLEN_NOTID: + default: + bit_depth = XLNX_PARAM_UNKNOWN; + break; + } + } + +log_params: + if (srate != XLNX_PARAM_UNKNOWN) + dev_info(dev, "sample rate = %d\n", srate); + else + dev_info(dev, "sample rate = unknown\n"); + + if (bit_depth != XLNX_PARAM_UNKNOWN) + dev_info(dev, "bit_depth = %d\n", bit_depth); + else + dev_info(dev, "bit_depth = unknown\n"); +} + static int xlnx_formatter_pcm_reset(void __iomem *mmio_base) { u32 val, retries = 0; @@ -302,8 +427,12 @@ static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample; + u32 aes_reg1_val, aes_reg2_val; int status; u64 size; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(prtd, + DRV_NAME); struct snd_pcm_runtime *runtime = substream->runtime; struct xlnx_pcm_stream_param *stream_data = runtime->private_data; @@ -311,6 +440,20 @@ static int xlnx_formatter_pcm_hw_params(struct snd_pcm_substream *substream, if (active_ch > stream_data->ch_limit) return -EINVAL; + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + stream_data->xfer_mode == AES_TO_PCM) { + val = readl(stream_data->mmio + XLNX_AUD_STS); + if (val & AUD_STS_CH_STS_MASK) { + aes_reg1_val = readl(stream_data->mmio + + XLNX_AUD_CH_STS_START); + aes_reg2_val = readl(stream_data->mmio + + XLNX_AUD_CH_STS_START + 0x4); + + xlnx_parse_aes_params(aes_reg1_val, aes_reg2_val, + component->dev); + } + } + size = params_buffer_bytes(params); status = snd_pcm_lib_malloc_pages(substream, size); if (status < 0) -- cgit v1.2.3-58-ga151 From 2e8cb2cf1bd6e90f58bd517eb9ca1938e64fa51c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 14 Jan 2019 15:35:46 -0600 Subject: PCI: Fix PCI kconfig menu organization After commit eb01d42a7778 ("PCI: consolidate PCI config entry in drivers/pci"), all the PCI kconfig options appear below "PCI support" rather than within a sub-menu. This is because menuconfig expects all kconfig entries to be enclosed in an if/endif section. Add the missing if/endif. With this, "depends on PCI" is redundant in the sub-menu entries and can be removed. Fixes: eb01d42a7778 ("PCI: consolidate PCI config entry in drivers/pci") Signed-off-by: Rob Herring Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig --- drivers/pci/Kconfig | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 4310c7a4212e..2ab92409210a 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -21,13 +21,14 @@ menuconfig PCI support for PCI-X and the foundations for PCI Express support. Say 'Y' here unless you know what you are doing. +if PCI + config PCI_DOMAINS bool depends on PCI config PCI_DOMAINS_GENERIC bool - depends on PCI select PCI_DOMAINS config PCI_SYSCALL @@ -37,7 +38,6 @@ source "drivers/pci/pcie/Kconfig" config PCI_MSI bool "Message Signaled Interrupts (MSI and MSI-X)" - depends on PCI select GENERIC_MSI_IRQ help This allows device drivers to enable MSI (Message Signaled @@ -59,7 +59,6 @@ config PCI_MSI_IRQ_DOMAIN config PCI_QUIRKS default y bool "Enable PCI quirk workarounds" if EXPERT - depends on PCI help This enables workarounds for various PCI chipset bugs/quirks. Disable this only if your target machine is unaffected by PCI @@ -67,7 +66,7 @@ config PCI_QUIRKS config PCI_DEBUG bool "PCI Debugging" - depends on PCI && DEBUG_KERNEL + depends on DEBUG_KERNEL help Say Y here if you want the PCI core to produce a bunch of debug messages to the system log. Select this if you are having a @@ -77,7 +76,6 @@ config PCI_DEBUG config PCI_REALLOC_ENABLE_AUTO bool "Enable PCI resource re-allocation detection" - depends on PCI depends on PCI_IOV help Say Y here if you want the PCI core to detect if PCI resource @@ -90,7 +88,6 @@ config PCI_REALLOC_ENABLE_AUTO config PCI_STUB tristate "PCI Stub driver" - depends on PCI help Say Y or M here if you want be able to reserve a PCI device when it is going to be assigned to a guest operating system. @@ -99,7 +96,6 @@ config PCI_STUB config PCI_PF_STUB tristate "PCI PF Stub driver" - depends on PCI depends on PCI_IOV help Say Y or M here if you want to enable support for devices that @@ -111,7 +107,7 @@ config PCI_PF_STUB config XEN_PCIDEV_FRONTEND tristate "Xen PCI Frontend" - depends on PCI && X86 && XEN + depends on X86 && XEN select PCI_XEN select XEN_XENBUS_FRONTEND default y @@ -133,7 +129,6 @@ config PCI_BRIDGE_EMUL config PCI_IOV bool "PCI IOV support" - depends on PCI select PCI_ATS help I/O Virtualization is a PCI feature supported by some devices @@ -144,7 +139,6 @@ config PCI_IOV config PCI_PRI bool "PCI PRI support" - depends on PCI select PCI_ATS help PRI is the PCI Page Request Interface. It allows PCI devices that are @@ -154,7 +148,6 @@ config PCI_PRI config PCI_PASID bool "PCI PASID support" - depends on PCI select PCI_ATS help Process Address Space Identifiers (PASIDs) can be used by PCI devices @@ -167,7 +160,7 @@ config PCI_PASID config PCI_P2PDMA bool "PCI peer-to-peer transfer support" - depends on PCI && ZONE_DEVICE + depends on ZONE_DEVICE select GENERIC_ALLOCATOR help Enableѕ drivers to do PCI peer-to-peer transactions to and from @@ -184,12 +177,11 @@ config PCI_P2PDMA config PCI_LABEL def_bool y if (DMI || ACPI) - depends on PCI select NLS config PCI_HYPERV tristate "Hyper-V PCI Frontend" - depends on PCI && X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64 + depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64 help The PCI device frontend driver allows the kernel to import arbitrary PCI devices from a PCI backend to support PCI driver domains. @@ -198,3 +190,5 @@ source "drivers/pci/hotplug/Kconfig" source "drivers/pci/controller/Kconfig" source "drivers/pci/endpoint/Kconfig" source "drivers/pci/switch/Kconfig" + +endif -- cgit v1.2.3-58-ga151 From d77651a227f8920dd7ec179b84e400cce844eeb3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 14 Jan 2019 13:54:55 -0800 Subject: Input: uinput - fix undefined behavior in uinput_validate_absinfo() An integer overflow may arise in uinput_validate_absinfo() if "max - min" can't be represented by an "int". We should check for overflow before trying to use the result. Reported-by: Kyungtae Kim Reviewed-by: Peter Hutterer Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 8ec483e8688b..26ec603fe220 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "../input-compat.h" @@ -405,7 +406,7 @@ static int uinput_open(struct inode *inode, struct file *file) static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code, const struct input_absinfo *abs) { - int min, max; + int min, max, range; min = abs->minimum; max = abs->maximum; @@ -417,7 +418,7 @@ static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code, return -EINVAL; } - if (abs->flat > max - min) { + if (!check_sub_overflow(max, min, &range) && abs->flat > range) { printk(KERN_DEBUG "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n", UINPUT_NAME, code, abs->flat, min, max); -- cgit v1.2.3-58-ga151 From b89a07c4373b27321b1f6d4b4fdc369fd45ef79d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 3 Jan 2019 17:08:03 +0100 Subject: virtio: fix virtio_config_ops description - get_features has returned 64 bits since commit d025477368792 ("virtio: add support for 64 bit features.") - properly mark all optional callbacks Signed-off-by: Cornelia Huck Signed-off-by: Michael S. Tsirkin Reviewed-by: Halil Pasic --- include/linux/virtio_config.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 32baf8e26735..7087ef946ba7 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -22,7 +22,7 @@ struct irq_affinity; * offset: the offset of the configuration field * buf: the buffer to read the field value from. * len: the length of the buffer - * @generation: config generation counter + * @generation: config generation counter (optional) * vdev: the virtio_device * Returns the config generation counter * @get_status: read the status byte @@ -48,17 +48,17 @@ struct irq_affinity; * @del_vqs: free virtqueues found by find_vqs(). * @get_features: get the array of feature bits for this device. * vdev: the virtio_device - * Returns the first 32 feature bits (all we currently need). + * Returns the first 64 feature bits (all we currently need). * @finalize_features: confirm what device features we'll be using. * vdev: the virtio_device * This gives the final feature bits for the device: it can change * the dev->feature bits if it wants. * Returns 0 on success or error status - * @bus_name: return the bus name associated with the device + * @bus_name: return the bus name associated with the device (optional) * vdev: the virtio_device * This returns a pointer to the bus name a la pci_name from which * the caller can then copy. - * @set_vq_affinity: set the affinity for a virtqueue. + * @set_vq_affinity: set the affinity for a virtqueue (optional). * @get_vq_affinity: get the affinity for a virtqueue (optional). */ typedef void vq_callback_t(struct virtqueue *); -- cgit v1.2.3-58-ga151 From d1c1dad89e7a8be2cfdc7b92deca2c8048f0d263 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 3 Jan 2019 17:08:04 +0100 Subject: virtio: document virtio_config_ops restrictions Some transports (e.g. virtio-ccw) implement virtio operations that seem to be a simple read/write as something more involved that cannot be done from an atomic context. Give at least a hint about that. Signed-off-by: Cornelia Huck Signed-off-by: Michael S. Tsirkin --- include/linux/virtio_config.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 7087ef946ba7..987b6491b946 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -12,6 +12,11 @@ struct irq_affinity; /** * virtio_config_ops - operations for configuring a virtio device + * Note: Do not assume that a transport implements all of the operations + * getting/setting a value as a simple read/write! Generally speaking, + * any of @get/@set, @get_status/@set_status, or @get_features/ + * @finalize_features are NOT safe to be called from an atomic + * context. * @get: read the value of a configuration field * vdev: the virtio_device * offset: the offset of the configuration field -- cgit v1.2.3-58-ga151 From ddbeac07a39a81d82331a312d0578fab94fccbf1 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Fri, 28 Dec 2018 10:26:25 +0800 Subject: virtio_pci: use queue idx instead of array idx to set up the vq When find_vqs, there will be no vq[i] allocation if its corresponding names[i] is NULL. For example, the caller may pass in names[i] (i=4) with names[2] being NULL because the related feature bit is turned off, so technically there are 3 queues on the device, and name[4] should correspond to the 3rd queue on the device. So we use queue_idx as the queue index, which is increased only when the queue exists. Signed-off-by: Wei Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Wei Wang Signed-off-by: Wei Wang --- drivers/virtio/virtio_pci_common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 465a6f5142cc..d0584c040c60 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -285,7 +285,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, { struct virtio_pci_device *vp_dev = to_vp_device(vdev); u16 msix_vec; - int i, err, nvectors, allocated_vectors; + int i, err, nvectors, allocated_vectors, queue_idx = 0; vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL); if (!vp_dev->vqs) @@ -321,7 +321,7 @@ static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, msix_vec = allocated_vectors++; else msix_vec = VP_MSIX_VQ_VECTOR; - vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i], + vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i], ctx ? ctx[i] : false, msix_vec); if (IS_ERR(vqs[i])) { @@ -356,7 +356,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs, const char * const names[], const bool *ctx) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); - int i, err; + int i, err, queue_idx = 0; vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL); if (!vp_dev->vqs) @@ -374,7 +374,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs, vqs[i] = NULL; continue; } - vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i], + vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i], ctx ? ctx[i] : false, VIRTIO_MSI_NO_VECTOR); if (IS_ERR(vqs[i])) { -- cgit v1.2.3-58-ga151 From a229989d975eb926076307c1f2f5e4c6111768e7 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Fri, 28 Dec 2018 10:26:26 +0800 Subject: virtio: don't allocate vqs when names[i] = NULL Some vqs may not need to be allocated when their related feature bits are disabled. So callers may pass in such vqs with "names = NULL". Then we skip such vq allocations. Signed-off-by: Wei Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Wei Wang Signed-off-by: Wei Wang Reviewed-by: Cornelia Huck Cc: stable@vger.kernel.org Fixes: 86a559787e6f ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT") --- drivers/misc/mic/vop/vop_main.c | 9 +++++++-- drivers/remoteproc/remoteproc_virtio.c | 9 +++++++-- drivers/s390/virtio/virtio_ccw.c | 12 +++++++++--- drivers/virtio/virtio_mmio.c | 9 +++++++-- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/misc/mic/vop/vop_main.c b/drivers/misc/mic/vop/vop_main.c index 6b212c8b78e7..2bfa3a903bf9 100644 --- a/drivers/misc/mic/vop/vop_main.c +++ b/drivers/misc/mic/vop/vop_main.c @@ -394,16 +394,21 @@ static int vop_find_vqs(struct virtio_device *dev, unsigned nvqs, struct _vop_vdev *vdev = to_vopvdev(dev); struct vop_device *vpdev = vdev->vpdev; struct mic_device_ctrl __iomem *dc = vdev->dc; - int i, err, retry; + int i, err, retry, queue_idx = 0; /* We must have this many virtqueues. */ if (nvqs > ioread8(&vdev->desc->num_vq)) return -ENOENT; for (i = 0; i < nvqs; ++i) { + if (!names[i]) { + vqs[i] = NULL; + continue; + } + dev_dbg(_vop_dev(vdev), "%s: %d: %s\n", __func__, i, names[i]); - vqs[i] = vop_find_vq(dev, i, callbacks[i], names[i], + vqs[i] = vop_find_vq(dev, queue_idx++, callbacks[i], names[i], ctx ? ctx[i] : false); if (IS_ERR(vqs[i])) { err = PTR_ERR(vqs[i]); diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index 183fc42a510a..2d7cd344f3bf 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -153,10 +153,15 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned int nvqs, const bool * ctx, struct irq_affinity *desc) { - int i, ret; + int i, ret, queue_idx = 0; for (i = 0; i < nvqs; ++i) { - vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i], + if (!names[i]) { + vqs[i] = NULL; + continue; + } + + vqs[i] = rp_find_vq(vdev, queue_idx++, callbacks[i], names[i], ctx ? ctx[i] : false); if (IS_ERR(vqs[i])) { ret = PTR_ERR(vqs[i]); diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index fc9dbad476c0..ae1d56da671d 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -635,7 +635,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, { struct virtio_ccw_device *vcdev = to_vc_device(vdev); unsigned long *indicatorp = NULL; - int ret, i; + int ret, i, queue_idx = 0; struct ccw1 *ccw; ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); @@ -643,8 +643,14 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, return -ENOMEM; for (i = 0; i < nvqs; ++i) { - vqs[i] = virtio_ccw_setup_vq(vdev, i, callbacks[i], names[i], - ctx ? ctx[i] : false, ccw); + if (!names[i]) { + vqs[i] = NULL; + continue; + } + + vqs[i] = virtio_ccw_setup_vq(vdev, queue_idx++, callbacks[i], + names[i], ctx ? ctx[i] : false, + ccw); if (IS_ERR(vqs[i])) { ret = PTR_ERR(vqs[i]); vqs[i] = NULL; diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 4cd9ea5c75be..d9dd0f789279 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -468,7 +468,7 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs, { struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); unsigned int irq = platform_get_irq(vm_dev->pdev, 0); - int i, err; + int i, err, queue_idx = 0; err = request_irq(irq, vm_interrupt, IRQF_SHARED, dev_name(&vdev->dev), vm_dev); @@ -476,7 +476,12 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs, return err; for (i = 0; i < nvqs; ++i) { - vqs[i] = vm_setup_vq(vdev, i, callbacks[i], names[i], + if (!names[i]) { + vqs[i] = NULL; + continue; + } + + vqs[i] = vm_setup_vq(vdev, queue_idx++, callbacks[i], names[i], ctx ? ctx[i] : false); if (IS_ERR(vqs[i])) { vm_del_vqs(vdev); -- cgit v1.2.3-58-ga151 From bf4dc0b2beebfd9338df7c0bcf473b356f67cf66 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Mon, 7 Jan 2019 15:01:04 +0800 Subject: virtio-balloon: tweak config_changed implementation virtio-ccw has deadlock issues with reading the config space inside the interrupt context, so we tweak the virtballoon_changed implementation by moving the config read operations into the related workqueue contexts. The config_read_bitmap is used as a flag to the workqueue callbacks about the related config fields that need to be read. The cmd_id_received is also renamed to cmd_id_received_cache, and the value should be obtained via virtio_balloon_cmd_id_received. Reported-by: Christian Borntraeger Signed-off-by: Wei Wang Reviewed-by: Cornelia Huck Reviewed-by: Halil Pasic Signed-off-by: Michael S. Tsirkin Cc: stable@vger.kernel.org Fixes: 86a559787e6f ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT") Tested-by: Christian Borntraeger --- drivers/virtio/virtio_balloon.c | 98 +++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 33 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 728ecd1eea30..fb12fe205f86 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -61,6 +61,10 @@ enum virtio_balloon_vq { VIRTIO_BALLOON_VQ_MAX }; +enum virtio_balloon_config_read { + VIRTIO_BALLOON_CONFIG_READ_CMD_ID = 0, +}; + struct virtio_balloon { struct virtio_device *vdev; struct virtqueue *inflate_vq, *deflate_vq, *stats_vq, *free_page_vq; @@ -77,14 +81,20 @@ struct virtio_balloon { /* Prevent updating balloon when it is being canceled. */ spinlock_t stop_update_lock; bool stop_update; + /* Bitmap to indicate if reading the related config fields are needed */ + unsigned long config_read_bitmap; /* The list of allocated free pages, waiting to be given back to mm */ struct list_head free_page_list; spinlock_t free_page_list_lock; /* The number of free page blocks on the above list */ unsigned long num_free_page_blocks; - /* The cmd id received from host */ - u32 cmd_id_received; + /* + * The cmd id received from host. + * Read it via virtio_balloon_cmd_id_received to get the latest value + * sent from host. + */ + u32 cmd_id_received_cache; /* The cmd id that is actively in use */ __virtio32 cmd_id_active; /* Buffer to store the stop sign */ @@ -390,37 +400,31 @@ static unsigned long return_free_pages_to_mm(struct virtio_balloon *vb, return num_returned; } +static void virtio_balloon_queue_free_page_work(struct virtio_balloon *vb) +{ + if (!virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) + return; + + /* No need to queue the work if the bit was already set. */ + if (test_and_set_bit(VIRTIO_BALLOON_CONFIG_READ_CMD_ID, + &vb->config_read_bitmap)) + return; + + queue_work(vb->balloon_wq, &vb->report_free_page_work); +} + static void virtballoon_changed(struct virtio_device *vdev) { struct virtio_balloon *vb = vdev->priv; unsigned long flags; - s64 diff = towards_target(vb); - - if (diff) { - spin_lock_irqsave(&vb->stop_update_lock, flags); - if (!vb->stop_update) - queue_work(system_freezable_wq, - &vb->update_balloon_size_work); - spin_unlock_irqrestore(&vb->stop_update_lock, flags); - } - if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) { - virtio_cread(vdev, struct virtio_balloon_config, - free_page_report_cmd_id, &vb->cmd_id_received); - if (vb->cmd_id_received == VIRTIO_BALLOON_CMD_ID_DONE) { - /* Pass ULONG_MAX to give back all the free pages */ - return_free_pages_to_mm(vb, ULONG_MAX); - } else if (vb->cmd_id_received != VIRTIO_BALLOON_CMD_ID_STOP && - vb->cmd_id_received != - virtio32_to_cpu(vdev, vb->cmd_id_active)) { - spin_lock_irqsave(&vb->stop_update_lock, flags); - if (!vb->stop_update) { - queue_work(vb->balloon_wq, - &vb->report_free_page_work); - } - spin_unlock_irqrestore(&vb->stop_update_lock, flags); - } + spin_lock_irqsave(&vb->stop_update_lock, flags); + if (!vb->stop_update) { + queue_work(system_freezable_wq, + &vb->update_balloon_size_work); + virtio_balloon_queue_free_page_work(vb); } + spin_unlock_irqrestore(&vb->stop_update_lock, flags); } static void update_balloon_size(struct virtio_balloon *vb) @@ -527,6 +531,17 @@ static int init_vqs(struct virtio_balloon *vb) return 0; } +static u32 virtio_balloon_cmd_id_received(struct virtio_balloon *vb) +{ + if (test_and_clear_bit(VIRTIO_BALLOON_CONFIG_READ_CMD_ID, + &vb->config_read_bitmap)) + virtio_cread(vb->vdev, struct virtio_balloon_config, + free_page_report_cmd_id, + &vb->cmd_id_received_cache); + + return vb->cmd_id_received_cache; +} + static int send_cmd_id_start(struct virtio_balloon *vb) { struct scatterlist sg; @@ -537,7 +552,8 @@ static int send_cmd_id_start(struct virtio_balloon *vb) while (virtqueue_get_buf(vq, &unused)) ; - vb->cmd_id_active = cpu_to_virtio32(vb->vdev, vb->cmd_id_received); + vb->cmd_id_active = virtio32_to_cpu(vb->vdev, + virtio_balloon_cmd_id_received(vb)); sg_init_one(&sg, &vb->cmd_id_active, sizeof(vb->cmd_id_active)); err = virtqueue_add_outbuf(vq, &sg, 1, &vb->cmd_id_active, GFP_KERNEL); if (!err) @@ -620,7 +636,8 @@ static int send_free_pages(struct virtio_balloon *vb) * stop the reporting. */ cmd_id_active = virtio32_to_cpu(vb->vdev, vb->cmd_id_active); - if (cmd_id_active != vb->cmd_id_received) + if (unlikely(cmd_id_active != + virtio_balloon_cmd_id_received(vb))) break; /* @@ -637,11 +654,9 @@ static int send_free_pages(struct virtio_balloon *vb) return 0; } -static void report_free_page_func(struct work_struct *work) +static void virtio_balloon_report_free_page(struct virtio_balloon *vb) { int err; - struct virtio_balloon *vb = container_of(work, struct virtio_balloon, - report_free_page_work); struct device *dev = &vb->vdev->dev; /* Start by sending the received cmd id to host with an outbuf. */ @@ -659,6 +674,23 @@ static void report_free_page_func(struct work_struct *work) dev_err(dev, "Failed to send a stop id, err = %d\n", err); } +static void report_free_page_func(struct work_struct *work) +{ + struct virtio_balloon *vb = container_of(work, struct virtio_balloon, + report_free_page_work); + u32 cmd_id_received; + + cmd_id_received = virtio_balloon_cmd_id_received(vb); + if (cmd_id_received == VIRTIO_BALLOON_CMD_ID_DONE) { + /* Pass ULONG_MAX to give back all the free pages */ + return_free_pages_to_mm(vb, ULONG_MAX); + } else if (cmd_id_received != VIRTIO_BALLOON_CMD_ID_STOP && + cmd_id_received != + virtio32_to_cpu(vb->vdev, vb->cmd_id_active)) { + virtio_balloon_report_free_page(vb); + } +} + #ifdef CONFIG_BALLOON_COMPACTION /* * virtballoon_migratepage - perform the balloon page migration on behalf of @@ -885,7 +917,7 @@ static int virtballoon_probe(struct virtio_device *vdev) goto out_del_vqs; } INIT_WORK(&vb->report_free_page_work, report_free_page_func); - vb->cmd_id_received = VIRTIO_BALLOON_CMD_ID_STOP; + vb->cmd_id_received_cache = VIRTIO_BALLOON_CMD_ID_STOP; vb->cmd_id_active = cpu_to_virtio32(vb->vdev, VIRTIO_BALLOON_CMD_ID_STOP); vb->cmd_id_stop = cpu_to_virtio32(vb->vdev, -- cgit v1.2.3-58-ga151 From 74ad7419489ddade8044e3c9ab064ad656520306 Mon Sep 17 00:00:00 2001 From: Pavel Tikhomirov Date: Thu, 13 Dec 2018 17:53:50 +0300 Subject: vhost: return EINVAL if iovecs size does not match the message size We've failed to copy and process vhost_iotlb_msg so let userspace at least know about it. For instance before these patch the code below runs without any error: int main() { struct vhost_msg msg; struct iovec iov; int fd; fd = open("/dev/vhost-net", O_RDWR); if (fd == -1) { perror("open"); return 1; } iov.iov_base = &msg; iov.iov_len = sizeof(msg)-4; if (writev(fd, &iov,1) == -1) { perror("writev"); return 1; } return 0; } Signed-off-by: Pavel Tikhomirov Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 9f7942cbcbb2..bac939af8dbb 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1034,8 +1034,10 @@ ssize_t vhost_chr_write_iter(struct vhost_dev *dev, int type, ret; ret = copy_from_iter(&type, sizeof(type), from); - if (ret != sizeof(type)) + if (ret != sizeof(type)) { + ret = -EINVAL; goto done; + } switch (type) { case VHOST_IOTLB_MSG: @@ -1054,8 +1056,10 @@ ssize_t vhost_chr_write_iter(struct vhost_dev *dev, iov_iter_advance(from, offset); ret = copy_from_iter(&msg, sizeof(msg), from); - if (ret != sizeof(msg)) + if (ret != sizeof(msg)) { + ret = -EINVAL; goto done; + } if (vhost_process_iotlb_msg(dev, &msg)) { ret = -EFAULT; goto done; -- cgit v1.2.3-58-ga151 From 8e5dadfe76cf2862ebf3e4f22adef29982df7766 Mon Sep 17 00:00:00 2001 From: Bijan Mottahedeh Date: Mon, 3 Dec 2018 16:48:23 -0800 Subject: vhost/scsi: Use copy_to_iter() to send control queue response Uses copy_to_iter() instead of __copy_to_user() in order to ensure we support arbitrary layouts and an input buffer split across iov entries. Fixes: 0d02dbd68c47b ("vhost/scsi: Respond to control queue operations") Signed-off-by: Bijan Mottahedeh Signed-off-by: Michael S. Tsirkin --- drivers/vhost/scsi.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 8e10ab436d1f..344684f3e2e4 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1127,16 +1127,18 @@ vhost_scsi_send_tmf_reject(struct vhost_scsi *vs, struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc) { - struct virtio_scsi_ctrl_tmf_resp __user *resp; struct virtio_scsi_ctrl_tmf_resp rsp; + struct iov_iter iov_iter; int ret; pr_debug("%s\n", __func__); memset(&rsp, 0, sizeof(rsp)); rsp.response = VIRTIO_SCSI_S_FUNCTION_REJECTED; - resp = vq->iov[vc->out].iov_base; - ret = __copy_to_user(resp, &rsp, sizeof(rsp)); - if (!ret) + + iov_iter_init(&iov_iter, READ, &vq->iov[vc->out], vc->in, sizeof(rsp)); + + ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter); + if (likely(ret == sizeof(rsp))) vhost_add_used_and_signal(&vs->dev, vq, vc->head, 0); else pr_err("Faulted on virtio_scsi_ctrl_tmf_resp\n"); @@ -1147,16 +1149,18 @@ vhost_scsi_send_an_resp(struct vhost_scsi *vs, struct vhost_virtqueue *vq, struct vhost_scsi_ctx *vc) { - struct virtio_scsi_ctrl_an_resp __user *resp; struct virtio_scsi_ctrl_an_resp rsp; + struct iov_iter iov_iter; int ret; pr_debug("%s\n", __func__); memset(&rsp, 0, sizeof(rsp)); /* event_actual = 0 */ rsp.response = VIRTIO_SCSI_S_OK; - resp = vq->iov[vc->out].iov_base; - ret = __copy_to_user(resp, &rsp, sizeof(rsp)); - if (!ret) + + iov_iter_init(&iov_iter, READ, &vq->iov[vc->out], vc->in, sizeof(rsp)); + + ret = copy_to_iter(&rsp, sizeof(rsp), &iov_iter); + if (likely(ret == sizeof(rsp))) vhost_add_used_and_signal(&vs->dev, vq, vc->head, 0); else pr_err("Faulted on virtio_scsi_ctrl_an_resp\n"); -- cgit v1.2.3-58-ga151 From fdac94489c4d247088b3885875b39b3e1eb621ef Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 18 Dec 2018 22:34:20 +0100 Subject: selftests: rtc: rtctest: fix alarm tests Return values for select are not checked properly and timeouts may not be detected. Signed-off-by: Alexandre Belloni Signed-off-by: Shuah Khan --- tools/testing/selftests/rtc/rtctest.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/rtc/rtctest.c b/tools/testing/selftests/rtc/rtctest.c index e20b017e7073..dea4e3d6d9e1 100644 --- a/tools/testing/selftests/rtc/rtctest.c +++ b/tools/testing/selftests/rtc/rtctest.c @@ -145,15 +145,12 @@ TEST_F(rtc, alarm_alm_set) { rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); ASSERT_NE(-1, rc); - EXPECT_NE(0, rc); + ASSERT_NE(0, rc); /* Disable alarm interrupts */ rc = ioctl(self->fd, RTC_AIE_OFF, 0); ASSERT_NE(-1, rc); - if (rc == 0) - return; - rc = read(self->fd, &data, sizeof(unsigned long)); ASSERT_NE(-1, rc); TH_LOG("data: %lx", data); @@ -202,7 +199,7 @@ TEST_F(rtc, alarm_wkalm_set) { rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); ASSERT_NE(-1, rc); - EXPECT_NE(0, rc); + ASSERT_NE(0, rc); rc = read(self->fd, &data, sizeof(unsigned long)); ASSERT_NE(-1, rc); -- cgit v1.2.3-58-ga151 From 7b3027728f4d4f6763f4d7e771acfc9424cdd0e6 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 18 Dec 2018 22:34:21 +0100 Subject: selftests: rtc: rtctest: add alarm test on minute boundary Unfortunately, some RTC don't have a second resolution for alarm so also test for alarm on a minute boundary. Signed-off-by: Alexandre Belloni Signed-off-by: Shuah Khan --- tools/testing/selftests/rtc/rtctest.c | 102 ++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tools/testing/selftests/rtc/rtctest.c b/tools/testing/selftests/rtc/rtctest.c index dea4e3d6d9e1..b2065536d407 100644 --- a/tools/testing/selftests/rtc/rtctest.c +++ b/tools/testing/selftests/rtc/rtctest.c @@ -211,6 +211,108 @@ TEST_F(rtc, alarm_wkalm_set) { ASSERT_EQ(new, secs); } +TEST_F(rtc, alarm_alm_set_minute) { + struct timeval tv = { .tv_sec = 62 }; + unsigned long data; + struct rtc_time tm; + fd_set readfds; + time_t secs, new; + int rc; + + rc = ioctl(self->fd, RTC_RD_TIME, &tm); + ASSERT_NE(-1, rc); + + secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec; + gmtime_r(&secs, (struct tm *)&tm); + + rc = ioctl(self->fd, RTC_ALM_SET, &tm); + if (rc == -1) { + ASSERT_EQ(EINVAL, errno); + TH_LOG("skip alarms are not supported."); + return; + } + + rc = ioctl(self->fd, RTC_ALM_READ, &tm); + ASSERT_NE(-1, rc); + + TH_LOG("Alarm time now set to %02d:%02d:%02d.", + tm.tm_hour, tm.tm_min, tm.tm_sec); + + /* Enable alarm interrupts */ + rc = ioctl(self->fd, RTC_AIE_ON, 0); + ASSERT_NE(-1, rc); + + FD_ZERO(&readfds); + FD_SET(self->fd, &readfds); + + rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); + ASSERT_NE(-1, rc); + ASSERT_NE(0, rc); + + /* Disable alarm interrupts */ + rc = ioctl(self->fd, RTC_AIE_OFF, 0); + ASSERT_NE(-1, rc); + + rc = read(self->fd, &data, sizeof(unsigned long)); + ASSERT_NE(-1, rc); + TH_LOG("data: %lx", data); + + rc = ioctl(self->fd, RTC_RD_TIME, &tm); + ASSERT_NE(-1, rc); + + new = timegm((struct tm *)&tm); + ASSERT_EQ(new, secs); +} + +TEST_F(rtc, alarm_wkalm_set_minute) { + struct timeval tv = { .tv_sec = 62 }; + struct rtc_wkalrm alarm = { 0 }; + struct rtc_time tm; + unsigned long data; + fd_set readfds; + time_t secs, new; + int rc; + + rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time); + ASSERT_NE(-1, rc); + + secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec; + gmtime_r(&secs, (struct tm *)&alarm.time); + + alarm.enabled = 1; + + rc = ioctl(self->fd, RTC_WKALM_SET, &alarm); + if (rc == -1) { + ASSERT_EQ(EINVAL, errno); + TH_LOG("skip alarms are not supported."); + return; + } + + rc = ioctl(self->fd, RTC_WKALM_RD, &alarm); + ASSERT_NE(-1, rc); + + TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.", + alarm.time.tm_mday, alarm.time.tm_mon + 1, + alarm.time.tm_year + 1900, alarm.time.tm_hour, + alarm.time.tm_min, alarm.time.tm_sec); + + FD_ZERO(&readfds); + FD_SET(self->fd, &readfds); + + rc = select(self->fd + 1, &readfds, NULL, NULL, &tv); + ASSERT_NE(-1, rc); + ASSERT_NE(0, rc); + + rc = read(self->fd, &data, sizeof(unsigned long)); + ASSERT_NE(-1, rc); + + rc = ioctl(self->fd, RTC_RD_TIME, &tm); + ASSERT_NE(-1, rc); + + new = timegm((struct tm *)&tm); + ASSERT_EQ(new, secs); +} + static void __attribute__((constructor)) __constructor_order_last(void) { -- cgit v1.2.3-58-ga151 From a180ac19ac19145789faa8ece9a45934822f6a29 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Jan 2019 09:54:03 +0000 Subject: x86/mpx/selftests: fix spelling mistake "succeded" -> "succeeded" There is a spelling mistake eprintf error message, fix it. Signed-off-by: Colin Ian King Signed-off-by: Shuah Khan --- tools/testing/selftests/x86/mpx-mini-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/x86/mpx-mini-test.c b/tools/testing/selftests/x86/mpx-mini-test.c index 50f7e9272481..bf1bb15b6fbe 100644 --- a/tools/testing/selftests/x86/mpx-mini-test.c +++ b/tools/testing/selftests/x86/mpx-mini-test.c @@ -1503,7 +1503,7 @@ exit: exit(20); } if (successes != total_nr_tests) { - eprintf("ERROR: succeded fewer than number of tries (%d != %d)\n", + eprintf("ERROR: succeeded fewer than number of tries (%d != %d)\n", successes, total_nr_tests); exit(21); } -- cgit v1.2.3-58-ga151 From b686057e95075b51939ade6b8c9b478a1011342a Mon Sep 17 00:00:00 2001 From: Sabyasachi Gupta Date: Mon, 14 Jan 2019 17:48:02 +0530 Subject: tools/testing/selftests/x86/unwind_vdso.c: Remove duplicate header Remove sys/ucontext.h which is included more than once. Signed-off-by: Sabyasachi Gupta Signed-off-by: Shuah Khan --- tools/testing/selftests/x86/unwind_vdso.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/testing/selftests/x86/unwind_vdso.c b/tools/testing/selftests/x86/unwind_vdso.c index 00a26a82fa98..97311333700e 100644 --- a/tools/testing/selftests/x86/unwind_vdso.c +++ b/tools/testing/selftests/x86/unwind_vdso.c @@ -44,7 +44,6 @@ int main() #include #include #include -#include #include #include #include -- cgit v1.2.3-58-ga151 From b4fe30e45a660efa8f122070fc7173715d0e1d00 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Tue, 15 Jan 2019 11:09:46 +0800 Subject: acpi/nfit: Remove duplicate set nd_set in acpi_nfit_init_interleave_set() We allocate nd_set in acpi_nfit_init_interleave_set() and assignn it to ndr_desc, while the assignment is done twice in this function. This patch removes the first assignment. No functional change. Signed-off-by: Wei Yang Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 790691d9a982..5143e11e3b0f 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2226,7 +2226,6 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc, nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL); if (!nd_set) return -ENOMEM; - ndr_desc->nd_set = nd_set; guid_copy(&nd_set->type_guid, (guid_t *) spa->range_guid); info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL); -- cgit v1.2.3-58-ga151 From fe76fc6aaf538df27708ffa3e5d549a6c8e16142 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 15 Jan 2019 11:59:52 +0800 Subject: sbitmap: Protect swap_lock from hardirq Because we may call blk_mq_get_driver_tag() directly from blk_mq_dispatch_rq_list() without holding any lock, then HARDIRQ may come and the above DEADLOCK is triggered. Commit ab53dcfb3e7b ("sbitmap: Protect swap_lock from hardirq") tries to fix this issue by using 'spin_lock_bh', which isn't enough because we complete request from hardirq context direclty in case of multiqueue. Cc: Clark Williams Fixes: ab53dcfb3e7b ("sbitmap: Protect swap_lock from hardirq") Cc: Jens Axboe Cc: Ming Lei Cc: Guenter Roeck Cc: Steven Rostedt (VMware) Signed-off-by: Ming Lei Signed-off-by: Linus Torvalds --- lib/sbitmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/sbitmap.c b/lib/sbitmap.c index 864354000e04..5b382c1244ed 100644 --- a/lib/sbitmap.c +++ b/lib/sbitmap.c @@ -27,8 +27,9 @@ static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index) { unsigned long mask, val; bool ret = false; + unsigned long flags; - spin_lock_bh(&sb->map[index].swap_lock); + spin_lock_irqsave(&sb->map[index].swap_lock, flags); if (!sb->map[index].cleared) goto out_unlock; @@ -49,7 +50,7 @@ static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index) ret = true; out_unlock: - spin_unlock_bh(&sb->map[index].swap_lock); + spin_unlock_irqrestore(&sb->map[index].swap_lock, flags); return ret; } -- cgit v1.2.3-58-ga151 From a31e184e4f69965c99c04cc5eb8a4920e0c63737 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 2 Jan 2019 13:56:55 -0800 Subject: x86/pkeys: Properly copy pkey state at fork() Memory protection key behavior should be the same in a child as it was in the parent before a fork. But, there is a bug that resets the state in the child at fork instead of preserving it. The creation of new mm's is a bit convoluted. At fork(), the code does: 1. memcpy() the parent mm to initialize child 2. mm_init() to initalize some select stuff stuff 3. dup_mmap() to create true copies that memcpy() did not do right For pkeys two bits of state need to be preserved across a fork: 'execute_only_pkey' and 'pkey_allocation_map'. Those are preserved by the memcpy(), but mm_init() invokes init_new_context() which overwrites 'execute_only_pkey' and 'pkey_allocation_map' with "new" values. The author of the code erroneously believed that init_new_context is *only* called at execve()-time. But, alas, init_new_context() is used at execve() and fork(). The result is that, after a fork(), the child's pkey state ends up looking like it does after an execve(), which is totally wrong. pkeys that are already allocated can be allocated again, for instance. To fix this, add code called by dup_mmap() to copy the pkey state from parent to child explicitly. Also add a comment above init_new_context() to make it more clear to the next poor sod what this code is used for. Fixes: e8c24d3a23a ("x86/pkeys: Allocation/free syscalls") Signed-off-by: Dave Hansen Signed-off-by: Thomas Gleixner Reviewed-by: Thomas Gleixner Cc: bp@alien8.de Cc: hpa@zytor.com Cc: peterz@infradead.org Cc: mpe@ellerman.id.au Cc: will.deacon@arm.com Cc: luto@kernel.org Cc: jroedel@suse.de Cc: stable@vger.kernel.org Cc: Borislav Petkov Cc: "H. Peter Anvin" Cc: Peter Zijlstra Cc: Michael Ellerman Cc: Will Deacon Cc: Andy Lutomirski Cc: Joerg Roedel Link: https://lkml.kernel.org/r/20190102215655.7A69518C@viggo.jf.intel.com --- arch/x86/include/asm/mmu_context.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index 0ca50611e8ce..19d18fae6ec6 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -178,6 +178,10 @@ static inline void switch_ldt(struct mm_struct *prev, struct mm_struct *next) void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk); +/* + * Init a new mm. Used on mm copies, like at fork() + * and on mm's that are brand-new, like at execve(). + */ static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { @@ -228,8 +232,22 @@ do { \ } while (0) #endif +static inline void arch_dup_pkeys(struct mm_struct *oldmm, + struct mm_struct *mm) +{ +#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS + if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) + return; + + /* Duplicate the oldmm pkey state in mm: */ + mm->context.pkey_allocation_map = oldmm->context.pkey_allocation_map; + mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; +#endif +} + static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) { + arch_dup_pkeys(oldmm, mm); paravirt_arch_dup_mmap(oldmm, mm); return ldt_dup_context(oldmm, mm); } -- cgit v1.2.3-58-ga151 From e1812933b17be7814f51b6c310c5d1ced7a9a5f5 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Wed, 2 Jan 2019 13:56:57 -0800 Subject: x86/selftests/pkeys: Fork() to check for state being preserved There was a bug where the per-mm pkey state was not being preserved across fork() in the child. fork() is performed in the pkey selftests, but all of the pkey activity is performed in the parent. The child does not perform any actions sensitive to pkey state. To make the test more sensitive to these kinds of bugs, add a fork() where the parent exits, and execution continues in the child. To achieve this let the key exhaustion test not terminate at the first allocation failure and fork after 2*NR_PKEYS loops and continue in the child. Signed-off-by: Dave Hansen Signed-off-by: Thomas Gleixner Cc: bp@alien8.de Cc: hpa@zytor.com Cc: peterz@infradead.org Cc: mpe@ellerman.id.au Cc: will.deacon@arm.com Cc: luto@kernel.org Cc: jroedel@suse.de Cc: stable@vger.kernel.org Cc: Borislav Petkov Cc: "H. Peter Anvin" Cc: Peter Zijlstra Cc: Michael Ellerman Cc: Will Deacon Cc: Andy Lutomirski Cc: Joerg Roedel Link: https://lkml.kernel.org/r/20190102215657.585704B7@viggo.jf.intel.com --- tools/testing/selftests/x86/protection_keys.c | 41 ++++++++++++++++++++------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index 460b4bdf4c1e..5d546dcdbc80 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c @@ -1133,6 +1133,21 @@ void test_pkey_syscalls_bad_args(int *ptr, u16 pkey) pkey_assert(err); } +void become_child(void) +{ + pid_t forkret; + + forkret = fork(); + pkey_assert(forkret >= 0); + dprintf3("[%d] fork() ret: %d\n", getpid(), forkret); + + if (!forkret) { + /* in the child */ + return; + } + exit(0); +} + /* Assumes that all pkeys other than 'pkey' are unallocated */ void test_pkey_alloc_exhaust(int *ptr, u16 pkey) { @@ -1141,7 +1156,7 @@ void test_pkey_alloc_exhaust(int *ptr, u16 pkey) int nr_allocated_pkeys = 0; int i; - for (i = 0; i < NR_PKEYS*2; i++) { + for (i = 0; i < NR_PKEYS*3; i++) { int new_pkey; dprintf1("%s() alloc loop: %d\n", __func__, i); new_pkey = alloc_pkey(); @@ -1152,20 +1167,26 @@ void test_pkey_alloc_exhaust(int *ptr, u16 pkey) if ((new_pkey == -1) && (errno == ENOSPC)) { dprintf2("%s() failed to allocate pkey after %d tries\n", __func__, nr_allocated_pkeys); - break; + } else { + /* + * Ensure the number of successes never + * exceeds the number of keys supported + * in the hardware. + */ + pkey_assert(nr_allocated_pkeys < NR_PKEYS); + allocated_pkeys[nr_allocated_pkeys++] = new_pkey; } - pkey_assert(nr_allocated_pkeys < NR_PKEYS); - allocated_pkeys[nr_allocated_pkeys++] = new_pkey; + + /* + * Make sure that allocation state is properly + * preserved across fork(). + */ + if (i == NR_PKEYS*2) + become_child(); } dprintf3("%s()::%d\n", __func__, __LINE__); - /* - * ensure it did not reach the end of the loop without - * failure: - */ - pkey_assert(i < NR_PKEYS*2); - /* * There are 16 pkeys supported in hardware. Three are * allocated by the time we get here: -- cgit v1.2.3-58-ga151 From f29fd331aa055fbeb5a496b4af937b7952111b6b Mon Sep 17 00:00:00 2001 From: Vitor Soares Date: Thu, 10 Jan 2019 16:34:59 +0100 Subject: i3c: master: dw-i3c-master: fix i3c_attach/reattach This patch fix i3c_attach/reattach functions. During the i3c_attach the driver ignores the static address used for SETDASA CCC command. During the i3c_reattach the driver doesn't update master->addrs[data->index] with new address if old_dyn_addr = 0. Fixes: 1dd728f5d4d4 ("i3c: master: Add driver for Synopsys DesignWare IP") Signed-off-by: Vitor Soares Signed-off-by: Boris Brezillon --- drivers/i3c/master/dw-i3c-master.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index b532e2c9cf5c..f8c00b94817f 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -901,9 +901,6 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, master->regs + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); - if (!old_dyn_addr) - return 0; - master->addrs[data->index] = dev->info.dyn_addr; return 0; @@ -925,11 +922,11 @@ static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev) return -ENOMEM; data->index = pos; - master->addrs[pos] = dev->info.dyn_addr; + master->addrs[pos] = dev->info.dyn_addr ? : dev->info.static_addr; master->free_pos &= ~BIT(pos); i3c_dev_set_master_data(dev, data); - writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr), + writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->addrs[pos]), master->regs + DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index)); -- cgit v1.2.3-58-ga151 From bddda606ec76550dd63592e32a6e87e7d32583f7 Mon Sep 17 00:00:00 2001 From: Srinivas Ramana Date: Thu, 20 Dec 2018 19:05:57 +0530 Subject: genirq: Make sure the initial affinity is not empty If all CPUs in the irq_default_affinity mask are offline when an interrupt is initialized then irq_setup_affinity() can set an empty affinity mask for a newly allocated interrupt. Fix this by falling back to cpu_online_mask in case the resulting affinity mask is zero. Signed-off-by: Srinivas Ramana Signed-off-by: Thomas Gleixner Cc: linux-arm-msm@vger.kernel.org Link: https://lkml.kernel.org/r/1545312957-8504-1-git-send-email-sramana@codeaurora.org --- kernel/irq/manage.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index a4888ce4667a..84b54a17b95d 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -393,6 +393,9 @@ int irq_setup_affinity(struct irq_desc *desc) } cpumask_and(&mask, cpu_online_mask, set); + if (cpumask_empty(&mask)) + cpumask_copy(&mask, cpu_online_mask); + if (node != NUMA_NO_NODE) { const struct cpumask *nodemask = cpumask_of_node(node); -- cgit v1.2.3-58-ga151 From da727097a482a93645ba5beea8d389ebab11fc64 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 14 Jan 2019 16:47:45 -0800 Subject: powerpc/pseries: Fix build break due to pnv_npu2_init() Commit 3be2df00e299 ("powerpc/pseries/npu: Enable platform support") added a call to pnv_npu2_init() in pseries code. This causes a build break if we build with CONFIG_PPC_PSERIES && !CONFIG_PPC_POWERNV: powerpc64le-pc-linux-gnu-ld: arch/powerpc/platforms/pseries/pci.o: in function `pSeries_final_fixup': pci.c:(.init.text+0x1b0): undefined reference to `pnv_npu2_init' This commit therefore wraps that line in an ifdef, so that pseries builds without powernv. Fixes: 3be2df00e299 ("powerpc/pseries/npu: Enable platform support") Signed-off-by: Jason A. Donenfeld Reviewed-by: Alexey Kardashevskiy [mpe: Frob change log a bit to blame a different commit] Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 7725825d887d..37a77e57893e 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -264,7 +264,9 @@ void __init pSeries_final_fixup(void) if (!of_device_is_compatible(nvdn->parent, "ibm,power9-npu")) continue; +#ifdef CONFIG_PPC_POWERNV WARN_ON_ONCE(pnv_npu2_init(hose)); +#endif break; } } -- cgit v1.2.3-58-ga151 From 6c2d0f9976ad19eca6d03dad5d726f8eff848b70 Mon Sep 17 00:00:00 2001 From: Hang Yuan Date: Mon, 14 Jan 2019 18:43:39 +0800 Subject: drm/i915/gvt: free VFIO region space in vgpu detach VFIO region space is allocated when one region is registered for one vgpu. So free the space when destroy the vgpu. Also change the parameter of detach_vgpu callback to use vgpu directly. Fixes: b851adeac0858c7d257b3 ("drm/i915/gvt: Add opregion support") Reviewed-by: Zhenyu Wang Signed-off-by: Hang Yuan Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/hypercall.h | 2 +- drivers/gpu/drm/i915/gvt/kvmgt.c | 16 ++++++++++++++-- drivers/gpu/drm/i915/gvt/mpt.h | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h index 5af11cf1b482..e1675a00df12 100644 --- a/drivers/gpu/drm/i915/gvt/hypercall.h +++ b/drivers/gpu/drm/i915/gvt/hypercall.h @@ -41,7 +41,7 @@ struct intel_gvt_mpt { int (*host_init)(struct device *dev, void *gvt, const void *ops); void (*host_exit)(struct device *dev, void *gvt); int (*attach_vgpu)(void *vgpu, unsigned long *handle); - void (*detach_vgpu)(unsigned long handle); + void (*detach_vgpu)(void *vgpu); int (*inject_msi)(unsigned long handle, u32 addr, u16 data); unsigned long (*from_virt_to_mfn)(void *p); int (*enable_page_track)(unsigned long handle, u64 gfn); diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index c1072143da1d..a3ee6b7c3cfc 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -1662,9 +1662,21 @@ static int kvmgt_attach_vgpu(void *vgpu, unsigned long *handle) return 0; } -static void kvmgt_detach_vgpu(unsigned long handle) +static void kvmgt_detach_vgpu(void *p_vgpu) { - /* nothing to do here */ + int i; + struct intel_vgpu *vgpu = (struct intel_vgpu *)p_vgpu; + + if (!vgpu->vdev.region) + return; + + for (i = 0; i < vgpu->vdev.num_regions; i++) + if (vgpu->vdev.region[i].ops->release) + vgpu->vdev.region[i].ops->release(vgpu, + &vgpu->vdev.region[i]); + vgpu->vdev.num_regions = 0; + kfree(vgpu->vdev.region); + vgpu->vdev.region = NULL; } static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data) diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h index 67f19992b226..3ed34123d8d1 100644 --- a/drivers/gpu/drm/i915/gvt/mpt.h +++ b/drivers/gpu/drm/i915/gvt/mpt.h @@ -101,7 +101,7 @@ static inline void intel_gvt_hypervisor_detach_vgpu(struct intel_vgpu *vgpu) if (!intel_gvt_host.mpt->detach_vgpu) return; - intel_gvt_host.mpt->detach_vgpu(vgpu->handle); + intel_gvt_host.mpt->detach_vgpu(vgpu); } #define MSI_CAP_CONTROL(offset) (offset + 2) -- cgit v1.2.3-58-ga151 From 7bea7ac0ca0121798f3618d16201ca4dc4e67a00 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 15 Jan 2019 17:37:28 +1100 Subject: powerpc/syscalls: Fix syscall tracing Recently in commit fbf508da7440 ("powerpc: split compat syscall table out from native table") we changed the layout of the system call table. Instead of having two entries for each syscall number, one for the regular entry point and one for the compat entry point, we now have separate tables for regular and compat entry points. This inadvertently broke syscall tracing (CONFIG_FTRACE_SYSCALLS), because our implementation of arch_syscall_addr() knew about the layout of the table (it did nr * 2). We can fix it just by dropping our version of arch_syscall_addr() and using the generic version which does: return (unsigned long)sys_call_table[nr]; Fixes: fbf508da7440 ("powerpc: split compat syscall table out from native table") Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/trace/ftrace.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c index 29746dc28df5..517662a56bdc 100644 --- a/arch/powerpc/kernel/trace/ftrace.c +++ b/arch/powerpc/kernel/trace/ftrace.c @@ -967,13 +967,6 @@ out: } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64) -unsigned long __init arch_syscall_addr(int nr) -{ - return sys_call_table[nr*2]; -} -#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 */ - #ifdef PPC64_ELF_ABI_v1 char *arch_ftrace_match_adjust(char *str, const char *search) { -- cgit v1.2.3-58-ga151 From bf7d28c53453ea904584960de55e33e03b9d93b1 Mon Sep 17 00:00:00 2001 From: Peng Hao Date: Sat, 29 Dec 2018 14:34:12 +0800 Subject: x86/mm/mem_encrypt: Fix erroneous sizeof() Using sizeof(pointer) for determining the size of a memset() only works when the size of the pointer and the size of type to which it points are the same. For pte_t this is only true for 64bit and 32bit-NONPAE. On 32bit PAE systems this is wrong as the pointer size is 4 byte but the PTE entry is 8 bytes. It's actually not a real world issue as this code depends on 64bit, but it's wrong nevertheless. Use sizeof(*p) for correctness sake. Fixes: aad983913d77 ("x86/mm/encrypt: Simplify sme_populate_pgd() and sme_populate_pgd_large()") Signed-off-by: Peng Hao Signed-off-by: Thomas Gleixner Cc: Kirill A. Shutemov Cc: Tom Lendacky Cc: dave.hansen@linux.intel.com Cc: peterz@infradead.org Cc: luto@kernel.org Link: https://lkml.kernel.org/r/1546065252-97996-1-git-send-email-peng.hao2@zte.com.cn --- arch/x86/mm/mem_encrypt_identity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/mem_encrypt_identity.c b/arch/x86/mm/mem_encrypt_identity.c index a19ef1a416ff..4aa9b1480866 100644 --- a/arch/x86/mm/mem_encrypt_identity.c +++ b/arch/x86/mm/mem_encrypt_identity.c @@ -158,8 +158,8 @@ static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd) pmd = pmd_offset(pud, ppd->vaddr); if (pmd_none(*pmd)) { pte = ppd->pgtable_area; - memset(pte, 0, sizeof(pte) * PTRS_PER_PTE); - ppd->pgtable_area += sizeof(pte) * PTRS_PER_PTE; + memset(pte, 0, sizeof(*pte) * PTRS_PER_PTE); + ppd->pgtable_area += sizeof(*pte) * PTRS_PER_PTE; set_pmd(pmd, __pmd(PMD_FLAGS | __pa(pte))); } -- cgit v1.2.3-58-ga151 From 51b00d8509dc69c98740da2ad07308b630d3eb7d Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Fri, 11 Jan 2019 13:58:53 +0800 Subject: drm/i915/gvt: Fix mmap range check This is to fix missed mmap range check on vGPU bar2 region and only allow to map vGPU allocated GMADDR range, which means user space should support sparse mmap to get proper offset for mmap vGPU aperture. And this takes care of actual pgoff in mmap request as original code always does from beginning of vGPU aperture. Fixes: 659643f7d814 ("drm/i915/gvt/kvmgt: add vfio/mdev support to KVMGT") Cc: "Monroy, Rodrigo Axel" Cc: "Orrala Contreras, Alfredo" Cc: stable@vger.kernel.org # v4.10+ Reviewed-by: Hang Yuan Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/kvmgt.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index a3ee6b7c3cfc..dd3dfd00f4e6 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -996,7 +996,7 @@ static int intel_vgpu_mmap(struct mdev_device *mdev, struct vm_area_struct *vma) { unsigned int index; u64 virtaddr; - unsigned long req_size, pgoff = 0; + unsigned long req_size, pgoff, req_start; pgprot_t pg_prot; struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); @@ -1014,7 +1014,17 @@ static int intel_vgpu_mmap(struct mdev_device *mdev, struct vm_area_struct *vma) pg_prot = vma->vm_page_prot; virtaddr = vma->vm_start; req_size = vma->vm_end - vma->vm_start; - pgoff = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT; + pgoff = vma->vm_pgoff & + ((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1); + req_start = pgoff << PAGE_SHIFT; + + if (!intel_vgpu_in_aperture(vgpu, req_start)) + return -EINVAL; + if (req_start + req_size > + vgpu_aperture_offset(vgpu) + vgpu_aperture_sz(vgpu)) + return -EINVAL; + + pgoff = (gvt_aperture_pa_base(vgpu->gvt) >> PAGE_SHIFT) + pgoff; return remap_pfn_range(vma, virtaddr, pgoff, req_size, pg_prot); } -- cgit v1.2.3-58-ga151 From 993a110319a4a60aadbd02f6defdebe048f7773b Mon Sep 17 00:00:00 2001 From: Dave Young Date: Fri, 28 Dec 2018 09:12:47 +0800 Subject: x86/kexec: Fix a kexec_file_load() failure Commit b6664ba42f14 ("s390, kexec_file: drop arch_kexec_mem_walk()") changed the behavior of kexec_locate_mem_hole(): it will try to allocate free memory only when kbuf.mem is initialized to zero. However, x86's kexec_file_load() implementation reuses a struct kexec_buf allocated on the stack and its kbuf.mem member gets set by each kexec_add_buffer() invocation. The second kexec_add_buffer() will reuse the same kbuf but not reinitialize kbuf.mem. Therefore, explictily reset kbuf.mem each time in order for kexec_locate_mem_hole() to locate a free memory region each time. [ bp: massage commit message. ] Fixes: b6664ba42f14 ("s390, kexec_file: drop arch_kexec_mem_walk()") Signed-off-by: Dave Young Signed-off-by: Borislav Petkov Acked-by: Baoquan He Cc: "Eric W. Biederman" Cc: "H. Peter Anvin" Cc: AKASHI Takahiro Cc: Andrew Morton Cc: Ingo Molnar Cc: Martin Schwidefsky Cc: Philipp Rudo Cc: Thomas Gleixner Cc: Vivek Goyal Cc: Yannik Sembritzki Cc: Yi Wang Cc: kexec@lists.infradead.org Cc: x86-ml Link: https://lkml.kernel.org/r/20181228011247.GA9999@dhcp-128-65.nay.redhat.com --- arch/x86/kernel/crash.c | 1 + arch/x86/kernel/kexec-bzimage64.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index c8b07d8ea5a2..17ffc869cab8 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -470,6 +470,7 @@ int crash_load_segments(struct kimage *image) kbuf.memsz = kbuf.bufsz; kbuf.buf_align = ELF_CORE_HEADER_ALIGN; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; ret = kexec_add_buffer(&kbuf); if (ret) { vfree((void *)image->arch.elf_headers); diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index 278cd07228dd..0d5efa34f359 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c @@ -434,6 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, kbuf.memsz = PAGE_ALIGN(header->init_size); kbuf.buf_align = header->kernel_alignment; kbuf.buf_min = MIN_KERNEL_LOAD_ADDR; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; ret = kexec_add_buffer(&kbuf); if (ret) goto out_free_params; @@ -448,6 +449,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, kbuf.bufsz = kbuf.memsz = initrd_len; kbuf.buf_align = PAGE_SIZE; kbuf.buf_min = MIN_INITRD_LOAD_ADDR; + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; ret = kexec_add_buffer(&kbuf); if (ret) goto out_free_params; -- cgit v1.2.3-58-ga151 From ce0210c12433031aba3bbacd75f4c02ab77f2004 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 14 Jan 2019 16:31:18 +0100 Subject: drm/meson: Fix atomic mode switching regression Since commit 2bcd3ecab773 when switching mode from X11 (ubuntu mate for example) the display gets blurry, looking like an invalid framebuffer width. This commit fixed atomic crtc modesetting in a totally wrong way and introduced a local unnecessary ->enabled crtc state. This commit reverts the crctc _begin() and _enable() changes and simply adds drm_atomic_helper_commit_tail_rpm as helper. Reported-by: Tony McKahan Suggested-by: Daniel Vetter Fixes: 2bcd3ecab773 ("drm/meson: Fixes for drm_crtc_vblank_on/off support") Signed-off-by: Neil Armstrong Acked-by: Daniel Vetter [narmstrong: fixed blank line issue from checkpatch] Link: https://patchwork.freedesktop.org/patch/msgid/20190114153118.8024-1-narmstrong@baylibre.com --- drivers/gpu/drm/meson/meson_crtc.c | 23 ++--------------------- drivers/gpu/drm/meson/meson_drv.c | 5 +++++ 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c index 75d97f1b2e8f..4f5c67f70c4d 100644 --- a/drivers/gpu/drm/meson/meson_crtc.c +++ b/drivers/gpu/drm/meson/meson_crtc.c @@ -46,7 +46,6 @@ struct meson_crtc { struct drm_crtc base; struct drm_pending_vblank_event *event; struct meson_drm *priv; - bool enabled; }; #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) @@ -82,7 +81,8 @@ static const struct drm_crtc_funcs meson_crtc_funcs = { }; -static void meson_crtc_enable(struct drm_crtc *crtc) +static void meson_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct meson_crtc *meson_crtc = to_meson_crtc(crtc); struct drm_crtc_state *crtc_state = crtc->state; @@ -108,20 +108,6 @@ static void meson_crtc_enable(struct drm_crtc *crtc) drm_crtc_vblank_on(crtc); - meson_crtc->enabled = true; -} - -static void meson_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) -{ - struct meson_crtc *meson_crtc = to_meson_crtc(crtc); - struct meson_drm *priv = meson_crtc->priv; - - DRM_DEBUG_DRIVER("\n"); - - if (!meson_crtc->enabled) - meson_crtc_enable(crtc); - priv->viu.osd1_enabled = true; } @@ -153,8 +139,6 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc, crtc->state->event = NULL; } - - meson_crtc->enabled = false; } static void meson_crtc_atomic_begin(struct drm_crtc *crtc, @@ -163,9 +147,6 @@ static void meson_crtc_atomic_begin(struct drm_crtc *crtc, struct meson_crtc *meson_crtc = to_meson_crtc(crtc); unsigned long flags; - if (crtc->state->enable && !meson_crtc->enabled) - meson_crtc_enable(crtc); - if (crtc->state->event) { WARN_ON(drm_crtc_vblank_get(crtc) != 0); diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index b59c7570f4cb..12ff47b13668 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -75,6 +75,10 @@ static const struct drm_mode_config_funcs meson_mode_config_funcs = { .fb_create = drm_gem_fb_create, }; +static const struct drm_mode_config_helper_funcs meson_mode_config_helpers = { + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, +}; + static irqreturn_t meson_irq(int irq, void *arg) { struct drm_device *dev = arg; @@ -266,6 +270,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) drm->mode_config.max_width = 3840; drm->mode_config.max_height = 2160; drm->mode_config.funcs = &meson_mode_config_funcs; + drm->mode_config.helper_private = &meson_mode_config_helpers; /* Hardware Initialization */ -- cgit v1.2.3-58-ga151 From c8a83a6b54d0ca078de036aafb3f6af58c1dc5eb Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 14 Jan 2019 09:48:09 +0100 Subject: nbd: Use set_blocksize() to set device blocksize NBD can update block device block size implicitely through bd_set_size(). Make it explicitely set blocksize with set_blocksize() as this behavior of bd_set_size() is going away. CC: Josef Bacik Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- drivers/block/nbd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 08696f5f00bb..7c9a949e876b 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -288,9 +288,10 @@ static void nbd_size_update(struct nbd_device *nbd) blk_queue_physical_block_size(nbd->disk->queue, config->blksize); set_capacity(nbd->disk, config->bytesize >> 9); if (bdev) { - if (bdev->bd_disk) + if (bdev->bd_disk) { bd_set_size(bdev, config->bytesize); - else + set_blocksize(bdev, config->blksize); + } else bdev->bd_invalidated = 1; bdput(bdev); } -- cgit v1.2.3-58-ga151 From 04906b2f542c23626b0ef6219b808406f8dddbe9 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 14 Jan 2019 09:48:10 +0100 Subject: blockdev: Fix livelocks on loop device bd_set_size() updates also block device's block size. This is somewhat unexpected from its name and at this point, only blkdev_open() uses this functionality. Furthermore, this can result in changing block size under a filesystem mounted on a loop device which leads to livelocks inside __getblk_gfp() like: Sending NMI from CPU 0 to CPUs 1: NMI backtrace for cpu 1 CPU: 1 PID: 10863 Comm: syz-executor0 Not tainted 4.18.0-rc5+ #151 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:__sanitizer_cov_trace_pc+0x3f/0x50 kernel/kcov.c:106 ... Call Trace: init_page_buffers+0x3e2/0x530 fs/buffer.c:904 grow_dev_page fs/buffer.c:947 [inline] grow_buffers fs/buffer.c:1009 [inline] __getblk_slow fs/buffer.c:1036 [inline] __getblk_gfp+0x906/0xb10 fs/buffer.c:1313 __bread_gfp+0x2d/0x310 fs/buffer.c:1347 sb_bread include/linux/buffer_head.h:307 [inline] fat12_ent_bread+0x14e/0x3d0 fs/fat/fatent.c:75 fat_ent_read_block fs/fat/fatent.c:441 [inline] fat_alloc_clusters+0x8ce/0x16e0 fs/fat/fatent.c:489 fat_add_cluster+0x7a/0x150 fs/fat/inode.c:101 __fat_get_block fs/fat/inode.c:148 [inline] ... Trivial reproducer for the problem looks like: truncate -s 1G /tmp/image losetup /dev/loop0 /tmp/image mkfs.ext4 -b 1024 /dev/loop0 mount -t ext4 /dev/loop0 /mnt losetup -c /dev/loop0 l /mnt Fix the problem by moving initialization of a block device block size into a separate function and call it when needed. Thanks to Tetsuo Handa for help with debugging the problem. Reported-by: syzbot+9933e4476f365f5d5a1b@syzkaller.appspotmail.com Signed-off-by: Jan Kara Signed-off-by: Jens Axboe --- fs/block_dev.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/fs/block_dev.c b/fs/block_dev.c index c546cdce77e6..58a4c1217fa8 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -104,6 +104,20 @@ void invalidate_bdev(struct block_device *bdev) } EXPORT_SYMBOL(invalidate_bdev); +static void set_init_blocksize(struct block_device *bdev) +{ + unsigned bsize = bdev_logical_block_size(bdev); + loff_t size = i_size_read(bdev->bd_inode); + + while (bsize < PAGE_SIZE) { + if (size & bsize) + break; + bsize <<= 1; + } + bdev->bd_block_size = bsize; + bdev->bd_inode->i_blkbits = blksize_bits(bsize); +} + int set_blocksize(struct block_device *bdev, int size) { /* Size must be a power of two, and between 512 and PAGE_SIZE */ @@ -1431,18 +1445,9 @@ EXPORT_SYMBOL(check_disk_change); void bd_set_size(struct block_device *bdev, loff_t size) { - unsigned bsize = bdev_logical_block_size(bdev); - inode_lock(bdev->bd_inode); i_size_write(bdev->bd_inode, size); inode_unlock(bdev->bd_inode); - while (bsize < PAGE_SIZE) { - if (size & bsize) - break; - bsize <<= 1; - } - bdev->bd_block_size = bsize; - bdev->bd_inode->i_blkbits = blksize_bits(bsize); } EXPORT_SYMBOL(bd_set_size); @@ -1519,8 +1524,10 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) } } - if (!ret) + if (!ret) { bd_set_size(bdev,(loff_t)get_capacity(disk)<<9); + set_init_blocksize(bdev); + } /* * If the device is invalidated, rescan partition @@ -1555,6 +1562,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) goto out_clear; } bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9); + set_init_blocksize(bdev); } if (bdev->bd_bdi == &noop_backing_dev_info) -- cgit v1.2.3-58-ga151 From b62ce02e157afa9b57d7f0625e8c585935f422a5 Mon Sep 17 00:00:00 2001 From: Július Milan Date: Mon, 7 Jan 2019 15:43:05 +0100 Subject: staging: wilc1000: fix registration frame size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following sparse warnings: drivers/staging/wilc1000/host_interface.c:2360:30: warning: incorrect type in assignment (different base types) expected restricted __le32 [addressable] [assigned] [usertype] frame_type got restricted __le16 [usertype] Fixes: 147ccfd451024 ("staging: wilc1000: handle mgmt_frame_register ops from cfg82011 context") Signed-off-by: Július Milan Reviewed-by: Ajay Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 70c854d939ce..7acb790d850b 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -36,7 +36,7 @@ struct wilc_op_mode { struct wilc_reg_frame { bool reg; u8 reg_id; - __le32 frame_type; + __le16 frame_type; } __packed; struct wilc_drv_handler { -- cgit v1.2.3-58-ga151 From fe2570fbf3dfce39996819deeaf1693ac6d7b5a3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Sat, 22 Dec 2018 03:08:15 -0600 Subject: staging: wilc1000: fix memory leak in wilc_add_rx_gtk In case *mode* happens to be different than WILC_AP_MODE and WILC_STATION_MODE, gtk_key is not released, hence leanding to a memory leak. So, in this case it is safer to release gtk_key just before returning to callers. Addresses-Coverity-ID: 1476020 ("Resource leak") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 7acb790d850b..3d0badc34825 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -1744,7 +1744,6 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, ARRAY_SIZE(wid_list), wilc_get_vif_idx(vif)); - kfree(gtk_key); } else if (mode == WILC_STATION_MODE) { struct wid wid; @@ -1754,9 +1753,9 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, wid.val = (u8 *)gtk_key; result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); - kfree(gtk_key); } + kfree(gtk_key); return result; } -- cgit v1.2.3-58-ga151 From 0a9019cc8ae0caf97d3d914d178e31ffd37cc48e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Dec 2018 12:12:02 +0300 Subject: Staging: wilc1000: unlock on error in init_chip() When there is an error in init_bus() then we need to call release_bus() before we return. Fixes: c5c77ba18ea6 ("staging: wilc1000: Add SDIO/SPI 802.11 driver") Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wlan.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 3c5e9e030cad..489e5a5038f8 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -1252,21 +1252,22 @@ static u32 init_chip(struct net_device *dev) ret = wilc->hif_func->hif_read_reg(wilc, 0x1118, ®); if (!ret) { netdev_err(dev, "fail read reg 0x1118\n"); - return ret; + goto release; } reg |= BIT(0); ret = wilc->hif_func->hif_write_reg(wilc, 0x1118, reg); if (!ret) { netdev_err(dev, "fail write reg 0x1118\n"); - return ret; + goto release; } ret = wilc->hif_func->hif_write_reg(wilc, 0xc0000, 0x71); if (!ret) { netdev_err(dev, "fail write reg 0xc0000\n"); - return ret; + goto release; } } +release: release_bus(wilc, WILC_BUS_RELEASE_ONLY); return ret; -- cgit v1.2.3-58-ga151 From a50c4c9a65779ca835746b5fd79d3d5278afbdbe Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 11 Jan 2019 11:34:53 +0000 Subject: staging: vchiq: Fix local event signalling Prior to the recent event reworking (see Fixes), thread synchronisation was implemented using completions, the worker thread being woken with a call to complete(). The replacement uses waitqueues, which are more like condition variables in that the waiting thread is only woken if the condition is true. When the VPU signals the ARM, it first sets the event's fired flag to indicate which event is being signalled, but the places in the ARM-side code where the worker thread is being woken - remote_event_signal_local via request_poll - did not do so as it wasn't previously necessary, and since the armed flag was being cleared this lead to a deadlock. Fixes: 852b2876a8a8 ("staging: vchiq: rework remove_event handling") Signed-off-by: Phil Elwell Tested-by: Stefan Wahren Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 9e17ec651bde..53f5a1cb4636 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -446,6 +446,7 @@ remote_event_wait(wait_queue_head_t *wq, struct remote_event *event) static inline void remote_event_signal_local(wait_queue_head_t *wq, struct remote_event *event) { + event->fired = 1; event->armed = 0; wake_up_all(wq); } -- cgit v1.2.3-58-ga151 From 5f74a8cbb38d10615ed46bc3e37d9a4c9af8045a Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Mon, 7 Jan 2019 18:28:58 +0100 Subject: staging: rtl8188eu: Add device code for D-Link DWA-121 rev B1 This device was added to the stand-alone driver on github. Add it to the staging driver as well. Link: https://github.com/lwfinger/rtl8188eu/commit/a0619a07cd1e Signed-off-by: Michael Straube Acked-by: Larry Finger Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 28cbd6b3d26c..dfee6985efa6 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -35,6 +35,7 @@ static const struct usb_device_id rtw_usb_id_tbl[] = { {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */ + {USB_DEVICE(0x2001, 0x331B)}, /* D-Link DWA-121 rev B1 */ {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */ {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */ -- cgit v1.2.3-58-ga151 From 93ad0fc088c5b4631f796c995bdd27a082ef33a6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 11 Jan 2019 14:33:16 +0100 Subject: posix-cpu-timers: Unbreak timer rearming The recent commit which prevented a division by 0 issue in the alarm timer code broke posix CPU timers as an unwanted side effect. The reason is that the common rearm code checks for timer->it_interval being 0 now. What went unnoticed is that the posix cpu timer setup does not initialize timer->it_interval as it stores the interval in CPU timer specific storage. The reason for the separate storage is historical as the posix CPU timers always had a 64bit nanoseconds representation internally while timer->it_interval is type ktime_t which used to be a modified timespec representation on 32bit machines. Instead of reverting the offending commit and fixing the alarmtimer issue in the alarmtimer code, store the interval in timer->it_interval at CPU timer setup time so the common code check works. This also repairs the existing inconistency of the posix CPU timer code which kept a single shot timer armed despite of the interval being 0. The separate storage can be removed in mainline, but that needs to be a separate commit as the current one has to be backported to stable kernels. Fixes: 0e334db6bb4b ("posix-timers: Fix division by zero bug") Reported-by: H.J. Lu Signed-off-by: Thomas Gleixner Cc: John Stultz Cc: Peter Zijlstra Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20190111133500.840117406@linutronix.de --- kernel/time/posix-cpu-timers.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 8f0644af40be..80f955210861 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -685,6 +685,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, * set up the signal and overrun bookkeeping. */ timer->it.cpu.incr = timespec64_to_ns(&new->it_interval); + timer->it_interval = ns_to_ktime(timer->it.cpu.incr); /* * This acts as a modification timestamp for the timer, -- cgit v1.2.3-58-ga151 From 25ec429e86bb790e40387a550f0501d0ac55a47c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 10 Jan 2019 12:16:57 +0100 Subject: Revert "drm/amdgpu: validate user GEM object size" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was at the same time too strict (for linear tiling modes, where no height alignment is required) and too lenient (for 2D tiling modes, where height may need to be aligned to values > 8). Acked-by: Alex Deucher Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index dafc645b2e4e..cb72d9675ab1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -531,7 +531,6 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev, struct drm_gem_object *obj; struct amdgpu_framebuffer *amdgpu_fb; int ret; - int height; struct amdgpu_device *adev = dev->dev_private; int cpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0); int pitch = mode_cmd->pitches[0] / cpp; @@ -556,13 +555,6 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev, return ERR_PTR(-EINVAL); } - height = ALIGN(mode_cmd->height, 8); - if (obj->size < pitch * height) { - DRM_DEBUG_KMS("Invalid GEM size: expecting >= %d but got %zu\n", - pitch * height, obj->size); - return ERR_PTR(-EINVAL); - } - amdgpu_fb = kzalloc(sizeof(*amdgpu_fb), GFP_KERNEL); if (amdgpu_fb == NULL) { drm_gem_object_put_unlocked(obj); -- cgit v1.2.3-58-ga151 From 92b0730eaf2d549fdfb10ecc8b71f34b9f472c12 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Fri, 11 Jan 2019 16:21:02 +0100 Subject: Revert "drm/amdgpu: validate user pitch alignment" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The check turned out to be too strict in some cases. Reviewed-by: Alex Deucher Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index cb72d9675ab1..b083b219b1a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -531,16 +531,6 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev, struct drm_gem_object *obj; struct amdgpu_framebuffer *amdgpu_fb; int ret; - struct amdgpu_device *adev = dev->dev_private; - int cpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0); - int pitch = mode_cmd->pitches[0] / cpp; - - pitch = amdgpu_align_pitch(adev, pitch, cpp, false); - if (mode_cmd->pitches[0] != pitch) { - DRM_DEBUG_KMS("Invalid pitch: expecting %d but got %d\n", - pitch, mode_cmd->pitches[0]); - return ERR_PTR(-EINVAL); - } obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[0]); if (obj == NULL) { -- cgit v1.2.3-58-ga151 From 45ac486ecf2dc998e25cf32f0cabf2deaad875be Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Fri, 11 Jan 2019 19:04:44 -0500 Subject: NFSv4.2 fix unnecessary retry in nfs4_copy_file_range Currently nfs42_proc_copy_file_range() can not return EAGAIN. Fixes: e4648aa4f98a ("NFS recover from destination server reboot for copies") Signed-off-by: Olga Kornievskaia Signed-off-by: Anna Schumaker --- fs/nfs/nfs4file.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 46d691ba04bc..45b2322e092d 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -133,15 +133,9 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, struct file *file_out, loff_t pos_out, size_t count, unsigned int flags) { - ssize_t ret; - if (file_inode(file_in) == file_inode(file_out)) return -EINVAL; -retry: - ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); - if (ret == -EAGAIN) - goto retry; - return ret; + return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); } static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) -- cgit v1.2.3-58-ga151 From 8b05a3a7503c2a982c9c462eae96cfbd59506783 Mon Sep 17 00:00:00 2001 From: Andrea Righi Date: Fri, 11 Jan 2019 07:01:13 +0100 Subject: tracing/kprobes: Fix NULL pointer dereference in trace_kprobe_create() It is possible to trigger a NULL pointer dereference by writing an incorrectly formatted string to krpobe_events (trying to create a kretprobe omitting the symbol). Example: echo "r:event_1 " >> /sys/kernel/debug/tracing/kprobe_events That triggers this: BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 #PF error: [normal kernel read fault] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 6 PID: 1757 Comm: bash Not tainted 5.0.0-rc1+ #125 Hardware name: Dell Inc. XPS 13 9370/0F6P3V, BIOS 1.5.1 08/09/2018 RIP: 0010:kstrtoull+0x2/0x20 Code: 28 00 00 00 75 17 48 83 c4 18 5b 41 5c 5d c3 b8 ea ff ff ff eb e1 b8 de ff ff ff eb da e8 d6 36 bb ff 66 0f 1f 44 00 00 31 c0 <80> 3f 2b 55 48 89 e5 0f 94 c0 48 01 c7 e8 5c ff ff ff 5d c3 66 2e RSP: 0018:ffffb5d482e57cb8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000001 RCX: ffffffff82b12720 RDX: ffffb5d482e57cf8 RSI: 0000000000000000 RDI: 0000000000000000 RBP: ffffb5d482e57d70 R08: ffffa0c05e5a7080 R09: ffffa0c05e003980 R10: 0000000000000000 R11: 0000000040000000 R12: ffffa0c04fe87b08 R13: 0000000000000001 R14: 000000000000000b R15: ffffa0c058d749e1 FS: 00007f137c7f7740(0000) GS:ffffa0c05e580000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 0000000497d46004 CR4: 00000000003606e0 Call Trace: ? trace_kprobe_create+0xb6/0x840 ? _cond_resched+0x19/0x40 ? _cond_resched+0x19/0x40 ? __kmalloc+0x62/0x210 ? argv_split+0x8f/0x140 ? trace_kprobe_create+0x840/0x840 ? trace_kprobe_create+0x840/0x840 create_or_delete_trace_kprobe+0x11/0x30 trace_run_command+0x50/0x90 trace_parse_run_command+0xc1/0x160 probes_write+0x10/0x20 __vfs_write+0x3a/0x1b0 ? apparmor_file_permission+0x1a/0x20 ? security_file_permission+0x31/0xf0 ? _cond_resched+0x19/0x40 vfs_write+0xb1/0x1a0 ksys_write+0x55/0xc0 __x64_sys_write+0x1a/0x20 do_syscall_64+0x5a/0x120 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Fix by doing the proper argument checks in trace_kprobe_create(). Cc: Ingo Molnar Link: https://lore.kernel.org/lkml/20190111095108.b79a2ee026185cbd62365977@kernel.org Link: http://lkml.kernel.org/r/20190111060113.GA22841@xps-13 Fixes: 6212dd29683e ("tracing/kprobes: Use dyn_event framework for kprobe events") Acked-by: Masami Hiramatsu Signed-off-by: Andrea Righi Signed-off-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) --- kernel/trace/trace_kprobe.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 5c19b8c41c7e..d5fb09ebba8b 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -607,11 +607,17 @@ static int trace_kprobe_create(int argc, const char *argv[]) char buf[MAX_EVENT_NAME_LEN]; unsigned int flags = TPARG_FL_KERNEL; - /* argc must be >= 1 */ - if (argv[0][0] == 'r') { + switch (argv[0][0]) { + case 'r': is_return = true; flags |= TPARG_FL_RETURN; - } else if (argv[0][0] != 'p' || argc < 2) + break; + case 'p': + break; + default: + return -ECANCELED; + } + if (argc < 2) return -ECANCELED; event = strchr(&argv[0][1], ':'); -- cgit v1.2.3-58-ga151 From 663ec3a2c2d02775bc723b20a1af33262f790f50 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 9 Jan 2019 22:51:44 +0100 Subject: mtd: rawnand: fsmc: Keep bank enable bit set Hammering the "bank enable" (PBKEN) bit on and off between every command crashes the Nomadik NHK15 with this message: Scanning device for bad blocks Unhandled fault: external abort on non-linefetch (0x008) at 0xcc95e000 pgd = (ptrval) [cc95e000] *pgd=0b808811, *pte=40000653, *ppte=40000552 Internal error: : 8 [#1] PREEMPT ARM Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 4.20.0-rc2+ #72 Hardware name: Nomadik STn8815 PC is at fsmc_exec_op+0x194/0x204 (...) After a discussion we (me and Boris Brezillon) start to suspect that this bit does not immediately control the chip select line at all, it rather enables access to the bank and the hardware will drive the CS autonomously. If there is a NAND chip connected, we should keep this enabled. As fsmc_nand_setup() sets this bit, we can simply remove the offending code. Fixes: 550b9fc4e3af ("mtd: rawnand: fsmc: Stop implementing ->select_chip()") Signed-off-by: Linus Walleij Acked-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/fsmc_nand.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 325b4414dccc..c9149a37f8f0 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -593,23 +593,6 @@ static void fsmc_write_buf_dma(struct fsmc_nand_data *host, const u8 *buf, dma_xfer(host, (void *)buf, len, DMA_TO_DEVICE); } -/* fsmc_select_chip - assert or deassert nCE */ -static void fsmc_ce_ctrl(struct fsmc_nand_data *host, bool assert) -{ - u32 pc = readl(host->regs_va + FSMC_PC); - - if (!assert) - writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + FSMC_PC); - else - writel_relaxed(pc | FSMC_ENABLE, host->regs_va + FSMC_PC); - - /* - * nCE line changes must be applied before returning from this - * function. - */ - mb(); -} - /* * fsmc_exec_op - hook called by the core to execute NAND operations * @@ -627,8 +610,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, pr_debug("Executing operation [%d instructions]:\n", op->ninstrs); - fsmc_ce_ctrl(host, true); - for (op_id = 0; op_id < op->ninstrs; op_id++) { instr = &op->instrs[op_id]; @@ -686,8 +667,6 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, } } - fsmc_ce_ctrl(host, false); - return ret; } -- cgit v1.2.3-58-ga151 From a811dc61559e0c8003f1086c2a4dc8e4d5ae4cb8 Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Sat, 12 Jan 2019 11:24:20 -0700 Subject: seccomp: fix UAF in user-trap code On the failure path, we do an fput() of the listener fd if the filter fails to install (e.g. because of a TSYNC race that's lost, or if the thread is killed, etc.). fput() doesn't actually release the fd, it just ads it to a work queue. Then the thread proceeds to free the filter, even though the listener struct file has a reference to it. To fix this, on the failure path let's set the private data to null, so we know in ->release() to ignore the filter. Reported-by: syzbot+981c26489b2d1c6316ba@syzkaller.appspotmail.com Fixes: 6a21cc50f0c7 ("seccomp: add a return code to trap to userspace") Signed-off-by: Tycho Andersen Acked-by: Kees Cook Signed-off-by: James Morris --- kernel/seccomp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index d7f538847b84..e815781ed751 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -976,6 +976,9 @@ static int seccomp_notify_release(struct inode *inode, struct file *file) struct seccomp_filter *filter = file->private_data; struct seccomp_knotif *knotif; + if (!filter) + return 0; + mutex_lock(&filter->notify_lock); /* @@ -1300,6 +1303,7 @@ out: out_put_fd: if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) { if (ret < 0) { + listener_f->private_data = NULL; fput(listener_f); put_unused_fd(listener); } else { -- cgit v1.2.3-58-ga151 From cc5b5d3565048ae57d14e5674a5fb085b2ab0193 Mon Sep 17 00:00:00 2001 From: Krzysztof Kazimierczak Date: Thu, 10 Jan 2019 20:29:02 +0100 Subject: xsk: Check if a queue exists during umem setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the xdp_umem_assign_dev() path, the xsk code does not check if a queue for which umem is to be created exists. It leads to a situation where umem is not assigned to any Tx/Rx queue of a netdevice, without notifying the stack about an error. This affects both XDP_SKB and XDP_DRV modes - in case of XDP_DRV_ZC, queue index is checked by the driver. This patch fixes xsk code, so that in both XDP_SKB and XDP_DRV mode of AF_XDP, an error is returned when requested queue index exceedes an existing maximum. Fixes: c9b47cc1fabca ("xsk: fix bug when trying to use both copy and zero-copy on one queue id") Reported-by: Jakub Spizewski Signed-off-by: Krzysztof Kazimierczak Acked-by: Björn Töpel Signed-off-by: Daniel Borkmann --- net/xdp/xdp_umem.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c index a264cf2accd0..d4de871e7d4d 100644 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@ -41,13 +41,20 @@ void xdp_del_sk_umem(struct xdp_umem *umem, struct xdp_sock *xs) * not know if the device has more tx queues than rx, or the opposite. * This might also change during run time. */ -static void xdp_reg_umem_at_qid(struct net_device *dev, struct xdp_umem *umem, - u16 queue_id) +static int xdp_reg_umem_at_qid(struct net_device *dev, struct xdp_umem *umem, + u16 queue_id) { + if (queue_id >= max_t(unsigned int, + dev->real_num_rx_queues, + dev->real_num_tx_queues)) + return -EINVAL; + if (queue_id < dev->real_num_rx_queues) dev->_rx[queue_id].umem = umem; if (queue_id < dev->real_num_tx_queues) dev->_tx[queue_id].umem = umem; + + return 0; } struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev, @@ -88,7 +95,10 @@ int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev, goto out_rtnl_unlock; } - xdp_reg_umem_at_qid(dev, umem, queue_id); + err = xdp_reg_umem_at_qid(dev, umem, queue_id); + if (err) + goto out_rtnl_unlock; + umem->dev = dev; umem->queue_id = queue_id; if (force_copy) -- cgit v1.2.3-58-ga151 From 1be72f29bfb98be27a95309f18b4ab5249967b59 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 14 Jan 2019 09:41:41 -0800 Subject: selftests/bpf: install with_tunnels.sh for test_flow_dissector.sh test_flow_dissector.sh depends on both with_addr.sh and with_tunnels.sh However, we install only with_addr.sh. Add with_tunnels.sh to TEST_PROGS_EXTENDED to make sure it gets installed as well. Tested with: make TARGETS=bpf install INSTALL_PATH=$PWD/x Fixes: ef4ab8447aa26 ("selftests: bpf: install script with_addr.sh") Signed-off-by: Stanislav Fomichev Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 70229de510f5..41ab7a3668b3 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -56,6 +56,7 @@ TEST_PROGS := test_kmod.sh \ test_xdp_vlan.sh TEST_PROGS_EXTENDED := with_addr.sh \ + with_tunnels.sh \ tcp_client.py \ tcp_server.py -- cgit v1.2.3-58-ga151 From 6bf3bbe1f4d4cf405e3c2bf07bbdff56d3223ec8 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Sat, 12 Jan 2019 15:04:30 -0800 Subject: samples/bpf: workaround clang asm goto compilation errors x86 compilation has required asm goto support since 4.17. Since clang does not support asm goto, at 4.17, Commit b1ae32dbab50 ("x86/cpufeature: Guard asm_volatile_goto usage for BPF compilation") worked around the issue by permitting an alternative implementation without asm goto for clang. At 5.0, more asm goto usages appeared. [yhs@148 x86]$ egrep -r asm_volatile_goto include/asm/cpufeature.h: asm_volatile_goto("1: jmp 6f\n" include/asm/jump_label.h: asm_volatile_goto("1:" include/asm/jump_label.h: asm_volatile_goto("1:" include/asm/rmwcc.h: asm_volatile_goto (fullop "; j" #cc " %l[cc_label]" \ include/asm/uaccess.h: asm_volatile_goto("\n" \ include/asm/uaccess.h: asm_volatile_goto("\n" \ [yhs@148 x86]$ Compiling samples/bpf directories, most bpf programs failed compilation with error messages like: In file included from /home/yhs/work/bpf-next/samples/bpf/xdp_sample_pkts_kern.c:2: In file included from /home/yhs/work/bpf-next/include/linux/ptrace.h:6: In file included from /home/yhs/work/bpf-next/include/linux/sched.h:15: In file included from /home/yhs/work/bpf-next/include/linux/sem.h:5: In file included from /home/yhs/work/bpf-next/include/uapi/linux/sem.h:5: In file included from /home/yhs/work/bpf-next/include/linux/ipc.h:9: In file included from /home/yhs/work/bpf-next/include/linux/refcount.h:72: /home/yhs/work/bpf-next/arch/x86/include/asm/refcount.h:70:9: error: 'asm goto' constructs are not supported yet return GEN_BINARY_SUFFIXED_RMWcc(LOCK_PREFIX "subl", ^ /home/yhs/work/bpf-next/arch/x86/include/asm/rmwcc.h:67:2: note: expanded from macro 'GEN_BINARY_SUFFIXED_RMWcc' __GEN_RMWcc(op " %[val], %[var]\n\t" suffix, var, cc, \ ^ /home/yhs/work/bpf-next/arch/x86/include/asm/rmwcc.h:21:2: note: expanded from macro '__GEN_RMWcc' asm_volatile_goto (fullop "; j" #cc " %l[cc_label]" \ ^ /home/yhs/work/bpf-next/include/linux/compiler_types.h:188:37: note: expanded from macro 'asm_volatile_goto' #define asm_volatile_goto(x...) asm goto(x) Most implementation does not even provide an alternative implementation. And it is also not practical to make changes for each call site. This patch workarounded the asm goto issue by redefining the macro like below: #define asm_volatile_goto(x...) asm volatile("invalid use of asm_volatile_goto") If asm_volatile_goto is not used by bpf programs, which is typically the case, nothing bad will happen. If asm_volatile_goto is used by bpf programs, which is incorrect, the compiler will issue an error since "invalid use of asm_volatile_goto" is not valid assembly codes. With this patch, all bpf programs under samples/bpf can pass compilation. Note that bpf programs under tools/testing/selftests/bpf/ compiled fine as they do not access kernel internal headers. Fixes: e769742d3584 ("Revert "x86/jump-labels: Macrofy inline assembly code to work around GCC inlining bugs"") Fixes: 18fe58229d80 ("x86, asm: change the GEN_*_RMWcc() macros to not quote the condition") Acked-by: Alexei Starovoitov Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- samples/bpf/Makefile | 1 + samples/bpf/asm_goto_workaround.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 samples/bpf/asm_goto_workaround.h diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 66ae15f27c70..db1a91dfa702 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -279,6 +279,7 @@ $(obj)/%.o: $(src)/%.c -Wno-gnu-variable-sized-type-not-at-end \ -Wno-address-of-packed-member -Wno-tautological-compare \ -Wno-unknown-warning-option $(CLANG_ARCH_ARGS) \ + -I$(srctree)/samples/bpf/ -include asm_goto_workaround.h \ -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf $(LLC_FLAGS) -filetype=obj -o $@ ifeq ($(DWARF2BTF),y) $(BTF_PAHOLE) -J $@ diff --git a/samples/bpf/asm_goto_workaround.h b/samples/bpf/asm_goto_workaround.h new file mode 100644 index 000000000000..5cd7c1d1a5d5 --- /dev/null +++ b/samples/bpf/asm_goto_workaround.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019 Facebook */ +#ifndef __ASM_GOTO_WORKAROUND_H +#define __ASM_GOTO_WORKAROUND_H + +/* this will bring in asm_volatile_goto macro definition + * if enabled by compiler and config options. + */ +#include + +#ifdef asm_volatile_goto +#undef asm_volatile_goto +#define asm_volatile_goto(x...) asm volatile("invalid use of asm_volatile_goto") +#endif + +#endif -- cgit v1.2.3-58-ga151 From e66721f0436396f779291a29616858b76bfd9415 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 2 Jan 2019 17:53:10 -0500 Subject: SUNRPC: Ensure rq_bytes_sent is reset before request transmission When we resend a request, ensure that the 'rq_bytes_sent' is reset to zero. Signed-off-by: Trond Myklebust Signed-off-by: Anna Schumaker --- net/sunrpc/clnt.c | 1 - net/sunrpc/xprt.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 71d9599b5816..0878c793ce7f 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1739,7 +1739,6 @@ rpc_xdr_encode(struct rpc_task *task) xdr_buf_init(&req->rq_rcv_buf, req->rq_rbuffer, req->rq_rcvsize); - req->rq_bytes_sent = 0; p = rpc_encode_header(task); if (p == NULL) { diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 73547d17d3c6..9075ae150ae5 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1151,6 +1151,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task) struct rpc_xprt *xprt = req->rq_xprt; if (xprt_request_need_enqueue_transmit(task, req)) { + req->rq_bytes_sent = 0; spin_lock(&xprt->queue_lock); /* * Requests that carry congestion control credits are added -- cgit v1.2.3-58-ga151 From 97b78ae96ba76f4ca2d8f5afee6a2e567ccb8f45 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 2 Jan 2019 17:53:13 -0500 Subject: SUNRPC: Ensure we respect the RPCSEC_GSS sequence number limit According to RFC2203, the RPCSEC_GSS sequence numbers are bounded to an upper limit of MAXSEQ = 0x80000000. Ensure that we handle that correctly. Signed-off-by: Trond Myklebust Signed-off-by: Anna Schumaker --- net/sunrpc/auth_gss/auth_gss.c | 12 +++++++++--- net/sunrpc/clnt.c | 19 ++++++++++++------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index dc86713b32b6..1531b0219344 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1549,8 +1549,10 @@ gss_marshal(struct rpc_task *task, __be32 *p) cred_len = p++; spin_lock(&ctx->gc_seq_lock); - req->rq_seqno = ctx->gc_seq++; + req->rq_seqno = (ctx->gc_seq < MAXSEQ) ? ctx->gc_seq++ : MAXSEQ; spin_unlock(&ctx->gc_seq_lock); + if (req->rq_seqno == MAXSEQ) + goto out_expired; *p++ = htonl((u32) RPC_GSS_VERSION); *p++ = htonl((u32) ctx->gc_proc); @@ -1572,14 +1574,18 @@ gss_marshal(struct rpc_task *task, __be32 *p) mic.data = (u8 *)(p + 1); maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); if (maj_stat == GSS_S_CONTEXT_EXPIRED) { - clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); + goto out_expired; } else if (maj_stat != 0) { - printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); + pr_warn("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); + task->tk_status = -EIO; goto out_put_ctx; } p = xdr_encode_opaque(p, NULL, mic.len); gss_put_ctx(ctx); return p; +out_expired: + clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); + task->tk_status = -EKEYEXPIRED; out_put_ctx: gss_put_ctx(ctx); return NULL; diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 0878c793ce7f..d7ec6132c046 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1741,11 +1741,8 @@ rpc_xdr_encode(struct rpc_task *task) req->rq_rcvsize); p = rpc_encode_header(task); - if (p == NULL) { - printk(KERN_INFO "RPC: couldn't encode RPC header, exit EIO\n"); - rpc_exit(task, -EIO); + if (p == NULL) return; - } encode = task->tk_msg.rpc_proc->p_encode; if (encode == NULL) @@ -1770,10 +1767,17 @@ call_encode(struct rpc_task *task) /* Did the encode result in an error condition? */ if (task->tk_status != 0) { /* Was the error nonfatal? */ - if (task->tk_status == -EAGAIN || task->tk_status == -ENOMEM) + switch (task->tk_status) { + case -EAGAIN: + case -ENOMEM: rpc_delay(task, HZ >> 4); - else + break; + case -EKEYEXPIRED: + task->tk_action = call_refresh; + break; + default: rpc_exit(task, task->tk_status); + } return; } @@ -2335,7 +2339,8 @@ rpc_encode_header(struct rpc_task *task) *p++ = htonl(clnt->cl_vers); /* program version */ *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ p = rpcauth_marshcred(task, p); - req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); + if (p) + req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); return p; } -- cgit v1.2.3-58-ga151 From 86edaed379632e216a97e6bcef9f498b64522d50 Mon Sep 17 00:00:00 2001 From: Lorenz Bauer Date: Tue, 8 Jan 2019 13:58:00 +0000 Subject: bpf: libbpf: retry loading program on EAGAIN Commit c3494801cd17 ("bpf: check pending signals while verifying programs") makes it possible for the BPF_PROG_LOAD to fail with EAGAIN. Retry unconditionally in this case. Fixes: c3494801cd17 ("bpf: check pending signals while verifying programs") Signed-off-by: Lorenz Bauer Signed-off-by: Daniel Borkmann --- tools/lib/bpf/bpf.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 3caaa3428774..88cbd110ae58 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -65,6 +65,17 @@ static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, return syscall(__NR_bpf, cmd, attr, size); } +static inline int sys_bpf_prog_load(union bpf_attr *attr, unsigned int size) +{ + int fd; + + do { + fd = sys_bpf(BPF_PROG_LOAD, attr, size); + } while (fd < 0 && errno == EAGAIN); + + return fd; +} + int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr) { __u32 name_len = create_attr->name ? strlen(create_attr->name) : 0; @@ -232,7 +243,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, memcpy(attr.prog_name, load_attr->name, min(name_len, BPF_OBJ_NAME_LEN - 1)); - fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); + fd = sys_bpf_prog_load(&attr, sizeof(attr)); if (fd >= 0) return fd; @@ -269,7 +280,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, break; } - fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); + fd = sys_bpf_prog_load(&attr, sizeof(attr)); if (fd >= 0) goto done; @@ -283,7 +294,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, attr.log_size = log_buf_sz; attr.log_level = 1; log_buf[0] = 0; - fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); + fd = sys_bpf_prog_load(&attr, sizeof(attr)); done: free(finfo); free(linfo); @@ -328,7 +339,7 @@ int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, attr.kern_version = kern_version; attr.prog_flags = prog_flags; - return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); + return sys_bpf_prog_load(&attr, sizeof(attr)); } int bpf_map_update_elem(int fd, const void *key, const void *value, -- cgit v1.2.3-58-ga151 From deaa5c96c2f7e8b934088a1e70a0fe8797bd1149 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 9 Jan 2019 10:04:57 -0500 Subject: SUNRPC: Address Kerberos performance/behavior regression When using Kerberos with v4.20, I've observed frequent connection loss on heavy workloads. I traced it down to the client underrunning the GSS sequence number window -- NFS servers are required to drop the RPC with the low sequence number, and also drop the connection to signal that an RPC was dropped. Bisected to commit 918f3c1fe83c ("SUNRPC: Improve latency for interactive tasks"). I've got a one-line workaround for this issue, which is easy to backport to v4.20 while a more permanent solution is being derived. Essentially, tk_owner-based sorting is disabled for RPCs that carry a GSS sequence number. Fixes: 918f3c1fe83c ("SUNRPC: Improve latency for interactive ... ") Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker --- net/sunrpc/xprt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 9075ae150ae5..f1ec2110efeb 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1178,7 +1178,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task) INIT_LIST_HEAD(&req->rq_xmit2); goto out; } - } else { + } else if (!req->rq_seqno) { list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { if (pos->rq_task->tk_owner != task->tk_owner) continue; -- cgit v1.2.3-58-ga151 From 4bb0e6d7258213d4893c2c876712fbba40e712fe Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Jan 2019 09:47:44 +0100 Subject: drm/sun4i: backend: add missing of_node_puts The device node iterators perform an of_node_get on each iteration, so a jump out of the loop requires an of_node_put. Remote and port also have augmented reference counts, so drop them on each iteration and at the end of the function, respectively. Remote is only used for the address it contains, not for the contents of that address, so the reference count can be dropped immediately. The semantic patch that fixes the first part of this problem is as follows (http://coccinelle.lip6.fr): // @@ expression root,e; local idexpression child; iterator name for_each_child_of_node; @@ for_each_available_child_of_node(root, child) { ... when != of_node_put(child) when != e = child + of_node_put(child); ? break; ... } ... when != child // Signed-off-by: Julia Lawall Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/1547369264-24831-5-git-send-email-Julia.Lawall@lip6.fr --- drivers/gpu/drm/sun4i/sun4i_backend.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 9e9255ee59cd..a021bab11a4f 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -786,17 +786,18 @@ static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv, remote = of_graph_get_remote_port_parent(ep); if (!remote) continue; + of_node_put(remote); /* does this node match any registered engines? */ list_for_each_entry(frontend, &drv->frontend_list, list) { if (remote == frontend->node) { - of_node_put(remote); of_node_put(port); + of_node_put(ep); return frontend; } } } - + of_node_put(port); return ERR_PTR(-EINVAL); } -- cgit v1.2.3-58-ga151 From 91cd63d320f84dcbf21d4327f31f7e1f85adebd0 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Fri, 7 Dec 2018 18:06:45 -0800 Subject: selftests/vm/gup_benchmark.c: match gup struct to kernel An expansion field was added to the kernel copy of this structure for future use. See mm/gup_benchmark.c. Add the same expansion field here, so that the IOCTL command decodes correctly. Otherwise, it fails with EINVAL. Signed-off-by: Alison Schofield Acked-by: Kirill A. Shutemov Signed-off-by: Shuah Khan --- tools/testing/selftests/vm/gup_benchmark.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/vm/gup_benchmark.c b/tools/testing/selftests/vm/gup_benchmark.c index 880b96fc80d4..c0534e298b51 100644 --- a/tools/testing/selftests/vm/gup_benchmark.c +++ b/tools/testing/selftests/vm/gup_benchmark.c @@ -25,6 +25,7 @@ struct gup_benchmark { __u64 size; __u32 nr_pages_per_call; __u32 flags; + __u64 expansion[10]; /* For future use */ }; int main(int argc, char **argv) -- cgit v1.2.3-58-ga151 From b488517b28a47d16b228ce8dcf07f5cb8e5b3dc5 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Wed, 2 Jan 2019 08:59:31 -0600 Subject: clk: socfpga: stratix10: fix naming convention for the fixed-clocks The fixed clocks in the DTS file have a hyphen, but the clock driver has the fixed clocks using underbar. Thus the clock driver cannot detect the other fixed clocks correctly. Change the fixed clock names to a hyphen. Fixes: 07afb8db7340 ("clk: socfpga: stratix10: add clock driver for Stratix10 platform") Cc: linux-stable@vger.kernel.org Signed-off-by: Dinh Nguyen Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-s10.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c index 5b238fc314ac..8281dfbf38c2 100644 --- a/drivers/clk/socfpga/clk-s10.c +++ b/drivers/clk/socfpga/clk-s10.c @@ -12,17 +12,17 @@ #include "stratix10-clk.h" -static const char * const pll_mux[] = { "osc1", "cb_intosc_hs_div2_clk", - "f2s_free_clk",}; +static const char * const pll_mux[] = { "osc1", "cb-intosc-hs-div2-clk", + "f2s-free-clk",}; static const char * const cntr_mux[] = { "main_pll", "periph_pll", - "osc1", "cb_intosc_hs_div2_clk", - "f2s_free_clk"}; -static const char * const boot_mux[] = { "osc1", "cb_intosc_hs_div2_clk",}; + "osc1", "cb-intosc-hs-div2-clk", + "f2s-free-clk"}; +static const char * const boot_mux[] = { "osc1", "cb-intosc-hs-div2-clk",}; static const char * const noc_free_mux[] = {"main_noc_base_clk", "peri_noc_base_clk", - "osc1", "cb_intosc_hs_div2_clk", - "f2s_free_clk"}; + "osc1", "cb-intosc-hs-div2-clk", + "f2s-free-clk"}; static const char * const emaca_free_mux[] = {"peri_emaca_clk", "boot_clk"}; static const char * const emacb_free_mux[] = {"peri_emacb_clk", "boot_clk"}; @@ -33,14 +33,14 @@ static const char * const s2f_usr1_free_mux[] = {"peri_s2f_usr1_clk", "boot_clk" static const char * const psi_ref_free_mux[] = {"peri_psi_ref_clk", "boot_clk"}; static const char * const mpu_mux[] = { "mpu_free_clk", "boot_clk",}; -static const char * const s2f_usr0_mux[] = {"f2s_free_clk", "boot_clk"}; +static const char * const s2f_usr0_mux[] = {"f2s-free-clk", "boot_clk"}; static const char * const emac_mux[] = {"emaca_free_clk", "emacb_free_clk"}; static const char * const noc_mux[] = {"noc_free_clk", "boot_clk"}; static const char * const mpu_free_mux[] = {"main_mpu_base_clk", "peri_mpu_base_clk", - "osc1", "cb_intosc_hs_div2_clk", - "f2s_free_clk"}; + "osc1", "cb-intosc-hs-div2-clk", + "f2s-free-clk"}; /* clocks in AO (always on) controller */ static const struct stratix10_pll_clock s10_pll_clks[] = { -- cgit v1.2.3-58-ga151 From d445bd9cec1a850c2100fcf53684c13b3fd934f2 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 15 Jan 2019 13:27:01 -0500 Subject: dm thin: fix passdown_double_checking_shared_status() Commit 00a0ea33b495 ("dm thin: do not queue freed thin mapping for next stage processing") changed process_prepared_discard_passdown_pt1() to increment all the blocks being discarded until after the passdown had completed to avoid them being prematurely reused. IO issued to a thin device that breaks sharing with a snapshot, followed by a discard issued to snapshot(s) that previously shared the block(s), results in passdown_double_checking_shared_status() being called to iterate through the blocks double checking their reference count is zero and issuing the passdown if so. So a side effect of commit 00a0ea33b495 is passdown_double_checking_shared_status() was broken. Fix this by checking if the block reference count is greater than 1. Also, rename dm_pool_block_is_used() to dm_pool_block_is_shared(). Fixes: 00a0ea33b495 ("dm thin: do not queue freed thin mapping for next stage processing") Cc: stable@vger.kernel.org # 4.9+ Reported-by: ryan.p.norwood@gmail.com Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer --- drivers/md/dm-thin-metadata.c | 4 ++-- drivers/md/dm-thin-metadata.h | 2 +- drivers/md/dm-thin.c | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 20b0776e39ef..ed3caceaed07 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -1678,7 +1678,7 @@ int dm_thin_remove_range(struct dm_thin_device *td, return r; } -int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result) +int dm_pool_block_is_shared(struct dm_pool_metadata *pmd, dm_block_t b, bool *result) { int r; uint32_t ref_count; @@ -1686,7 +1686,7 @@ int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *resu down_read(&pmd->root_lock); r = dm_sm_get_count(pmd->data_sm, b, &ref_count); if (!r) - *result = (ref_count != 0); + *result = (ref_count > 1); up_read(&pmd->root_lock); return r; diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h index 35e954ea20a9..f6be0d733c20 100644 --- a/drivers/md/dm-thin-metadata.h +++ b/drivers/md/dm-thin-metadata.h @@ -195,7 +195,7 @@ int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd, int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result); -int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result); +int dm_pool_block_is_shared(struct dm_pool_metadata *pmd, dm_block_t b, bool *result); int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e); int dm_pool_dec_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e); diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index dadd9696340c..ca8af21bf644 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1048,7 +1048,7 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m * passdown we have to check that these blocks are now unused. */ int r = 0; - bool used = true; + bool shared = true; struct thin_c *tc = m->tc; struct pool *pool = tc->pool; dm_block_t b = m->data_block, e, end = m->data_block + m->virt_end - m->virt_begin; @@ -1058,11 +1058,11 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m while (b != end) { /* find start of unmapped run */ for (; b < end; b++) { - r = dm_pool_block_is_used(pool->pmd, b, &used); + r = dm_pool_block_is_shared(pool->pmd, b, &shared); if (r) goto out; - if (!used) + if (!shared) break; } @@ -1071,11 +1071,11 @@ static void passdown_double_checking_shared_status(struct dm_thin_new_mapping *m /* find end of run */ for (e = b + 1; e != end; e++) { - r = dm_pool_block_is_used(pool->pmd, e, &used); + r = dm_pool_block_is_shared(pool->pmd, e, &shared); if (r) goto out; - if (used) + if (shared) break; } -- cgit v1.2.3-58-ga151 From b4711098066f1cf808d4dc11a1a842860a3292fe Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Tue, 15 Jan 2019 10:31:27 +0800 Subject: pvcalls-front: fix potential null dereference static checker warning: drivers/xen/pvcalls-front.c:373 alloc_active_ring() error: we previously assumed 'map->active.ring' could be null (see line 357) drivers/xen/pvcalls-front.c 351 static int alloc_active_ring(struct sock_mapping *map) 352 { 353 void *bytes; 354 355 map->active.ring = (struct pvcalls_data_intf *) 356 get_zeroed_page(GFP_KERNEL); 357 if (!map->active.ring) ^^^^^^^^^^^^^^^^^ Check 358 goto out; 359 360 map->active.ring->ring_order = PVCALLS_RING_ORDER; 361 bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 362 PVCALLS_RING_ORDER); 363 if (!bytes) 364 goto out; 365 366 map->active.data.in = bytes; 367 map->active.data.out = bytes + 368 XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER); 369 370 return 0; 371 372 out: --> 373 free_active_ring(map); ^^^ Add null check on map->active.ring before dereferencing it to avoid any NULL pointer dereferences. Fixes: 9f51c05dc41a ("pvcalls-front: Avoid get_free_pages(GFP_KERNEL) under spinlock") Reported-by: Dan Carpenter Suggested-by: Boris Ostrovsky Signed-off-by: Wen Yang Reviewed-by: Boris Ostrovsky CC: Boris Ostrovsky CC: Juergen Gross CC: Stefano Stabellini CC: Dan Carpenter CC: xen-devel@lists.xenproject.org CC: linux-kernel@vger.kernel.org Signed-off-by: Boris Ostrovsky --- drivers/xen/pvcalls-front.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 307861f9e485..8a249c95c193 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -343,6 +343,9 @@ int pvcalls_front_socket(struct socket *sock) static void free_active_ring(struct sock_mapping *map) { + if (!map->active.ring) + return; + free_pages((unsigned long)map->active.data.in, map->active.ring->ring_order); free_page((unsigned long)map->active.ring); -- cgit v1.2.3-58-ga151 From ab5098fa25b91cb6fe0a0676f17abb64f2bbf024 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Wed, 9 Jan 2019 10:57:21 +0100 Subject: ip6_gre: fix tunnel list corruption for x-netns In changelink ops, the ip6gre_net pointer is retrieved from dev_net(dev), which is wrong in case of x-netns. Thus, the tunnel is not unlinked from its current list and is relinked into another net namespace. This corrupts the tunnel lists and can later trigger a kernel oops. Fix this by retrieving the netns from device private area. Fixes: c8632fc30bb0 ("net: ip6_gre: Split up ip6gre_changelink()") Cc: Petr Machata Signed-off-by: Olivier Matz Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv6/ip6_gre.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 09d0826742f8..f2543df50035 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2025,9 +2025,9 @@ static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); + struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); struct __ip6_tnl_parm p; - struct ip6_tnl *t; t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) -- cgit v1.2.3-58-ga151 From f97f4dd8b3bb9d0993d2491e0f22024c68109184 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 9 Jan 2019 09:57:39 +0000 Subject: net: ipv4: Fix memory leak in network namespace dismantle IPv4 routing tables are flushed in two cases: 1. In response to events in the netdev and inetaddr notification chains 2. When a network namespace is being dismantled In both cases only routes associated with a dead nexthop group are flushed. However, a nexthop group will only be marked as dead in case it is populated with actual nexthops using a nexthop device. This is not the case when the route in question is an error route (e.g., 'blackhole', 'unreachable'). Therefore, when a network namespace is being dismantled such routes are not flushed and leaked [1]. To reproduce: # ip netns add blue # ip -n blue route add unreachable 192.0.2.0/24 # ip netns del blue Fix this by not skipping error routes that are not marked with RTNH_F_DEAD when flushing the routing tables. To prevent the flushing of such routes in case #1, add a parameter to fib_table_flush() that indicates if the table is flushed as part of namespace dismantle or not. Note that this problem does not exist in IPv6 since error routes are associated with the loopback device. [1] unreferenced object 0xffff888066650338 (size 56): comm "ip", pid 1206, jiffies 4294786063 (age 26.235s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 b0 1c 62 61 80 88 ff ff ..........ba.... e8 8b a1 64 80 88 ff ff 00 07 00 08 fe 00 00 00 ...d............ backtrace: [<00000000856ed27d>] inet_rtm_newroute+0x129/0x220 [<00000000fcdfc00a>] rtnetlink_rcv_msg+0x397/0xa20 [<00000000cb85801a>] netlink_rcv_skb+0x132/0x380 [<00000000ebc991d2>] netlink_unicast+0x4c0/0x690 [<0000000014f62875>] netlink_sendmsg+0x929/0xe10 [<00000000bac9d967>] sock_sendmsg+0xc8/0x110 [<00000000223e6485>] ___sys_sendmsg+0x77a/0x8f0 [<000000002e94f880>] __sys_sendmsg+0xf7/0x250 [<00000000ccb1fa72>] do_syscall_64+0x14d/0x610 [<00000000ffbe3dae>] entry_SYSCALL_64_after_hwframe+0x49/0xbe [<000000003a8b605b>] 0xffffffffffffffff unreferenced object 0xffff888061621c88 (size 48): comm "ip", pid 1206, jiffies 4294786063 (age 26.235s) hex dump (first 32 bytes): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk 6b 6b 6b 6b 6b 6b 6b 6b d8 8e 26 5f 80 88 ff ff kkkkkkkk..&_.... backtrace: [<00000000733609e3>] fib_table_insert+0x978/0x1500 [<00000000856ed27d>] inet_rtm_newroute+0x129/0x220 [<00000000fcdfc00a>] rtnetlink_rcv_msg+0x397/0xa20 [<00000000cb85801a>] netlink_rcv_skb+0x132/0x380 [<00000000ebc991d2>] netlink_unicast+0x4c0/0x690 [<0000000014f62875>] netlink_sendmsg+0x929/0xe10 [<00000000bac9d967>] sock_sendmsg+0xc8/0x110 [<00000000223e6485>] ___sys_sendmsg+0x77a/0x8f0 [<000000002e94f880>] __sys_sendmsg+0xf7/0x250 [<00000000ccb1fa72>] do_syscall_64+0x14d/0x610 [<00000000ffbe3dae>] entry_SYSCALL_64_after_hwframe+0x49/0xbe [<000000003a8b605b>] 0xffffffffffffffff Fixes: 8cced9eff1d4 ("[NETNS]: Enable routing configuration in non-initial namespace.") Signed-off-by: Ido Schimmel Reviewed-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip_fib.h | 2 +- net/ipv4/fib_frontend.c | 4 ++-- net/ipv4/fib_trie.c | 15 ++++++++++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index c5969762a8f4..9c8214d2116d 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -241,7 +241,7 @@ int fib_table_delete(struct net *, struct fib_table *, struct fib_config *, struct netlink_ext_ack *extack); int fib_table_dump(struct fib_table *table, struct sk_buff *skb, struct netlink_callback *cb, struct fib_dump_filter *filter); -int fib_table_flush(struct net *net, struct fib_table *table); +int fib_table_flush(struct net *net, struct fib_table *table, bool flush_all); struct fib_table *fib_trie_unmerge(struct fib_table *main_tb); void fib_table_flush_external(struct fib_table *table); void fib_free_table(struct fib_table *tb); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 6df95be96311..fe4f6a624238 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -203,7 +203,7 @@ static void fib_flush(struct net *net) struct fib_table *tb; hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) - flushed += fib_table_flush(net, tb); + flushed += fib_table_flush(net, tb, false); } if (flushed) @@ -1463,7 +1463,7 @@ static void ip_fib_net_exit(struct net *net) hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) { hlist_del(&tb->tb_hlist); - fib_table_flush(net, tb); + fib_table_flush(net, tb, true); fib_free_table(tb); } } diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 237c9f72b265..a573e37e0615 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1856,7 +1856,7 @@ void fib_table_flush_external(struct fib_table *tb) } /* Caller must hold RTNL. */ -int fib_table_flush(struct net *net, struct fib_table *tb) +int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all) { struct trie *t = (struct trie *)tb->tb_data; struct key_vector *pn = t->kv; @@ -1904,8 +1904,17 @@ int fib_table_flush(struct net *net, struct fib_table *tb) hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { struct fib_info *fi = fa->fa_info; - if (!fi || !(fi->fib_flags & RTNH_F_DEAD) || - tb->tb_id != fa->tb_id) { + if (!fi || tb->tb_id != fa->tb_id || + (!(fi->fib_flags & RTNH_F_DEAD) && + !fib_props[fa->fa_type].error)) { + slen = fa->fa_slen; + continue; + } + + /* Do not flush error routes if network namespace is + * not being dismantled + */ + if (!flush_all && fib_props[fa->fa_type].error) { slen = fa->fa_slen; continue; } -- cgit v1.2.3-58-ga151 From 5be99560c6a0c24b7a0cc3bb4f26051c92cdff2a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 9 Jan 2019 13:50:07 +0300 Subject: selftests/txtimestamp: Fix an equals vs assign bug This should be == instead of =. Fixes: b52354aa068e ("selftests: expand txtimestamp with ipv6 dgram + raw and pf_packet") Signed-off-by: Dan Carpenter Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/networking/timestamping/txtimestamp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/networking/timestamping/txtimestamp.c b/tools/testing/selftests/networking/timestamping/txtimestamp.c index 2e563d17cf0c..d1bbafb16f47 100644 --- a/tools/testing/selftests/networking/timestamping/txtimestamp.c +++ b/tools/testing/selftests/networking/timestamping/txtimestamp.c @@ -240,7 +240,7 @@ static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len) cm->cmsg_type == IP_RECVERR) || (cm->cmsg_level == SOL_IPV6 && cm->cmsg_type == IPV6_RECVERR) || - (cm->cmsg_level = SOL_PACKET && + (cm->cmsg_level == SOL_PACKET && cm->cmsg_type == PACKET_TX_TIMESTAMP)) { serr = (void *) CMSG_DATA(cm); if (serr->ee_errno != ENOMSG || -- cgit v1.2.3-58-ga151 From 5642e27bf6a935c1d0d9149e83d625dfba286463 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 9 Jan 2019 09:10:53 -0800 Subject: Revert "igb: reduce CPU0 latency when updating statistics" This reverts commit 59361316afcb08569af21e1af83e89c7051c055a. Due to problems found in additional testing, this causes an illegal context switch in the RCU read-side critical section. CC: Dave Jones CC: Cong Wang CC: Jan Jablonsky Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/igb/igb.h | 2 +- drivers/net/ethernet/intel/igb/igb_ethtool.c | 4 ++-- drivers/net/ethernet/intel/igb/igb_main.c | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index fe1592ae8769..ca54e268d157 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -515,7 +515,7 @@ struct igb_adapter { /* OS defined structs */ struct pci_dev *pdev; - struct mutex stats64_lock; + spinlock_t stats64_lock; struct rtnl_link_stats64 stats64; /* structs defined in e1000_hw.h */ diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 7426060b678f..c57671068245 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2295,7 +2295,7 @@ static void igb_get_ethtool_stats(struct net_device *netdev, int i, j; char *p; - mutex_lock(&adapter->stats64_lock); + spin_lock(&adapter->stats64_lock); igb_update_stats(adapter); for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { @@ -2338,7 +2338,7 @@ static void igb_get_ethtool_stats(struct net_device *netdev, } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start)); i += IGB_RX_QUEUE_STATS_LEN; } - mutex_unlock(&adapter->stats64_lock); + spin_unlock(&adapter->stats64_lock); } static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 87bdf1604ae2..7137e7f9c7f3 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2203,9 +2203,9 @@ void igb_down(struct igb_adapter *adapter) del_timer_sync(&adapter->phy_info_timer); /* record the stats before reset*/ - mutex_lock(&adapter->stats64_lock); + spin_lock(&adapter->stats64_lock); igb_update_stats(adapter); - mutex_unlock(&adapter->stats64_lock); + spin_unlock(&adapter->stats64_lock); adapter->link_speed = 0; adapter->link_duplex = 0; @@ -3840,7 +3840,7 @@ static int igb_sw_init(struct igb_adapter *adapter) adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; spin_lock_init(&adapter->nfc_lock); - mutex_init(&adapter->stats64_lock); + spin_lock_init(&adapter->stats64_lock); #ifdef CONFIG_PCI_IOV switch (hw->mac.type) { case e1000_82576: @@ -5406,9 +5406,9 @@ no_wait: } } - mutex_lock(&adapter->stats64_lock); + spin_lock(&adapter->stats64_lock); igb_update_stats(adapter); - mutex_unlock(&adapter->stats64_lock); + spin_unlock(&adapter->stats64_lock); for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *tx_ring = adapter->tx_ring[i]; @@ -6235,10 +6235,10 @@ static void igb_get_stats64(struct net_device *netdev, { struct igb_adapter *adapter = netdev_priv(netdev); - mutex_lock(&adapter->stats64_lock); + spin_lock(&adapter->stats64_lock); igb_update_stats(adapter); memcpy(stats, &adapter->stats64, sizeof(*stats)); - mutex_unlock(&adapter->stats64_lock); + spin_unlock(&adapter->stats64_lock); } /** -- cgit v1.2.3-58-ga151 From d9f903f6af3dc6d13b21c0eca8f4a169aa70d80d Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 9 Jan 2019 20:34:56 +0100 Subject: net: phy: fix too strict check in phy_start_aneg When adding checks to detect wrong usage of the phylib API we added a check to phy_start_aneg() which is too strict. If the phylib state machine is in state PHY_HALTED we should allow reconfiguring and restarting aneg, and just don't touch the state. Fixes: 2b3e88ea6528 ("net: phy: improve phy state checking") Reported-by: Chris Wilson Signed-off-by: Heiner Kallweit Tested-by: Chris Wilson Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d33e7b3caf03..189cd2048c3a 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -543,13 +543,6 @@ int phy_start_aneg(struct phy_device *phydev) mutex_lock(&phydev->lock); - if (!__phy_is_started(phydev)) { - WARN(1, "called from state %s\n", - phy_state_to_str(phydev->state)); - err = -EBUSY; - goto out_unlock; - } - if (AUTONEG_DISABLE == phydev->autoneg) phy_sanitize_settings(phydev); @@ -560,11 +553,13 @@ int phy_start_aneg(struct phy_device *phydev) if (err < 0) goto out_unlock; - if (phydev->autoneg == AUTONEG_ENABLE) { - err = phy_check_link_status(phydev); - } else { - phydev->state = PHY_FORCING; - phydev->link_timeout = PHY_FORCE_TIMEOUT; + if (__phy_is_started(phydev)) { + if (phydev->autoneg == AUTONEG_ENABLE) { + err = phy_check_link_status(phydev); + } else { + phydev->state = PHY_FORCING; + phydev->link_timeout = PHY_FORCE_TIMEOUT; + } } out_unlock: -- cgit v1.2.3-58-ga151 From 80b3671e9377916bf2b02e56113fa7377ce5705a Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 10 Jan 2019 11:17:42 +0800 Subject: ip6_gre: update version related info when changing link We forgot to update ip6erspan version related info when changing link, which will cause setting new hwid failed. Reported-by: Jianlin Shi Fixes: 94d7d8f292870 ("ip6_gre: add erspan v2 support") Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller --- net/ipv6/ip6_gre.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index f2543df50035..026f08735549 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1169,6 +1169,10 @@ static void ip6gre_tnl_copy_tnl_parm(struct ip6_tnl *t, t->parms.i_flags = p->i_flags; t->parms.o_flags = p->o_flags; t->parms.fwmark = p->fwmark; + t->parms.erspan_ver = p->erspan_ver; + t->parms.index = p->index; + t->parms.dir = p->dir; + t->parms.hwid = p->hwid; dst_cache_reset(&t->dst_cache); } -- cgit v1.2.3-58-ga151 From 0ddb0fb00a769ef85c788cb40627d09df6919833 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Tue, 15 Jan 2019 19:02:53 +0800 Subject: ASoC: qcom: Kconfig: select max98927 for sdm845 Select SND_SOC_MAX98927 for SND_SOC_SDM845. Acked-by: Srinivas Kandagatla Signed-off-by: Rohit kumar Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 804ae0d93058..7948e993adba 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -102,6 +102,7 @@ config SND_SOC_SDM845 select SND_SOC_QDSP6 select SND_SOC_QCOM_COMMON select SND_SOC_RT5663 + select SND_SOC_MAX98927 help To add support for audio on Qualcomm Technologies Inc. SDM845 SoC-based systems. -- cgit v1.2.3-58-ga151 From faa8bd6e12e6aeea289d8e6ba74777b72a69434c Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 15 Jan 2019 11:26:21 -0700 Subject: libnvdimm/security: Fix nvdimm_security_state() state request selection The input parameter should be enum nvdimm_passphrase_type instead of bool for selection of master/user for selection of extended master passphrase state or the regular user passphrase state. Fixes: 89fa9d8ea7bdf ("...add Intel DSM 1.8 master passphrase support") Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/nvdimm/nd-core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index 2b2cf4e554d3..e5ffd5733540 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -54,12 +54,12 @@ struct nvdimm { }; static inline enum nvdimm_security_state nvdimm_security_state( - struct nvdimm *nvdimm, bool master) + struct nvdimm *nvdimm, enum nvdimm_passphrase_type ptype) { if (!nvdimm->sec.ops) return -ENXIO; - return nvdimm->sec.ops->state(nvdimm, master); + return nvdimm->sec.ops->state(nvdimm, ptype); } int nvdimm_security_freeze(struct nvdimm *nvdimm); #if IS_ENABLED(CONFIG_NVDIMM_KEYS) -- cgit v1.2.3-58-ga151 From 1622745551db05071ed7263abf768007f7cbd3ae Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 5 Jan 2019 10:05:56 +0000 Subject: ACPI / LPSS: Make PCI dependency explicit After commit 5d32a66541c4 (PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set), it is possible to build ACPI without any PCI support. This code depends on PCI. Compile only when PCI is present. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Makefile | 3 ++- drivers/acpi/internal.h | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 7c6afc111d76..bb857421c2e8 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -41,7 +41,8 @@ acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-$(CONFIG_PCI) += pci_root.o pci_link.o pci_irq.o obj-$(CONFIG_ACPI_MCFG) += pci_mcfg.o -acpi-y += acpi_lpss.o acpi_apd.o +acpi-$(CONFIG_PCI) += acpi_lpss.o +acpi-y += acpi_apd.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o acpi-$(CONFIG_ARM_AMBA) += acpi_amba.o diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 7e6952edb5b0..6a9e1fb8913a 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -81,7 +81,11 @@ void acpi_debugfs_init(void); #else static inline void acpi_debugfs_init(void) { return; } #endif +#ifdef CONFIG_PCI void acpi_lpss_init(void); +#else +static inline void acpi_lpss_init(void) {} +#endif void acpi_apd_init(void); -- cgit v1.2.3-58-ga151 From 995592bc531992d4a93c37d86e7f9635ee823258 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 5 Jan 2019 10:05:57 +0000 Subject: ata: pata_acpi: Make PCI dependency explicit After commit 5d32a66541c4 (PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set) dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. PATA_ACPI is a PCI device driver but the PCI dependency has not been explicitly called out. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Acked-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sinan Kaya Reviewed-by: Jens Axboe Signed-off-by: Rafael J. Wysocki --- drivers/ata/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4ca7a6b4eaae..8218db17ebdb 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -1091,7 +1091,7 @@ comment "Generic fallback / legacy drivers" config PATA_ACPI tristate "ACPI firmware driver for PATA" - depends on ATA_ACPI && ATA_BMDMA + depends on ATA_ACPI && ATA_BMDMA && PCI help This option enables an ACPI method driver which drives motherboard PATA controller interfaces through the ACPI -- cgit v1.2.3-58-ga151 From 94e8e8e97661dc3c2a4c253755f6bfe9e2e697f3 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 5 Jan 2019 10:05:58 +0000 Subject: vga-switcheroo: make PCI dependency explicit This driver depends on the PCI infrastructure, but the dependency has not been explicitly called out. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Reviewed-by: Lukas Wunner Acked-by: Daniel Vetter Signed-off-by: Rafael J. Wysocki --- drivers/gpu/vga/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig index b677e5d524e6..d5f1d8e1c6f8 100644 --- a/drivers/gpu/vga/Kconfig +++ b/drivers/gpu/vga/Kconfig @@ -21,6 +21,7 @@ config VGA_SWITCHEROO bool "Laptop Hybrid Graphics - GPU switching support" depends on X86 depends on ACPI + depends on PCI select VGA_ARB help Many laptops released in 2008/9/10 have two GPUs with a multiplexer -- cgit v1.2.3-58-ga151 From 63680e0d625be8f4bd570d30aaf3562551e179e3 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 5 Jan 2019 10:05:59 +0000 Subject: platform/x86: intel_ips: make PCI dependency explicit After commit 5d32a66541c4 (PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set) dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. intel_ips is a PCI device driver but this has not been mentioned anywhere in Kconfig. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Acked-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/platform/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index e3b62c2ee8d1..b36ea14b41ad 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1009,7 +1009,7 @@ config INTEL_MFLD_THERMAL config INTEL_IPS tristate "Intel Intelligent Power Sharing" - depends on ACPI + depends on ACPI && PCI ---help--- Intel Calpella platforms support dynamic power sharing between the CPU and GPU, maximizing performance in a given TDP. This driver, -- cgit v1.2.3-58-ga151 From 737ee5824d91292682be7e0c0771ad67992c199f Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 5 Jan 2019 10:06:00 +0000 Subject: platform/x86: intel_pmc: Make PCI dependency explicit After commit 5d32a66541c4 (PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set) dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. Some code in intel_pmc relies on PCI for execution. Specify this in the Kconfig. [ Andy S: For sake of a quick fix this introduces a new mandatory dependency to the driver which may survive without it. Otherwise we need to revisit the driver architecture to address this properly. ] Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Signed-off-by: Rafael J. Wysocki --- drivers/platform/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index b36ea14b41ad..7afb96cb1cd6 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1174,7 +1174,7 @@ config INTEL_SMARTCONNECT config INTEL_PMC_IPC tristate "Intel PMC IPC Driver" - depends on ACPI + depends on ACPI && PCI ---help--- This driver provides support for PMC control on some Intel platforms. The PMC is an ARC processor which defines IPC commands for communication -- cgit v1.2.3-58-ga151 From 7934d76c88816f12ac991540eeece403204f8a1c Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 5 Jan 2019 10:06:01 +0000 Subject: platform/x86: apple-gmux: Make PCI dependency explicit After commit 5d32a66541c4 (PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set) dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. This driver depends on the PCI infrastructure but the dependency has not been called out explicitly yet. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Reviewed-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/platform/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 7afb96cb1cd6..5e2109c54c7c 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1135,7 +1135,7 @@ config SAMSUNG_Q10 config APPLE_GMUX tristate "Apple Gmux Driver" - depends on ACPI + depends on ACPI && PCI depends on PNP depends on BACKLIGHT_CLASS_DEVICE depends on BACKLIGHT_APPLE=n || BACKLIGHT_APPLE -- cgit v1.2.3-58-ga151 From e9820d6b0a6c85f753e8d6626320367ef12ebe15 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 5 Jan 2019 10:06:05 +0000 Subject: x86/intel/lpss: Make PCI dependency explicit After commit 5d32a66541c4 (PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set) dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. LPSS code relies on PCI infrastructure but this dependency has not been called out explicitly yet. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Signed-off-by: Rafael J. Wysocki --- arch/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 15af091611e2..4b4a7f32b68e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -617,7 +617,7 @@ config X86_INTEL_QUARK config X86_INTEL_LPSS bool "Intel Low Power Subsystem Support" - depends on X86 && ACPI + depends on X86 && ACPI && PCI select COMMON_CLK select PINCTRL select IOSF_MBI -- cgit v1.2.3-58-ga151 From 6f9b5e70dfcde983192155549f584472aa9f54cd Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 5 Jan 2019 10:06:06 +0000 Subject: drivers: thermal: int340x_thermal: Make PCI dependency explicit After commit 5d32a66541c4 (PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set) dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. IOSF_CORE depends on PCI. For this reason, add a direct dependency on CONFIG_PCI. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Signed-off-by: Rafael J. Wysocki --- drivers/thermal/intel/int340x_thermal/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/intel/int340x_thermal/Kconfig b/drivers/thermal/intel/int340x_thermal/Kconfig index 0582bd12a239..0ca908d12750 100644 --- a/drivers/thermal/intel/int340x_thermal/Kconfig +++ b/drivers/thermal/intel/int340x_thermal/Kconfig @@ -4,7 +4,7 @@ config INT340X_THERMAL tristate "ACPI INT340X thermal drivers" - depends on X86 && ACPI + depends on X86 && ACPI && PCI select THERMAL_GOV_USER_SPACE select ACPI_THERMAL_REL select ACPI_FAN -- cgit v1.2.3-58-ga151 From b1c0330823fe842dbb34641f1410f0afa51c29d3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 9 Jan 2019 00:34:37 +0100 Subject: ACPI: EC: Look for ECDT EC after calling acpi_load_tables() Some systems have had functional issues since commit 5a8361f7ecce (ACPICA: Integrate package handling with module-level code) that, among other things, changed the initial values of the acpi_gbl_group_module_level_code and acpi_gbl_parse_table_as_term_list global flags in ACPICA which implicitly caused acpi_ec_ecdt_probe() to be called before acpi_load_tables() on the vast majority of platforms. Namely, before commit 5a8361f7ecce, acpi_load_tables() was called from acpi_early_init() if acpi_gbl_parse_table_as_term_list was FALSE and acpi_gbl_group_module_level_code was TRUE, which almost always was the case as FALSE and TRUE were their initial values, respectively. The acpi_gbl_parse_table_as_term_list value would be changed to TRUE for a couple of platforms in acpi_quirks_dmi_table[], but it remained FALSE in the vast majority of cases. After commit 5a8361f7ecce, the initial values of the two flags have been reversed, so in effect acpi_load_tables() has not been called from acpi_early_init() any more. That, in turn, affects acpi_ec_ecdt_probe() which is invoked before acpi_load_tables() now and it is not possible to evaluate the _REG method for the EC address space handler installed by it. That effectively causes the EC address space to be inaccessible to AML on platforms with an ECDT matching the EC device definition in the DSDT and functional problems ensue in there. Because the default behavior before commit 5a8361f7ecce was to call acpi_ec_ecdt_probe() after acpi_load_tables(), it should be safe to do that again. Moreover, the EC address space handler installed by acpi_ec_ecdt_probe() is only needed for AML to be able to access the EC address space and the only AML that can run during acpi_load_tables() is module-level code which only is allowed to access address spaces with default handlers (memory, I/O and PCI config space). For this reason, move the acpi_ec_ecdt_probe() invocation back to acpi_bus_init(), from where it was taken away by commit d737f333b211 (ACPI: probe ECDT before loading AML tables regardless of module-level code flag), and put it after the invocation of acpi_load_tables() to restore the original code ordering from before commit 5a8361f7ecce. Fixes: 5a8361f7ecce ("ACPICA: Integrate package handling with module-level code") Link: https://bugzilla.kernel.org/show_bug.cgi?id=199981 Reported-by: step-ali Reported-by: Charles Stanhope Tested-by: Charles Stanhope Reported-by: Paulo Nascimento Reported-by: David Purton Reported-by: Adam Harvey Reported-by: Zhang Rui Tested-by: Zhang Rui Tested-by: Jean-Marc Lenoir Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 99d820a693a8..5c093ce01bcd 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1054,18 +1054,6 @@ void __init acpi_early_init(void) goto error0; } - /* - * ACPI 2.0 requires the EC driver to be loaded and work before - * the EC device is found in the namespace (i.e. before - * acpi_load_tables() is called). - * - * This is accomplished by looking for the ECDT table, and getting - * the EC parameters out of that. - * - * Ignore the result. Not having an ECDT is not fatal. - */ - status = acpi_ec_ecdt_probe(); - #ifdef CONFIG_X86 if (!acpi_ioapic) { /* compatible (0) means level (3) */ @@ -1142,6 +1130,18 @@ static int __init acpi_bus_init(void) goto error1; } + /* + * ACPI 2.0 requires the EC driver to be loaded and work before the EC + * device is found in the namespace. + * + * This is accomplished by looking for the ECDT table and getting the EC + * parameters out of that. + * + * Do that before calling acpi_initialize_objects() which may trigger EC + * address space accesses. + */ + acpi_ec_ecdt_probe(); + status = acpi_enable_subsystem(ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX -- cgit v1.2.3-58-ga151 From 77f88abd4a6f73a1a68dbdc0e3f21575fd508fc3 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 15 Jan 2019 17:31:29 -0600 Subject: PCI/MSI: Return -ENOSPC from pci_alloc_irq_vectors_affinity() The API of pci_alloc_irq_vectors_affinity() says it returns -ENOSPC if fewer than @min_vecs interrupt vectors are available for @dev. However, if a device supports MSI-X but not MSI and a caller requests @min_vecs that can't be satisfied by MSI-X, we previously returned -EINVAL (from the failed attempt to enable MSI), not -ENOSPC. When -ENOSPC is returned, callers may reduce the number IRQs they request and try again. Most callers can use the @min_vecs and @max_vecs parameters to avoid this retry loop, but that doesn't work when using IRQ affinity "nr_sets" because rebalancing the sets is driver-specific. This return value bug has been present since pci_alloc_irq_vectors() was added in v4.10 by aff171641d18 ("PCI: Provide sensible IRQ vector alloc/free routines"), but it wasn't an issue because @min_vecs/@max_vecs removed the need for callers to iteratively reduce the number of IRQs requested and retry the allocation, so they didn't need to distinguish -ENOSPC from -EINVAL. In v5.0, 6da4b3ab9a6e ("genirq/affinity: Add support for allocating interrupt sets") added IRQ sets to the interface, which reintroduced the need to check for -ENOSPC and possibly reduce the number of IRQs requested and retry the allocation. Signed-off-by: Ming Lei [bhelgaas: changelog] Signed-off-by: Bjorn Helgaas Cc: Jens Axboe Cc: Keith Busch Cc: Christoph Hellwig --- drivers/pci/msi.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 7a1c8a09efa5..4c0b47867258 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1168,7 +1168,8 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, const struct irq_affinity *affd) { static const struct irq_affinity msi_default_affd; - int vecs = -ENOSPC; + int msix_vecs = -ENOSPC; + int msi_vecs = -ENOSPC; if (flags & PCI_IRQ_AFFINITY) { if (!affd) @@ -1179,16 +1180,17 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, } if (flags & PCI_IRQ_MSIX) { - vecs = __pci_enable_msix_range(dev, NULL, min_vecs, max_vecs, - affd); - if (vecs > 0) - return vecs; + msix_vecs = __pci_enable_msix_range(dev, NULL, min_vecs, + max_vecs, affd); + if (msix_vecs > 0) + return msix_vecs; } if (flags & PCI_IRQ_MSI) { - vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, affd); - if (vecs > 0) - return vecs; + msi_vecs = __pci_enable_msi_range(dev, min_vecs, max_vecs, + affd); + if (msi_vecs > 0) + return msi_vecs; } /* use legacy irq if allowed */ @@ -1199,7 +1201,9 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, } } - return vecs; + if (msix_vecs == -ENOSPC) + return -ENOSPC; + return msi_vecs; } EXPORT_SYMBOL(pci_alloc_irq_vectors_affinity); -- cgit v1.2.3-58-ga151 From 6e8ccb4f624a73c56fc6ef0c45bcf91ca80703c3 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Tue, 15 Jan 2019 14:03:27 -0800 Subject: tools/bpf: properly account for libbfd variations On some platforms, in order to link against libbfd, we need to link against liberty and even possibly libz. Account for that in the bpftool Makefile. We now have proper feature detection for each case, so handle each one separately. See recent commit 14541b1e7e72 ("perf build: Don't unconditionally link the libbfd feature test to -liberty and -lz") where I fixed feature detection. v2 (addressed Jakub's nits): * better syntax for 'else ifeq' * no space between ifeq args v3: * use LIBS, not EXTLIBS for -DHAVE_LIBBFD_SUPPORT Fixes: 29a9c10e4110 ("bpftool: make libbfd optional") Signed-off-by: Stanislav Fomichev Acked-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 492f0f24e2d3..4ad1f0894d53 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -93,9 +93,16 @@ BFD_SRCS = jit_disasm.c SRCS = $(filter-out $(BFD_SRCS),$(wildcard *.c)) ifeq ($(feature-libbfd),1) + LIBS += -lbfd -ldl -lopcodes +else ifeq ($(feature-libbfd-liberty),1) + LIBS += -lbfd -ldl -lopcodes -liberty +else ifeq ($(feature-libbfd-liberty-z),1) + LIBS += -lbfd -ldl -lopcodes -liberty -lz +endif + +ifneq ($(filter -lbfd,$(LIBS)),) CFLAGS += -DHAVE_LIBBFD_SUPPORT SRCS += $(BFD_SRCS) -LIBS += -lbfd -lopcodes endif OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o -- cgit v1.2.3-58-ga151 From f6bab199315b70fd83fe3ee0947bc84c7a35f3d4 Mon Sep 17 00:00:00 2001 From: Toke Høiland-Jørgensen Date: Wed, 9 Jan 2019 17:09:42 +0100 Subject: sched: Avoid dereferencing skb pointer after child enqueue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parent qdiscs may dereference the pointer to the enqueued skb after enqueue. However, both CAKE and TBF call consume_skb() on the original skb when splitting GSO packets, leading to a potential use-after-free in the parent. Fix this by avoiding dereferencing the skb pointer after enqueueing to the child. Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: David S. Miller --- net/sched/sch_cbs.c | 3 ++- net/sched/sch_drr.c | 3 ++- net/sched/sch_dsmark.c | 3 ++- net/sched/sch_hfsc.c | 5 ++--- net/sched/sch_htb.c | 3 ++- net/sched/sch_prio.c | 3 ++- net/sched/sch_qfq.c | 16 +++++++++------- net/sched/sch_tbf.c | 3 ++- 8 files changed, 23 insertions(+), 16 deletions(-) diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c index e689e11b6d0f..c6a502933fe7 100644 --- a/net/sched/sch_cbs.c +++ b/net/sched/sch_cbs.c @@ -88,13 +88,14 @@ static int cbs_child_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct Qdisc *child, struct sk_buff **to_free) { + unsigned int len = qdisc_pkt_len(skb); int err; err = child->ops->enqueue(skb, child, to_free); if (err != NET_XMIT_SUCCESS) return err; - qdisc_qstats_backlog_inc(sch, skb); + sch->qstats.backlog += len; sch->q.qlen++; return NET_XMIT_SUCCESS; diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index cdebaed0f8cf..feaf47178653 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -350,6 +350,7 @@ static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch, static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { + unsigned int len = qdisc_pkt_len(skb); struct drr_sched *q = qdisc_priv(sch); struct drr_class *cl; int err = 0; @@ -376,7 +377,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, cl->deficit = cl->quantum; } - qdisc_qstats_backlog_inc(sch, skb); + sch->qstats.backlog += len; sch->q.qlen++; return err; } diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index f6f480784bc6..42471464ded3 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -199,6 +199,7 @@ static struct tcf_block *dsmark_tcf_block(struct Qdisc *sch, unsigned long cl, static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { + unsigned int len = qdisc_pkt_len(skb); struct dsmark_qdisc_data *p = qdisc_priv(sch); int err; @@ -271,7 +272,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch, return err; } - qdisc_qstats_backlog_inc(sch, skb); + sch->qstats.backlog += len; sch->q.qlen++; return NET_XMIT_SUCCESS; diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index b18ec1f6de60..6bb8f73a8473 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1539,6 +1539,7 @@ hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb) static int hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { + unsigned int len = qdisc_pkt_len(skb); struct hfsc_class *cl; int uninitialized_var(err); @@ -1560,8 +1561,6 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) } if (cl->qdisc->q.qlen == 1) { - unsigned int len = qdisc_pkt_len(skb); - if (cl->cl_flags & HFSC_RSC) init_ed(cl, len); if (cl->cl_flags & HFSC_FSC) @@ -1576,7 +1575,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) } - qdisc_qstats_backlog_inc(sch, skb); + sch->qstats.backlog += len; sch->q.qlen++; return NET_XMIT_SUCCESS; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 58b449490757..30f9da7e1076 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -581,6 +581,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { int uninitialized_var(ret); + unsigned int len = qdisc_pkt_len(skb); struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = htb_classify(skb, sch, &ret); @@ -610,7 +611,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch, htb_activate(q, cl); } - qdisc_qstats_backlog_inc(sch, skb); + sch->qstats.backlog += len; sch->q.qlen++; return NET_XMIT_SUCCESS; } diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index cdf68706e40f..847141cd900f 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -72,6 +72,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) static int prio_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { + unsigned int len = qdisc_pkt_len(skb); struct Qdisc *qdisc; int ret; @@ -88,7 +89,7 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) ret = qdisc_enqueue(skb, qdisc, to_free); if (ret == NET_XMIT_SUCCESS) { - qdisc_qstats_backlog_inc(sch, skb); + sch->qstats.backlog += len; sch->q.qlen++; return NET_XMIT_SUCCESS; } diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index dc37c4ead439..8d5e55d5bed2 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1210,6 +1210,7 @@ static struct qfq_aggregate *qfq_choose_next_agg(struct qfq_sched *q) static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { + unsigned int len = qdisc_pkt_len(skb), gso_segs; struct qfq_sched *q = qdisc_priv(sch); struct qfq_class *cl; struct qfq_aggregate *agg; @@ -1224,17 +1225,17 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, } pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid); - if (unlikely(cl->agg->lmax < qdisc_pkt_len(skb))) { + if (unlikely(cl->agg->lmax < len)) { pr_debug("qfq: increasing maxpkt from %u to %u for class %u", - cl->agg->lmax, qdisc_pkt_len(skb), cl->common.classid); - err = qfq_change_agg(sch, cl, cl->agg->class_weight, - qdisc_pkt_len(skb)); + cl->agg->lmax, len, cl->common.classid); + err = qfq_change_agg(sch, cl, cl->agg->class_weight, len); if (err) { cl->qstats.drops++; return qdisc_drop(skb, sch, to_free); } } + gso_segs = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1; err = qdisc_enqueue(skb, cl->qdisc, to_free); if (unlikely(err != NET_XMIT_SUCCESS)) { pr_debug("qfq_enqueue: enqueue failed %d\n", err); @@ -1245,8 +1246,9 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, return err; } - bstats_update(&cl->bstats, skb); - qdisc_qstats_backlog_inc(sch, skb); + cl->bstats.bytes += len; + cl->bstats.packets += gso_segs; + sch->qstats.backlog += len; ++sch->q.qlen; agg = cl->agg; @@ -1254,7 +1256,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (cl->qdisc->q.qlen != 1) { if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) && list_first_entry(&agg->active, struct qfq_class, alist) - == cl && cl->deficit < qdisc_pkt_len(skb)) + == cl && cl->deficit < len) list_move_tail(&cl->alist, &agg->active); return err; diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 942dcca09cf2..7f272a9070c5 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -185,6 +185,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { struct tbf_sched_data *q = qdisc_priv(sch); + unsigned int len = qdisc_pkt_len(skb); int ret; if (qdisc_pkt_len(skb) > q->max_size) { @@ -200,7 +201,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch, return ret; } - qdisc_qstats_backlog_inc(sch, skb); + sch->qstats.backlog += len; sch->q.qlen++; return NET_XMIT_SUCCESS; } -- cgit v1.2.3-58-ga151 From 37d9cf1a3ce35de3df6f7d209bfb1f50cf188cea Mon Sep 17 00:00:00 2001 From: Toke Høiland-Jørgensen Date: Wed, 9 Jan 2019 17:09:43 +0100 Subject: sched: Fix detection of empty queues in child qdiscs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several qdiscs check on enqueue whether the packet was enqueued to a class with an empty queue, in which case the class is activated. This is done by checking if the qlen is exactly 1 after enqueue. However, if GSO splitting is enabled in the child qdisc, a single packet can result in a qlen longer than 1. This means the activation check fails, leading to a stalled queue. Fix this by checking if the queue is empty *before* enqueue, and running the activation logic if this was the case. Reported-by: Pete Heist Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: David S. Miller --- net/sched/sch_drr.c | 4 +++- net/sched/sch_hfsc.c | 4 +++- net/sched/sch_qfq.c | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index feaf47178653..09b800991065 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -354,6 +354,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct drr_sched *q = qdisc_priv(sch); struct drr_class *cl; int err = 0; + bool first; cl = drr_classify(skb, sch, &err); if (cl == NULL) { @@ -363,6 +364,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, return err; } + first = !cl->qdisc->q.qlen; err = qdisc_enqueue(skb, cl->qdisc, to_free); if (unlikely(err != NET_XMIT_SUCCESS)) { if (net_xmit_drop_count(err)) { @@ -372,7 +374,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch, return err; } - if (cl->qdisc->q.qlen == 1) { + if (first) { list_add_tail(&cl->alist, &q->active); cl->deficit = cl->quantum; } diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 6bb8f73a8473..24cc220a3218 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1542,6 +1542,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) unsigned int len = qdisc_pkt_len(skb); struct hfsc_class *cl; int uninitialized_var(err); + bool first; cl = hfsc_classify(skb, sch, &err); if (cl == NULL) { @@ -1551,6 +1552,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) return err; } + first = !cl->qdisc->q.qlen; err = qdisc_enqueue(skb, cl->qdisc, to_free); if (unlikely(err != NET_XMIT_SUCCESS)) { if (net_xmit_drop_count(err)) { @@ -1560,7 +1562,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) return err; } - if (cl->qdisc->q.qlen == 1) { + if (first) { if (cl->cl_flags & HFSC_RSC) init_ed(cl, len); if (cl->cl_flags & HFSC_FSC) diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 8d5e55d5bed2..29f5c4a24688 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1215,6 +1215,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct qfq_class *cl; struct qfq_aggregate *agg; int err = 0; + bool first; cl = qfq_classify(skb, sch, &err); if (cl == NULL) { @@ -1236,6 +1237,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, } gso_segs = skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1; + first = !cl->qdisc->q.qlen; err = qdisc_enqueue(skb, cl->qdisc, to_free); if (unlikely(err != NET_XMIT_SUCCESS)) { pr_debug("qfq_enqueue: enqueue failed %d\n", err); @@ -1253,7 +1255,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, agg = cl->agg; /* if the queue was not empty, then done here */ - if (cl->qdisc->q.qlen != 1) { + if (!first) { if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) && list_first_entry(&agg->active, struct qfq_class, alist) == cl && cl->deficit < len) -- cgit v1.2.3-58-ga151 From 8c6c37fdc20ec9ffaa342f827a8e20afe736fb0c Mon Sep 17 00:00:00 2001 From: Toke Høiland-Jørgensen Date: Wed, 9 Jan 2019 17:09:44 +0100 Subject: sch_cake: Correctly update parent qlen when splitting GSO packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To ensure parent qdiscs have the same notion of the number of enqueued packets even after splitting a GSO packet, update the qdisc tree with the number of packets that was added due to the split. Reported-by: Pete Heist Tested-by: Pete Heist Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: David S. Miller --- net/sched/sch_cake.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index b910cd5c56f7..73940293700d 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -1667,7 +1667,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (skb_is_gso(skb) && q->rate_flags & CAKE_FLAG_SPLIT_GSO) { struct sk_buff *segs, *nskb; netdev_features_t features = netif_skb_features(skb); - unsigned int slen = 0; + unsigned int slen = 0, numsegs = 0; segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); if (IS_ERR_OR_NULL(segs)) @@ -1683,6 +1683,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, flow_queue_add(flow, segs); sch->q.qlen++; + numsegs++; slen += segs->len; q->buffer_used += segs->truesize; b->packets++; @@ -1696,7 +1697,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, sch->qstats.backlog += slen; q->avg_window_bytes += slen; - qdisc_tree_reduce_backlog(sch, 1, len); + qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); consume_skb(skb); } else { /* not splitting */ -- cgit v1.2.3-58-ga151 From a88289f4ddee4165d5f796bd99e09eec3133c16b Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Mon, 14 Jan 2019 17:22:24 +0800 Subject: tipc: fix uninit-value in in tipc_conn_rcv_sub syzbot reported: BUG: KMSAN: uninit-value in tipc_conn_rcv_sub+0x184/0x950 net/tipc/topsrv.c:373 CPU: 0 PID: 66 Comm: kworker/u4:4 Not tainted 4.17.0-rc3+ #88 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: tipc_rcv tipc_conn_recv_work Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:113 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:683 tipc_conn_rcv_sub+0x184/0x950 net/tipc/topsrv.c:373 tipc_conn_rcv_from_sock net/tipc/topsrv.c:409 [inline] tipc_conn_recv_work+0x3cd/0x560 net/tipc/topsrv.c:424 process_one_work+0x12c6/0x1f60 kernel/workqueue.c:2145 worker_thread+0x113c/0x24f0 kernel/workqueue.c:2279 kthread+0x539/0x720 kernel/kthread.c:239 ret_from_fork+0x35/0x40 arch/x86/entry/entry_64.S:412 Local variable description: ----s.i@tipc_conn_recv_work Variable was created at: tipc_conn_recv_work+0x65/0x560 net/tipc/topsrv.c:419 process_one_work+0x12c6/0x1f60 kernel/workqueue.c:2145 In tipc_conn_rcv_from_sock(), it always supposes the length of message received from sock_recvmsg() is not smaller than the size of struct tipc_subscr. However, this assumption is false. Especially when the length of received message is shorter than struct tipc_subscr size, we will end up touching uninitialized fields in tipc_conn_rcv_sub(). Reported-by: syzbot+8951a3065ee7fd6d6e23@syzkaller.appspotmail.com Reported-by: syzbot+75e6e042c5bbf691fc82@syzkaller.appspotmail.com Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/topsrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c index efb16f69bd2c..a457c0fbbef1 100644 --- a/net/tipc/topsrv.c +++ b/net/tipc/topsrv.c @@ -398,7 +398,7 @@ static int tipc_conn_rcv_from_sock(struct tipc_conn *con) ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT); if (ret == -EWOULDBLOCK) return -EWOULDBLOCK; - if (ret > 0) { + if (ret == sizeof(s)) { read_lock_bh(&sk->sk_callback_lock); ret = tipc_conn_rcv_sub(srv, con, &s); read_unlock_bh(&sk->sk_callback_lock); -- cgit v1.2.3-58-ga151 From 8b66fee7f8ee18f9c51260e7a43ab37db5177a05 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Mon, 14 Jan 2019 17:22:25 +0800 Subject: tipc: fix uninit-value in tipc_nl_compat_link_reset_stats syzbot reports following splat: BUG: KMSAN: uninit-value in strlen+0x3b/0xa0 lib/string.c:486 CPU: 1 PID: 11057 Comm: syz-executor0 Not tainted 4.20.0-rc7+ #2 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x173/0x1d0 lib/dump_stack.c:113 kmsan_report+0x12e/0x2a0 mm/kmsan/kmsan.c:613 __msan_warning+0x82/0xf0 mm/kmsan/kmsan_instr.c:295 strlen+0x3b/0xa0 lib/string.c:486 nla_put_string include/net/netlink.h:1154 [inline] tipc_nl_compat_link_reset_stats+0x1f0/0x360 net/tipc/netlink_compat.c:760 __tipc_nl_compat_doit net/tipc/netlink_compat.c:311 [inline] tipc_nl_compat_doit+0x3aa/0xaf0 net/tipc/netlink_compat.c:344 tipc_nl_compat_handle net/tipc/netlink_compat.c:1107 [inline] tipc_nl_compat_recv+0x14d7/0x2760 net/tipc/netlink_compat.c:1210 genl_family_rcv_msg net/netlink/genetlink.c:601 [inline] genl_rcv_msg+0x185f/0x1a60 net/netlink/genetlink.c:626 netlink_rcv_skb+0x444/0x640 net/netlink/af_netlink.c:2477 genl_rcv+0x63/0x80 net/netlink/genetlink.c:637 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0xf40/0x1020 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x127f/0x1300 net/netlink/af_netlink.c:1917 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] ___sys_sendmsg+0xdb9/0x11b0 net/socket.c:2116 __sys_sendmsg net/socket.c:2154 [inline] __do_sys_sendmsg net/socket.c:2163 [inline] __se_sys_sendmsg+0x305/0x460 net/socket.c:2161 __x64_sys_sendmsg+0x4a/0x70 net/socket.c:2161 do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 RIP: 0033:0x457ec9 Code: 6d b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 3b b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f2557338c78 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000457ec9 RDX: 0000000000000000 RSI: 00000000200001c0 RDI: 0000000000000003 RBP: 000000000073bf00 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f25573396d4 R13: 00000000004cb478 R14: 00000000004d86c8 R15: 00000000ffffffff Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:204 [inline] kmsan_internal_poison_shadow+0x92/0x150 mm/kmsan/kmsan.c:158 kmsan_kmalloc+0xa6/0x130 mm/kmsan/kmsan_hooks.c:176 kmsan_slab_alloc+0xe/0x10 mm/kmsan/kmsan_hooks.c:185 slab_post_alloc_hook mm/slab.h:446 [inline] slab_alloc_node mm/slub.c:2759 [inline] __kmalloc_node_track_caller+0xe18/0x1030 mm/slub.c:4383 __kmalloc_reserve net/core/skbuff.c:137 [inline] __alloc_skb+0x309/0xa20 net/core/skbuff.c:205 alloc_skb include/linux/skbuff.h:998 [inline] netlink_alloc_large_skb net/netlink/af_netlink.c:1182 [inline] netlink_sendmsg+0xb82/0x1300 net/netlink/af_netlink.c:1892 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] ___sys_sendmsg+0xdb9/0x11b0 net/socket.c:2116 __sys_sendmsg net/socket.c:2154 [inline] __do_sys_sendmsg net/socket.c:2163 [inline] __se_sys_sendmsg+0x305/0x460 net/socket.c:2161 __x64_sys_sendmsg+0x4a/0x70 net/socket.c:2161 do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 The uninitialised access happened in tipc_nl_compat_link_reset_stats: nla_put_string(skb, TIPC_NLA_LINK_NAME, name) This is because name string is not validated before it's used. Reported-by: syzbot+e01d94b5a4c266be6e4c@syzkaller.appspotmail.com Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/netlink_compat.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 77e4b2418f30..b2b115b22871 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -87,6 +87,11 @@ static int tipc_skb_tailroom(struct sk_buff *skb) return limit; } +static inline int TLV_GET_DATA_LEN(struct tlv_desc *tlv) +{ + return TLV_GET_LEN(tlv) - TLV_SPACE(0); +} + static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len) { struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(skb); @@ -166,6 +171,11 @@ static struct sk_buff *tipc_get_err_tlv(char *str) return buf; } +static inline bool string_is_valid(char *s, int len) +{ + return memchr(s, '\0', len) ? true : false; +} + static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd, struct tipc_nl_compat_msg *msg, struct sk_buff *arg) @@ -750,6 +760,7 @@ static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd, { char *name; struct nlattr *link; + int len; name = (char *)TLV_DATA(msg->req); @@ -757,6 +768,10 @@ static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd, if (!link) return -EMSGSIZE; + len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); + if (!string_is_valid(name, len)) + return -EINVAL; + if (nla_put_string(skb, TIPC_NLA_LINK_NAME, name)) return -EMSGSIZE; -- cgit v1.2.3-58-ga151 From 0762216c0ad2a2fccd63890648eca491f2c83d9a Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Mon, 14 Jan 2019 17:22:26 +0800 Subject: tipc: fix uninit-value in tipc_nl_compat_bearer_enable syzbot reported: BUG: KMSAN: uninit-value in strlen+0x3b/0xa0 lib/string.c:484 CPU: 1 PID: 6371 Comm: syz-executor652 Not tainted 4.19.0-rc8+ #70 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x306/0x460 lib/dump_stack.c:113 kmsan_report+0x1a2/0x2e0 mm/kmsan/kmsan.c:917 __msan_warning+0x7c/0xe0 mm/kmsan/kmsan_instr.c:500 strlen+0x3b/0xa0 lib/string.c:484 nla_put_string include/net/netlink.h:1011 [inline] tipc_nl_compat_bearer_enable+0x238/0x7b0 net/tipc/netlink_compat.c:389 __tipc_nl_compat_doit net/tipc/netlink_compat.c:311 [inline] tipc_nl_compat_doit+0x39f/0xae0 net/tipc/netlink_compat.c:344 tipc_nl_compat_recv+0x147c/0x2760 net/tipc/netlink_compat.c:1107 genl_family_rcv_msg net/netlink/genetlink.c:601 [inline] genl_rcv_msg+0x185c/0x1a20 net/netlink/genetlink.c:626 netlink_rcv_skb+0x394/0x640 net/netlink/af_netlink.c:2454 genl_rcv+0x63/0x80 net/netlink/genetlink.c:637 netlink_unicast_kernel net/netlink/af_netlink.c:1317 [inline] netlink_unicast+0x166d/0x1720 net/netlink/af_netlink.c:1343 netlink_sendmsg+0x1391/0x1420 net/netlink/af_netlink.c:1908 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] ___sys_sendmsg+0xe47/0x1200 net/socket.c:2116 __sys_sendmsg net/socket.c:2154 [inline] __do_sys_sendmsg net/socket.c:2163 [inline] __se_sys_sendmsg+0x307/0x460 net/socket.c:2161 __x64_sys_sendmsg+0x4a/0x70 net/socket.c:2161 do_syscall_64+0xbe/0x100 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 RIP: 0033:0x440179 Code: 18 89 d0 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 fb 13 fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007fffef7beee8 EFLAGS: 00000213 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 0000000000440179 RDX: 0000000000000000 RSI: 0000000020000100 RDI: 0000000000000003 RBP: 00000000006ca018 R08: 0000000000000000 R09: 00000000004002c8 R10: 0000000000000000 R11: 0000000000000213 R12: 0000000000401a00 R13: 0000000000401a90 R14: 0000000000000000 R15: 0000000000000000 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:255 [inline] kmsan_internal_poison_shadow+0xc8/0x1d0 mm/kmsan/kmsan.c:180 kmsan_kmalloc+0xa4/0x120 mm/kmsan/kmsan_hooks.c:104 kmsan_slab_alloc+0x10/0x20 mm/kmsan/kmsan_hooks.c:113 slab_post_alloc_hook mm/slab.h:446 [inline] slab_alloc_node mm/slub.c:2727 [inline] __kmalloc_node_track_caller+0xb43/0x1400 mm/slub.c:4360 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x422/0xe90 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:996 [inline] netlink_alloc_large_skb net/netlink/af_netlink.c:1189 [inline] netlink_sendmsg+0xcaf/0x1420 net/netlink/af_netlink.c:1883 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] ___sys_sendmsg+0xe47/0x1200 net/socket.c:2116 __sys_sendmsg net/socket.c:2154 [inline] __do_sys_sendmsg net/socket.c:2163 [inline] __se_sys_sendmsg+0x307/0x460 net/socket.c:2161 __x64_sys_sendmsg+0x4a/0x70 net/socket.c:2161 do_syscall_64+0xbe/0x100 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 The root cause is that we don't validate whether bear name is a valid string in tipc_nl_compat_bearer_enable(). Meanwhile, we also fix the same issue in the following functions: tipc_nl_compat_bearer_disable() tipc_nl_compat_link_stat_dump() tipc_nl_compat_media_set() tipc_nl_compat_bearer_set() Reported-by: syzbot+b33d5cae0efd35dbfe77@syzkaller.appspotmail.com Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/netlink_compat.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index b2b115b22871..68a0b7308936 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -389,6 +389,7 @@ static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd, struct nlattr *prop; struct nlattr *bearer; struct tipc_bearer_config *b; + int len; b = (struct tipc_bearer_config *)TLV_DATA(msg->req); @@ -396,6 +397,10 @@ static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd, if (!bearer) return -EMSGSIZE; + len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_BEARER_NAME); + if (!string_is_valid(b->name, len)) + return -EINVAL; + if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, b->name)) return -EMSGSIZE; @@ -421,6 +426,7 @@ static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd, { char *name; struct nlattr *bearer; + int len; name = (char *)TLV_DATA(msg->req); @@ -428,6 +434,10 @@ static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd, if (!bearer) return -EMSGSIZE; + len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_BEARER_NAME); + if (!string_is_valid(name, len)) + return -EINVAL; + if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, name)) return -EMSGSIZE; @@ -488,6 +498,7 @@ static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg, struct nlattr *prop[TIPC_NLA_PROP_MAX + 1]; struct nlattr *stats[TIPC_NLA_STATS_MAX + 1]; int err; + int len; if (!attrs[TIPC_NLA_LINK]) return -EINVAL; @@ -514,6 +525,11 @@ static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg, return err; name = (char *)TLV_DATA(msg->req); + + len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); + if (!string_is_valid(name, len)) + return -EINVAL; + if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0) return 0; @@ -654,6 +670,7 @@ static int tipc_nl_compat_media_set(struct sk_buff *skb, struct nlattr *prop; struct nlattr *media; struct tipc_link_config *lc; + int len; lc = (struct tipc_link_config *)TLV_DATA(msg->req); @@ -661,6 +678,10 @@ static int tipc_nl_compat_media_set(struct sk_buff *skb, if (!media) return -EMSGSIZE; + len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_MEDIA_NAME); + if (!string_is_valid(lc->name, len)) + return -EINVAL; + if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name)) return -EMSGSIZE; @@ -681,6 +702,7 @@ static int tipc_nl_compat_bearer_set(struct sk_buff *skb, struct nlattr *prop; struct nlattr *bearer; struct tipc_link_config *lc; + int len; lc = (struct tipc_link_config *)TLV_DATA(msg->req); @@ -688,6 +710,10 @@ static int tipc_nl_compat_bearer_set(struct sk_buff *skb, if (!bearer) return -EMSGSIZE; + len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_MEDIA_NAME); + if (!string_is_valid(lc->name, len)) + return -EINVAL; + if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name)) return -EMSGSIZE; -- cgit v1.2.3-58-ga151 From edf5ff04a45750ac8ce2435974f001dc9cfbf055 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Mon, 14 Jan 2019 17:22:27 +0800 Subject: tipc: fix uninit-value in tipc_nl_compat_link_set syzbot reports following splat: BUG: KMSAN: uninit-value in strlen+0x3b/0xa0 lib/string.c:486 CPU: 1 PID: 9306 Comm: syz-executor172 Not tainted 4.20.0-rc7+ #2 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x173/0x1d0 lib/dump_stack.c:113 kmsan_report+0x12e/0x2a0 mm/kmsan/kmsan.c:613 __msan_warning+0x82/0xf0 mm/kmsan/kmsan_instr.c:313 strlen+0x3b/0xa0 lib/string.c:486 nla_put_string include/net/netlink.h:1154 [inline] __tipc_nl_compat_link_set net/tipc/netlink_compat.c:708 [inline] tipc_nl_compat_link_set+0x929/0x1220 net/tipc/netlink_compat.c:744 __tipc_nl_compat_doit net/tipc/netlink_compat.c:311 [inline] tipc_nl_compat_doit+0x3aa/0xaf0 net/tipc/netlink_compat.c:344 tipc_nl_compat_handle net/tipc/netlink_compat.c:1107 [inline] tipc_nl_compat_recv+0x14d7/0x2760 net/tipc/netlink_compat.c:1210 genl_family_rcv_msg net/netlink/genetlink.c:601 [inline] genl_rcv_msg+0x185f/0x1a60 net/netlink/genetlink.c:626 netlink_rcv_skb+0x444/0x640 net/netlink/af_netlink.c:2477 genl_rcv+0x63/0x80 net/netlink/genetlink.c:637 netlink_unicast_kernel net/netlink/af_netlink.c:1310 [inline] netlink_unicast+0xf40/0x1020 net/netlink/af_netlink.c:1336 netlink_sendmsg+0x127f/0x1300 net/netlink/af_netlink.c:1917 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] ___sys_sendmsg+0xdb9/0x11b0 net/socket.c:2116 __sys_sendmsg net/socket.c:2154 [inline] __do_sys_sendmsg net/socket.c:2163 [inline] __se_sys_sendmsg+0x305/0x460 net/socket.c:2161 __x64_sys_sendmsg+0x4a/0x70 net/socket.c:2161 do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 The uninitialised access happened in nla_put_string(skb, TIPC_NLA_LINK_NAME, lc->name) This is because lc->name string is not validated before it's used. Reported-by: syzbot+d78b8a29241a195aefb8@syzkaller.appspotmail.com Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/netlink_compat.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 68a0b7308936..89e6ae3b3c33 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -762,9 +762,14 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd, struct tipc_link_config *lc; struct tipc_bearer *bearer; struct tipc_media *media; + int len; lc = (struct tipc_link_config *)TLV_DATA(msg->req); + len = min_t(int, TLV_GET_DATA_LEN(msg->req), TIPC_MAX_LINK_NAME); + if (!string_is_valid(lc->name, len)) + return -EINVAL; + media = tipc_media_find(lc->name); if (media) { cmd->doit = &__tipc_nl_media_set; -- cgit v1.2.3-58-ga151 From 974cb0e3e7c963ced06c4e32c5b2884173fa5e01 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Mon, 14 Jan 2019 17:22:28 +0800 Subject: tipc: fix uninit-value in tipc_nl_compat_name_table_dump syzbot reported: BUG: KMSAN: uninit-value in __arch_swab32 arch/x86/include/uapi/asm/swab.h:10 [inline] BUG: KMSAN: uninit-value in __fswab32 include/uapi/linux/swab.h:59 [inline] BUG: KMSAN: uninit-value in tipc_nl_compat_name_table_dump+0x4a8/0xba0 net/tipc/netlink_compat.c:826 CPU: 0 PID: 6290 Comm: syz-executor848 Not tainted 4.19.0-rc8+ #70 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x306/0x460 lib/dump_stack.c:113 kmsan_report+0x1a2/0x2e0 mm/kmsan/kmsan.c:917 __msan_warning+0x7c/0xe0 mm/kmsan/kmsan_instr.c:500 __arch_swab32 arch/x86/include/uapi/asm/swab.h:10 [inline] __fswab32 include/uapi/linux/swab.h:59 [inline] tipc_nl_compat_name_table_dump+0x4a8/0xba0 net/tipc/netlink_compat.c:826 __tipc_nl_compat_dumpit+0x59e/0xdb0 net/tipc/netlink_compat.c:205 tipc_nl_compat_dumpit+0x63a/0x820 net/tipc/netlink_compat.c:270 tipc_nl_compat_handle net/tipc/netlink_compat.c:1151 [inline] tipc_nl_compat_recv+0x1402/0x2760 net/tipc/netlink_compat.c:1210 genl_family_rcv_msg net/netlink/genetlink.c:601 [inline] genl_rcv_msg+0x185c/0x1a20 net/netlink/genetlink.c:626 netlink_rcv_skb+0x394/0x640 net/netlink/af_netlink.c:2454 genl_rcv+0x63/0x80 net/netlink/genetlink.c:637 netlink_unicast_kernel net/netlink/af_netlink.c:1317 [inline] netlink_unicast+0x166d/0x1720 net/netlink/af_netlink.c:1343 netlink_sendmsg+0x1391/0x1420 net/netlink/af_netlink.c:1908 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] ___sys_sendmsg+0xe47/0x1200 net/socket.c:2116 __sys_sendmsg net/socket.c:2154 [inline] __do_sys_sendmsg net/socket.c:2163 [inline] __se_sys_sendmsg+0x307/0x460 net/socket.c:2161 __x64_sys_sendmsg+0x4a/0x70 net/socket.c:2161 do_syscall_64+0xbe/0x100 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 RIP: 0033:0x440179 Code: 18 89 d0 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 fb 13 fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007ffecec49318 EFLAGS: 00000213 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 0000000000440179 RDX: 0000000000000000 RSI: 0000000020000100 RDI: 0000000000000003 RBP: 00000000006ca018 R08: 0000000000000000 R09: 00000000004002c8 R10: 0000000000000000 R11: 0000000000000213 R12: 0000000000401a00 R13: 0000000000401a90 R14: 0000000000000000 R15: 0000000000000000 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:255 [inline] kmsan_internal_poison_shadow+0xc8/0x1d0 mm/kmsan/kmsan.c:180 kmsan_kmalloc+0xa4/0x120 mm/kmsan/kmsan_hooks.c:104 kmsan_slab_alloc+0x10/0x20 mm/kmsan/kmsan_hooks.c:113 slab_post_alloc_hook mm/slab.h:446 [inline] slab_alloc_node mm/slub.c:2727 [inline] __kmalloc_node_track_caller+0xb43/0x1400 mm/slub.c:4360 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x422/0xe90 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:996 [inline] netlink_alloc_large_skb net/netlink/af_netlink.c:1189 [inline] netlink_sendmsg+0xcaf/0x1420 net/netlink/af_netlink.c:1883 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] ___sys_sendmsg+0xe47/0x1200 net/socket.c:2116 __sys_sendmsg net/socket.c:2154 [inline] __do_sys_sendmsg net/socket.c:2163 [inline] __se_sys_sendmsg+0x307/0x460 net/socket.c:2161 __x64_sys_sendmsg+0x4a/0x70 net/socket.c:2161 do_syscall_64+0xbe/0x100 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 We cannot take for granted the thing that the length of data contained in TLV is longer than the size of struct tipc_name_table_query in tipc_nl_compat_name_table_dump(). Reported-by: syzbot+06e771a754829716a327@syzkaller.appspotmail.com Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/netlink_compat.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 89e6ae3b3c33..b90786ca1d21 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -824,6 +824,8 @@ static int tipc_nl_compat_name_table_dump_header(struct tipc_nl_compat_msg *msg) }; ntq = (struct tipc_name_table_query *)TLV_DATA(msg->req); + if (TLV_GET_DATA_LEN(msg->req) < sizeof(struct tipc_name_table_query)) + return -EINVAL; depth = ntohl(ntq->depth); -- cgit v1.2.3-58-ga151 From 2753ca5d9009c180dbfd4c802c80983b4b6108d1 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Mon, 14 Jan 2019 17:22:29 +0800 Subject: tipc: fix uninit-value in tipc_nl_compat_doit BUG: KMSAN: uninit-value in tipc_nl_compat_doit+0x404/0xa10 net/tipc/netlink_compat.c:335 CPU: 0 PID: 4514 Comm: syz-executor485 Not tainted 4.16.0+ #87 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:683 tipc_nl_compat_doit+0x404/0xa10 net/tipc/netlink_compat.c:335 tipc_nl_compat_recv+0x164b/0x2700 net/tipc/netlink_compat.c:1153 genl_family_rcv_msg net/netlink/genetlink.c:599 [inline] genl_rcv_msg+0x1686/0x1810 net/netlink/genetlink.c:624 netlink_rcv_skb+0x378/0x600 net/netlink/af_netlink.c:2447 genl_rcv+0x63/0x80 net/netlink/genetlink.c:635 netlink_unicast_kernel net/netlink/af_netlink.c:1311 [inline] netlink_unicast+0x166b/0x1740 net/netlink/af_netlink.c:1337 netlink_sendmsg+0x1048/0x1310 net/netlink/af_netlink.c:1900 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2046 __sys_sendmsg net/socket.c:2080 [inline] SYSC_sendmsg+0x2a3/0x3d0 net/socket.c:2091 SyS_sendmsg+0x54/0x80 net/socket.c:2087 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x43fda9 RSP: 002b:00007ffd0c184ba8 EFLAGS: 00000213 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 000000000043fda9 RDX: 0000000000000000 RSI: 0000000020023000 RDI: 0000000000000003 RBP: 00000000006ca018 R08: 00000000004002c8 R09: 00000000004002c8 R10: 00000000004002c8 R11: 0000000000000213 R12: 00000000004016d0 R13: 0000000000401760 R14: 0000000000000000 R15: 0000000000000000 Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline] kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188 kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314 kmsan_slab_alloc+0x11/0x20 mm/kmsan/kmsan.c:321 slab_post_alloc_hook mm/slab.h:445 [inline] slab_alloc_node mm/slub.c:2737 [inline] __kmalloc_node_track_caller+0xaed/0x11c0 mm/slub.c:4369 __kmalloc_reserve net/core/skbuff.c:138 [inline] __alloc_skb+0x2cf/0x9f0 net/core/skbuff.c:206 alloc_skb include/linux/skbuff.h:984 [inline] netlink_alloc_large_skb net/netlink/af_netlink.c:1183 [inline] netlink_sendmsg+0x9a6/0x1310 net/netlink/af_netlink.c:1875 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg net/socket.c:640 [inline] ___sys_sendmsg+0xec0/0x1310 net/socket.c:2046 __sys_sendmsg net/socket.c:2080 [inline] SYSC_sendmsg+0x2a3/0x3d0 net/socket.c:2091 SyS_sendmsg+0x54/0x80 net/socket.c:2087 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 In tipc_nl_compat_recv(), when the len variable returned by nlmsg_attrlen() is 0, the message is still treated as a valid one, which is obviously unresonable. When len is zero, it means the message not only doesn't contain any valid TLV payload, but also TLV header is not included. Under this stituation, tlv_type field in TLV header is still accessed in tipc_nl_compat_dumpit() or tipc_nl_compat_doit(), but the field space is obviously illegal. Of course, it is not initialized. Reported-by: syzbot+bca0dc46634781f08b38@syzkaller.appspotmail.com Reported-by: syzbot+6bdb590321a7ae40c1a6@syzkaller.appspotmail.com Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/netlink_compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index b90786ca1d21..4ad3586da8f0 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -1256,7 +1256,7 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info) } len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN); - if (len && !TLV_OK(msg.req, len)) { + if (!len || !TLV_OK(msg.req, len)) { msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); err = -EOPNOTSUPP; goto send; -- cgit v1.2.3-58-ga151 From e122d845a01ece2ddd28b2f125ef2db66b8b627a Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 10 Jan 2019 16:59:13 +0000 Subject: Revert "rxrpc: Allow failed client calls to be retried" The changes introduced to allow rxrpc calls to be retried creates an issue when it comes to refcounting afs_call structs. The problem is that when rxrpc_send_data() queues the last packet for an asynchronous call, the following sequence can occur: (1) The notify_end_tx callback is invoked which causes the state in the afs_call to be changed from AFS_CALL_CL_REQUESTING or AFS_CALL_SV_REPLYING. (2) afs_deliver_to_call() can then process event notifications from rxrpc on the async_work queue. (3) Delivery of events, such as an abort from the server, can cause the afs_call state to be changed to AFS_CALL_COMPLETE on async_work. (4) For an asynchronous call, afs_process_async_call() notes that the call is complete and tried to clean up all the refs on async_work. (5) rxrpc_send_data() might return the amount of data transferred (success) or an error - which could in turn reflect a local error or a received error. Synchronising the clean up after rxrpc_kernel_send_data() returns an error with the asynchronous cleanup is then tricky to get right. Mostly revert commit c038a58ccfd6704d4d7d60ed3d6a0fca13cf13a4. The two API functions the original commit added aren't currently used. This makes rxrpc_kernel_send_data() always return successfully if it queued the data it was given. Note that this doesn't affect synchronous calls since their Rx notification function merely pokes a wait queue and does not refcounting. The asynchronous call notification function *has* to do refcounting and pass a ref over the work item to avoid the need to sync the workqueue in call cleanup. Signed-off-by: David Howells Signed-off-by: David S. Miller --- Documentation/networking/rxrpc.txt | 45 ------------------ include/net/af_rxrpc.h | 16 ------- net/rxrpc/af_rxrpc.c | 70 --------------------------- net/rxrpc/ar-internal.h | 19 +++++--- net/rxrpc/call_object.c | 97 -------------------------------------- net/rxrpc/conn_client.c | 5 +- net/rxrpc/sendmsg.c | 24 +++++----- 7 files changed, 24 insertions(+), 252 deletions(-) diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt index c9d052e0cf51..2df5894353d6 100644 --- a/Documentation/networking/rxrpc.txt +++ b/Documentation/networking/rxrpc.txt @@ -1000,51 +1000,6 @@ The kernel interface functions are as follows: size should be set when the call is begun. tx_total_len may not be less than zero. - (*) Check to see the completion state of a call so that the caller can assess - whether it needs to be retried. - - enum rxrpc_call_completion { - RXRPC_CALL_SUCCEEDED, - RXRPC_CALL_REMOTELY_ABORTED, - RXRPC_CALL_LOCALLY_ABORTED, - RXRPC_CALL_LOCAL_ERROR, - RXRPC_CALL_NETWORK_ERROR, - }; - - int rxrpc_kernel_check_call(struct socket *sock, struct rxrpc_call *call, - enum rxrpc_call_completion *_compl, - u32 *_abort_code); - - On return, -EINPROGRESS will be returned if the call is still ongoing; if - it is finished, *_compl will be set to indicate the manner of completion, - *_abort_code will be set to any abort code that occurred. 0 will be - returned on a successful completion, -ECONNABORTED will be returned if the - client failed due to a remote abort and anything else will return an - appropriate error code. - - The caller should look at this information to decide if it's worth - retrying the call. - - (*) Retry a client call. - - int rxrpc_kernel_retry_call(struct socket *sock, - struct rxrpc_call *call, - struct sockaddr_rxrpc *srx, - struct key *key); - - This attempts to partially reinitialise a call and submit it again while - reusing the original call's Tx queue to avoid the need to repackage and - re-encrypt the data to be sent. call indicates the call to retry, srx the - new address to send it to and key the encryption key to use for signing or - encrypting the packets. - - For this to work, the first Tx data packet must still be in the transmit - queue, and currently this is only permitted for local and network errors - and the call must not have been aborted. Any partially constructed Tx - packet is left as is and can continue being filled afterwards. - - It returns 0 if the call was requeued and an error otherwise. - (*) Get call RTT. u64 rxrpc_kernel_get_rtt(struct socket *sock, struct rxrpc_call *call); diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h index 1adefe42c0a6..2bfb87eb98ce 100644 --- a/include/net/af_rxrpc.h +++ b/include/net/af_rxrpc.h @@ -20,18 +20,6 @@ struct sock; struct socket; struct rxrpc_call; -/* - * Call completion condition (state == RXRPC_CALL_COMPLETE). - */ -enum rxrpc_call_completion { - RXRPC_CALL_SUCCEEDED, /* - Normal termination */ - RXRPC_CALL_REMOTELY_ABORTED, /* - call aborted by peer */ - RXRPC_CALL_LOCALLY_ABORTED, /* - call aborted locally on error or close */ - RXRPC_CALL_LOCAL_ERROR, /* - call failed due to local error */ - RXRPC_CALL_NETWORK_ERROR, /* - call terminated by network error */ - NR__RXRPC_CALL_COMPLETIONS -}; - /* * Debug ID counter for tracing. */ @@ -73,10 +61,6 @@ int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t, rxrpc_user_attach_call_t, unsigned long, gfp_t, unsigned int); void rxrpc_kernel_set_tx_length(struct socket *, struct rxrpc_call *, s64); -int rxrpc_kernel_retry_call(struct socket *, struct rxrpc_call *, - struct sockaddr_rxrpc *, struct key *); -int rxrpc_kernel_check_call(struct socket *, struct rxrpc_call *, - enum rxrpc_call_completion *, u32 *); u32 rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *); void rxrpc_kernel_probe_life(struct socket *, struct rxrpc_call *); u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *); diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index a2522f9d71e2..96f2952bbdfd 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -418,76 +418,6 @@ u32 rxrpc_kernel_get_epoch(struct socket *sock, struct rxrpc_call *call) } EXPORT_SYMBOL(rxrpc_kernel_get_epoch); -/** - * rxrpc_kernel_check_call - Check a call's state - * @sock: The socket the call is on - * @call: The call to check - * @_compl: Where to store the completion state - * @_abort_code: Where to store any abort code - * - * Allow a kernel service to query the state of a call and find out the manner - * of its termination if it has completed. Returns -EINPROGRESS if the call is - * still going, 0 if the call finished successfully, -ECONNABORTED if the call - * was aborted and an appropriate error if the call failed in some other way. - */ -int rxrpc_kernel_check_call(struct socket *sock, struct rxrpc_call *call, - enum rxrpc_call_completion *_compl, u32 *_abort_code) -{ - if (call->state != RXRPC_CALL_COMPLETE) - return -EINPROGRESS; - smp_rmb(); - *_compl = call->completion; - *_abort_code = call->abort_code; - return call->error; -} -EXPORT_SYMBOL(rxrpc_kernel_check_call); - -/** - * rxrpc_kernel_retry_call - Allow a kernel service to retry a call - * @sock: The socket the call is on - * @call: The call to retry - * @srx: The address of the peer to contact - * @key: The security context to use (defaults to socket setting) - * - * Allow a kernel service to try resending a client call that failed due to a - * network error to a new address. The Tx queue is maintained intact, thereby - * relieving the need to re-encrypt any request data that has already been - * buffered. - */ -int rxrpc_kernel_retry_call(struct socket *sock, struct rxrpc_call *call, - struct sockaddr_rxrpc *srx, struct key *key) -{ - struct rxrpc_conn_parameters cp; - struct rxrpc_sock *rx = rxrpc_sk(sock->sk); - int ret; - - _enter("%d{%d}", call->debug_id, atomic_read(&call->usage)); - - if (!key) - key = rx->key; - if (key && !key->payload.data[0]) - key = NULL; /* a no-security key */ - - memset(&cp, 0, sizeof(cp)); - cp.local = rx->local; - cp.key = key; - cp.security_level = 0; - cp.exclusive = false; - cp.service_id = srx->srx_service; - - mutex_lock(&call->user_mutex); - - ret = rxrpc_prepare_call_for_retry(rx, call); - if (ret == 0) - ret = rxrpc_retry_client_call(rx, call, &cp, srx, GFP_KERNEL); - - mutex_unlock(&call->user_mutex); - rxrpc_put_peer(cp.peer); - _leave(" = %d", ret); - return ret; -} -EXPORT_SYMBOL(rxrpc_kernel_retry_call); - /** * rxrpc_kernel_new_call_notification - Get notifications of new calls * @sock: The socket to intercept received messages on diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index bc628acf4f4f..4b1a534d290a 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -476,7 +476,6 @@ enum rxrpc_call_flag { RXRPC_CALL_EXPOSED, /* The call was exposed to the world */ RXRPC_CALL_RX_LAST, /* Received the last packet (at rxtx_top) */ RXRPC_CALL_TX_LAST, /* Last packet in Tx buffer (at rxtx_top) */ - RXRPC_CALL_TX_LASTQ, /* Last packet has been queued */ RXRPC_CALL_SEND_PING, /* A ping will need to be sent */ RXRPC_CALL_PINGING, /* Ping in process */ RXRPC_CALL_RETRANS_TIMEOUT, /* Retransmission due to timeout occurred */ @@ -517,6 +516,18 @@ enum rxrpc_call_state { NR__RXRPC_CALL_STATES }; +/* + * Call completion condition (state == RXRPC_CALL_COMPLETE). + */ +enum rxrpc_call_completion { + RXRPC_CALL_SUCCEEDED, /* - Normal termination */ + RXRPC_CALL_REMOTELY_ABORTED, /* - call aborted by peer */ + RXRPC_CALL_LOCALLY_ABORTED, /* - call aborted locally on error or close */ + RXRPC_CALL_LOCAL_ERROR, /* - call failed due to local error */ + RXRPC_CALL_NETWORK_ERROR, /* - call terminated by network error */ + NR__RXRPC_CALL_COMPLETIONS +}; + /* * Call Tx congestion management modes. */ @@ -761,15 +772,9 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *, struct sockaddr_rxrpc *, struct rxrpc_call_params *, gfp_t, unsigned int); -int rxrpc_retry_client_call(struct rxrpc_sock *, - struct rxrpc_call *, - struct rxrpc_conn_parameters *, - struct sockaddr_rxrpc *, - gfp_t); void rxrpc_incoming_call(struct rxrpc_sock *, struct rxrpc_call *, struct sk_buff *); void rxrpc_release_call(struct rxrpc_sock *, struct rxrpc_call *); -int rxrpc_prepare_call_for_retry(struct rxrpc_sock *, struct rxrpc_call *); void rxrpc_release_calls_on_socket(struct rxrpc_sock *); bool __rxrpc_queue_call(struct rxrpc_call *); bool rxrpc_queue_call(struct rxrpc_call *); diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c index 8f1a8f85b1f9..8aa2937b069f 100644 --- a/net/rxrpc/call_object.c +++ b/net/rxrpc/call_object.c @@ -324,48 +324,6 @@ error: return ERR_PTR(ret); } -/* - * Retry a call to a new address. It is expected that the Tx queue of the call - * will contain data previously packaged for an old call. - */ -int rxrpc_retry_client_call(struct rxrpc_sock *rx, - struct rxrpc_call *call, - struct rxrpc_conn_parameters *cp, - struct sockaddr_rxrpc *srx, - gfp_t gfp) -{ - const void *here = __builtin_return_address(0); - int ret; - - /* Set up or get a connection record and set the protocol parameters, - * including channel number and call ID. - */ - ret = rxrpc_connect_call(rx, call, cp, srx, gfp); - if (ret < 0) - goto error; - - trace_rxrpc_call(call, rxrpc_call_connected, atomic_read(&call->usage), - here, NULL); - - rxrpc_start_call_timer(call); - - _net("CALL new %d on CONN %d", call->debug_id, call->conn->debug_id); - - if (!test_and_set_bit(RXRPC_CALL_EV_RESEND, &call->events)) - rxrpc_queue_call(call); - - _leave(" = 0"); - return 0; - -error: - rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, - RX_CALL_DEAD, ret); - trace_rxrpc_call(call, rxrpc_call_error, atomic_read(&call->usage), - here, ERR_PTR(ret)); - _leave(" = %d", ret); - return ret; -} - /* * Set up an incoming call. call->conn points to the connection. * This is called in BH context and isn't allowed to fail. @@ -533,61 +491,6 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) _leave(""); } -/* - * Prepare a kernel service call for retry. - */ -int rxrpc_prepare_call_for_retry(struct rxrpc_sock *rx, struct rxrpc_call *call) -{ - const void *here = __builtin_return_address(0); - int i; - u8 last = 0; - - _enter("{%d,%d}", call->debug_id, atomic_read(&call->usage)); - - trace_rxrpc_call(call, rxrpc_call_release, atomic_read(&call->usage), - here, (const void *)call->flags); - - ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); - ASSERTCMP(call->completion, !=, RXRPC_CALL_REMOTELY_ABORTED); - ASSERTCMP(call->completion, !=, RXRPC_CALL_LOCALLY_ABORTED); - ASSERT(list_empty(&call->recvmsg_link)); - - del_timer_sync(&call->timer); - - _debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, call->conn); - - if (call->conn) - rxrpc_disconnect_call(call); - - if (rxrpc_is_service_call(call) || - !call->tx_phase || - call->tx_hard_ack != 0 || - call->rx_hard_ack != 0 || - call->rx_top != 0) - return -EINVAL; - - call->state = RXRPC_CALL_UNINITIALISED; - call->completion = RXRPC_CALL_SUCCEEDED; - call->call_id = 0; - call->cid = 0; - call->cong_cwnd = 0; - call->cong_extra = 0; - call->cong_ssthresh = 0; - call->cong_mode = 0; - call->cong_dup_acks = 0; - call->cong_cumul_acks = 0; - call->acks_lowest_nak = 0; - - for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) { - last |= call->rxtx_annotations[i]; - call->rxtx_annotations[i] &= RXRPC_TX_ANNO_LAST; - call->rxtx_annotations[i] |= RXRPC_TX_ANNO_RETRANS; - } - - _leave(" = 0"); - return 0; -} - /* * release all the calls associated with a socket */ diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index 521189f4b666..b2adfa825363 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c @@ -562,10 +562,7 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn, clear_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags); write_lock_bh(&call->state_lock); - if (!test_bit(RXRPC_CALL_TX_LASTQ, &call->flags)) - call->state = RXRPC_CALL_CLIENT_SEND_REQUEST; - else - call->state = RXRPC_CALL_CLIENT_AWAIT_REPLY; + call->state = RXRPC_CALL_CLIENT_SEND_REQUEST; write_unlock_bh(&call->state_lock); rxrpc_see_call(call); diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index be01f9c5d963..46c9312085b1 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -169,10 +169,8 @@ static void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call, ASSERTCMP(seq, ==, call->tx_top + 1); - if (last) { + if (last) annotation |= RXRPC_TX_ANNO_LAST; - set_bit(RXRPC_CALL_TX_LASTQ, &call->flags); - } /* We have to set the timestamp before queueing as the retransmit * algorithm can see the packet as soon as we queue it. @@ -386,6 +384,11 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, call->tx_total_len -= copy; } + /* check for the far side aborting the call or a network error + * occurring */ + if (call->state == RXRPC_CALL_COMPLETE) + goto call_terminated; + /* add the packet to the send queue if it's now full */ if (sp->remain <= 0 || (msg_data_left(msg) == 0 && !more)) { @@ -425,16 +428,6 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, notify_end_tx); skb = NULL; } - - /* Check for the far side aborting the call or a network error - * occurring. If this happens, save any packet that was under - * construction so that in the case of a network error, the - * call can be retried or redirected. - */ - if (call->state == RXRPC_CALL_COMPLETE) { - ret = call->error; - goto out; - } } while (msg_data_left(msg) > 0); success: @@ -444,6 +437,11 @@ out: _leave(" = %d", ret); return ret; +call_terminated: + rxrpc_free_skb(skb, rxrpc_skb_tx_freed); + _leave(" = %d", call->error); + return call->error; + maybe_error: if (copied) goto success; -- cgit v1.2.3-58-ga151 From 9174c3df1cd181c14913138d50ccbe539bb08335 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 10 Jan 2019 20:21:02 +0100 Subject: net/sched: act_tunnel_key: fix memory leak in case of action replace running the following TDC test cases: 7afc - Replace tunnel_key set action with all parameters 364d - Replace tunnel_key set action with all parameters and cookie it's possible to trigger kmemleak warnings like: unreferenced object 0xffff94797127ab40 (size 192): comm "tc", pid 3248, jiffies 4300565293 (age 1006.862s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 c0 93 f9 8a ff ff ff ff ................ 41 84 ee 89 ff ff ff ff 00 00 00 00 00 00 00 00 A............... backtrace: [<000000001e85b61c>] tunnel_key_init+0x31d/0x820 [act_tunnel_key] [<000000007f3f6ee7>] tcf_action_init_1+0x384/0x4c0 [<00000000e89e3ded>] tcf_action_init+0x12b/0x1a0 [<00000000c1c8c0f8>] tcf_action_add+0x73/0x170 [<0000000095a9fc28>] tc_ctl_action+0x122/0x160 [<000000004bebeac5>] rtnetlink_rcv_msg+0x263/0x2d0 [<000000009fd862dd>] netlink_rcv_skb+0x4a/0x110 [<00000000b55199e7>] netlink_unicast+0x1a0/0x250 [<000000004996cd21>] netlink_sendmsg+0x2c1/0x3c0 [<000000004d6a94b4>] sock_sendmsg+0x36/0x40 [<000000005d9f0208>] ___sys_sendmsg+0x280/0x2f0 [<00000000dec19023>] __sys_sendmsg+0x5e/0xa0 [<000000004b82ac81>] do_syscall_64+0x5b/0x180 [<00000000a0f1209a>] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [<000000002926b2ab>] 0xffffffffffffffff when the tunnel_key action is replaced, the kernel forgets to release the dst metadata: ensure they are released by tunnel_key_init(), the same way it's done in tunnel_key_release(). Fixes: d0f6dd8a914f4 ("net/sched: Introduce act_tunnel_key") Signed-off-by: Davide Caratti Acked-by: Cong Wang Signed-off-by: David S. Miller --- net/sched/act_tunnel_key.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index c3b90fadaff6..8b43fe0130f7 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -197,6 +197,15 @@ static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = { [TCA_TUNNEL_KEY_ENC_TTL] = { .type = NLA_U8 }, }; +static void tunnel_key_release_params(struct tcf_tunnel_key_params *p) +{ + if (!p) + return; + if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET) + dst_release(&p->tcft_enc_metadata->dst); + kfree_rcu(p, rcu); +} + static int tunnel_key_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, int ovr, int bind, bool rtnl_held, @@ -360,8 +369,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, rcu_swap_protected(t->params, params_new, lockdep_is_held(&t->tcf_lock)); spin_unlock_bh(&t->tcf_lock); - if (params_new) - kfree_rcu(params_new, rcu); + tunnel_key_release_params(params_new); if (ret == ACT_P_CREATED) tcf_idr_insert(tn, *a); @@ -385,12 +393,7 @@ static void tunnel_key_release(struct tc_action *a) struct tcf_tunnel_key_params *params; params = rcu_dereference_protected(t->params, 1); - if (params) { - if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) - dst_release(¶ms->tcft_enc_metadata->dst); - - kfree_rcu(params, rcu); - } + tunnel_key_release_params(params); } static int tunnel_key_geneve_opts_dump(struct sk_buff *skb, -- cgit v1.2.3-58-ga151 From 1d16073a326891c2a964e4cb95bc18fbcafb5f74 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 10 Jan 2019 20:22:26 +0100 Subject: net: phy: micrel: set soft_reset callback to genphy_soft_reset for KSZ9031 So far genphy_soft_reset was used automatically if the PHY driver didn't implement the soft_reset callback. This changed with the mentioned commit and broke KSZ9031. To fix this configure the KSZ9031 PHY driver to use genphy_soft_reset. Fixes: 6e2d85ec0559 ("net: phy: Stop with excessive soft reset") Reported-by: Tony Lindgren Signed-off-by: Heiner Kallweit Tested-by: Tony Lindgren Tested-by: Sekhar Nori Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index c33384710d26..7828d17f0662 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -1070,6 +1070,7 @@ static struct phy_driver ksphy_driver[] = { .driver_data = &ksz9021_type, .probe = kszphy_probe, .config_init = ksz9031_config_init, + .soft_reset = genphy_soft_reset, .read_status = ksz9031_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, -- cgit v1.2.3-58-ga151 From 13d7f46386e060df31b727c9975e38306fa51e7a Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 10 Jan 2019 14:40:33 -0500 Subject: tcp: allow MSG_ZEROCOPY transmission also in CLOSE_WAIT state TCP transmission with MSG_ZEROCOPY fails if the peer closes its end of the connection and so transitions this socket to CLOSE_WAIT state. Transmission in close wait state is acceptable. Other similar tests in the stack (e.g., in FastOpen) accept both states. Relax this test, too. Link: https://www.mail-archive.com/netdev@vger.kernel.org/msg276886.html Link: https://www.mail-archive.com/netdev@vger.kernel.org/msg227390.html Fixes: f214f915e7db ("tcp: enable MSG_ZEROCOPY") Reported-by: Marek Majkowski Signed-off-by: Willem de Bruijn CC: Yuchung Cheng CC: Neal Cardwell CC: Soheil Hassas Yeganeh CC: Alexey Kodanev Acked-by: Soheil Hassas Yeganeh Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 27e2f6837062..2079145a3b7c 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1186,7 +1186,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) flags = msg->msg_flags; if (flags & MSG_ZEROCOPY && size && sock_flag(sk, SOCK_ZEROCOPY)) { - if (sk->sk_state != TCP_ESTABLISHED) { + if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { err = -EINVAL; goto out_err; } -- cgit v1.2.3-58-ga151 From f275ee0fa3a06eb87edc229749cf1eb18f0663fa Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 10 Jan 2019 21:24:13 +0100 Subject: IN_BADCLASS: fix macro to actually work Commit 65cab850f0ee ("net: Allow class-e address assignment via ifconfig ioctl") modified the IN_BADCLASS macro a bit, but unfortunatly one too many '(' characters were added to the line, making any code that used it, not build properly. Also, the macro now compares an unsigned with a signed value, which isn't ok, so fix that up by making both types match properly. Reported-by: Christopher Ferris Fixes: 65cab850f0ee ("net: Allow class-e address assignment via ifconfig ioctl") Cc: Dave Taht Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller --- include/uapi/linux/in.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h index f6052e70bf40..a55cb8b10165 100644 --- a/include/uapi/linux/in.h +++ b/include/uapi/linux/in.h @@ -268,7 +268,7 @@ struct sockaddr_in { #define IN_MULTICAST(a) IN_CLASSD(a) #define IN_MULTICAST_NET 0xe0000000 -#define IN_BADCLASS(a) ((((long int) (a) ) == 0xffffffff) +#define IN_BADCLASS(a) (((long int) (a) ) == (long int)0xffffffff) #define IN_EXPERIMENTAL(a) IN_BADCLASS((a)) #define IN_CLASSE(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) -- cgit v1.2.3-58-ga151 From 8cbcdc1a51999ca81db2956608b917aacd28d837 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 10 Jan 2019 22:48:36 +0100 Subject: net: phy: marvell: Errata for mv88e6390 internal PHYs The VOD can be out of spec, unless some magic value is poked into an undocumented register in an undocumented page. Fixes: e4cf8a38fc0d ("net: phy: Marvell: Add mv88e6390 internal PHY") Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index a9c7c7f41b0c..0d6b58d1cdc0 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1046,6 +1046,39 @@ static int m88e1145_config_init(struct phy_device *phydev) return 0; } +/* The VOD can be out of specification on link up. Poke an + * undocumented register, in an undocumented page, with a magic value + * to fix this. + */ +static int m88e6390_errata(struct phy_device *phydev) +{ + int err; + + err = phy_write(phydev, MII_BMCR, + BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_FULLDPLX); + if (err) + return err; + + usleep_range(300, 400); + + err = phy_write_paged(phydev, 0xf8, 0x08, 0x36); + if (err) + return err; + + return genphy_soft_reset(phydev); +} + +static int m88e6390_config_aneg(struct phy_device *phydev) +{ + int err; + + err = m88e6390_errata(phydev); + if (err) + return err; + + return m88e1510_config_aneg(phydev); +} + /** * fiber_lpa_mod_linkmode_lpa_t * @advertising: the linkmode advertisement settings @@ -2283,7 +2316,7 @@ static struct phy_driver marvell_drivers[] = { .features = PHY_GBIT_FEATURES, .probe = m88e6390_probe, .config_init = &marvell_config_init, - .config_aneg = &m88e1510_config_aneg, + .config_aneg = &m88e6390_config_aneg, .read_status = &marvell_read_status, .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, -- cgit v1.2.3-58-ga151 From e0a7328fad9979104f73e19bedca821ef3262ae1 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 11 Jan 2019 00:15:21 +0100 Subject: net: phy: marvell: Fix deadlock from wrong locking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit m88e1318_set_wol() takes the lock as part of phy_select_page(). Don't take the lock again with phy_read(), use the unlocked __phy_read(). Fixes: 424ca4c55121 ("net: phy: marvell: fix paged access races") Reported-by: Åke Rehnman Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 0d6b58d1cdc0..2e12f982534f 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1435,7 +1435,7 @@ static int m88e1318_set_wol(struct phy_device *phydev, * before enabling it if !phy_interrupt_is_valid() */ if (!phy_interrupt_is_valid(phydev)) - phy_read(phydev, MII_M1011_IEVENT); + __phy_read(phydev, MII_M1011_IEVENT); /* Enable the WOL interrupt */ err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0, -- cgit v1.2.3-58-ga151 From e413615502a3324daba038f529932ba9a5248af0 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 11 Jan 2019 11:49:58 +0100 Subject: selftests: tc-testing: drop test on missing tunnel key id After merge of commit 80ef0f22ceda ("net/sched: act_tunnel_key: Allow key-less tunnels"), act_tunnel_key does not reject anymore requests to install 'set' rules where the key id is missing. Therefore, drop the following TDC testcase: ba4e - Add tunnel_key set action with missing mandatory id parameter because it's going to become a systematic fail as soon as userspace iproute2 will start supporting key-less tunnels. Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/tunnel_key.json | 29 ---------------------- 1 file changed, 29 deletions(-) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json b/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json index 10b2d894e436..af5e99d27229 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json @@ -81,35 +81,6 @@ ] ] }, - { - "id": "ba4e", - "name": "Add tunnel_key set action with missing mandatory id parameter", - "category": [ - "actions", - "tunnel_key" - ], - "setup": [ - [ - "$TC actions flush action tunnel_key", - 0, - 1, - 255 - ] - ], - "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2", - "expExitCode": "255", - "verifyCmd": "$TC actions list action tunnel_key", - "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2", - "matchCount": "0", - "teardown": [ - [ - "$TC actions flush action tunnel_key", - 0, - 1, - 255 - ] - ] - }, { "id": "a5e0", "name": "Add tunnel_key set action with invalid src_ip parameter", -- cgit v1.2.3-58-ga151 From 5216bd77798e2ed773ecd45f3f368dcaec63e5dd Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 11 Jan 2019 15:08:23 +0100 Subject: selftests: tc-testing: fix tunnel_key failure if dst_port is unspecified After commit 1c25324caf82 ("net/sched: act_tunnel_key: Don't dump dst port if it wasn't set"), act_tunnel_key doesn't dump anymore the destination port, unless it was explicitly configured. This caused systematic failures in the following TDC test case: 7a88 - Add tunnel_key action with cookie parameter Avoid matching zero values of TCA_TUNNEL_KEY_ENC_DST_PORT to let the test pass again. Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json b/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json index af5e99d27229..e7e15a7336b6 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json @@ -605,7 +605,7 @@ "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7 index 4 cookie aa11bb22cc33dd44ee55ff66aa11b1b2", "expExitCode": "0", "verifyCmd": "$TC actions get action tunnel_key index 4", - "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7.*dst_port 0.*csum pipe.*index 4 ref.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2", + "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7.*csum pipe.*index 4 ref.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2", "matchCount": "1", "teardown": [ "$TC actions flush action tunnel_key" -- cgit v1.2.3-58-ga151 From 26fc181e6cacacd4837da7ffe0c871134a421600 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 11 Jan 2019 06:27:35 -0800 Subject: fou, fou6: do not assume linear skbs Both gue_err() and gue6_err() incorrectly assume linear skbs. Fix them to use pskb_may_pull(). BUG: KMSAN: uninit-value in gue6_err+0x475/0xc40 net/ipv6/fou6.c:101 CPU: 0 PID: 18083 Comm: syz-executor1 Not tainted 5.0.0-rc1+ #7 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x173/0x1d0 lib/dump_stack.c:113 kmsan_report+0x12e/0x2a0 mm/kmsan/kmsan.c:600 __msan_warning+0x82/0xf0 mm/kmsan/kmsan_instr.c:313 gue6_err+0x475/0xc40 net/ipv6/fou6.c:101 __udp6_lib_err_encap_no_sk net/ipv6/udp.c:434 [inline] __udp6_lib_err_encap net/ipv6/udp.c:491 [inline] __udp6_lib_err+0x18d0/0x2590 net/ipv6/udp.c:522 udplitev6_err+0x118/0x130 net/ipv6/udplite.c:27 icmpv6_notify+0x462/0x9f0 net/ipv6/icmp.c:784 icmpv6_rcv+0x18ac/0x3fa0 net/ipv6/icmp.c:872 ip6_protocol_deliver_rcu+0xb5a/0x23a0 net/ipv6/ip6_input.c:394 ip6_input_finish net/ipv6/ip6_input.c:434 [inline] NF_HOOK include/linux/netfilter.h:289 [inline] ip6_input+0x2b6/0x350 net/ipv6/ip6_input.c:443 dst_input include/net/dst.h:450 [inline] ip6_rcv_finish+0x4e7/0x6d0 net/ipv6/ip6_input.c:76 NF_HOOK include/linux/netfilter.h:289 [inline] ipv6_rcv+0x34b/0x3f0 net/ipv6/ip6_input.c:272 __netif_receive_skb_one_core net/core/dev.c:4973 [inline] __netif_receive_skb net/core/dev.c:5083 [inline] process_backlog+0x756/0x10e0 net/core/dev.c:5923 napi_poll net/core/dev.c:6346 [inline] net_rx_action+0x78b/0x1a60 net/core/dev.c:6412 __do_softirq+0x53f/0x93a kernel/softirq.c:293 do_softirq_own_stack+0x49/0x80 arch/x86/entry/entry_64.S:1039 do_softirq kernel/softirq.c:338 [inline] __local_bh_enable_ip+0x16f/0x1a0 kernel/softirq.c:190 local_bh_enable+0x36/0x40 include/linux/bottom_half.h:32 rcu_read_unlock_bh include/linux/rcupdate.h:696 [inline] ip6_finish_output2+0x1d64/0x25f0 net/ipv6/ip6_output.c:121 ip6_finish_output+0xae4/0xbc0 net/ipv6/ip6_output.c:154 NF_HOOK_COND include/linux/netfilter.h:278 [inline] ip6_output+0x5ca/0x710 net/ipv6/ip6_output.c:171 dst_output include/net/dst.h:444 [inline] ip6_local_out+0x164/0x1d0 net/ipv6/output_core.c:176 ip6_send_skb+0xfa/0x390 net/ipv6/ip6_output.c:1727 udp_v6_send_skb+0x1733/0x1d20 net/ipv6/udp.c:1169 udpv6_sendmsg+0x424e/0x45d0 net/ipv6/udp.c:1466 inet_sendmsg+0x54a/0x720 net/ipv4/af_inet.c:798 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] ___sys_sendmsg+0xdb9/0x11b0 net/socket.c:2116 __sys_sendmmsg+0x580/0xad0 net/socket.c:2211 __do_sys_sendmmsg net/socket.c:2240 [inline] __se_sys_sendmmsg+0xbd/0xe0 net/socket.c:2237 __x64_sys_sendmmsg+0x56/0x70 net/socket.c:2237 do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 RIP: 0033:0x457ec9 Code: 6d b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 3b b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f4a5204fc78 EFLAGS: 00000246 ORIG_RAX: 0000000000000133 RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 0000000000457ec9 RDX: 00000000040001ab RSI: 0000000020000240 RDI: 0000000000000003 RBP: 000000000073bf00 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f4a520506d4 R13: 00000000004c4ce5 R14: 00000000004d85d8 R15: 00000000ffffffff Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:205 [inline] kmsan_internal_poison_shadow+0x92/0x150 mm/kmsan/kmsan.c:159 kmsan_kmalloc+0xa6/0x130 mm/kmsan/kmsan_hooks.c:176 kmsan_slab_alloc+0xe/0x10 mm/kmsan/kmsan_hooks.c:185 slab_post_alloc_hook mm/slab.h:446 [inline] slab_alloc_node mm/slub.c:2754 [inline] __kmalloc_node_track_caller+0xe9e/0xff0 mm/slub.c:4377 __kmalloc_reserve net/core/skbuff.c:140 [inline] __alloc_skb+0x309/0xa20 net/core/skbuff.c:208 alloc_skb include/linux/skbuff.h:1012 [inline] alloc_skb_with_frags+0x1c7/0xac0 net/core/skbuff.c:5288 sock_alloc_send_pskb+0xafd/0x10a0 net/core/sock.c:2091 sock_alloc_send_skb+0xca/0xe0 net/core/sock.c:2108 __ip6_append_data+0x42ed/0x5dc0 net/ipv6/ip6_output.c:1443 ip6_append_data+0x3c2/0x650 net/ipv6/ip6_output.c:1619 icmp6_send+0x2f5c/0x3c40 net/ipv6/icmp.c:574 icmpv6_send+0xe5/0x110 net/ipv6/ip6_icmp.c:43 ip6_link_failure+0x5c/0x2c0 net/ipv6/route.c:2231 dst_link_failure include/net/dst.h:427 [inline] vti_xmit net/ipv4/ip_vti.c:229 [inline] vti_tunnel_xmit+0xf3b/0x1ea0 net/ipv4/ip_vti.c:265 __netdev_start_xmit include/linux/netdevice.h:4382 [inline] netdev_start_xmit include/linux/netdevice.h:4391 [inline] xmit_one net/core/dev.c:3278 [inline] dev_hard_start_xmit+0x604/0xc40 net/core/dev.c:3294 __dev_queue_xmit+0x2e48/0x3b80 net/core/dev.c:3864 dev_queue_xmit+0x4b/0x60 net/core/dev.c:3897 neigh_direct_output+0x42/0x50 net/core/neighbour.c:1511 neigh_output include/net/neighbour.h:508 [inline] ip6_finish_output2+0x1d4e/0x25f0 net/ipv6/ip6_output.c:120 ip6_finish_output+0xae4/0xbc0 net/ipv6/ip6_output.c:154 NF_HOOK_COND include/linux/netfilter.h:278 [inline] ip6_output+0x5ca/0x710 net/ipv6/ip6_output.c:171 dst_output include/net/dst.h:444 [inline] ip6_local_out+0x164/0x1d0 net/ipv6/output_core.c:176 ip6_send_skb+0xfa/0x390 net/ipv6/ip6_output.c:1727 udp_v6_send_skb+0x1733/0x1d20 net/ipv6/udp.c:1169 udpv6_sendmsg+0x424e/0x45d0 net/ipv6/udp.c:1466 inet_sendmsg+0x54a/0x720 net/ipv4/af_inet.c:798 sock_sendmsg_nosec net/socket.c:621 [inline] sock_sendmsg net/socket.c:631 [inline] ___sys_sendmsg+0xdb9/0x11b0 net/socket.c:2116 __sys_sendmmsg+0x580/0xad0 net/socket.c:2211 __do_sys_sendmmsg net/socket.c:2240 [inline] __se_sys_sendmmsg+0xbd/0xe0 net/socket.c:2237 __x64_sys_sendmmsg+0x56/0x70 net/socket.c:2237 do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x63/0xe7 Fixes: b8a51b38e4d4 ("fou, fou6: ICMP error handlers for FoU and GUE") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Stefano Brivio Cc: Sabrina Dubroca Signed-off-by: David S. Miller --- net/ipv4/fou.c | 9 +++++++-- net/ipv6/fou6.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 632863541082..437070d1ffb1 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -1020,10 +1020,11 @@ static int gue_err(struct sk_buff *skb, u32 info) { int transport_offset = skb_transport_offset(skb); struct guehdr *guehdr; - size_t optlen; + size_t len, optlen; int ret; - if (skb->len < sizeof(struct udphdr) + sizeof(struct guehdr)) + len = sizeof(struct udphdr) + sizeof(struct guehdr); + if (!pskb_may_pull(skb, len)) return -EINVAL; guehdr = (struct guehdr *)&udp_hdr(skb)[1]; @@ -1058,6 +1059,10 @@ static int gue_err(struct sk_buff *skb, u32 info) optlen = guehdr->hlen << 2; + if (!pskb_may_pull(skb, len + optlen)) + return -EINVAL; + + guehdr = (struct guehdr *)&udp_hdr(skb)[1]; if (validate_gue_flags(guehdr, optlen)) return -EINVAL; diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c index 7da7bf3b7fe3..b858bd5280bf 100644 --- a/net/ipv6/fou6.c +++ b/net/ipv6/fou6.c @@ -90,10 +90,11 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, { int transport_offset = skb_transport_offset(skb); struct guehdr *guehdr; - size_t optlen; + size_t len, optlen; int ret; - if (skb->len < sizeof(struct udphdr) + sizeof(struct guehdr)) + len = sizeof(struct udphdr) + sizeof(struct guehdr); + if (!pskb_may_pull(skb, len)) return -EINVAL; guehdr = (struct guehdr *)&udp_hdr(skb)[1]; @@ -128,6 +129,10 @@ static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, optlen = guehdr->hlen << 2; + if (!pskb_may_pull(skb, len + optlen)) + return -EINVAL; + + guehdr = (struct guehdr *)&udp_hdr(skb)[1]; if (validate_gue_flags(guehdr, optlen)) return -EINVAL; -- cgit v1.2.3-58-ga151 From a6c7c7aac2de6be777b9805fe21848b9a323b8ff Mon Sep 17 00:00:00 2001 From: yupeng Date: Fri, 11 Jan 2019 15:07:24 -0800 Subject: net: add document for several snmp counters add document for below counters: TcpEstabResets TcpAttemptFails TcpOutRsts TcpExtTCPSACKDiscard TcpExtTCPDSACKIgnoredOld TcpExtTCPDSACKIgnoredNoUndo TcpExtTCPSackShifted TcpExtTCPSackMerged TcpExtTCPSackShiftFallback TcpExtTCPWantZeroWindowAdv TcpExtTCPToZeroWindowAdv TcpExtTCPFromZeroWindowAdv TcpExtDelayedACKs TcpExtDelayedACKLocked TcpExtDelayedACKLost TcpExtTCPLossProbes TcpExtTCPLossProbeRecovery Signed-off-by: yupeng Signed-off-by: David S. Miller --- Documentation/networking/snmp_counter.rst | 130 ++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 5 deletions(-) diff --git a/Documentation/networking/snmp_counter.rst b/Documentation/networking/snmp_counter.rst index b0dfdaaca512..fe8f741193be 100644 --- a/Documentation/networking/snmp_counter.rst +++ b/Documentation/networking/snmp_counter.rst @@ -336,7 +336,26 @@ time client replies ACK, this socket will get another chance to move to the accept queue. -TCP Fast Open +* TcpEstabResets +Defined in `RFC1213 tcpEstabResets`_. + +.. _RFC1213 tcpEstabResets: https://tools.ietf.org/html/rfc1213#page-48 + +* TcpAttemptFails +Defined in `RFC1213 tcpAttemptFails`_. + +.. _RFC1213 tcpAttemptFails: https://tools.ietf.org/html/rfc1213#page-48 + +* TcpOutRsts +Defined in `RFC1213 tcpOutRsts`_. The RFC says this counter indicates +the 'segments sent containing the RST flag', but in linux kernel, this +couner indicates the segments kerenl tried to send. The sending +process might be failed due to some errors (e.g. memory alloc failed). + +.. _RFC1213 tcpOutRsts: https://tools.ietf.org/html/rfc1213#page-52 + + +TCP Fast Path ============ When kernel receives a TCP packet, it has two paths to handler the packet, one is fast path, another is slow path. The comment in kernel @@ -383,8 +402,6 @@ increase 1. TCP abort ======== - - * TcpExtTCPAbortOnData It means TCP layer has data in flight, but need to close the connection. So TCP layer sends a RST to the other side, indicate the @@ -545,7 +562,6 @@ packet yet, the sender would know packet 4 is out of order. The TCP stack of kernel will increase TcpExtTCPSACKReorder for both of the above scenarios. - DSACK ===== The DSACK is defined in `RFC2883`_. The receiver uses DSACK to report @@ -566,13 +582,63 @@ The TCP stack receives an out of order duplicate packet, so it sends a DSACK to the sender. * TcpExtTCPDSACKRecv -The TCP stack receives a DSACK, which indicate an acknowledged +The TCP stack receives a DSACK, which indicates an acknowledged duplicate packet is received. * TcpExtTCPDSACKOfoRecv The TCP stack receives a DSACK, which indicate an out of order duplicate packet is received. +invalid SACK and DSACK +==================== +When a SACK (or DSACK) block is invalid, a corresponding counter would +be updated. The validation method is base on the start/end sequence +number of the SACK block. For more details, please refer the comment +of the function tcp_is_sackblock_valid in the kernel source code. A +SACK option could have up to 4 blocks, they are checked +individually. E.g., if 3 blocks of a SACk is invalid, the +corresponding counter would be updated 3 times. The comment of the +`Add counters for discarded SACK blocks`_ patch has additional +explaination: + +.. _Add counters for discarded SACK blocks: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=18f02545a9a16c9a89778b91a162ad16d510bb32 + +* TcpExtTCPSACKDiscard +This counter indicates how many SACK blocks are invalid. If the invalid +SACK block is caused by ACK recording, the TCP stack will only ignore +it and won't update this counter. + +* TcpExtTCPDSACKIgnoredOld and TcpExtTCPDSACKIgnoredNoUndo +When a DSACK block is invalid, one of these two counters would be +updated. Which counter will be updated depends on the undo_marker flag +of the TCP socket. If the undo_marker is not set, the TCP stack isn't +likely to re-transmit any packets, and we still receive an invalid +DSACK block, the reason might be that the packet is duplicated in the +middle of the network. In such scenario, TcpExtTCPDSACKIgnoredNoUndo +will be updated. If the undo_marker is set, TcpExtTCPDSACKIgnoredOld +will be updated. As implied in its name, it might be an old packet. + +SACK shift +========= +The linux networking stack stores data in sk_buff struct (skb for +short). If a SACK block acrosses multiple skb, the TCP stack will try +to re-arrange data in these skb. E.g. if a SACK block acknowledges seq +10 to 15, skb1 has seq 10 to 13, skb2 has seq 14 to 20. The seq 14 and +15 in skb2 would be moved to skb1. This operation is 'shift'. If a +SACK block acknowledges seq 10 to 20, skb1 has seq 10 to 13, skb2 has +seq 14 to 20. All data in skb2 will be moved to skb1, and skb2 will be +discard, this operation is 'merge'. + +* TcpExtTCPSackShifted +A skb is shifted + +* TcpExtTCPSackMerged +A skb is merged + +* TcpExtTCPSackShiftFallback +A skb should be shifted or merged, but the TCP stack doesn't do it for +some reasons. + TCP out of order =============== * TcpExtTCPOFOQueue @@ -662,6 +728,60 @@ unacknowledged number (more strict than `RFC 5961 section 5.2`_). .. _RFC 5961 section 4.2: https://tools.ietf.org/html/rfc5961#page-9 .. _RFC 5961 section 5.2: https://tools.ietf.org/html/rfc5961#page-11 +TCP receive window +================= +* TcpExtTCPWantZeroWindowAdv +Depending on current memory usage, the TCP stack tries to set receive +window to zero. But the receive window might still be a no-zero +value. For example, if the previous window size is 10, and the TCP +stack receives 3 bytes, the current window size would be 7 even if the +window size calculated by the memory usage is zero. + +* TcpExtTCPToZeroWindowAdv +The TCP receive window is set to zero from a no-zero value. + +* TcpExtTCPFromZeroWindowAdv +The TCP receive window is set to no-zero value from zero. + + +Delayed ACK +========== +The TCP Delayed ACK is a technique which is used for reducing the +packet count in the network. For more details, please refer the +`Delayed ACK wiki`_ + +.. _Delayed ACK wiki: https://en.wikipedia.org/wiki/TCP_delayed_acknowledgment + +* TcpExtDelayedACKs +A delayed ACK timer expires. The TCP stack will send a pure ACK packet +and exit the delayed ACK mode. + +* TcpExtDelayedACKLocked +A delayed ACK timer expires, but the TCP stack can't send an ACK +immediately due to the socket is locked by a userspace program. The +TCP stack will send a pure ACK later (after the userspace program +unlock the socket). When the TCP stack sends the pure ACK later, the +TCP stack will also update TcpExtDelayedACKs and exit the delayed ACK +mode. + +* TcpExtDelayedACKLost +It will be updated when the TCP stack receives a packet which has been +ACKed. A Delayed ACK loss might cause this issue, but it would also be +triggered by other reasons, such as a packet is duplicated in the +network. + +Tail Loss Probe (TLP) +=================== +TLP is an algorithm which is used to detect TCP packet loss. For more +details, please refer the `TLP paper`_. + +.. _TLP paper: https://tools.ietf.org/html/draft-dukkipati-tcpm-tcp-loss-probe-01 + +* TcpExtTCPLossProbes +A TLP probe packet is sent. + +* TcpExtTCPLossProbeRecovery +A packet loss is detected and recovered by TLP. examples ======= -- cgit v1.2.3-58-ga151 From f2f98c1d7fa81e25a5cf910edc9db4d3c6f36c1b Mon Sep 17 00:00:00 2001 From: Timotej Lazar Date: Sun, 13 Jan 2019 01:22:55 +0100 Subject: net: phy: meson-gxl: Use the genphy_soft_reset callback Since the referenced commit, Ethernet fails to come up at boot on the board meson-gxl-s905x-libretech-cc. Fix this by re-enabling the genphy_soft_reset callback for the Amlogic Meson GXL PHY driver. Fixes: 6e2d85ec0559 ("net: phy: Stop with excessive soft reset") Signed-off-by: Timotej Lazar Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/meson-gxl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c index b03bcf2c388a..3ddaf9595697 100644 --- a/drivers/net/phy/meson-gxl.c +++ b/drivers/net/phy/meson-gxl.c @@ -233,6 +233,7 @@ static struct phy_driver meson_gxl_phy[] = { .name = "Meson GXL Internal PHY", .features = PHY_BASIC_FEATURES, .flags = PHY_IS_INTERNAL, + .soft_reset = genphy_soft_reset, .config_init = meson_gxl_config_init, .aneg_done = genphy_aneg_done, .read_status = meson_gxl_read_status, -- cgit v1.2.3-58-ga151 From 2f97967503df8e45bc256a348b6f050abd2a38ed Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 15 Jan 2019 18:49:17 +0000 Subject: arm64: kpti: Update arm64_kernel_use_ng_mappings() when forced on Since commit b89d82ef01b3 ("arm64: kpti: Avoid rewriting early page tables when KASLR is enabled"), a kernel built with CONFIG_RANDOMIZE_BASE can decide early whether to use non-global mappings by checking the kaslr_offset(). A kernel built without CONFIG_RANDOMIZE_BASE, instead checks the cpufeature static-key. This leaves a gap where CONFIG_RANDOMIZE_BASE was enabled, no kaslr seed was provided, but kpti was forced on using the cmdline option. When the decision is made late, kpti_install_ng_mappings() will re-write the page tables, but arm64_kernel_use_ng_mappings()'s value does not change as it only tests the cpufeature static-key if CONFIG_RANDOMIZE_BASE is disabled. This function influences PROT_DEFAULT via PTE_MAYBE_NG, and causes pgattr_change_is_safe() to catch nG->G transitions when the unchanged PROT_DEFAULT is used as part of PAGE_KERNEL_RO: [ 1.942255] alternatives: patching kernel code [ 1.998288] ------------[ cut here ]------------ [ 2.000693] kernel BUG at arch/arm64/mm/mmu.c:165! [ 2.019215] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP [ 2.020257] Modules linked in: [ 2.020807] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.0.0-rc2 #51 [ 2.021917] Hardware name: linux,dummy-virt (DT) [ 2.022790] pstate: 40000005 (nZcv daif -PAN -UAO) [ 2.023742] pc : __create_pgd_mapping+0x508/0x6d0 [ 2.024671] lr : __create_pgd_mapping+0x500/0x6d0 [ 2.058059] Process swapper/0 (pid: 1, stack limit = 0x(____ptrval____)) [ 2.059369] Call trace: [ 2.059845] __create_pgd_mapping+0x508/0x6d0 [ 2.060684] update_mapping_prot+0x48/0xd0 [ 2.061477] mark_linear_text_alias_ro+0xdc/0xe4 [ 2.070502] smp_cpus_done+0x90/0x98 [ 2.071216] smp_init+0x100/0x114 [ 2.071878] kernel_init_freeable+0xd4/0x220 [ 2.072750] kernel_init+0x10/0x100 [ 2.073455] ret_from_fork+0x10/0x18 [ 2.075414] ---[ end trace 3572f3a7782292de ]--- [ 2.076389] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b If arm64_kernel_unmapped_at_el0() is true, arm64_kernel_use_ng_mappings() should also be true. Signed-off-by: James Morse CC: Ard Biesheuvel CC: John Garry CC: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/include/asm/mmu.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index ac352accb3d9..3e8063f4f9d3 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -60,8 +60,11 @@ static inline bool arm64_kernel_use_ng_mappings(void) * later determine that kpti is required, then * kpti_install_ng_mappings() will make them non-global. */ + if (arm64_kernel_unmapped_at_el0()) + return true; + if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE)) - return arm64_kernel_unmapped_at_el0(); + return false; /* * KASLR is enabled so we're going to be enabling kpti on non-broken -- cgit v1.2.3-58-ga151 From 1598ecda7b239e9232dda032bfddeed9d89fab6c Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 15 Jan 2019 20:47:07 +0100 Subject: arm64: kaslr: ensure randomized quantities are clean to the PoC kaslr_early_init() is called with the kernel mapped at its link time offset, and if it returns with a non-zero offset, the kernel is unmapped and remapped again at the randomized offset. During its execution, kaslr_early_init() also randomizes the base of the module region and of the linear mapping of DRAM, and sets two variables accordingly. However, since these variables are assigned with the caches on, they may get lost during the cache maintenance that occurs when unmapping and remapping the kernel, so ensure that these values are cleaned to the PoC. Acked-by: Catalin Marinas Fixes: f80fb3a3d508 ("arm64: add support for kernel ASLR") Cc: # v4.6+ Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm64/kernel/kaslr.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c index f0e6ab8abe9c..ba6b41790fcd 100644 --- a/arch/arm64/kernel/kaslr.c +++ b/arch/arm64/kernel/kaslr.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -43,7 +44,7 @@ static __init u64 get_kaslr_seed(void *fdt) return ret; } -static __init const u8 *get_cmdline(void *fdt) +static __init const u8 *kaslr_get_cmdline(void *fdt) { static __initconst const u8 default_cmdline[] = CONFIG_CMDLINE; @@ -109,7 +110,7 @@ u64 __init kaslr_early_init(u64 dt_phys) * Check if 'nokaslr' appears on the command line, and * return 0 if that is the case. */ - cmdline = get_cmdline(fdt); + cmdline = kaslr_get_cmdline(fdt); str = strstr(cmdline, "nokaslr"); if (str == cmdline || (str > cmdline && *(str - 1) == ' ')) return 0; @@ -169,5 +170,8 @@ u64 __init kaslr_early_init(u64 dt_phys) module_alloc_base += (module_range * (seed & ((1 << 21) - 1))) >> 21; module_alloc_base &= PAGE_MASK; + __flush_dcache_area(&module_alloc_base, sizeof(module_alloc_base)); + __flush_dcache_area(&memstart_offset_seed, sizeof(memstart_offset_seed)); + return offset; } -- cgit v1.2.3-58-ga151 From 7fa1e2e6afa7f4c9f46528e61de6a15d9e8dffd9 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Fri, 11 Jan 2019 14:47:40 +0100 Subject: kasan, arm64: remove redundant ARCH_SLAB_MINALIGN define Defining ARCH_SLAB_MINALIGN in arch/arm64/include/asm/cache.h when KASAN is off is not needed, as it is defined in defined in include/linux/slab.h as ifndef. Signed-off-by: Andrey Konovalov Signed-off-by: Will Deacon --- arch/arm64/include/asm/cache.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h index eb43e09c1980..926434f413fa 100644 --- a/arch/arm64/include/asm/cache.h +++ b/arch/arm64/include/asm/cache.h @@ -60,8 +60,6 @@ #ifdef CONFIG_KASAN_SW_TAGS #define ARCH_SLAB_MINALIGN (1ULL << KASAN_SHADOW_SCALE_SHIFT) -#else -#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long) #endif #ifndef __ASSEMBLY__ -- cgit v1.2.3-58-ga151 From 1138a442a0c5e97594ec63e898098b0c9e781172 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 22 Dec 2018 11:56:53 +0000 Subject: phy: ti: ensure priv is not null before dereferencing it Currently priv is being dereferenced before priv is being null checked. Fix this by moving the null check on priv before the dereference. Detected by CoverityScan, CID#1476018 ("Dereference before null check") Fixes: 92b58b34741f ("phy: ti: introduce phy-gmii-sel driver") Signed-off-by: Colin Ian King Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/ti/phy-gmii-sel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 77fdaa551977..a52c5bb35033 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -204,11 +204,11 @@ static struct phy *phy_gmii_sel_of_xlate(struct device *dev, if (args->args_count < 1) return ERR_PTR(-EINVAL); + if (!priv || !priv->if_phys) + return ERR_PTR(-ENODEV); if (priv->soc_data->features & BIT(PHY_GMII_SEL_RMII_IO_CLK_EN) && args->args_count < 2) return ERR_PTR(-EINVAL); - if (!priv || !priv->if_phys) - return ERR_PTR(-ENODEV); if (phy_id > priv->soc_data->num_ports) return ERR_PTR(-EINVAL); if (phy_id != priv->if_phys[phy_id - 1].id) -- cgit v1.2.3-58-ga151 From 4fae92797879bd58bd5d4e39c790b515bce4a1af Mon Sep 17 00:00:00 2001 From: John Hubbard Date: Sat, 12 Jan 2019 17:29:09 -0800 Subject: phy: fix build breakage: add PHY_MODE_SATA Commit 49e54187ae0b ("ata: libahci_platform: comply to PHY framework") uses the PHY_MODE_SATA, but that enum had not yet been added. This caused a build failure for me, with today's linux.git. Also, there is a potentially conflicting (mis-named) PHY_MODE_SATA, hiding in the Marvell Berlin SATA PHY driver. Fix the build by: 1) Renaming Marvell's defined value to a more scoped name, in order to avoid any potential conflicts: PHY_BERLIN_MODE_SATA. 2) Adding the missing enum, which was going to be added anyway as part of [1]. [1] https://lkml.kernel.org/r/20190108163124.6409-3-miquel.raynal@bootlin.com Fixes: 49e54187ae0b ("ata: libahci_platform: comply to PHY framework") Cc: Grzegorz Jaszczyk Cc: Miquel Raynal Cc: Hans de Goede Cc: Jens Axboe Signed-off-by: John Hubbard Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/marvell/phy-berlin-sata.c | 5 +++-- include/linux/phy/phy.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/phy/marvell/phy-berlin-sata.c b/drivers/phy/marvell/phy-berlin-sata.c index a91fc67fc4e0..d70ba9bc42d9 100644 --- a/drivers/phy/marvell/phy-berlin-sata.c +++ b/drivers/phy/marvell/phy-berlin-sata.c @@ -32,7 +32,7 @@ /* register 0x01 */ #define REF_FREF_SEL_25 BIT(0) -#define PHY_MODE_SATA (0x0 << 5) +#define PHY_BERLIN_MODE_SATA (0x0 << 5) /* register 0x02 */ #define USE_MAX_PLL_RATE BIT(12) @@ -102,7 +102,8 @@ static int phy_berlin_sata_power_on(struct phy *phy) /* set PHY mode and ref freq to 25 MHz */ phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x01, - 0x00ff, REF_FREF_SEL_25 | PHY_MODE_SATA); + 0x00ff, + REF_FREF_SEL_25 | PHY_BERLIN_MODE_SATA); /* set PHY up to 6 Gbps */ phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x25, diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index e8e118d70fd7..3f350e2749fe 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -42,6 +42,7 @@ enum phy_mode { PHY_MODE_PCIE, PHY_MODE_ETHERNET, PHY_MODE_MIPI_DPHY, + PHY_MODE_SATA }; /** -- cgit v1.2.3-58-ga151 From 009808154c69c48d5b41fc8cf5ad5ab5704efd8f Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Mon, 7 Jan 2019 20:44:53 +0100 Subject: phy: ath79-usb: Fix the power on error path In the power on function the error path doesn't return the suspend override to its proper state. It should should deassert this reset line to enable the suspend override. Signed-off-by: Alban Bedel Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/phy-ath79-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-ath79-usb.c b/drivers/phy/qualcomm/phy-ath79-usb.c index 6fd6e07ab345..f7d64f3910b4 100644 --- a/drivers/phy/qualcomm/phy-ath79-usb.c +++ b/drivers/phy/qualcomm/phy-ath79-usb.c @@ -31,7 +31,7 @@ static int ath79_usb_phy_power_on(struct phy *phy) err = reset_control_deassert(priv->reset); if (err && priv->no_suspend_override) - reset_control_assert(priv->no_suspend_override); + reset_control_deassert(priv->no_suspend_override); return err; } -- cgit v1.2.3-58-ga151 From 827cb0323928952c0db9515aba9d534fb1285b3f Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Mon, 7 Jan 2019 20:44:54 +0100 Subject: phy: ath79-usb: Fix the main reset name to match the DT binding I submitted this driver several times before it got accepted. The first series hasn't been accepted but the DTS binding did made it. I then made a second series that added generic reset support to the PHY core, this in turn required a change to the DT binding. This second series seemed to have been ignored, so I did a third one without the change to the PHY core and the DT binding update, and this last attempt finally made it. But two months later the DT binding update from the second series has been integrated too. So now the driver doesn't match the binding and the only DTS using it. This patch fix the driver to match the new binding. Signed-off-by: Alban Bedel Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/qualcomm/phy-ath79-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-ath79-usb.c b/drivers/phy/qualcomm/phy-ath79-usb.c index f7d64f3910b4..09a77e556ece 100644 --- a/drivers/phy/qualcomm/phy-ath79-usb.c +++ b/drivers/phy/qualcomm/phy-ath79-usb.c @@ -69,7 +69,7 @@ static int ath79_usb_phy_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->reset = devm_reset_control_get(&pdev->dev, "usb-phy"); + priv->reset = devm_reset_control_get(&pdev->dev, "phy"); if (IS_ERR(priv->reset)) return PTR_ERR(priv->reset); -- cgit v1.2.3-58-ga151 From 1950f462916edc9581168ca8d5882a8101e8bbcf Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 14 Jan 2019 08:19:22 +0100 Subject: HID: core: simplify active collection tracking Manually tracking an active collection to set collection parents is not necessary, we just have to look one step back into the collection stack to find the correct parent. Signed-off-by: Philipp Zabel Reviewed-by: Peter Hutterer Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-core.c | 13 ++----------- include/linux/hid.h | 1 - 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f9093dedf647..9993b692598f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -173,8 +173,8 @@ static int open_collection(struct hid_parser *parser, unsigned type) collection->type = type; collection->usage = usage; collection->level = parser->collection_stack_ptr - 1; - collection->parent_idx = parser->active_collection_idx; - parser->active_collection_idx = collection_index; + collection->parent_idx = (collection->level == 0) ? -1 : + parser->collection_stack[collection->level - 1]; if (type == HID_COLLECTION_APPLICATION) parser->device->maxapplication++; @@ -193,13 +193,6 @@ static int close_collection(struct hid_parser *parser) return -EINVAL; } parser->collection_stack_ptr--; - if (parser->active_collection_idx != -1) { - struct hid_device *device = parser->device; - struct hid_collection *c; - - c = &device->collection[parser->active_collection_idx]; - parser->active_collection_idx = c->parent_idx; - } return 0; } @@ -825,7 +818,6 @@ static int hid_scan_report(struct hid_device *hid) return -ENOMEM; parser->device = hid; - parser->active_collection_idx = -1; hid->group = HID_GROUP_GENERIC; /* @@ -1179,7 +1171,6 @@ int hid_open_report(struct hid_device *device) } parser->device = device; - parser->active_collection_idx = -1; end = start + size; diff --git a/include/linux/hid.h b/include/linux/hid.h index 992bbb7196df..f9707d1dcb58 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -658,7 +658,6 @@ struct hid_parser { unsigned int *collection_stack; unsigned int collection_stack_ptr; unsigned int collection_stack_size; - int active_collection_idx; /* device->collection */ struct hid_device *device; unsigned int scan_flags; }; -- cgit v1.2.3-58-ga151 From 7809167da5c86fd6bf309b33dee7a797e263342f Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 16 Jan 2019 19:08:15 +0800 Subject: block: don't lose track of REQ_INTEGRITY flag We need to pass bio->bi_opf after bio intergrity preparing, otherwise the flag of REQ_INTEGRITY may not be set on the allocated request, then breaks block integrity. Fixes: f9afca4d367b ("blk-mq: pass in request/bio flags to queue mapping") Cc: Hannes Reinecke Cc: Keith Busch Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- block/blk-mq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 3ba37b9e15e9..8f5b533764ca 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1906,7 +1906,7 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio) { const int is_sync = op_is_sync(bio->bi_opf); const int is_flush_fua = op_is_flush(bio->bi_opf); - struct blk_mq_alloc_data data = { .flags = 0, .cmd_flags = bio->bi_opf }; + struct blk_mq_alloc_data data = { .flags = 0}; struct request *rq; struct blk_plug *plug; struct request *same_queue_rq = NULL; @@ -1928,6 +1928,7 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio) rq_qos_throttle(q, bio); + data.cmd_flags = bio->bi_opf; rq = blk_mq_get_request(q, bio, &data); if (unlikely(!rq)) { rq_qos_cleanup(q, bio); -- cgit v1.2.3-58-ga151 From b421b8a6cb87f099466fff00d1870c2db778c617 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 14 Jan 2019 17:29:29 +0900 Subject: kbuild: remove unused archmrproper No one uses archmrproper. Signed-off-by: Masahiro Yamada --- Makefile | 4 ++-- arch/h8300/Makefile | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 499b96810995..ff1054cfca33 100644 --- a/Makefile +++ b/Makefile @@ -1360,11 +1360,11 @@ mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS)) mrproper: rm-files := $(wildcard $(MRPROPER_FILES)) mrproper-dirs := $(addprefix _mrproper_,scripts) -PHONY += $(mrproper-dirs) mrproper archmrproper +PHONY += $(mrproper-dirs) mrproper $(mrproper-dirs): $(Q)$(MAKE) $(clean)=$(patsubst _mrproper_%,%,$@) -mrproper: clean archmrproper $(mrproper-dirs) +mrproper: clean $(mrproper-dirs) $(call cmd,rmdirs) $(call cmd,rmfiles) diff --git a/arch/h8300/Makefile b/arch/h8300/Makefile index 4003ddc616e1..f801f3708a89 100644 --- a/arch/h8300/Makefile +++ b/arch/h8300/Makefile @@ -37,8 +37,6 @@ libs-y += arch/$(ARCH)/lib/ boot := arch/h8300/boot -archmrproper: - archclean: $(Q)$(MAKE) $(clean)=$(boot) -- cgit v1.2.3-58-ga151 From be3bb599d84b50d27d6077085388afabdd2ee18a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 14 Jan 2019 17:19:57 +0900 Subject: ia64: remove redundant 'export AWK' This is exported by the top Makefile. Signed-off-by: Masahiro Yamada --- arch/ia64/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 320d86f192ee..171290f9f1de 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -16,8 +16,6 @@ KBUILD_DEFCONFIG := generic_defconfig NM := $(CROSS_COMPILE)nm -B READELF := $(CROSS_COMPILE)readelf -export AWK - CHECKFLAGS += -D__ia64=1 -D__ia64__=1 -D_LP64 -D__LP64__ OBJCOPYFLAGS := --strip-all -- cgit v1.2.3-58-ga151 From 227a76b64718888c1687cc237463aa000ae6fb2b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 14 Jan 2019 21:14:08 +0100 Subject: swiotlb: clear io_tlb_start and io_tlb_end in swiotlb_exit Otherwise is_swiotlb_buffer will return false positives when we first initialize a swiotlb buffer, but then free it because we have an IOMMU available. Fixes: 55897af63091 ("dma-direct: merge swiotlb_dma_ops into the dma_direct code") Reported-by: Sibren Vasse Signed-off-by: Christoph Hellwig Tested-by: Sibren Vasse Signed-off-by: Konrad Rzeszutek Wilk --- kernel/dma/swiotlb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index d6361776dc5c..1fb6fd68b9c7 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -378,6 +378,8 @@ void __init swiotlb_exit(void) memblock_free_late(io_tlb_start, PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT)); } + io_tlb_start = 0; + io_tlb_end = 0; io_tlb_nslabs = 0; max_segment = 0; } -- cgit v1.2.3-58-ga151 From dd91642ac71208fe972a9c577ed52b6b3ba7b732 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 10 Jan 2019 05:48:39 -0500 Subject: media: v4l2-ioctl: Clear only per-plane reserved fields Currently the IOCTL code clears everything after the per-plane bytesperline field in struct v4l2_format. The intent was to only clear the per-plane reserved fields since there is data in struct v4l2_format after the per-plane format data that userspace may have filled in. Fixes: 4e1e0eb0e074 ("media: v4l2-ioctl: Zero v4l2_plane_pix_format reserved fields") Signed-off-by: Thierry Reding Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: fix checkpatch alignment warning] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 1441a73ce64c..ca85c3a9a7b9 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1552,7 +1552,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); for (i = 0; i < p->fmt.pix_mp.num_planes; i++) - CLEAR_AFTER_FIELD(p, fmt.pix_mp.plane_fmt[i].bytesperline); + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_overlay)) @@ -1582,7 +1583,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); for (i = 0; i < p->fmt.pix_mp.num_planes; i++) - CLEAR_AFTER_FIELD(p, fmt.pix_mp.plane_fmt[i].bytesperline); + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay)) @@ -1649,7 +1651,8 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); for (i = 0; i < p->fmt.pix_mp.num_planes; i++) - CLEAR_AFTER_FIELD(p, fmt.pix_mp.plane_fmt[i].bytesperline); + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_overlay)) @@ -1679,7 +1682,8 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); for (i = 0; i < p->fmt.pix_mp.num_planes; i++) - CLEAR_AFTER_FIELD(p, fmt.pix_mp.plane_fmt[i].bytesperline); + CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], + bytesperline); return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay)) -- cgit v1.2.3-58-ga151 From 9048b2e15b11c591c649cc6edc7a64fa62c15419 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 10 Jan 2019 07:43:19 -0500 Subject: media: v4l: ioctl: Validate num_planes before using it The for loop to reset the memory of the plane reserved fields runs over num_planes provided by the user without validating it. Ensure num_planes is no more than VIDEO_MAX_PLANES before the loop. Fixes: 4e1e0eb0e074 ("media: v4l2-ioctl: Zero v4l2_plane_pix_format reserved fields") Signed-off-by: Sakari Ailus Reviewed-by: Thierry Reding Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index ca85c3a9a7b9..44bc7c4f1c11 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1551,6 +1551,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + if (p->fmt.pix_mp.num_planes > VIDEO_MAX_PLANES) + break; for (i = 0; i < p->fmt.pix_mp.num_planes; i++) CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], bytesperline); @@ -1582,6 +1584,8 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + if (p->fmt.pix_mp.num_planes > VIDEO_MAX_PLANES) + break; for (i = 0; i < p->fmt.pix_mp.num_planes; i++) CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], bytesperline); @@ -1650,6 +1654,8 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + if (p->fmt.pix_mp.num_planes > VIDEO_MAX_PLANES) + break; for (i = 0; i < p->fmt.pix_mp.num_planes; i++) CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], bytesperline); @@ -1681,6 +1687,8 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); + if (p->fmt.pix_mp.num_planes > VIDEO_MAX_PLANES) + break; for (i = 0; i < p->fmt.pix_mp.num_planes; i++) CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], bytesperline); -- cgit v1.2.3-58-ga151 From 7fe9f01c04c2673bd6662c35b664f0f91888b96f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 10 Jan 2019 09:24:26 -0500 Subject: media: v4l: ioctl: Validate num_planes for debug messages The num_planes field in struct v4l2_pix_format_mplane is used in a loop before validating it. As the use is printing a debug message in this case, just cap the value to the maximum allowed. Signed-off-by: Sakari Ailus Cc: stable@vger.kernel.org Reviewed-by: Thierry Reding Signed-off-by: Hans Verkuil Cc: # for v4.12 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 44bc7c4f1c11..90aad465f9ed 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -287,6 +287,7 @@ static void v4l_print_format(const void *arg, bool write_only) const struct v4l2_window *win; const struct v4l2_sdr_format *sdr; const struct v4l2_meta_format *meta; + u32 planes; unsigned i; pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); @@ -317,7 +318,8 @@ static void v4l_print_format(const void *arg, bool write_only) prt_names(mp->field, v4l2_field_names), mp->colorspace, mp->num_planes, mp->flags, mp->ycbcr_enc, mp->quantization, mp->xfer_func); - for (i = 0; i < mp->num_planes; i++) + planes = min_t(u32, mp->num_planes, VIDEO_MAX_PLANES); + for (i = 0; i < planes; i++) printk(KERN_DEBUG "plane %u: bytesperline=%u sizeimage=%u\n", i, mp->plane_fmt[i].bytesperline, mp->plane_fmt[i].sizeimage); -- cgit v1.2.3-58-ga151 From 240809ef6630a4ce57c273c2d79ffb657cd361eb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 11 Jan 2019 07:07:25 -0500 Subject: media: vim2m: only cancel work if it is for right context cancel_delayed_work_sync() was called for any queue, but it should only be called for the queue that is associated with the currently running job. Otherwise, if two filehandles are streaming at the same time, then closing the first will cancel the work which might still be running for a job from the second filehandle. As a result the second filehandle will never be able to finish the job and an attempt to stop streaming on that second filehandle will stall. Fixes: 52117be68b82 ("media: vim2m: use cancel_delayed_work_sync instead of flush_schedule_work") Signed-off-by: Hans Verkuil Cc: # for v4.20 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vim2m.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index d01821a6906a..89d9c4c21037 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -807,7 +807,9 @@ static void vim2m_stop_streaming(struct vb2_queue *q) struct vb2_v4l2_buffer *vbuf; unsigned long flags; - cancel_delayed_work_sync(&dev->work_run); + if (v4l2_m2m_get_curr_priv(dev->m2m_dev) == ctx) + cancel_delayed_work_sync(&dev->work_run); + for (;;) { if (V4L2_TYPE_IS_OUTPUT(q->type)) vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); -- cgit v1.2.3-58-ga151 From 9019ab102fe8d741f873e6f630fb7aa74c38818a Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Tue, 15 Jan 2019 16:41:59 +0800 Subject: ASoC: sdm845: Set DAI format for dmic codec Set codec DAI format for dmic codec in startup. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown --- sound/soc/qcom/sdm845.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 6f66a58e23ca..882f52ed8231 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -248,12 +248,14 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream) break; case SECONDARY_MI2S_TX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; if (++(data->sec_mi2s_clk_count) == 1) { snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE); } snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; case QUATERNARY_TDM_RX_0: -- cgit v1.2.3-58-ga151 From 890d14d2d4b57ff5a149309da3ed36c8a529987f Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Wed, 16 Jan 2019 17:42:35 +0100 Subject: fbdev: fbmem: convert CONFIG_FB_LOGO_CENTER into a cmd line option A command line option is much more flexible than a config option and the supporting code is small. Gets rid of #ifdefs in the code too... Suggested-by: Geert Uytterhoeven Cc: Jonathan Corbet Signed-off-by: Peter Rosin Signed-off-by: Bartlomiej Zolnierkiewicz --- Documentation/fb/fbcon.txt | 8 ++++++++ drivers/video/fbdev/core/fbcon.c | 7 +++++++ drivers/video/fbdev/core/fbmem.c | 19 ++++++++++--------- drivers/video/logo/Kconfig | 9 --------- include/linux/fb.h | 1 + 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Documentation/fb/fbcon.txt b/Documentation/fb/fbcon.txt index 62af30511a95..60a5ec04e8f0 100644 --- a/Documentation/fb/fbcon.txt +++ b/Documentation/fb/fbcon.txt @@ -163,6 +163,14 @@ C. Boot options be preserved until there actually is some text is output to the console. This option causes fbcon to bind immediately to the fbdev device. +7. fbcon=logo-pos: + + The only possible 'location' is 'center' (without quotes), and when + given, the bootup logo is moved from the default top-left corner + location to the center of the framebuffer. If more than one logo is + displayed due to multiple CPUs, the collected line of logos is moved + as a whole. + C. Attaching, Detaching and Unloading Before going on to how to attach, detach and unload the framebuffer console, an diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 8976190b6c1f..bfa1360ec750 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -510,6 +510,13 @@ static int __init fb_console_setup(char *this_opt) continue; } #endif + + if (!strncmp(options, "logo-pos:", 9)) { + options += 9; + if (!strcmp(options, "center")) + fb_center_logo = true; + continue; + } } return 1; } diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 558ed2ed3124..cb43a2258c51 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -53,6 +53,9 @@ EXPORT_SYMBOL(registered_fb); int num_registered_fb __read_mostly; EXPORT_SYMBOL(num_registered_fb); +bool fb_center_logo __read_mostly; +EXPORT_SYMBOL(fb_center_logo); + static struct fb_info *get_fb_info(unsigned int idx) { struct fb_info *fb_info; @@ -506,8 +509,7 @@ static int fb_show_logo_line(struct fb_info *info, int rotate, fb_set_logo(info, logo, logo_new, fb_logo.depth); } -#ifdef CONFIG_FB_LOGO_CENTER - { + if (fb_center_logo) { int xres = info->var.xres; int yres = info->var.yres; @@ -520,11 +522,11 @@ static int fb_show_logo_line(struct fb_info *info, int rotate, --n; image.dx = (xres - n * (logo->width + 8) - 8) / 2; image.dy = y ?: (yres - logo->height) / 2; + } else { + image.dx = 0; + image.dy = y; } -#else - image.dx = 0; - image.dy = y; -#endif + image.width = logo->width; image.height = logo->height; @@ -684,9 +686,8 @@ int fb_prepare_logo(struct fb_info *info, int rotate) } height = fb_logo.logo->height; -#ifdef CONFIG_FB_LOGO_CENTER - height += (yres - fb_logo.logo->height) / 2; -#endif + if (fb_center_logo) + height += (yres - fb_logo.logo->height) / 2; return fb_prepare_extra_logos(info, height, yres); } diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 1e972c4e88b1..d1f6196c8b9a 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -10,15 +10,6 @@ menuconfig LOGO if LOGO -config FB_LOGO_CENTER - bool "Center the logo" - depends on FB=y - help - When this option is selected, the bootup logo is centered both - horizontally and vertically. If more than one logo is displayed - due to multiple CPUs, the collected line of logos is centered - as a whole. - config FB_LOGO_EXTRA bool depends on FB=y diff --git a/include/linux/fb.h b/include/linux/fb.h index 7cdd31a69719..f52ef0ad6781 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -653,6 +653,7 @@ extern int fb_new_modelist(struct fb_info *info); extern struct fb_info *registered_fb[FB_MAX]; extern int num_registered_fb; +extern bool fb_center_logo; extern struct class *fb_class; #define for_each_registered_fb(i) \ -- cgit v1.2.3-58-ga151 From fb8658581a150a859b654b154cefe3118ff4f1e0 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 9 Jan 2019 14:56:32 -0800 Subject: nvmet-tcp: fix uninitialized variable access If we end up in nvmet_tcp_try_recv_one with a bogus state queue receive state we will access result which is uninitialized. Initialize restult to 0 which will be considered as if no data was received by the tcp socket. Fixes: 872d26a391da ("nvmet-tcp: add NVMe over TCP target driver") Reported-by: Dan Carpenter Signed-off-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/nvme/target/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 44b37b202e39..ad0df786fe93 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -1089,7 +1089,7 @@ out: static int nvmet_tcp_try_recv_one(struct nvmet_tcp_queue *queue) { - int result; + int result = 0; if (unlikely(queue->rcv_state == NVMET_TCP_RECV_ERR)) return 0; -- cgit v1.2.3-58-ga151 From c45b1fa2433c65e44bdf48f513cb37289f3116b9 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 3 Jan 2019 09:34:39 +0800 Subject: nvme-pci: fix nvme_setup_irqs() When -ENOSPC is returned from pci_alloc_irq_vectors_affinity(), we still try to allocate multiple irq vectors again, so irq queues covers the admin queue actually. But we don't consider that, then number of the allocated irq vector may be same with sum of io_queues[HCTX_TYPE_DEFAULT] and io_queues[HCTX_TYPE_READ], this way is obviously wrong, and finally breaks nvme_pci_map_queues(), and warning from pci_irq_get_affinity() is triggered. IRQ queues should cover admin queues, this patch makes this point explicitely in nvme_calc_io_queues(). We got severl boot failure internal report on aarch64, so please consider to fix it in v4.20. Fixes: 6451fe73fa0f ("nvme: fix irq vs io_queue calculations") Signed-off-by: Ming Lei Reviewed-by: Keith Busch Tested-by: fin4478 Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/nvme/host/pci.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index fc9d17c317b8..89f9dd72135a 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2041,14 +2041,18 @@ static int nvme_setup_host_mem(struct nvme_dev *dev) return ret; } +/* irq_queues covers admin queue */ static void nvme_calc_io_queues(struct nvme_dev *dev, unsigned int irq_queues) { unsigned int this_w_queues = write_queues; + WARN_ON(!irq_queues); + /* - * Setup read/write queue split + * Setup read/write queue split, assign admin queue one independent + * irq vector if irq_queues is > 1. */ - if (irq_queues == 1) { + if (irq_queues <= 2) { dev->io_queues[HCTX_TYPE_DEFAULT] = 1; dev->io_queues[HCTX_TYPE_READ] = 0; return; @@ -2056,21 +2060,21 @@ static void nvme_calc_io_queues(struct nvme_dev *dev, unsigned int irq_queues) /* * If 'write_queues' is set, ensure it leaves room for at least - * one read queue + * one read queue and one admin queue */ if (this_w_queues >= irq_queues) - this_w_queues = irq_queues - 1; + this_w_queues = irq_queues - 2; /* * If 'write_queues' is set to zero, reads and writes will share * a queue set. */ if (!this_w_queues) { - dev->io_queues[HCTX_TYPE_DEFAULT] = irq_queues; + dev->io_queues[HCTX_TYPE_DEFAULT] = irq_queues - 1; dev->io_queues[HCTX_TYPE_READ] = 0; } else { dev->io_queues[HCTX_TYPE_DEFAULT] = this_w_queues; - dev->io_queues[HCTX_TYPE_READ] = irq_queues - this_w_queues; + dev->io_queues[HCTX_TYPE_READ] = irq_queues - this_w_queues - 1; } } @@ -2095,7 +2099,7 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) this_p_queues = nr_io_queues - 1; irq_queues = 1; } else { - irq_queues = nr_io_queues - this_p_queues; + irq_queues = nr_io_queues - this_p_queues + 1; } dev->io_queues[HCTX_TYPE_POLL] = this_p_queues; @@ -2115,8 +2119,9 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) * If we got a failure and we're down to asking for just * 1 + 1 queues, just ask for a single vector. We'll share * that between the single IO queue and the admin queue. + * Otherwise, we assign one independent vector to admin queue. */ - if (result >= 0 && irq_queues > 1) + if (irq_queues > 1) irq_queues = irq_sets[0] + irq_sets[1] + 1; result = pci_alloc_irq_vectors_affinity(pdev, irq_queues, -- cgit v1.2.3-58-ga151 From 867cefb4cb1012f42cada1c7d1f35ac8dd276071 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 14 Jan 2019 13:44:13 +0100 Subject: xen: Fix x86 sched_clock() interface for xen Commit f94c8d11699759 ("sched/clock, x86/tsc: Rework the x86 'unstable' sched_clock() interface") broke Xen guest time handling across migration: [ 187.249951] Freezing user space processes ... (elapsed 0.001 seconds) done. [ 187.251137] OOM killer disabled. [ 187.251137] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done. [ 187.252299] suspending xenstore... [ 187.266987] xen:grant_table: Grant tables using version 1 layout [18446743811.706476] OOM killer enabled. [18446743811.706478] Restarting tasks ... done. [18446743811.720505] Setting capacity to 16777216 Fix that by setting xen_sched_clock_offset at resume time to ensure a monotonic clock value. [boris: replaced pr_info() with pr_info_once() in xen_callback_vector() to avoid printing with incorrect timestamp during resume (as we haven't re-adjusted the clock yet)] Fixes: f94c8d11699759 ("sched/clock, x86/tsc: Rework the x86 'unstable' sched_clock() interface") Cc: # 4.11 Reported-by: Hans van Kranenburg Signed-off-by: Juergen Gross Tested-by: Hans van Kranenburg Signed-off-by: Boris Ostrovsky --- arch/x86/xen/time.c | 12 +++++++++--- drivers/xen/events/events_base.c | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 72bf446c3fee..6e29794573b7 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -361,8 +361,6 @@ void xen_timer_resume(void) { int cpu; - pvclock_resume(); - if (xen_clockevent != &xen_vcpuop_clockevent) return; @@ -379,12 +377,15 @@ static const struct pv_time_ops xen_time_ops __initconst = { }; static struct pvclock_vsyscall_time_info *xen_clock __read_mostly; +static u64 xen_clock_value_saved; void xen_save_time_memory_area(void) { struct vcpu_register_time_memory_area t; int ret; + xen_clock_value_saved = xen_clocksource_read() - xen_sched_clock_offset; + if (!xen_clock) return; @@ -404,7 +405,7 @@ void xen_restore_time_memory_area(void) int ret; if (!xen_clock) - return; + goto out; t.addr.v = &xen_clock->pvti; @@ -421,6 +422,11 @@ void xen_restore_time_memory_area(void) if (ret != 0) pr_notice("Cannot restore secondary vcpu_time_info (err %d)", ret); + +out: + /* Need pvclock_resume() before using xen_clocksource_read(). */ + pvclock_resume(); + xen_sched_clock_offset = xen_clocksource_read() - xen_clock_value_saved; } static void xen_setup_vsyscall_time_info(void) diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 93194f3e7540..117e76b2f939 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -1650,7 +1650,7 @@ void xen_callback_vector(void) xen_have_vector_callback = 0; return; } - pr_info("Xen HVM callback vector for event delivery is enabled\n"); + pr_info_once("Xen HVM callback vector for event delivery is enabled\n"); alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, xen_hvm_callback_vector); } -- cgit v1.2.3-58-ga151 From 5bbc73a841d7f0bbe025a342146dde462a796a5a Mon Sep 17 00:00:00 2001 From: Fathi Boudra Date: Wed, 16 Jan 2019 11:43:19 -0600 Subject: selftests: seccomp: use LDLIBS instead of LDFLAGS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit seccomp_bpf fails to build due to undefined reference errors: aarch64-linaro-linux-gcc --sysroot=/build/tmp-rpb-glibc/sysroots/hikey -O2 -pipe -g -feliminate-unused-debug-types -Wl,-no-as-needed -Wall -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -lpthread seccomp_bpf.c -o /build/tmp-rpb-glibc/work/hikey-linaro-linux/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf /tmp/ccrlR3MW.o: In function `tsync_sibling': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1920: undefined reference to `sem_post' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1920: undefined reference to `sem_post' /tmp/ccrlR3MW.o: In function `TSYNC_setup': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1863: undefined reference to `sem_init' /tmp/ccrlR3MW.o: In function `TSYNC_teardown': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1904: undefined reference to `sem_destroy' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1897: undefined reference to `pthread_kill' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1898: undefined reference to `pthread_cancel' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1899: undefined reference to `pthread_join' /tmp/ccrlR3MW.o: In function `tsync_start_sibling': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /tmp/ccrlR3MW.o: In function `TSYNC_siblings_fail_prctl': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1978: undefined reference to `sem_wait' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1990: undefined reference to `pthread_join' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1992: undefined reference to `pthread_join' /tmp/ccrlR3MW.o: In function `tsync_start_sibling': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /tmp/ccrlR3MW.o: In function `TSYNC_two_siblings_with_ancestor': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2016: undefined reference to `sem_wait' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2032: undefined reference to `pthread_join' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2034: undefined reference to `pthread_join' /tmp/ccrlR3MW.o: In function `tsync_start_sibling': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /tmp/ccrlR3MW.o: In function `TSYNC_two_sibling_want_nnp': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2046: undefined reference to `sem_wait' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2058: undefined reference to `pthread_join' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2060: undefined reference to `pthread_join' /tmp/ccrlR3MW.o: In function `tsync_start_sibling': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /tmp/ccrlR3MW.o: In function `TSYNC_two_siblings_with_no_filter': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2073: undefined reference to `sem_wait' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2098: undefined reference to `pthread_join' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2100: undefined reference to `pthread_join' /tmp/ccrlR3MW.o: In function `tsync_start_sibling': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /tmp/ccrlR3MW.o: In function `TSYNC_two_siblings_with_one_divergence': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2125: undefined reference to `sem_wait' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2143: undefined reference to `pthread_join' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2145: undefined reference to `pthread_join' /tmp/ccrlR3MW.o: In function `tsync_start_sibling': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' /tmp/ccrlR3MW.o: In function `TSYNC_two_siblings_not_under_filter': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2169: undefined reference to `sem_wait' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2202: undefined reference to `pthread_join' /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:2227: undefined reference to `pthread_join' /tmp/ccrlR3MW.o: In function `tsync_start_sibling': /usr/src/debug/kselftests/4.12-r0/linux-4.12-rc7/tools/testing/selftests/seccomp/seccomp_bpf.c:1941: undefined reference to `pthread_create' It's GNU Make and linker specific. The default Makefile rule looks like: $(CC) $(CFLAGS) $(LDFLAGS) $@ $^ $(LDLIBS) When linking is done by gcc itself, no issue, but when it needs to be passed to proper ld, only LDLIBS follows and then ld cannot know what libs to link with. More detail: https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html LDFLAGS Extra flags to give to compilers when they are supposed to invoke the linker, ‘ld’, such as -L. Libraries (-lfoo) should be added to the LDLIBS variable instead. LDLIBS Library flags or names given to compilers when they are supposed to invoke the linker, ‘ld’. LOADLIBES is a deprecated (but still supported) alternative to LDLIBS. Non-library linker flags, such as -L, should go in the LDFLAGS variable. https://lkml.org/lkml/2010/2/10/362 tools/perf: libraries must come after objects Link order matters, use LDLIBS instead of LDFLAGS to properly link against libpthread. Signed-off-by: Fathi Boudra Acked-by: Kees Cook Signed-off-by: Shuah Khan --- tools/testing/selftests/seccomp/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/seccomp/Makefile b/tools/testing/selftests/seccomp/Makefile index fce7f4ce0692..1760b3e39730 100644 --- a/tools/testing/selftests/seccomp/Makefile +++ b/tools/testing/selftests/seccomp/Makefile @@ -9,7 +9,7 @@ BINARIES := seccomp_bpf seccomp_benchmark CFLAGS += -Wl,-no-as-needed -Wall seccomp_bpf: seccomp_bpf.c ../kselftest_harness.h - $(CC) $(CFLAGS) $(LDFLAGS) -lpthread $< -o $@ + $(CC) $(CFLAGS) $(LDFLAGS) $< -lpthread -o $@ TEST_PROGS += $(BINARIES) EXTRA_CLEAN := $(BINARIES) -- cgit v1.2.3-58-ga151 From 28b170e88bc0c7509e6724717c15cb4b5686026e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Jan 2019 10:44:50 +0100 Subject: OF: properties: add missing of_node_put Add an of_node_put when the result of of_graph_get_remote_port_parent is not available. The semantic match that finds this problem is as follows (http://coccinelle.lip6.fr): // @r exists@ local idexpression e; expression x; @@ e = of_graph_get_remote_port_parent(...); ... when != x = e when != true e == NULL when != of_node_put(e) when != of_fwnode_handle(e) ( return e; | *return ...; ) // Signed-off-by: Julia Lawall Cc: stable@vger.kernel.org Signed-off-by: Rob Herring --- drivers/of/property.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/of/property.c b/drivers/of/property.c index 08430031bd28..8631efa1daa1 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -806,6 +806,7 @@ struct device_node *of_graph_get_remote_node(const struct device_node *node, if (!of_device_is_available(remote)) { pr_debug("not available for remote node\n"); + of_node_put(remote); return NULL; } -- cgit v1.2.3-58-ga151 From 889f4ce60ed19cfd16216e96f90e64a0c1181c0d Mon Sep 17 00:00:00 2001 From: Otto Sabart Date: Wed, 9 Jan 2019 20:07:41 +0100 Subject: doc: gpio-mvebu: fix broken reference to cp110-system-controller0.txt file The cp110-system-controller0.txt file was renamed to cp110-system-controller.txt. Fixes: 4aa5496980e4 ("dt-bindings: cp110: rename cp110 syscon file") Signed-off-by: Otto Sabart Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/gpio/gpio-mvebu.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt b/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt index 38ca2201e8ae..2e097b57f170 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt @@ -14,8 +14,6 @@ Required properties: "marvell,armada-8k-gpio" should be used for the Armada 7K and 8K SoCs (either from AP or CP), see - Documentation/devicetree/bindings/arm/marvell/cp110-system-controller0.txt - and Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt for specific details about the offset property. -- cgit v1.2.3-58-ga151 From 9eac0ae1683575375de8c63166b3596b11d3b56a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Jan 2019 13:11:40 +0100 Subject: dt-bindings: soc: qcom: Fix trivial language typos Fix few trivial language typos in bindings. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt | 2 +- Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt index 0b8cc533ca83..cf759e5f9b10 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,glink.txt @@ -55,7 +55,7 @@ of these nodes are defined by the individual bindings for the specific function = EXAMPLE The following example represents the GLINK RPM node on a MSM8996 device, with the function for the "rpm_request" channel defined, which is used for -regualtors and root clocks. +regulators and root clocks. apcs_glb: mailbox@9820000 { compatible = "qcom,msm8996-apcs-hmss-global"; diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt index a35af2dafdad..49e1d72d3648 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt @@ -41,12 +41,12 @@ processor ID) and a string identifier. - qcom,local-pid: Usage: required Value type: - Definition: specifies the identfier of the local endpoint of this edge + Definition: specifies the identifier of the local endpoint of this edge - qcom,remote-pid: Usage: required Value type: - Definition: specifies the identfier of the remote endpoint of this edge + Definition: specifies the identifier of the remote endpoint of this edge = SUBNODES Each SMP2P pair contain a set of inbound and outbound entries, these are -- cgit v1.2.3-58-ga151 From 3705add0b783e0deeb6646ba0311bf214fe52b0a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 16 Jan 2019 11:36:32 +0100 Subject: dt-bindings: reset: meson-axg: fix SPDX license id As reported, the SPDX license id is not placed correctly and the variant of the BSD License used should be specified. Fixes: c16292578ffa ("dt-bindings: reset: Add bindings for the Meson-AXG SoC Reset Controller") Reported-by: Thomas Gleixner Signed-off-by: Jerome Brunet Reviewed-by: Thomas Gleixner Signed-off-by: Rob Herring --- include/dt-bindings/reset/amlogic,meson-axg-reset.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/dt-bindings/reset/amlogic,meson-axg-reset.h b/include/dt-bindings/reset/amlogic,meson-axg-reset.h index ad6f55dabd6d..0f2e0fe45ca4 100644 --- a/include/dt-bindings/reset/amlogic,meson-axg-reset.h +++ b/include/dt-bindings/reset/amlogic,meson-axg-reset.h @@ -1,12 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ /* - * * Copyright (c) 2016 BayLibre, SAS. * Author: Neil Armstrong * * Copyright (c) 2017 Amlogic, inc. * Author: Yixun Lan * - * SPDX-License-Identifier: (GPL-2.0+ OR BSD) */ #ifndef _DT_BINDINGS_AMLOGIC_MESON_AXG_RESET_H -- cgit v1.2.3-58-ga151 From 9474f4e7cd71a633fa1ef93b7daefd44bbdfd482 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 16 Jan 2019 10:31:09 -0800 Subject: Yama: Check for pid death before checking ancestry It's possible that a pid has died before we take the rcu lock, in which case we can't walk the ancestry list as it may be detached. Instead, check for death first before doing the walk. Reported-by: syzbot+a9ac39bf55329e206219@syzkaller.appspotmail.com Fixes: 2d514487faf1 ("security: Yama LSM") Cc: stable@vger.kernel.org Suggested-by: Oleg Nesterov Signed-off-by: Kees Cook Signed-off-by: James Morris --- security/yama/yama_lsm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index ffda91a4a1aa..02514fe558b4 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -368,7 +368,9 @@ static int yama_ptrace_access_check(struct task_struct *child, break; case YAMA_SCOPE_RELATIONAL: rcu_read_lock(); - if (!task_is_descendant(current, child) && + if (!pid_alive(child)) + rc = -EPERM; + if (!rc && !task_is_descendant(current, child) && !ptracer_exception_found(current, child) && !ns_capable(__task_cred(child)->user_ns, CAP_SYS_PTRACE)) rc = -EPERM; -- cgit v1.2.3-58-ga151 From cd0c4e70fc0ccfa705cdf55efb27519ce9337a26 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 11 Jan 2019 18:55:42 -0800 Subject: net_sched: refetch skb protocol for each filter Martin reported a set of filters don't work after changing from reclassify to continue. Looking into the code, it looks like skb protocol is not always fetched for each iteration of the filters. But, as demonstrated by Martin, TC actions could modify skb->protocol, for example act_vlan, this means we have to refetch skb protocol in each iteration, rather than using the one we fetch in the beginning of the loop. This bug is _not_ introduced by commit 3b3ae880266d ("net: sched: consolidate tc_classify{,_compat}"), technically, if act_vlan is the only action that modifies skb protocol, then it is commit c7e2b9689ef8 ("sched: introduce vlan action") which introduced this bug. Reported-by: Martin Olsson Cc: Jamal Hadi Salim Cc: Jiri Pirko Signed-off-by: Cong Wang Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/cls_api.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 8ce2a0507970..e2b5cb2eb34e 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -1277,7 +1277,6 @@ EXPORT_SYMBOL(tcf_block_cb_unregister); int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct tcf_result *res, bool compat_mode) { - __be16 protocol = tc_skb_protocol(skb); #ifdef CONFIG_NET_CLS_ACT const int max_reclassify_loop = 4; const struct tcf_proto *orig_tp = tp; @@ -1287,6 +1286,7 @@ int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp, reclassify: #endif for (; tp; tp = rcu_dereference_bh(tp->next)) { + __be16 protocol = tc_skb_protocol(skb); int err; if (tp->protocol != protocol && @@ -1319,7 +1319,6 @@ reset: } tp = first_tp; - protocol = tc_skb_protocol(skb); goto reclassify; #endif } -- cgit v1.2.3-58-ga151 From 9098f21f4cc0f13bc0caa747590e53479c267405 Mon Sep 17 00:00:00 2001 From: Dmitry Bezrukov Date: Mon, 14 Jan 2019 08:14:41 +0000 Subject: net: usb: aqc111: Extend HWID table by TRENDnet device New device of TRENDnet based on aqc111u Add this ID to blacklist of cdc_ether driver as well Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/usb/aqc111.c | 15 +++++++++++++++ drivers/net/usb/cdc_ether.c | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/net/usb/aqc111.c b/drivers/net/usb/aqc111.c index 57f1c94fca0b..820a2fe7d027 100644 --- a/drivers/net/usb/aqc111.c +++ b/drivers/net/usb/aqc111.c @@ -1287,6 +1287,20 @@ static const struct driver_info asix112_info = { #undef ASIX112_DESC +static const struct driver_info trendnet_info = { + .description = "USB-C 3.1 to 5GBASE-T Ethernet Adapter", + .bind = aqc111_bind, + .unbind = aqc111_unbind, + .status = aqc111_status, + .link_reset = aqc111_link_reset, + .reset = aqc111_reset, + .stop = aqc111_stop, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | + FLAG_AVOID_UNLINK_URBS | FLAG_MULTI_PACKET, + .rx_fixup = aqc111_rx_fixup, + .tx_fixup = aqc111_tx_fixup, +}; + static int aqc111_suspend(struct usb_interface *intf, pm_message_t message) { struct usbnet *dev = usb_get_intfdata(intf); @@ -1440,6 +1454,7 @@ static const struct usb_device_id products[] = { {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)}, {AQC111_USB_ETH_DEV(0x0b95, 0x2790, asix111_info)}, {AQC111_USB_ETH_DEV(0x0b95, 0x2791, asix112_info)}, + {AQC111_USB_ETH_DEV(0x20f4, 0xe05a, trendnet_info)}, { },/* END */ }; MODULE_DEVICE_TABLE(usb, products); diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 3305f23793c7..5512a1038721 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -843,6 +843,14 @@ static const struct usb_device_id products[] = { .driver_info = 0, }, +/* USB-C 3.1 to 5GBASE-T Ethernet Adapter (based on AQC111U) */ +{ + USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0xe05a, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info = 0, +}, + /* WHITELIST!!! * * CDC Ether uses two interfaces, not necessarily consecutive. -- cgit v1.2.3-58-ga151 From 04a4af334b971814eedf4e4a413343ad3287d9a9 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Mon, 14 Jan 2019 09:16:56 +0000 Subject: openvswitch: Avoid OOB read when parsing flow nlattrs For nested and variable attributes, the expected length of an attribute is not known and marked by a negative number. This results in an OOB read when the expected length is later used to check if the attribute is all zeros. Fix this by using the actual length of the attribute rather than the expected length. Signed-off-by: Ross Lagerwall Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/flow_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 435a4bdf8f89..691da853bef5 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -500,7 +500,7 @@ static int __parse_flow_nlattrs(const struct nlattr *attr, return -EINVAL; } - if (!nz || !is_all_zero(nla_data(nla), expected_len)) { + if (!nz || !is_all_zero(nla_data(nla), nla_len(nla))) { attrs |= 1 << type; a[type] = nla; } -- cgit v1.2.3-58-ga151 From 20704bd1633dd5afb29a321d3a615c9c8e9c9d05 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 14 Jan 2019 18:10:06 +0800 Subject: erspan: build the header with the right proto according to erspan_ver As said in draft-foschiano-erspan-03#section4: Different frame variants known as "ERSPAN Types" can be distinguished based on the GRE "Protocol Type" field value: Type I and II's value is 0x88BE while Type III's is 0x22EB [ETYPES]. So set it properly in erspan_xmit() according to erspan_ver. While at it, also remove the unused parameter 'proto' in erspan_fb_xmit(). Fixes: 94d7d8f29287 ("ip6_gre: add erspan v2 support") Reported-by: Jianlin Shi Signed-off-by: Xin Long Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 23 ++++++++++++++--------- net/ipv6/ip6_gre.c | 6 ++++-- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d1d09f3e5f9e..b1a74d80d868 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -569,8 +569,7 @@ err_free_skb: dev->stats.tx_dropped++; } -static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, - __be16 proto) +static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct ip_tunnel_info *tun_info; @@ -578,10 +577,10 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, struct erspan_metadata *md; struct rtable *rt = NULL; bool truncate = false; + __be16 df, proto; struct flowi4 fl; int tunnel_hlen; int version; - __be16 df; int nhoff; int thoff; @@ -626,18 +625,20 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, if (version == 1) { erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)), ntohl(md->u.index), truncate, true); + proto = htons(ETH_P_ERSPAN); } else if (version == 2) { erspan_build_header_v2(skb, ntohl(tunnel_id_to_key32(key->tun_id)), md->u.md2.dir, get_hwid(&md->u.md2), truncate, true); + proto = htons(ETH_P_ERSPAN2); } else { goto err_free_rt; } gre_build_header(skb, 8, TUNNEL_SEQ, - htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++)); + proto, 0, htonl(tunnel->o_seqno++)); df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; @@ -721,12 +722,13 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, { struct ip_tunnel *tunnel = netdev_priv(dev); bool truncate = false; + __be16 proto; if (!pskb_inet_may_pull(skb)) goto free_skb; if (tunnel->collect_md) { - erspan_fb_xmit(skb, dev, skb->protocol); + erspan_fb_xmit(skb, dev); return NETDEV_TX_OK; } @@ -742,19 +744,22 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, } /* Push ERSPAN header */ - if (tunnel->erspan_ver == 1) + if (tunnel->erspan_ver == 1) { erspan_build_header(skb, ntohl(tunnel->parms.o_key), tunnel->index, truncate, true); - else if (tunnel->erspan_ver == 2) + proto = htons(ETH_P_ERSPAN); + } else if (tunnel->erspan_ver == 2) { erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key), tunnel->dir, tunnel->hwid, truncate, true); - else + proto = htons(ETH_P_ERSPAN2); + } else { goto free_skb; + } tunnel->parms.o_flags &= ~TUNNEL_KEY; - __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN)); + __gre_xmit(skb, dev, &tunnel->parms.iph, proto); return NETDEV_TX_OK; free_skb: diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 026f08735549..b1be67ca6768 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -922,6 +922,7 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, __u8 dsfield = false; struct flowi6 fl6; int err = -EINVAL; + __be16 proto; __u32 mtu; int nhoff; int thoff; @@ -1035,8 +1036,9 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, } /* Push GRE header. */ - gre_build_header(skb, 8, TUNNEL_SEQ, - htons(ETH_P_ERSPAN), 0, htonl(t->o_seqno++)); + proto = (t->parms.erspan_ver == 1) ? htons(ETH_P_ERSPAN) + : htons(ETH_P_ERSPAN2); + gre_build_header(skb, 8, TUNNEL_SEQ, proto, 0, htonl(t->o_seqno++)); /* TooBig packet may have updated dst->dev's mtu */ if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu) -- cgit v1.2.3-58-ga151 From 400b8b9a2a17918f8ce00786f596f530e7f30d50 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 14 Jan 2019 18:34:02 +0800 Subject: sctp: allocate sctp_sockaddr_entry with kzalloc The similar issue as fixed in Commit 4a2eb0c37b47 ("sctp: initialize sin6_flowinfo for ipv6 addrs in sctp_inet6addr_event") also exists in sctp_inetaddr_event, as Alexander noticed. To fix it, allocate sctp_sockaddr_entry with kzalloc for both sctp ipv4 and ipv6 addresses, as does in sctp_v4/6_copy_addrlist(). Reported-by: Alexander Potapenko Signed-off-by: Xin Long Reported-by: syzbot+ae0c70c0c2d40c51bb92@syzkaller.appspotmail.com Acked-by: Marcelo Ricardo Leitner Acked-by: Neil Horman Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 5 +---- net/sctp/protocol.c | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index b9ed271b7ef7..ed8e006dae85 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -97,11 +97,9 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev, switch (ev) { case NETDEV_UP: - addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); + addr = kzalloc(sizeof(*addr), GFP_ATOMIC); if (addr) { addr->a.v6.sin6_family = AF_INET6; - addr->a.v6.sin6_port = 0; - addr->a.v6.sin6_flowinfo = 0; addr->a.v6.sin6_addr = ifa->addr; addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex; addr->valid = 1; @@ -434,7 +432,6 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist, addr = kzalloc(sizeof(*addr), GFP_ATOMIC); if (addr) { addr->a.v6.sin6_family = AF_INET6; - addr->a.v6.sin6_port = 0; addr->a.v6.sin6_addr = ifp->addr; addr->a.v6.sin6_scope_id = dev->ifindex; addr->valid = 1; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index d5878ae55840..4e0eeb113ef5 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -101,7 +101,6 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, addr = kzalloc(sizeof(*addr), GFP_ATOMIC); if (addr) { addr->a.v4.sin_family = AF_INET; - addr->a.v4.sin_port = 0; addr->a.v4.sin_addr.s_addr = ifa->ifa_local; addr->valid = 1; INIT_LIST_HEAD(&addr->list); @@ -776,10 +775,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, switch (ev) { case NETDEV_UP: - addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); + addr = kzalloc(sizeof(*addr), GFP_ATOMIC); if (addr) { addr->a.v4.sin_family = AF_INET; - addr->a.v4.sin_port = 0; addr->a.v4.sin_addr.s_addr = ifa->ifa_local; addr->valid = 1; spin_lock_bh(&net->sctp.local_addr_lock); -- cgit v1.2.3-58-ga151 From 01b833ab44c9e484060aad72267fc7e71beb559b Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Mon, 14 Jan 2019 13:38:43 +0300 Subject: net/core/neighbour: fix kmemleak minimal reference count for hash tables This should be 1 for normal allocations, 0 disables leak reporting. Signed-off-by: Konstantin Khlebnikov Reported-by: Cong Wang Fixes: 85704cb8dcfd ("net/core/neighbour: tell kmemleak about hash tables") Signed-off-by: David S. Miller --- net/core/neighbour.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 3e27a779f288..96fdc9134726 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -450,7 +450,7 @@ static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift) buckets = (struct neighbour __rcu **) __get_free_pages(GFP_ATOMIC | __GFP_ZERO, get_order(size)); - kmemleak_alloc(buckets, size, 0, GFP_ATOMIC); + kmemleak_alloc(buckets, size, 1, GFP_ATOMIC); } if (!buckets) { kfree(ret); -- cgit v1.2.3-58-ga151 From 508cacd7da6659ae7b7bdd0a335f675422277758 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 14 Jan 2019 14:51:33 +0100 Subject: selftests: gpio-mockup-chardev: Check asprintf() for error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With gcc 7.3.0: gpio-mockup-chardev.c: In function ‘get_debugfs’: gpio-mockup-chardev.c:62:3: warning: ignoring return value of ‘asprintf’, declared with attribute warn_unused_result [-Wunused-result] asprintf(path, "%s/gpio", mnt_fs_get_target(fs)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Handle asprintf() failures to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Shuah Khan --- tools/testing/selftests/gpio/gpio-mockup-chardev.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/gpio/gpio-mockup-chardev.c b/tools/testing/selftests/gpio/gpio-mockup-chardev.c index f8d468f54e98..aaa1e9f083c3 100644 --- a/tools/testing/selftests/gpio/gpio-mockup-chardev.c +++ b/tools/testing/selftests/gpio/gpio-mockup-chardev.c @@ -37,7 +37,7 @@ static int get_debugfs(char **path) struct libmnt_table *tb; struct libmnt_iter *itr = NULL; struct libmnt_fs *fs; - int found = 0; + int found = 0, ret; cxt = mnt_new_context(); if (!cxt) @@ -58,8 +58,11 @@ static int get_debugfs(char **path) break; } } - if (found) - asprintf(path, "%s/gpio", mnt_fs_get_target(fs)); + if (found) { + ret = asprintf(path, "%s/gpio", mnt_fs_get_target(fs)); + if (ret < 0) + err(EXIT_FAILURE, "failed to format string"); + } mnt_free_iter(itr); mnt_free_context(cxt); -- cgit v1.2.3-58-ga151 From 91fa038d9446b5bf5ea80822790af7dd9bcbb5a2 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Mon, 14 Jan 2019 18:16:44 +0100 Subject: selftests: tc-testing: fix parsing of ife type In iproute2 commit 90c5c969f0b9 ("fix print_0xhex on 32 bit"), the format specifier for the ife type changed from 0x%X to %#llX, causing systematic failures in the following TDC test cases: 7682 - Create valid ife encode action with mark and pass control ef47 - Create valid ife encode action with mark and pipe control df43 - Create valid ife encode action with mark and continue control e4cf - Create valid ife encode action with mark and drop control ccba - Create valid ife encode action with mark and reclassify control a1cf - Create valid ife encode action with mark and jump control cb3d - Create valid ife encode action with mark value at 32-bit maximum 95ed - Create valid ife encode action with prio and pass control aa17 - Create valid ife encode action with prio and pipe control 74c7 - Create valid ife encode action with prio and continue control 7a97 - Create valid ife encode action with prio and drop control f66b - Create valid ife encode action with prio and reclassify control 3056 - Create valid ife encode action with prio and jump control 7dd3 - Create valid ife encode action with prio value at 32-bit maximum 05bb - Create valid ife encode action with tcindex and pass control ce65 - Create valid ife encode action with tcindex and pipe control 09cd - Create valid ife encode action with tcindex and continue control 8eb5 - Create valid ife encode action with tcindex and continue control 451a - Create valid ife encode action with tcindex and drop control d76c - Create valid ife encode action with tcindex and reclassify control e731 - Create valid ife encode action with tcindex and jump control b7b8 - Create valid ife encode action with tcindex value at 16-bit maximum 2a9c - Create valid ife encode action with mac src parameter cf5c - Create valid ife encode action with mac dst parameter 2353 - Create valid ife encode action with mac src and mac dst parameters 552c - Create valid ife encode action with mark and type parameters 0421 - Create valid ife encode action with prio and type parameters 4017 - Create valid ife encode action with tcindex and type parameters fac3 - Create valid ife encode action with index at 32-bit maximnum 7c25 - Create valid ife decode action with pass control dccb - Create valid ife decode action with pipe control 7bb9 - Create valid ife decode action with continue control d9ad - Create valid ife decode action with drop control 219f - Create valid ife decode action with reclassify control 8f44 - Create valid ife decode action with jump control b330 - Create ife encode action with cookie Change 'matchPattern' values, allowing '0' and '0x0' if ife type is equal to 0, and accepting both '0x' and '0X' otherwise, to let these tests pass both with old and new tc binaries. While at it, fix a small typo in test case fac3 ('maximnum'->'maximum'). Signed-off-by: Davide Caratti Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- .../selftests/tc-testing/tc-tests/actions/ife.json | 88 +++++++++++----------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json index 637ea0219617..0da3545cabdb 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json @@ -17,7 +17,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow mark pass index 2", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 2", - "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xED3E.*allow mark.*index 2", + "matchPattern": "action order [0-9]*: ife encode action pass.*type 0[xX]ED3E.*allow mark.*index 2", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -41,7 +41,7 @@ "cmdUnderTest": "$TC actions add action ife encode use mark 10 pipe index 2", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 2", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xED3E.*use mark.*index 2", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ED3E.*use mark.*index 2", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -65,7 +65,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow mark continue index 2", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 2", - "matchPattern": "action order [0-9]*: ife encode action continue.*type 0xED3E.*allow mark.*index 2", + "matchPattern": "action order [0-9]*: ife encode action continue.*type 0[xX]ED3E.*allow mark.*index 2", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -89,7 +89,7 @@ "cmdUnderTest": "$TC actions add action ife encode use mark 789 drop index 2", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 2", - "matchPattern": "action order [0-9]*: ife encode action drop.*type 0xED3E.*use mark 789.*index 2", + "matchPattern": "action order [0-9]*: ife encode action drop.*type 0[xX]ED3E.*use mark 789.*index 2", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -113,7 +113,7 @@ "cmdUnderTest": "$TC actions add action ife encode use mark 656768 reclassify index 2", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 2", - "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0xED3E.*use mark 656768.*index 2", + "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0[xX]ED3E.*use mark 656768.*index 2", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -137,7 +137,7 @@ "cmdUnderTest": "$TC actions add action ife encode use mark 65 jump 1 index 2", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 2", - "matchPattern": "action order [0-9]*: ife encode action jump 1.*type 0xED3E.*use mark 65.*index 2", + "matchPattern": "action order [0-9]*: ife encode action jump 1.*type 0[xX]ED3E.*use mark 65.*index 2", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -161,7 +161,7 @@ "cmdUnderTest": "$TC actions add action ife encode use mark 4294967295 reclassify index 90", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 90", - "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0xED3E.*use mark 4294967295.*index 90", + "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0[xX]ED3E.*use mark 4294967295.*index 90", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -185,7 +185,7 @@ "cmdUnderTest": "$TC actions add action ife encode use mark 4294967295999 pipe index 90", "expExitCode": "255", "verifyCmd": "$TC actions get action ife index 90", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xED3E.*use mark 4294967295999.*index 90", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ED3E.*use mark 4294967295999.*index 90", "matchCount": "0", "teardown": [] }, @@ -207,7 +207,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow prio pass index 9", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 9", - "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xED3E.*allow prio.*index 9", + "matchPattern": "action order [0-9]*: ife encode action pass.*type 0[xX]ED3E.*allow prio.*index 9", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -231,7 +231,7 @@ "cmdUnderTest": "$TC actions add action ife encode use prio 7 pipe index 9", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 9", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xED3E.*use prio 7.*index 9", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ED3E.*use prio 7.*index 9", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -255,7 +255,7 @@ "cmdUnderTest": "$TC actions add action ife encode use prio 3 continue index 9", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 9", - "matchPattern": "action order [0-9]*: ife encode action continue.*type 0xED3E.*use prio 3.*index 9", + "matchPattern": "action order [0-9]*: ife encode action continue.*type 0[xX]ED3E.*use prio 3.*index 9", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -279,7 +279,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow prio drop index 9", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 9", - "matchPattern": "action order [0-9]*: ife encode action drop.*type 0xED3E.*allow prio.*index 9", + "matchPattern": "action order [0-9]*: ife encode action drop.*type 0[xX]ED3E.*allow prio.*index 9", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -303,7 +303,7 @@ "cmdUnderTest": "$TC actions add action ife encode use prio 998877 reclassify index 9", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 9", - "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0xED3E.*use prio 998877.*index 9", + "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0[xX]ED3E.*use prio 998877.*index 9", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -327,7 +327,7 @@ "cmdUnderTest": "$TC actions add action ife encode use prio 998877 jump 10 index 9", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 9", - "matchPattern": "action order [0-9]*: ife encode action jump 10.*type 0xED3E.*use prio 998877.*index 9", + "matchPattern": "action order [0-9]*: ife encode action jump 10.*type 0[xX]ED3E.*use prio 998877.*index 9", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -351,7 +351,7 @@ "cmdUnderTest": "$TC actions add action ife encode use prio 4294967295 reclassify index 99", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 99", - "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0xED3E.*use prio 4294967295.*index 99", + "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0[xX]ED3E.*use prio 4294967295.*index 99", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -375,7 +375,7 @@ "cmdUnderTest": "$TC actions add action ife encode use prio 4294967298 pipe index 99", "expExitCode": "255", "verifyCmd": "$TC actions get action ife index 99", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xED3E.*use prio 4294967298.*index 99", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ED3E.*use prio 4294967298.*index 99", "matchCount": "0", "teardown": [] }, @@ -397,7 +397,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow tcindex pass index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xED3E.*allow tcindex.*index 1", + "matchPattern": "action order [0-9]*: ife encode action pass.*type 0[xX]ED3E.*allow tcindex.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -421,7 +421,7 @@ "cmdUnderTest": "$TC actions add action ife encode use tcindex 111 pipe index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xED3E.*use tcindex 111.*index 1", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ED3E.*use tcindex 111.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -445,7 +445,7 @@ "cmdUnderTest": "$TC actions add action ife encode use tcindex 1 continue index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife encode action continue.*type 0xED3E.*use tcindex 1.*index 1", + "matchPattern": "action order [0-9]*: ife encode action continue.*type 0[xX]ED3E.*use tcindex 1.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -469,7 +469,7 @@ "cmdUnderTest": "$TC actions add action ife encode use tcindex 1 continue index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife encode action continue.*type 0xED3E.*use tcindex 1.*index 1", + "matchPattern": "action order [0-9]*: ife encode action continue.*type 0[xX]ED3E.*use tcindex 1.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -493,7 +493,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow tcindex drop index 77", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 77", - "matchPattern": "action order [0-9]*: ife encode action drop.*type 0xED3E.*allow tcindex.*index 77", + "matchPattern": "action order [0-9]*: ife encode action drop.*type 0[xX]ED3E.*allow tcindex.*index 77", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -517,7 +517,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow tcindex reclassify index 77", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 77", - "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0xED3E.*allow tcindex.*index 77", + "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0[xX]ED3E.*allow tcindex.*index 77", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -541,7 +541,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow tcindex jump 999 index 77", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 77", - "matchPattern": "action order [0-9]*: ife encode action jump 999.*type 0xED3E.*allow tcindex.*index 77", + "matchPattern": "action order [0-9]*: ife encode action jump 999.*type 0[xX]ED3E.*allow tcindex.*index 77", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -565,7 +565,7 @@ "cmdUnderTest": "$TC actions add action ife encode use tcindex 65535 pass index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xED3E.*use tcindex 65535.*index 1", + "matchPattern": "action order [0-9]*: ife encode action pass.*type 0[xX]ED3E.*use tcindex 65535.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -589,7 +589,7 @@ "cmdUnderTest": "$TC actions add action ife encode use tcindex 65539 pipe index 1", "expExitCode": "255", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xED3E.*use tcindex 65539.*index 1", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ED3E.*use tcindex 65539.*index 1", "matchCount": "0", "teardown": [] }, @@ -611,7 +611,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow mark src 00:11:22:33:44:55 pipe index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xED3E.*allow mark src 00:11:22:33:44:55.*index 1", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ED3E.*allow mark src 00:11:22:33:44:55.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -635,7 +635,7 @@ "cmdUnderTest": "$TC actions add action ife encode use prio 9876 dst 00:11:22:33:44:55 reclassify index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0xED3E.*use prio 9876 dst 00:11:22:33:44:55.*index 1", + "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0[xX]ED3E.*use prio 9876 dst 00:11:22:33:44:55.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -659,7 +659,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow tcindex src 00:aa:bb:cc:dd:ee dst 00:11:22:33:44:55 pass index 11", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 11", - "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xED3E.*allow tcindex dst 00:11:22:33:44:55 src 00:aa:bb:cc:dd:ee .*index 11", + "matchPattern": "action order [0-9]*: ife encode action pass.*type 0[xX]ED3E.*allow tcindex dst 00:11:22:33:44:55 src 00:aa:bb:cc:dd:ee .*index 11", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -683,7 +683,7 @@ "cmdUnderTest": "$TC actions add action ife encode use mark 7 type 0xfefe pass index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xFEFE.*use mark 7.*index 1", + "matchPattern": "action order [0-9]*: ife encode action pass.*type 0[xX]FEFE.*use mark 7.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -707,7 +707,7 @@ "cmdUnderTest": "$TC actions add action ife encode use prio 444 type 0xabba pipe index 21", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 21", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xABBA.*use prio 444.*index 21", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ABBA.*use prio 444.*index 21", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -731,7 +731,7 @@ "cmdUnderTest": "$TC actions add action ife encode use tcindex 5000 type 0xabcd reclassify index 21", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 21", - "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0xABCD.*use tcindex 5000.*index 21", + "matchPattern": "action order [0-9]*: ife encode action reclassify.*type 0[xX]ABCD.*use tcindex 5000.*index 21", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -739,7 +739,7 @@ }, { "id": "fac3", - "name": "Create valid ife encode action with index at 32-bit maximnum", + "name": "Create valid ife encode action with index at 32-bit maximum", "category": [ "actions", "ife" @@ -755,7 +755,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow mark pass index 4294967295", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 4294967295", - "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xED3E.*allow mark.*index 4294967295", + "matchPattern": "action order [0-9]*: ife encode action pass.*type 0[xX]ED3E.*allow mark.*index 4294967295", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -779,7 +779,7 @@ "cmdUnderTest": "$TC actions add action ife decode pass index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife decode action pass.*type 0x0.*allow mark allow tcindex allow prio.*index 1", + "matchPattern": "action order [0-9]*: ife decode action pass.*type 0(x0)?.*allow mark allow tcindex allow prio.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -803,7 +803,7 @@ "cmdUnderTest": "$TC actions add action ife decode pipe index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife decode action pipe.*type 0x0.*allow mark allow tcindex allow prio.*index 1", + "matchPattern": "action order [0-9]*: ife decode action pipe.*type 0(x0)?.*allow mark allow tcindex allow prio.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -827,7 +827,7 @@ "cmdUnderTest": "$TC actions add action ife decode continue index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife decode action continue.*type 0x0.*allow mark allow tcindex allow prio.*index 1", + "matchPattern": "action order [0-9]*: ife decode action continue.*type 0(x0)?.*allow mark allow tcindex allow prio.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -851,7 +851,7 @@ "cmdUnderTest": "$TC actions add action ife decode drop index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife decode action drop.*type 0x0.*allow mark allow tcindex allow prio.*index 1", + "matchPattern": "action order [0-9]*: ife decode action drop.*type 0(x0)?.*allow mark allow tcindex allow prio.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -875,7 +875,7 @@ "cmdUnderTest": "$TC actions add action ife decode reclassify index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife decode action reclassify.*type 0x0.*allow mark allow tcindex allow prio.*index 1", + "matchPattern": "action order [0-9]*: ife decode action reclassify.*type 0(x0)?.*allow mark allow tcindex allow prio.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -899,7 +899,7 @@ "cmdUnderTest": "$TC actions add action ife decode jump 10 index 1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 1", - "matchPattern": "action order [0-9]*: ife decode action jump 10.*type 0x0.*allow mark allow tcindex allow prio.*index 1", + "matchPattern": "action order [0-9]*: ife decode action jump 10.*type 0(x0)?.*allow mark allow tcindex allow prio.*index 1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -923,7 +923,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow mark pass index 4294967295999", "expExitCode": "255", "verifyCmd": "$TC actions get action ife index 4294967295999", - "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xED3E.*allow mark.*index 4294967295999", + "matchPattern": "action order [0-9]*: ife encode action pass.*type 0[xX]ED3E.*allow mark.*index 4294967295999", "matchCount": "0", "teardown": [] }, @@ -945,7 +945,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow mark kuka index 4", "expExitCode": "255", "verifyCmd": "$TC actions get action ife index 4", - "matchPattern": "action order [0-9]*: ife encode action kuka.*type 0xED3E.*allow mark.*index 4", + "matchPattern": "action order [0-9]*: ife encode action kuka.*type 0[xX]ED3E.*allow mark.*index 4", "matchCount": "0", "teardown": [] }, @@ -967,7 +967,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow prio pipe index 4 cookie aabbccddeeff112233445566778800a1", "expExitCode": "0", "verifyCmd": "$TC actions get action ife index 4", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xED3E.*allow prio.*index 4.*cookie aabbccddeeff112233445566778800a1", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ED3E.*allow prio.*index 4.*cookie aabbccddeeff112233445566778800a1", "matchCount": "1", "teardown": [ "$TC actions flush action ife" @@ -991,7 +991,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow foo pipe index 4", "expExitCode": "255", "verifyCmd": "$TC actions get action ife index 4", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0xED3E.*allow foo.*index 4", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]ED3E.*allow foo.*index 4", "matchCount": "0", "teardown": [] }, @@ -1013,7 +1013,7 @@ "cmdUnderTest": "$TC actions add action ife encode allow prio type 70000 pipe index 4", "expExitCode": "255", "verifyCmd": "$TC actions get action ife index 4", - "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0x11170.*allow prio.*index 4", + "matchPattern": "action order [0-9]*: ife encode action pipe.*type 0[xX]11170.*allow prio.*index 4", "matchCount": "0", "teardown": [] }, -- cgit v1.2.3-58-ga151 From a5a82d841186d13c4a6d500dfcf7d02b4195e3ff Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 14 Jan 2019 10:52:45 -0800 Subject: ipv6: route: place a warning with duplicated string with correct extack "IPv6: " prefix is already added by pr_fmt, no need to include it again in the pr_warn() format. The message predates extack support, we can replace the whole thing with an extack message. Suggested-by: David Ahern Signed-off-by: Jakub Kicinski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 40b225f87d5e..964491cf3672 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -4251,17 +4251,6 @@ struct rt6_nh { struct list_head next; }; -static void ip6_print_replace_route_err(struct list_head *rt6_nh_list) -{ - struct rt6_nh *nh; - - list_for_each_entry(nh, rt6_nh_list, next) { - pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6c nexthop %pI6c ifi %d\n", - &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway, - nh->r_cfg.fc_ifindex); - } -} - static int ip6_route_info_append(struct net *net, struct list_head *rt6_nh_list, struct fib6_info *rt, @@ -4407,7 +4396,8 @@ static int ip6_route_multipath_add(struct fib6_config *cfg, nh->fib6_info = NULL; if (err) { if (replace && nhn) - ip6_print_replace_route_err(&rt6_nh_list); + NL_SET_ERR_MSG_MOD(extack, + "multipath route replace failed (check consistency of installed routes)"); err_nh = nh; goto add_errout; } -- cgit v1.2.3-58-ga151 From 35dad45d5cad3c9ca8d6a338cbf668cd7ea86469 Mon Sep 17 00:00:00 2001 From: David Francis Date: Tue, 20 Nov 2018 09:42:58 -0500 Subject: drm/amd/display: Detach backlight from stream [Why] Backlight is conceptually a property of links, not streams. All backlight programming is done on links, but there is a stream property bl_pwm_level that is used to restore backlight on dpms on and s3 resume. This is unnecessary, as backlight is already restored by hardware with no driver intervention. [How] Remove bl_pwm_level, and the stream argument to set_backlight Bug: https://bugs.freedesktop.org/show_bug.cgi?id=109375 Signed-off-by: David Francis Reviewed-by: Harry Wentland Acked-by: Anthony Koo Acked-by: Leo Li Signed-off-by: Alex Deucher (cherry picked from commit 923fe4951282cbdfce05186c10380bbc45b5e03b) --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 12 +----------- drivers/gpu/drm/amd/display/dc/dc_link.h | 3 +-- drivers/gpu/drm/amd/display/dc/dc_stream.h | 1 - 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 903dbafc144d..f4fa40c387d3 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1772,7 +1772,7 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd) + caps.min_input_signal * 0x101; if (dc_link_set_backlight_level(dm->backlight_link, - brightness, 0, 0)) + brightness, 0)) return 0; else return 1; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 52deacf39841..b0265dbebd4c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -2190,8 +2190,7 @@ int dc_link_get_backlight_level(const struct dc_link *link) bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp, - const struct dc_stream_state *stream) + uint32_t frame_ramp) { struct dc *core_dc = link->ctx->dc; struct abm *abm = core_dc->res_pool->abm; @@ -2206,10 +2205,6 @@ bool dc_link_set_backlight_level(const struct dc_link *link, (abm->funcs->set_backlight_level_pwm == NULL)) return false; - if (stream) - ((struct dc_stream_state *)stream)->bl_pwm_level = - backlight_pwm_u16_16; - use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", @@ -2637,11 +2632,6 @@ void core_link_enable_stream( if (dc_is_dp_signal(pipe_ctx->stream->signal)) enable_stream_features(pipe_ctx); - - dc_link_set_backlight_level(pipe_ctx->stream->sink->link, - pipe_ctx->stream->bl_pwm_level, - 0, - pipe_ctx->stream); } } diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 29f19d57ff7a..b2243e0dad1f 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -146,8 +146,7 @@ static inline struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_ */ bool dc_link_set_backlight_level(const struct dc_link *dc_link, uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp, - const struct dc_stream_state *stream); + uint32_t frame_ramp); int dc_link_get_backlight_level(const struct dc_link *dc_link); diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index be34d638e15d..d70c9e1cda3d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -91,7 +91,6 @@ struct dc_stream_state { /* DMCU info */ unsigned int abm_level; - unsigned int bl_pwm_level; /* from core_stream struct */ struct dc_context *ctx; -- cgit v1.2.3-58-ga151 From 9e857a40dc4eba15a739b4194d7db873d82c28a0 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 15 Jan 2019 16:55:30 +0100 Subject: net: phy: Add missing features to PHY drivers The bcm87xx and micrel driver has PHYs which are missing the .features value. Add them. The bcm87xx is a 10G FEC only PHY. Add the needed features definition of this PHY. Fixes: 719655a14971 ("net: phy: Replace phy driver features u32 with link_mode bitmap") Reported-by: Scott Wood Reported-by: Camelia Groza Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/bcm87xx.c | 2 ++ drivers/net/phy/micrel.c | 1 + drivers/net/phy/phy_device.c | 12 ++++++++++++ include/linux/phy.h | 2 ++ 4 files changed, 17 insertions(+) diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c index 1b350183bffb..a271239748f2 100644 --- a/drivers/net/phy/bcm87xx.c +++ b/drivers/net/phy/bcm87xx.c @@ -197,6 +197,7 @@ static struct phy_driver bcm87xx_driver[] = { .phy_id = PHY_ID_BCM8706, .phy_id_mask = 0xffffffff, .name = "Broadcom BCM8706", + .features = PHY_10GBIT_FEC_FEATURES, .config_init = bcm87xx_config_init, .config_aneg = bcm87xx_config_aneg, .read_status = bcm87xx_read_status, @@ -208,6 +209,7 @@ static struct phy_driver bcm87xx_driver[] = { .phy_id = PHY_ID_BCM8727, .phy_id_mask = 0xffffffff, .name = "Broadcom BCM8727", + .features = PHY_10GBIT_FEC_FEATURES, .config_init = bcm87xx_config_init, .config_aneg = bcm87xx_config_aneg, .read_status = bcm87xx_read_status, diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 7828d17f0662..b1f959935f50 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -1099,6 +1099,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id = PHY_ID_KSZ8873MLL, .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Micrel KSZ8873MLL Switch", + .features = PHY_BASIC_FEATURES, .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 51990002d495..bf3ce48a1e5d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -61,6 +61,9 @@ EXPORT_SYMBOL_GPL(phy_gbit_all_ports_features); __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features) __ro_after_init; EXPORT_SYMBOL_GPL(phy_10gbit_features); +__ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_fec_features) __ro_after_init; +EXPORT_SYMBOL_GPL(phy_10gbit_fec_features); + static const int phy_basic_ports_array[] = { ETHTOOL_LINK_MODE_Autoneg_BIT, ETHTOOL_LINK_MODE_TP_BIT, @@ -109,6 +112,11 @@ const int phy_10gbit_features_array[1] = { }; EXPORT_SYMBOL_GPL(phy_10gbit_features_array); +const int phy_10gbit_fec_features_array[1] = { + ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, +}; +EXPORT_SYMBOL_GPL(phy_10gbit_fec_features_array); + __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_init; EXPORT_SYMBOL_GPL(phy_10gbit_full_features); @@ -191,6 +199,10 @@ static void features_init(void) linkmode_set_bit_array(phy_10gbit_full_features_array, ARRAY_SIZE(phy_10gbit_full_features_array), phy_10gbit_full_features); + /* 10G FEC only */ + linkmode_set_bit_array(phy_10gbit_fec_features_array, + ARRAY_SIZE(phy_10gbit_fec_features_array), + phy_10gbit_fec_features); } void phy_device_free(struct phy_device *phydev) diff --git a/include/linux/phy.h b/include/linux/phy.h index 3b051f761450..55114657a577 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -48,6 +48,7 @@ extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_fibre_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_gbit_all_ports_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_features) __ro_after_init; +extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_fec_features) __ro_after_init; extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_init; #define PHY_BASIC_FEATURES ((unsigned long *)&phy_basic_features) @@ -56,6 +57,7 @@ extern __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_10gbit_full_features) __ro_after_ini #define PHY_GBIT_FIBRE_FEATURES ((unsigned long *)&phy_gbit_fibre_features) #define PHY_GBIT_ALL_PORTS_FEATURES ((unsigned long *)&phy_gbit_all_ports_features) #define PHY_10GBIT_FEATURES ((unsigned long *)&phy_10gbit_features) +#define PHY_10GBIT_FEC_FEATURES ((unsigned long *)&phy_10gbit_fec_features) #define PHY_10GBIT_FULL_FEATURES ((unsigned long *)&phy_10gbit_full_features) extern const int phy_10_100_features_array[4]; -- cgit v1.2.3-58-ga151 From a5795fd38ee8194451ba3f281f075301a3696ce2 Mon Sep 17 00:00:00 2001 From: James Morris Date: Wed, 16 Jan 2019 15:41:11 -0800 Subject: LSM: Check for NULL cred-security on free From: Casey Schaufler Check that the cred security blob has been set before trying to clean it up. There is a case during credential initialization that could result in this. Signed-off-by: Casey Schaufler Acked-by: John Johansen Signed-off-by: James Morris Reported-by: syzbot+69ca07954461f189e808@syzkaller.appspotmail.com --- security/security.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/security/security.c b/security/security.c index f1b8d2587639..55bc49027ba9 100644 --- a/security/security.c +++ b/security/security.c @@ -1027,6 +1027,13 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) void security_cred_free(struct cred *cred) { + /* + * There is a failure case in prepare_creds() that + * may result in a call here with ->security being NULL. + */ + if (unlikely(cred->security == NULL)) + return; + call_void_hook(cred_free, cred); } -- cgit v1.2.3-58-ga151 From 1a9352687c19e4937d861ff2c5c6fc45c0a08aff Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Wed, 16 Jan 2019 01:35:22 +0900 Subject: net: bpfilter: change section name of bpfilter UMH blob. The section of bpfilter UMH blob is the ".bpfilter_umh". but this is not an explicit section. so linking warning occurred at compile time for the powerpc. So, this patch makes use of the ".rodata" instead of the ".bpfilter_umh". Config condition: CONFIG_BPFILTER=y CONFIG_BPFILTER_UMH=y Result: ld: warning: orphan section `.bpfilter_umh' from `net/bpfilter/bpfilter_umh_blob.o' being placed in section `.bpfilter_umh' Fixes: 61fbf5933d42 ("net: bpfilter: restart bpfilter_umh when error occurred") Reported-by: Stephen Rothwell Signed-off-by: Taehee Yoo Signed-off-by: David S. Miller --- net/bpfilter/bpfilter_umh_blob.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bpfilter/bpfilter_umh_blob.S b/net/bpfilter/bpfilter_umh_blob.S index 7f1c521dcc2f..9ea6100dca87 100644 --- a/net/bpfilter/bpfilter_umh_blob.S +++ b/net/bpfilter/bpfilter_umh_blob.S @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ - .section .bpfilter_umh, "a" + .section .rodata, "a" .global bpfilter_umh_start bpfilter_umh_start: .incbin "net/bpfilter/bpfilter_umh" -- cgit v1.2.3-58-ga151 From 0f149c9fec3cd720628ecde83bfc6f64c1e7dcb6 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 15 Jan 2019 11:40:02 -0500 Subject: udp: with udp_segment release on error path Failure __ip_append_data triggers udp_flush_pending_frames, but these tests happen later. The skb must be freed directly. Fixes: bec1f6f697362 ("udp: generate gso with UDP_SEGMENT") Reported-by: Eric Dumazet Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- net/ipv4/udp.c | 16 ++++++++++++---- net/ipv6/udp.c | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 3fb0ed5e4789..3d2a81bdc2ab 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -847,15 +847,23 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4, const int hlen = skb_network_header_len(skb) + sizeof(struct udphdr); - if (hlen + cork->gso_size > cork->fragsize) + if (hlen + cork->gso_size > cork->fragsize) { + kfree_skb(skb); return -EINVAL; - if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) + } + if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) { + kfree_skb(skb); return -EINVAL; - if (sk->sk_no_check_tx) + } + if (sk->sk_no_check_tx) { + kfree_skb(skb); return -EINVAL; + } if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || - dst_xfrm(skb_dst(skb))) + dst_xfrm(skb_dst(skb))) { + kfree_skb(skb); return -EIO; + } skb_shinfo(skb)->gso_size = cork->gso_size; skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 7c3505006f8e..e1f2b9660666 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1132,15 +1132,23 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6, const int hlen = skb_network_header_len(skb) + sizeof(struct udphdr); - if (hlen + cork->gso_size > cork->fragsize) + if (hlen + cork->gso_size > cork->fragsize) { + kfree_skb(skb); return -EINVAL; - if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) + } + if (skb->len > cork->gso_size * UDP_MAX_SEGMENTS) { + kfree_skb(skb); return -EINVAL; - if (udp_sk(sk)->no_check6_tx) + } + if (udp_sk(sk)->no_check6_tx) { + kfree_skb(skb); return -EINVAL; + } if (skb->ip_summed != CHECKSUM_PARTIAL || is_udplite || - dst_xfrm(skb_dst(skb))) + dst_xfrm(skb_dst(skb))) { + kfree_skb(skb); return -EIO; + } skb_shinfo(skb)->gso_size = cork->gso_size; skb_shinfo(skb)->gso_type = SKB_GSO_UDP_L4; -- cgit v1.2.3-58-ga151 From ec87da107d11521123beaa9f8e4869c6f54e8df8 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 16 Jan 2019 23:09:31 -0800 Subject: Input: olpc_apsp - assign priv->dev earlier The dev field needs to be set when serio_register_port() is called, because the open callback may use it (in the error handling path). Fixes: commit af518342effd ("Input: olpc_apsp - check FIFO status on open(), not probe()") Signed-off-by: Lubomir Rintel Signed-off-by: Dmitry Torokhov --- drivers/input/serio/olpc_apsp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c index b36084710f69..bae08226e3d9 100644 --- a/drivers/input/serio/olpc_apsp.c +++ b/drivers/input/serio/olpc_apsp.c @@ -195,6 +195,8 @@ static int olpc_apsp_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + priv->dev = &pdev->dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) { @@ -248,7 +250,6 @@ static int olpc_apsp_probe(struct platform_device *pdev) goto err_irq; } - priv->dev = &pdev->dev; device_init_wakeup(priv->dev, 1); platform_set_drvdata(pdev, priv); -- cgit v1.2.3-58-ga151 From edcddd4c879af48ec922d680b2d56834c085683b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 17 Jan 2019 07:15:35 -0500 Subject: XArray: Fix an arithmetic error in xa_is_err There is a math problem here which leads to a lot of static checker warnings for me: net/sunrpc/clnt.c:451 rpc_new_client() error: (-4096) too low for ERR_PTR Error values are from -1 to -4095 or from 0xffffffff to 0xfffff001 in hexadecimal. (I am assuming a 32 bit system for simplicity). We are using the lowest two bits to hold some internal XArray data so the error is shifted two spaces to the left. 0xfffff001 << 2 is 0xffffc004. And finally we want to check that BIT(1) is set so we add 2 which gives us 0xffffc006. In other words, we should be checking that "entry >= 0xffffc006", but the check is actually testing if "entry >= 0xffffc002". Fixes: 76b4e5299565 ("XArray: Permit storing 2-byte-aligned pointers") Signed-off-by: Dan Carpenter [Use xa_mk_internal() instead of changing the bracketing] Signed-off-by: Matthew Wilcox --- include/linux/xarray.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/xarray.h b/include/linux/xarray.h index 7da665f5cb20..5d9d318bcf7a 100644 --- a/include/linux/xarray.h +++ b/include/linux/xarray.h @@ -177,7 +177,7 @@ static inline bool xa_is_internal(const void *entry) static inline bool xa_is_err(const void *entry) { return unlikely(xa_is_internal(entry) && - (unsigned long)entry >= -((MAX_ERRNO << 2) + 2)); + entry >= xa_mk_internal(-MAX_ERRNO)); } /** -- cgit v1.2.3-58-ga151 From 3ac1b2e4158c73175278a27c5551fa331c260b48 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 17 Jan 2019 06:08:53 +0800 Subject: ASoC: rt5682: add default pdata for i2s mode Add a default pdata which can fit most HW design. So we don't need to add a lot of DMI checking in this driver. Signed-off-by: Bard liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 89c43b26c379..bd45d0343913 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -43,6 +43,12 @@ static const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = { "VBAT", }; +static const struct rt5682_platform_data i2s_default_platform_data = { + .dmic1_data_pin = RT5682_DMIC1_DATA_GPIO2, + .dmic1_clk_pin = RT5682_DMIC1_CLK_GPIO3, + .jd_src = RT5682_JD1, +}; + struct rt5682_priv { struct snd_soc_component *component; struct rt5682_platform_data pdata; @@ -2534,6 +2540,8 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5682); + rt5682->pdata = i2s_default_platform_data; + if (pdata) rt5682->pdata = *pdata; else -- cgit v1.2.3-58-ga151 From 87b6d2c56825c3119a0e64cc208ae6d795810a2e Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Wed, 12 Dec 2018 16:44:32 +0400 Subject: usb: dwc2: gadget: Fix Remote Wakeup interrupt bit clearing To clear GINTSTS2_WKUP_ALERT_INT bit in GINTSTS2 register require to write 1. This bit is implemented as "Write to clear". Fixes: 187c5298a122 ("usb: dwc2: gadget: Add handler for WkupAlert interrupt") Signed-off-by: Minas Harutyunyan Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 68ad75a7460d..55ef3cc2701b 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -261,7 +261,7 @@ static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); - dwc2_clear_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); + dwc2_set_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG); } } -- cgit v1.2.3-58-ga151 From 558ee616d177c8225e65c75b6b72952408e64a74 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 14 Jan 2019 17:44:40 +0900 Subject: nds32: remove unneeded code in arch/nds32/Makefile - scripts/Kbuild.include already defined 'comma' - The top Makefile has 'PHONY += FORCE' - include/asm-*/ was moved to arch/*/include/asm/ a decade ago Signed-off-by: Masahiro Yamada --- arch/nds32/Makefile | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/nds32/Makefile b/arch/nds32/Makefile index 0a935c136ec2..ac3482882cf9 100644 --- a/arch/nds32/Makefile +++ b/arch/nds32/Makefile @@ -3,9 +3,6 @@ OBJCOPYFLAGS := -O binary -R .note -R .note.gnu.build-id -R .comment -S KBUILD_DEFCONFIG := defconfig -comma = , - - ifdef CONFIG_FUNCTION_TRACER arch-y += -malways-save-lp -mno-relax endif @@ -54,8 +51,6 @@ endif boot := arch/nds32/boot core-y += $(boot)/dts/ -.PHONY: FORCE - Image: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ @@ -68,9 +63,6 @@ prepare: vdso_prepare vdso_prepare: prepare0 $(Q)$(MAKE) $(build)=arch/nds32/kernel/vdso include/generated/vdso-offsets.h -CLEAN_FILES += include/asm-nds32/constants.h* - -# We use MRPROPER_FILES and CLEAN_FILES now archclean: $(Q)$(MAKE) $(clean)=$(boot) -- cgit v1.2.3-58-ga151 From 1b504a7bb18fc32a324712a0fc56d667bdabe258 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 15 Jan 2019 04:14:23 +0900 Subject: openrisc: remove unneeded code in arch/openrisc/Makefile - LDFLAGS_vmlinux is cleared by the top Makefile - 'all: vmlinux' is specified by the top Makefile Signed-off-by: Masahiro Yamada --- arch/openrisc/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/openrisc/Makefile b/arch/openrisc/Makefile index 70e06d34006c..bf10141c7426 100644 --- a/arch/openrisc/Makefile +++ b/arch/openrisc/Makefile @@ -20,7 +20,6 @@ KBUILD_DEFCONFIG := or1ksim_defconfig OBJCOPYFLAGS := -O binary -R .note -R .comment -S -LDFLAGS_vmlinux := LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) KBUILD_CFLAGS += -pipe -ffixed-r10 -D__linux__ @@ -50,5 +49,3 @@ else BUILTIN_DTB := n endif core-$(BUILTIN_DTB) += arch/openrisc/boot/dts/ - -all: vmlinux -- cgit v1.2.3-58-ga151 From e00d8880481497474792d28c14479a9fb6752046 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 15 Jan 2019 16:19:00 +0900 Subject: kbuild: mark prepare0 as PHONY to fix external module build Commit c3ff2a5193fa ("powerpc/32: add stack protector support") caused kernel panic on PowerPC when an external module is used with CONFIG_STACKPROTECTOR because the 'prepare' target was not executed for the external module build. Commit e07db28eea38 ("kbuild: fix single target build for external module") turned it into a build error because the 'prepare' target is now executed but the 'prepare0' target is missing for the external module build. External module on arm/arm64 with CONFIG_STACKPROTECTOR_PER_TASK is also broken in the same way. Move 'PHONY += prepare0' to the common place. GNU Make is fine with missing rule for phony targets. I also removed the comment which is wrong irrespective of this commit. I minimize the change so it can be easily backported to 4.20.x To fix v4.20, please backport e07db28eea38 ("kbuild: fix single target build for external module"), and then this commit. Link: https://bugzilla.kernel.org/show_bug.cgi?id=201891 Fixes: e07db28eea38 ("kbuild: fix single target build for external module") Fixes: c3ff2a5193fa ("powerpc/32: add stack protector support") Fixes: 189af4657186 ("ARM: smp: add support for per-task stack canaries") Fixes: 0a1213fa7432 ("arm64: enable per-task stack canaries") Cc: linux-stable # v4.20 Reported-by: Samuel Holland Reported-by: Alexey Kardashevskiy Signed-off-by: Masahiro Yamada Acked-by: Ard Biesheuvel Tested-by: Alexey Kardashevskiy --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ff1054cfca33..a189ceadcd08 100644 --- a/Makefile +++ b/Makefile @@ -955,6 +955,7 @@ ifdef CONFIG_STACK_VALIDATION endif endif +PHONY += prepare0 ifeq ($(KBUILD_EXTMOD),) core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ @@ -1061,8 +1062,7 @@ scripts: scripts_basic scripts_dtc # archprepare is used in arch Makefiles and when processed asm symlink, # version.h and scripts_basic is processed / created. -# Listed in dependency order -PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 +PHONY += prepare archprepare prepare1 prepare2 prepare3 # prepare3 is used to check if we are building in a separate output directory, # and if so do: -- cgit v1.2.3-58-ga151 From d2fd6e81912a665993b24dcdc1c1384a42a54f7e Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Thu, 17 Jan 2019 08:46:34 -0600 Subject: PCI: Fix __initdata issue with "pci=disable_acs_redir" parameter The disable_acs_redir parameter stores a pointer to the string passed to pci_setup(). However, the string passed to PCI setup is actually a temporary copy allocated in static __initdata memory. After init, once the memory is freed, it is no longer valid to reference this pointer. This bug was noticed in v5.0-rc1 after a change in commit c5eb1190074c ("PCI / PM: Allow runtime PM without callback functions") caused pci_disable_acs_redir() to be called during shutdown which manifested as an unable to handle kernel paging request at: RIP: 0010:pci_enable_acs+0x3f/0x1e0 Call Trace: pci_restore_state.part.44+0x159/0x3c0 pci_restore_standard_config+0x33/0x40 pci_pm_runtime_resume+0x2b/0xd0 ? pci_restore_standard_config+0x40/0x40 __rpm_callback+0xbc/0x1b0 rpm_callback+0x1f/0x70 ? pci_restore_standard_config+0x40/0x40 rpm_resume+0x4f9/0x710 ? pci_conf1_read+0xb6/0xf0 ? pci_conf1_write+0xb2/0xe0 __pm_runtime_resume+0x47/0x70 pci_device_shutdown+0x1e/0x60 device_shutdown+0x14a/0x1f0 kernel_restart+0xe/0x50 __do_sys_reboot+0x1ee/0x210 ? __fput+0x144/0x1d0 do_writev+0x5e/0xf0 ? do_writev+0x5e/0xf0 do_syscall_64+0x48/0xf0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 It was also likely possible to trigger this bug when hotplugging PCI devices. To fix this, instead of storing a pointer, we use kstrdup() to copy the disable_acs_redir_param to its own buffer which will never be freed. Fixes: aaca43fda742 ("PCI: Add "pci=disable_acs_redir=" parameter for peer-to-peer support") Tested-by: Jarkko Nikula Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Reviewed-by: Jarkko Nikula --- drivers/pci/pci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c9d8e3c837de..c25acace7d91 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -6195,7 +6195,8 @@ static int __init pci_setup(char *str) } else if (!strncmp(str, "pcie_scan_all", 13)) { pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS); } else if (!strncmp(str, "disable_acs_redir=", 18)) { - disable_acs_redir_param = str + 18; + disable_acs_redir_param = + kstrdup(str + 18, GFP_KERNEL); } else { printk(KERN_ERR "PCI: Unknown option `%s'\n", str); -- cgit v1.2.3-58-ga151 From 4882a27cec24319d10f95e978ecc80050e3e3e15 Mon Sep 17 00:00:00 2001 From: Marc Dionne Date: Wed, 9 Jan 2019 17:23:54 +0000 Subject: afs: Don't set vnode->cb_s_break in afs_validate() A cb_interest record is not necessarily attached to the vnode on entry to afs_validate(), which can cause an oops when we try to bring the vnode's cb_s_break up to date in the default case (ie. no current callback promise and the vnode has not been deleted). Fix this by simply removing the line, as vnode->cb_s_break will be set when needed by afs_register_server_cb_interest() when we next get a callback promise from RPC call. The oops looks something like: BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 ... RIP: 0010:afs_validate+0x66/0x250 [kafs] ... Call Trace: afs_d_revalidate+0x8d/0x340 [kafs] ? __d_lookup+0x61/0x150 lookup_dcache+0x44/0x70 ? lookup_dcache+0x44/0x70 __lookup_hash+0x24/0xa0 do_unlinkat+0x11d/0x2c0 __x64_sys_unlink+0x23/0x30 do_syscall_64+0x4d/0xf0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Fixes: ae3b7361dc0e ("afs: Fix validation/callback interaction") Signed-off-by: Marc Dionne Signed-off-by: David Howells --- fs/afs/inode.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 6b17d3620414..211343831c30 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -414,7 +414,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { valid = true; } else { - vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; vnode->cb_v_break = vnode->volume->cb_v_break; valid = false; } -- cgit v1.2.3-58-ga151 From 59d49076ae3e6912e6d7df2fd68e2337f3d02036 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 9 Jan 2019 17:23:54 +0000 Subject: afs: Fix key refcounting in file locking code Fix the refcounting of the authentication keys in the file locking code. The vnode->lock_key member points to a key on which it expects to be holding a ref, but it isn't always given an extra ref, however. Fixes: 0fafdc9f888b ("afs: Fix file locking") Signed-off-by: David Howells --- fs/afs/flock.c | 4 ++-- fs/afs/inode.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 0568fd986821..e432bd27a2e7 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -208,7 +208,7 @@ again: /* The new front of the queue now owns the state variables. */ next = list_entry(vnode->pending_locks.next, struct file_lock, fl_u.afs.link); - vnode->lock_key = afs_file_key(next->fl_file); + vnode->lock_key = key_get(afs_file_key(next->fl_file)); vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB; goto again; @@ -413,7 +413,7 @@ static void afs_dequeue_lock(struct afs_vnode *vnode, struct file_lock *fl) /* The new front of the queue now owns the state variables. */ next = list_entry(vnode->pending_locks.next, struct file_lock, fl_u.afs.link); - vnode->lock_key = afs_file_key(next->fl_file); + vnode->lock_key = key_get(afs_file_key(next->fl_file)); vnode->lock_type = (next->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; vnode->lock_state = AFS_VNODE_LOCK_WAITING_FOR_CB; afs_lock_may_be_available(vnode); diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 211343831c30..1a4ce07fb406 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -545,6 +545,8 @@ void afs_evict_inode(struct inode *inode) #endif afs_put_permits(rcu_access_pointer(vnode->permit_cache)); + key_put(vnode->lock_key); + vnode->lock_key = NULL; _leave(""); } -- cgit v1.2.3-58-ga151 From 7a75b0079a1d54e342c502c3c8107ba97e05d3d3 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 10 Jan 2019 15:14:29 +0000 Subject: afs: Provide a function to get a ref on a call Provide a function to get a reference on an afs_call struct. Signed-off-by: David Howells --- fs/afs/rxrpc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index a7b44863d502..4830e0a6bf1d 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -203,20 +203,26 @@ void afs_put_call(struct afs_call *call) } } +static struct afs_call *afs_get_call(struct afs_call *call, + enum afs_call_trace why) +{ + int u = atomic_inc_return(&call->usage); + + trace_afs_call(call, why, u, + atomic_read(&call->net->nr_outstanding_calls), + __builtin_return_address(0)); + return call; +} + /* * Queue the call for actual work. */ static void afs_queue_call_work(struct afs_call *call) { if (call->type->work) { - int u = atomic_inc_return(&call->usage); - - trace_afs_call(call, afs_call_trace_work, u, - atomic_read(&call->net->nr_outstanding_calls), - __builtin_return_address(0)); - INIT_WORK(&call->work, call->type->work); + afs_get_call(call, afs_call_trace_work); if (!queue_work(afs_wq, &call->work)) afs_put_call(call); } -- cgit v1.2.3-58-ga151 From 34fa47612bfe5d7de7fcaf658a6952b6aeec3b13 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 10 Jan 2019 15:40:50 +0000 Subject: afs: Fix race in async call refcounting There's a race between afs_make_call() and afs_wake_up_async_call() in the case that an error is returned from rxrpc_kernel_send_data() after it has queued the final packet. afs_make_call() will try and clean up the mess, but the call state may have been moved on thereby causing afs_process_async_call() to also try and to delete the call. Fix this by: (1) Getting an extra ref for an asynchronous call for the call itself to hold. This makes sure the call doesn't evaporate on us accidentally and will allow the call to be retained by the caller in a future patch. The ref is released on leaving afs_make_call() or afs_wait_for_call_to_complete(). (2) In the event of an error from rxrpc_kernel_send_data(): (a) Don't set the call state to AFS_CALL_COMPLETE until *after* the call has been aborted and ended. This prevents afs_deliver_to_call() from doing anything with any notifications it gets. (b) Explicitly end the call immediately to prevent further callbacks. (c) Cancel any queued async_work and wait for the work if it's executing. This allows us to be sure the race won't recur when we change the state. We put the work queue's ref on the call if we managed to cancel it. (d) Put the call's ref that we got in (1). This belongs to us as long as the call is in state AFS_CALL_CL_REQUESTING. Fixes: 341f741f04be ("afs: Refcount the afs_call struct") Signed-off-by: David Howells --- fs/afs/rxrpc.c | 35 ++++++++++++++++++++++++++++++----- include/trace/events/afs.h | 2 ++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 4830e0a6bf1d..2c588f9bbbda 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -23,6 +23,7 @@ struct workqueue_struct *afs_async_calls; static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); static long afs_wait_for_call_to_complete(struct afs_call *, struct afs_addr_cursor *); static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); +static void afs_delete_async_call(struct work_struct *); static void afs_process_async_call(struct work_struct *); static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long); static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long); @@ -404,6 +405,12 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, } } + /* If the call is going to be asynchronous, we need an extra ref for + * the call to hold itself so the caller need not hang on to its ref. + */ + if (call->async) + afs_get_call(call, afs_call_trace_get); + /* create a call */ rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, (unsigned long)call, @@ -444,15 +451,17 @@ long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, goto error_do_abort; } - /* at this point, an async call may no longer exist as it may have - * already completed */ - if (call->async) + /* Note that at this point, we may have received the reply or an abort + * - and an asynchronous call may already have completed. + */ + if (call->async) { + afs_put_call(call); return -EINPROGRESS; + } return afs_wait_for_call_to_complete(call, ac); error_do_abort: - call->state = AFS_CALL_COMPLETE; if (ret != -ECONNABORTED) { rxrpc_kernel_abort_call(call->net->socket, rxcall, RX_USER_ABORT, ret, "KSD"); @@ -469,8 +478,24 @@ error_do_abort: error_kill_call: if (call->type->done) call->type->done(call); - afs_put_call(call); + + /* We need to dispose of the extra ref we grabbed for an async call. + * The call, however, might be queued on afs_async_calls and we need to + * make sure we don't get any more notifications that might requeue it. + */ + if (call->rxcall) { + rxrpc_kernel_end_call(call->net->socket, call->rxcall); + call->rxcall = NULL; + } + if (call->async) { + if (cancel_work_sync(&call->async_work)) + afs_put_call(call); + afs_put_call(call); + } + ac->error = ret; + call->state = AFS_CALL_COMPLETE; + afs_put_call(call); _leave(" = %d", ret); return ret; } diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 33d291888ba9..e3f005eae1f7 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -25,6 +25,7 @@ enum afs_call_trace { afs_call_trace_alloc, afs_call_trace_free, + afs_call_trace_get, afs_call_trace_put, afs_call_trace_wake, afs_call_trace_work, @@ -159,6 +160,7 @@ enum afs_file_error { #define afs_call_traces \ EM(afs_call_trace_alloc, "ALLOC") \ EM(afs_call_trace_free, "FREE ") \ + EM(afs_call_trace_get, "GET ") \ EM(afs_call_trace_put, "PUT ") \ EM(afs_call_trace_wake, "WAKE ") \ E_(afs_call_trace_work, "WORK ") -- cgit v1.2.3-58-ga151 From 0b698005a9d11c0e91141ec11a2c4918a129f703 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 16 Jan 2019 14:03:15 -0800 Subject: bpf: don't assume build-id length is always 20 bytes Build-id length is not fixed to 20, it can be (`man ld` /--build-id): * 128-bit (uuid) * 160-bit (sha1) * any length specified in ld --build-id=0xhexstring To fix the issue of missing BPF_STACK_BUILD_ID_VALID for shorter build-ids, assume that build-id is somewhere in the range of 1 .. 20. Set the remaining bytes to zero. v2: * don't introduce new "len = min(BPF_BUILD_ID_SIZE, nhdr->n_descsz)", we already know that nhdr->n_descsz <= BPF_BUILD_ID_SIZE if we enter this 'if' condition Fixes: 615755a77b24 ("bpf: extend stackmap to save binary_build_id+offset instead of address") Acked-by: Song Liu Signed-off-by: Stanislav Fomichev Signed-off-by: Daniel Borkmann --- kernel/bpf/stackmap.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index d9e2483669d0..f9df545e92f6 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -180,11 +180,14 @@ static inline int stack_map_parse_build_id(void *page_addr, if (nhdr->n_type == BPF_BUILD_ID && nhdr->n_namesz == sizeof("GNU") && - nhdr->n_descsz == BPF_BUILD_ID_SIZE) { + nhdr->n_descsz > 0 && + nhdr->n_descsz <= BPF_BUILD_ID_SIZE) { memcpy(build_id, note_start + note_offs + ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr), - BPF_BUILD_ID_SIZE); + nhdr->n_descsz); + memset(build_id + nhdr->n_descsz, 0, + BPF_BUILD_ID_SIZE - nhdr->n_descsz); return 0; } new_offs = note_offs + sizeof(Elf32_Nhdr) + -- cgit v1.2.3-58-ga151 From 4af396ae4836c4ecab61e975b8e61270c551894d Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 16 Jan 2019 14:03:16 -0800 Subject: bpf: zero out build_id for BPF_STACK_BUILD_ID_IP When returning BPF_STACK_BUILD_ID_IP from stack_map_get_build_id_offset, make sure that build_id field is empty. Since we are using percpu free list, there is a possibility that we might reuse some previous bpf_stack_build_id with non-zero build_id. Fixes: 615755a77b24 ("bpf: extend stackmap to save binary_build_id+offset instead of address") Acked-by: Song Liu Signed-off-by: Stanislav Fomichev Signed-off-by: Daniel Borkmann --- kernel/bpf/stackmap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index f9df545e92f6..d43b14535827 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -314,6 +314,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs, for (i = 0; i < trace_nr; i++) { id_offs[i].status = BPF_STACK_BUILD_ID_IP; id_offs[i].ip = ips[i]; + memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE); } return; } @@ -324,6 +325,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs, /* per entry fall back to ips */ id_offs[i].status = BPF_STACK_BUILD_ID_IP; id_offs[i].ip = ips[i]; + memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE); continue; } id_offs[i].offset = (vma->vm_pgoff << PAGE_SHIFT) + ips[i] -- cgit v1.2.3-58-ga151 From f67ad87ab3120e82845521b18a2b99273a340308 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Wed, 16 Jan 2019 14:03:17 -0800 Subject: selftests/bpf: retry tests that expect build-id While running test_progs in a loop I found out that I'm sometimes hitting "Didn't find expected build ID from the map" error. Looking at stack_map_get_build_id_offset() it seems that it is racy (by design) and can sometimes return BPF_STACK_BUILD_ID_IP (i.e. can't trylock current->mm->mmap_sem). Let's retry this test a single time. Fixes: 13790d1cc72c ("bpf: add selftest for stackmap with build_id in NMI context") Acked-by: Song Liu Signed-off-by: Stanislav Fomichev Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_progs.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 126fc624290d..25f0083a9b2e 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -1188,7 +1188,9 @@ static void test_stacktrace_build_id(void) int i, j; struct bpf_stack_build_id id_offs[PERF_MAX_STACK_DEPTH]; int build_id_matches = 0; + int retry = 1; +retry: err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno)) goto out; @@ -1301,6 +1303,19 @@ static void test_stacktrace_build_id(void) previous_key = key; } while (bpf_map_get_next_key(stackmap_fd, &previous_key, &key) == 0); + /* stack_map_get_build_id_offset() is racy and sometimes can return + * BPF_STACK_BUILD_ID_IP instead of BPF_STACK_BUILD_ID_VALID; + * try it one more time. + */ + if (build_id_matches < 1 && retry--) { + ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); + close(pmu_fd); + bpf_object__close(obj); + printf("%s:WARN:Didn't find expected build ID from the map, retrying\n", + __func__); + goto retry; + } + if (CHECK(build_id_matches < 1, "build id match", "Didn't find expected build ID from the map\n")) goto disable_pmu; @@ -1341,7 +1356,9 @@ static void test_stacktrace_build_id_nmi(void) int i, j; struct bpf_stack_build_id id_offs[PERF_MAX_STACK_DEPTH]; int build_id_matches = 0; + int retry = 1; +retry: err = bpf_prog_load(file, BPF_PROG_TYPE_PERF_EVENT, &obj, &prog_fd); if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno)) return; @@ -1436,6 +1453,19 @@ static void test_stacktrace_build_id_nmi(void) previous_key = key; } while (bpf_map_get_next_key(stackmap_fd, &previous_key, &key) == 0); + /* stack_map_get_build_id_offset() is racy and sometimes can return + * BPF_STACK_BUILD_ID_IP instead of BPF_STACK_BUILD_ID_VALID; + * try it one more time. + */ + if (build_id_matches < 1 && retry--) { + ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); + close(pmu_fd); + bpf_object__close(obj); + printf("%s:WARN:Didn't find expected build ID from the map, retrying\n", + __func__); + goto retry; + } + if (CHECK(build_id_matches < 1, "build id match", "Didn't find expected build ID from the map\n")) goto disable_pmu; -- cgit v1.2.3-58-ga151 From 583c53185399cea5c51195064564d1c9ddc70cf3 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 16 Jan 2019 20:29:40 +0100 Subject: bpf: Make function btf_name_offset_valid static Initially in commit 69b693f0aefa ("bpf: btf: Introduce BPF Type Format (BTF)") the function 'btf_name_offset_valid' was introduced as static function it was later on changed to a non-static one, and then finally in commit 23127b33ec80 ("bpf: Create a new btf_name_by_offset() for non type name use case") the function prototype was removed. Revert back to original implementation and make the function static. Remove warning triggered with W=1: kernel/bpf/btf.c:470:6: warning: no previous prototype for 'btf_name_offset_valid' [-Wmissing-prototypes] Fixes: 23127b33ec80 ("bpf: Create a new btf_name_by_offset() for non type name use case") Signed-off-by: Mathieu Malaterre Acked-by: Martin KaFai Lau Signed-off-by: Daniel Borkmann --- kernel/bpf/btf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index a2f53642592b..befe570be5ba 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -467,7 +467,7 @@ static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) return kind_ops[BTF_INFO_KIND(t->info)]; } -bool btf_name_offset_valid(const struct btf *btf, u32 offset) +static bool btf_name_offset_valid(const struct btf *btf, u32 offset) { return BTF_STR_OFFSET_VALID(offset) && offset < btf->hdr.str_len; -- cgit v1.2.3-58-ga151 From c8dc79806e7f6cb6b0952aae1ce626c39905ad7e Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 16 Jan 2019 20:35:29 +0100 Subject: bpf: Annotate implicit fall through in cgroup_dev_func_proto There is a plan to build the kernel with -Wimplicit-fallthrough and this place in the code produced a warnings (W=1). This commit removes the following warning: kernel/bpf/cgroup.c:719:6: warning: this statement may fall through [-Wimplicit-fallthrough=] Signed-off-by: Mathieu Malaterre Signed-off-by: Daniel Borkmann --- kernel/bpf/cgroup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 9425c2fb872f..ab612fe9862f 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -718,6 +718,7 @@ cgroup_dev_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_trace_printk: if (capable(CAP_SYS_ADMIN)) return bpf_get_trace_printk_proto(); + /* fall through */ default: return NULL; } -- cgit v1.2.3-58-ga151 From c61c27687a5abce11431e6de1adb6e36099b9859 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 16 Jan 2019 20:35:41 +0100 Subject: bpf: Correctly annotate implicit fall through in bpf_base_func_proto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a plan to build the kernel with -Wimplicit-fallthrough and this place in the code produced a warnings (W=1). To preserve as much of the existing comment only change a ‘:’ into a ‘,’. This is enough change, to match the regular expression expected by GCC. This commit removes the following warning: net/core/filter.c:5310:6: warning: this statement may fall through [-Wimplicit-fallthrough=] Signed-off-by: Mathieu Malaterre Signed-off-by: Daniel Borkmann --- net/core/filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/filter.c b/net/core/filter.c index 2b3b436ef545..d9076e609fca 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -5309,7 +5309,7 @@ bpf_base_func_proto(enum bpf_func_id func_id) case BPF_FUNC_trace_printk: if (capable(CAP_SYS_ADMIN)) return bpf_get_trace_printk_proto(); - /* else: fall through */ + /* else, fall through */ default: return NULL; } -- cgit v1.2.3-58-ga151 From 4dcf9ddc9ad5ab649abafa98c5a4d54b1a33dabb Mon Sep 17 00:00:00 2001 From: Charles Yeh Date: Tue, 15 Jan 2019 23:13:56 +0800 Subject: USB: serial: pl2303: add new PID to support PL2303TB Add new PID to support PL2303TB (TYPE_HX) Signed-off-by: Charles Yeh Cc: stable Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 98e7a5df0f6d..bb3f9aa4a909 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -46,6 +46,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID), diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 4e2554d55362..559941ca884d 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -8,6 +8,7 @@ #define PL2303_VENDOR_ID 0x067b #define PL2303_PRODUCT_ID 0x2303 +#define PL2303_PRODUCT_ID_TB 0x2304 #define PL2303_PRODUCT_ID_RSAQ2 0x04bb #define PL2303_PRODUCT_ID_DCU11 0x1234 #define PL2303_PRODUCT_ID_PHAROS 0xaaa0 @@ -20,6 +21,7 @@ #define PL2303_PRODUCT_ID_MOTOROLA 0x0307 #define PL2303_PRODUCT_ID_ZTEK 0xe1f1 + #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 #define ATEN_PRODUCT_ID 0x2008 -- cgit v1.2.3-58-ga151 From 1d47f48bf2d1608c2d6eb76b3ec7a5ec0c3f9e95 Mon Sep 17 00:00:00 2001 From: Loic Pallardy Date: Fri, 11 Jan 2019 18:54:31 +0100 Subject: irqchip/stm32-exti: Add domain translate function Domain translate function is needed to recover irq configuration parameters from DT node Fixes: 927abfc4461e ("irqchip/stm32: Add stm32mp1 support with hierarchy domain") Signed-off-by: Loic Pallardy Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-stm32-exti.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 6edfd4bfa169..a93296b9b45d 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -822,6 +822,7 @@ out_unmap: static const struct irq_domain_ops stm32_exti_h_domain_ops = { .alloc = stm32_exti_h_domain_alloc, .free = irq_domain_free_irqs_common, + .xlate = irq_domain_xlate_twocell, }; static int -- cgit v1.2.3-58-ga151 From c530bb8a726a37811e9fb5d68cd6b5408173b545 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Fri, 26 Oct 2018 15:51:17 +0800 Subject: irqchip/gic-v3-mbi: Fix uninitialized mbi_lock The mbi_lock mutex is left uninitialized, so let's use DEFINE_MUTEX to initialize it statically. Fixes: 505287525c24d ("irqchip/gic-v3: Add support for Message Based Interrupts as an MSI controller") Signed-off-by: Yang Yingliang Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-mbi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3-mbi.c b/drivers/irqchip/irq-gic-v3-mbi.c index ad70e7c416e3..fbfa7ff6deb1 100644 --- a/drivers/irqchip/irq-gic-v3-mbi.c +++ b/drivers/irqchip/irq-gic-v3-mbi.c @@ -24,7 +24,7 @@ struct mbi_range { unsigned long *bm; }; -static struct mutex mbi_lock; +static DEFINE_MUTEX(mbi_lock); static phys_addr_t mbi_phys_base; static struct mbi_range *mbi_ranges; static unsigned int mbi_range_nr; -- cgit v1.2.3-58-ga151 From 8fa4e55bbfbfca3ad996517f679ab3648c03d8bb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 3 Jan 2019 11:26:23 +0100 Subject: irqchip/madera: Drop GPIO includes This irqchip does not use anything GPIO-related so drop the GPIO includes. Signed-off-by: Linus Walleij Acked-by: Richard Fitzgerald Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-madera.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/irqchip/irq-madera.c b/drivers/irqchip/irq-madera.c index e9256dee1a45..8b81271c823c 100644 --- a/drivers/irqchip/irq-madera.c +++ b/drivers/irqchip/irq-madera.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include @@ -16,7 +15,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-58-ga151 From 6a4c9ab13feeacd3072175d7d1f1fcfabbb9fc90 Mon Sep 17 00:00:00 2001 From: Sai Prakash Ranjan Date: Thu, 17 Jan 2019 09:09:29 -0800 Subject: pstore/ram: Fix console ramoops to show the previous boot logs commit b05c950698fe ("pstore/ram: Simplify ramoops_get_next_prz() arguments") changed update assignment in getting next persistent ram zone by adding a check for record type. But the check always returns true since the record type is assigned 0. And this breaks console ramoops by showing current console log instead of previous log on warm reset and hard reset (actually hard reset should not be showing any logs). Fix this by having persistent ram zone type check instead of record type check. Tested this on SDM845 MTP and dragonboard 410c. Reproducing this issue is simple as below: 1. Trigger hard reset and mount pstore. Will see console-ramoops record in the mounted location which is the current log. 2. Trigger warm reset and mount pstore. Will see the current console-ramoops record instead of previous record. Fixes: b05c950698fe ("pstore/ram: Simplify ramoops_get_next_prz() arguments") Signed-off-by: Sai Prakash Ranjan Acked-by: Joel Fernandes (Google) [kees: dropped local variable usage] Signed-off-by: Kees Cook --- fs/pstore/ram.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 96f7d32cd184..076e26fdc0c0 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -128,7 +128,6 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], int id, struct pstore_record *record) { struct persistent_ram_zone *prz; - bool update = (record->type == PSTORE_TYPE_DMESG); /* Give up if we never existed or have hit the end. */ if (!przs) @@ -139,7 +138,7 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], int id, return NULL; /* Update old/shadowed buffer. */ - if (update) + if (prz->type == PSTORE_TYPE_DMESG) persistent_ram_save_old(prz); if (!persistent_ram_old_size(prz)) -- cgit v1.2.3-58-ga151 From 3d244c192afeee7dd4f5fb1b916ea4e47420d401 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 16 Jan 2019 16:35:25 -0800 Subject: selftests/seccomp: Abort without user notification support In the face of missing user notification support, the self test needs to stop executing a test (ASSERT_*) instead of just reporting and continuing (EXPECT_*). This adjusts the user notification tests to do that where needed. Reported-by: Shuah Khan Fixes: 6a21cc50f0c7 ("seccomp: add a return code to trap to userspace") Signed-off-by: Kees Cook Reviewed-by: Tycho Andersen Tested-by: Shuah Khan Signed-off-by: Shuah Khan --- tools/testing/selftests/seccomp/seccomp_bpf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 067cb4607d6c..496a9a8c773a 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -3044,7 +3044,7 @@ TEST(user_notification_basic) /* Check that the basic notification machinery works */ listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER); - EXPECT_GE(listener, 0); + ASSERT_GE(listener, 0); /* Installing a second listener in the chain should EBUSY */ EXPECT_EQ(user_trap_syscall(__NR_getpid, @@ -3103,7 +3103,7 @@ TEST(user_notification_kill_in_middle) listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER); - EXPECT_GE(listener, 0); + ASSERT_GE(listener, 0); /* * Check that nothing bad happens when we kill the task in the middle @@ -3152,7 +3152,7 @@ TEST(user_notification_signal) listener = user_trap_syscall(__NR_gettid, SECCOMP_FILTER_FLAG_NEW_LISTENER); - EXPECT_GE(listener, 0); + ASSERT_GE(listener, 0); pid = fork(); ASSERT_GE(pid, 0); @@ -3215,7 +3215,7 @@ TEST(user_notification_closed_listener) listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER); - EXPECT_GE(listener, 0); + ASSERT_GE(listener, 0); /* * Check that we get an ENOSYS when the listener is closed. @@ -3376,7 +3376,7 @@ TEST(seccomp_get_notif_sizes) { struct seccomp_notif_sizes sizes; - EXPECT_EQ(seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes), 0); + ASSERT_EQ(seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes), 0); EXPECT_EQ(sizes.seccomp_notif, sizeof(struct seccomp_notif)); EXPECT_EQ(sizes.seccomp_notif_resp, sizeof(struct seccomp_notif_resp)); } -- cgit v1.2.3-58-ga151 From cb12d72b27a6f41325ae23a11033cf5fedfa1b97 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 15 Jan 2019 18:03:38 +0000 Subject: atm: he: fix sign-extension overflow on large shift Shifting the 1 by exp by an int can lead to sign-extension overlow when exp is 31 since 1 is an signed int and sign-extending this result to an unsigned long long will set the upper 32 bits. Fix this by shifting an unsigned long. Detected by cppcheck: (warning) Shifting signed 32-bit value by 31 bits is undefined behaviour Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/atm/he.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 2e9d1cfe3aeb..211607986134 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -718,7 +718,7 @@ static int he_init_cs_block_rcm(struct he_dev *he_dev) instead of '/ 512', use '>> 9' to prevent a call to divdu3 on x86 platforms */ - rate_cps = (unsigned long long) (1 << exp) * (man + 512) >> 9; + rate_cps = (unsigned long long) (1UL << exp) * (man + 512) >> 9; if (rate_cps < 10) rate_cps = 10; /* 2.2.1 minimum payload rate is 10 cps */ -- cgit v1.2.3-58-ga151 From f15f3eb26e8d9d25ea2330ed1273473df2f039df Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 15 Jan 2019 12:09:09 -0500 Subject: drm/amdgpu: Add APTX quirk for Lenovo laptop Needs ATPX rather than _PR3 for dGPU power control. Bug: https://bugzilla.kernel.org/show_bug.cgi?id=202263 Reviewed-by: Jim Qu Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index a028661d9e20..92b11de19581 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -576,6 +576,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1025, 0x125A, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0x1002, 0x6900, 0x17AA, 0x3806, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0, 0, 0, 0, 0 }, }; -- cgit v1.2.3-58-ga151 From f422449b58548a41e98fc97b259a283718e527db Mon Sep 17 00:00:00 2001 From: Cheng-Min Ao Date: Mon, 7 Jan 2019 14:29:32 +0800 Subject: hwmon: (tmp421) Correct the misspelling of the tmp442 compatible attribute in OF device ID table Correct a typo in OF device ID table The last one should be 'ti,tmp442' Signed-off-by: Cheng-Min Ao Signed-off-by: Yu-Hsiang Chen Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp421.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index 8844c9565d2a..7053be59ad2e 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -88,7 +88,7 @@ static const struct of_device_id tmp421_of_match[] = { .data = (void *)2 }, { - .compatible = "ti,tmp422", + .compatible = "ti,tmp442", .data = (void *)3 }, { }, -- cgit v1.2.3-58-ga151 From 248b57015f35c94d4eae2fdd8c6febf5cd703900 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Tue, 25 Dec 2018 22:18:23 -0600 Subject: leds: lp5523: fix a missing check of return value of lp55xx_read When lp55xx_read() fails, "status" is an uninitialized variable and thus may contain random value; using it leads to undefined behaviors. The fix inserts a check for the return value of lp55xx_read: if it fails, returns with its error code. Signed-off-by: Kangjie Lu Signed-off-by: Jacek Anaszewski --- drivers/leds/leds-lp5523.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index a2e74feee2b2..fd64df5a57a5 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -318,7 +318,9 @@ static int lp5523_init_program_engine(struct lp55xx_chip *chip) /* Let the programs run for couple of ms and check the engine status */ usleep_range(3000, 6000); - lp55xx_read(chip, LP5523_REG_STATUS, &status); + ret = lp55xx_read(chip, LP5523_REG_STATUS, &status); + if (ret) + return ret; status &= LP5523_ENG_STATUS_MASK; if (status != LP5523_ENG_STATUS_MASK) { -- cgit v1.2.3-58-ga151 From 3f1bb6abdf19cfa89860b3bc9e7f31b44b6a0ba1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 16 Jan 2019 11:27:08 +0100 Subject: net: dsa: realtek-smi: fix OF child-node lookup Use the new of_get_compatible_child() helper to look up child nodes to avoid ever matching non-child nodes elsewhere in the tree. Also fix up the related struct device_node leaks. Fixes: d8652956cf37 ("net: dsa: realtek-smi: Add Realtek SMI driver") Cc: stable # 4.19: 36156f9241cb0 Cc: Linus Walleij Signed-off-by: Johan Hovold Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/realtek-smi.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/realtek-smi.c b/drivers/net/dsa/realtek-smi.c index b4b839a1d095..ad41ec63cc9f 100644 --- a/drivers/net/dsa/realtek-smi.c +++ b/drivers/net/dsa/realtek-smi.c @@ -347,16 +347,17 @@ int realtek_smi_setup_mdio(struct realtek_smi *smi) struct device_node *mdio_np; int ret; - mdio_np = of_find_compatible_node(smi->dev->of_node, NULL, - "realtek,smi-mdio"); + mdio_np = of_get_compatible_child(smi->dev->of_node, "realtek,smi-mdio"); if (!mdio_np) { dev_err(smi->dev, "no MDIO bus node\n"); return -ENODEV; } smi->slave_mii_bus = devm_mdiobus_alloc(smi->dev); - if (!smi->slave_mii_bus) - return -ENOMEM; + if (!smi->slave_mii_bus) { + ret = -ENOMEM; + goto err_put_node; + } smi->slave_mii_bus->priv = smi; smi->slave_mii_bus->name = "SMI slave MII"; smi->slave_mii_bus->read = realtek_smi_mdio_read; @@ -371,10 +372,15 @@ int realtek_smi_setup_mdio(struct realtek_smi *smi) if (ret) { dev_err(smi->dev, "unable to register MDIO bus %s\n", smi->slave_mii_bus->id); - of_node_put(mdio_np); + goto err_put_node; } return 0; + +err_put_node: + of_node_put(mdio_np); + + return ret; } static int realtek_smi_probe(struct platform_device *pdev) @@ -457,6 +463,8 @@ static int realtek_smi_remove(struct platform_device *pdev) struct realtek_smi *smi = dev_get_drvdata(&pdev->dev); dsa_unregister_switch(smi->ds); + if (smi->slave_mii_bus) + of_node_put(smi->slave_mii_bus->dev.of_node); gpiod_set_value(smi->reset, 1); return 0; -- cgit v1.2.3-58-ga151 From 97e981324d492340e33baa9680780046377b561f Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 6 Dec 2018 00:17:50 -0800 Subject: ARCv2: boot log: BPU return stack depth Signed-off-by: Vineet Gupta --- arch/arc/include/asm/arcregs.h | 2 +- arch/arc/kernel/setup.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 49bfbd879caa..9f10d32ee1bd 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -283,7 +283,7 @@ struct cpuinfo_arc_cache { }; struct cpuinfo_arc_bpu { - unsigned int ver, full, num_cache, num_pred; + unsigned int ver, full, num_cache, num_pred, ret_stk; }; struct cpuinfo_arc_ccm { diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 2e018b8c2e19..33e232145d83 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -195,6 +195,7 @@ static void read_arc_build_cfg_regs(void) cpu->bpu.full = bpu.ft; cpu->bpu.num_cache = 256 << bpu.bce; cpu->bpu.num_pred = 2048 << bpu.pte; + cpu->bpu.ret_stk = 4 << bpu.rse; if (cpu->core.family >= 0x54) { unsigned int exec_ctrl; @@ -299,10 +300,10 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len) if (cpu->bpu.ver) n += scnprintf(buf + n, len - n, - "BPU\t\t: %s%s match, cache:%d, Predict Table:%d", + "BPU\t\t: %s%s match, cache:%d, Predict Table:%d Return stk: %d", IS_AVAIL1(cpu->bpu.full, "full"), IS_AVAIL1(!cpu->bpu.full, "partial"), - cpu->bpu.num_cache, cpu->bpu.num_pred); + cpu->bpu.num_cache, cpu->bpu.num_pred, cpu->bpu.ret_stk); if (is_isa_arcv2()) { struct bcr_lpb lpb; -- cgit v1.2.3-58-ga151 From 7dd380c338f1ec20ed46607ccd03541a7683cd67 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Wed, 9 Jan 2019 09:36:00 -0800 Subject: ARC: boot log: print Action point details This now prints the number of action points {2,4,8} and {min,full} targets supported. Signed-off-by: Vineet Gupta --- arch/arc/include/asm/arcregs.h | 10 +++++++++- arch/arc/kernel/setup.c | 22 +++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 9f10d32ee1bd..f1b86cef0905 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -216,6 +216,14 @@ struct bcr_fp_arcv2 { #endif }; +struct bcr_actionpoint { +#ifdef CONFIG_CPU_BIG_ENDIAN + unsigned int pad:21, min:1, num:2, ver:8; +#else + unsigned int ver:8, num:2, min:1, pad:21; +#endif +}; + #include struct bcr_bpu_arcompact { @@ -302,7 +310,7 @@ struct cpuinfo_arc { struct { unsigned int swap:1, norm:1, minmax:1, barrel:1, crc:1, swape:1, pad1:2, fpu_sp:1, fpu_dp:1, dual:1, dual_enb:1, pad2:4, - debug:1, ap:1, smart:1, rtt:1, pad3:4, + ap_num:4, ap_full:1, smart:1, rtt:1, pad3:1, timer0:1, timer1:1, rtc:1, gfrc:1, pad4:4; } extn; struct bcr_mpy extn_mpy; diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 33e232145d83..feb90093e6b1 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c @@ -123,6 +123,7 @@ static void read_arc_build_cfg_regs(void) struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()]; const struct id_to_str *tbl; struct bcr_isa_arcv2 isa; + struct bcr_actionpoint ap; FIX_PTR(cpu); @@ -208,8 +209,11 @@ static void read_arc_build_cfg_regs(void) } } - READ_BCR(ARC_REG_AP_BCR, bcr); - cpu->extn.ap = bcr.ver ? 1 : 0; + READ_BCR(ARC_REG_AP_BCR, ap); + if (ap.ver) { + cpu->extn.ap_num = 2 << ap.num; + cpu->extn.ap_full = !!ap.min; + } READ_BCR(ARC_REG_SMART_BCR, bcr); cpu->extn.smart = bcr.ver ? 1 : 0; @@ -217,8 +221,6 @@ static void read_arc_build_cfg_regs(void) READ_BCR(ARC_REG_RTT_BCR, bcr); cpu->extn.rtt = bcr.ver ? 1 : 0; - cpu->extn.debug = cpu->extn.ap | cpu->extn.smart | cpu->extn.rtt; - READ_BCR(ARC_REG_ISA_CFG_BCR, isa); /* some hacks for lack of feature BCR info in old ARC700 cores */ @@ -337,11 +339,17 @@ static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len) IS_AVAIL1(cpu->extn.fpu_sp, "SP "), IS_AVAIL1(cpu->extn.fpu_dp, "DP ")); - if (cpu->extn.debug) - n += scnprintf(buf + n, len - n, "DEBUG\t\t: %s%s%s\n", - IS_AVAIL1(cpu->extn.ap, "ActionPoint "), + if (cpu->extn.ap_num | cpu->extn.smart | cpu->extn.rtt) { + n += scnprintf(buf + n, len - n, "DEBUG\t\t: %s%s", IS_AVAIL1(cpu->extn.smart, "smaRT "), IS_AVAIL1(cpu->extn.rtt, "RTT ")); + if (cpu->extn.ap_num) { + n += scnprintf(buf + n, len - n, "ActionPoint %d/%s", + cpu->extn.ap_num, + cpu->extn.ap_full ? "full":"min"); + } + n += scnprintf(buf + n, len - n, "\n"); + } if (cpu->dccm.sz || cpu->iccm.sz) n += scnprintf(buf + n, len - n, "Extn [CCM]\t: DCCM @ %x, %d KB / ICCM: @ %x, %d KB\n", -- cgit v1.2.3-58-ga151 From 4e868f8419cb4cb558c5d428e7ab5629cef864c7 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 13 Dec 2018 18:42:57 +0300 Subject: ARC: fix __ffs return value to avoid build warnings | CC mm/nobootmem.o |In file included from ./include/asm-generic/bug.h:18:0, | from ./arch/arc/include/asm/bug.h:32, | from ./include/linux/bug.h:5, | from ./include/linux/mmdebug.h:5, | from ./include/linux/gfp.h:5, | from ./include/linux/slab.h:15, | from mm/nobootmem.c:14: |mm/nobootmem.c: In function '__free_pages_memory': |./include/linux/kernel.h:845:29: warning: comparison of distinct pointer types lacks a cast | (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1))) | ^ |./include/linux/kernel.h:859:4: note: in expansion of macro '__typecheck' | (__typecheck(x, y) && __no_side_effects(x, y)) | ^~~~~~~~~~~ |./include/linux/kernel.h:869:24: note: in expansion of macro '__safe_cmp' | __builtin_choose_expr(__safe_cmp(x, y), \ | ^~~~~~~~~~ |./include/linux/kernel.h:878:19: note: in expansion of macro '__careful_cmp' | #define min(x, y) __careful_cmp(x, y, <) | ^~~~~~~~~~~~~ |mm/nobootmem.c:104:11: note: in expansion of macro 'min' | order = min(MAX_ORDER - 1UL, __ffs(start)); Change __ffs return value from 'int' to 'unsigned long' as it is done in other implementations (like asm-generic, x86, etc...) to avoid build-time warnings in places where type is strictly checked. As __ffs may return values in [0-31] interval changing return type to unsigned is valid. Signed-off-by: Eugeniy Paltsev Signed-off-by: Vineet Gupta --- arch/arc/include/asm/bitops.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arc/include/asm/bitops.h b/arch/arc/include/asm/bitops.h index ee9246184033..202b74c339f0 100644 --- a/arch/arc/include/asm/bitops.h +++ b/arch/arc/include/asm/bitops.h @@ -340,7 +340,7 @@ static inline __attribute__ ((const)) int __fls(unsigned long x) /* * __ffs: Similar to ffs, but zero based (0-31) */ -static inline __attribute__ ((const)) int __ffs(unsigned long word) +static inline __attribute__ ((const)) unsigned long __ffs(unsigned long word) { if (!word) return word; @@ -400,9 +400,9 @@ static inline __attribute__ ((const)) int ffs(unsigned long x) /* * __ffs: Similar to ffs, but zero based (0-31) */ -static inline __attribute__ ((const)) int __ffs(unsigned long x) +static inline __attribute__ ((const)) unsigned long __ffs(unsigned long x) { - int n; + unsigned long n; asm volatile( " ffs.f %0, %1 \n" /* 0:31; 31(Z) if src 0 */ -- cgit v1.2.3-58-ga151 From 76e6086760563164d91f61f1e3e58c6a2a031fa5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 16 Dec 2018 23:16:21 +0900 Subject: arc: remove redundant kernel-space generic-y This commit removes redundant generic-y defines in arch/arc/include/asm/Kbuild. It is redundant to define generic-y when arch-specific implementation exists in arch/$(ARCH)/include/asm/*.h Remove the following generic-y: dma-mapping.h fb.h kmap_types.h pci.h Signed-off-by: Masahiro Yamada Signed-off-by: Vineet Gupta --- arch/arc/include/asm/Kbuild | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild index feed50ce89fa..caa270261521 100644 --- a/arch/arc/include/asm/Kbuild +++ b/arch/arc/include/asm/Kbuild @@ -3,23 +3,19 @@ generic-y += bugs.h generic-y += compat.h generic-y += device.h generic-y += div64.h -generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += extable.h -generic-y += fb.h generic-y += ftrace.h generic-y += hardirq.h generic-y += hw_irq.h generic-y += irq_regs.h generic-y += irq_work.h -generic-y += kmap_types.h generic-y += local.h generic-y += local64.h generic-y += mcs_spinlock.h generic-y += mm-arch-hooks.h generic-y += msi.h generic-y += parport.h -generic-y += pci.h generic-y += percpu.h generic-y += preempt.h generic-y += topology.h -- cgit v1.2.3-58-ga151 From a3010a0465383300f909f62b8a83f83ffa7b2517 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Wed, 19 Dec 2018 19:16:16 +0300 Subject: ARC: adjust memblock_reserve of kernel memory In setup_arch_memory we reserve the memory area wherein the kernel is located. Current implementation may reserve more memory than it actually required in case of CONFIG_LINUX_LINK_BASE is not equal to CONFIG_LINUX_RAM_BASE. This happens because we calculate start of the reserved region relatively to the CONFIG_LINUX_RAM_BASE and end of the region relatively to the CONFIG_LINUX_RAM_BASE. For example in case of HSDK board we wasted 256MiB of physical memory: ------------------->8------------------------------ Memory: 770416K/1048576K available (5496K kernel code, 240K rwdata, 1064K rodata, 2200K init, 275K bss, 278160K reserved, 0K cma-reserved) ------------------->8------------------------------ Fix that. Fixes: 9ed68785f7f2b ("ARC: mm: Decouple RAM base address from kernel link addr") Cc: stable@vger.kernel.org #4.14+ Signed-off-by: Eugeniy Paltsev Signed-off-by: Vineet Gupta --- arch/arc/mm/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c index 43bf4c3a1290..e1ab2d7f1d64 100644 --- a/arch/arc/mm/init.c +++ b/arch/arc/mm/init.c @@ -119,7 +119,8 @@ void __init setup_arch_memory(void) */ memblock_add_node(low_mem_start, low_mem_sz, 0); - memblock_reserve(low_mem_start, __pa(_end) - low_mem_start); + memblock_reserve(CONFIG_LINUX_LINK_BASE, + __pa(_end) - CONFIG_LINUX_LINK_BASE); #ifdef CONFIG_BLK_DEV_INITRD if (phys_initrd_size) { -- cgit v1.2.3-58-ga151 From 3affbf0e154ee351add6fcc254c59c3f3947fa8f Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Mon, 17 Dec 2018 12:54:23 +0300 Subject: ARC: perf: map generic branches to correct hardware condition So far we've mapped branches to "ijmp" which also counts conditional branches NOT taken. This makes us different from other architectures such as ARM which seem to be counting only taken branches. So use "ijmptak" hardware condition which only counts (all jump instructions that are taken) 'ijmptak' event is available on both ARCompact and ARCv2 ISA based cores. Signed-off-by: Eugeniy Paltsev Cc: stable@vger.kernel.org Signed-off-by: Vineet Gupta [vgupta: reworked changelog] --- arch/arc/include/asm/perf_event.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arc/include/asm/perf_event.h b/arch/arc/include/asm/perf_event.h index 9185541035cc..6958545390f0 100644 --- a/arch/arc/include/asm/perf_event.h +++ b/arch/arc/include/asm/perf_event.h @@ -103,7 +103,8 @@ static const char * const arc_pmu_ev_hw_map[] = { /* counts condition */ [PERF_COUNT_HW_INSTRUCTIONS] = "iall", - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "ijmp", /* Excludes ZOL jumps */ + /* All jump instructions that are taken */ + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "ijmptak", [PERF_COUNT_ARC_BPOK] = "bpok", /* NP-NT, PT-T, PNT-NT */ #ifdef CONFIG_ISA_ARCV2 [PERF_COUNT_HW_BRANCH_MISSES] = "bpmp", -- cgit v1.2.3-58-ga151 From 14f81a91ad29a57d6c3cf123ad9489f2ca9133fb Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 13 Dec 2018 19:56:18 +0300 Subject: ARC: perf: trivial code cleanup * Use BIT(), lower_32_bits(), upper_32_bits() macroses, fix code style violations. * Use u32, u64, s64 instead of uint32_t, uint64_t, int64_t * Fix description comment as this code doesn't belong only to ARC700 anymore. * Use SPDX License Identifier. * Remove useless ifdefs. ifdef around 'arc_pmu_match' structure declaration is useless as we refer to 'arc_pmu_match' in several places which aren't guarded with ifdef. Nevertheless 'ARC' option selects 'OF' unconditionally so we can simply get rid of this ifdef. Acked-by: Vineet Gupta Signed-off-by: Eugeniy Paltsev Signed-off-by: Vineet Gupta --- arch/arc/kernel/perf_event.c | 85 ++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c index 8aec462d90fb..693f32d60c35 100644 --- a/arch/arc/kernel/perf_event.c +++ b/arch/arc/kernel/perf_event.c @@ -1,15 +1,10 @@ -/* - * Linux performance counter support for ARC700 series - * - * Copyright (C) 2013-2015 Synopsys, Inc. (www.synopsys.com) - * - * This code is inspired by the perf support of various other architectures. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// Linux performance counter support for ARC CPUs. +// This code is inspired by the perf support of various other architectures. +// +// Copyright (C) 2013-2018 Synopsys, Inc. (www.synopsys.com) + #include #include #include @@ -19,6 +14,9 @@ #include #include +/* HW holds 8 symbols + one for null terminator */ +#define ARCPMU_EVENT_NAME_LEN 9 + struct arc_pmu { struct pmu pmu; unsigned int irq; @@ -49,6 +47,7 @@ static int callchain_trace(unsigned int addr, void *data) { struct arc_callchain_trace *ctrl = data; struct perf_callchain_entry_ctx *entry = ctrl->perf_stuff; + perf_callchain_store(entry, addr); if (ctrl->depth++ < 3) @@ -57,8 +56,8 @@ static int callchain_trace(unsigned int addr, void *data) return -1; } -void -perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) +void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, + struct pt_regs *regs) { struct arc_callchain_trace ctrl = { .depth = 0, @@ -68,8 +67,8 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re arc_unwind_core(NULL, regs, callchain_trace, &ctrl); } -void -perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) +void perf_callchain_user(struct perf_callchain_entry_ctx *entry, + struct pt_regs *regs) { /* * User stack can't be unwound trivially with kernel dwarf unwinder @@ -82,10 +81,10 @@ static struct arc_pmu *arc_pmu; static DEFINE_PER_CPU(struct arc_pmu_cpu, arc_pmu_cpu); /* read counter #idx; note that counter# != event# on ARC! */ -static uint64_t arc_pmu_read_counter(int idx) +static u64 arc_pmu_read_counter(int idx) { - uint32_t tmp; - uint64_t result; + u32 tmp; + u64 result; /* * ARC supports making 'snapshots' of the counters, so we don't @@ -94,7 +93,7 @@ static uint64_t arc_pmu_read_counter(int idx) write_aux_reg(ARC_REG_PCT_INDEX, idx); tmp = read_aux_reg(ARC_REG_PCT_CONTROL); write_aux_reg(ARC_REG_PCT_CONTROL, tmp | ARC_REG_PCT_CONTROL_SN); - result = (uint64_t) (read_aux_reg(ARC_REG_PCT_SNAPH)) << 32; + result = (u64) (read_aux_reg(ARC_REG_PCT_SNAPH)) << 32; result |= read_aux_reg(ARC_REG_PCT_SNAPL); return result; @@ -103,9 +102,9 @@ static uint64_t arc_pmu_read_counter(int idx) static void arc_perf_event_update(struct perf_event *event, struct hw_perf_event *hwc, int idx) { - uint64_t prev_raw_count = local64_read(&hwc->prev_count); - uint64_t new_raw_count = arc_pmu_read_counter(idx); - int64_t delta = new_raw_count - prev_raw_count; + u64 prev_raw_count = local64_read(&hwc->prev_count); + u64 new_raw_count = arc_pmu_read_counter(idx); + s64 delta = new_raw_count - prev_raw_count; /* * We aren't afraid of hwc->prev_count changing beneath our feet @@ -155,7 +154,7 @@ static int arc_pmu_event_init(struct perf_event *event) int ret; if (!is_sampling_event(event)) { - hwc->sample_period = arc_pmu->max_period; + hwc->sample_period = arc_pmu->max_period; hwc->last_period = hwc->sample_period; local64_set(&hwc->period_left, hwc->sample_period); } @@ -192,6 +191,7 @@ static int arc_pmu_event_init(struct perf_event *event) pr_debug("init cache event with h/w %08x \'%s\'\n", (int)hwc->config, arc_pmu_ev_hw_map[ret]); return 0; + default: return -ENOENT; } @@ -200,7 +200,7 @@ static int arc_pmu_event_init(struct perf_event *event) /* starts all counters */ static void arc_pmu_enable(struct pmu *pmu) { - uint32_t tmp; + u32 tmp; tmp = read_aux_reg(ARC_REG_PCT_CONTROL); write_aux_reg(ARC_REG_PCT_CONTROL, (tmp & 0xffff0000) | 0x1); } @@ -208,7 +208,7 @@ static void arc_pmu_enable(struct pmu *pmu) /* stops all counters */ static void arc_pmu_disable(struct pmu *pmu) { - uint32_t tmp; + u32 tmp; tmp = read_aux_reg(ARC_REG_PCT_CONTROL); write_aux_reg(ARC_REG_PCT_CONTROL, (tmp & 0xffff0000) | 0x0); } @@ -228,7 +228,7 @@ static int arc_pmu_event_set_period(struct perf_event *event) local64_set(&hwc->period_left, left); hwc->last_period = period; overflow = 1; - } else if (unlikely(left <= 0)) { + } else if (unlikely(left <= 0)) { /* left underflowed by less than period. */ left += period; local64_set(&hwc->period_left, left); @@ -246,8 +246,8 @@ static int arc_pmu_event_set_period(struct perf_event *event) write_aux_reg(ARC_REG_PCT_INDEX, idx); /* Write value */ - write_aux_reg(ARC_REG_PCT_COUNTL, (u32)value); - write_aux_reg(ARC_REG_PCT_COUNTH, (value >> 32)); + write_aux_reg(ARC_REG_PCT_COUNTL, lower_32_bits(value)); + write_aux_reg(ARC_REG_PCT_COUNTH, upper_32_bits(value)); perf_event_update_userpage(event); @@ -277,7 +277,7 @@ static void arc_pmu_start(struct perf_event *event, int flags) /* Enable interrupt for this counter */ if (is_sampling_event(event)) write_aux_reg(ARC_REG_PCT_INT_CTRL, - read_aux_reg(ARC_REG_PCT_INT_CTRL) | (1 << idx)); + read_aux_reg(ARC_REG_PCT_INT_CTRL) | BIT(idx)); /* enable ARC pmu here */ write_aux_reg(ARC_REG_PCT_INDEX, idx); /* counter # */ @@ -295,9 +295,9 @@ static void arc_pmu_stop(struct perf_event *event, int flags) * Reset interrupt flag by writing of 1. This is required * to make sure pending interrupt was not left. */ - write_aux_reg(ARC_REG_PCT_INT_ACT, 1 << idx); + write_aux_reg(ARC_REG_PCT_INT_ACT, BIT(idx)); write_aux_reg(ARC_REG_PCT_INT_CTRL, - read_aux_reg(ARC_REG_PCT_INT_CTRL) & ~(1 << idx)); + read_aux_reg(ARC_REG_PCT_INT_CTRL) & ~BIT(idx)); } if (!(event->hw.state & PERF_HES_STOPPED)) { @@ -349,9 +349,10 @@ static int arc_pmu_add(struct perf_event *event, int flags) if (is_sampling_event(event)) { /* Mimic full counter overflow as other arches do */ - write_aux_reg(ARC_REG_PCT_INT_CNTL, (u32)arc_pmu->max_period); + write_aux_reg(ARC_REG_PCT_INT_CNTL, + lower_32_bits(arc_pmu->max_period)); write_aux_reg(ARC_REG_PCT_INT_CNTH, - (arc_pmu->max_period >> 32)); + upper_32_bits(arc_pmu->max_period)); } write_aux_reg(ARC_REG_PCT_CONFIG, 0); @@ -392,7 +393,7 @@ static irqreturn_t arc_pmu_intr(int irq, void *dev) idx = __ffs(active_ints); /* Reset interrupt flag by writing of 1 */ - write_aux_reg(ARC_REG_PCT_INT_ACT, 1 << idx); + write_aux_reg(ARC_REG_PCT_INT_ACT, BIT(idx)); /* * On reset of "interrupt active" bit corresponding @@ -400,7 +401,7 @@ static irqreturn_t arc_pmu_intr(int irq, void *dev) * Now we need to re-enable interrupt for the counter. */ write_aux_reg(ARC_REG_PCT_INT_CTRL, - read_aux_reg(ARC_REG_PCT_INT_CTRL) | (1 << idx)); + read_aux_reg(ARC_REG_PCT_INT_CTRL) | BIT(idx)); event = pmu_cpu->act_counter[idx]; hwc = &event->hw; @@ -414,7 +415,7 @@ static irqreturn_t arc_pmu_intr(int irq, void *dev) arc_pmu_stop(event, 0); } - active_ints &= ~(1U << idx); + active_ints &= ~BIT(idx); } while (active_ints); done: @@ -450,10 +451,10 @@ static int arc_pmu_device_probe(struct platform_device *pdev) union cc_name { struct { - uint32_t word0, word1; + u32 word0, word1; char sentinel; } indiv; - char str[9]; + char str[ARCPMU_EVENT_NAME_LEN]; } cc_name; @@ -481,9 +482,9 @@ static int arc_pmu_device_probe(struct platform_device *pdev) pr_info("ARC perf\t: %d counters (%d bits), %d conditions%s\n", arc_pmu->n_counters, counter_size, cc_bcr.c, - has_interrupts ? ", [overflow IRQ support]":""); + has_interrupts ? ", [overflow IRQ support]" : ""); - cc_name.str[8] = 0; + cc_name.str[ARCPMU_EVENT_NAME_LEN - 1] = 0; for (i = 0; i < PERF_COUNT_ARC_HW_MAX; i++) arc_pmu->ev_hw_idx[i] = -1; @@ -538,14 +539,12 @@ static int arc_pmu_device_probe(struct platform_device *pdev) return perf_pmu_register(&arc_pmu->pmu, pdev->name, PERF_TYPE_RAW); } -#ifdef CONFIG_OF static const struct of_device_id arc_pmu_match[] = { { .compatible = "snps,arc700-pct" }, { .compatible = "snps,archs-pct" }, {}, }; MODULE_DEVICE_TABLE(of, arc_pmu_match); -#endif static struct platform_driver arc_pmu_driver = { .driver = { -- cgit v1.2.3-58-ga151 From 0e956150fe09fa4430c42a9bbe48a72967fa0012 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 13 Dec 2018 19:56:19 +0300 Subject: ARC: perf: introduce Kernel PMU events support Export all available ARC architected hardware events as kernel PMU events to make non-generic events accessible. ARC PMU HW allow us to read the list of all available events names. So we generate kernel PMU event list dynamically in arc_pmu_device_probe() using human-readable events names we got from HW instead of using pre-defined events list. -------------------------->8-------------------------- $ perf list [snip] arc_pmu/bdata64/ [Kernel PMU event] arc_pmu/bdcstall/ [Kernel PMU event] arc_pmu/bdslot/ [Kernel PMU event] arc_pmu/bfbmp/ [Kernel PMU event] arc_pmu/bfirqex/ [Kernel PMU event] arc_pmu/bflgstal/ [Kernel PMU event] arc_pmu/bflush/ [Kernel PMU event] -------------------------->8-------------------------- Signed-off-by: Eugeniy Paltsev Signed-off-by: Vineet Gupta --- arch/arc/kernel/perf_event.c | 106 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c index 693f32d60c35..d60aaaead421 100644 --- a/arch/arc/kernel/perf_event.c +++ b/arch/arc/kernel/perf_event.c @@ -17,12 +17,28 @@ /* HW holds 8 symbols + one for null terminator */ #define ARCPMU_EVENT_NAME_LEN 9 +enum arc_pmu_attr_groups { + ARCPMU_ATTR_GR_EVENTS, + ARCPMU_ATTR_GR_FORMATS, + ARCPMU_NR_ATTR_GR +}; + +struct arc_pmu_raw_event_entry { + char name[ARCPMU_EVENT_NAME_LEN]; +}; + struct arc_pmu { struct pmu pmu; unsigned int irq; int n_counters; + int n_events; u64 max_period; int ev_hw_idx[PERF_COUNT_ARC_HW_MAX]; + + struct arc_pmu_raw_event_entry *raw_entry; + struct attribute **attrs; + struct perf_pmu_events_attr *attr; + const struct attribute_group *attr_groups[ARCPMU_NR_ATTR_GR + 1]; }; struct arc_pmu_cpu { @@ -192,6 +208,17 @@ static int arc_pmu_event_init(struct perf_event *event) (int)hwc->config, arc_pmu_ev_hw_map[ret]); return 0; + case PERF_TYPE_RAW: + if (event->attr.config >= arc_pmu->n_events) + return -ENOENT; + + hwc->config |= event->attr.config; + pr_debug("init raw event with idx %lld \'%s\'\n", + event->attr.config, + arc_pmu->raw_entry[event->attr.config].name); + + return 0; + default: return -ENOENT; } @@ -442,6 +469,67 @@ static void arc_cpu_pmu_irq_init(void *data) write_aux_reg(ARC_REG_PCT_INT_ACT, 0xffffffff); } +/* Event field occupies the bottom 15 bits of our config field */ +PMU_FORMAT_ATTR(event, "config:0-14"); +static struct attribute *arc_pmu_format_attrs[] = { + &format_attr_event.attr, + NULL, +}; + +static struct attribute_group arc_pmu_format_attr_gr = { + .name = "format", + .attrs = arc_pmu_format_attrs, +}; + +static ssize_t arc_pmu_events_sysfs_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + struct perf_pmu_events_attr *pmu_attr; + + pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); + return sprintf(page, "event=0x%04llx\n", pmu_attr->id); +} + +/* + * We don't add attrs here as we don't have pre-defined list of perf events. + * We will generate and add attrs dynamically in probe() after we read HW + * configuration. + */ +static struct attribute_group arc_pmu_events_attr_gr = { + .name = "events", +}; + +static void arc_pmu_add_raw_event_attr(int j, char *str) +{ + memmove(arc_pmu->raw_entry[j].name, str, ARCPMU_EVENT_NAME_LEN - 1); + arc_pmu->attr[j].attr.attr.name = arc_pmu->raw_entry[j].name; + arc_pmu->attr[j].attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444); + arc_pmu->attr[j].attr.show = arc_pmu_events_sysfs_show; + arc_pmu->attr[j].id = j; + arc_pmu->attrs[j] = &(arc_pmu->attr[j].attr.attr); +} + +static int arc_pmu_raw_alloc(struct device *dev) +{ + arc_pmu->attr = devm_kmalloc_array(dev, arc_pmu->n_events + 1, + sizeof(*arc_pmu->attr), GFP_KERNEL | __GFP_ZERO); + if (!arc_pmu->attr) + return -ENOMEM; + + arc_pmu->attrs = devm_kmalloc_array(dev, arc_pmu->n_events + 1, + sizeof(*arc_pmu->attrs), GFP_KERNEL | __GFP_ZERO); + if (!arc_pmu->attrs) + return -ENOMEM; + + arc_pmu->raw_entry = devm_kmalloc_array(dev, arc_pmu->n_events, + sizeof(*arc_pmu->raw_entry), GFP_KERNEL | __GFP_ZERO); + if (!arc_pmu->raw_entry) + return -ENOMEM; + + return 0; +} + static int arc_pmu_device_probe(struct platform_device *pdev) { struct arc_reg_pct_build pct_bcr; @@ -473,6 +561,11 @@ static int arc_pmu_device_probe(struct platform_device *pdev) if (!arc_pmu) return -ENOMEM; + arc_pmu->n_events = cc_bcr.c; + + if (arc_pmu_raw_alloc(&pdev->dev)) + return -ENOMEM; + has_interrupts = is_isa_arcv2() ? pct_bcr.i : 0; arc_pmu->n_counters = pct_bcr.c; @@ -504,8 +597,14 @@ static int arc_pmu_device_probe(struct platform_device *pdev) arc_pmu->ev_hw_idx[i] = j; } } + + arc_pmu_add_raw_event_attr(j, cc_name.str); } + arc_pmu_events_attr_gr.attrs = arc_pmu->attrs; + arc_pmu->attr_groups[ARCPMU_ATTR_GR_EVENTS] = &arc_pmu_events_attr_gr; + arc_pmu->attr_groups[ARCPMU_ATTR_GR_FORMATS] = &arc_pmu_format_attr_gr; + arc_pmu->pmu = (struct pmu) { .pmu_enable = arc_pmu_enable, .pmu_disable = arc_pmu_disable, @@ -515,6 +614,7 @@ static int arc_pmu_device_probe(struct platform_device *pdev) .start = arc_pmu_start, .stop = arc_pmu_stop, .read = arc_pmu_read, + .attr_groups = arc_pmu->attr_groups, }; if (has_interrupts) { @@ -536,7 +636,11 @@ static int arc_pmu_device_probe(struct platform_device *pdev) } else arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; - return perf_pmu_register(&arc_pmu->pmu, pdev->name, PERF_TYPE_RAW); + /* + * perf parser doesn't really like '-' symbol in events name, so let's + * use '_' in arc pct name as it goes to kernel PMU event prefix. + */ + return perf_pmu_register(&arc_pmu->pmu, "arc_pct", PERF_TYPE_RAW); } static const struct of_device_id arc_pmu_match[] = { -- cgit v1.2.3-58-ga151 From baf9cc85ba01f32cf2ee79042a64b874a58cfb92 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 13 Dec 2018 19:56:20 +0300 Subject: ARC: perf: move HW events mapping to separate function Move HW events mapping to separate function to make code more readable. Signed-off-by: Eugeniy Paltsev Signed-off-by: Vineet Gupta --- arch/arc/kernel/perf_event.c | 48 ++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c index d60aaaead421..248c7b61690a 100644 --- a/arch/arc/kernel/perf_event.c +++ b/arch/arc/kernel/perf_event.c @@ -530,11 +530,39 @@ static int arc_pmu_raw_alloc(struct device *dev) return 0; } +static inline bool event_in_hw_event_map(int i, char *name) +{ + if (!arc_pmu_ev_hw_map[i]) + return false; + + if (!strlen(arc_pmu_ev_hw_map[i])) + return false; + + if (strcmp(arc_pmu_ev_hw_map[i], name)) + return false; + + return true; +} + +static void arc_pmu_map_hw_event(int j, char *str) +{ + int i; + + /* See if HW condition has been mapped to a perf event_id */ + for (i = 0; i < ARRAY_SIZE(arc_pmu_ev_hw_map); i++) { + if (event_in_hw_event_map(i, str)) { + pr_debug("mapping perf event %2d to h/w event \'%8s\' (idx %d)\n", + i, str, j); + arc_pmu->ev_hw_idx[i] = j; + } + } +} + static int arc_pmu_device_probe(struct platform_device *pdev) { struct arc_reg_pct_build pct_bcr; struct arc_reg_cc_build cc_bcr; - int i, j, has_interrupts; + int i, has_interrupts; int counter_size; /* in bits */ union cc_name { @@ -582,23 +610,13 @@ static int arc_pmu_device_probe(struct platform_device *pdev) arc_pmu->ev_hw_idx[i] = -1; /* loop thru all available h/w condition indexes */ - for (j = 0; j < cc_bcr.c; j++) { - write_aux_reg(ARC_REG_CC_INDEX, j); + for (i = 0; i < cc_bcr.c; i++) { + write_aux_reg(ARC_REG_CC_INDEX, i); cc_name.indiv.word0 = read_aux_reg(ARC_REG_CC_NAME0); cc_name.indiv.word1 = read_aux_reg(ARC_REG_CC_NAME1); - /* See if it has been mapped to a perf event_id */ - for (i = 0; i < ARRAY_SIZE(arc_pmu_ev_hw_map); i++) { - if (arc_pmu_ev_hw_map[i] && - !strcmp(arc_pmu_ev_hw_map[i], cc_name.str) && - strlen(arc_pmu_ev_hw_map[i])) { - pr_debug("mapping perf event %2d to h/w event \'%8s\' (idx %d)\n", - i, cc_name.str, j); - arc_pmu->ev_hw_idx[i] = j; - } - } - - arc_pmu_add_raw_event_attr(j, cc_name.str); + arc_pmu_map_hw_event(i, cc_name.str); + arc_pmu_add_raw_event_attr(i, cc_name.str); } arc_pmu_events_attr_gr.attrs = arc_pmu->attrs; -- cgit v1.2.3-58-ga151 From 29133260f7c2e4ce50b4da6bf0674331bc0a4da5 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Thu, 13 Dec 2018 19:56:21 +0300 Subject: ARC: perf: avoid kernel killing where it is possible No, not gonna die tonight. Signed-off-by: Eugeniy Paltsev Signed-off-by: Vineet Gupta --- arch/arc/kernel/perf_event.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c index 248c7b61690a..861a8aea51f9 100644 --- a/arch/arc/kernel/perf_event.c +++ b/arch/arc/kernel/perf_event.c @@ -580,10 +580,12 @@ static int arc_pmu_device_probe(struct platform_device *pdev) return -ENODEV; } BUILD_BUG_ON(ARC_PERF_MAX_COUNTERS > 32); - BUG_ON(pct_bcr.c > ARC_PERF_MAX_COUNTERS); + if (WARN_ON(pct_bcr.c > ARC_PERF_MAX_COUNTERS)) + return -EINVAL; READ_BCR(ARC_REG_CC_BUILD, cc_bcr); - BUG_ON(!cc_bcr.v); /* Counters exist but No countable conditions ? */ + if (WARN(!cc_bcr.v, "Counters exist but No countable conditions?")) + return -EINVAL; arc_pmu = devm_kzalloc(&pdev->dev, sizeof(struct arc_pmu), GFP_KERNEL); if (!arc_pmu) -- cgit v1.2.3-58-ga151 From ab6c03676cb190156603cf4c5ecf97aa406c9c53 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 17 Dec 2018 14:11:19 -0800 Subject: ARC: show_regs: lockdep: avoid page allocator... and use smaller/on-stack buffer instead The motivation for this change was lockdep splat like below. | potentially unexpected fatal signal 11. | BUG: sleeping function called from invalid context at ../mm/page_alloc.c:4317 | in_atomic(): 1, irqs_disabled(): 0, pid: 57, name: segv | no locks held by segv/57. | Preemption disabled at: | [<8182f17e>] get_signal+0x4a6/0x7c4 | CPU: 0 PID: 57 Comm: segv Not tainted 4.17.0+ #23 | | Stack Trace: | arc_unwind_core.constprop.1+0xd0/0xf4 | __might_sleep+0x1f6/0x234 | __get_free_pages+0x174/0xca0 | show_regs+0x22/0x330 | get_signal+0x4ac/0x7c4 # print_fatal_signals() -> preempt_disable() | do_signal+0x30/0x224 | resume_user_mode_begin+0x90/0xd8 So signal handling core calls show_regs() with preemption disabled but an ensuing GFP_KERNEL page allocator call is flagged by lockdep. We could have switched to GFP_NOWAIT, but turns out that is not enough anways and eliding page allocator call leads to less code and instruction traces to sift thru when debugging pesky crashes. FWIW, this patch doesn't cure the lockdep splat (which next patch does). Reviewed-by: William Kucharski Signed-off-by: Vineet Gupta --- arch/arc/kernel/troubleshoot.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c index e8d9fb452346..5c6663321e87 100644 --- a/arch/arc/kernel/troubleshoot.c +++ b/arch/arc/kernel/troubleshoot.c @@ -18,6 +18,8 @@ #include #include +#define ARC_PATH_MAX 256 + /* * Common routine to print scratch regs (r0-r12) or callee regs (r13-r25) * -Prints 3 regs per line and a CR. @@ -58,11 +60,12 @@ static void show_callee_regs(struct callee_regs *cregs) print_reg_file(&(cregs->r13), 13); } -static void print_task_path_n_nm(struct task_struct *tsk, char *buf) +static void print_task_path_n_nm(struct task_struct *tsk) { char *path_nm = NULL; struct mm_struct *mm; struct file *exe_file; + char buf[ARC_PATH_MAX]; mm = get_task_mm(tsk); if (!mm) @@ -72,7 +75,7 @@ static void print_task_path_n_nm(struct task_struct *tsk, char *buf) mmput(mm); if (exe_file) { - path_nm = file_path(exe_file, buf, 255); + path_nm = file_path(exe_file, buf, ARC_PATH_MAX-1); fput(exe_file); } @@ -80,10 +83,9 @@ done: pr_info("Path: %s\n", !IS_ERR(path_nm) ? path_nm : "?"); } -static void show_faulting_vma(unsigned long address, char *buf) +static void show_faulting_vma(unsigned long address) { struct vm_area_struct *vma; - char *nm = buf; struct mm_struct *active_mm = current->active_mm; /* can't use print_vma_addr() yet as it doesn't check for @@ -96,8 +98,11 @@ static void show_faulting_vma(unsigned long address, char *buf) * if the container VMA is not found */ if (vma && (vma->vm_start <= address)) { + char buf[ARC_PATH_MAX]; + char *nm = "?"; + if (vma->vm_file) { - nm = file_path(vma->vm_file, buf, PAGE_SIZE - 1); + nm = file_path(vma->vm_file, buf, ARC_PATH_MAX-1); if (IS_ERR(nm)) nm = "?"; } @@ -173,13 +178,8 @@ void show_regs(struct pt_regs *regs) { struct task_struct *tsk = current; struct callee_regs *cregs; - char *buf; - buf = (char *)__get_free_page(GFP_KERNEL); - if (!buf) - return; - - print_task_path_n_nm(tsk, buf); + print_task_path_n_nm(tsk); show_regs_print_info(KERN_INFO); show_ecr_verbose(regs); @@ -189,7 +189,7 @@ void show_regs(struct pt_regs *regs) (void *)regs->blink, (void *)regs->ret); if (user_mode(regs)) - show_faulting_vma(regs->ret, buf); /* faulting code, not data */ + show_faulting_vma(regs->ret); /* faulting code, not data */ pr_info("[STAT32]: 0x%08lx", regs->status32); @@ -221,8 +221,6 @@ void show_regs(struct pt_regs *regs) cregs = (struct callee_regs *)current->thread.callee_reg; if (cregs) show_callee_regs(cregs); - - free_page((unsigned long)buf); } void show_kernel_fault_diag(const char *str, struct pt_regs *regs, -- cgit v1.2.3-58-ga151 From f731a8e89f8c78985707c626680f3e24c7a60772 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 18 Dec 2018 10:39:58 -0800 Subject: ARC: show_regs: lockdep: re-enable preemption signal handling core calls show_regs() with preemption disabled which on ARC takes mmap_sem for mm/vma access, causing lockdep splat. | [ARCLinux]# ./segv-null-ptr | potentially unexpected fatal signal 11. | BUG: sleeping function called from invalid context at kernel/fork.c:1011 | in_atomic(): 1, irqs_disabled(): 0, pid: 70, name: segv-null-ptr | no locks held by segv-null-ptr/70. | CPU: 0 PID: 70 Comm: segv-null-ptr Not tainted 4.18.0+ #69 | | Stack Trace: | arc_unwind_core+0xcc/0x100 | ___might_sleep+0x17a/0x190 | mmput+0x16/0xb8 | show_regs+0x52/0x310 | get_signal+0x5ee/0x610 | do_signal+0x2c/0x218 | resume_user_mode_begin+0x90/0xd8 Workaround by re-enabling preemption temporarily. Note that the preemption disabling in core code around show_regs() was introduced by commit 3a9f84d354ce ("signals, debug: fix BUG: using smp_processor_id() in preemptible code in print_fatal_signal()") to silence a differnt lockdep seen on x86 bakc in 2009. Cc: Signed-off-by: Vineet Gupta --- arch/arc/kernel/troubleshoot.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c index 5c6663321e87..215f515442e0 100644 --- a/arch/arc/kernel/troubleshoot.c +++ b/arch/arc/kernel/troubleshoot.c @@ -179,6 +179,12 @@ void show_regs(struct pt_regs *regs) struct task_struct *tsk = current; struct callee_regs *cregs; + /* + * generic code calls us with preemption disabled, but some calls + * here could sleep, so re-enable to avoid lockdep splat + */ + preempt_enable(); + print_task_path_n_nm(tsk); show_regs_print_info(KERN_INFO); @@ -221,6 +227,8 @@ void show_regs(struct pt_regs *regs) cregs = (struct callee_regs *)current->thread.callee_reg; if (cregs) show_callee_regs(cregs); + + preempt_disable(); } void show_kernel_fault_diag(const char *str, struct pt_regs *regs, -- cgit v1.2.3-58-ga151 From 2cddd20147826aef283115abb00012d4dafe3cdb Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Wed, 16 Jan 2019 16:53:52 +0100 Subject: net/sched: cls_flower: allocate mask dynamically in fl_change() Recent changes (especially 05cd271fd61a ("cls_flower: Support multiple masks per priority")) in the fl_flow_mask structure grow it and its current size e.g. on x86_64 with defconfig is 760 bytes and more than 1024 bytes with some debug options enabled. Prior the mentioned commit its size was 176 bytes (using defconfig on x86_64). With regard to this fact it's reasonable to allocate this structure dynamically in fl_change() to reduce its stack size. v2: - use kzalloc() instead of kcalloc() Fixes: 05cd271fd61a ("cls_flower: Support multiple masks per priority") Cc: Jiri Pirko Cc: Paul Blakey Acked-by: Jiri Pirko Signed-off-by: Ivan Vecera Signed-off-by: David S. Miller --- net/sched/cls_flower.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index dad04e710493..f6aa57fbbbaf 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -1290,17 +1290,23 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, struct cls_fl_head *head = rtnl_dereference(tp->root); struct cls_fl_filter *fold = *arg; struct cls_fl_filter *fnew; + struct fl_flow_mask *mask; struct nlattr **tb; - struct fl_flow_mask mask = {}; int err; if (!tca[TCA_OPTIONS]) return -EINVAL; - tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); - if (!tb) + mask = kzalloc(sizeof(struct fl_flow_mask), GFP_KERNEL); + if (!mask) return -ENOBUFS; + tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL); + if (!tb) { + err = -ENOBUFS; + goto errout_mask_alloc; + } + err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy, NULL); if (err < 0) @@ -1343,12 +1349,12 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, } } - err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr, + err = fl_set_parms(net, tp, fnew, mask, base, tb, tca[TCA_RATE], ovr, tp->chain->tmplt_priv, extack); if (err) goto errout_idr; - err = fl_check_assign_mask(head, fnew, fold, &mask); + err = fl_check_assign_mask(head, fnew, fold, mask); if (err) goto errout_idr; @@ -1392,6 +1398,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, } kfree(tb); + kfree(mask); return 0; errout_mask: @@ -1405,6 +1412,8 @@ errout: kfree(fnew); errout_tb: kfree(tb); +errout_mask_alloc: + kfree(mask); return err; } -- cgit v1.2.3-58-ga151 From 8f6b5392856a4b74224e257f3e0874a163b04603 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Wed, 16 Jan 2019 19:17:44 +0300 Subject: udp: add missing rehash callback to udplite After commit 4cdeeee9252a ("net: udp: prefer listeners bound to an address"), UDP-Lite only works when specifying a local address for the sockets. This is related to the problem addressed in the commit 719f835853a9 ("udp: add rehash on connect()"). Moreover, __udp4_lib_lookup() now looks for a socket immediately in the secondary hash table. The issue was found with LTP/network tests (UDP-Lite test-cases). Fixes: 4cdeeee9252a ("net: udp: prefer listeners bound to an address") Signed-off-by: Alexey Kodanev Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/udp.c | 2 +- net/ipv4/udp_impl.h | 1 + net/ipv4/udplite.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 3d2a81bdc2ab..5c3cd5d84a6f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1926,7 +1926,7 @@ void udp_lib_rehash(struct sock *sk, u16 newhash) } EXPORT_SYMBOL(udp_lib_rehash); -static void udp_v4_rehash(struct sock *sk) +void udp_v4_rehash(struct sock *sk) { u16 new_hash = ipv4_portaddr_hash(sock_net(sk), inet_sk(sk)->inet_rcv_saddr, diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 322672655419..6b2fa77eeb1c 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h @@ -10,6 +10,7 @@ int __udp4_lib_rcv(struct sk_buff *, struct udp_table *, int); int __udp4_lib_err(struct sk_buff *, u32, struct udp_table *); int udp_v4_get_port(struct sock *sk, unsigned short snum); +void udp_v4_rehash(struct sock *sk); int udp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, unsigned int optlen); diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 39c7f17d916f..3c94b8f0ff27 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -53,6 +53,7 @@ struct proto udplite_prot = { .sendpage = udp_sendpage, .hash = udp_lib_hash, .unhash = udp_lib_unhash, + .rehash = udp_v4_rehash, .get_port = udp_v4_get_port, .memory_allocated = &udp_memory_allocated, .sysctl_mem = sysctl_udp_mem, -- cgit v1.2.3-58-ga151 From f7c46156f4a9d6ba5c6bcc5c48945e87b0f08c65 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Wed, 16 Jan 2019 19:17:45 +0300 Subject: udp6: add missing rehash callback to udplite After commit 23b0269e58ae ("net: udp6: prefer listeners bound to an address"), UDP-Lite only works when specifying a local address for the sockets. This is related to the problem addressed in the commit 719f835853a9 ("udp: add rehash on connect()"). Moreover, __udp6_lib_lookup() now looks for a socket immediately in the secondary hash table. And this issue was found with LTP/network tests as well. Fixes: 23b0269e58ae ("net: udp6: prefer listeners bound to an address") Signed-off-by: Alexey Kodanev Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/udp.c | 2 +- net/ipv6/udp_impl.h | 1 + net/ipv6/udplite.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index e1f2b9660666..2596ffdeebea 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -102,7 +102,7 @@ int udp_v6_get_port(struct sock *sk, unsigned short snum) return udp_lib_get_port(sk, snum, hash2_nulladdr); } -static void udp_v6_rehash(struct sock *sk) +void udp_v6_rehash(struct sock *sk) { u16 new_hash = ipv6_portaddr_hash(sock_net(sk), &sk->sk_v6_rcv_saddr, diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 5730e6503cb4..20e324b6f358 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h @@ -13,6 +13,7 @@ int __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, __be32, struct udp_table *); int udp_v6_get_port(struct sock *sk, unsigned short snum); +void udp_v6_rehash(struct sock *sk); int udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index a125aebc29e5..f35907836444 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -49,6 +49,7 @@ struct proto udplitev6_prot = { .recvmsg = udpv6_recvmsg, .hash = udp_lib_hash, .unhash = udp_lib_unhash, + .rehash = udp_v6_rehash, .get_port = udp_v6_get_port, .memory_allocated = &udp_memory_allocated, .sysctl_mem = sysctl_udp_mem, -- cgit v1.2.3-58-ga151 From 70921ae25f944423f0abf096f73455c586da0652 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 8 Jan 2019 17:04:32 -0700 Subject: genirq: Fix the kerneldoc comment for struct irq_affinity_desc A recent commit added a new field but did not update the kerneldoc comment, leading to this build warning: ./include/linux/interrupt.h:268: warning: Function parameter or member 'is_managed' not described in 'irq_affinity_desc' Add the missing information, making the docs build 0.001% quieter. Fixes: c410abbbacb9 ("genirq/affinity: Add is_managed to struct irq_affinity_desc") Signed-off-by: Jonathan Corbet Signed-off-by: Thomas Gleixner Cc: Dou Liyang Link: https://lkml.kernel.org/r/20190108170432.59bae8a6@lwn.net --- include/linux/interrupt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index c672f34235e7..4a728dba02e2 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -260,6 +260,7 @@ struct irq_affinity { /** * struct irq_affinity_desc - Interrupt affinity descriptor * @mask: cpumask to hold the affinity assignment + * @is_managed: 1 if the interrupt is managed internally */ struct irq_affinity_desc { struct cpumask mask; -- cgit v1.2.3-58-ga151 From f4924f24da8c7ef64195096817f3cde324091d97 Mon Sep 17 00:00:00 2001 From: Peter Oskolkov Date: Wed, 16 Jan 2019 08:47:54 -0800 Subject: bpf: bpf_setsockopt: reset sock dst on SO_MARK changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In sock_setsockopt() (net/core/sock.h), when SO_MARK option is used to change sk_mark, sk_dst_reset(sk) is called. The same should be done in bpf_setsockopt(). Fixes: 8c4b4c7e9ff0 ("bpf: Add setsockopt helper function to bpf") Reported-by: Maciej Żenczykowski Signed-off-by: Peter Oskolkov Acked-by: Martin KaFai Lau Reviewed-by: Maciej Żenczykowski Signed-off-by: Daniel Borkmann --- net/core/filter.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/core/filter.c b/net/core/filter.c index d9076e609fca..d9ea51b47f35 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4132,7 +4132,10 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, sk->sk_rcvlowat = val ? : 1; break; case SO_MARK: - sk->sk_mark = val; + if (sk->sk_mark != val) { + sk->sk_mark = val; + sk_dst_reset(sk); + } break; default: ret = -EINVAL; -- cgit v1.2.3-58-ga151 From e224c390a6259c529f7b2a6bd215a087b3344f5c Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 17 Jan 2019 08:51:01 -0800 Subject: bpf: fix SO_MAX_PACING_RATE to support TCP internal pacing If sch_fq packet scheduler is not used, TCP can fallback to internal pacing, but this requires sk_pacing_status to be properly set. Fixes: 8c4b4c7e9ff0 ("bpf: Add setsockopt helper function to bpf") Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Cc: Lawrence Brakmo Acked-by: Martin KaFai Lau Signed-off-by: Daniel Borkmann --- net/core/filter.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/core/filter.c b/net/core/filter.c index d9ea51b47f35..dab10d21cae8 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -4119,6 +4119,10 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock, sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF); break; case SO_MAX_PACING_RATE: /* 32bit version */ + if (val != ~0U) + cmpxchg(&sk->sk_pacing_status, + SK_PACING_NONE, + SK_PACING_NEEDED); sk->sk_max_pacing_rate = (val == ~0U) ? ~0UL : val; sk->sk_pacing_rate = min(sk->sk_pacing_rate, sk->sk_max_pacing_rate); -- cgit v1.2.3-58-ga151 From fc24d75a7f91837d7918e40719575951820b2b8f Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 15 Jan 2019 09:58:16 -0700 Subject: x86/entry/64/compat: Fix stack switching for XEN PV While in the native case entry into the kernel happens on the trampoline stack, PV Xen kernels get entered with the current thread stack right away. Hence source and destination stacks are identical in that case, and special care is needed. Other than in sync_regs() the copying done on the INT80 path isn't NMI / #MC safe, as either of these events occurring in the middle of the stack copying would clobber data on the (source) stack. There is similar code in interrupt_entry() and nmi(), but there is no fixup required because those code paths are unreachable in XEN PV guests. [ tglx: Sanitized subject, changelog, Fixes tag and stable mail address. Sigh ] Fixes: 7f2590a110b8 ("x86/entry/64: Use a per-CPU trampoline stack for IDT entries") Signed-off-by: Jan Beulich Signed-off-by: Thomas Gleixner Reviewed-by: Juergen Gross Acked-by: Andy Lutomirski Cc: Peter Anvin Cc: xen-devel@lists.xenproject.org> Cc: Boris Ostrovsky Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/5C3E1128020000780020DFAD@prv1-mh.provo.novell.com --- arch/x86/entry/entry_64_compat.S | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index 8eaf8952c408..39913770a44d 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S @@ -361,7 +361,8 @@ ENTRY(entry_INT80_compat) /* Need to switch before accessing the thread stack. */ SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi - movq %rsp, %rdi + /* In the Xen PV case we already run on the thread stack. */ + ALTERNATIVE "movq %rsp, %rdi", "jmp .Lint80_keep_stack", X86_FEATURE_XENPV movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp pushq 6*8(%rdi) /* regs->ss */ @@ -370,8 +371,9 @@ ENTRY(entry_INT80_compat) pushq 3*8(%rdi) /* regs->cs */ pushq 2*8(%rdi) /* regs->ip */ pushq 1*8(%rdi) /* regs->orig_ax */ - pushq (%rdi) /* pt_regs->di */ +.Lint80_keep_stack: + pushq %rsi /* pt_regs->si */ xorl %esi, %esi /* nospec si */ pushq %rdx /* pt_regs->dx */ -- cgit v1.2.3-58-ga151 From 12fee4cd5be2c4a73cc13d7ad76eb2d2feda8a71 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 17 Jan 2019 11:00:09 +0800 Subject: genirq/irqdesc: Fix double increment in alloc_descs() The recent rework of alloc_descs() introduced a double increment of the loop counter. As a consequence only every second affinity mask is validated. Remove it. [ tglx: Massaged changelog ] Fixes: c410abbbacb9 ("genirq/affinity: Add is_managed to struct irq_affinity_desc") Signed-off-by: Huacai Chen Signed-off-by: Thomas Gleixner Cc: Fuxin Zhang Cc: Zhangjin Wu Cc: Huacai Chen Cc: Dou Liyang Link: https://lkml.kernel.org/r/1547694009-16261-1-git-send-email-chenhc@lemote.com --- kernel/irq/irqdesc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index ee062b7939d3..ef8ad36cadcf 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -457,7 +457,7 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node, /* Validate affinity mask(s) */ if (affinity) { - for (i = 0; i < cnt; i++, i++) { + for (i = 0; i < cnt; i++) { if (cpumask_empty(&affinity[i].mask)) return -EINVAL; } -- cgit v1.2.3-58-ga151 From 88a8121dc1d3d0dbddd411b79ed236b6b6ea415c Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 17 Jan 2019 11:27:22 +0100 Subject: af_packet: fix raw sockets over 6in4 tunnel Since commit cb9f1b783850, scapy (which uses an AF_PACKET socket in SOCK_RAW mode) is unable to send a basic icmp packet over a sit tunnel: Here is a example of the setup: $ ip link set ntfp2 up $ ip addr add 10.125.0.1/24 dev ntfp2 $ ip tunnel add tun1 mode sit ttl 64 local 10.125.0.1 remote 10.125.0.2 dev ntfp2 $ ip addr add fd00:cafe:cafe::1/128 dev tun1 $ ip link set dev tun1 up $ ip route add fd00:200::/64 dev tun1 $ scapy >>> p = [] >>> p += IPv6(src='fd00:100::1', dst='fd00:200::1')/ICMPv6EchoRequest() >>> send(p, count=1, inter=0.1) >>> quit() $ ip -s link ls dev tun1 | grep -A1 "TX.*errors" TX: bytes packets errors dropped carrier collsns 0 0 1 0 0 0 The problem is that the network offset is set to the hard_header_len of the output device (tun1, ie 14 + 20) and in our case, because the packet is small (48 bytes) the pskb_inet_may_pull() fails (it tries to pull 40 bytes (ipv6 header) starting from the network offset). This problem is more generally related to device with variable hard header length. To avoid a too intrusive patch in the current release, a (ugly) workaround is proposed in this patch. It has to be cleaned up in net-next. Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=993675a3100b1 Link: http://patchwork.ozlabs.org/patch/1024489/ Fixes: cb9f1b783850 ("ip: validate header length on virtual device xmit") CC: Willem de Bruijn CC: Maxim Mikityanskiy Signed-off-by: Nicolas Dichtel Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- net/packet/af_packet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d0945253f43b..3b1a78906bc0 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2887,7 +2887,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) goto out_free; } else if (reserve) { skb_reserve(skb, -reserve); - if (len < reserve) + if (len < reserve + sizeof(struct ipv6hdr) && + dev->min_header_len != dev->hard_header_len) skb_reset_network_header(skb); } -- cgit v1.2.3-58-ga151 From 4d447455e73b47c43dd35fcc38ed823d3182a474 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 10 Dec 2018 16:56:45 -0800 Subject: ARC: mm: do_page_fault fixes #1: relinquish mmap_sem if signal arrives while handle_mm_fault do_page_fault() forgot to relinquish mmap_sem if a signal came while handling handle_mm_fault() - due to say a ctl+c or oom etc. This would later cause a deadlock by acquiring it twice. This came to light when running libc testsuite tst-tls3-malloc test but is likely also the cause for prior seen LTP failures. Using lockdep clearly showed what the issue was. | # while true; do ./tst-tls3-malloc ; done | Didn't expect signal from child: got `Segmentation fault' | ^C | ============================================ | WARNING: possible recursive locking detected | 4.17.0+ #25 Not tainted | -------------------------------------------- | tst-tls3-malloc/510 is trying to acquire lock: | 606c7728 (&mm->mmap_sem){++++}, at: __might_fault+0x28/0x5c | |but task is already holding lock: |606c7728 (&mm->mmap_sem){++++}, at: do_page_fault+0x9c/0x2a0 | | other info that might help us debug this: | Possible unsafe locking scenario: | | CPU0 | ---- | lock(&mm->mmap_sem); | lock(&mm->mmap_sem); | | *** DEADLOCK *** | ------------------------------------------------------------ What the change does is not obvious (note to myself) prior code was | do_page_fault | | down_read() <-- lock taken | handle_mm_fault <-- signal pending as this runs | if fatal_signal_pending | if VM_FAULT_ERROR | up_read | if user_mode | return <-- lock still held, this was the BUG New code | do_page_fault | | down_read() <-- lock taken | handle_mm_fault <-- signal pending as this runs | if fatal_signal_pending | if VM_FAULT_RETRY | return <-- not same case as above, but still OK since | core mm already relinq lock for FAULT_RETRY | ... | | < Now falls through for bug case above > | | up_read() <-- lock relinquished Cc: stable@vger.kernel.org Signed-off-by: Vineet Gupta --- arch/arc/mm/fault.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c index a1d723197084..8df1638259f3 100644 --- a/arch/arc/mm/fault.c +++ b/arch/arc/mm/fault.c @@ -141,12 +141,17 @@ good_area: */ fault = handle_mm_fault(vma, address, flags); - /* If Pagefault was interrupted by SIGKILL, exit page fault "early" */ if (fatal_signal_pending(current)) { - if ((fault & VM_FAULT_ERROR) && !(fault & VM_FAULT_RETRY)) - up_read(&mm->mmap_sem); - if (user_mode(regs)) + + /* + * if fault retry, mmap_sem already relinquished by core mm + * so OK to return to user mode (with signal handled first) + */ + if (fault & VM_FAULT_RETRY) { + if (!user_mode(regs)) + goto no_context; return; + } } perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); -- cgit v1.2.3-58-ga151 From e6a72b7daeeb521753803550f0ed711152bb2555 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Mon, 14 Jan 2019 18:16:48 +0300 Subject: ARCv2: lib: memeset: fix doing prefetchw outside of buffer ARCv2 optimized memset uses PREFETCHW instruction for prefetching the next cache line but doesn't ensure that the line is not past the end of the buffer. PRETECHW changes the line ownership and marks it dirty, which can cause issues in SMP config when next line was already owned by other core. Fix the issue by avoiding the PREFETCHW Some more details: The current code has 3 logical loops (ignroing the unaligned part) (a) Big loop for doing aligned 64 bytes per iteration with PREALLOC (b) Loop for 32 x 2 bytes with PREFETCHW (c) any left over bytes loop (a) was already eliding the last 64 bytes, so PREALLOC was safe. The fix was removing PREFETCW from (b). Another potential issue (applicable to configs with 32 or 128 byte L1 cache line) is that PREALLOC assumes 64 byte cache line and may not do the right thing specially for 32b. While it would be easy to adapt, there are no known configs with those lie sizes, so for now, just compile out PREALLOC in such cases. Signed-off-by: Eugeniy Paltsev Cc: stable@vger.kernel.org #4.4+ Signed-off-by: Vineet Gupta [vgupta: rewrote changelog, used asm .macro vs. "C" macro] --- arch/arc/lib/memset-archs.S | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/arch/arc/lib/memset-archs.S b/arch/arc/lib/memset-archs.S index 62ad4bcb841a..f230bb7092fd 100644 --- a/arch/arc/lib/memset-archs.S +++ b/arch/arc/lib/memset-archs.S @@ -7,11 +7,39 @@ */ #include +#include -#undef PREALLOC_NOT_AVAIL +/* + * The memset implementation below is optimized to use prefetchw and prealloc + * instruction in case of CPU with 64B L1 data cache line (L1_CACHE_SHIFT == 6) + * If you want to implement optimized memset for other possible L1 data cache + * line lengths (32B and 128B) you should rewrite code carefully checking + * we don't call any prefetchw/prealloc instruction for L1 cache lines which + * don't belongs to memset area. + */ + +#if L1_CACHE_SHIFT == 6 + +.macro PREALLOC_INSTR reg, off + prealloc [\reg, \off] +.endm + +.macro PREFETCHW_INSTR reg, off + prefetchw [\reg, \off] +.endm + +#else + +.macro PREALLOC_INSTR +.endm + +.macro PREFETCHW_INSTR +.endm + +#endif ENTRY_CFI(memset) - prefetchw [r0] ; Prefetch the write location + PREFETCHW_INSTR r0, 0 ; Prefetch the first write location mov.f 0, r2 ;;; if size is zero jz.d [blink] @@ -48,11 +76,8 @@ ENTRY_CFI(memset) lpnz @.Lset64bytes ;; LOOP START -#ifdef PREALLOC_NOT_AVAIL - prefetchw [r3, 64] ;Prefetch the next write location -#else - prealloc [r3, 64] -#endif + PREALLOC_INSTR r3, 64 ; alloc next line w/o fetching + #ifdef CONFIG_ARC_HAS_LL64 std.ab r4, [r3, 8] std.ab r4, [r3, 8] @@ -85,7 +110,6 @@ ENTRY_CFI(memset) lsr.f lp_count, r2, 5 ;Last remaining max 124 bytes lpnz .Lset32bytes ;; LOOP START - prefetchw [r3, 32] ;Prefetch the next write location #ifdef CONFIG_ARC_HAS_LL64 std.ab r4, [r3, 8] std.ab r4, [r3, 8] -- cgit v1.2.3-58-ga151 From 7ebec5f43134bbf3dd5f20228ac4c1b55ee73284 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 17 Jan 2019 11:39:55 +1000 Subject: drm/nouveau/core: recognise TU102 Would usually do this split-out, verifying each component indivitually, but this has been squashed together to be more palatable for merging in 5.0-rc. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index bfbc9341e0c2..d9edb5785813 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2434,6 +2434,38 @@ nv140_chipset = { .sec2 = gp102_sec2_new, }; +static const struct nvkm_device_chip +nv162_chipset = { + .name = "TU102", + .bar = tu104_bar_new, + .bios = nvkm_bios_new, + .bus = gf100_bus_new, + .devinit = tu104_devinit_new, + .fault = tu104_fault_new, + .fb = gv100_fb_new, + .fuse = gm107_fuse_new, + .gpio = gk104_gpio_new, + .i2c = gm200_i2c_new, + .ibus = gm200_ibus_new, + .imem = nv50_instmem_new, + .ltc = gp102_ltc_new, + .mc = tu104_mc_new, + .mmu = tu104_mmu_new, + .pci = gp100_pci_new, + .pmu = gp102_pmu_new, + .therm = gp100_therm_new, + .timer = gk20a_timer_new, + .top = gk104_top_new, + .ce[0] = tu104_ce_new, + .ce[1] = tu104_ce_new, + .ce[2] = tu104_ce_new, + .ce[3] = tu104_ce_new, + .ce[4] = tu104_ce_new, + .disp = tu104_disp_new, + .dma = gv100_dma_new, + .fifo = tu104_fifo_new, +}; + static const struct nvkm_device_chip nv164_chipset = { .name = "TU104", @@ -2950,6 +2982,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, case 0x138: device->chip = &nv138_chipset; break; case 0x13b: device->chip = &nv13b_chipset; break; case 0x140: device->chip = &nv140_chipset; break; + case 0x162: device->chip = &nv162_chipset; break; case 0x164: device->chip = &nv164_chipset; break; case 0x166: device->chip = &nv166_chipset; break; default: -- cgit v1.2.3-58-ga151 From 38197ca176fc259fa4c871d07bcf8389d044a895 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 18 Jan 2019 00:14:17 +0100 Subject: block: Cleanup license notice Remove the imprecise and sloppy: "This files is licensed under the GPL." license notice in the top level comment. 1) The file already contains a SPDX license identifier which clearly states that the license of the file is GPL V2 only 2) The notice resolves to GPL v1 or later for scanners which is just contrary to the intent of SPDX identifiers to provide clear and non ambiguous license information. Aside of that the value add of this notice is below zero, Cc: Damien Le Moal Cc: Matias Bjorling Cc: Christoph Hellwig Cc: Jens Axboe Cc: linux-block@vger.kernel.org Fixes: 6a5ac9846508 ("block: Make struct request_queue smaller for CONFIG_BLK_DEV_ZONED=n") Reviewed-by: Bart Van Assche Signed-off-by: Thomas Gleixner Signed-off-by: Jens Axboe --- block/blk-mq-debugfs-zoned.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/block/blk-mq-debugfs-zoned.c b/block/blk-mq-debugfs-zoned.c index fb2c82c351e4..038cb627c868 100644 --- a/block/blk-mq-debugfs-zoned.c +++ b/block/blk-mq-debugfs-zoned.c @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017 Western Digital Corporation or its affiliates. - * - * This file is released under the GPL. */ #include -- cgit v1.2.3-58-ga151 From f655f8b818684716b2ebe35760c9b96184587d56 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 12 Jan 2019 12:51:05 -0800 Subject: Documentation: timestamping: correct path to net_tstamp.h net_tstamp.h is an UAPI header, so it was moved under include/uapi. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/networking/timestamping.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index 1be0b6f9e0cb..9d1432e0aaa8 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -417,7 +417,7 @@ is again deprecated and ts[2] holds a hardware timestamp if set. Hardware time stamping must also be initialized for each device driver that is expected to do hardware time stamping. The parameter is defined in -/include/linux/net_tstamp.h as: +include/uapi/linux/net_tstamp.h as: struct hwtstamp_config { int flags; /* no flags defined right now, must be zero */ @@ -487,7 +487,7 @@ enum { HWTSTAMP_FILTER_PTP_V1_L4_EVENT, /* for the complete list of values, please check - * the include file /include/linux/net_tstamp.h + * the include file include/uapi/linux/net_tstamp.h */ }; -- cgit v1.2.3-58-ga151 From cc5e710759470bc7f3c61d11fd54586f15fdbdf4 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 16 Jan 2019 16:54:42 +0800 Subject: vhost: log dirty page correctly Vhost dirty page logging API is designed to sync through GPA. But we try to log GIOVA when device IOTLB is enabled. This is wrong and may lead to missing data after migration. To solve this issue, when logging with device IOTLB enabled, we will: 1) reuse the device IOTLB translation result of GIOVA->HVA mapping to get HVA, for writable descriptor, get HVA through iovec. For used ring update, translate its GIOVA to HVA 2) traverse the GPA->HVA mapping to get the possible GPA and log through GPA. Pay attention this reverse mapping is not guaranteed to be unique, so we should log each possible GPA in this case. This fix the failure of scp to guest during migration. In -next, we will probably support passing GIOVA->GPA instead of GIOVA->HVA. Fixes: 6b1e6cc7855b ("vhost: new device IOTLB API") Reported-by: Jintack Lim Cc: Jintack Lim Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/vhost/net.c | 3 +- drivers/vhost/vhost.c | 97 +++++++++++++++++++++++++++++++++++++++++++-------- drivers/vhost/vhost.h | 3 +- 3 files changed, 87 insertions(+), 16 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 36f3d0f49e60..bca86bf7189f 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1236,7 +1236,8 @@ static void handle_rx(struct vhost_net *net) if (nvq->done_idx > VHOST_NET_BATCH) vhost_net_signal_used(nvq); if (unlikely(vq_log)) - vhost_log_write(vq, vq_log, log, vhost_len); + vhost_log_write(vq, vq_log, log, vhost_len, + vq->iov, in); total_len += vhost_len; if (unlikely(vhost_exceeds_weight(++recv_pkts, total_len))) { vhost_poll_queue(&vq->poll); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 9f7942cbcbb2..babbb32b9bf0 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1733,13 +1733,87 @@ static int log_write(void __user *log_base, return r; } +static int log_write_hva(struct vhost_virtqueue *vq, u64 hva, u64 len) +{ + struct vhost_umem *umem = vq->umem; + struct vhost_umem_node *u; + u64 start, end, l, min; + int r; + bool hit = false; + + while (len) { + min = len; + /* More than one GPAs can be mapped into a single HVA. So + * iterate all possible umems here to be safe. + */ + list_for_each_entry(u, &umem->umem_list, link) { + if (u->userspace_addr > hva - 1 + len || + u->userspace_addr - 1 + u->size < hva) + continue; + start = max(u->userspace_addr, hva); + end = min(u->userspace_addr - 1 + u->size, + hva - 1 + len); + l = end - start + 1; + r = log_write(vq->log_base, + u->start + start - u->userspace_addr, + l); + if (r < 0) + return r; + hit = true; + min = min(l, min); + } + + if (!hit) + return -EFAULT; + + len -= min; + hva += min; + } + + return 0; +} + +static int log_used(struct vhost_virtqueue *vq, u64 used_offset, u64 len) +{ + struct iovec iov[64]; + int i, ret; + + if (!vq->iotlb) + return log_write(vq->log_base, vq->log_addr + used_offset, len); + + ret = translate_desc(vq, (uintptr_t)vq->used + used_offset, + len, iov, 64, VHOST_ACCESS_WO); + if (ret) + return ret; + + for (i = 0; i < ret; i++) { + ret = log_write_hva(vq, (uintptr_t)iov[i].iov_base, + iov[i].iov_len); + if (ret) + return ret; + } + + return 0; +} + int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, - unsigned int log_num, u64 len) + unsigned int log_num, u64 len, struct iovec *iov, int count) { int i, r; /* Make sure data written is seen before log. */ smp_wmb(); + + if (vq->iotlb) { + for (i = 0; i < count; i++) { + r = log_write_hva(vq, (uintptr_t)iov[i].iov_base, + iov[i].iov_len); + if (r < 0) + return r; + } + return 0; + } + for (i = 0; i < log_num; ++i) { u64 l = min(log[i].len, len); r = log_write(vq->log_base, log[i].addr, l); @@ -1769,9 +1843,8 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq) smp_wmb(); /* Log used flag write. */ used = &vq->used->flags; - log_write(vq->log_base, vq->log_addr + - (used - (void __user *)vq->used), - sizeof vq->used->flags); + log_used(vq, (used - (void __user *)vq->used), + sizeof vq->used->flags); if (vq->log_ctx) eventfd_signal(vq->log_ctx, 1); } @@ -1789,9 +1862,8 @@ static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event) smp_wmb(); /* Log avail event write */ used = vhost_avail_event(vq); - log_write(vq->log_base, vq->log_addr + - (used - (void __user *)vq->used), - sizeof *vhost_avail_event(vq)); + log_used(vq, (used - (void __user *)vq->used), + sizeof *vhost_avail_event(vq)); if (vq->log_ctx) eventfd_signal(vq->log_ctx, 1); } @@ -2191,10 +2263,8 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq, /* Make sure data is seen before log. */ smp_wmb(); /* Log used ring entry write. */ - log_write(vq->log_base, - vq->log_addr + - ((void __user *)used - (void __user *)vq->used), - count * sizeof *used); + log_used(vq, ((void __user *)used - (void __user *)vq->used), + count * sizeof *used); } old = vq->last_used_idx; new = (vq->last_used_idx += count); @@ -2236,9 +2306,8 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads, /* Make sure used idx is seen before log. */ smp_wmb(); /* Log used index update. */ - log_write(vq->log_base, - vq->log_addr + offsetof(struct vring_used, idx), - sizeof vq->used->idx); + log_used(vq, offsetof(struct vring_used, idx), + sizeof vq->used->idx); if (vq->log_ctx) eventfd_signal(vq->log_ctx, 1); } diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 466ef7542291..1b675dad5e05 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -205,7 +205,8 @@ bool vhost_vq_avail_empty(struct vhost_dev *, struct vhost_virtqueue *); bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *); int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, - unsigned int log_num, u64 len); + unsigned int log_num, u64 len, + struct iovec *iov, int count); int vq_iotlb_prefetch(struct vhost_virtqueue *vq); struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type); -- cgit v1.2.3-58-ga151 From 28c1382fa28f2e2d9d0d6f25ae879b5af2ecbd03 Mon Sep 17 00:00:00 2001 From: Yunjian Wang Date: Thu, 17 Jan 2019 09:46:41 +0800 Subject: net: bridge: Fix ethernet header pointer before check skb forwardable The skb header should be set to ethernet header before using is_skb_forwardable. Because the ethernet header length has been considered in is_skb_forwardable(including dev->hard_header_len length). To reproduce the issue: 1, add 2 ports on linux bridge br using following commands: $ brctl addbr br $ brctl addif br eth0 $ brctl addif br eth1 2, the MTU of eth0 and eth1 is 1500 3, send a packet(Data 1480, UDP 8, IP 20, Ethernet 14, VLAN 4) from eth0 to eth1 So the expect result is packet larger than 1500 cannot pass through eth0 and eth1. But currently, the packet passes through success, it means eth1's MTU limit doesn't take effect. Fixes: f6367b4660dd ("bridge: use is_skb_forwardable in forward path") Cc: bridge@lists.linux-foundation.org Cc: Nkolay Aleksandrov Cc: Roopa Prabhu Cc: Stephen Hemminger Signed-off-by: Yunjian Wang Signed-off-by: David S. Miller --- net/bridge/br_forward.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 2cb8da465b98..48ddc60b4fbd 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -36,10 +36,10 @@ static inline int should_deliver(const struct net_bridge_port *p, int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) { + skb_push(skb, ETH_HLEN); if (!is_skb_forwardable(skb->dev, skb)) goto drop; - skb_push(skb, ETH_HLEN); br_drop_fake_rtable(skb); if (skb->ip_summed == CHECKSUM_PARTIAL && @@ -98,12 +98,11 @@ static void __br_forward(const struct net_bridge_port *to, net = dev_net(indev); } else { if (unlikely(netpoll_tx_running(to->br->dev))) { - if (!is_skb_forwardable(skb->dev, skb)) { + skb_push(skb, ETH_HLEN); + if (!is_skb_forwardable(skb->dev, skb)) kfree_skb(skb); - } else { - skb_push(skb, ETH_HLEN); + else br_netpoll_send_skb(to, skb); - } return; } br_hook = NF_BR_LOCAL_OUT; -- cgit v1.2.3-58-ga151 From c6ddfb9a963f0cac0f7365acfc87f3f3b33a3b69 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 17 Jan 2019 11:42:27 +0200 Subject: dpaa_eth: NETIF_F_LLTX requires to do our own update of trans_start As txq_trans_update() only updates trans_start when the lock is held, trans_start does not get updated if NETIF_F_LLTX is declared. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index f53090cde041..dfebc30c4841 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -2051,6 +2051,7 @@ dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev) bool nonlinear = skb_is_nonlinear(skb); struct rtnl_link_stats64 *percpu_stats; struct dpaa_percpu_priv *percpu_priv; + struct netdev_queue *txq; struct dpaa_priv *priv; struct qm_fd fd; int offset = 0; @@ -2100,6 +2101,11 @@ dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev) if (unlikely(err < 0)) goto skb_to_fd_failed; + txq = netdev_get_tx_queue(net_dev, queue_mapping); + + /* LLTX requires to do our own update of trans_start */ + txq->trans_start = jiffies; + if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { fd.cmd |= cpu_to_be32(FM_FD_CMD_UPD); skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; -- cgit v1.2.3-58-ga151 From 40f89ebfbd73fc9439ae8d4950f60226ad176690 Mon Sep 17 00:00:00 2001 From: Camelia Groza Date: Thu, 17 Jan 2019 14:33:33 +0200 Subject: net: phy: add missing phy driver features The phy drivers for CS4340 and TN2020 are missing their features attributes. Add them. Fixes: 719655a14971 ("net: phy: Replace phy driver features u32 with link_mode bitmap") Reported-by: Scott Wood Signed-off-by: Camelia Groza Signed-off-by: David S. Miller --- drivers/net/phy/cortina.c | 1 + drivers/net/phy/teranetics.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c index 8022cd317f62..1a4d04afb7f0 100644 --- a/drivers/net/phy/cortina.c +++ b/drivers/net/phy/cortina.c @@ -88,6 +88,7 @@ static struct phy_driver cortina_driver[] = { .phy_id = PHY_ID_CS4340, .phy_id_mask = 0xffffffff, .name = "Cortina CS4340", + .features = PHY_10GBIT_FEATURES, .config_init = gen10g_config_init, .config_aneg = gen10g_config_aneg, .read_status = cortina_read_status, diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c index 22f3bdd8206c..91247182bc52 100644 --- a/drivers/net/phy/teranetics.c +++ b/drivers/net/phy/teranetics.c @@ -80,6 +80,7 @@ static struct phy_driver teranetics_driver[] = { .phy_id = PHY_ID_TN2020, .phy_id_mask = 0xffffffff, .name = "Teranetics TN2020", + .features = PHY_10GBIT_FEATURES, .soft_reset = gen10g_no_soft_reset, .aneg_done = teranetics_aneg_done, .config_init = gen10g_config_init, -- cgit v1.2.3-58-ga151 From 5ab3121beeb76aa6090195b67d237115860dd9ec Mon Sep 17 00:00:00 2001 From: "Lendacky, Thomas" Date: Thu, 17 Jan 2019 14:20:14 +0000 Subject: amd-xgbe: Fix mdio access for non-zero ports and clause 45 PHYs The XGBE hardware has support for performing MDIO operations using an MDIO command request. The driver mistakenly uses the mdio port address as the MDIO command request device address instead of the MDIO command request port address. Additionally, the driver does not properly check for and create a clause 45 MDIO command. Check the supplied MDIO register to determine if the request is a clause 45 operation (MII_ADDR_C45). For a clause 45 operation, extract the device address and register number from the supplied MDIO register and use them to set the MDIO command request device address and register number fields. For a clause 22 operation, the MDIO request device address is set to zero and the MDIO command request register number is set to the supplied MDIO register. In either case, the supplied MDIO port address is used as the MDIO command request port address. Fixes: 732f2ab7afb9 ("amd-xgbe: Add support for MDIO attached PHYs") Signed-off-by: Tom Lendacky Tested-by: Shyam Sundar S K Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-common.h | 2 -- drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 22 ++++++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index d272dc6984ac..b40d4377cc71 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -431,8 +431,6 @@ #define MAC_MDIOSCAR_PA_WIDTH 5 #define MAC_MDIOSCAR_RA_INDEX 0 #define MAC_MDIOSCAR_RA_WIDTH 16 -#define MAC_MDIOSCAR_REG_INDEX 0 -#define MAC_MDIOSCAR_REG_WIDTH 21 #define MAC_MDIOSCCDR_BUSY_INDEX 22 #define MAC_MDIOSCCDR_BUSY_WIDTH 1 #define MAC_MDIOSCCDR_CMD_INDEX 16 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index 1e929a1e4ca7..4666084eda16 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1284,6 +1284,20 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad, } } +static unsigned int xgbe_create_mdio_sca(int port, int reg) +{ + unsigned int mdio_sca, da; + + da = (reg & MII_ADDR_C45) ? reg >> 16 : 0; + + mdio_sca = 0; + XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, RA, reg); + XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, PA, port); + XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, da); + + return mdio_sca; +} + static int xgbe_write_ext_mii_regs(struct xgbe_prv_data *pdata, int addr, int reg, u16 val) { @@ -1291,9 +1305,7 @@ static int xgbe_write_ext_mii_regs(struct xgbe_prv_data *pdata, int addr, reinit_completion(&pdata->mdio_complete); - mdio_sca = 0; - XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg); - XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr); + mdio_sca = xgbe_create_mdio_sca(addr, reg); XGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca); mdio_sccd = 0; @@ -1317,9 +1329,7 @@ static int xgbe_read_ext_mii_regs(struct xgbe_prv_data *pdata, int addr, reinit_completion(&pdata->mdio_complete); - mdio_sca = 0; - XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, REG, reg); - XGMAC_SET_BITS(mdio_sca, MAC_MDIOSCAR, DA, addr); + mdio_sca = xgbe_create_mdio_sca(addr, reg); XGMAC_IOWRITE(pdata, MAC_MDIOSCAR, mdio_sca); mdio_sccd = 0; -- cgit v1.2.3-58-ga151 From 87fff3cacd0112bcaf42f932c1e44ae32b42f1fb Mon Sep 17 00:00:00 2001 From: Yang Wei Date: Thu, 17 Jan 2019 23:11:30 +0800 Subject: neighbour: Do not perturb drop profiles when neigh_probe Replace the kfree_skb() by consume_skb() to be drop monitor(dropwatch, perf) friendly. Signed-off-by: Yang Wei Signed-off-by: David S. Miller --- net/core/neighbour.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 96fdc9134726..4230400b9a30 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1007,7 +1007,7 @@ static void neigh_probe(struct neighbour *neigh) if (neigh->ops->solicit) neigh->ops->solicit(neigh, skb); atomic_inc(&neigh->probes); - kfree_skb(skb); + consume_skb(skb); } /* Called when a timer expires for a neighbour entry. */ -- cgit v1.2.3-58-ga151 From bf97403ac4bfbc9f9f92f47e737aee983d9191f5 Mon Sep 17 00:00:00 2001 From: Yang Wei Date: Thu, 17 Jan 2019 23:30:03 +0800 Subject: macvlan: replace kfree_skb by consume_skb for drop profiles Replace the kfree_skb() by consume_skb() to be drop monitor(dropwatch, perf) friendly. Signed-off-by: Yang Wei Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index fc726ce4c164..6d067176320f 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -337,7 +337,7 @@ static void macvlan_process_broadcast(struct work_struct *w) if (src) dev_put(src->dev); - kfree_skb(skb); + consume_skb(skb); } } -- cgit v1.2.3-58-ga151 From 129699bb8c7572106b5bbb2407c2daee4727ccad Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 24 Dec 2018 14:23:36 -0500 Subject: drivers: thermal: int340x_thermal: Fix sysfs race condition Changes since V1: * Use dev_info instead of printk * Use dev_warn instead of BUG_ON Previously, sysfs_create_group was called before all initialization had fully run - specifically, before pci_set_drvdata was called. Since the sysctl group is visible to userspace as soon as sysfs_create_group returns, a small window of time existed during which a process could read from an uninitialized/partially-initialized device. This commit moves the creation of the sysctl group to after all initialized is completed. This ensures that it's impossible for userspace to read from a sysctl file before initialization has fully completed. To catch any future regressions, I've added a check to ensure that proc_thermal_emum_mode is never PROC_THERMAL_NONE when a process tries to read from a sysctl file. Previously, the aforementioned race condition could result in the 'else' branch running while PROC_THERMAL_NONE was set, leading to a null pointer deference. Signed-off-by: Aaron Hill Signed-off-by: Zhang Rui --- .../int340x_thermal/processor_thermal_device.c | 28 ++++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 8e0f665cf06f..8e1cf4d789be 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -84,7 +84,12 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ struct pci_dev *pci_dev; \ struct platform_device *pdev; \ struct proc_thermal_device *proc_dev; \ -\ + \ + if (proc_thermal_emum_mode == PROC_THERMAL_NONE) { \ + dev_warn(dev, "Attempted to get power limit before device was initialized!\n"); \ + return 0; \ + } \ + \ if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) { \ pdev = to_platform_device(dev); \ proc_dev = platform_get_drvdata(pdev); \ @@ -298,11 +303,6 @@ static int proc_thermal_add(struct device *dev, *priv = proc_priv; ret = proc_thermal_read_ppcc(proc_priv); - if (!ret) { - ret = sysfs_create_group(&dev->kobj, - &power_limit_attribute_group); - - } if (ret) return ret; @@ -316,8 +316,7 @@ static int proc_thermal_add(struct device *dev, proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); if (IS_ERR(proc_priv->int340x_zone)) { - ret = PTR_ERR(proc_priv->int340x_zone); - goto remove_group; + return PTR_ERR(proc_priv->int340x_zone); } else ret = 0; @@ -331,9 +330,6 @@ static int proc_thermal_add(struct device *dev, remove_zone: int340x_thermal_zone_remove(proc_priv->int340x_zone); -remove_group: - sysfs_remove_group(&proc_priv->dev->kobj, - &power_limit_attribute_group); return ret; } @@ -364,7 +360,10 @@ static int int3401_add(struct platform_device *pdev) platform_set_drvdata(pdev, proc_priv); proc_thermal_emum_mode = PROC_THERMAL_PLATFORM_DEV; - return 0; + dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PLATFORM_DEV\n"); + + return sysfs_create_group(&pdev->dev.kobj, + &power_limit_attribute_group); } static int int3401_remove(struct platform_device *pdev) @@ -441,7 +440,10 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "No auxiliary DTSs enabled\n"); } - return 0; + dev_info(&pdev->dev, "Creating sysfs group for PROC_THERMAL_PCI\n"); + + return sysfs_create_group(&pdev->dev.kobj, + &power_limit_attribute_group); } static void proc_thermal_pci_remove(struct pci_dev *pdev) -- cgit v1.2.3-58-ga151 From fa5762fca80146153bff37ce5b74fa69b84904eb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 17 Jan 2019 09:23:48 +0100 Subject: USB: usbip: delete README file The README file ni the drivers/usb/usbip/ directory is not needed anymore, so just delete it. Cc: Valentina Manea Signed-off-by: Greg Kroah-Hartman Acked-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/README | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 drivers/usb/usbip/README diff --git a/drivers/usb/usbip/README b/drivers/usb/usbip/README deleted file mode 100644 index 41a2cf2e77a6..000000000000 --- a/drivers/usb/usbip/README +++ /dev/null @@ -1,7 +0,0 @@ -TODO: - - more discussion about the protocol - - testing - - review of the userspace interface - - document the protocol - -Please send patches for this code to Greg Kroah-Hartman -- cgit v1.2.3-58-ga151 From a817c59e8273e555acb5cbccc75f5b57c27e3da9 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 16 Jan 2019 16:28:20 -0700 Subject: MAINTAINERS: email address update in MAINTAINERS entries Update email address in MAINTAINERS entries. Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4d04cebb4a71..6ca780f24808 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3979,6 +3979,7 @@ F: drivers/cpufreq/arm_big_little.c CPU POWER MONITORING SUBSYSTEM M: Thomas Renninger M: Shuah Khan +M: Shuah Khan L: linux-pm@vger.kernel.org S: Maintained F: tools/power/cpupower/ @@ -8259,6 +8260,7 @@ F: include/uapi/linux/sunrpc/ KERNEL SELFTEST FRAMEWORK M: Shuah Khan +M: Shuah Khan L: linux-kselftest@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git Q: https://patchwork.kernel.org/project/linux-kselftest/list/ @@ -15842,6 +15844,7 @@ F: drivers/usb/common/usb-otg-fsm.c USB OVER IP DRIVER M: Valentina Manea M: Shuah Khan +M: Shuah Khan L: linux-usb@vger.kernel.org S: Maintained F: Documentation/usb/usbip_protocol.txt -- cgit v1.2.3-58-ga151 From 8ff396fe56f5593640a8ce7223cac33a2cda619e Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 17 Jan 2019 09:24:20 +0000 Subject: usb: chipidea: fix static checker warning for NULL pointer During the static checker, "data->usbmisc_data" may be NULL. Fix it by adding this pointer judgement before using. Reported-by: Dan Carpenter Signed-off-by: Peter Chen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index e81de9ca8729..9b45aa422e69 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -316,7 +316,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) if (IS_ERR(data->usbmisc_data)) return PTR_ERR(data->usbmisc_data); - if (of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) { + if ((of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) + && data->usbmisc_data) { pdata.flags |= CI_HDRC_IMX_IS_HSIC; data->usbmisc_data->hsic = 1; data->pinctrl = devm_pinctrl_get(dev); -- cgit v1.2.3-58-ga151 From 91f7d2e89868fcac0e750a28230fdb1ad4512137 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 11 Jan 2019 17:29:45 +0100 Subject: USB: leds: fix regression in usbport led trigger The patch "usb: simplify usbport trigger" together with "leds: triggers: add device attribute support" caused an regression for the usbport trigger. it will no longer enumerate any active usb hub ports under the "ports" directory in the sysfs class directory, if the usb host drivers are fully initialized before the usbport trigger was loaded. The reason is that the usbport driver tries to register the sysfs entries during the activate() callback. And this will fail with -2 / ENOENT because the patch "leds: triggers: add device attribute support" made it so that the sysfs "ports" group was only being added after the activate() callback succeeded. This version of the patch reverts parts of the "usb: simplify usbport trigger" patch and restores usbport trigger's functionality. Fixes: 6f7b0bad8839 ("usb: simplify usbport trigger") Signed-off-by: Christian Lamparter Cc: stable Acked-by: Jacek Anaszewski Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/ledtrig-usbport.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index dc7f7fd71684..c12ac56606c3 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -119,11 +119,6 @@ static const struct attribute_group ports_group = { .attrs = ports_attrs, }; -static const struct attribute_group *ports_groups[] = { - &ports_group, - NULL -}; - /*************************************** * Adding & removing ports ***************************************/ @@ -307,6 +302,7 @@ static int usbport_trig_notify(struct notifier_block *nb, unsigned long action, static int usbport_trig_activate(struct led_classdev *led_cdev) { struct usbport_trig_data *usbport_data; + int err; usbport_data = kzalloc(sizeof(*usbport_data), GFP_KERNEL); if (!usbport_data) @@ -315,6 +311,9 @@ static int usbport_trig_activate(struct led_classdev *led_cdev) /* List of ports */ INIT_LIST_HEAD(&usbport_data->ports); + err = sysfs_create_group(&led_cdev->dev->kobj, &ports_group); + if (err) + goto err_free; usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports); usbport_trig_update_count(usbport_data); @@ -322,8 +321,11 @@ static int usbport_trig_activate(struct led_classdev *led_cdev) usbport_data->nb.notifier_call = usbport_trig_notify; led_set_trigger_data(led_cdev, usbport_data); usb_register_notify(&usbport_data->nb); - return 0; + +err_free: + kfree(usbport_data); + return err; } static void usbport_trig_deactivate(struct led_classdev *led_cdev) @@ -335,6 +337,8 @@ static void usbport_trig_deactivate(struct led_classdev *led_cdev) usbport_trig_remove_port(usbport_data, port); } + sysfs_remove_group(&led_cdev->dev->kobj, &ports_group); + usb_unregister_notify(&usbport_data->nb); kfree(usbport_data); @@ -344,7 +348,6 @@ static struct led_trigger usbport_led_trigger = { .name = "usbport", .activate = usbport_trig_activate, .deactivate = usbport_trig_deactivate, - .groups = ports_groups, }; static int __init usbport_trig_init(void) -- cgit v1.2.3-58-ga151 From 70d0ba4cf79a0e73485b22d955991c6f27257376 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 14 Jan 2019 21:16:08 +0100 Subject: USB: EHCI: ehci-mv: add MODULE_DEVICE_TABLE This fixes autoloading the module by the OF compatible string. Fixes: 813e18b18a87 ("USB: EHCI: ehci-mv: add DT support") Cc: stable@vger.kernel.org Signed-off-by: Lubomir Rintel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-mv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index f26109eafdbf..66ec1fdf9fe7 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -302,3 +302,4 @@ MODULE_AUTHOR("Chao Xie "); MODULE_AUTHOR("Neil Zhang "); MODULE_ALIAS("mv-ehci"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, ehci_mv_dt_ids); -- cgit v1.2.3-58-ga151 From 01eeb927bbcc1952114b0aec1447699c4747c337 Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Thu, 17 Jan 2019 18:39:07 +0100 Subject: mtd: nand: jz4740: fix '__iomem *' vs. '* __iomem' The function jz_nand_ioremap_resource() needs a pointer to an __iomem pointer as its last argument but this argument is declared as: void * __iomem *base Fix this by using the correct declaration: void __iomem **base which then also removes the following Sparse's warnings: 282:15: warning: incorrect type in assignment (different address spaces) 282:15: expected void *[noderef] 282:15: got void [noderef] * 322:57: warning: incorrect type in argument 4 (different address spaces) 322:57: expected void *[noderef] *base 322:57: got void [noderef] ** 402:67: warning: incorrect type in argument 4 (different address spaces) 402:67: expected void *[noderef] *base 402:67: got void [noderef] ** Signed-off-by: Luc Van Oostenryck Acked-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/jz4740_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c index f92ae5aa2a54..9526d5b23c80 100644 --- a/drivers/mtd/nand/raw/jz4740_nand.c +++ b/drivers/mtd/nand/raw/jz4740_nand.c @@ -260,7 +260,7 @@ static int jz_nand_correct_ecc_rs(struct nand_chip *chip, uint8_t *dat, } static int jz_nand_ioremap_resource(struct platform_device *pdev, - const char *name, struct resource **res, void *__iomem *base) + const char *name, struct resource **res, void __iomem **base) { int ret; -- cgit v1.2.3-58-ga151 From d311e0c27b8fcc27f707f8cac48cd8bdc4155224 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 18 Jan 2019 14:30:38 +0900 Subject: mtd: rawnand: denali: get ->setup_data_interface() working again Commit 7a08dbaedd36 ("mtd: rawnand: Move ->setup_data_interface() to nand_controller_ops") missed to invert the if-conditonal for denali. Since then, the Denali NAND driver cannnot invoke setup_data_interface. Fixes: 7a08dbaedd36 ("mtd: rawnand: Move ->setup_data_interface() to nand_controller_ops") Signed-off-by: Masahiro Yamada Acked-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/raw/denali.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index eebac35304c6..6e8edc9375dd 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -1322,7 +1322,7 @@ int denali_init(struct denali_nand_info *denali) } /* clk rate info is needed for setup_data_interface */ - if (denali->clk_rate && denali->clk_x_rate) + if (!denali->clk_rate || !denali->clk_x_rate) chip->options |= NAND_KEEP_TIMINGS; chip->legacy.dummy_controller.ops = &denali_controller_ops; -- cgit v1.2.3-58-ga151 From 97715058b70da1262fd07798c8b2e3e894f759dd Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 16 Jan 2019 06:20:11 -0700 Subject: staging: rtl8723bs: Fix build error with Clang when inlining is disabled When CONFIG_NO_AUTO_INLINE was present in linux-next (which added '-fno-inline-functions' to KBUILD_CFLAGS), an allyesconfig build with Clang failed at the modpost stage: ERROR: "is_broadcast_mac_addr" [drivers/staging/rtl8723bs/r8723bs.ko] undefined! ERROR: "is_zero_mac_addr" [drivers/staging/rtl8723bs/r8723bs.ko] undefined! ERROR: "is_multicast_mac_addr" [drivers/staging/rtl8723bs/r8723bs.ko] undefined! These functions were marked as extern inline, meaning that if inlining doesn't happen, the function will be undefined, as it is above. This happens to work with GCC because the '-fno-inline-functions' option respects the __inline attribute so all instances of these functions are inlined as expected and the definition doesn't actually matter. However, with Clang and '-fno-inline-functions', a function has to be marked with the __always_inline attribute to be considered for inlining, which none of these functions are. Clang tries to find the symbol definition elsewhere as it was told and fails, which trickles down to modpost. To make sure that this code compiles regardless of compiler and make the intention of the code clearer, use 'static' to ensure these functions are always defined, regardless of inlining. Additionally, silence a checkpatch warning by switching from '__inline' to 'inline'. Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/include/ieee80211.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index bcc8dfa8e672..9efb4dcb9d3a 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -850,18 +850,18 @@ enum ieee80211_state { #define IP_FMT "%pI4" #define IP_ARG(x) (x) -extern __inline int is_multicast_mac_addr(const u8 *addr) +static inline int is_multicast_mac_addr(const u8 *addr) { return ((addr[0] != 0xff) && (0x01 & addr[0])); } -extern __inline int is_broadcast_mac_addr(const u8 *addr) +static inline int is_broadcast_mac_addr(const u8 *addr) { return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); } -extern __inline int is_zero_mac_addr(const u8 *addr) +static inline int is_zero_mac_addr(const u8 *addr) { return ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && \ (addr[3] == 0x00) && (addr[4] == 0x00) && (addr[5] == 0x00)); -- cgit v1.2.3-58-ga151 From 527c1e567ead03ec21f6707e79c166ce680f17f7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 17 Jan 2019 09:23:46 +0100 Subject: USB: serial: keyspan_usa: add proper SPDX lines for .h files The keyspan_usa??msg.h files are under a BSD-3 style license, so properly label them as such with a SPDX line at the top of the file. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/keyspan_usa26msg.h | 1 + drivers/usb/serial/keyspan_usa28msg.h | 1 + drivers/usb/serial/keyspan_usa49msg.h | 1 + drivers/usb/serial/keyspan_usa67msg.h | 1 + drivers/usb/serial/keyspan_usa90msg.h | 1 + 5 files changed, 5 insertions(+) diff --git a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h index 09e21e84fc4e..a68f1fb25b8a 100644 --- a/drivers/usb/serial/keyspan_usa26msg.h +++ b/drivers/usb/serial/keyspan_usa26msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa26msg.h diff --git a/drivers/usb/serial/keyspan_usa28msg.h b/drivers/usb/serial/keyspan_usa28msg.h index dee454c4609a..a19f3fe5d98d 100644 --- a/drivers/usb/serial/keyspan_usa28msg.h +++ b/drivers/usb/serial/keyspan_usa28msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa28msg.h diff --git a/drivers/usb/serial/keyspan_usa49msg.h b/drivers/usb/serial/keyspan_usa49msg.h index 163b2dea2ec5..8c3970fdd868 100644 --- a/drivers/usb/serial/keyspan_usa49msg.h +++ b/drivers/usb/serial/keyspan_usa49msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa49msg.h diff --git a/drivers/usb/serial/keyspan_usa67msg.h b/drivers/usb/serial/keyspan_usa67msg.h index 20fa3e2f7187..dcf502fdbb44 100644 --- a/drivers/usb/serial/keyspan_usa67msg.h +++ b/drivers/usb/serial/keyspan_usa67msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa67msg.h diff --git a/drivers/usb/serial/keyspan_usa90msg.h b/drivers/usb/serial/keyspan_usa90msg.h index 86708ecd8735..c4ca0f631d20 100644 --- a/drivers/usb/serial/keyspan_usa90msg.h +++ b/drivers/usb/serial/keyspan_usa90msg.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ /* usa90msg.h -- cgit v1.2.3-58-ga151 From aff9cf5955185d1f183227e46c5f8673fa483813 Mon Sep 17 00:00:00 2001 From: Samir Virmani Date: Wed, 16 Jan 2019 10:28:07 -0800 Subject: uart: Fix crash in uart_write and uart_put_char We were experiencing a crash similar to the one reported as part of commit:a5ba1d95e46e ("uart: fix race between uart_put_char() and uart_shutdown()") in our testbed as well. We continue to observe the same crash after integrating the commit a5ba1d95e46e ("uart: fix race between uart_put_char() and uart_shutdown()") On reviewing the change, the port lock should be taken prior to checking for if (!circ->buf) in fn. __uart_put_char and other fns. that update the buffer uart_state->xmit. Traceback: [11/27/2018 06:24:32.4870] Unable to handle kernel NULL pointer dereference at virtual address 0000003b [11/27/2018 06:24:32.4950] PC is at memcpy+0x48/0x180 [11/27/2018 06:24:32.4950] LR is at uart_write+0x74/0x120 [11/27/2018 06:24:32.4950] pc : [] lr : [] pstate: 000001c5 [11/27/2018 06:24:32.4950] sp : ffffffc076433d30 [11/27/2018 06:24:32.4950] x29: ffffffc076433d30 x28: 0000000000000140 [11/27/2018 06:24:32.4950] x27: ffffffc0009b9d5e x26: ffffffc07ce36580 [11/27/2018 06:24:32.4950] x25: 0000000000000000 x24: 0000000000000140 [11/27/2018 06:24:32.4950] x23: ffffffc000891200 x22: ffffffc01fc34000 [11/27/2018 06:24:32.4950] x21: 0000000000000fff x20: 0000000000000076 [11/27/2018 06:24:32.4950] x19: 0000000000000076 x18: 0000000000000000 [11/27/2018 06:24:32.4950] x17: 000000000047cf08 x16: ffffffc000099e68 [11/27/2018 06:24:32.4950] x15: 0000000000000018 x14: 776d726966205948 [11/27/2018 06:24:32.4950] x13: 50203a6c6974755f x12: 74647075205d3333 [11/27/2018 06:24:32.4950] x11: 3a35323a36203831 x10: 30322f37322f3131 [11/27/2018 06:24:32.4950] x9 : 5b205d303638342e x8 : 746164206f742070 [11/27/2018 06:24:32.4950] x7 : 7520736920657261 x6 : 000000000000003b [11/27/2018 06:24:32.4950] x5 : 000000000000817a x4 : 0000000000000008 [11/27/2018 06:24:32.4950] x3 : 2f37322f31312a5b x2 : 000000000000006e [11/27/2018 06:24:32.4950] x1 : ffffffc0009b9cf0 x0 : 000000000000003b [11/27/2018 06:24:32.4950] CPU2: stopping [11/27/2018 06:24:32.4950] CPU: 2 PID: 0 Comm: swapper/2 Tainted: P D O 4.1.51 #3 [11/27/2018 06:24:32.4950] Hardware name: Broadcom-v8A (DT) [11/27/2018 06:24:32.4950] Call trace: [11/27/2018 06:24:32.4950] [] dump_backtrace+0x0/0x150 [11/27/2018 06:24:32.4950] [] show_stack+0x14/0x20 [11/27/2018 06:24:32.4950] [] dump_stack+0x90/0xb0 [11/27/2018 06:24:32.4950] [] handle_IPI+0x18c/0x1a0 [11/27/2018 06:24:32.4950] [] gic_handle_irq+0x88/0x90 Fixes: a5ba1d95e46e ("uart: fix race between uart_put_char() and uart_shutdown()") Cc: stable Signed-off-by: Samir Virmani Acked-by: Tycho Andersen Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index d4cca5bdaf1c..5c01bb6d1c24 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -550,10 +550,12 @@ static int uart_put_char(struct tty_struct *tty, unsigned char c) int ret = 0; circ = &state->xmit; - if (!circ->buf) + port = uart_port_lock(state, flags); + if (!circ->buf) { + uart_port_unlock(port, flags); return 0; + } - port = uart_port_lock(state, flags); if (port && uart_circ_chars_free(circ) != 0) { circ->buf[circ->head] = c; circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); @@ -586,11 +588,13 @@ static int uart_write(struct tty_struct *tty, return -EL3HLT; } + port = uart_port_lock(state, flags); circ = &state->xmit; - if (!circ->buf) + if (!circ->buf) { + uart_port_unlock(port, flags); return 0; + } - port = uart_port_lock(state, flags); while (port) { c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); if (count < c) -- cgit v1.2.3-58-ga151 From 352c4cf40c4a7d439fa5d30aa2160f54b394da82 Mon Sep 17 00:00:00 2001 From: He Zhe Date: Thu, 17 Jan 2019 17:00:19 +0800 Subject: serial: 8250: Fix serial8250 initialization crash The initialization code of interrupt backoff work might reference NULL pointer and cause the following crash, if no port was found. [ 10.017727] CPU 0 Unable to handle kernel paging request at virtual address 000001b0, epc == 807088e0, ra == 8070863c ---- snip ---- [ 11.704470] [<807088e0>] serial8250_register_8250_port+0x318/0x4ac [ 11.747251] [<80708d74>] serial8250_probe+0x148/0x1c0 [ 11.789301] [<80728450>] platform_drv_probe+0x40/0x94 [ 11.830515] [<807264f8>] really_probe+0xf8/0x318 [ 11.870876] [<80726b7c>] __driver_attach+0x110/0x12c [ 11.910960] [<80724374>] bus_for_each_dev+0x78/0xcc [ 11.951134] [<80725958>] bus_add_driver+0x200/0x234 [ 11.989756] [<807273d8>] driver_register+0x84/0x148 [ 12.029832] [<80d72f84>] serial8250_init+0x138/0x198 [ 12.070447] [<80100e6c>] do_one_initcall+0x5c/0x2a0 [ 12.110104] [<80d3a208>] kernel_init_freeable+0x370/0x484 [ 12.150722] [<80a49420>] kernel_init+0x10/0xf8 [ 12.191517] [<8010756c>] ret_from_kernel_thread+0x14/0x1c This patch makes sure the initialization code can be reached only if a port is found. Fixes: 6d7f677a2afa ("serial: 8250: Rate limit serial port rx interrupts during input overruns") Signed-off-by: He Zhe Reviewed-by: Darwin Dingel Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 189ab1212d9a..e441221e04b9 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1070,15 +1070,16 @@ int serial8250_register_8250_port(struct uart_8250_port *up) ret = 0; } - } - /* Initialise interrupt backoff work if required */ - if (up->overrun_backoff_time_ms > 0) { - uart->overrun_backoff_time_ms = up->overrun_backoff_time_ms; - INIT_DELAYED_WORK(&uart->overrun_backoff, - serial_8250_overrun_backoff_work); - } else { - uart->overrun_backoff_time_ms = 0; + /* Initialise interrupt backoff work if required */ + if (up->overrun_backoff_time_ms > 0) { + uart->overrun_backoff_time_ms = + up->overrun_backoff_time_ms; + INIT_DELAYED_WORK(&uart->overrun_backoff, + serial_8250_overrun_backoff_work); + } else { + uart->overrun_backoff_time_ms = 0; + } } mutex_unlock(&serial_mutex); -- cgit v1.2.3-58-ga151 From fc01d8c61ce02c034e67378cd3e645734bc18c8c Mon Sep 17 00:00:00 2001 From: Paul Fulghum Date: Tue, 1 Jan 2019 12:28:53 -0800 Subject: tty/n_hdlc: fix __might_sleep warning Fix __might_sleep warning[1] in tty/n_hdlc.c read due to copy_to_user call while current is TASK_INTERRUPTIBLE. This is a false positive since the code path does not depend on current state remaining TASK_INTERRUPTIBLE. The loop breaks out and sets TASK_RUNNING after calling copy_to_user. This patch supresses the warning by setting TASK_RUNNING before calling copy_to_user. [1] https://syzkaller.appspot.com/bug?id=17d5de7f1fcab794cb8c40032f893f52de899324 Signed-off-by: Paul Fulghum Reported-by: syzbot Cc: Tetsuo Handa Cc: Alan Cox Cc: stable Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 4164414d4c64..8bdf42bc8fc8 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -597,6 +597,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, /* too large for caller's buffer */ ret = -EOVERFLOW; } else { + __set_current_state(TASK_RUNNING); if (copy_to_user(buf, rbuf->buf, rbuf->count)) ret = -EFAULT; else -- cgit v1.2.3-58-ga151 From 6609cff65c5b184ab889880ef5d41189611ea05f Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 8 Jan 2019 22:54:59 -0500 Subject: vt: make vt_console_print() compatible with the unicode screen buffer When kernel messages are printed to the console, they appear blank on the unicode screen. This is because vt_console_print() is lacking a call to vc_uniscr_putc(). However the later function assumes vc->vc_x is always up to date when called, which is not the case here as vt_console_print() uses it to mark the beginning of the display update. This patch reworks (and simplifies) vt_console_print() so that vc->vc_x is always valid and keeps the start of display update in a local variable instead, which finally allows for adding the missing vc_uniscr_putc() call. Signed-off-by: Nicolas Pitre Cc: stable@vger.kernel.org # v4.19+ Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 47 +++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 41ec8e5010f3..b9004bd08772 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2884,8 +2884,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) unsigned char c; static DEFINE_SPINLOCK(printing_lock); const ushort *start; - ushort cnt = 0; - ushort myx; + ushort start_x, cnt; int kmsg_console; /* console busy or not yet initialized */ @@ -2898,10 +2897,6 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) if (kmsg_console && vc_cons_allocated(kmsg_console - 1)) vc = vc_cons[kmsg_console - 1].d; - /* read `x' only after setting currcons properly (otherwise - the `x' macro will read the x of the foreground console). */ - myx = vc->vc_x; - if (!vc_cons_allocated(fg_console)) { /* impossible */ /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */ @@ -2916,53 +2911,41 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) hide_cursor(vc); start = (ushort *)vc->vc_pos; - - /* Contrived structure to try to emulate original need_wrap behaviour - * Problems caused when we have need_wrap set on '\n' character */ + start_x = vc->vc_x; + cnt = 0; while (count--) { c = *b++; if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { - if (cnt > 0) { - if (con_is_visible(vc)) - vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); - vc->vc_x += cnt; - if (vc->vc_need_wrap) - vc->vc_x--; - cnt = 0; - } + if (cnt && con_is_visible(vc)) + vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x); + cnt = 0; if (c == 8) { /* backspace */ bs(vc); start = (ushort *)vc->vc_pos; - myx = vc->vc_x; + start_x = vc->vc_x; continue; } if (c != 13) lf(vc); cr(vc); start = (ushort *)vc->vc_pos; - myx = vc->vc_x; + start_x = vc->vc_x; if (c == 10 || c == 13) continue; } + vc_uniscr_putc(vc, c); scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos); notify_write(vc, c); cnt++; - if (myx == vc->vc_cols - 1) { - vc->vc_need_wrap = 1; - continue; - } - vc->vc_pos += 2; - myx++; - } - if (cnt > 0) { - if (con_is_visible(vc)) - vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); - vc->vc_x += cnt; - if (vc->vc_x == vc->vc_cols) { - vc->vc_x--; + if (vc->vc_x == vc->vc_cols - 1) { vc->vc_need_wrap = 1; + } else { + vc->vc_pos += 2; + vc->vc_x++; } } + if (cnt && con_is_visible(vc)) + vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, start_x); set_cursor(vc); notify_update(vc); -- cgit v1.2.3-58-ga151 From 7e1d226345f89ad5d0216a9092c81386c89b4983 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 8 Jan 2019 22:55:00 -0500 Subject: vt: always call notifier with the console lock held Every invocation of notify_write() and notify_update() is performed under the console lock, except for one case. Let's fix that. Signed-off-by: Nicolas Pitre Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index b9004bd08772..5b8b0e33f939 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2764,8 +2764,8 @@ rescan_last_byte: con_flush(vc, draw_from, draw_to, &draw_x); vc_uniscr_debug_check(vc); console_conditional_schedule(); - console_unlock(); notify_update(vc); + console_unlock(); return n; } -- cgit v1.2.3-58-ga151 From 0c9b1965faddad7534b6974b5b36c4ad37998f8e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 8 Jan 2019 22:55:01 -0500 Subject: vt: invoke notifier on screen size change User space using poll() on /dev/vcs devices are not awaken when a screen size change occurs. Let's fix that. Signed-off-by: Nicolas Pitre Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 5b8b0e33f939..bba75560d11e 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1272,6 +1272,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (con_is_visible(vc)) update_screen(vc); vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num); + notify_update(vc); return err; } -- cgit v1.2.3-58-ga151 From bfd8d8fe98b8792f362cd210a7873969f8d2fc04 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 10 Jan 2019 16:33:55 -0500 Subject: vgacon: unconfuse vc_origin when using soft scrollback When CONFIG_VGACON_SOFT_SCROLLBACK is selected, the VGA display memory index and vc_visible_origin don't change when scrollback is activated. The actual screen content is saved away and the scrollbackdata is copied over it. However the vt code, and /dev/vcs devices in particular, still expect vc_origin to always point at the actual screen content not the displayed scrollback content. So adjust vc_origin to point at the saved screen content when scrollback is active and set it back to vc_visible_origin when restoring the screen. This fixes /dev/vcsa that return scrollback content when they shouldn't (onli /dev/vcsa without a number should), and also fixes /dev/vcsu that should return scrollback content when scrollback is active but currently doesn't. An unnecessary call to vga_set_mem_top() is also removed. Signed-off-by: Nicolas Pitre Cc: stable@vger.kernel.org # v4.19+ Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/vgacon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 09731b2f6815..c6b3bdbbdbc9 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -271,6 +271,7 @@ static void vgacon_scrollback_update(struct vc_data *c, int t, int count) static void vgacon_restore_screen(struct vc_data *c) { + c->vc_origin = c->vc_visible_origin; vgacon_scrollback_cur->save = 0; if (!vga_is_gfx && !vgacon_scrollback_cur->restore) { @@ -287,8 +288,7 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines) int start, end, count, soff; if (!lines) { - c->vc_visible_origin = c->vc_origin; - vga_set_mem_top(c); + vgacon_restore_screen(c); return; } @@ -298,6 +298,7 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines) if (!vgacon_scrollback_cur->save) { vgacon_cursor(c, CM_ERASE); vgacon_save_screen(c); + c->vc_origin = (unsigned long)c->vc_screenbuf; vgacon_scrollback_cur->save = 1; } @@ -335,7 +336,7 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines) int copysize; int diff = c->vc_rows - count; - void *d = (void *) c->vc_origin; + void *d = (void *) c->vc_visible_origin; void *s = (void *) c->vc_screenbuf; count *= c->vc_size_row; -- cgit v1.2.3-58-ga151 From 7e7ca7744a539f1a172e3b81c29d000787e3d774 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 16 Jan 2019 10:42:59 +0000 Subject: binderfs: fix error return code in binderfs_fill_super() Fix to return a negative error code -ENOMEM from the new_inode() and d_make_root() error handling cases instead of 0, as done elsewhere in this function. Fixes: 849d540ddfcd ("binderfs: implement "max" mount option") Signed-off-by: Wei Yongjun Reviewed-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 9518e2e7da05..e4ff4c3fa371 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -518,6 +518,7 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_fs_info = info; + ret = -ENOMEM; inode = new_inode(sb); if (!inode) goto err_without_dentry; -- cgit v1.2.3-58-ga151 From e25df7812c91f62581301f9a7ac102acf92e4937 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 16 Jan 2019 10:46:16 -0600 Subject: misc: ibmvsm: Fix potential NULL pointer dereference There is a potential NULL pointer dereference in case kzalloc() fails and returns NULL. Fix this by adding a NULL check on *session* Also, update the function header with information about the expected return on failure and remove unnecessary variable rc. This issue was detected with the help of Coccinelle. Fixes: 0eca353e7ae7 ("misc: IBM Virtual Management Channel Driver (VMC)") Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ibmvmc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/misc/ibmvmc.c b/drivers/misc/ibmvmc.c index b8aaa684c397..2ed23c99f59f 100644 --- a/drivers/misc/ibmvmc.c +++ b/drivers/misc/ibmvmc.c @@ -820,21 +820,24 @@ static int ibmvmc_send_msg(struct crq_server_adapter *adapter, * * Return: * 0 - Success + * Non-zero - Failure */ static int ibmvmc_open(struct inode *inode, struct file *file) { struct ibmvmc_file_session *session; - int rc = 0; pr_debug("%s: inode = 0x%lx, file = 0x%lx, state = 0x%x\n", __func__, (unsigned long)inode, (unsigned long)file, ibmvmc.state); session = kzalloc(sizeof(*session), GFP_KERNEL); + if (!session) + return -ENOMEM; + session->file = file; file->private_data = session; - return rc; + return 0; } /** -- cgit v1.2.3-58-ga151 From 8208d1708b88b412ca97f50a6d951242c88cbbac Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 18 Jan 2019 14:08:59 +0000 Subject: irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size The way we allocate events works fine in most cases, except when multiple PCI devices share an ITS-visible DevID, and that one of them is trying to use MultiMSI allocation. In that case, our allocation is not guaranteed to be zero-based anymore, and we have to make sure we allocate it on a boundary that is compatible with the PCI Multi-MSI constraints. Fix this by allocating the full region upfront instead of iterating over the number of MSIs. MSI-X are always allocated one by one, so this shouldn't change anything on that front. Fixes: b48ac83d6bbc2 ("irqchip: GICv3: ITS: MSI support") Cc: stable@vger.kernel.org Reported-by: Ard Biesheuvel Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier --- drivers/irqchip/irq-gic-v3-its.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index db20e992a40f..7f2a45445b00 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -2399,13 +2399,14 @@ static void its_free_device(struct its_device *its_dev) kfree(its_dev); } -static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq) +static int its_alloc_device_irq(struct its_device *dev, int nvecs, irq_hw_number_t *hwirq) { int idx; - idx = find_first_zero_bit(dev->event_map.lpi_map, - dev->event_map.nr_lpis); - if (idx == dev->event_map.nr_lpis) + idx = bitmap_find_free_region(dev->event_map.lpi_map, + dev->event_map.nr_lpis, + get_count_order(nvecs)); + if (idx < 0) return -ENOSPC; *hwirq = dev->event_map.lpi_base + idx; @@ -2501,21 +2502,21 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, int err; int i; - for (i = 0; i < nr_irqs; i++) { - err = its_alloc_device_irq(its_dev, &hwirq); - if (err) - return err; + err = its_alloc_device_irq(its_dev, nr_irqs, &hwirq); + if (err) + return err; - err = its_irq_gic_domain_alloc(domain, virq + i, hwirq); + for (i = 0; i < nr_irqs; i++) { + err = its_irq_gic_domain_alloc(domain, virq + i, hwirq + i); if (err) return err; irq_domain_set_hwirq_and_chip(domain, virq + i, - hwirq, &its_irq_chip, its_dev); + hwirq + i, &its_irq_chip, its_dev); irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq + i))); pr_debug("ID:%d pID:%d vID:%d\n", - (int)(hwirq - its_dev->event_map.lpi_base), - (int) hwirq, virq + i); + (int)(hwirq + i - its_dev->event_map.lpi_base), + (int)(hwirq + i), virq + i); } return 0; -- cgit v1.2.3-58-ga151 From 0ce23d6d42147a692768e6baaaa3db75c44f4235 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 17 Jan 2019 17:32:05 +0000 Subject: ASoC: hdmi-codec: fix oops on re-probe hdmi-codec oopses the kernel when it is unbound from a successfully bound audio subsystem, and is then rebound: Unable to handle kernel NULL pointer dereference at virtual address 0000001c pgd = ee3f0000 [0000001c] *pgd=3cc59831 Internal error: Oops: 817 [#1] PREEMPT ARM Modules linked in: ext2 snd_soc_spdif_tx vmeta dove_thermal snd_soc_kirkwood ofpart marvell_cesa m25p80 orion_wdt mtd spi_nor des_generic gpio_ir_recv snd_soc_kirkwood_spdif bmm_dmabuf auth_rpcgss nfsd autofs4 etnaviv thermal_sys hwmon gpu_sched tda9950 CPU: 0 PID: 1005 Comm: bash Not tainted 4.20.0+ #1762 Hardware name: Marvell Dove (Cubox) PC is at hdmi_dai_probe+0x68/0x80 LR is at find_held_lock+0x20/0x94 pc : [] lr : [] psr: 600f0013 sp : ee15bd28 ip : eebd8b1c fp : c093b488 r10: ee048000 r9 : eebdab18 r8 : ee048600 r7 : 00000001 r6 : 00000000 r5 : 00000000 r4 : ee82c100 r3 : 00000006 r2 : 00000001 r1 : c067e38c r0 : ee82c100 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none[ 297.318599] Control: 10c5387d Table: 2e3f0019 DAC: 00000051 Process bash (pid: 1005, stack limit = 0xee15a248) ... [] (hdmi_dai_probe) from [] (soc_probe_dai.part.9+0x34/0x70) [] (soc_probe_dai.part.9) from [] (snd_soc_instantiate_card+0x734/0xc9c) [] (snd_soc_instantiate_card) from [] (snd_soc_add_component+0x29c/0x378) [] (snd_soc_add_component) from [] (snd_soc_register_component+0x44/0x54) [] (snd_soc_register_component) from [] (devm_snd_soc_register_component+0x48/0x84) [] (devm_snd_soc_register_component) from [] (hdmi_codec_probe+0x150/0x260) [] (hdmi_codec_probe) from [] (platform_drv_probe+0x48/0x98) This happens because hdmi_dai_probe() attempts to access the HDMI codec private data, but this has not been assigned by hdmi_dai_probe() before it calls devm_snd_soc_register_component(). Move the call to dev_set_drvdata() before devm_snd_soc_register_component() to avoid this oops. Signed-off-by: Russell King Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/hdmi-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index d00734d31e04..e5b6769b9797 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -795,6 +795,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) if (hcd->spdif) hcp->daidrv[i] = hdmi_spdif_dai; + dev_set_drvdata(dev, hcp); + ret = devm_snd_soc_register_component(dev, &hdmi_driver, hcp->daidrv, dai_count); if (ret) { @@ -802,8 +804,6 @@ static int hdmi_codec_probe(struct platform_device *pdev) __func__, ret); return ret; } - - dev_set_drvdata(dev, hcp); return 0; } -- cgit v1.2.3-58-ga151 From 701956d4018e5d5438570e39e8bda47edd32c489 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Jan 2019 13:02:36 -0600 Subject: char/mwave: fix potential Spectre v1 vulnerability ipcnum is indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: drivers/char/mwave/mwavedd.c:299 mwave_ioctl() warn: potential spectre issue 'pDrvData->IPCs' [w] (local cap) Fix this by sanitizing ipcnum before using it to index pDrvData->IPCs. Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2 Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/char/mwave/mwavedd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index b5e3103c1175..e43c876a9223 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c @@ -59,6 +59,7 @@ #include #include #include +#include #include "smapi.h" #include "mwavedd.h" #include "3780i.h" @@ -289,6 +290,8 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, ipcnum); return -EINVAL; } + ipcnum = array_index_nospec(ipcnum, + ARRAY_SIZE(pDrvData->IPCs)); PRINTK_3(TRACE_MWAVE, "mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC" " ipcnum %x entry usIntCount %x\n", @@ -317,6 +320,8 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, " Invalid ipcnum %x\n", ipcnum); return -EINVAL; } + ipcnum = array_index_nospec(ipcnum, + ARRAY_SIZE(pDrvData->IPCs)); PRINTK_3(TRACE_MWAVE, "mwavedd::mwave_ioctl IOCTL_MW_GET_IPC" " ipcnum %x, usIntCount %x\n", @@ -383,6 +388,8 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd, ipcnum); return -EINVAL; } + ipcnum = array_index_nospec(ipcnum, + ARRAY_SIZE(pDrvData->IPCs)); mutex_lock(&mwave_mutex); if (pDrvData->IPCs[ipcnum].bIsEnabled == true) { pDrvData->IPCs[ipcnum].bIsEnabled = false; -- cgit v1.2.3-58-ga151 From d8e346eb30372233063236edeb7600b92c92b287 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Fri, 11 Jan 2019 13:25:25 +0100 Subject: misc: pvpanic: fix warning implicit declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building and have fragment CONFIG_NO_IOPORT_MAP enabled then the following warning: ../drivers/misc/pvpanic.c: In function ‘pvpanic_walk_resources’: ../drivers/misc/pvpanic.c:73:10: error: implicit declaration of function ‘ioport_map’; did you mean ‘ioremap’? [-Werror=implicit-function-declaration] base = ioport_map(r.start, resource_size(&r)); ^~~~~~~~~~ Since commmit 5d32a66541c4 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set"), its now possible to have ACPI enabled without haveing PCI enabled. However, the pvpanic driver depends on HAS_IOPORT_MAP or HAVE_IOREMAP_PROT when ACPI is enabled. It was fine until commit 725eba2928ad ("misc/pvpanic: add MMIO support") got added. Rework so that we do a extra check ifdef CONFIG_HAS_IOPORT_MAP. Fixes: 5d32a66541c4 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Suggested-by: Arnd Bergmann Signed-off-by: Anders Roxell Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/misc/pvpanic.c b/drivers/misc/pvpanic.c index 595ac065b401..95ff7c5a1dfb 100644 --- a/drivers/misc/pvpanic.c +++ b/drivers/misc/pvpanic.c @@ -70,8 +70,12 @@ pvpanic_walk_resources(struct acpi_resource *res, void *context) struct resource r; if (acpi_dev_resource_io(res, &r)) { +#ifdef CONFIG_HAS_IOPORT_MAP base = ioport_map(r.start, resource_size(&r)); return AE_OK; +#else + return AE_ERROR; +#endif } else if (acpi_dev_resource_memory(res, &r)) { base = ioremap(r.start, resource_size(&r)); return AE_OK; -- cgit v1.2.3-58-ga151 From 77b7aad195099e7c6da11e94b7fa6ef5e6fb0025 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Wed, 9 Jan 2019 15:02:23 +0100 Subject: Revert "btrfs: balance dirty metadata pages in btrfs_finish_ordered_io" This reverts commit e73e81b6d0114d4a303205a952ab2e87c44bd279. This patch causes a few problems: - adds latency to btrfs_finish_ordered_io - as btrfs_finish_ordered_io is used for free space cache, generating more work from btrfs_btree_balance_dirty_nodelay could end up in the same workque, effectively deadlocking 12260 kworker/u96:16+btrfs-freespace-write D [<0>] balance_dirty_pages+0x6e6/0x7ad [<0>] balance_dirty_pages_ratelimited+0x6bb/0xa90 [<0>] btrfs_finish_ordered_io+0x3da/0x770 [<0>] normal_work_helper+0x1c5/0x5a0 [<0>] process_one_work+0x1ee/0x5a0 [<0>] worker_thread+0x46/0x3d0 [<0>] kthread+0xf5/0x130 [<0>] ret_from_fork+0x24/0x30 [<0>] 0xffffffffffffffff Transaction commit will wait on the freespace cache: 838 btrfs-transacti D [<0>] btrfs_start_ordered_extent+0x154/0x1e0 [<0>] btrfs_wait_ordered_range+0xbd/0x110 [<0>] __btrfs_wait_cache_io+0x49/0x1a0 [<0>] btrfs_write_dirty_block_groups+0x10b/0x3b0 [<0>] commit_cowonly_roots+0x215/0x2b0 [<0>] btrfs_commit_transaction+0x37e/0x910 [<0>] transaction_kthread+0x14d/0x180 [<0>] kthread+0xf5/0x130 [<0>] ret_from_fork+0x24/0x30 [<0>] 0xffffffffffffffff And then writepages ends up waiting on transaction commit: 9520 kworker/u96:13+flush-btrfs-1 D [<0>] wait_current_trans+0xac/0xe0 [<0>] start_transaction+0x21b/0x4b0 [<0>] cow_file_range_inline+0x10b/0x6b0 [<0>] cow_file_range.isra.69+0x329/0x4a0 [<0>] run_delalloc_range+0x105/0x3c0 [<0>] writepage_delalloc+0x119/0x180 [<0>] __extent_writepage+0x10c/0x390 [<0>] extent_write_cache_pages+0x26f/0x3d0 [<0>] extent_writepages+0x4f/0x80 [<0>] do_writepages+0x17/0x60 [<0>] __writeback_single_inode+0x59/0x690 [<0>] writeback_sb_inodes+0x291/0x4e0 [<0>] __writeback_inodes_wb+0x87/0xb0 [<0>] wb_writeback+0x3bb/0x500 [<0>] wb_workfn+0x40d/0x610 [<0>] process_one_work+0x1ee/0x5a0 [<0>] worker_thread+0x1e0/0x3d0 [<0>] kthread+0xf5/0x130 [<0>] ret_from_fork+0x24/0x30 [<0>] 0xffffffffffffffff Eventually, we have every process in the system waiting on balance_dirty_pages(), and nobody is able to make progress on page writeback. The original patch tried to fix an OOM condition, that happened on 4.4 but no success reproducing that on later kernels (4.19 and 4.20). This is more likely a problem in OOM itself. Link: https://lore.kernel.org/linux-btrfs/20180528054821.9092-1-ethanlien@synology.com/ Reported-by: Chris Mason CC: stable@vger.kernel.org # 4.18+ CC: ethanlien Signed-off-by: David Sterba --- fs/btrfs/inode.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 43eb4535319d..b6025b5d0b25 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3129,9 +3129,6 @@ out: /* once for the tree */ btrfs_put_ordered_extent(ordered_extent); - /* Try to release some metadata so we don't get an OOM but don't wait */ - btrfs_btree_balance_dirty_nodelay(fs_info); - return ret; } -- cgit v1.2.3-58-ga151 From 31890da0bfdd24b135a258404b93c58a65510c7a Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 21 Nov 2018 14:05:41 -0500 Subject: btrfs: handle delayed ref head accounting cleanup in abort We weren't doing any of the accounting cleanup when we aborted transactions. Fix this by making cleanup_ref_head_accounting global and calling it from the abort code, this fixes the issue where our accounting was all wrong after the fs aborts. The test generic/475 on a 2G VM can trigger the problems eg.: [ 8502.136957] WARNING: CPU: 0 PID: 11064 at fs/btrfs/extent-tree.c:5986 btrfs_free_block_grou +ps+0x3dc/0x410 [btrfs] [ 8502.148372] CPU: 0 PID: 11064 Comm: umount Not tainted 5.0.0-rc1-default+ #394 [ 8502.150807] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.2-0-gf9626 +cc-prebuilt.qemu-project.org 04/01/2014 [ 8502.154317] RIP: 0010:btrfs_free_block_groups+0x3dc/0x410 [btrfs] [ 8502.160623] RSP: 0018:ffffb1ab84b93de8 EFLAGS: 00010206 [ 8502.161906] RAX: 0000000001000000 RBX: ffff9f34b1756400 RCX: 0000000000000000 [ 8502.163448] RDX: 0000000000000002 RSI: 0000000000000001 RDI: ffff9f34b1755400 [ 8502.164906] RBP: ffff9f34b7e8c000 R08: 0000000000000001 R09: 0000000000000000 [ 8502.166716] R10: 0000000000000000 R11: 0000000000000001 R12: ffff9f34b7e8c108 [ 8502.168498] R13: ffff9f34b7e8c158 R14: 0000000000000000 R15: dead000000000100 [ 8502.170296] FS: 00007fb1cf15ffc0(0000) GS:ffff9f34bd400000(0000) knlGS:0000000000000000 [ 8502.172439] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 8502.173669] CR2: 00007fb1ced507b0 CR3: 000000002f7a6000 CR4: 00000000000006f0 [ 8502.175094] Call Trace: [ 8502.175759] close_ctree+0x17f/0x350 [btrfs] [ 8502.176721] generic_shutdown_super+0x64/0x100 [ 8502.177702] kill_anon_super+0x14/0x30 [ 8502.178607] btrfs_kill_super+0x12/0xa0 [btrfs] [ 8502.179602] deactivate_locked_super+0x29/0x60 [ 8502.180595] cleanup_mnt+0x3b/0x70 [ 8502.181406] task_work_run+0x98/0xc0 [ 8502.182255] exit_to_usermode_loop+0x83/0x90 [ 8502.183113] do_syscall_64+0x15b/0x180 [ 8502.183919] entry_SYSCALL_64_after_hwframe+0x49/0xbe Corresponding to release_global_block_rsv() { ... WARN_ON(fs_info->delayed_refs_rsv.reserved > 0); CC: stable@vger.kernel.org Signed-off-by: Josef Bacik [ add log dump ] Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 4 ++++ fs/btrfs/disk-io.c | 1 + fs/btrfs/extent-tree.c | 12 +++++------- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f031a447a047..34019c8b6158 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -35,6 +35,7 @@ struct btrfs_trans_handle; struct btrfs_transaction; struct btrfs_pending_snapshot; +struct btrfs_delayed_ref_root; extern struct kmem_cache *btrfs_trans_handle_cachep; extern struct kmem_cache *btrfs_bit_radix_cachep; extern struct kmem_cache *btrfs_path_cachep; @@ -2664,6 +2665,9 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, unsigned long count); int btrfs_async_run_delayed_refs(struct btrfs_fs_info *fs_info, unsigned long count, u64 transid, int wait); +void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info, + struct btrfs_delayed_ref_root *delayed_refs, + struct btrfs_delayed_ref_head *head); int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len); int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 bytenr, diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 8da2f380d3c0..469a51b4b273 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -4265,6 +4265,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, if (pin_bytes) btrfs_pin_extent(fs_info, head->bytenr, head->num_bytes, 1); + btrfs_cleanup_ref_head_accounting(fs_info, delayed_refs, head); btrfs_put_delayed_ref_head(head); cond_resched(); spin_lock(&delayed_refs->lock); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index b15afeae16df..6f6fae410fc1 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2456,12 +2456,10 @@ static int run_and_cleanup_extent_op(struct btrfs_trans_handle *trans, return ret ? ret : 1; } -static void cleanup_ref_head_accounting(struct btrfs_trans_handle *trans, - struct btrfs_delayed_ref_head *head) +void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info, + struct btrfs_delayed_ref_root *delayed_refs, + struct btrfs_delayed_ref_head *head) { - struct btrfs_fs_info *fs_info = trans->fs_info; - struct btrfs_delayed_ref_root *delayed_refs = - &trans->transaction->delayed_refs; int nr_items = 1; /* Dropping this ref head update. */ if (head->total_ref_mod < 0) { @@ -2544,7 +2542,7 @@ static int cleanup_ref_head(struct btrfs_trans_handle *trans, } } - cleanup_ref_head_accounting(trans, head); + btrfs_cleanup_ref_head_accounting(fs_info, delayed_refs, head); trace_run_delayed_ref_head(fs_info, head, 0); btrfs_delayed_ref_unlock(head); @@ -7188,7 +7186,7 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans, if (head->must_insert_reserved) ret = 1; - cleanup_ref_head_accounting(trans, head); + btrfs_cleanup_ref_head_accounting(trans->fs_info, delayed_refs, head); mutex_unlock(&head->mutex); btrfs_put_delayed_ref_head(head); return ret; -- cgit v1.2.3-58-ga151 From 74d5d229b1bf60f93bff244b2dfc0eb21ec32a07 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 21 Nov 2018 14:05:45 -0500 Subject: btrfs: wait on ordered extents on abort cleanup If we flip read-only before we initiate writeback on all dirty pages for ordered extents we've created then we'll have ordered extents left over on umount, which results in all sorts of bad things happening. Fix this by making sure we wait on ordered extents if we have to do the aborted transaction cleanup stuff. generic/475 can produce this warning: [ 8531.177332] WARNING: CPU: 2 PID: 11997 at fs/btrfs/disk-io.c:3856 btrfs_free_fs_root+0x95/0xa0 [btrfs] [ 8531.183282] CPU: 2 PID: 11997 Comm: umount Tainted: G W 5.0.0-rc1-default+ #394 [ 8531.185164] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),BIOS rel-1.11.2-0-gf9626cc-prebuilt.qemu-project.org 04/01/2014 [ 8531.187851] RIP: 0010:btrfs_free_fs_root+0x95/0xa0 [btrfs] [ 8531.193082] RSP: 0018:ffffb1ab86163d98 EFLAGS: 00010286 [ 8531.194198] RAX: ffff9f3449494d18 RBX: ffff9f34a2695000 RCX:0000000000000000 [ 8531.195629] RDX: 0000000000000002 RSI: 0000000000000001 RDI:0000000000000000 [ 8531.197315] RBP: ffff9f344e930000 R08: 0000000000000001 R09:0000000000000000 [ 8531.199095] R10: 0000000000000000 R11: ffff9f34494d4ff8 R12:ffffb1ab86163dc0 [ 8531.200870] R13: ffff9f344e9300b0 R14: ffffb1ab86163db8 R15:0000000000000000 [ 8531.202707] FS: 00007fc68e949fc0(0000) GS:ffff9f34bd800000(0000)knlGS:0000000000000000 [ 8531.204851] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 8531.205942] CR2: 00007ffde8114dd8 CR3: 000000002dfbd000 CR4:00000000000006e0 [ 8531.207516] Call Trace: [ 8531.208175] btrfs_free_fs_roots+0xdb/0x170 [btrfs] [ 8531.210209] ? wait_for_completion+0x5b/0x190 [ 8531.211303] close_ctree+0x157/0x350 [btrfs] [ 8531.212412] generic_shutdown_super+0x64/0x100 [ 8531.213485] kill_anon_super+0x14/0x30 [ 8531.214430] btrfs_kill_super+0x12/0xa0 [btrfs] [ 8531.215539] deactivate_locked_super+0x29/0x60 [ 8531.216633] cleanup_mnt+0x3b/0x70 [ 8531.217497] task_work_run+0x98/0xc0 [ 8531.218397] exit_to_usermode_loop+0x83/0x90 [ 8531.219324] do_syscall_64+0x15b/0x180 [ 8531.220192] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 8531.221286] RIP: 0033:0x7fc68e5e4d07 [ 8531.225621] RSP: 002b:00007ffde8116608 EFLAGS: 00000246 ORIG_RAX:00000000000000a6 [ 8531.227512] RAX: 0000000000000000 RBX: 00005580c2175970 RCX:00007fc68e5e4d07 [ 8531.229098] RDX: 0000000000000001 RSI: 0000000000000000 RDI:00005580c2175b80 [ 8531.230730] RBP: 0000000000000000 R08: 00005580c2175ba0 R09:00007ffde8114e80 [ 8531.232269] R10: 0000000000000000 R11: 0000000000000246 R12:00005580c2175b80 [ 8531.233839] R13: 00007fc68eac61c4 R14: 00005580c2175a68 R15:0000000000000000 Leaving a tree in the rb-tree: 3853 void btrfs_free_fs_root(struct btrfs_root *root) 3854 { 3855 iput(root->ino_cache_inode); 3856 WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); CC: stable@vger.kernel.org Reviewed-by: Nikolay Borisov Signed-off-by: Josef Bacik [ add stacktrace ] Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 469a51b4b273..18eefc5b2532 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -4201,6 +4201,14 @@ static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info) spin_lock(&fs_info->ordered_root_lock); } spin_unlock(&fs_info->ordered_root_lock); + + /* + * We need this here because if we've been flipped read-only we won't + * get sync() from the umount, so we need to make sure any ordered + * extents that haven't had their dirty pages IO start writeout yet + * actually get run and error out properly. + */ + btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1); } static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, -- cgit v1.2.3-58-ga151 From 3ec9a4c81c8cc2a8d9673588dd84d9cc7c31019b Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 11 Jan 2019 10:21:01 -0500 Subject: btrfs: run delayed iputs before committing Delayed iputs means we can have final iputs of deleted inodes in the queue, which could potentially generate a lot of pinned space that could be free'd. So before we decide to commit the transaction for ENOPSC reasons, run the delayed iputs so that any potential space is free'd up. If there is and we freed enough we can then commit the transaction and potentially be able to make our reservation. Reviewed-by: Omar Sandoval Signed-off-by: Josef Bacik Signed-off-by: David Sterba --- fs/btrfs/extent-tree.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 6f6fae410fc1..d81035b7ea7d 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4952,6 +4952,15 @@ static void flush_space(struct btrfs_fs_info *fs_info, ret = 0; break; case COMMIT_TRANS: + /* + * If we have pending delayed iputs then we could free up a + * bunch of pinned space, so make sure we run the iputs before + * we do our pinned bytes check below. + */ + mutex_lock(&fs_info->cleaner_delayed_iput_mutex); + btrfs_run_delayed_iputs(fs_info); + mutex_unlock(&fs_info->cleaner_delayed_iput_mutex); + ret = may_commit_transaction(fs_info, space_info); break; default: -- cgit v1.2.3-58-ga151 From fd340d0f68cc87badfc9efcb226f23a5428826a0 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 11 Jan 2019 10:21:02 -0500 Subject: btrfs: wakeup cleaner thread when adding delayed iput The cleaner thread usually takes care of delayed iputs, with the exception of the btrfs_end_transaction_throttle path. Delaying iputs means we are potentially delaying the eviction of an inode and it's respective space. The cleaner thread only gets woken up every 30 seconds, or when we require space. If there are a lot of inodes that need to be deleted we could induce a serious amount of latency while we wait for these inodes to be evicted. So instead wakeup the cleaner if it's not already awake to process any new delayed iputs we add to the list. If we suddenly need space we will less likely be backed up behind a bunch of inodes that are waiting to be deleted, and we could possibly free space before we need to get into the flushing logic which will save us some latency. Reviewed-by: Filipe Manana Signed-off-by: Josef Bacik Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 3 +++ fs/btrfs/disk-io.c | 3 +++ fs/btrfs/inode.c | 2 ++ 3 files changed, 8 insertions(+) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 34019c8b6158..8b1d06fa222d 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -787,6 +787,9 @@ enum { * main phase. The fs_info::balance_ctl is initialized. */ BTRFS_FS_BALANCE_RUNNING, + + /* Indicate that the cleaner thread is awake and doing something. */ + BTRFS_FS_CLEANER_RUNNING, }; struct btrfs_fs_info { diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 18eefc5b2532..6a2a2a951705 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1682,6 +1682,8 @@ static int cleaner_kthread(void *arg) while (1) { again = 0; + set_bit(BTRFS_FS_CLEANER_RUNNING, &fs_info->flags); + /* Make the cleaner go to sleep early. */ if (btrfs_need_cleaner_sleep(fs_info)) goto sleep; @@ -1728,6 +1730,7 @@ static int cleaner_kthread(void *arg) */ btrfs_delete_unused_bgs(fs_info); sleep: + clear_bit(BTRFS_FS_CLEANER_RUNNING, &fs_info->flags); if (kthread_should_park()) kthread_parkme(); if (kthread_should_stop()) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b6025b5d0b25..5c349667c761 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3251,6 +3251,8 @@ void btrfs_add_delayed_iput(struct inode *inode) ASSERT(list_empty(&binode->delayed_iput)); list_add_tail(&binode->delayed_iput, &fs_info->delayed_iputs); spin_unlock(&fs_info->delayed_iput_lock); + if (!test_bit(BTRFS_FS_CLEANER_RUNNING, &fs_info->flags)) + wake_up_process(fs_info->cleaner_kthread); } void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info) -- cgit v1.2.3-58-ga151 From d9866572486802bc598a3e8576a5231378d190de Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:52 +0100 Subject: ASoC: imx-sgtl5000: put of nodes if finding codec fails Make sure to properly put the of node in case finding the codec fails. Fixes: 81e8e4926167 ("ASoC: fsl: add sgtl5000 clock support for imx-sgtl5000") Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-sgtl5000.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index c29200cf755a..594bde3b0ded 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -111,7 +111,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) codec_dev = of_find_i2c_device_by_node(codec_np); if (!codec_dev) { dev_err(&pdev->dev, "failed to find codec platform device\n"); - return -EPROBE_DEFER; + ret = -EPROBE_DEFER; + goto fail; } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); -- cgit v1.2.3-58-ga151 From 691beb02d9ff364000a8de4e74898600b9caee89 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:53 +0100 Subject: ASoC: imx-sgtl5000: lower log level for potential probe deferral cases Not finding the codec/SSI instance can be due to probe deferral. Do not print error messages in those cases. Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-sgtl5000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 594bde3b0ded..9790a2a8ec2d 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -104,13 +104,13 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) ssi_pdev = of_find_device_by_node(ssi_np); if (!ssi_pdev) { - dev_err(&pdev->dev, "failed to find SSI platform device\n"); + dev_dbg(&pdev->dev, "failed to find SSI platform device\n"); ret = -EPROBE_DEFER; goto fail; } codec_dev = of_find_i2c_device_by_node(codec_np); if (!codec_dev) { - dev_err(&pdev->dev, "failed to find codec platform device\n"); + dev_dbg(&pdev->dev, "failed to find codec platform device\n"); ret = -EPROBE_DEFER; goto fail; } -- cgit v1.2.3-58-ga151 From e379ee969ecbc807c5b233460c2a88b6ee06bde3 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:54 +0100 Subject: ASoC: imx-sgtl5000: don't print EPROBE_DEFER as error Probe deferral is to be expected during normal operation, so avoid printing an error when it is encountered. Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-sgtl5000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 9790a2a8ec2d..b6cb80480b60 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -157,7 +157,9 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); goto fail; } -- cgit v1.2.3-58-ga151 From 1aabff2508cbd184b0141f2d1b8712bacbb78cef Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:55 +0100 Subject: ASoC: fsl_spdif: don't print EPROBE_DEFER as error Probe deferral is to be expected during normal operation, so avoid printing an error when it is encountered. Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 740b90df44bb..a26686e7281c 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1320,7 +1320,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) } ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE); - if (ret) + if (ret && ret != -EPROBE_DEFER) dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); return ret; -- cgit v1.2.3-58-ga151 From 2363d85f4e04f7218efc66b6167a405cccbc8ff7 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:56 +0100 Subject: ASoC: imx-spdif: don't print EPROBE_DEFER as error Probe deferral is to be expected during normal operation, so avoid printing an error when it is encountered. Removing the goto would not be strictly necessary. However, if code gets added later, the cleanup in the EPROBE_DEFER case likely would get missed. Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/imx-spdif.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index fb896b2c9ba3..797d66e43d49 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c @@ -67,10 +67,8 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) goto end; ret = devm_snd_soc_register_card(&pdev->dev, &data->card); - if (ret) { + if (ret && ret != -EPROBE_DEFER) dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret); - goto end; - } end: of_node_put(spdif_np); -- cgit v1.2.3-58-ga151 From 7c7e2d6a9ca3c74ba7ed4da2a75916b2f9ae38f0 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:55:04 +0100 Subject: ASoC: soc-core: remove error due to probe deferral Deferred probes shouldn't cause error messages in the boot log, so change the dev_err() to the more harmless dev_info(). Signed-off-by: Stefan Agner Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0462b3ec977a..98bb05f6ed56 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -903,8 +903,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { - dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", - codecs[i].dai_name); + dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", + codecs[i].dai_name); goto _err_defer; } snd_soc_rtdcom_add(rtd, codec_dais[i]->component); -- cgit v1.2.3-58-ga151 From e412fcb0db5c44a3450ca678b281ea9332e6bf82 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 18 Jan 2019 14:26:46 +0000 Subject: ASoC: fsl_sai: Remove expensive print in irq handler When stopping audio, ASoC will first stop DMA then CPU DAI. Sometimes there is a delay between DMA stop and CPU DAI stop, which triggers an underrun error. Now, because of the delay introduced by dev_err another underrun error will occur causing a vicious circle making impossible to stop CPU DAI. Signed-off-by: Shengjiu Wang Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 4163f2cfc06f..db9e0872f73d 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -62,10 +62,10 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) dev_dbg(dev, "isr: Start of Tx word detected\n"); if (flags & FSL_SAI_CSR_SEF) - dev_warn(dev, "isr: Tx Frame sync error detected\n"); + dev_dbg(dev, "isr: Tx Frame sync error detected\n"); if (flags & FSL_SAI_CSR_FEF) { - dev_warn(dev, "isr: Transmit underrun detected\n"); + dev_dbg(dev, "isr: Transmit underrun detected\n"); /* FIFO reset for safety */ xcsr |= FSL_SAI_CSR_FR; } @@ -96,10 +96,10 @@ irq_rx: dev_dbg(dev, "isr: Start of Rx word detected\n"); if (flags & FSL_SAI_CSR_SEF) - dev_warn(dev, "isr: Rx Frame sync error detected\n"); + dev_dbg(dev, "isr: Rx Frame sync error detected\n"); if (flags & FSL_SAI_CSR_FEF) { - dev_warn(dev, "isr: Receive overflow detected\n"); + dev_dbg(dev, "isr: Receive overflow detected\n"); /* FIFO reset for safety */ xcsr |= FSL_SAI_CSR_FR; } -- cgit v1.2.3-58-ga151 From 0e78f389a7cdc6de7dfd0778733f3b140c981c9e Mon Sep 17 00:00:00 2001 From: Otto Sabart Date: Mon, 14 Jan 2019 12:56:36 +0100 Subject: doc: net: fix bad references to network drivers Fix "reference to nonexisting document" warnings. Fixes: b255e500c8dc ("net: documentation: build a directory structure for drivers") Signed-off-by: Otto Sabart Signed-off-by: David S. Miller --- Documentation/networking/index.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 6a47629ef8ed..59e86de662cd 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -11,19 +11,19 @@ Contents: batman-adv can can_ucan_protocol - dpaa2/index - e100 - e1000 - e1000e - fm10k - igb - igbvf - ixgb - ixgbe - ixgbevf - i40e - iavf - ice + device_drivers/freescale/dpaa2/index + device_drivers/intel/e100 + device_drivers/intel/e1000 + device_drivers/intel/e1000e + device_drivers/intel/fm10k + device_drivers/intel/igb + device_drivers/intel/igbvf + device_drivers/intel/ixgb + device_drivers/intel/ixgbe + device_drivers/intel/ixgbevf + device_drivers/intel/i40e + device_drivers/intel/iavf + device_drivers/intel/ice kapi z8530book msg_zerocopy -- cgit v1.2.3-58-ga151 From e40e2a2e78664fa90ea4b9bdf4a84efce2fea9d9 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 16 Jan 2019 10:53:58 +0100 Subject: net: phy: mdio_bus: add missing device_del() in mdiobus_register() error handling The current code in __mdiobus_register() doesn't properly handle failures returned by the devm_gpiod_get_optional() call: it returns immediately, without unregistering the device that was added by the call to device_register() earlier in the function. This leaves a stale device, which then causes a NULL pointer dereference in the code that handles deferred probing: [ 1.489982] Unable to handle kernel NULL pointer dereference at virtual address 00000074 [ 1.498110] pgd = (ptrval) [ 1.500838] [00000074] *pgd=00000000 [ 1.504432] Internal error: Oops: 17 [#1] SMP ARM [ 1.509133] Modules linked in: [ 1.512192] CPU: 1 PID: 51 Comm: kworker/1:3 Not tainted 4.20.0-00039-g3b73a4cc8b3e-dirty #99 [ 1.520708] Hardware name: Xilinx Zynq Platform [ 1.525261] Workqueue: events deferred_probe_work_func [ 1.530403] PC is at klist_next+0x10/0xfc [ 1.534403] LR is at device_for_each_child+0x40/0x94 [ 1.539361] pc : [] lr : [] psr: 200e0013 [ 1.545628] sp : ceeefe68 ip : 00000001 fp : ffffe000 [ 1.550863] r10: 00000000 r9 : c0c66790 r8 : 00000000 [ 1.556079] r7 : c0457d44 r6 : 00000000 r5 : ceeefe8c r4 : cfa2ec78 [ 1.562604] r3 : 00000064 r2 : c0457d44 r1 : ceeefe8c r0 : 00000064 [ 1.569129] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 1.576263] Control: 18c5387d Table: 0ed7804a DAC: 00000051 [ 1.582013] Process kworker/1:3 (pid: 51, stack limit = 0x(ptrval)) [ 1.588280] Stack: (0xceeefe68 to 0xceef0000) [ 1.592630] fe60: cfa2ec78 c0c03c08 00000000 c0457d44 00000000 c0c66790 [ 1.600814] fe80: 00000000 c0455d90 ceeefeac 00000064 00000000 0d7a542e cee9d494 cfa2ec78 [ 1.608998] fea0: cfa2ec78 00000000 c0457d44 c0457d7c cee9d494 c0c03c08 00000000 c0455dac [ 1.617182] fec0: cf98ba44 cf926a00 cee9d494 0d7a542e 00000000 cf935a10 cf935a10 cf935a10 [ 1.625366] fee0: c0c4e9b8 c0457d7c c0c4e80c 00000001 cf935a10 c0457df4 cf935a10 c0c4e99c [ 1.633550] ff00: c0c4e99c c045a27c c0c4e9c4 ced63f80 cfde8a80 cfdebc00 00000000 c013893c [ 1.641734] ff20: cfde8a80 cfde8a80 c07bd354 ced63f80 ced63f94 cfde8a80 00000008 c0c02d00 [ 1.649936] ff40: cfde8a98 cfde8a80 ffffe000 c0139a30 ffffe000 c0c6624a c07bd354 00000000 [ 1.658120] ff60: ffffe000 cee9e780 ceebfe00 00000000 ceeee000 ced63f80 c0139788 cf8cdea4 [ 1.666304] ff80: cee9e79c c013e598 00000001 ceebfe00 c013e44c 00000000 00000000 00000000 [ 1.674488] ffa0: 00000000 00000000 00000000 c01010e8 00000000 00000000 00000000 00000000 [ 1.682671] ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 1.690855] ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000 [ 1.699058] [] (klist_next) from [] (device_for_each_child+0x40/0x94) [ 1.707241] [] (device_for_each_child) from [] (device_reorder_to_tail+0x38/0x88) [ 1.716476] [] (device_reorder_to_tail) from [] (device_for_each_child+0x5c/0x94) [ 1.725692] [] (device_for_each_child) from [] (device_reorder_to_tail+0x38/0x88) [ 1.734927] [] (device_reorder_to_tail) from [] (device_pm_move_to_tail+0x28/0x40) [ 1.744235] [] (device_pm_move_to_tail) from [] (deferred_probe_work_func+0x58/0x8c) [ 1.753746] [] (deferred_probe_work_func) from [] (process_one_work+0x210/0x4fc) [ 1.762888] [] (process_one_work) from [] (worker_thread+0x2a8/0x5c0) [ 1.771072] [] (worker_thread) from [] (kthread+0x14c/0x154) [ 1.778482] [] (kthread) from [] (ret_from_fork+0x14/0x2c) [ 1.785689] Exception stack(0xceeeffb0 to 0xceeefff8) [ 1.790739] ffa0: 00000000 00000000 00000000 00000000 [ 1.798923] ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 1.807107] ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 [ 1.813724] Code: e92d47f0 e1a05000 e8900048 e1a00003 (e5937010) [ 1.819844] ---[ end trace 3c2c0c8b65399ec9 ]--- The actual error that we had from devm_gpiod_get_optional() was -EPROBE_DEFER, due to the GPIO being provided by a driver that is probed later than the Ethernet controller driver. To fix this, we simply add the missing device_del() invocation in the error path. Fixes: 69226896ad636 ("mdio_bus: Issue GPIO RESET to PHYs") Signed-off-by: Thomas Petazzoni Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 2e59a8419b17..66b9cfe692fc 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -390,6 +390,7 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner) if (IS_ERR(gpiod)) { dev_err(&bus->dev, "mii_bus %s couldn't get reset GPIO\n", bus->id); + device_del(&bus->dev); return PTR_ERR(gpiod); } else if (gpiod) { bus->reset_gpiod = gpiod; -- cgit v1.2.3-58-ga151 From 62bc79d35ebb55451112979babea864975cfd16d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 18 Jan 2019 11:20:41 +0900 Subject: ASoC: soc.h: add explanation of legacy/modern style of dai_link Current ALSA SoC is assuming 1 CPU 1 Platform (= DMA) style system. Because of this background, it is directly using xxx_name / xxx_of_node / xxx_dai_name on dai_link. Let's call it as legacy style here. More complex style system like multi CPU multi Platform (= DMA) will coming. To supporting it, we can use snd_soc_dai_link_component on dai_link. Let's call it as modern style here. But current ALSA SoC can't support it so far. Thus, we need to have multi CPU / multi Codec / multi Platform style in the future on ALSA SoC. Currently we already have multi Codec support. Platform is starting to use modern style on dai_link, but still style only. Multi Platform is not yet implemented. And we still don't have multi CPU support on ALSA SoC, and not have modern style either. Currently, if driver is using legacy style Codec/Platform, it will be converted to modern style on soc-core. This means, we are using glue code for legacy vs modern style so far on ALSA SoC. We can fully switch to modern style on all drivers if ALSA SoC supported modern style for CPU, and then, legacy style code will be removed from ALSA SoC. Untile then, we need to keep both legacy/modern style and its glue code. This patch adds such future plan and background on soc.h Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 36 ++++++++++++++++++++++++++++++++++++ sound/soc/soc-core.c | 20 ++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index e665f111b0d2..c31b6d122ff6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -891,6 +891,18 @@ struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ const char *stream_name; /* Stream name */ + + /* + * cpu_name + * cpu_of_node + * cpu_dai_name + * + * These are legacy style, and will be replaced to + * modern style (= snd_soc_dai_link_component) in the future, + * but, not yet supported so far. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MAY specify the link's CPU-side device, either by device name, * or by DT/OF node, but not both. If this information is omitted, @@ -906,6 +918,19 @@ struct snd_soc_dai_link { * only, which only works well when that device exposes a single DAI. */ const char *cpu_dai_name; + + /* + * codec_name + * codec_of_node + * codec_dai_name + * + * These are legacy style, it will be converted to modern style + * (= snd_soc_dai_link_component) automatically in soc-core + * if driver is using legacy style. + * Driver shouldn't use both legacy and modern style in the same time. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MUST specify the link's codec, either by device name, or by * DT/OF node, but not both. @@ -918,6 +943,17 @@ struct snd_soc_dai_link { struct snd_soc_dai_link_component *codecs; unsigned int num_codecs; + /* + * platform_name + * platform_of_node + * + * These are legacy style, it will be converted to modern style + * (= snd_soc_dai_link_component) automatically in soc-core + * if driver is using legacy style. + * Driver shouldn't use both legacy and modern style in the same time. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MAY specify the link's platform/PCM/DMA driver, either by * device name, or by DT/OF node, but not both. Some forms of link diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 890d6c9c2752..de2851f1b3df 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1029,9 +1029,14 @@ static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link_component *platform = dai_link->platform; /* - * FIXME + * REMOVE ME * - * this function should be removed in the future + * This is glue code for Legacy vs Modern dai_link. + * This function will be removed if all derivers are switched to + * modern style dai_link. + * Driver shouldn't use both legacy and modern style in the same time. + * see + * soc.h :: struct snd_soc_dai_link */ /* convert Legacy platform link */ if (!platform || dai_link->legacy_platform) { @@ -1059,6 +1064,17 @@ static int snd_soc_init_platform(struct snd_soc_card *card, static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { + /* + * REMOVE ME + * + * This is glue code for Legacy vs Modern dai_link. + * This function will be removed if all derivers are switched to + * modern style dai_link. + * Driver shouldn't use both legacy and modern style in the same time. + * see + * soc.h :: struct snd_soc_dai_link + */ + /* Legacy codec/codec_dai link is a single entry in multicodec */ if (dai_link->codec_name || dai_link->codec_of_node || dai_link->codec_dai_name) { -- cgit v1.2.3-58-ga151 From 6c57f0458022298e4da1729c67bd33ce41c14e7a Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Thu, 17 Jan 2019 15:34:38 +0000 Subject: net: Fix usage of pskb_trim_rcsum In certain cases, pskb_trim_rcsum() may change skb pointers. Reinitialize header pointers afterwards to avoid potential use-after-frees. Add a note in the documentation of pskb_trim_rcsum(). Found by KASAN. Signed-off-by: Ross Lagerwall Signed-off-by: David S. Miller --- drivers/net/ppp/pppoe.c | 1 + include/linux/skbuff.h | 1 + net/bridge/br_netfilter_ipv6.c | 1 + net/bridge/netfilter/nft_reject_bridge.c | 1 + net/ipv4/ip_input.c | 1 + 5 files changed, 5 insertions(+) diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 62dc564b251d..f22639f0116a 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -445,6 +445,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, if (pskb_trim_rcsum(skb, len)) goto drop; + ph = pppoe_hdr(skb); pn = pppoe_pernet(dev_net(dev)); /* Note that get_item does a sock_hold(), so sk_pppox(po) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 93f56fddd92a..95d25b010a25 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3218,6 +3218,7 @@ int pskb_trim_rcsum_slow(struct sk_buff *skb, unsigned int len); * * This is exactly the same as pskb_trim except that it ensures the * checksum of received packets are still valid after the operation. + * It can change skb pointers. */ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) diff --git a/net/bridge/br_netfilter_ipv6.c b/net/bridge/br_netfilter_ipv6.c index 94039f588f1d..564710f88f93 100644 --- a/net/bridge/br_netfilter_ipv6.c +++ b/net/bridge/br_netfilter_ipv6.c @@ -131,6 +131,7 @@ int br_validate_ipv6(struct net *net, struct sk_buff *skb) IPSTATS_MIB_INDISCARDS); goto drop; } + hdr = ipv6_hdr(skb); } if (hdr->nexthdr == NEXTHDR_HOP && br_nf_check_hbh_len(skb)) goto drop; diff --git a/net/bridge/netfilter/nft_reject_bridge.c b/net/bridge/netfilter/nft_reject_bridge.c index 08cbed7d940e..419e8edf23ba 100644 --- a/net/bridge/netfilter/nft_reject_bridge.c +++ b/net/bridge/netfilter/nft_reject_bridge.c @@ -229,6 +229,7 @@ static bool reject6_br_csum_ok(struct sk_buff *skb, int hook) pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h))) return false; + ip6h = ipv6_hdr(skb); thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) return false; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 26921f6b3b92..51d8efba6de2 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -488,6 +488,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) goto drop; } + iph = ip_hdr(skb); skb->transport_header = skb->network_header + iph->ihl*4; /* Remove any debris in the socket control block */ -- cgit v1.2.3-58-ga151 From 9437b629518866274d324122066a86ac6500c6b5 Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Thu, 17 Jan 2019 18:02:18 +0100 Subject: net: Fix typo in NET_FAILOVER help text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "also enables" should not be spelled as one word. Fixes: cfc80d9a1163 ("net: Introduce net_failover driver") Signed-off-by: Jonathan Neuschäfer Signed-off-by: David S. Miller --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6371958dd170..edb1c023a753 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -519,7 +519,7 @@ config NET_FAILOVER and destroy a failover master netdev and manages a primary and standby slave netdevs that get registered via the generic failover infrastructure. This can be used by paravirtual drivers to enable - an alternate low latency datapath. It alsoenables live migration of + an alternate low latency datapath. It also enables live migration of a VM with direct attached VF by failing over to the paravirtual datapath when the VF is unplugged. -- cgit v1.2.3-58-ga151 From 20f5248a502b6d41746c02c699ec9791a03a4e27 Mon Sep 17 00:00:00 2001 From: Felix Manlunas Date: Thu, 17 Jan 2019 18:07:45 +0000 Subject: MAINTAINERS: update email addresses of liquidio driver maintainers Update email addresses of liquidio driver maintainers. Also remove a former maintainer. Signed-off-by: Felix Manlunas Acked-by: Derek Chickles Signed-off-by: David S. Miller --- MAINTAINERS | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 4d04cebb4a71..51029a425dbe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3471,10 +3471,9 @@ F: drivers/i2c/busses/i2c-octeon* F: drivers/i2c/busses/i2c-thunderx* CAVIUM LIQUIDIO NETWORK DRIVER -M: Derek Chickles -M: Satanand Burla -M: Felix Manlunas -M: Raghu Vatsavayi +M: Derek Chickles +M: Satanand Burla +M: Felix Manlunas L: netdev@vger.kernel.org W: http://www.cavium.com S: Supported -- cgit v1.2.3-58-ga151 From c9ebea04cb1b0a84d08de00f4800f726ca544ad2 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 18 Jan 2019 15:57:55 +0000 Subject: mlxsw: pci: Ring CQ's doorbell before RDQ's When a packet should be trapped to the CPU the device consumes a WQE (work queue element) from an RDQ (receive descriptor queue) and copies the packet to the address specified in the WQE. The device then tries to post a CQE (completion queue element) that contains various metadata (e.g., ingress port) about the packet to a CQ (completion queue). In case the device managed to consume a WQE, but did not manage to post the corresponding CQE, it will get stuck. This unlikely situation can be triggered due to the scheme the driver is currently using to process CQEs. The driver will consume up to 512 CQEs at a time and after processing each corresponding WQE it will ring the RDQ's doorbell, letting the device know that a new WQE was posted for it to consume. Only after processing all the CQEs (up to 512), the driver will ring the CQ's doorbell, letting the device know that new ones can be posted. Fix this by having the driver ring the CQ's doorbell for every processed CQE, but before ringing the RDQ's doorbell. This guarantees that whenever we post a new WQE, there is a corresponding CQE available. Copy the currently processed CQE to prevent the device from overwriting it with a new CQE after ringing the doorbell. Note that the driver still arms the CQ only after processing all the pending CQEs, so that interrupts for this CQ will only be delivered after the driver finished its processing. Before commit 8404f6f2e8ed ("mlxsw: pci: Allow to use CQEs of version 1 and version 2") the issue was virtually impossible to trigger since the number of CQEs was twice the number of WQEs and the number of CQEs processed at a time was equal to the number of available WQEs. Fixes: 8404f6f2e8ed ("mlxsw: pci: Allow to use CQEs of version 1 and version 2") Signed-off-by: Ido Schimmel Reported-by: Semion Lisyansky Tested-by: Semion Lisyansky Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 12 +++++++----- drivers/net/ethernet/mellanox/mlxsw/pci_hw.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 66b8098c6fd2..91bf294f7677 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -604,29 +604,31 @@ static void mlxsw_pci_cq_tasklet(unsigned long data) u16 wqe_counter = mlxsw_pci_cqe_wqe_counter_get(cqe); u8 sendq = mlxsw_pci_cqe_sr_get(q->u.cq.v, cqe); u8 dqn = mlxsw_pci_cqe_dqn_get(q->u.cq.v, cqe); + char ncqe[MLXSW_PCI_CQE_SIZE_MAX]; + + memcpy(ncqe, cqe, q->elem_size); + mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); if (sendq) { struct mlxsw_pci_queue *sdq; sdq = mlxsw_pci_sdq_get(mlxsw_pci, dqn); mlxsw_pci_cqe_sdq_handle(mlxsw_pci, sdq, - wqe_counter, cqe); + wqe_counter, ncqe); q->u.cq.comp_sdq_count++; } else { struct mlxsw_pci_queue *rdq; rdq = mlxsw_pci_rdq_get(mlxsw_pci, dqn); mlxsw_pci_cqe_rdq_handle(mlxsw_pci, rdq, - wqe_counter, q->u.cq.v, cqe); + wqe_counter, q->u.cq.v, ncqe); q->u.cq.comp_rdq_count++; } if (++items == credits) break; } - if (items) { - mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); + if (items) mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); - } } static u16 mlxsw_pci_cq_elem_count(const struct mlxsw_pci_queue *q) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index bb99f6d41fe0..4265dd394f27 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -53,6 +53,7 @@ #define MLXSW_PCI_WQE_SIZE 32 /* 32 bytes per element */ #define MLXSW_PCI_CQE01_SIZE 16 /* 16 bytes per element */ #define MLXSW_PCI_CQE2_SIZE 32 /* 32 bytes per element */ +#define MLXSW_PCI_CQE_SIZE_MAX MLXSW_PCI_CQE2_SIZE #define MLXSW_PCI_EQE_SIZE 16 /* 16 bytes per element */ #define MLXSW_PCI_WQE_COUNT (MLXSW_PCI_AQ_SIZE / MLXSW_PCI_WQE_SIZE) #define MLXSW_PCI_CQE01_COUNT (MLXSW_PCI_AQ_SIZE / MLXSW_PCI_CQE01_SIZE) -- cgit v1.2.3-58-ga151 From d2f372ba0914e5722ac28e15f2ed2db61bcf0e44 Mon Sep 17 00:00:00 2001 From: Nir Dotan Date: Fri, 18 Jan 2019 15:57:56 +0000 Subject: mlxsw: pci: Increase PCI SW reset timeout Spectrum-2 PHY layer introduces a calibration period which is a part of the Spectrum-2 firmware boot process. Hence increase the SW timeout waiting for the firmware to come out of boot. This does not increase system boot time in cases where the firmware PHY calibration process is done quickly. Fixes: c3ab435466d5 ("mlxsw: spectrum: Extend to support Spectrum-2 ASIC") Signed-off-by: Nir Dotan Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci_hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index 4265dd394f27..ffee38e36ce8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -27,7 +27,7 @@ #define MLXSW_PCI_SW_RESET 0xF0010 #define MLXSW_PCI_SW_RESET_RST_BIT BIT(0) -#define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 5000 +#define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 13000 #define MLXSW_PCI_SW_RESET_WAIT_MSECS 100 #define MLXSW_PCI_FW_READY 0xA1844 #define MLXSW_PCI_FW_READY_MASK 0xFFFF -- cgit v1.2.3-58-ga151 From 67c14cc9b35055264fc0efed00159a7de1819f1b Mon Sep 17 00:00:00 2001 From: Nir Dotan Date: Fri, 18 Jan 2019 15:57:57 +0000 Subject: mlxsw: pci: Return error on PCI reset timeout Return an appropriate error in the case when the driver timeouts on waiting for firmware to go out of PCI reset. Fixes: 233fa44bd67a ("mlxsw: pci: Implement reset done check") Signed-off-by: Nir Dotan Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 91bf294f7677..a2321fe8d6a0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1367,10 +1367,10 @@ static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci, u32 val = mlxsw_pci_read32(mlxsw_pci, FW_READY); if ((val & MLXSW_PCI_FW_READY_MASK) == MLXSW_PCI_FW_READY_MAGIC) - break; + return 0; cond_resched(); } while (time_before(jiffies, end)); - return 0; + return -EBUSY; } static int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci) -- cgit v1.2.3-58-ga151 From a11dcd6497915ba79d95ef4fe2541aaac27f6201 Mon Sep 17 00:00:00 2001 From: Nir Dotan Date: Fri, 18 Jan 2019 15:57:59 +0000 Subject: mlxsw: spectrum_fid: Update dummy FID index When using a tc flower action of egress mirred redirect, the driver adds an implicit FID setting action. This implicit action sets a dummy FID to the packet and is used as part of a design for trapping unmatched flows in OVS. While this implicit FID setting action is supposed to be a NOP when a redirect action is added, in Spectrum-2 the FID record is consulted as the dummy FID index is an 802.1D FID index and the packet is dropped instead of being redirected. Set the dummy FID index value to be within 802.1Q range. This satisfies both Spectrum-1 which ignores the FID and Spectrum-2 which identifies it as an 802.1Q FID and will then follow the redirect action. Fixes: c3ab435466d5 ("mlxsw: spectrum: Extend to support Spectrum-2 ASIC") Signed-off-by: Nir Dotan Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c index 055cc6943b34..9d9aa28684af 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -997,8 +997,8 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = { .type = MLXSW_SP_FID_TYPE_DUMMY, .fid_size = sizeof(struct mlxsw_sp_fid), - .start_index = MLXSW_SP_RFID_BASE - 1, - .end_index = MLXSW_SP_RFID_BASE - 1, + .start_index = VLAN_N_VID - 1, + .end_index = VLAN_N_VID - 1, .ops = &mlxsw_sp_fid_dummy_ops, }; -- cgit v1.2.3-58-ga151 From 710ae72877378e7cde611efd30fe90502a6e5b30 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 18 Jan 2019 15:58:00 +0000 Subject: net: bridge: Mark FDB entries that were added by user as such Externally learned entries can be added by a user or by a switch driver that is notifying the bridge driver about entries that were learned in hardware. In the first case, the entries are not marked with the 'added_by_user' flag, which causes switch drivers to ignore them and not offload them. The 'added_by_user' flag can be set on externally learned FDB entries based on the 'swdev_notify' parameter in br_fdb_external_learn_add(), which effectively means if the created / updated FDB entry was added by a user or not. Fixes: 816a3bed9549 ("switchdev: Add fdb.added_by_user to switchdev notifications") Signed-off-by: Ido Schimmel Reported-by: Alexander Petrovskiy Reviewed-by: Petr Machata Cc: Roopa Prabhu Cc: Nikolay Aleksandrov Cc: bridge@lists.linux-foundation.org Signed-off-by: David S. Miller --- net/bridge/br_fdb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index fe3c758791ca..9e14767500ea 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -1128,6 +1128,8 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, err = -ENOMEM; goto err_unlock; } + if (swdev_notify) + fdb->added_by_user = 1; fdb->added_by_external_learn = 1; fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); } else { @@ -1147,6 +1149,9 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, modified = true; } + if (swdev_notify) + fdb->added_by_user = 1; + if (modified) fdb_notify(br, fdb, RTM_NEWNEIGH, swdev_notify); } -- cgit v1.2.3-58-ga151 From 64254a2054611205798e6bde634639bc704573ac Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 18 Jan 2019 15:58:01 +0000 Subject: mlxsw: spectrum_switchdev: Do not treat static FDB entries as sticky The driver currently treats static FDB entries as both static and sticky. This is incorrect and prevents such entries from being roamed to a different port via learning. Fix this by configuring static entries with ageing disabled and roaming enabled. In net-next we can add proper support for the newly introduced 'sticky' flag. Fixes: 56ade8fe3fe1 ("mlxsw: spectrum: Add initial support for Spectrum ASIC") Signed-off-by: Ido Schimmel Reported-by: Alexander Petrovskiy Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 0abbaa0fbf14..c772109b638d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1233,7 +1233,7 @@ mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp, static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic) { return dynamic ? MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_INGRESS : - MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY; + MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_MLAG; } static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding) @@ -1290,7 +1290,7 @@ out: static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, const char *mac, u16 fid, bool adding, enum mlxsw_reg_sfd_rec_action action, - bool dynamic) + enum mlxsw_reg_sfd_rec_policy policy) { char *sfd_pl; u8 num_rec; @@ -1301,8 +1301,7 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, return -ENOMEM; mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); - mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), - mac, fid, action, local_port); + mlxsw_reg_sfd_uc_pack(sfd_pl, 0, policy, mac, fid, action, local_port); num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); if (err) @@ -1321,7 +1320,8 @@ static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, bool dynamic) { return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding, - MLXSW_REG_SFD_REC_ACTION_NOP, dynamic); + MLXSW_REG_SFD_REC_ACTION_NOP, + mlxsw_sp_sfd_rec_policy(dynamic)); } int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, @@ -1329,7 +1329,7 @@ int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, { return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, 0, mac, fid, adding, MLXSW_REG_SFD_REC_ACTION_FORWARD_IP_ROUTER, - false); + MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY); } static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, -- cgit v1.2.3-58-ga151 From 72159272fc08230a76791dd5d0a0019ede1b802c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 18 Jan 2019 15:58:02 +0000 Subject: selftests: mlxsw: Test FDB offload indication Test that externally learned FDB entries added from user space are marked as offloaded. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../testing/selftests/drivers/net/mlxsw/rtnetlink.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/rtnetlink.sh b/tools/testing/selftests/drivers/net/mlxsw/rtnetlink.sh index 94fdbf215c14..c4cf6e6d800e 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/rtnetlink.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/rtnetlink.sh @@ -25,6 +25,7 @@ ALL_TESTS=" lag_unlink_slaves_test lag_dev_deletion_test vlan_interface_uppers_test + bridge_extern_learn_test devlink_reload_test " NUM_NETIFS=2 @@ -541,6 +542,25 @@ vlan_interface_uppers_test() ip link del dev br0 } +bridge_extern_learn_test() +{ + # Test that externally learned entries added from user space are + # marked as offloaded + RET=0 + + ip link add name br0 type bridge + ip link set dev $swp1 master br0 + + bridge fdb add de:ad:be:ef:13:37 dev $swp1 master extern_learn + + bridge fdb show brport $swp1 | grep de:ad:be:ef:13:37 | grep -q offload + check_err $? "fdb entry not marked as offloaded when should" + + log_test "externally learned fdb entry" + + ip link del dev br0 +} + devlink_reload_test() { # Test that after executing all the above configuration tests, a -- cgit v1.2.3-58-ga151 From 479a2b761d61c04e2ae97325aa391a8a8c99c23e Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 18 Jan 2019 15:58:03 +0000 Subject: selftests: forwarding: Add a test case for externally learned FDB entries Test that externally learned FDB entries can roam, but not age out. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../selftests/net/forwarding/bridge_vlan_aware.sh | 34 +++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh index 04c6431b2bd8..b90dff8d3a94 100755 --- a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -1,7 +1,7 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 -ALL_TESTS="ping_ipv4 ping_ipv6 learning flooding vlan_deletion" +ALL_TESTS="ping_ipv4 ping_ipv6 learning flooding vlan_deletion extern_learn" NUM_NETIFS=4 CHECK_TC="yes" source lib.sh @@ -109,6 +109,38 @@ vlan_deletion() ping_ipv6 } +extern_learn() +{ + local mac=de:ad:be:ef:13:37 + local ageing_time + + # Test that externally learned FDB entries can roam, but not age out + RET=0 + + bridge fdb add de:ad:be:ef:13:37 dev $swp1 master extern_learn vlan 1 + + bridge fdb show brport $swp1 | grep -q de:ad:be:ef:13:37 + check_err $? "Did not find FDB entry when should" + + # Wait for 10 seconds after the ageing time to make sure the FDB entry + # was not aged out + ageing_time=$(bridge_ageing_time_get br0) + sleep $((ageing_time + 10)) + + bridge fdb show brport $swp1 | grep -q de:ad:be:ef:13:37 + check_err $? "FDB entry was aged out when should not" + + $MZ $h2 -c 1 -p 64 -a $mac -t ip -q + + bridge fdb show brport $swp2 | grep -q de:ad:be:ef:13:37 + check_err $? "FDB entry did not roam when should" + + log_test "Externally learned FDB entry - ageing & roaming" + + bridge fdb del de:ad:be:ef:13:37 dev $swp2 master vlan 1 &> /dev/null + bridge fdb del de:ad:be:ef:13:37 dev $swp1 master vlan 1 &> /dev/null +} + trap cleanup EXIT setup_prepare -- cgit v1.2.3-58-ga151 From ad6dd7a9c47ba587c0aba57f73737764cd31136f Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 17 Jan 2019 16:15:09 +0100 Subject: bpf: pull in pkt_sched.h header for tooling to fix bpftool build Dan reported that bpftool does not compile for him: $ make tools/bpf DESCEND bpf Auto-detecting system features: .. libbfd: [ on ] .. disassembler-four-args: [ OFF ] DESCEND bpftool Auto-detecting system features: .. libbfd: [ on ] .. disassembler-four-args: [ OFF ] CC /opt/linux.git/tools/bpf/bpftool/net.o In file included from /opt/linux.git/tools/include/uapi/linux/pkt_cls.h:6:0, from /opt/linux.git/tools/include/uapi/linux/tc_act/tc_bpf.h:14, from net.c:13: net.c: In function 'show_dev_tc_bpf': net.c:164:21: error: 'TC_H_CLSACT' undeclared (first use in this function) handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); [...] Fix it by importing pkt_sched.h header copy into tooling infrastructure. Fixes: 49a249c38726 ("tools/bpftool: copy a few net uapi headers to tools directory") Fixes: f6f3bac08ff9 ("tools/bpf: bpftool: add net support") Reported-by: Dan Gilson Reference: https://bugzilla.kernel.org/show_bug.cgi?id=202315 Signed-off-by: Daniel Borkmann Acked-by: Martin KaFai Lau Signed-off-by: Alexei Starovoitov --- tools/include/uapi/linux/pkt_sched.h | 1163 ++++++++++++++++++++++++++++++++++ 1 file changed, 1163 insertions(+) create mode 100644 tools/include/uapi/linux/pkt_sched.h diff --git a/tools/include/uapi/linux/pkt_sched.h b/tools/include/uapi/linux/pkt_sched.h new file mode 100644 index 000000000000..0d18b1d1fbbc --- /dev/null +++ b/tools/include/uapi/linux/pkt_sched.h @@ -0,0 +1,1163 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_PKT_SCHED_H +#define __LINUX_PKT_SCHED_H + +#include + +/* Logical priority bands not depending on specific packet scheduler. + Every scheduler will map them to real traffic classes, if it has + no more precise mechanism to classify packets. + + These numbers have no special meaning, though their coincidence + with obsolete IPv6 values is not occasional :-). New IPv6 drafts + preferred full anarchy inspired by diffserv group. + + Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy + class, actually, as rule it will be handled with more care than + filler or even bulk. + */ + +#define TC_PRIO_BESTEFFORT 0 +#define TC_PRIO_FILLER 1 +#define TC_PRIO_BULK 2 +#define TC_PRIO_INTERACTIVE_BULK 4 +#define TC_PRIO_INTERACTIVE 6 +#define TC_PRIO_CONTROL 7 + +#define TC_PRIO_MAX 15 + +/* Generic queue statistics, available for all the elements. + Particular schedulers may have also their private records. + */ + +struct tc_stats { + __u64 bytes; /* Number of enqueued bytes */ + __u32 packets; /* Number of enqueued packets */ + __u32 drops; /* Packets dropped because of lack of resources */ + __u32 overlimits; /* Number of throttle events when this + * flow goes out of allocated bandwidth */ + __u32 bps; /* Current flow byte rate */ + __u32 pps; /* Current flow packet rate */ + __u32 qlen; + __u32 backlog; +}; + +struct tc_estimator { + signed char interval; + unsigned char ewma_log; +}; + +/* "Handles" + --------- + + All the traffic control objects have 32bit identifiers, or "handles". + + They can be considered as opaque numbers from user API viewpoint, + but actually they always consist of two fields: major and + minor numbers, which are interpreted by kernel specially, + that may be used by applications, though not recommended. + + F.e. qdisc handles always have minor number equal to zero, + classes (or flows) have major equal to parent qdisc major, and + minor uniquely identifying class inside qdisc. + + Macros to manipulate handles: + */ + +#define TC_H_MAJ_MASK (0xFFFF0000U) +#define TC_H_MIN_MASK (0x0000FFFFU) +#define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK) +#define TC_H_MIN(h) ((h)&TC_H_MIN_MASK) +#define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK)) + +#define TC_H_UNSPEC (0U) +#define TC_H_ROOT (0xFFFFFFFFU) +#define TC_H_INGRESS (0xFFFFFFF1U) +#define TC_H_CLSACT TC_H_INGRESS + +#define TC_H_MIN_PRIORITY 0xFFE0U +#define TC_H_MIN_INGRESS 0xFFF2U +#define TC_H_MIN_EGRESS 0xFFF3U + +/* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */ +enum tc_link_layer { + TC_LINKLAYER_UNAWARE, /* Indicate unaware old iproute2 util */ + TC_LINKLAYER_ETHERNET, + TC_LINKLAYER_ATM, +}; +#define TC_LINKLAYER_MASK 0x0F /* limit use to lower 4 bits */ + +struct tc_ratespec { + unsigned char cell_log; + __u8 linklayer; /* lower 4 bits */ + unsigned short overhead; + short cell_align; + unsigned short mpu; + __u32 rate; +}; + +#define TC_RTAB_SIZE 1024 + +struct tc_sizespec { + unsigned char cell_log; + unsigned char size_log; + short cell_align; + int overhead; + unsigned int linklayer; + unsigned int mpu; + unsigned int mtu; + unsigned int tsize; +}; + +enum { + TCA_STAB_UNSPEC, + TCA_STAB_BASE, + TCA_STAB_DATA, + __TCA_STAB_MAX +}; + +#define TCA_STAB_MAX (__TCA_STAB_MAX - 1) + +/* FIFO section */ + +struct tc_fifo_qopt { + __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */ +}; + +/* SKBPRIO section */ + +/* + * Priorities go from zero to (SKBPRIO_MAX_PRIORITY - 1). + * SKBPRIO_MAX_PRIORITY should be at least 64 in order for skbprio to be able + * to map one to one the DS field of IPV4 and IPV6 headers. + * Memory allocation grows linearly with SKBPRIO_MAX_PRIORITY. + */ + +#define SKBPRIO_MAX_PRIORITY 64 + +struct tc_skbprio_qopt { + __u32 limit; /* Queue length in packets. */ +}; + +/* PRIO section */ + +#define TCQ_PRIO_BANDS 16 +#define TCQ_MIN_PRIO_BANDS 2 + +struct tc_prio_qopt { + int bands; /* Number of bands */ + __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ +}; + +/* MULTIQ section */ + +struct tc_multiq_qopt { + __u16 bands; /* Number of bands */ + __u16 max_bands; /* Maximum number of queues */ +}; + +/* PLUG section */ + +#define TCQ_PLUG_BUFFER 0 +#define TCQ_PLUG_RELEASE_ONE 1 +#define TCQ_PLUG_RELEASE_INDEFINITE 2 +#define TCQ_PLUG_LIMIT 3 + +struct tc_plug_qopt { + /* TCQ_PLUG_BUFFER: Inset a plug into the queue and + * buffer any incoming packets + * TCQ_PLUG_RELEASE_ONE: Dequeue packets from queue head + * to beginning of the next plug. + * TCQ_PLUG_RELEASE_INDEFINITE: Dequeue all packets from queue. + * Stop buffering packets until the next TCQ_PLUG_BUFFER + * command is received (just act as a pass-thru queue). + * TCQ_PLUG_LIMIT: Increase/decrease queue size + */ + int action; + __u32 limit; +}; + +/* TBF section */ + +struct tc_tbf_qopt { + struct tc_ratespec rate; + struct tc_ratespec peakrate; + __u32 limit; + __u32 buffer; + __u32 mtu; +}; + +enum { + TCA_TBF_UNSPEC, + TCA_TBF_PARMS, + TCA_TBF_RTAB, + TCA_TBF_PTAB, + TCA_TBF_RATE64, + TCA_TBF_PRATE64, + TCA_TBF_BURST, + TCA_TBF_PBURST, + TCA_TBF_PAD, + __TCA_TBF_MAX, +}; + +#define TCA_TBF_MAX (__TCA_TBF_MAX - 1) + + +/* TEQL section */ + +/* TEQL does not require any parameters */ + +/* SFQ section */ + +struct tc_sfq_qopt { + unsigned quantum; /* Bytes per round allocated to flow */ + int perturb_period; /* Period of hash perturbation */ + __u32 limit; /* Maximal packets in queue */ + unsigned divisor; /* Hash divisor */ + unsigned flows; /* Maximal number of flows */ +}; + +struct tc_sfqred_stats { + __u32 prob_drop; /* Early drops, below max threshold */ + __u32 forced_drop; /* Early drops, after max threshold */ + __u32 prob_mark; /* Marked packets, below max threshold */ + __u32 forced_mark; /* Marked packets, after max threshold */ + __u32 prob_mark_head; /* Marked packets, below max threshold */ + __u32 forced_mark_head;/* Marked packets, after max threshold */ +}; + +struct tc_sfq_qopt_v1 { + struct tc_sfq_qopt v0; + unsigned int depth; /* max number of packets per flow */ + unsigned int headdrop; +/* SFQRED parameters */ + __u32 limit; /* HARD maximal flow queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + unsigned char Wlog; /* log(W) */ + unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ + unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; + __u32 max_P; /* probability, high resolution */ +/* SFQRED stats */ + struct tc_sfqred_stats stats; +}; + + +struct tc_sfq_xstats { + __s32 allot; +}; + +/* RED section */ + +enum { + TCA_RED_UNSPEC, + TCA_RED_PARMS, + TCA_RED_STAB, + TCA_RED_MAX_P, + __TCA_RED_MAX, +}; + +#define TCA_RED_MAX (__TCA_RED_MAX - 1) + +struct tc_red_qopt { + __u32 limit; /* HARD maximal queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + unsigned char Wlog; /* log(W) */ + unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ + unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; +#define TC_RED_ECN 1 +#define TC_RED_HARDDROP 2 +#define TC_RED_ADAPTATIVE 4 +}; + +struct tc_red_xstats { + __u32 early; /* Early drops */ + __u32 pdrop; /* Drops due to queue limits */ + __u32 other; /* Drops due to drop() calls */ + __u32 marked; /* Marked packets */ +}; + +/* GRED section */ + +#define MAX_DPs 16 + +enum { + TCA_GRED_UNSPEC, + TCA_GRED_PARMS, + TCA_GRED_STAB, + TCA_GRED_DPS, + TCA_GRED_MAX_P, + TCA_GRED_LIMIT, + TCA_GRED_VQ_LIST, /* nested TCA_GRED_VQ_ENTRY */ + __TCA_GRED_MAX, +}; + +#define TCA_GRED_MAX (__TCA_GRED_MAX - 1) + +enum { + TCA_GRED_VQ_ENTRY_UNSPEC, + TCA_GRED_VQ_ENTRY, /* nested TCA_GRED_VQ_* */ + __TCA_GRED_VQ_ENTRY_MAX, +}; +#define TCA_GRED_VQ_ENTRY_MAX (__TCA_GRED_VQ_ENTRY_MAX - 1) + +enum { + TCA_GRED_VQ_UNSPEC, + TCA_GRED_VQ_PAD, + TCA_GRED_VQ_DP, /* u32 */ + TCA_GRED_VQ_STAT_BYTES, /* u64 */ + TCA_GRED_VQ_STAT_PACKETS, /* u32 */ + TCA_GRED_VQ_STAT_BACKLOG, /* u32 */ + TCA_GRED_VQ_STAT_PROB_DROP, /* u32 */ + TCA_GRED_VQ_STAT_PROB_MARK, /* u32 */ + TCA_GRED_VQ_STAT_FORCED_DROP, /* u32 */ + TCA_GRED_VQ_STAT_FORCED_MARK, /* u32 */ + TCA_GRED_VQ_STAT_PDROP, /* u32 */ + TCA_GRED_VQ_STAT_OTHER, /* u32 */ + TCA_GRED_VQ_FLAGS, /* u32 */ + __TCA_GRED_VQ_MAX +}; + +#define TCA_GRED_VQ_MAX (__TCA_GRED_VQ_MAX - 1) + +struct tc_gred_qopt { + __u32 limit; /* HARD maximal queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + __u32 DP; /* up to 2^32 DPs */ + __u32 backlog; + __u32 qave; + __u32 forced; + __u32 early; + __u32 other; + __u32 pdrop; + __u8 Wlog; /* log(W) */ + __u8 Plog; /* log(P_max/(qth_max-qth_min)) */ + __u8 Scell_log; /* cell size for idle damping */ + __u8 prio; /* prio of this VQ */ + __u32 packets; + __u32 bytesin; +}; + +/* gred setup */ +struct tc_gred_sopt { + __u32 DPs; + __u32 def_DP; + __u8 grio; + __u8 flags; + __u16 pad1; +}; + +/* CHOKe section */ + +enum { + TCA_CHOKE_UNSPEC, + TCA_CHOKE_PARMS, + TCA_CHOKE_STAB, + TCA_CHOKE_MAX_P, + __TCA_CHOKE_MAX, +}; + +#define TCA_CHOKE_MAX (__TCA_CHOKE_MAX - 1) + +struct tc_choke_qopt { + __u32 limit; /* Hard queue length (packets) */ + __u32 qth_min; /* Min average threshold (packets) */ + __u32 qth_max; /* Max average threshold (packets) */ + unsigned char Wlog; /* log(W) */ + unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ + unsigned char Scell_log; /* cell size for idle damping */ + unsigned char flags; /* see RED flags */ +}; + +struct tc_choke_xstats { + __u32 early; /* Early drops */ + __u32 pdrop; /* Drops due to queue limits */ + __u32 other; /* Drops due to drop() calls */ + __u32 marked; /* Marked packets */ + __u32 matched; /* Drops due to flow match */ +}; + +/* HTB section */ +#define TC_HTB_NUMPRIO 8 +#define TC_HTB_MAXDEPTH 8 +#define TC_HTB_PROTOVER 3 /* the same as HTB and TC's major */ + +struct tc_htb_opt { + struct tc_ratespec rate; + struct tc_ratespec ceil; + __u32 buffer; + __u32 cbuffer; + __u32 quantum; + __u32 level; /* out only */ + __u32 prio; +}; +struct tc_htb_glob { + __u32 version; /* to match HTB/TC */ + __u32 rate2quantum; /* bps->quantum divisor */ + __u32 defcls; /* default class number */ + __u32 debug; /* debug flags */ + + /* stats */ + __u32 direct_pkts; /* count of non shaped packets */ +}; +enum { + TCA_HTB_UNSPEC, + TCA_HTB_PARMS, + TCA_HTB_INIT, + TCA_HTB_CTAB, + TCA_HTB_RTAB, + TCA_HTB_DIRECT_QLEN, + TCA_HTB_RATE64, + TCA_HTB_CEIL64, + TCA_HTB_PAD, + __TCA_HTB_MAX, +}; + +#define TCA_HTB_MAX (__TCA_HTB_MAX - 1) + +struct tc_htb_xstats { + __u32 lends; + __u32 borrows; + __u32 giants; /* unused since 'Make HTB scheduler work with TSO.' */ + __s32 tokens; + __s32 ctokens; +}; + +/* HFSC section */ + +struct tc_hfsc_qopt { + __u16 defcls; /* default class */ +}; + +struct tc_service_curve { + __u32 m1; /* slope of the first segment in bps */ + __u32 d; /* x-projection of the first segment in us */ + __u32 m2; /* slope of the second segment in bps */ +}; + +struct tc_hfsc_stats { + __u64 work; /* total work done */ + __u64 rtwork; /* work done by real-time criteria */ + __u32 period; /* current period */ + __u32 level; /* class level in hierarchy */ +}; + +enum { + TCA_HFSC_UNSPEC, + TCA_HFSC_RSC, + TCA_HFSC_FSC, + TCA_HFSC_USC, + __TCA_HFSC_MAX, +}; + +#define TCA_HFSC_MAX (__TCA_HFSC_MAX - 1) + + +/* CBQ section */ + +#define TC_CBQ_MAXPRIO 8 +#define TC_CBQ_MAXLEVEL 8 +#define TC_CBQ_DEF_EWMA 5 + +struct tc_cbq_lssopt { + unsigned char change; + unsigned char flags; +#define TCF_CBQ_LSS_BOUNDED 1 +#define TCF_CBQ_LSS_ISOLATED 2 + unsigned char ewma_log; + unsigned char level; +#define TCF_CBQ_LSS_FLAGS 1 +#define TCF_CBQ_LSS_EWMA 2 +#define TCF_CBQ_LSS_MAXIDLE 4 +#define TCF_CBQ_LSS_MINIDLE 8 +#define TCF_CBQ_LSS_OFFTIME 0x10 +#define TCF_CBQ_LSS_AVPKT 0x20 + __u32 maxidle; + __u32 minidle; + __u32 offtime; + __u32 avpkt; +}; + +struct tc_cbq_wrropt { + unsigned char flags; + unsigned char priority; + unsigned char cpriority; + unsigned char __reserved; + __u32 allot; + __u32 weight; +}; + +struct tc_cbq_ovl { + unsigned char strategy; +#define TC_CBQ_OVL_CLASSIC 0 +#define TC_CBQ_OVL_DELAY 1 +#define TC_CBQ_OVL_LOWPRIO 2 +#define TC_CBQ_OVL_DROP 3 +#define TC_CBQ_OVL_RCLASSIC 4 + unsigned char priority2; + __u16 pad; + __u32 penalty; +}; + +struct tc_cbq_police { + unsigned char police; + unsigned char __res1; + unsigned short __res2; +}; + +struct tc_cbq_fopt { + __u32 split; + __u32 defmap; + __u32 defchange; +}; + +struct tc_cbq_xstats { + __u32 borrows; + __u32 overactions; + __s32 avgidle; + __s32 undertime; +}; + +enum { + TCA_CBQ_UNSPEC, + TCA_CBQ_LSSOPT, + TCA_CBQ_WRROPT, + TCA_CBQ_FOPT, + TCA_CBQ_OVL_STRATEGY, + TCA_CBQ_RATE, + TCA_CBQ_RTAB, + TCA_CBQ_POLICE, + __TCA_CBQ_MAX, +}; + +#define TCA_CBQ_MAX (__TCA_CBQ_MAX - 1) + +/* dsmark section */ + +enum { + TCA_DSMARK_UNSPEC, + TCA_DSMARK_INDICES, + TCA_DSMARK_DEFAULT_INDEX, + TCA_DSMARK_SET_TC_INDEX, + TCA_DSMARK_MASK, + TCA_DSMARK_VALUE, + __TCA_DSMARK_MAX, +}; + +#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1) + +/* ATM section */ + +enum { + TCA_ATM_UNSPEC, + TCA_ATM_FD, /* file/socket descriptor */ + TCA_ATM_PTR, /* pointer to descriptor - later */ + TCA_ATM_HDR, /* LL header */ + TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */ + TCA_ATM_ADDR, /* PVC address (for output only) */ + TCA_ATM_STATE, /* VC state (ATM_VS_*; for output only) */ + __TCA_ATM_MAX, +}; + +#define TCA_ATM_MAX (__TCA_ATM_MAX - 1) + +/* Network emulator */ + +enum { + TCA_NETEM_UNSPEC, + TCA_NETEM_CORR, + TCA_NETEM_DELAY_DIST, + TCA_NETEM_REORDER, + TCA_NETEM_CORRUPT, + TCA_NETEM_LOSS, + TCA_NETEM_RATE, + TCA_NETEM_ECN, + TCA_NETEM_RATE64, + TCA_NETEM_PAD, + TCA_NETEM_LATENCY64, + TCA_NETEM_JITTER64, + TCA_NETEM_SLOT, + TCA_NETEM_SLOT_DIST, + __TCA_NETEM_MAX, +}; + +#define TCA_NETEM_MAX (__TCA_NETEM_MAX - 1) + +struct tc_netem_qopt { + __u32 latency; /* added delay (us) */ + __u32 limit; /* fifo limit (packets) */ + __u32 loss; /* random packet loss (0=none ~0=100%) */ + __u32 gap; /* re-ordering gap (0 for none) */ + __u32 duplicate; /* random packet dup (0=none ~0=100%) */ + __u32 jitter; /* random jitter in latency (us) */ +}; + +struct tc_netem_corr { + __u32 delay_corr; /* delay correlation */ + __u32 loss_corr; /* packet loss correlation */ + __u32 dup_corr; /* duplicate correlation */ +}; + +struct tc_netem_reorder { + __u32 probability; + __u32 correlation; +}; + +struct tc_netem_corrupt { + __u32 probability; + __u32 correlation; +}; + +struct tc_netem_rate { + __u32 rate; /* byte/s */ + __s32 packet_overhead; + __u32 cell_size; + __s32 cell_overhead; +}; + +struct tc_netem_slot { + __s64 min_delay; /* nsec */ + __s64 max_delay; + __s32 max_packets; + __s32 max_bytes; + __s64 dist_delay; /* nsec */ + __s64 dist_jitter; /* nsec */ +}; + +enum { + NETEM_LOSS_UNSPEC, + NETEM_LOSS_GI, /* General Intuitive - 4 state model */ + NETEM_LOSS_GE, /* Gilbert Elliot models */ + __NETEM_LOSS_MAX +}; +#define NETEM_LOSS_MAX (__NETEM_LOSS_MAX - 1) + +/* State transition probabilities for 4 state model */ +struct tc_netem_gimodel { + __u32 p13; + __u32 p31; + __u32 p32; + __u32 p14; + __u32 p23; +}; + +/* Gilbert-Elliot models */ +struct tc_netem_gemodel { + __u32 p; + __u32 r; + __u32 h; + __u32 k1; +}; + +#define NETEM_DIST_SCALE 8192 +#define NETEM_DIST_MAX 16384 + +/* DRR */ + +enum { + TCA_DRR_UNSPEC, + TCA_DRR_QUANTUM, + __TCA_DRR_MAX +}; + +#define TCA_DRR_MAX (__TCA_DRR_MAX - 1) + +struct tc_drr_stats { + __u32 deficit; +}; + +/* MQPRIO */ +#define TC_QOPT_BITMASK 15 +#define TC_QOPT_MAX_QUEUE 16 + +enum { + TC_MQPRIO_HW_OFFLOAD_NONE, /* no offload requested */ + TC_MQPRIO_HW_OFFLOAD_TCS, /* offload TCs, no queue counts */ + __TC_MQPRIO_HW_OFFLOAD_MAX +}; + +#define TC_MQPRIO_HW_OFFLOAD_MAX (__TC_MQPRIO_HW_OFFLOAD_MAX - 1) + +enum { + TC_MQPRIO_MODE_DCB, + TC_MQPRIO_MODE_CHANNEL, + __TC_MQPRIO_MODE_MAX +}; + +#define __TC_MQPRIO_MODE_MAX (__TC_MQPRIO_MODE_MAX - 1) + +enum { + TC_MQPRIO_SHAPER_DCB, + TC_MQPRIO_SHAPER_BW_RATE, /* Add new shapers below */ + __TC_MQPRIO_SHAPER_MAX +}; + +#define __TC_MQPRIO_SHAPER_MAX (__TC_MQPRIO_SHAPER_MAX - 1) + +struct tc_mqprio_qopt { + __u8 num_tc; + __u8 prio_tc_map[TC_QOPT_BITMASK + 1]; + __u8 hw; + __u16 count[TC_QOPT_MAX_QUEUE]; + __u16 offset[TC_QOPT_MAX_QUEUE]; +}; + +#define TC_MQPRIO_F_MODE 0x1 +#define TC_MQPRIO_F_SHAPER 0x2 +#define TC_MQPRIO_F_MIN_RATE 0x4 +#define TC_MQPRIO_F_MAX_RATE 0x8 + +enum { + TCA_MQPRIO_UNSPEC, + TCA_MQPRIO_MODE, + TCA_MQPRIO_SHAPER, + TCA_MQPRIO_MIN_RATE64, + TCA_MQPRIO_MAX_RATE64, + __TCA_MQPRIO_MAX, +}; + +#define TCA_MQPRIO_MAX (__TCA_MQPRIO_MAX - 1) + +/* SFB */ + +enum { + TCA_SFB_UNSPEC, + TCA_SFB_PARMS, + __TCA_SFB_MAX, +}; + +#define TCA_SFB_MAX (__TCA_SFB_MAX - 1) + +/* + * Note: increment, decrement are Q0.16 fixed-point values. + */ +struct tc_sfb_qopt { + __u32 rehash_interval; /* delay between hash move, in ms */ + __u32 warmup_time; /* double buffering warmup time in ms (warmup_time < rehash_interval) */ + __u32 max; /* max len of qlen_min */ + __u32 bin_size; /* maximum queue length per bin */ + __u32 increment; /* probability increment, (d1 in Blue) */ + __u32 decrement; /* probability decrement, (d2 in Blue) */ + __u32 limit; /* max SFB queue length */ + __u32 penalty_rate; /* inelastic flows are rate limited to 'rate' pps */ + __u32 penalty_burst; +}; + +struct tc_sfb_xstats { + __u32 earlydrop; + __u32 penaltydrop; + __u32 bucketdrop; + __u32 queuedrop; + __u32 childdrop; /* drops in child qdisc */ + __u32 marked; + __u32 maxqlen; + __u32 maxprob; + __u32 avgprob; +}; + +#define SFB_MAX_PROB 0xFFFF + +/* QFQ */ +enum { + TCA_QFQ_UNSPEC, + TCA_QFQ_WEIGHT, + TCA_QFQ_LMAX, + __TCA_QFQ_MAX +}; + +#define TCA_QFQ_MAX (__TCA_QFQ_MAX - 1) + +struct tc_qfq_stats { + __u32 weight; + __u32 lmax; +}; + +/* CODEL */ + +enum { + TCA_CODEL_UNSPEC, + TCA_CODEL_TARGET, + TCA_CODEL_LIMIT, + TCA_CODEL_INTERVAL, + TCA_CODEL_ECN, + TCA_CODEL_CE_THRESHOLD, + __TCA_CODEL_MAX +}; + +#define TCA_CODEL_MAX (__TCA_CODEL_MAX - 1) + +struct tc_codel_xstats { + __u32 maxpacket; /* largest packet we've seen so far */ + __u32 count; /* how many drops we've done since the last time we + * entered dropping state + */ + __u32 lastcount; /* count at entry to dropping state */ + __u32 ldelay; /* in-queue delay seen by most recently dequeued packet */ + __s32 drop_next; /* time to drop next packet */ + __u32 drop_overlimit; /* number of time max qdisc packet limit was hit */ + __u32 ecn_mark; /* number of packets we ECN marked instead of dropped */ + __u32 dropping; /* are we in dropping state ? */ + __u32 ce_mark; /* number of CE marked packets because of ce_threshold */ +}; + +/* FQ_CODEL */ + +enum { + TCA_FQ_CODEL_UNSPEC, + TCA_FQ_CODEL_TARGET, + TCA_FQ_CODEL_LIMIT, + TCA_FQ_CODEL_INTERVAL, + TCA_FQ_CODEL_ECN, + TCA_FQ_CODEL_FLOWS, + TCA_FQ_CODEL_QUANTUM, + TCA_FQ_CODEL_CE_THRESHOLD, + TCA_FQ_CODEL_DROP_BATCH_SIZE, + TCA_FQ_CODEL_MEMORY_LIMIT, + __TCA_FQ_CODEL_MAX +}; + +#define TCA_FQ_CODEL_MAX (__TCA_FQ_CODEL_MAX - 1) + +enum { + TCA_FQ_CODEL_XSTATS_QDISC, + TCA_FQ_CODEL_XSTATS_CLASS, +}; + +struct tc_fq_codel_qd_stats { + __u32 maxpacket; /* largest packet we've seen so far */ + __u32 drop_overlimit; /* number of time max qdisc + * packet limit was hit + */ + __u32 ecn_mark; /* number of packets we ECN marked + * instead of being dropped + */ + __u32 new_flow_count; /* number of time packets + * created a 'new flow' + */ + __u32 new_flows_len; /* count of flows in new list */ + __u32 old_flows_len; /* count of flows in old list */ + __u32 ce_mark; /* packets above ce_threshold */ + __u32 memory_usage; /* in bytes */ + __u32 drop_overmemory; +}; + +struct tc_fq_codel_cl_stats { + __s32 deficit; + __u32 ldelay; /* in-queue delay seen by most recently + * dequeued packet + */ + __u32 count; + __u32 lastcount; + __u32 dropping; + __s32 drop_next; +}; + +struct tc_fq_codel_xstats { + __u32 type; + union { + struct tc_fq_codel_qd_stats qdisc_stats; + struct tc_fq_codel_cl_stats class_stats; + }; +}; + +/* FQ */ + +enum { + TCA_FQ_UNSPEC, + + TCA_FQ_PLIMIT, /* limit of total number of packets in queue */ + + TCA_FQ_FLOW_PLIMIT, /* limit of packets per flow */ + + TCA_FQ_QUANTUM, /* RR quantum */ + + TCA_FQ_INITIAL_QUANTUM, /* RR quantum for new flow */ + + TCA_FQ_RATE_ENABLE, /* enable/disable rate limiting */ + + TCA_FQ_FLOW_DEFAULT_RATE,/* obsolete, do not use */ + + TCA_FQ_FLOW_MAX_RATE, /* per flow max rate */ + + TCA_FQ_BUCKETS_LOG, /* log2(number of buckets) */ + + TCA_FQ_FLOW_REFILL_DELAY, /* flow credit refill delay in usec */ + + TCA_FQ_ORPHAN_MASK, /* mask applied to orphaned skb hashes */ + + TCA_FQ_LOW_RATE_THRESHOLD, /* per packet delay under this rate */ + + TCA_FQ_CE_THRESHOLD, /* DCTCP-like CE-marking threshold */ + + __TCA_FQ_MAX +}; + +#define TCA_FQ_MAX (__TCA_FQ_MAX - 1) + +struct tc_fq_qd_stats { + __u64 gc_flows; + __u64 highprio_packets; + __u64 tcp_retrans; + __u64 throttled; + __u64 flows_plimit; + __u64 pkts_too_long; + __u64 allocation_errors; + __s64 time_next_delayed_flow; + __u32 flows; + __u32 inactive_flows; + __u32 throttled_flows; + __u32 unthrottle_latency_ns; + __u64 ce_mark; /* packets above ce_threshold */ +}; + +/* Heavy-Hitter Filter */ + +enum { + TCA_HHF_UNSPEC, + TCA_HHF_BACKLOG_LIMIT, + TCA_HHF_QUANTUM, + TCA_HHF_HH_FLOWS_LIMIT, + TCA_HHF_RESET_TIMEOUT, + TCA_HHF_ADMIT_BYTES, + TCA_HHF_EVICT_TIMEOUT, + TCA_HHF_NON_HH_WEIGHT, + __TCA_HHF_MAX +}; + +#define TCA_HHF_MAX (__TCA_HHF_MAX - 1) + +struct tc_hhf_xstats { + __u32 drop_overlimit; /* number of times max qdisc packet limit + * was hit + */ + __u32 hh_overlimit; /* number of times max heavy-hitters was hit */ + __u32 hh_tot_count; /* number of captured heavy-hitters so far */ + __u32 hh_cur_count; /* number of current heavy-hitters */ +}; + +/* PIE */ +enum { + TCA_PIE_UNSPEC, + TCA_PIE_TARGET, + TCA_PIE_LIMIT, + TCA_PIE_TUPDATE, + TCA_PIE_ALPHA, + TCA_PIE_BETA, + TCA_PIE_ECN, + TCA_PIE_BYTEMODE, + __TCA_PIE_MAX +}; +#define TCA_PIE_MAX (__TCA_PIE_MAX - 1) + +struct tc_pie_xstats { + __u32 prob; /* current probability */ + __u32 delay; /* current delay in ms */ + __u32 avg_dq_rate; /* current average dq_rate in bits/pie_time */ + __u32 packets_in; /* total number of packets enqueued */ + __u32 dropped; /* packets dropped due to pie_action */ + __u32 overlimit; /* dropped due to lack of space in queue */ + __u32 maxq; /* maximum queue size */ + __u32 ecn_mark; /* packets marked with ecn*/ +}; + +/* CBS */ +struct tc_cbs_qopt { + __u8 offload; + __u8 _pad[3]; + __s32 hicredit; + __s32 locredit; + __s32 idleslope; + __s32 sendslope; +}; + +enum { + TCA_CBS_UNSPEC, + TCA_CBS_PARMS, + __TCA_CBS_MAX, +}; + +#define TCA_CBS_MAX (__TCA_CBS_MAX - 1) + + +/* ETF */ +struct tc_etf_qopt { + __s32 delta; + __s32 clockid; + __u32 flags; +#define TC_ETF_DEADLINE_MODE_ON BIT(0) +#define TC_ETF_OFFLOAD_ON BIT(1) +}; + +enum { + TCA_ETF_UNSPEC, + TCA_ETF_PARMS, + __TCA_ETF_MAX, +}; + +#define TCA_ETF_MAX (__TCA_ETF_MAX - 1) + + +/* CAKE */ +enum { + TCA_CAKE_UNSPEC, + TCA_CAKE_PAD, + TCA_CAKE_BASE_RATE64, + TCA_CAKE_DIFFSERV_MODE, + TCA_CAKE_ATM, + TCA_CAKE_FLOW_MODE, + TCA_CAKE_OVERHEAD, + TCA_CAKE_RTT, + TCA_CAKE_TARGET, + TCA_CAKE_AUTORATE, + TCA_CAKE_MEMORY, + TCA_CAKE_NAT, + TCA_CAKE_RAW, + TCA_CAKE_WASH, + TCA_CAKE_MPU, + TCA_CAKE_INGRESS, + TCA_CAKE_ACK_FILTER, + TCA_CAKE_SPLIT_GSO, + __TCA_CAKE_MAX +}; +#define TCA_CAKE_MAX (__TCA_CAKE_MAX - 1) + +enum { + __TCA_CAKE_STATS_INVALID, + TCA_CAKE_STATS_PAD, + TCA_CAKE_STATS_CAPACITY_ESTIMATE64, + TCA_CAKE_STATS_MEMORY_LIMIT, + TCA_CAKE_STATS_MEMORY_USED, + TCA_CAKE_STATS_AVG_NETOFF, + TCA_CAKE_STATS_MIN_NETLEN, + TCA_CAKE_STATS_MAX_NETLEN, + TCA_CAKE_STATS_MIN_ADJLEN, + TCA_CAKE_STATS_MAX_ADJLEN, + TCA_CAKE_STATS_TIN_STATS, + TCA_CAKE_STATS_DEFICIT, + TCA_CAKE_STATS_COBALT_COUNT, + TCA_CAKE_STATS_DROPPING, + TCA_CAKE_STATS_DROP_NEXT_US, + TCA_CAKE_STATS_P_DROP, + TCA_CAKE_STATS_BLUE_TIMER_US, + __TCA_CAKE_STATS_MAX +}; +#define TCA_CAKE_STATS_MAX (__TCA_CAKE_STATS_MAX - 1) + +enum { + __TCA_CAKE_TIN_STATS_INVALID, + TCA_CAKE_TIN_STATS_PAD, + TCA_CAKE_TIN_STATS_SENT_PACKETS, + TCA_CAKE_TIN_STATS_SENT_BYTES64, + TCA_CAKE_TIN_STATS_DROPPED_PACKETS, + TCA_CAKE_TIN_STATS_DROPPED_BYTES64, + TCA_CAKE_TIN_STATS_ACKS_DROPPED_PACKETS, + TCA_CAKE_TIN_STATS_ACKS_DROPPED_BYTES64, + TCA_CAKE_TIN_STATS_ECN_MARKED_PACKETS, + TCA_CAKE_TIN_STATS_ECN_MARKED_BYTES64, + TCA_CAKE_TIN_STATS_BACKLOG_PACKETS, + TCA_CAKE_TIN_STATS_BACKLOG_BYTES, + TCA_CAKE_TIN_STATS_THRESHOLD_RATE64, + TCA_CAKE_TIN_STATS_TARGET_US, + TCA_CAKE_TIN_STATS_INTERVAL_US, + TCA_CAKE_TIN_STATS_WAY_INDIRECT_HITS, + TCA_CAKE_TIN_STATS_WAY_MISSES, + TCA_CAKE_TIN_STATS_WAY_COLLISIONS, + TCA_CAKE_TIN_STATS_PEAK_DELAY_US, + TCA_CAKE_TIN_STATS_AVG_DELAY_US, + TCA_CAKE_TIN_STATS_BASE_DELAY_US, + TCA_CAKE_TIN_STATS_SPARSE_FLOWS, + TCA_CAKE_TIN_STATS_BULK_FLOWS, + TCA_CAKE_TIN_STATS_UNRESPONSIVE_FLOWS, + TCA_CAKE_TIN_STATS_MAX_SKBLEN, + TCA_CAKE_TIN_STATS_FLOW_QUANTUM, + __TCA_CAKE_TIN_STATS_MAX +}; +#define TCA_CAKE_TIN_STATS_MAX (__TCA_CAKE_TIN_STATS_MAX - 1) +#define TC_CAKE_MAX_TINS (8) + +enum { + CAKE_FLOW_NONE = 0, + CAKE_FLOW_SRC_IP, + CAKE_FLOW_DST_IP, + CAKE_FLOW_HOSTS, /* = CAKE_FLOW_SRC_IP | CAKE_FLOW_DST_IP */ + CAKE_FLOW_FLOWS, + CAKE_FLOW_DUAL_SRC, /* = CAKE_FLOW_SRC_IP | CAKE_FLOW_FLOWS */ + CAKE_FLOW_DUAL_DST, /* = CAKE_FLOW_DST_IP | CAKE_FLOW_FLOWS */ + CAKE_FLOW_TRIPLE, /* = CAKE_FLOW_HOSTS | CAKE_FLOW_FLOWS */ + CAKE_FLOW_MAX, +}; + +enum { + CAKE_DIFFSERV_DIFFSERV3 = 0, + CAKE_DIFFSERV_DIFFSERV4, + CAKE_DIFFSERV_DIFFSERV8, + CAKE_DIFFSERV_BESTEFFORT, + CAKE_DIFFSERV_PRECEDENCE, + CAKE_DIFFSERV_MAX +}; + +enum { + CAKE_ACK_NONE = 0, + CAKE_ACK_FILTER, + CAKE_ACK_AGGRESSIVE, + CAKE_ACK_MAX +}; + +enum { + CAKE_ATM_NONE = 0, + CAKE_ATM_ATM, + CAKE_ATM_PTM, + CAKE_ATM_MAX +}; + + +/* TAPRIO */ +enum { + TC_TAPRIO_CMD_SET_GATES = 0x00, + TC_TAPRIO_CMD_SET_AND_HOLD = 0x01, + TC_TAPRIO_CMD_SET_AND_RELEASE = 0x02, +}; + +enum { + TCA_TAPRIO_SCHED_ENTRY_UNSPEC, + TCA_TAPRIO_SCHED_ENTRY_INDEX, /* u32 */ + TCA_TAPRIO_SCHED_ENTRY_CMD, /* u8 */ + TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, /* u32 */ + TCA_TAPRIO_SCHED_ENTRY_INTERVAL, /* u32 */ + __TCA_TAPRIO_SCHED_ENTRY_MAX, +}; +#define TCA_TAPRIO_SCHED_ENTRY_MAX (__TCA_TAPRIO_SCHED_ENTRY_MAX - 1) + +/* The format for schedule entry list is: + * [TCA_TAPRIO_SCHED_ENTRY_LIST] + * [TCA_TAPRIO_SCHED_ENTRY] + * [TCA_TAPRIO_SCHED_ENTRY_CMD] + * [TCA_TAPRIO_SCHED_ENTRY_GATES] + * [TCA_TAPRIO_SCHED_ENTRY_INTERVAL] + */ +enum { + TCA_TAPRIO_SCHED_UNSPEC, + TCA_TAPRIO_SCHED_ENTRY, + __TCA_TAPRIO_SCHED_MAX, +}; + +#define TCA_TAPRIO_SCHED_MAX (__TCA_TAPRIO_SCHED_MAX - 1) + +enum { + TCA_TAPRIO_ATTR_UNSPEC, + TCA_TAPRIO_ATTR_PRIOMAP, /* struct tc_mqprio_qopt */ + TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST, /* nested of entry */ + TCA_TAPRIO_ATTR_SCHED_BASE_TIME, /* s64 */ + TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY, /* single entry */ + TCA_TAPRIO_ATTR_SCHED_CLOCKID, /* s32 */ + TCA_TAPRIO_PAD, + __TCA_TAPRIO_ATTR_MAX, +}; + +#define TCA_TAPRIO_ATTR_MAX (__TCA_TAPRIO_ATTR_MAX - 1) + +#endif -- cgit v1.2.3-58-ga151 From 9d5564ddcf2a0f5ba3fa1c3a1f8a1b59ad309553 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 17 Jan 2019 16:34:45 +0100 Subject: bpf: fix inner map masking to prevent oob under speculation During review I noticed that inner meta map setup for map in map is buggy in that it does not propagate all needed data from the reference map which the verifier is later accessing. In particular one such case is index masking to prevent out of bounds access under speculative execution due to missing the map's unpriv_array/index_mask field propagation. Fix this such that the verifier is generating the correct code for inlined lookups in case of unpriviledged use. Before patch (test_verifier's 'map in map access' dump): # bpftool prog dump xla id 3 0: (62) *(u32 *)(r10 -4) = 0 1: (bf) r2 = r10 2: (07) r2 += -4 3: (18) r1 = map[id:4] 5: (07) r1 += 272 | 6: (61) r0 = *(u32 *)(r2 +0) | 7: (35) if r0 >= 0x1 goto pc+6 | Inlined map in map lookup 8: (54) (u32) r0 &= (u32) 0 | with index masking for 9: (67) r0 <<= 3 | map->unpriv_array. 10: (0f) r0 += r1 | 11: (79) r0 = *(u64 *)(r0 +0) | 12: (15) if r0 == 0x0 goto pc+1 | 13: (05) goto pc+1 | 14: (b7) r0 = 0 | 15: (15) if r0 == 0x0 goto pc+11 16: (62) *(u32 *)(r10 -4) = 0 17: (bf) r2 = r10 18: (07) r2 += -4 19: (bf) r1 = r0 20: (07) r1 += 272 | 21: (61) r0 = *(u32 *)(r2 +0) | Index masking missing (!) 22: (35) if r0 >= 0x1 goto pc+3 | for inner map despite 23: (67) r0 <<= 3 | map->unpriv_array set. 24: (0f) r0 += r1 | 25: (05) goto pc+1 | 26: (b7) r0 = 0 | 27: (b7) r0 = 0 28: (95) exit After patch: # bpftool prog dump xla id 1 0: (62) *(u32 *)(r10 -4) = 0 1: (bf) r2 = r10 2: (07) r2 += -4 3: (18) r1 = map[id:2] 5: (07) r1 += 272 | 6: (61) r0 = *(u32 *)(r2 +0) | 7: (35) if r0 >= 0x1 goto pc+6 | Same inlined map in map lookup 8: (54) (u32) r0 &= (u32) 0 | with index masking due to 9: (67) r0 <<= 3 | map->unpriv_array. 10: (0f) r0 += r1 | 11: (79) r0 = *(u64 *)(r0 +0) | 12: (15) if r0 == 0x0 goto pc+1 | 13: (05) goto pc+1 | 14: (b7) r0 = 0 | 15: (15) if r0 == 0x0 goto pc+12 16: (62) *(u32 *)(r10 -4) = 0 17: (bf) r2 = r10 18: (07) r2 += -4 19: (bf) r1 = r0 20: (07) r1 += 272 | 21: (61) r0 = *(u32 *)(r2 +0) | 22: (35) if r0 >= 0x1 goto pc+4 | Now fixed inlined inner map 23: (54) (u32) r0 &= (u32) 0 | lookup with proper index masking 24: (67) r0 <<= 3 | for map->unpriv_array. 25: (0f) r0 += r1 | 26: (05) goto pc+1 | 27: (b7) r0 = 0 | 28: (b7) r0 = 0 29: (95) exit Fixes: b2157399cc98 ("bpf: prevent out-of-bounds speculation") Signed-off-by: Daniel Borkmann Acked-by: Martin KaFai Lau Signed-off-by: Alexei Starovoitov --- kernel/bpf/map_in_map.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c index 99d243e1ad6e..52378d3e34b3 100644 --- a/kernel/bpf/map_in_map.c +++ b/kernel/bpf/map_in_map.c @@ -12,6 +12,7 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd) { struct bpf_map *inner_map, *inner_map_meta; + u32 inner_map_meta_size; struct fd f; f = fdget(inner_map_ufd); @@ -36,7 +37,12 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd) return ERR_PTR(-EINVAL); } - inner_map_meta = kzalloc(sizeof(*inner_map_meta), GFP_USER); + inner_map_meta_size = sizeof(*inner_map_meta); + /* In some cases verifier needs to access beyond just base map. */ + if (inner_map->ops == &array_map_ops) + inner_map_meta_size = sizeof(struct bpf_array); + + inner_map_meta = kzalloc(inner_map_meta_size, GFP_USER); if (!inner_map_meta) { fdput(f); return ERR_PTR(-ENOMEM); @@ -46,9 +52,16 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd) inner_map_meta->key_size = inner_map->key_size; inner_map_meta->value_size = inner_map->value_size; inner_map_meta->map_flags = inner_map->map_flags; - inner_map_meta->ops = inner_map->ops; inner_map_meta->max_entries = inner_map->max_entries; + /* Misc members not needed in bpf_map_meta_equal() check. */ + inner_map_meta->ops = inner_map->ops; + if (inner_map->ops == &array_map_ops) { + inner_map_meta->unpriv_array = inner_map->unpriv_array; + container_of(inner_map_meta, struct bpf_array, map)->index_mask = + container_of(inner_map, struct bpf_array, map)->index_mask; + } + fdput(f); return inner_map_meta; } -- cgit v1.2.3-58-ga151 From 64cf5481262b9664ae3cdcb333f4a06af3e8fb58 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 18 Jan 2019 00:14:24 +0100 Subject: tools: bpftool: Cleanup license mess Precise and non-ambiguous license information is important. The recent relicensing of the bpftools introduced a license conflict. The files have now: SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause and * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version Amazingly about 20 people acked that change and neither they nor the committer noticed. Oh well. Digging deeper: The files were imported from the iproute2 repository with the GPL V2 or later boiler plate text in commit b66e907cfee2 ("tools: bpftool: copy JSON writer from iproute2 repository") Looking at the iproute2 repository at git://git.kernel.org/pub/scm/network/iproute2/iproute2.git the following commit is the equivivalent: commit d9d8c839 ("json_writer: add SPDX Identifier (GPL-2/BSD-2)") That commit explicitly removes the boiler plate and relicenses the code uner GPL-2.0-only and BSD-2-Clause. As Steven wrote the original code and also the relicensing commit, it's assumed that the relicensing was intended to do exaclty that. Just the kernel side update failed to remove the boiler plate. Do so now. Fixes: 907b22365115 ("tools: bpftool: dual license all files") Signed-off-by: Thomas Gleixner Cc: Jakub Kicinski Cc: Roman Gushchin Cc: YueHaibing Cc: Yonghong Song Cc: Stanislav Fomichev Cc: Sean Young Cc: Jiri Benc Cc: David Calavera Cc: Andrey Ignatov Cc: Joe Stringer Cc: David Ahern Cc: Alexei Starovoitov Cc: Petar Penkov Cc: Sandipan Das Cc: Prashant Bhole Cc: Stephen Hemminger Cc: John Fastabend Cc: Taeung Song Cc: Jiri Olsa Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Quentin Monnet CC: okash.khawaja@gmail.com Cc: netdev@vger.kernel.org Acked-by: Jakub Kicinski Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/json_writer.c | 7 +------ tools/bpf/bpftool/json_writer.h | 5 ----- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/tools/bpf/bpftool/json_writer.c b/tools/bpf/bpftool/json_writer.c index bff7ee026680..6046dcab51cc 100644 --- a/tools/bpf/bpftool/json_writer.c +++ b/tools/bpf/bpftool/json_writer.c @@ -1,15 +1,10 @@ -// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) /* * Simple streaming JSON writer * * This takes care of the annoying bits of JSON syntax like the commas * after elements * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * * Authors: Stephen Hemminger */ diff --git a/tools/bpf/bpftool/json_writer.h b/tools/bpf/bpftool/json_writer.h index c1ab51aed99c..cb9a1993681c 100644 --- a/tools/bpf/bpftool/json_writer.h +++ b/tools/bpf/bpftool/json_writer.h @@ -5,11 +5,6 @@ * This takes care of the annoying bits of JSON syntax like the commas * after elements * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * * Authors: Stephen Hemminger */ -- cgit v1.2.3-58-ga151 From e8c8b53ccaff568fef4c13a6ccaf08bf241aa01a Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Mon, 3 Dec 2018 22:14:04 -0800 Subject: net/mlx5e: Force CHECKSUM_UNNECESSARY for short ethernet frames When an ethernet frame is padded to meet the minimum ethernet frame size, the padding octets are not covered by the hardware checksum. Fortunately the padding octets are usually zero's, which don't affect checksum. However, we have a switch which pads non-zero octets, this causes kernel hardware checksum fault repeatedly. Prior to: commit '88078d98d1bb ("net: pskb_trim_rcsum() and CHECKSUM_COMPLETE ...")' skb checksum was forced to be CHECKSUM_NONE when padding is detected. After it, we need to keep skb->csum updated, like what we do for RXFCS. However, fixing up CHECKSUM_COMPLETE requires to verify and parse IP headers, it is not worthy the effort as the packets are so small that CHECKSUM_COMPLETE can't save anything. Fixes: 88078d98d1bb ("net: pskb_trim_rcsum() and CHECKSUM_COMPLETE are friends"), Cc: Eric Dumazet Cc: Tariq Toukan Cc: Nikola Ciprich Signed-off-by: Cong Wang Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 1d0bb5ff8c26..f86e4804e83e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -732,6 +732,8 @@ static u8 get_ip_proto(struct sk_buff *skb, int network_depth, __be16 proto) ((struct ipv6hdr *)ip_p)->nexthdr; } +#define short_frame(size) ((size) <= ETH_ZLEN + ETH_FCS_LEN) + static inline void mlx5e_handle_csum(struct net_device *netdev, struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq, @@ -754,6 +756,17 @@ static inline void mlx5e_handle_csum(struct net_device *netdev, if (unlikely(test_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &rq->state))) goto csum_unnecessary; + /* CQE csum doesn't cover padding octets in short ethernet + * frames. And the pad field is appended prior to calculating + * and appending the FCS field. + * + * Detecting these padded frames requires to verify and parse + * IP headers, so we simply force all those small frames to be + * CHECKSUM_UNNECESSARY even if they are not padded. + */ + if (short_frame(skb->len)) + goto csum_unnecessary; + if (likely(is_last_ethertype_ip(skb, &network_depth, &proto))) { if (unlikely(get_ip_proto(skb, network_depth, proto) == IPPROTO_SCTP)) goto csum_unnecessary; -- cgit v1.2.3-58-ga151 From 2eb1e42551a8128d9182480dfaea52fa861e26e8 Mon Sep 17 00:00:00 2001 From: Shay Agroskin Date: Sun, 9 Dec 2018 12:00:13 +0200 Subject: net/mlx5e: Fix wrong error code return on FEC query failure Advertised and configured FEC query failure resulted in printing wrong error code. Fixes: 6cfa94605091 ("net/mlx5e: Ethtool driver callback for query/set FEC policy") Signed-off-by: Shay Agroskin Reported-by: Or Gerlitz Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index c9df08133718..3bbccead2f63 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -844,9 +844,12 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv, ethtool_link_ksettings_add_link_mode(link_ksettings, supported, Autoneg); - if (get_fec_supported_advertised(mdev, link_ksettings)) + err = get_fec_supported_advertised(mdev, link_ksettings); + if (err) { netdev_dbg(priv->netdev, "%s: FEC caps query failed: %d\n", __func__, err); + err = 0; /* don't fail caps query because of FEC error */ + } if (!an_disable_admin) ethtool_link_ksettings_add_link_mode(link_ksettings, -- cgit v1.2.3-58-ga151 From 7fdc1adc52d3975740547a78c2df329bb207f15d Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 8 Nov 2018 12:06:53 +0200 Subject: net/mlx5e: Fix wrong (zero) TX drop counter indication for representor For representors, the TX dropped counter is not folded from the per-ring counters. Fix it. Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 96cc0c6a4014..c9a7081a5329 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -179,6 +179,7 @@ static void mlx5e_rep_update_sw_counters(struct mlx5e_priv *priv) s->tx_packets += sq_stats->packets; s->tx_bytes += sq_stats->bytes; + s->tx_queue_dropped += sq_stats->dropped; } } } -- cgit v1.2.3-58-ga151 From 25f2d0e7791e71cc89c58a7c2231768ad200764b Mon Sep 17 00:00:00 2001 From: Eli Britstein Date: Wed, 19 Dec 2018 07:36:51 +0200 Subject: net/mlx5e: Fix cb_ident duplicate in indirect block register Previously the identifier used for indirect block callback registry and for block rule cb registry (when done via indirect blocks) was the pointer to the tunnel netdev we were interested in receiving updates on. This worked fine if a single PF existed that registered one callback for the tunnel netdev of interest. However, if multiple PFs are in place then the 2nd PF tries to register with the same tunnel netdev identifier. This leads to EEXIST errors and/or incorrect cb deletions. Prevent this conflict by using the rpriv pointer as the identifier for netdev indirect block cb registry, allowing each PF to register a unique callback per tunnel netdev. For block cb registry, the same PF may register multiple cbs to the same block if using TC shared blocks. Instead of the rpriv, use the pointer to the allocated indr_priv data as the identifier here. This means that there can be a unique block callback for each PF/tunnel netdev combo. Fixes: f5bc2c5de101 ("net/mlx5e: Support TC indirect block notifications for eswitch uplink reprs") Signed-off-by: Eli Britstein Reviewed-by: Oz Shlomo Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 29 +++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index c9a7081a5329..04736212a21c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -58,7 +58,8 @@ struct mlx5e_rep_indr_block_priv { struct list_head list; }; -static void mlx5e_rep_indr_unregister_block(struct net_device *netdev); +static void mlx5e_rep_indr_unregister_block(struct mlx5e_rep_priv *rpriv, + struct net_device *netdev); static void mlx5e_rep_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) @@ -664,7 +665,7 @@ static void mlx5e_rep_indr_clean_block_privs(struct mlx5e_rep_priv *rpriv) struct list_head *head = &rpriv->uplink_priv.tc_indr_block_priv_list; list_for_each_entry_safe(cb_priv, temp, head, list) { - mlx5e_rep_indr_unregister_block(cb_priv->netdev); + mlx5e_rep_indr_unregister_block(rpriv, cb_priv->netdev); kfree(cb_priv); } } @@ -736,7 +737,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev, err = tcf_block_cb_register(f->block, mlx5e_rep_indr_setup_block_cb, - netdev, indr_priv, f->extack); + indr_priv, indr_priv, f->extack); if (err) { list_del(&indr_priv->list); kfree(indr_priv); @@ -744,14 +745,15 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev, return err; case TC_BLOCK_UNBIND: + indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev); + if (!indr_priv) + return -ENOENT; + tcf_block_cb_unregister(f->block, mlx5e_rep_indr_setup_block_cb, - netdev); - indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev); - if (indr_priv) { - list_del(&indr_priv->list); - kfree(indr_priv); - } + indr_priv); + list_del(&indr_priv->list); + kfree(indr_priv); return 0; default: @@ -780,7 +782,7 @@ static int mlx5e_rep_indr_register_block(struct mlx5e_rep_priv *rpriv, err = __tc_indr_block_cb_register(netdev, rpriv, mlx5e_rep_indr_setup_tc_cb, - netdev); + rpriv); if (err) { struct mlx5e_priv *priv = netdev_priv(rpriv->netdev); @@ -790,10 +792,11 @@ static int mlx5e_rep_indr_register_block(struct mlx5e_rep_priv *rpriv, return err; } -static void mlx5e_rep_indr_unregister_block(struct net_device *netdev) +static void mlx5e_rep_indr_unregister_block(struct mlx5e_rep_priv *rpriv, + struct net_device *netdev) { __tc_indr_block_cb_unregister(netdev, mlx5e_rep_indr_setup_tc_cb, - netdev); + rpriv); } static int mlx5e_nic_rep_netdevice_event(struct notifier_block *nb, @@ -812,7 +815,7 @@ static int mlx5e_nic_rep_netdevice_event(struct notifier_block *nb, mlx5e_rep_indr_register_block(rpriv, netdev); break; case NETDEV_UNREGISTER: - mlx5e_rep_indr_unregister_block(netdev); + mlx5e_rep_indr_unregister_block(rpriv, netdev); break; } return NOTIFY_OK; -- cgit v1.2.3-58-ga151 From 9c5d3afac436beef91b7a6312068e9360c7d8446 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 15 Jan 2019 14:24:23 +0100 Subject: mac80211_hwsim: check that n_limits makes sense Under certain circumstances, radios created via netlink could have n_limits be zero and no possible interface types, which makes no sense. Reject this early to prevent a WARN_ON() in cfg80211. Fixes: 99e3a44bac37 ("mac80211_hwsim: allow setting iftype support") Reported-by: syzbot+73fd8b0aa60c67fa4b60@syzkaller.appspotmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 3a4b8786f7ea..320edcac4699 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2761,6 +2761,11 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, BIT(NL80211_CHAN_WIDTH_160); } + if (!n_limits) { + err = -EINVAL; + goto failed_hw; + } + data->if_combination.n_limits = n_limits; data->if_combination.max_interfaces = 2048; data->if_combination.limits = data->if_limits; -- cgit v1.2.3-58-ga151 From a0dc02039a2ee54fb4ae400e0b755ed30e73e58c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Thu, 17 Jan 2019 16:32:42 -0500 Subject: mac80211: fix miscounting of ttl-dropped frames In ieee80211_rx_h_mesh_fwding, we increment the 'dropped_frames_ttl' counter when we decrement the ttl to zero. For unicast frames destined for other hosts, we stop processing the frame at that point. For multicast frames, we do not rebroadcast it in this case, but we do pass the frame up the stack to process it on this STA. That doesn't match the usual definition of "dropped," so don't count those as such. With this change, something like `ping6 -i0.2 ff02::1%mesh0` from a peer in a ttl=1 network no longer increments the counter rapidly. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 45aad3d3108c..27a337bc8acf 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2723,7 +2723,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) skb_set_queue_mapping(skb, q); if (!--mesh_hdr->ttl) { - IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); + if (!is_multicast_ether_addr(hdr->addr1)) + IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, + dropped_frames_ttl); goto out; } -- cgit v1.2.3-58-ga151 From f9d672f1c2ca36b788511bbd773d650c744e109a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 18 Jan 2019 07:29:52 +0000 Subject: virt_wifi: fix error return code in virt_wifi_newlink() Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in this function. Fixes: c7cdba31ed8b ("mac80211-next: rtnetlink wifi simulation device") Signed-off-by: Wei Yongjun Signed-off-by: Johannes Berg --- drivers/net/wireless/virt_wifi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c index 64b218699656..3a93e4d9828b 100644 --- a/drivers/net/wireless/virt_wifi.c +++ b/drivers/net/wireless/virt_wifi.c @@ -530,8 +530,10 @@ static int virt_wifi_newlink(struct net *src_net, struct net_device *dev, SET_NETDEV_DEV(dev, &priv->lowerdev->dev); dev->ieee80211_ptr = kzalloc(sizeof(*dev->ieee80211_ptr), GFP_KERNEL); - if (!dev->ieee80211_ptr) + if (!dev->ieee80211_ptr) { + err = -ENOMEM; goto remove_handler; + } dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; dev->ieee80211_ptr->wiphy = common_wiphy; -- cgit v1.2.3-58-ga151 From 75a080cde08d2dcba19ee864f9732094d93fab41 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 18 Jan 2019 08:12:10 -0600 Subject: powerpc: chrp: Use of_node_is_type to access device_type Commit 8ce5f8415753 ("of: Remove struct device_node.type pointer") removed struct device_node.type pointer, but the conversion to use of_node_is_type() accessor was missed in chrp_init_IRQ(). Fixes: 8ce5f8415753 ("of: Remove struct device_node.type pointer") Reported-by: kbuild test robot Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: linuxppc-dev@lists.ozlabs.org Acked-by: Michael Ellerman Signed-off-by: Rob Herring --- arch/powerpc/platforms/chrp/setup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index e66644e0fb40..9438fa0fc355 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -538,8 +538,7 @@ static void __init chrp_init_IRQ(void) /* see if there is a keyboard in the device tree with a parent of type "adb" */ for_each_node_by_name(kbd, "keyboard") - if (kbd->parent && kbd->parent->type - && strcmp(kbd->parent->type, "adb") == 0) + if (of_node_is_type(kbd->parent, "adb")) break; of_node_put(kbd); if (kbd) -- cgit v1.2.3-58-ga151 From 7afa81c55fca0cad589722cb4bce698b4803b0e1 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 9 Jan 2019 22:41:08 -0700 Subject: isdn: avm: Fix string plus integer warning from Clang A recent commit in Clang expanded the -Wstring-plus-int warning, showing some odd behavior in this file. drivers/isdn/hardware/avm/b1.c:426:30: warning: adding 'int' to a string does not append to the string [-Wstring-plus-int] cinfo->version[j] = "\0\0" + 1; ~~~~~~~^~~ drivers/isdn/hardware/avm/b1.c:426:30: note: use array indexing to silence this warning cinfo->version[j] = "\0\0" + 1; ^ & [ ] 1 warning generated. This is equivalent to just "\0". Nick pointed out that it is smarter to use "" instead of "\0" because "" is used elsewhere in the kernel and can be deduplicated at the linking stage. Link: https://github.com/ClangBuiltLinux/linux/issues/309 Suggested-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Signed-off-by: David S. Miller --- drivers/isdn/hardware/avm/b1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 4ac378e48902..40ca1e8fa09f 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -423,7 +423,7 @@ void b1_parse_version(avmctrl_info *cinfo) int i, j; for (j = 0; j < AVM_MAXVERSION; j++) - cinfo->version[j] = "\0\0" + 1; + cinfo->version[j] = ""; for (i = 0, j = 0; j < AVM_MAXVERSION && i < cinfo->versionlen; j++, i += cinfo->versionbuf[i] + 1) -- cgit v1.2.3-58-ga151 From 3e64cf7a435ed0500e3adaa8aada2272d3ae8abc Mon Sep 17 00:00:00 2001 From: Camelia Groza Date: Thu, 17 Jan 2019 14:22:36 +0200 Subject: net: phy: phy driver features are mandatory Since phy driver features became a link_mode bitmap, phy drivers that don't have a list of features configured will cause the kernel to crash when probed. Prevent the phy driver from registering if the features field is missing. Fixes: 719655a14971 ("net: phy: Replace phy driver features u32 with link_mode bitmap") Reported-by: Scott Wood Signed-off-by: Camelia Groza Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 5 +++++ include/linux/phy.h | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index bf3ce48a1e5d..46c86725a693 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2255,6 +2255,11 @@ int phy_driver_register(struct phy_driver *new_driver, struct module *owner) { int retval; + if (WARN_ON(!new_driver->features)) { + pr_err("%s: Driver features are missing\n", new_driver->name); + return -EINVAL; + } + new_driver->mdiodrv.flags |= MDIO_DEVICE_IS_PHY; new_driver->mdiodrv.driver.name = new_driver->name; new_driver->mdiodrv.driver.bus = &mdio_bus_type; diff --git a/include/linux/phy.h b/include/linux/phy.h index 55114657a577..ef20aeea10cc 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -469,8 +469,8 @@ struct phy_device { * only works for PHYs with IDs which match this field * name: The friendly name of this PHY type * phy_id_mask: Defines the important bits of the phy_id - * features: A list of features (speed, duplex, etc) supported - * by this PHY + * features: A mandatory list of features (speed, duplex, etc) + * supported by this PHY * flags: A bitfield defining certain other features this PHY * supports (like interrupts) * -- cgit v1.2.3-58-ga151 From 99e309b6ed75fab4a43afd9e523441ecc5a1f511 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 18 Jan 2019 22:57:04 +0000 Subject: clang-format: Update .clang-format with the latest for_each macro list Re-run the shell fragment that generated the original list. In particular this adds the missing xarray related functions. Signed-off-by: Jason Gunthorpe Signed-off-by: Miguel Ojeda --- .clang-format | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index e6080f5834a3..bc2ffb2a0b53 100644 --- a/.clang-format +++ b/.clang-format @@ -72,6 +72,10 @@ ForEachMacros: - 'apei_estatus_for_each_section' - 'ata_for_each_dev' - 'ata_for_each_link' + - '__ata_qc_for_each' + - 'ata_qc_for_each' + - 'ata_qc_for_each_raw' + - 'ata_qc_for_each_with_internal' - 'ax25_for_each' - 'ax25_uid_for_each' - 'bio_for_each_integrity_vec' @@ -85,6 +89,7 @@ ForEachMacros: - 'blk_queue_for_each_rl' - 'bond_for_each_slave' - 'bond_for_each_slave_rcu' + - 'bpf_for_each_spilled_reg' - 'btree_for_each_safe128' - 'btree_for_each_safe32' - 'btree_for_each_safe64' @@ -103,6 +108,8 @@ ForEachMacros: - 'drm_atomic_crtc_for_each_plane' - 'drm_atomic_crtc_state_for_each_plane' - 'drm_atomic_crtc_state_for_each_plane_state' + - 'drm_atomic_for_each_plane_damage' + - 'drm_connector_for_each_possible_encoder' - 'drm_for_each_connector_iter' - 'drm_for_each_crtc' - 'drm_for_each_encoder' @@ -121,11 +128,21 @@ ForEachMacros: - 'for_each_bio' - 'for_each_board_func_rsrc' - 'for_each_bvec' + - 'for_each_card_components' + - 'for_each_card_links' + - 'for_each_card_links_safe' + - 'for_each_card_prelinks' + - 'for_each_card_rtds' + - 'for_each_card_rtds_safe' + - 'for_each_cgroup_storage_type' - 'for_each_child_of_node' - 'for_each_clear_bit' - 'for_each_clear_bit_from' - 'for_each_cmsghdr' - 'for_each_compatible_node' + - 'for_each_component_dais' + - 'for_each_component_dais_safe' + - 'for_each_comp_order' - 'for_each_console' - 'for_each_cpu' - 'for_each_cpu_and' @@ -133,6 +150,10 @@ ForEachMacros: - 'for_each_cpu_wrap' - 'for_each_dev_addr' - 'for_each_dma_cap_mask' + - 'for_each_dpcm_be' + - 'for_each_dpcm_be_rollback' + - 'for_each_dpcm_be_safe' + - 'for_each_dpcm_fe' - 'for_each_drhd_unit' - 'for_each_dss_dev' - 'for_each_efi_memory_desc' @@ -149,6 +170,7 @@ ForEachMacros: - 'for_each_iommu' - 'for_each_ip_tunnel_rcu' - 'for_each_irq_nr' + - 'for_each_link_codecs' - 'for_each_lru' - 'for_each_matching_node' - 'for_each_matching_node_and_match' @@ -160,6 +182,7 @@ ForEachMacros: - 'for_each_mem_range_rev' - 'for_each_migratetype_order' - 'for_each_msi_entry' + - 'for_each_msi_entry_safe' - 'for_each_net' - 'for_each_netdev' - 'for_each_netdev_continue' @@ -183,12 +206,14 @@ ForEachMacros: - 'for_each_node_with_property' - 'for_each_of_allnodes' - 'for_each_of_allnodes_from' + - 'for_each_of_cpu_node' - 'for_each_of_pci_range' - 'for_each_old_connector_in_state' - 'for_each_old_crtc_in_state' - 'for_each_oldnew_connector_in_state' - 'for_each_oldnew_crtc_in_state' - 'for_each_oldnew_plane_in_state' + - 'for_each_oldnew_plane_in_state_reverse' - 'for_each_oldnew_private_obj_in_state' - 'for_each_old_plane_in_state' - 'for_each_old_private_obj_in_state' @@ -206,14 +231,17 @@ ForEachMacros: - 'for_each_process' - 'for_each_process_thread' - 'for_each_property_of_node' + - 'for_each_registered_fb' - 'for_each_reserved_mem_region' - - 'for_each_resv_unavail_range' + - 'for_each_rtd_codec_dai' + - 'for_each_rtd_codec_dai_rollback' - 'for_each_rtdcom' - 'for_each_rtdcom_safe' - 'for_each_set_bit' - 'for_each_set_bit_from' - 'for_each_sg' - 'for_each_sg_page' + - 'for_each_sibling_event' - '__for_each_thread' - 'for_each_thread' - 'for_each_zone' @@ -251,6 +279,8 @@ ForEachMacros: - 'hlist_nulls_for_each_entry_from' - 'hlist_nulls_for_each_entry_rcu' - 'hlist_nulls_for_each_entry_safe' + - 'i3c_bus_for_each_i2cdev' + - 'i3c_bus_for_each_i3cdev' - 'ide_host_for_each_port' - 'ide_port_for_each_dev' - 'ide_port_for_each_present_dev' @@ -267,11 +297,14 @@ ForEachMacros: - 'kvm_for_each_memslot' - 'kvm_for_each_vcpu' - 'list_for_each' + - 'list_for_each_codec' + - 'list_for_each_codec_safe' - 'list_for_each_entry' - 'list_for_each_entry_continue' - 'list_for_each_entry_continue_rcu' - 'list_for_each_entry_continue_reverse' - 'list_for_each_entry_from' + - 'list_for_each_entry_from_rcu' - 'list_for_each_entry_from_reverse' - 'list_for_each_entry_lockless' - 'list_for_each_entry_rcu' @@ -291,6 +324,7 @@ ForEachMacros: - 'media_device_for_each_intf' - 'media_device_for_each_link' - 'media_device_for_each_pad' + - 'nanddev_io_for_each_page' - 'netdev_for_each_lower_dev' - 'netdev_for_each_lower_private' - 'netdev_for_each_lower_private_rcu' @@ -357,12 +391,14 @@ ForEachMacros: - 'sk_nulls_for_each' - 'sk_nulls_for_each_from' - 'sk_nulls_for_each_rcu' + - 'snd_array_for_each' - 'snd_pcm_group_for_each_entry' - 'snd_soc_dapm_widget_for_each_path' - 'snd_soc_dapm_widget_for_each_path_safe' - 'snd_soc_dapm_widget_for_each_sink_path' - 'snd_soc_dapm_widget_for_each_source_path' - 'tb_property_for_each' + - 'tcf_exts_for_each_action' - 'udp_portaddr_for_each_entry' - 'udp_portaddr_for_each_entry_rcu' - 'usb_hub_for_each_child' @@ -371,6 +407,11 @@ ForEachMacros: - 'v4l2_m2m_for_each_dst_buf_safe' - 'v4l2_m2m_for_each_src_buf' - 'v4l2_m2m_for_each_src_buf_safe' + - 'virtio_device_for_each_vq' + - 'xa_for_each' + - 'xas_for_each' + - 'xas_for_each_conflict' + - 'xas_for_each_marked' - 'zorro_for_each_dev' #IncludeBlocks: Preserve # Unknown to clang-format-5.0 -- cgit v1.2.3-58-ga151 From df133f3f96257ee29696c0ed8bd198ec801dc810 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 17 Jan 2019 23:20:07 -0500 Subject: virtio_net: bulk free tx skbs Use napi_consume_skb() to get bulk free. Note that napi_consume_skb is safe to call in a non-napi context as long as the napi_budget flag is correct. Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 023725086046..8fadd8eaf601 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1330,7 +1330,7 @@ static int virtnet_receive(struct receive_queue *rq, int budget, return stats.packets; } -static void free_old_xmit_skbs(struct send_queue *sq) +static void free_old_xmit_skbs(struct send_queue *sq, bool in_napi) { struct sk_buff *skb; unsigned int len; @@ -1343,7 +1343,7 @@ static void free_old_xmit_skbs(struct send_queue *sq) bytes += skb->len; packets++; - dev_consume_skb_any(skb); + napi_consume_skb(skb, in_napi); } /* Avoid overhead when no packets have been processed @@ -1369,7 +1369,7 @@ static void virtnet_poll_cleantx(struct receive_queue *rq) return; if (__netif_tx_trylock(txq)) { - free_old_xmit_skbs(sq); + free_old_xmit_skbs(sq, true); __netif_tx_unlock(txq); } @@ -1445,7 +1445,7 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget) struct netdev_queue *txq = netdev_get_tx_queue(vi->dev, vq2txq(sq->vq)); __netif_tx_lock(txq, raw_smp_processor_id()); - free_old_xmit_skbs(sq); + free_old_xmit_skbs(sq, true); __netif_tx_unlock(txq); virtqueue_napi_complete(napi, sq->vq, 0); @@ -1514,7 +1514,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) bool use_napi = sq->napi.weight; /* Free up any pending old buffers before queueing new ones. */ - free_old_xmit_skbs(sq); + free_old_xmit_skbs(sq, false); if (use_napi && kick) virtqueue_enable_cb_delayed(sq->vq); @@ -1557,7 +1557,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) if (!use_napi && unlikely(!virtqueue_enable_cb_delayed(sq->vq))) { /* More just got used, free them then recheck. */ - free_old_xmit_skbs(sq); + free_old_xmit_skbs(sq, false); if (sq->vq->num_free >= 2+MAX_SKB_FRAGS) { netif_start_subqueue(dev, qnum); virtqueue_disable_cb(sq->vq); -- cgit v1.2.3-58-ga151 From e7c87bd6cc4ec7b0ac1ed0a88a58f8206c577488 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 15 Jan 2019 20:19:22 -0500 Subject: bpf: in __bpf_redirect_no_mac pull mac only if present Syzkaller was able to construct a packet of negative length by redirecting from bpf_prog_test_run_skb with BPF_PROG_TYPE_LWT_XMIT: BUG: KASAN: slab-out-of-bounds in memcpy include/linux/string.h:345 [inline] BUG: KASAN: slab-out-of-bounds in skb_copy_from_linear_data include/linux/skbuff.h:3421 [inline] BUG: KASAN: slab-out-of-bounds in __pskb_copy_fclone+0x2dd/0xeb0 net/core/skbuff.c:1395 Read of size 4294967282 at addr ffff8801d798009c by task syz-executor2/12942 kasan_report.cold.9+0x242/0x309 mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267 memcpy+0x23/0x50 mm/kasan/kasan.c:302 memcpy include/linux/string.h:345 [inline] skb_copy_from_linear_data include/linux/skbuff.h:3421 [inline] __pskb_copy_fclone+0x2dd/0xeb0 net/core/skbuff.c:1395 __pskb_copy include/linux/skbuff.h:1053 [inline] pskb_copy include/linux/skbuff.h:2904 [inline] skb_realloc_headroom+0xe7/0x120 net/core/skbuff.c:1539 ipip6_tunnel_xmit net/ipv6/sit.c:965 [inline] sit_tunnel_xmit+0xe1b/0x30d0 net/ipv6/sit.c:1029 __netdev_start_xmit include/linux/netdevice.h:4325 [inline] netdev_start_xmit include/linux/netdevice.h:4334 [inline] xmit_one net/core/dev.c:3219 [inline] dev_hard_start_xmit+0x295/0xc90 net/core/dev.c:3235 __dev_queue_xmit+0x2f0d/0x3950 net/core/dev.c:3805 dev_queue_xmit+0x17/0x20 net/core/dev.c:3838 __bpf_tx_skb net/core/filter.c:2016 [inline] __bpf_redirect_common net/core/filter.c:2054 [inline] __bpf_redirect+0x5cf/0xb20 net/core/filter.c:2061 ____bpf_clone_redirect net/core/filter.c:2094 [inline] bpf_clone_redirect+0x2f6/0x490 net/core/filter.c:2066 bpf_prog_41f2bcae09cd4ac3+0xb25/0x1000 The generated test constructs a packet with mac header, network header, skb->data pointing to network header and skb->len 0. Redirecting to a sit0 through __bpf_redirect_no_mac pulls the mac length, even though skb->data already is at skb->network_header. bpf_prog_test_run_skb has already pulled it as LWT_XMIT !is_l2. Update the offset calculation to pull only if skb->data differs from skb->network_header, which is not true in this case. The test itself can be run only from commit 1cf1cae963c2 ("bpf: introduce BPF_PROG_TEST_RUN command"), but the same type of packets with skb at network header could already be built from lwt xmit hooks, so this fix is more relevant to that commit. Also set the mac header on redirect from LWT_XMIT, as even after this change to __bpf_redirect_no_mac that field is expected to be set, but is not yet in ip_finish_output2. Fixes: 3a0af8fd61f9 ("bpf: BPF for lightweight tunnel infrastructure") Reported-by: syzbot Signed-off-by: Willem de Bruijn Acked-by: Martin KaFai Lau Signed-off-by: Daniel Borkmann --- net/core/filter.c | 21 +++++++++++---------- net/core/lwt_bpf.c | 1 + 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index dab10d21cae8..7559d6835ecb 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2020,18 +2020,19 @@ static inline int __bpf_tx_skb(struct net_device *dev, struct sk_buff *skb) static int __bpf_redirect_no_mac(struct sk_buff *skb, struct net_device *dev, u32 flags) { - /* skb->mac_len is not set on normal egress */ - unsigned int mlen = skb->network_header - skb->mac_header; + unsigned int mlen = skb_network_offset(skb); - __skb_pull(skb, mlen); + if (mlen) { + __skb_pull(skb, mlen); - /* At ingress, the mac header has already been pulled once. - * At egress, skb_pospull_rcsum has to be done in case that - * the skb is originated from ingress (i.e. a forwarded skb) - * to ensure that rcsum starts at net header. - */ - if (!skb_at_tc_ingress(skb)) - skb_postpull_rcsum(skb, skb_mac_header(skb), mlen); + /* At ingress, the mac header has already been pulled once. + * At egress, skb_pospull_rcsum has to be done in case that + * the skb is originated from ingress (i.e. a forwarded skb) + * to ensure that rcsum starts at net header. + */ + if (!skb_at_tc_ingress(skb)) + skb_postpull_rcsum(skb, skb_mac_header(skb), mlen); + } skb_pop_mac_header(skb); skb_reset_mac_len(skb); return flags & BPF_F_INGRESS ? diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c index 3e85437f7106..a648568c5e8f 100644 --- a/net/core/lwt_bpf.c +++ b/net/core/lwt_bpf.c @@ -63,6 +63,7 @@ static int run_lwt_bpf(struct sk_buff *skb, struct bpf_lwt_prog *lwt, lwt->name ? : ""); ret = BPF_OK; } else { + skb_reset_mac_header(skb); ret = skb_do_redirect(skb); if (ret == 0) ret = BPF_REDIRECT; -- cgit v1.2.3-58-ga151 From 6e693b3ffecb0b478c7050b44a4842854154f715 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Sat, 19 Jan 2019 21:56:05 +0000 Subject: x86: uaccess: Inhibit speculation past access_ok() in user_access_begin() Commit 594cc251fdd0 ("make 'user_access_begin()' do 'access_ok()'") makes the access_ok() check part of the user_access_begin() preceding a series of 'unsafe' accesses. This has the desirable effect of ensuring that all 'unsafe' accesses have been range-checked, without having to pick through all of the callsites to verify whether the appropriate checking has been made. However, the consolidated range check does not inhibit speculation, so it is still up to the caller to ensure that they are not susceptible to any speculative side-channel attacks for user addresses that ultimately fail the access_ok() check. This is an oversight, so use __uaccess_begin_nospec() to ensure that speculation is inhibited until the access_ok() check has passed. Reported-by: Julien Thierry Signed-off-by: Will Deacon Signed-off-by: Linus Torvalds --- arch/x86/include/asm/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index a77445d1b034..780f2b42c8ef 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -711,7 +711,7 @@ static __must_check inline bool user_access_begin(const void __user *ptr, size_t { if (unlikely(!access_ok(ptr,len))) return 0; - __uaccess_begin(); + __uaccess_begin_nospec(); return 1; } #define user_access_begin(a,b) user_access_begin(a,b) -- cgit v1.2.3-58-ga151 From fbfaf851902cd9293f392f3a1735e0543016d530 Mon Sep 17 00:00:00 2001 From: Florian La Roche Date: Sat, 19 Jan 2019 16:14:50 +0100 Subject: fix int_sqrt64() for very large numbers If an input number x for int_sqrt64() has the highest bit set, then fls64(x) is 64. (1UL << 64) is an overflow and breaks the algorithm. Subtracting 1 is a better guess for the initial value of m anyway and that's what also done in int_sqrt() implicitly [*]. [*] Note how int_sqrt() uses __fls() with two underscores, which already returns the proper raw bit number. In contrast, int_sqrt64() used fls64(), and that returns bit numbers illogically starting at 1, because of error handling for the "no bits set" case. Will points out that he bug probably is due to a copy-and-paste error from the regular int_sqrt() case. Signed-off-by: Florian La Roche Acked-by: Will Deacon Signed-off-by: Linus Torvalds --- lib/int_sqrt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c index 14436f4ca6bd..30e0f9770f88 100644 --- a/lib/int_sqrt.c +++ b/lib/int_sqrt.c @@ -52,7 +52,7 @@ u32 int_sqrt64(u64 x) if (x <= ULONG_MAX) return int_sqrt((unsigned long) x); - m = 1ULL << (fls64(x) & ~1ULL); + m = 1ULL << ((fls64(x) - 1) & ~1ULL); while (m != 0) { b = y + m; y >>= 1; -- cgit v1.2.3-58-ga151 From 560706d5d2589ef510f5436d69ab510a351b8cf7 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 18 Jan 2019 11:58:06 +0100 Subject: gcc-plugins: arm_ssp_per_task_plugin: sign extend the SP mask The ARM per-task stack protector GCC plugin hits an assert in the compiler in some case, due to the fact the the SP mask expression is not sign-extended as it should be. So fix that. Suggested-by: Kugan Vivekanandarajah Signed-off-by: Ard Biesheuvel Signed-off-by: Kees Cook --- scripts/gcc-plugins/arm_ssp_per_task_plugin.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/gcc-plugins/arm_ssp_per_task_plugin.c b/scripts/gcc-plugins/arm_ssp_per_task_plugin.c index de70b8470971..a65fbefb8501 100644 --- a/scripts/gcc-plugins/arm_ssp_per_task_plugin.c +++ b/scripts/gcc-plugins/arm_ssp_per_task_plugin.c @@ -13,7 +13,7 @@ static unsigned int arm_pertask_ssp_rtl_execute(void) for (insn = get_insns(); insn; insn = NEXT_INSN(insn)) { const char *sym; rtx body; - rtx masked_sp; + rtx mask, masked_sp; /* * Find a SET insn involving a SYMBOL_REF to __stack_chk_guard @@ -33,12 +33,13 @@ static unsigned int arm_pertask_ssp_rtl_execute(void) * produces the address of the copy of the stack canary value * stored in struct thread_info */ + mask = GEN_INT(sext_hwi(sp_mask, GET_MODE_PRECISION(Pmode))); masked_sp = gen_reg_rtx(Pmode); emit_insn_before(gen_rtx_SET(masked_sp, gen_rtx_AND(Pmode, stack_pointer_rtx, - GEN_INT(sp_mask))), + mask)), insn); SET_SRC(body) = gen_rtx_PLUS(Pmode, masked_sp, -- cgit v1.2.3-58-ga151 From 2c88c742d011707b55da7b54b06a030c6f57233f Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 18 Jan 2019 11:58:07 +0100 Subject: gcc-plugins: arm_ssp_per_task_plugin: fix for GCC 9+ GCC 9 reworks the way the references to the stack canary are emitted, to prevent the value from being spilled to the stack before the final comparison in the epilogue, defeating the purpose, given that the spill slot is under control of the attacker that we are protecting ourselves from. Since our canary value address is obtained without accessing memory (as opposed to pre-v7 code that will obtain it from a literal pool), it is unlikely (although not guaranteed) that the compiler will spill the canary value in the same way, so let's just disable this improvement when building with GCC9+. Signed-off-by: Ard Biesheuvel Signed-off-by: Kees Cook --- scripts/gcc-plugins/arm_ssp_per_task_plugin.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/scripts/gcc-plugins/arm_ssp_per_task_plugin.c b/scripts/gcc-plugins/arm_ssp_per_task_plugin.c index a65fbefb8501..89c47f57d1ce 100644 --- a/scripts/gcc-plugins/arm_ssp_per_task_plugin.c +++ b/scripts/gcc-plugins/arm_ssp_per_task_plugin.c @@ -53,6 +53,19 @@ static unsigned int arm_pertask_ssp_rtl_execute(void) #define NO_GATE #include "gcc-generate-rtl-pass.h" +#if BUILDING_GCC_VERSION >= 9000 +static bool no(void) +{ + return false; +} + +static void arm_pertask_ssp_start_unit(void *gcc_data, void *user_data) +{ + targetm.have_stack_protect_combined_set = no; + targetm.have_stack_protect_combined_test = no; +} +#endif + __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) { @@ -100,5 +113,10 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &arm_pertask_ssp_rtl_pass_info); +#if BUILDING_GCC_VERSION >= 9000 + register_callback(plugin_info->base_name, PLUGIN_START_UNIT, + arm_pertask_ssp_start_unit, NULL); +#endif + return 0; } -- cgit v1.2.3-58-ga151 From 5631e8576a3caf606cdc375f97425a67983b420c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 20 Jan 2019 14:33:34 -0800 Subject: pstore/ram: Avoid allocation and leak of platform data Yue Hu noticed that when parsing device tree the allocated platform data was never freed. Since it's not used beyond the function scope, this switches to using a stack variable instead. Reported-by: Yue Hu Fixes: 35da60941e44 ("pstore/ram: add Device Tree bindings") Cc: stable@vger.kernel.org Signed-off-by: Kees Cook --- fs/pstore/ram.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 076e26fdc0c0..898c8321b343 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -710,18 +710,15 @@ static int ramoops_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ramoops_platform_data *pdata = dev->platform_data; + struct ramoops_platform_data pdata_local; struct ramoops_context *cxt = &oops_cxt; size_t dump_mem_sz; phys_addr_t paddr; int err = -EINVAL; if (dev_of_node(dev) && !pdata) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - pr_err("cannot allocate platform data buffer\n"); - err = -ENOMEM; - goto fail_out; - } + pdata = &pdata_local; + memset(pdata, 0, sizeof(*pdata)); err = ramoops_parse_dt(pdev, pdata); if (err < 0) -- cgit v1.2.3-58-ga151 From 49a57857aeea06ca831043acbb0fa5e0f50602fd Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 21 Jan 2019 13:14:44 +1300 Subject: Linux 5.0-rc3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a189ceadcd08..f5b1d0d168e0 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 5 PATCHLEVEL = 0 SUBLEVEL = 0 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Shy Crocodile # *DOCUMENTATION* -- cgit v1.2.3-58-ga151 From 6dc080eeb2ba01973bfff0d79844d7a59e12542e Mon Sep 17 00:00:00 2001 From: Prateek Sood Date: Fri, 30 Nov 2018 20:40:56 +0530 Subject: sched/wait: Fix rcuwait_wake_up() ordering For some peculiar reason rcuwait_wake_up() has the right barrier in the comment, but not in the code. This mistake has been observed to cause a deadlock in the following situation: P1 P2 percpu_up_read() percpu_down_write() rcu_sync_is_idle() // false rcu_sync_enter() ... __percpu_up_read() [S] ,- __this_cpu_dec(*sem->read_count) | smp_rmb(); [L] | task = rcu_dereference(w->task) // NULL | | [S] w->task = current | smp_mb(); | [L] readers_active_check() // fail `-> Where the smp_rmb() (obviously) fails to constrain the store. [ peterz: Added changelog. ] Signed-off-by: Prateek Sood Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Andrea Parri Acked-by: Davidlohr Bueso Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 8f95c90ceb54 ("sched/wait, RCU: Introduce rcuwait machinery") Link: https://lkml.kernel.org/r/1543590656-7157-1-git-send-email-prsood@codeaurora.org Signed-off-by: Ingo Molnar --- kernel/exit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/exit.c b/kernel/exit.c index 284f2fe9a293..3fb7be001964 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -307,7 +307,7 @@ void rcuwait_wake_up(struct rcuwait *w) * MB (A) MB (B) * [L] cond [L] tsk */ - smp_rmb(); /* (B) */ + smp_mb(); /* (B) */ /* * Avoid using task_rcu_dereference() magic as long as we are careful, -- cgit v1.2.3-58-ga151 From e6018c0f5c996e61639adce6a0697391a2861916 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 17 Dec 2018 10:14:53 +0100 Subject: sched/wake_q: Document wake_q_add() The only guarantee provided by wake_q_add() is that a wakeup will happen after it, it does _NOT_ guarantee the wakeup will be delayed until the matching wake_up_q(). If wake_q_add() fails the cmpxchg() a concurrent wakeup is pending and that can happen at any time after the cmpxchg(). This means we should not rely on the wakeup happening at wake_q_up(), but should be ready for wake_q_add() to issue the wakeup. The delay; if provided (most likely); should only result in more efficient behaviour. Reported-by: Yongji Xie Signed-off-by: Peter Zijlstra (Intel) Cc: Davidlohr Bueso Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Waiman Long Cc: Will Deacon Signed-off-by: Ingo Molnar --- include/linux/sched/wake_q.h | 6 +++++- kernel/sched/core.c | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/linux/sched/wake_q.h b/include/linux/sched/wake_q.h index 10b19a192b2d..545f37138057 100644 --- a/include/linux/sched/wake_q.h +++ b/include/linux/sched/wake_q.h @@ -24,9 +24,13 @@ * called near the end of a function. Otherwise, the list can be * re-initialized for later re-use by wake_q_init(). * - * Note that this can cause spurious wakeups. schedule() callers + * NOTE that this can cause spurious wakeups. schedule() callers * must ensure the call is done inside a loop, confirming that the * wakeup condition has in fact occurred. + * + * NOTE that there is no guarantee the wakeup will happen any later than the + * wake_q_add() location. Therefore task must be ready to be woken at the + * location of the wake_q_add(). */ #include diff --git a/kernel/sched/core.c b/kernel/sched/core.c index a674c7db2f29..cc814933f7d6 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -396,6 +396,18 @@ static bool set_nr_if_polling(struct task_struct *p) #endif #endif +/** + * wake_q_add() - queue a wakeup for 'later' waking. + * @head: the wake_q_head to add @task to + * @task: the task to queue for 'later' wakeup + * + * Queue a task for later wakeup, most likely by the wake_up_q() call in the + * same context, _HOWEVER_ this is not guaranteed, the wakeup can come + * instantly. + * + * This function must be used as-if it were wake_up_process(); IOW the task + * must be ready to be woken at this location. + */ void wake_q_add(struct wake_q_head *head, struct task_struct *task) { struct wake_q_node *node = &task->wake_q; -- cgit v1.2.3-58-ga151 From 4c4e3731564c8945ac5ac90fc2a1e1f21cb79c92 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 17 Dec 2018 10:14:53 +0100 Subject: sched/wake_q: Fix wakeup ordering for wake_q Notable cmpxchg() does not provide ordering when it fails, however wake_q_add() requires ordering in this specific case too. Without this it would be possible for the concurrent wakeup to not observe our prior state. Andrea Parri provided: C wake_up_q-wake_q_add { int next = 0; int y = 0; } P0(int *next, int *y) { int r0; /* in wake_up_q() */ WRITE_ONCE(*next, 1); /* node->next = NULL */ smp_mb(); /* implied by wake_up_process() */ r0 = READ_ONCE(*y); } P1(int *next, int *y) { int r1; /* in wake_q_add() */ WRITE_ONCE(*y, 1); /* wake_cond = true */ smp_mb__before_atomic(); r1 = cmpxchg_relaxed(next, 1, 2); } exists (0:r0=0 /\ 1:r1=0) This "exists" clause cannot be satisfied according to the LKMM: Test wake_up_q-wake_q_add Allowed States 3 0:r0=0; 1:r1=1; 0:r0=1; 1:r1=0; 0:r0=1; 1:r1=1; No Witnesses Positive: 0 Negative: 3 Condition exists (0:r0=0 /\ 1:r1=0) Observation wake_up_q-wake_q_add Never 0 3 Reported-by: Yongji Xie Signed-off-by: Peter Zijlstra (Intel) Cc: Davidlohr Bueso Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Waiman Long Cc: Will Deacon Signed-off-by: Ingo Molnar --- kernel/sched/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index cc814933f7d6..d8d76a65cfdd 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -417,10 +417,11 @@ void wake_q_add(struct wake_q_head *head, struct task_struct *task) * its already queued (either by us or someone else) and will get the * wakeup due to that. * - * This cmpxchg() executes a full barrier, which pairs with the full - * barrier executed by the wakeup in wake_up_q(). + * In order to ensure that a pending wakeup will observe our pending + * state, even in the failed case, an explicit smp_mb() must be used. */ - if (cmpxchg(&node->next, NULL, WAKE_Q_TAIL)) + smp_mb__before_atomic(); + if (cmpxchg_relaxed(&node->next, NULL, WAKE_Q_TAIL)) return; get_task_struct(task); -- cgit v1.2.3-58-ga151 From b061c38bef43406df8e73c5be06cbfacad5ee6ad Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 29 Nov 2018 14:44:49 +0100 Subject: futex: Fix (possible) missed wakeup We must not rely on wake_q_add() to delay the wakeup; in particular commit: 1d0dcb3ad9d3 ("futex: Implement lockless wakeups") moved wake_q_add() before smp_store_release(&q->lock_ptr, NULL), which could result in futex_wait() waking before observing ->lock_ptr == NULL and going back to sleep again. Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 1d0dcb3ad9d3 ("futex: Implement lockless wakeups") Signed-off-by: Ingo Molnar --- kernel/futex.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index be3bff2315ff..fdd312da0992 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1452,11 +1452,7 @@ static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q) if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n")) return; - /* - * Queue the task for later wakeup for after we've released - * the hb->lock. wake_q_add() grabs reference to p. - */ - wake_q_add(wake_q, p); + get_task_struct(p); __unqueue_futex(q); /* * The waiting task can free the futex_q as soon as q->lock_ptr = NULL @@ -1466,6 +1462,13 @@ static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q) * plist_del in __unqueue_futex(). */ smp_store_release(&q->lock_ptr, NULL); + + /* + * Queue the task for later wakeup for after we've released + * the hb->lock. wake_q_add() grabs reference to p. + */ + wake_q_add(wake_q, p); + put_task_struct(p); } /* -- cgit v1.2.3-58-ga151 From e158488be27b157802753a59b336142dc0eb0380 Mon Sep 17 00:00:00 2001 From: Xie Yongji Date: Thu, 29 Nov 2018 20:50:30 +0800 Subject: locking/rwsem: Fix (possible) missed wakeup Because wake_q_add() can imply an immediate wakeup (cmpxchg failure case), we must not rely on the wakeup being delayed. However, commit: e38513905eea ("locking/rwsem: Rework zeroing reader waiter->task") relies on exactly that behaviour in that the wakeup must not happen until after we clear waiter->task. [ peterz: Added changelog. ] Signed-off-by: Xie Yongji Signed-off-by: Zhang Yu Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: e38513905eea ("locking/rwsem: Rework zeroing reader waiter->task") Link: https://lkml.kernel.org/r/1543495830-2644-1-git-send-email-xieyongji@baidu.com Signed-off-by: Ingo Molnar --- kernel/locking/rwsem-xadd.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index 09b180063ee1..50d9af615dc4 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -198,15 +198,22 @@ static void __rwsem_mark_wake(struct rw_semaphore *sem, woken++; tsk = waiter->task; - wake_q_add(wake_q, tsk); + get_task_struct(tsk); list_del(&waiter->list); /* - * Ensure that the last operation is setting the reader + * Ensure calling get_task_struct() before setting the reader * waiter to nil such that rwsem_down_read_failed() cannot * race with do_exit() by always holding a reference count * to the task to wakeup. */ smp_store_release(&waiter->task, NULL); + /* + * Ensure issuing the wakeup (either by us or someone else) + * after setting the reader waiter to nil. + */ + wake_q_add(wake_q, tsk); + /* wake_q_add() already take the task ref */ + put_task_struct(tsk); } adjustment = woken * RWSEM_ACTIVE_READ_BIAS - adjustment; -- cgit v1.2.3-58-ga151 From d95e674c01cfb5461e8b9fdeebf6d878c9b80b2f Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Thu, 10 Jan 2019 15:41:09 +0800 Subject: ceph: clear inode pointer when snap realm gets dropped by its inode snap realm and corresponding inode have pointers to each other. The two pointer should get clear at the same time. Otherwise, snap realm's pointer may reference freed inode. Cc: stable@vger.kernel.org # 4.17+ Signed-off-by: "Yan, Zheng" Reviewed-by: Luis Henriques Signed-off-by: Ilya Dryomov --- fs/ceph/caps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 94c026bba2c2..bba28a5034ba 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1035,6 +1035,8 @@ static void drop_inode_snap_realm(struct ceph_inode_info *ci) list_del_init(&ci->i_snap_realm_item); ci->i_snap_realm_counter++; ci->i_snap_realm = NULL; + if (realm->ino == ci->i_vino.ino) + realm->inode = NULL; spin_unlock(&realm->inodes_with_caps_lock); ceph_put_snap_realm(ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc, realm); -- cgit v1.2.3-58-ga151 From 4aac9228d16458cedcfd90c7fb37211cf3653ac3 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 14 Jan 2019 21:13:10 +0100 Subject: libceph: avoid KEEPALIVE_PENDING races in ceph_con_keepalive() con_fault() can transition the connection into STANDBY right after ceph_con_keepalive() clears STANDBY in clear_standby(): libceph user thread ceph-msgr worker ceph_con_keepalive() mutex_lock(&con->mutex) clear_standby(con) mutex_unlock(&con->mutex) mutex_lock(&con->mutex) con_fault() ... if KEEPALIVE_PENDING isn't set set state to STANDBY ... mutex_unlock(&con->mutex) set KEEPALIVE_PENDING set WRITE_PENDING This triggers warnings in clear_standby() when either ceph_con_send() or ceph_con_keepalive() get to clearing STANDBY next time. I don't see a reason to condition queue_con() call on the previous value of KEEPALIVE_PENDING, so move the setting of KEEPALIVE_PENDING into the critical section -- unlike WRITE_PENDING, KEEPALIVE_PENDING could have been a non-atomic flag. Reported-by: syzbot+acdeb633f6211ccdf886@syzkaller.appspotmail.com Signed-off-by: Ilya Dryomov Tested-by: Myungho Jung --- net/ceph/messenger.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index d5718284db57..3661cdd927f1 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -3206,9 +3206,10 @@ void ceph_con_keepalive(struct ceph_connection *con) dout("con_keepalive %p\n", con); mutex_lock(&con->mutex); clear_standby(con); + con_flag_set(con, CON_FLAG_KEEPALIVE_PENDING); mutex_unlock(&con->mutex); - if (con_flag_test_and_set(con, CON_FLAG_KEEPALIVE_PENDING) == 0 && - con_flag_test_and_set(con, CON_FLAG_WRITE_PENDING) == 0) + + if (con_flag_test_and_set(con, CON_FLAG_WRITE_PENDING) == 0) queue_con(con); } EXPORT_SYMBOL(ceph_con_keepalive); -- cgit v1.2.3-58-ga151 From 74827ee29565f86e2a64495a5e3e58d3371d74ee Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 18 Jan 2019 00:14:22 +0100 Subject: ceph: quota: cleanup license mess Precise and non-ambiguous license information is important. The recently added quota.c file has a SPDX license identifier, which is nice, but at the same time it has a contradictionary license boiler plate text. SPDX-License-Identifier: GPL-2.0 versus * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. Oh well. As the other ceph related files are licensed under the GPL v2 only, it's assumed that the SPDX id is correct and the boiler plate was randomly copied into that patch. Remove the boiler plate as it is wrong and even if correct it is redundant. Fixes: fb18a57568c2 ("ceph: quota: add initial infrastructure to support cephfs quotas") Signed-off-by: Thomas Gleixner Cc: Luis Henriques Cc: Jiri Kosina Cc: "Yan, Zheng" Cc: Sage Weil Cc: Ilya Dryomov Cc: ceph-devel@vger.kernel.org Acked-by: Luis Henriques Signed-off-by: Ilya Dryomov --- fs/ceph/quota.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/fs/ceph/quota.c b/fs/ceph/quota.c index 03f4d24db8fe..9455d3aef0c3 100644 --- a/fs/ceph/quota.c +++ b/fs/ceph/quota.c @@ -3,19 +3,6 @@ * quota.c - CephFS quota * * Copyright (C) 2017-2018 SUSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . */ #include -- cgit v1.2.3-58-ga151 From 57c36519e4b949f89381053f7283f5d605595b42 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Wed, 16 Jan 2019 18:53:26 -0500 Subject: dm: fix clone_bio() to trigger blk_recount_segments() DM's clone_bio() now benefits from using bio_trim() by fixing the fact that clone_bio() wasn't clearing BIO_SEG_VALID like bio_trim() does; which triggers blk_recount_segments() via bio_phys_segments(). Reviewed-by: Ming Lei Signed-off-by: Mike Snitzer --- drivers/md/dm.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index d67c95ef8d7e..fcb97b0a5743 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1320,7 +1320,7 @@ static int clone_bio(struct dm_target_io *tio, struct bio *bio, __bio_clone_fast(clone, bio); - if (unlikely(bio_integrity(bio) != NULL)) { + if (bio_integrity(bio)) { int r; if (unlikely(!dm_target_has_integrity(tio->ti->type) && @@ -1336,11 +1336,7 @@ static int clone_bio(struct dm_target_io *tio, struct bio *bio, return r; } - bio_advance(clone, to_bytes(sector - clone->bi_iter.bi_sector)); - clone->bi_iter.bi_size = to_bytes(len); - - if (unlikely(bio_integrity(bio) != NULL)) - bio_integrity_trim(clone); + bio_trim(clone, sector - clone->bi_iter.bi_sector, len); return 0; } -- cgit v1.2.3-58-ga151 From a1e1cb72d96491277ede8d257ce6b48a381dd336 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 17 Jan 2019 10:48:01 -0500 Subject: dm: fix redundant IO accounting for bios that need splitting The risk of redundant IO accounting was not taken into consideration when commit 18a25da84354 ("dm: ensure bio submission follows a depth-first tree walk") introduced IO splitting in terms of recursion via generic_make_request(). Fix this by subtracting the split bio's payload from the IO stats that were already accounted for by start_io_acct() upon dm_make_request() entry. This repeat oscillation of the IO accounting, up then down, isn't ideal but refactoring DM core's IO splitting to pre-split bios _before_ they are accounted turned out to be an excessive amount of change that will need a full development cycle to refine and verify. Before this fix: /dev/mapper/stripe_dev is a 4-way stripe using a 32k chunksize, so bios are split on 32k boundaries. # fio --name=16M --filename=/dev/mapper/stripe_dev --rw=write --bs=64k --size=16M \ --iodepth=1 --ioengine=libaio --direct=1 --refill_buffers with debugging added: [103898.310264] device-mapper: core: start_io_acct: dm-2 WRITE bio->bi_iter.bi_sector=0 len=128 [103898.318704] device-mapper: core: __split_and_process_bio: recursing for following split bio: [103898.329136] device-mapper: core: start_io_acct: dm-2 WRITE bio->bi_iter.bi_sector=64 len=64 ... 16M written yet 136M (278528 * 512b) accounted: # cat /sys/block/dm-2/stat | awk '{ print $7 }' 278528 After this fix: 16M written and 16M (32768 * 512b) accounted: # cat /sys/block/dm-2/stat | awk '{ print $7 }' 32768 Fixes: 18a25da84354 ("dm: ensure bio submission follows a depth-first tree walk") Cc: stable@vger.kernel.org # 4.16+ Reported-by: Bryan Gurney Reviewed-by: Ming Lei Signed-off-by: Mike Snitzer --- drivers/md/dm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index fcb97b0a5743..fbadda68e23b 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1584,6 +1584,9 @@ static void init_clone_info(struct clone_info *ci, struct mapped_device *md, ci->sector = bio->bi_iter.bi_sector; } +#define __dm_part_stat_sub(part, field, subnd) \ + (part_stat_get(part, field) -= (subnd)) + /* * Entry point to split a bio into clones and submit them to the targets. */ @@ -1638,6 +1641,19 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md, struct bio *b = bio_split(bio, bio_sectors(bio) - ci.sector_count, GFP_NOIO, &md->queue->bio_split); ci.io->orig_bio = b; + + /* + * Adjust IO stats for each split, otherwise upon queue + * reentry there will be redundant IO accounting. + * NOTE: this is a stop-gap fix, a proper fix involves + * significant refactoring of DM core's bio splitting + * (by eliminating DM's splitting and just using bio_split) + */ + part_stat_lock(); + __dm_part_stat_sub(&dm_disk(md)->part0, + sectors[op_stat_group(bio_op(bio))], ci.sector_count); + part_stat_unlock(); + bio_chain(b, bio); ret = generic_make_request(bio); break; -- cgit v1.2.3-58-ga151 From 27cfb3a53be46a54ec5e0bd04e51995b74c90343 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 20 Jan 2019 10:46:58 +0100 Subject: tty: Handle problem if line discipline does not have receive_buf Some tty line disciplines do not have a receive buf callback, so properly check for that before calling it. If they do not have this callback, just eat the character quietly, as we can't fail this call. Reported-by: Jann Horn Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 23c6fd238422..21ffcce16927 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2189,7 +2189,8 @@ static int tiocsti(struct tty_struct *tty, char __user *p) ld = tty_ldisc_ref_wait(tty); if (!ld) return -EIO; - ld->ops->receive_buf(tty, &ch, &mbz, 1); + if (ld->ops->receive_buf) + ld->ops->receive_buf(tty, &ch, &mbz, 1); tty_ldisc_deref(ld); return 0; } -- cgit v1.2.3-58-ga151 From 78ddc9b4417dacfbababb1c02f9987ebcc75c786 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 21 Jan 2019 14:27:11 -0200 Subject: ASoC: MAINTAINERS: fsl: Change Fabio's email address I prefer to use my personal email address for kernel related work. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5b9c6af98283..9cd09c593c34 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6069,7 +6069,7 @@ FREESCALE SOC SOUND DRIVERS M: Timur Tabi M: Nicolin Chen M: Xiubo Li -R: Fabio Estevam +R: Fabio Estevam L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: linuxppc-dev@lists.ozlabs.org S: Maintained @@ -10748,7 +10748,7 @@ F: include/linux/nvmem-consumer.h F: include/linux/nvmem-provider.h NXP SGTL5000 DRIVER -M: Fabio Estevam +M: Fabio Estevam L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/sound/sgtl5000.txt -- cgit v1.2.3-58-ga151 From 266c7bf52a7fe5cb5a97e78fedcaac629378008f Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 14 Jan 2019 18:41:04 -0700 Subject: nfit_test: fix security state pull for nvdimm security nfit_test The override status function needs to be updated to use the proper request parameter in order to get the security state. Fixes: 3c13e2ac747a ("...Add test support for Intel nvdimm security DSMs") Reported-by: Vishal Verma Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- tools/testing/nvdimm/dimm_devs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/nvdimm/dimm_devs.c b/tools/testing/nvdimm/dimm_devs.c index e75238404555..2d4baf57822f 100644 --- a/tools/testing/nvdimm/dimm_devs.c +++ b/tools/testing/nvdimm/dimm_devs.c @@ -18,8 +18,8 @@ ssize_t security_show(struct device *dev, * For the test version we need to poll the "hardware" in order * to get the updated status for unlock testing. */ - nvdimm->sec.state = nvdimm_security_state(nvdimm, false); - nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, true); + nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); + nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); switch (nvdimm->sec.state) { case NVDIMM_SECURITY_DISABLED: -- cgit v1.2.3-58-ga151 From 1cd7386549f9b6f2f230da54aa9e7fe2d6c216d2 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 19 Jan 2019 08:45:56 -0800 Subject: libnvdimm/security: Require nvdimm_security_setup_events() to succeed The following warning: ACPI0012:00: security event setup failed: -19 ...is meant to capture exceptional failures of sysfs_get_dirent(), however it will also fail in the common case when security support is disabled. A few issues: 1/ A dev_warn() report for a common case is too chatty 2/ The setup of this notifier is generic, no need for it to be driven from the nfit driver, it can exist completely in the core. 3/ If it fails for any reason besides security support being disabled, that's fatal and should abort DIMM activation. Userspace may hang if it never gets overwrite notifications. 4/ The dirent needs to be released. Move the call to the core 'dimm' driver, make it conditional on security support being active, make it fatal for the exceptional case, add the missing sysfs_put() at device disable time. Fixes: 7d988097c546 ("...Add security DSM overwrite support") Reviewed-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 5 ----- drivers/nvdimm/dimm.c | 6 ++++++ drivers/nvdimm/dimm_devs.c | 22 +++++++++++++++++----- drivers/nvdimm/nd.h | 1 + include/linux/libnvdimm.h | 1 - 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 5143e11e3b0f..c1fb06654749 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2042,11 +2042,6 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) if (!nvdimm) continue; - rc = nvdimm_security_setup_events(nvdimm); - if (rc < 0) - dev_warn(acpi_desc->dev, - "security event setup failed: %d\n", rc); - nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit"); if (nfit_kernfs) nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs, diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 0cf58cabc9ed..3cf50274fadb 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -26,6 +26,12 @@ static int nvdimm_probe(struct device *dev) struct nvdimm_drvdata *ndd; int rc; + rc = nvdimm_security_setup_events(dev); + if (rc < 0) { + dev_err(dev, "security event setup failed: %d\n", rc); + return rc; + } + rc = nvdimm_check_config_data(dev); if (rc) { /* not required for non-aliased nvdimm, ex. NVDIMM-N */ diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 4890310df874..efe412a6b5b9 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -578,13 +578,25 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, } EXPORT_SYMBOL_GPL(__nvdimm_create); -int nvdimm_security_setup_events(struct nvdimm *nvdimm) +static void shutdown_security_notify(void *data) { - nvdimm->sec.overwrite_state = sysfs_get_dirent(nvdimm->dev.kobj.sd, - "security"); + struct nvdimm *nvdimm = data; + + sysfs_put(nvdimm->sec.overwrite_state); +} + +int nvdimm_security_setup_events(struct device *dev) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + + if (nvdimm->sec.state < 0 || !nvdimm->sec.ops + || !nvdimm->sec.ops->overwrite) + return 0; + nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security"); if (!nvdimm->sec.overwrite_state) - return -ENODEV; - return 0; + return -ENOMEM; + + return devm_add_action_or_reset(dev, shutdown_security_notify, nvdimm); } EXPORT_SYMBOL_GPL(nvdimm_security_setup_events); diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index cfde992684e7..379bf4305e61 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -250,6 +250,7 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys, void nvdimm_set_aliasing(struct device *dev); void nvdimm_set_locked(struct device *dev); void nvdimm_clear_locked(struct device *dev); +int nvdimm_security_setup_events(struct device *dev); #if IS_ENABLED(CONFIG_NVDIMM_KEYS) int nvdimm_security_unlock(struct device *dev); #else diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 7315977b64da..ad609617aeb8 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -235,7 +235,6 @@ static inline struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, cmd_mask, num_flush, flush_wpq, NULL, NULL); } -int nvdimm_security_setup_events(struct nvdimm *nvdimm); const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd); u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, -- cgit v1.2.3-58-ga151 From 5e9e38d0db1d29efed1dd4cf9a70115d33521be7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 14 Jan 2019 14:07:19 -0800 Subject: acpi/nfit: Block function zero DSMs In preparation for using function number 0 as an error value, prevent it from being considered a valid function value by acpi_nfit_ctl(). Cc: Cc: stuart hayes Fixes: e02fb7264d8a ("nfit: add Microsoft NVDIMM DSM command set...") Reported-by: Jeff Moyer Reviewed-by: Jeff Moyer Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index c1fb06654749..ed05697a2b38 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1867,6 +1867,13 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, return 0; } + /* + * Function 0 is the command interrogation function, don't + * export it to potential userspace use, and enable it to be + * used as an error value in acpi_nfit_ctl(). + */ + dsm_mask &= ~1UL; + guid = to_nfit_uuid(nfit_mem->family); for_each_set_bit(i, &dsm_mask, BITS_PER_LONG) if (acpi_check_dsm(adev_dimm->handle, guid, -- cgit v1.2.3-58-ga151 From 11189c1089da413aa4b5fd6be4c4d47c78968819 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 19 Jan 2019 10:55:04 -0800 Subject: acpi/nfit: Fix command-supported detection The _DSM function number validation only happens to succeed when the generic Linux command number translation corresponds with a DSM-family-specific function number. This breaks NVDIMM-N implementations that correctly implement _LSR, _LSW, and _LSI, but do not happen to publish support for DSM function numbers 4, 5, and 6. Recall that the support for _LS{I,R,W} family of methods results in the DIMM being marked as supporting those command numbers at acpi_nfit_register_dimms() time. The DSM function mask is only used for ND_CMD_CALL support of non-NVDIMM_FAMILY_INTEL devices. Fixes: 31eca76ba2fc ("nfit, libnvdimm: limited/whitelisted dimm command...") Cc: Link: https://github.com/pmem/ndctl/issues/78 Reported-by: Sujith Pandel Tested-by: Sujith Pandel Reviewed-by: Vishal Verma Reviewed-by: Jeff Moyer Signed-off-by: Dan Williams --- drivers/acpi/nfit/core.c | 54 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index ed05697a2b38..e18ade5d74e9 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -409,6 +409,32 @@ static bool payload_dumpable(struct nvdimm *nvdimm, unsigned int func) return true; } +static int cmd_to_func(struct nfit_mem *nfit_mem, unsigned int cmd, + struct nd_cmd_pkg *call_pkg) +{ + if (call_pkg) { + int i; + + if (nfit_mem->family != call_pkg->nd_family) + return -ENOTTY; + + for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++) + if (call_pkg->nd_reserved2[i]) + return -EINVAL; + return call_pkg->nd_command; + } + + /* Linux ND commands == NVDIMM_FAMILY_INTEL function numbers */ + if (nfit_mem->family == NVDIMM_FAMILY_INTEL) + return cmd; + + /* + * Force function number validation to fail since 0 is never + * published as a valid function in dsm_mask. + */ + return 0; +} + int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) { @@ -422,30 +448,23 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned long cmd_mask, dsm_mask; u32 offset, fw_status = 0; acpi_handle handle; - unsigned int func; const guid_t *guid; - int rc, i; + int func, rc, i; if (cmd_rc) *cmd_rc = -EINVAL; - func = cmd; - if (cmd == ND_CMD_CALL) { - call_pkg = buf; - func = call_pkg->nd_command; - - for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++) - if (call_pkg->nd_reserved2[i]) - return -EINVAL; - } if (nvdimm) { struct acpi_device *adev = nfit_mem->adev; if (!adev) return -ENOTTY; - if (call_pkg && nfit_mem->family != call_pkg->nd_family) - return -ENOTTY; + if (cmd == ND_CMD_CALL) + call_pkg = buf; + func = cmd_to_func(nfit_mem, cmd, call_pkg); + if (func < 0) + return func; dimm_name = nvdimm_name(nvdimm); cmd_name = nvdimm_cmd_name(cmd); cmd_mask = nvdimm_cmd_mask(nvdimm); @@ -456,6 +475,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, } else { struct acpi_device *adev = to_acpi_dev(acpi_desc); + func = cmd; cmd_name = nvdimm_bus_cmd_name(cmd); cmd_mask = nd_desc->cmd_mask; dsm_mask = cmd_mask; @@ -470,7 +490,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, if (!desc || (cmd && (desc->out_num + desc->in_num == 0))) return -ENOTTY; - if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask)) + /* + * Check for a valid command. For ND_CMD_CALL, we also have to + * make sure that the DSM function is supported. + */ + if (cmd == ND_CMD_CALL && !test_bit(func, &dsm_mask)) + return -ENOTTY; + else if (!test_bit(cmd, &cmd_mask)) return -ENOTTY; in_obj.type = ACPI_TYPE_PACKAGE; -- cgit v1.2.3-58-ga151 From 910fdcabedd2354d161b1beab6ad7dc7e859651d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:32 +0900 Subject: ASoC: soc-core: add .num_platform for dai_link Current snd_soc_dai_link is starting to use snd_soc_dai_link_component (= modern) style for Platform, but it is still assuming single Platform so far. We will need to have multi Platform support in the not far future. Currently only simple card is using it as sound card driver, and other drivers are converted to it from legacy style by snd_soc_init_platform(). To avoid future problem of multi Platform support, let's add num_platforms before it is too late. In the same time, to make it same naming mothed, "platform" should be "platforms". This patch fixup it too. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- include/sound/soc.h | 3 ++- sound/soc/generic/audio-graph-card.c | 5 +++-- sound/soc/generic/simple-card-utils.c | 4 ++-- sound/soc/generic/simple-card.c | 7 ++++--- sound/soc/soc-core.c | 23 ++++++++++++++++------- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 6d69ed2bd7b1..ab5a2ba09c07 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -75,7 +75,7 @@ void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); &dai_link->codec_dai_name, \ list_name, cells_name, NULL) #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, dai_link->platform, \ + asoc_simple_card_parse_dai(node, dai_link->platforms, \ &dai_link->platform_of_node, \ NULL, list_name, cells_name, NULL) int asoc_simple_card_parse_dai(struct device_node *node, diff --git a/include/sound/soc.h b/include/sound/soc.h index c31b6d122ff6..3089257ead95 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -961,7 +961,8 @@ struct snd_soc_dai_link { */ const char *platform_name; struct device_node *platform_of_node; - struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link_component *platforms; + unsigned int num_platforms; int id; /* optional ID for machine driver link identification */ diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 3ec96cdc683b..42b077c6be4c 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -26,7 +26,7 @@ struct graph_priv { struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ - struct snd_soc_dai_link_component platform; + struct snd_soc_dai_link_component platforms; struct asoc_simple_card_data adata; struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; @@ -687,7 +687,8 @@ static int graph_probe(struct platform_device *pdev) for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; + dai_link[i].platforms = &dai_props[i].platforms; + dai_link[i].num_platforms = 1; } priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 336895f7fd1e..3c0901df5796 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -397,8 +397,8 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ - if (!dai_link->platform->of_node) - dai_link->platform->of_node = dai_link->cpu_of_node; + if (!dai_link->platforms->of_node) + dai_link->platforms->of_node = dai_link->cpu_of_node; return 0; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 479de236e694..d8a0d1ec256e 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -21,7 +21,7 @@ struct simple_priv { struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ - struct snd_soc_dai_link_component platform; + struct snd_soc_dai_link_component platforms; struct asoc_simple_card_data adata; struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; @@ -732,7 +732,8 @@ static int simple_probe(struct platform_device *pdev) for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; + dai_link[i].platforms = &dai_props[i].platforms; + dai_link[i].num_platforms = 1; } priv->dai_props = dai_props; @@ -782,7 +783,7 @@ static int simple_probe(struct platform_device *pdev) codecs->name = cinfo->codec; codecs->dai_name = cinfo->codec_dai.name; - platform = dai_link->platform; + platform = dai_link->platforms; platform->name = cinfo->platform; card->name = (cinfo->card) ? cinfo->card : cinfo->name; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index de2851f1b3df..2c63921675d5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -915,7 +915,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* find one from the set of registered platforms */ for_each_component(component) { - if (!snd_soc_is_matching_component(dai_link->platform, + if (!snd_soc_is_matching_component(dai_link->platforms, component)) continue; @@ -1026,7 +1026,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link_component *platform = dai_link->platform; + struct snd_soc_dai_link_component *platform = dai_link->platforms; /* * REMOVE ME @@ -1046,7 +1046,8 @@ static int snd_soc_init_platform(struct snd_soc_card *card, if (!platform) return -ENOMEM; - dai_link->platform = platform; + dai_link->platforms = platform; + dai_link->num_platforms = 1; dai_link->legacy_platform = 1; platform->name = dai_link->platform_name; platform->of_node = dai_link->platform_of_node; @@ -1136,11 +1137,19 @@ static int soc_init_dai_link(struct snd_soc_card *card, } } + /* FIXME */ + if (link->num_platforms > 1) { + dev_err(card->dev, + "ASoC: multi platform is not yet supported %s\n", + link->name); + return -EINVAL; + } + /* * Platform may be specified by either name or OF node, but * can be left unspecified, and a dummy platform will be used. */ - if (link->platform->name && link->platform->of_node) { + if (link->platforms->name && link->platforms->of_node) { dev_err(card->dev, "ASoC: Both platform name/of_node are set for %s\n", link->name); @@ -1151,8 +1160,8 @@ static int soc_init_dai_link(struct snd_soc_card *card, * Defer card registartion if platform dai component is not added to * component list. */ - if ((link->platform->of_node || link->platform->name) && - !soc_find_component(link->platform->of_node, link->platform->name)) + if ((link->platforms->of_node || link->platforms->name) && + !soc_find_component(link->platforms->of_node, link->platforms->name)) return -EPROBE_DEFER; /* @@ -1956,7 +1965,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) dev_err(card->dev, "init platform error"); continue; } - dai_link->platform->name = component->name; + dai_link->platforms->name = component->name; /* convert non BE into BE */ dai_link->no_pcm = 1; -- cgit v1.2.3-58-ga151 From 65462e445f78cb2f9378443be7ba8b7e07300694 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:37 +0900 Subject: ASoC: soc-core: add new snd_soc_flush_all_delayed_work() soc-core is calling flush_delayed_work() many times for same purpose. Same code in many places makes code un-understandable. This patch adds new snd_soc_flush_all_delayed_work() for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2c63921675d5..eeb794d8a262 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -425,6 +425,14 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); +static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + for_each_card_rtds(card, rtd) + flush_delayed_work(&rtd->delayed_work); +} + static void codec2codec_close_delayed_work(struct work_struct *work) { /* @@ -494,8 +502,7 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); for_each_card_rtds(card, rtd) { @@ -2228,11 +2235,8 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd; - /* make sure any delayed work runs */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); /* free the ALSA card at first; this syncs with pending operations */ snd_card_free(card->snd_card); @@ -2275,8 +2279,7 @@ int snd_soc_poweroff(struct device *dev) * Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); snd_soc_dapm_shutdown(card); -- cgit v1.2.3-58-ga151 From 53e947a0e1f770b9707febb7054b856878945d50 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:42 +0900 Subject: ASoC: soc-core: merge card resources cleanup method We need to cleanup card resources when snd_soc_instantiate_card() was failed, or when snd_soc_unbind_card() was called. But they are cleanuping card resources on each way. Same code in many places makes code un-understandable. This patch reuses soc_cleanup_card_resources() for cleanuping code resource. Then, it makes avoiding cleanup order. It will be called from snd_soc_instantiate_card() and snd_soc_unbind_card(). Then, original soc_cleanup_card_resources() included snd_soc_flush_all_delayed_work(), but it is now separated. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 103 +++++++++++++++++++++------------------------------ 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index eeb794d8a262..d59b5ea9fa25 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2008,6 +2008,29 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) } } +static int soc_cleanup_card_resources(struct snd_soc_card *card) +{ + /* free the ALSA card at first; this syncs with pending operations */ + if (card->snd_card) + snd_card_free(card->snd_card); + + /* remove and free each DAI */ + soc_remove_dai_links(card); + soc_remove_pcm_runtimes(card); + + /* remove auxiliary devices */ + soc_remove_aux_devices(card); + + snd_soc_dapm_free(&card->dapm); + soc_cleanup_card_debugfs(card); + + /* remove the card */ + if (card->remove) + card->remove(card); + + return 0; +} + static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -2017,6 +2040,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) mutex_lock(&client_mutex); mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); + card->dapm.bias_level = SND_SOC_BIAS_OFF; + card->dapm.dev = card->dev; + card->dapm.card = card; + list_add(&card->dapm.list, &card->dapm_list); + /* check whether any platform is ignore machine FE and using topology */ soc_check_tplg_fes(card); @@ -2024,14 +2052,14 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for_each_card_prelinks(card, i, dai_link) { ret = soc_bind_dai_link(card, dai_link); if (ret != 0) - goto base_error; + goto probe_end; } /* bind aux_devs too */ for (i = 0; i < card->num_aux_devs; i++) { ret = soc_bind_aux_dev(card, i); if (ret != 0) - goto base_error; + goto probe_end; } /* add predefined DAI links to the list */ @@ -2045,16 +2073,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: can't create sound card for card %s: %d\n", card->name, ret); - goto base_error; + goto probe_end; } soc_init_card_debugfs(card); - card->dapm.bias_level = SND_SOC_BIAS_OFF; - card->dapm.dev = card->dev; - card->dapm.card = card; - list_add(&card->dapm.list, &card->dapm_list); - #ifdef CONFIG_DEBUG_FS snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); #endif @@ -2076,7 +2099,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (card->probe) { ret = card->probe(card); if (ret < 0) - goto card_probe_error; + goto probe_end; } /* probe all components used by DAI links on this card */ @@ -2087,7 +2110,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: failed to instantiate card %d\n", ret); - goto probe_dai_err; + goto probe_end; } } } @@ -2095,7 +2118,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe auxiliary components */ ret = soc_probe_aux_devices(card); if (ret < 0) - goto probe_dai_err; + goto probe_end; /* * Find new DAI links added during probing components and bind them. @@ -2107,10 +2130,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ret = soc_init_dai_link(card, dai_link); if (ret) - goto probe_dai_err; + goto probe_end; ret = soc_bind_dai_link(card, dai_link); if (ret) - goto probe_dai_err; + goto probe_end; } /* probe all DAI links on this card */ @@ -2121,7 +2144,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: failed to instantiate card %d\n", ret); - goto probe_dai_err; + goto probe_end; } } } @@ -2168,7 +2191,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) { dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n", card->name, ret); - goto probe_aux_dev_err; + goto probe_end; } } @@ -2178,33 +2201,17 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) { dev_err(card->dev, "ASoC: failed to register soundcard %d\n", ret); - goto probe_aux_dev_err; + goto probe_end; } card->instantiated = 1; dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); - mutex_unlock(&card->mutex); - mutex_unlock(&client_mutex); - - return 0; -probe_aux_dev_err: - soc_remove_aux_devices(card); - -probe_dai_err: - soc_remove_dai_links(card); - -card_probe_error: - if (card->remove) - card->remove(card); - - snd_soc_dapm_free(&card->dapm); - soc_cleanup_card_debugfs(card); - snd_card_free(card->snd_card); +probe_end: + if (ret < 0) + soc_cleanup_card_resources(card); -base_error: - soc_remove_pcm_runtimes(card); mutex_unlock(&card->mutex); mutex_unlock(&client_mutex); @@ -2233,31 +2240,6 @@ static int soc_probe(struct platform_device *pdev) return snd_soc_register_card(card); } -static int soc_cleanup_card_resources(struct snd_soc_card *card) -{ - /* make sure any delayed work runs */ - snd_soc_flush_all_delayed_work(card); - - /* free the ALSA card at first; this syncs with pending operations */ - snd_card_free(card->snd_card); - - /* remove and free each DAI */ - soc_remove_dai_links(card); - soc_remove_pcm_runtimes(card); - - /* remove auxiliary devices */ - soc_remove_aux_devices(card); - - snd_soc_dapm_free(&card->dapm); - soc_cleanup_card_debugfs(card); - - /* remove the card */ - if (card->remove) - card->remove(card); - - return 0; -} - /* removes a socdev */ static int soc_remove(struct platform_device *pdev) { @@ -2823,6 +2805,7 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) if (card->instantiated) { card->instantiated = false; snd_soc_dapm_shutdown(card); + snd_soc_flush_all_delayed_work(card); soc_cleanup_card_resources(card); if (!unregister) list_add(&card->list, &unbind_card_list); -- cgit v1.2.3-58-ga151 From 52293596f5afff10d14e033aa3edfc801a31b3a1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:50 +0900 Subject: ASoC: soc-core: reduce if/else nest on soc_probe_link_dais Deep nested codec is not readable. Let's reduce if/else nest. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d59b5ea9fa25..7fc10a41e0e9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1612,27 +1612,24 @@ static int soc_probe_link_dais(struct snd_soc_card *card, dai_link->stream_name); return ret; } - } else { - - if (!dai_link->params) { - /* create the pcm */ - ret = soc_new_pcm(rtd, num); - if (ret < 0) { - dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", - dai_link->stream_name, ret); - return ret; - } - ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); - if (ret < 0) - return ret; - ret = soc_link_dai_pcm_new(rtd->codec_dais, - rtd->num_codecs, rtd); - if (ret < 0) - return ret; - } else { - INIT_DELAYED_WORK(&rtd->delayed_work, - codec2codec_close_delayed_work); + } else if (!dai_link->params) { + /* create the pcm */ + ret = soc_new_pcm(rtd, num); + if (ret < 0) { + dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", + dai_link->stream_name, ret); + return ret; } + ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); + if (ret < 0) + return ret; + ret = soc_link_dai_pcm_new(rtd->codec_dais, + rtd->num_codecs, rtd); + if (ret < 0) + return ret; + } else { + INIT_DELAYED_WORK(&rtd->delayed_work, + codec2codec_close_delayed_work); } return 0; -- cgit v1.2.3-58-ga151 From 22d1423187e5b4d9d5a9851f24466fc0f585a36f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:55 +0900 Subject: ASoC: soc-core: add soc_cleanup_component() We need to cleanup component when soc_probe_component() was failed, or when soc_remove_component() was called. But they are cleanuping component on each way. (And soc_probe_component() doesn't call snd_soc_dapm_free(), but it should). Same code in many places makes code un-understandable. This patch adds new soc_cleanup_component() and call it from snd_probe_component() and snd_remove_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7fc10a41e0e9..8a58fa86675a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -937,21 +937,24 @@ _err_defer: return -EPROBE_DEFER; } +static void soc_cleanup_component(struct snd_soc_component *component) +{ + list_del(&component->card_list); + snd_soc_dapm_free(snd_soc_component_get_dapm(component)); + soc_cleanup_component_debugfs(component); + component->card = NULL; + module_put(component->dev->driver->owner); +} + static void soc_remove_component(struct snd_soc_component *component) { if (!component->card) return; - list_del(&component->card_list); - if (component->driver->remove) component->driver->remove(component); - snd_soc_dapm_free(snd_soc_component_get_dapm(component)); - - soc_cleanup_component_debugfs(component); - component->card = NULL; - module_put(component->dev->driver->owner); + soc_cleanup_component(component); } static void soc_remove_dai(struct snd_soc_dai *dai, int order) @@ -1360,6 +1363,8 @@ static int soc_probe_component(struct snd_soc_card *card, component->card = card; dapm->card = card; + INIT_LIST_HEAD(&component->card_list); + INIT_LIST_HEAD(&dapm->list); soc_set_name_prefix(card, component); soc_init_component_debugfs(component); @@ -1422,12 +1427,9 @@ static int soc_probe_component(struct snd_soc_card *card, /* see for_each_card_components */ list_add(&component->card_list, &card->component_dev_list); - return 0; - err_probe: - soc_cleanup_component_debugfs(component); - component->card = NULL; - module_put(component->dev->driver->owner); + if (ret < 0) + soc_cleanup_component(component); return ret; } -- cgit v1.2.3-58-ga151 From 10dff9b0ddf70bebe9523fc311ec77a872ce0a9c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:59 +0900 Subject: ASoC: soc-core: use for_each_link_codecs() for dai_link codecs We can use for_each_link_codecs() without waiting for_each_rtd_codec_dai() on soc_bind_dai_link(). Let's use for_each macro Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8a58fa86675a..1c92b4aff57b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,9 +905,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ - /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for (i = 0; i < rtd->num_codecs; i++) { + for_each_link_codecs(dai_link, i, codecs) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", -- cgit v1.2.3-58-ga151 From fe7ed4dec2e6289eab81dd18c0d613c0851d85a1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 16:40:59 +0900 Subject: ASoC: simple-card: rename to asoc_simple_card_canonicalize_platform() Current simple-card is using asoc_simple_card_canonicalize_dailink(). Its naming is "dailink", but is for "platform". We already have asoc_simple_card_canonicalize_cpu() for "cpu", let's follow same naming rule. It never return error, so, void function is better idea. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/audio-graph-card.c | 11 +++-------- sound/soc/generic/simple-card-utils.c | 7 ++----- sound/soc/generic/simple-card.c | 11 +++-------- 4 files changed, 9 insertions(+), 22 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ab5a2ba09c07..7afe45389972 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -108,7 +108,7 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep, int asoc_simple_card_init_dai(struct snd_soc_dai *dai, struct asoc_simple_dai *simple_dai); -int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link); +void asoc_simple_card_canonicalize_platform(struct snd_soc_dai_link *dai_link); void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, int is_single_links); diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 42b077c6be4c..bb12351330e8 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -307,14 +307,12 @@ static int graph_dai_link_of_dpcm(struct graph_priv *priv, "prefix"); } + asoc_simple_card_canonicalize_platform(dai_link); + ret = asoc_simple_card_of_parse_tdm(ep, dai); if (ret) return ret; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, NULL, &dai_link->dai_fmt); if (ret < 0) @@ -405,10 +403,6 @@ static int graph_dai_link_of(struct graph_priv *priv, if (ret < 0) return ret; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, @@ -419,6 +413,7 @@ static int graph_dai_link_of(struct graph_priv *priv, dai_link->ops = &graph_ops; dai_link->init = graph_dai_init; + asoc_simple_card_canonicalize_platform(dai_link); asoc_simple_card_canonicalize_cpu(dai_link, of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 3c0901df5796..5c1424f03620 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -394,16 +394,13 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); -int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) +void asoc_simple_card_canonicalize_platform(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ if (!dai_link->platforms->of_node) dai_link->platforms->of_node = dai_link->cpu_of_node; - - return 0; - } -EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink); +EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_platform); void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, int is_single_links) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d8a0d1ec256e..08df261024cf 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -297,14 +297,12 @@ static int simple_dai_link_of_dpcm(struct simple_priv *priv, simple_get_conversion(dev, np, &dai_props->adata); + asoc_simple_card_canonicalize_platform(dai_link); + ret = asoc_simple_card_of_parse_tdm(np, dai); if (ret) return ret; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - snprintf(prop, sizeof(prop), "%smclk-fs", prefix); of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(node, prop, &dai_props->mclk_fs); @@ -409,10 +407,6 @@ static int simple_dai_link_of(struct simple_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - goto dai_link_of_err; - ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, @@ -424,6 +418,7 @@ static int simple_dai_link_of(struct simple_priv *priv, dai_link->init = simple_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); + asoc_simple_card_canonicalize_platform(dai_link); dai_link_of_err: of_node_put(node); -- cgit v1.2.3-58-ga151 From 6d87dc97eb3341de3f7b1efa3156cb0e014f4a96 Mon Sep 17 00:00:00 2001 From: Kenneth Feng Date: Fri, 18 Jan 2019 18:08:19 +0800 Subject: drm/amd/powerplay: OD setting fix on Vega10 gfxclk for OD setting is limited to 1980M for non-acg ASICs of Vega10 Signed-off-by: Kenneth Feng Reviewed-by: Evan Quan Signed-off-by: Alex Deucher --- .../amd/powerplay/hwmgr/vega10_processpptables.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c index b8747a5c9204..99d596dc0e89 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_processpptables.c @@ -32,6 +32,7 @@ #include "vega10_pptable.h" #define NUM_DSPCLK_LEVELS 8 +#define VEGA10_ENGINECLOCK_HARDMAX 198000 static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable, enum phm_platform_caps cap) @@ -258,7 +259,26 @@ static int init_over_drive_limits( struct pp_hwmgr *hwmgr, const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) { - hwmgr->platform_descriptor.overdriveLimit.engineClock = + const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table = + (const ATOM_Vega10_GFXCLK_Dependency_Table *) + (((unsigned long) powerplay_table) + + le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset)); + bool is_acg_enabled = false; + ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_v2; + + if (gfxclk_dep_table->ucRevId == 1) { + patom_record_v2 = + (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)gfxclk_dep_table->entries; + is_acg_enabled = + (bool)patom_record_v2[gfxclk_dep_table->ucNumEntries-1].ucACGEnable; + } + + if (powerplay_table->ulMaxODEngineClock > VEGA10_ENGINECLOCK_HARDMAX && + !is_acg_enabled) + hwmgr->platform_descriptor.overdriveLimit.engineClock = + VEGA10_ENGINECLOCK_HARDMAX; + else + hwmgr->platform_descriptor.overdriveLimit.engineClock = le32_to_cpu(powerplay_table->ulMaxODEngineClock); hwmgr->platform_descriptor.overdriveLimit.memoryClock = le32_to_cpu(powerplay_table->ulMaxODMemoryClock); -- cgit v1.2.3-58-ga151 From f8ff6c732d35904d773043f979b844ef330c701b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 20 Dec 2018 17:16:53 +0100 Subject: ide: fix a typo in the settings proc file name Fixes: ec7d9c9ce8 ("ide: replace ->proc_fops with ->proc_show") Reported-by: kernel test robot Signed-off-by: Christoph Hellwig Signed-off-by: Linus Torvalds --- drivers/ide/ide-proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 4c8c7a620d08..a5dc13576394 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -544,7 +544,7 @@ void ide_proc_port_register_devices(ide_hwif_t *hwif) drive->proc = proc_mkdir(drive->name, parent); if (drive->proc) { ide_add_proc_entries(drive->proc, generic_drive_entries, drive); - proc_create_data("setting", S_IFREG|S_IRUSR|S_IWUSR, + proc_create_data("settings", S_IFREG|S_IRUSR|S_IWUSR, drive->proc, &ide_settings_proc_fops, drive); } -- cgit v1.2.3-58-ga151 From 71e3e00c96efa851b2d5d3a3731711f9cc958b5b Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Fri, 18 Jan 2019 14:32:23 +0100 Subject: mmc: meson-gx: enable signal re-sampling together with tuning card detection fails on "BeeLink Mini M8 SII" if enabled too early mmc1: error -110 whilst initialising MMC card Fixes: 71645e65729f ("mmc: meson-gx: add signal resampling") Signed-off-by: Andreas Fenkart Reviewed-by: Jerome Brunet Tested-by: Jerome Brunet Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-gx-mmc.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index f115d7c63ffe..f19ec60bcbdc 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -740,6 +740,11 @@ static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode, static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct meson_host *host = mmc_priv(mmc); + int adj = 0; + + /* enable signal resampling w/o delay */ + adj = ADJUST_ADJ_EN; + writel(adj, host->regs + host->data->adjust); return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); } @@ -770,6 +775,9 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (!IS_ERR(mmc->supply.vmmc)) mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); + /* disable signal resampling */ + writel(0, host->regs + host->data->adjust); + /* Reset rx phase */ clk_set_phase(host->rx_clk, 0); @@ -1168,7 +1176,7 @@ static int meson_mmc_get_cd(struct mmc_host *mmc) static void meson_mmc_cfg_init(struct meson_host *host) { - u32 cfg = 0, adj = 0; + u32 cfg = 0; cfg |= FIELD_PREP(CFG_RESP_TIMEOUT_MASK, ilog2(SD_EMMC_CFG_RESP_TIMEOUT)); @@ -1179,10 +1187,6 @@ static void meson_mmc_cfg_init(struct meson_host *host) cfg |= CFG_ERR_ABORT; writel(cfg, host->regs + SD_EMMC_CFG); - - /* enable signal resampling w/o delay */ - adj = ADJUST_ADJ_EN; - writel(adj, host->regs + host->data->adjust); } static int meson_mmc_card_busy(struct mmc_host *mmc) -- cgit v1.2.3-58-ga151 From f3716b8ae9347797b73896725f192c3a7b0069b5 Mon Sep 17 00:00:00 2001 From: Liming Sun Date: Fri, 18 Jan 2019 13:12:06 -0500 Subject: mmc: dw_mmc-bluefield: : Fix the license information The SPDX license identifier and the boiler plate text are contradicting. Only the SPDX license identifier is needed. The other one is removed. Fixes: 86958dcc5ad7 ("mmc: dw_mmc-bluefield: Add driver extension") Cc: stable@vger.kernel.org Reviewed-by: David Woods Signed-off-by: Liming Sun Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-bluefield.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/mmc/host/dw_mmc-bluefield.c b/drivers/mmc/host/dw_mmc-bluefield.c index ed8f2254b66a..aa38b1a8017e 100644 --- a/drivers/mmc/host/dw_mmc-bluefield.c +++ b/drivers/mmc/host/dw_mmc-bluefield.c @@ -1,11 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2018 Mellanox Technologies. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include -- cgit v1.2.3-58-ga151 From e8a6ca808c5ed1e2b43ab25f1f2cbd43a7574f73 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Fri, 18 Jan 2019 16:23:05 -0800 Subject: tty: serial: qcom_geni_serial: Allow mctrl when flow control is disabled The geni set/get_mctrl() functions currently do nothing unless hardware flow control is enabled. Remove this arbitrary limitation. Suggested-by: Johan Hovold Fixes: 8a8a66a1a18a ("tty: serial: qcom_geni_serial: Add support for flow control") Signed-off-by: Matthias Kaehlcke Reviewed-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index a72d6d9fb983..38016609c7fa 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -225,7 +225,7 @@ static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport) unsigned int mctrl = TIOCM_DSR | TIOCM_CAR; u32 geni_ios; - if (uart_console(uport) || !uart_cts_enabled(uport)) { + if (uart_console(uport)) { mctrl |= TIOCM_CTS; } else { geni_ios = readl_relaxed(uport->membase + SE_GENI_IOS); @@ -241,7 +241,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, { u32 uart_manual_rfr = 0; - if (uart_console(uport) || !uart_cts_enabled(uport)) + if (uart_console(uport)) return; if (!(mctrl & TIOCM_RTS)) -- cgit v1.2.3-58-ga151 From 815d835b7ba46685c316b000013367dacb2b461b Mon Sep 17 00:00:00 2001 From: Tomonori Sakita Date: Mon, 21 Jan 2019 17:34:16 +0900 Subject: serial: fsl_lpuart: fix maximum acceptable baud rate with over-sampling Using over-sampling ratio, lpuart can accept baud rate upto uartclk / 4. Signed-off-by: Tomonori Sakita Signed-off-by: Atsushi Nemoto Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 241a48e5052c..debdd1b9e01a 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1697,7 +1697,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, } /* ask the core to calculate the divisor */ - baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); + baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 4); spin_lock_irqsave(&sport->port.lock, flags); -- cgit v1.2.3-58-ga151 From 5e1bc251cebc84b41b8eb5d2434e54d939a85430 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 22 Jan 2019 09:32:32 +0200 Subject: drm/sun4i: hdmi: Fix usage of TMDS clock Although TMDS clock is required for HDMI to properly function, nobody called clk_prepare_enable(). This fixes reference counting issues and makes sure clock is running when it needs to be running. Due to TDMS clock being parent clock for DDC clock, TDMS clock was turned on/off for each EDID probe, causing spurious failures for certain HDMI/DVI screens. Fixes: 9c5681011a0c ("drm/sun4i: Add HDMI support") Signed-off-by: Priit Laes [Maxime: Moved the TMDS clock enable earlier] Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20190122073232.7240-1-plaes@plaes.org --- drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index 061d2e0d9011..416da5376701 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -92,6 +92,8 @@ static void sun4i_hdmi_disable(struct drm_encoder *encoder) val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG); val &= ~SUN4I_HDMI_VID_CTRL_ENABLE; writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG); + + clk_disable_unprepare(hdmi->tmds_clk); } static void sun4i_hdmi_enable(struct drm_encoder *encoder) @@ -102,6 +104,8 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder) DRM_DEBUG_DRIVER("Enabling the HDMI Output\n"); + clk_prepare_enable(hdmi->tmds_clk); + sun4i_hdmi_setup_avi_infoframes(hdmi, mode); val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI); val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END); -- cgit v1.2.3-58-ga151 From 7b12c8189a3dc50638e7d53714c88007268d47ef Mon Sep 17 00:00:00 2001 From: Manfred Schlaegl Date: Wed, 19 Dec 2018 19:39:58 +0100 Subject: can: dev: __can_get_echo_skb(): fix bogous check for non-existing skb by removing it This patch revert commit 7da11ba5c506 ("can: dev: __can_get_echo_skb(): print error message, if trying to echo non existing skb") After introduction of this change we encountered following new error message on various i.MX plattforms (flexcan): | flexcan 53fc8000.can can0: __can_get_echo_skb: BUG! Trying to echo non | existing skb: can_priv::echo_skb[0] The introduction of the message was a mistake because priv->echo_skb[idx] = NULL is a perfectly valid in following case: If CAN_RAW_LOOPBACK is disabled (setsockopt) in applications, the pkt_type of the tx skb's given to can_put_echo_skb is set to PACKET_LOOPBACK. In this case can_put_echo_skb will not set priv->echo_skb[idx]. It is therefore kept NULL. As additional argument for revert: The order of check and usage of idx was changed. idx is used to access an array element before checking it's boundaries. Signed-off-by: Manfred Schlaegl Fixes: 7da11ba5c506 ("can: dev: __can_get_echo_skb(): print error message, if trying to echo non existing skb") Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 3b3f88ffab53..c05e4d50d43d 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -480,8 +480,6 @@ EXPORT_SYMBOL_GPL(can_put_echo_skb); struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr) { struct can_priv *priv = netdev_priv(dev); - struct sk_buff *skb = priv->echo_skb[idx]; - struct canfd_frame *cf; if (idx >= priv->echo_skb_max) { netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n", @@ -489,20 +487,21 @@ struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 return NULL; } - if (!skb) { - netdev_err(dev, "%s: BUG! Trying to echo non existing skb: can_priv::echo_skb[%u]\n", - __func__, idx); - return NULL; - } + if (priv->echo_skb[idx]) { + /* Using "struct canfd_frame::len" for the frame + * length is supported on both CAN and CANFD frames. + */ + struct sk_buff *skb = priv->echo_skb[idx]; + struct canfd_frame *cf = (struct canfd_frame *)skb->data; + u8 len = cf->len; - /* Using "struct canfd_frame::len" for the frame - * length is supported on both CAN and CANFD frames. - */ - cf = (struct canfd_frame *)skb->data; - *len_ptr = cf->len; - priv->echo_skb[idx] = NULL; + *len_ptr = len; + priv->echo_skb[idx] = NULL; - return skb; + return skb; + } + + return NULL; } /* -- cgit v1.2.3-58-ga151 From 93171ba6f1deffd82f381d36cb13177872d023f6 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 13 Jan 2019 19:31:43 +0100 Subject: can: bcm: check timer values before ktime conversion Kyungtae Kim detected a potential integer overflow in bcm_[rx|tx]_setup() when the conversion into ktime multiplies the given value with NSEC_PER_USEC (1000). Reference: https://marc.info/?l=linux-can&m=154732118819828&w=2 Add a check for the given tv_usec, so that the value stays below one second. Additionally limit the tv_sec value to a reasonable value for CAN related use-cases of 400 days and ensure all values to be positive. Reported-by: Kyungtae Kim Tested-by: Oliver Hartkopp Signed-off-by: Oliver Hartkopp Cc: linux-stable # >= 2.6.26 Tested-by: Kyungtae Kim Acked-by: Andre Naujoks Signed-off-by: Marc Kleine-Budde --- net/can/bcm.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/net/can/bcm.c b/net/can/bcm.c index 0af8f0db892a..79bb8afa9c0c 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -67,6 +67,9 @@ */ #define MAX_NFRAMES 256 +/* limit timers to 400 days for sending/timeouts */ +#define BCM_TIMER_SEC_MAX (400 * 24 * 60 * 60) + /* use of last_frames[index].flags */ #define RX_RECV 0x40 /* received data for this element */ #define RX_THR 0x80 /* element not been sent due to throttle feature */ @@ -140,6 +143,22 @@ static inline ktime_t bcm_timeval_to_ktime(struct bcm_timeval tv) return ktime_set(tv.tv_sec, tv.tv_usec * NSEC_PER_USEC); } +/* check limitations for timeval provided by user */ +static bool bcm_is_invalid_tv(struct bcm_msg_head *msg_head) +{ + if ((msg_head->ival1.tv_sec < 0) || + (msg_head->ival1.tv_sec > BCM_TIMER_SEC_MAX) || + (msg_head->ival1.tv_usec < 0) || + (msg_head->ival1.tv_usec >= USEC_PER_SEC) || + (msg_head->ival2.tv_sec < 0) || + (msg_head->ival2.tv_sec > BCM_TIMER_SEC_MAX) || + (msg_head->ival2.tv_usec < 0) || + (msg_head->ival2.tv_usec >= USEC_PER_SEC)) + return true; + + return false; +} + #define CFSIZ(flags) ((flags & CAN_FD_FRAME) ? CANFD_MTU : CAN_MTU) #define OPSIZ sizeof(struct bcm_op) #define MHSIZ sizeof(struct bcm_msg_head) @@ -873,6 +892,10 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, if (msg_head->nframes < 1 || msg_head->nframes > MAX_NFRAMES) return -EINVAL; + /* check timeval limitations */ + if ((msg_head->flags & SETTIMER) && bcm_is_invalid_tv(msg_head)) + return -EINVAL; + /* check the given can_id */ op = bcm_find_op(&bo->tx_ops, msg_head, ifindex); if (op) { @@ -1053,6 +1076,10 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, (!(msg_head->can_id & CAN_RTR_FLAG)))) return -EINVAL; + /* check timeval limitations */ + if ((msg_head->flags & SETTIMER) && bcm_is_invalid_tv(msg_head)) + return -EINVAL; + /* check the given can_id */ op = bcm_find_op(&bo->rx_ops, msg_head, ifindex); if (op) { -- cgit v1.2.3-58-ga151 From 7873e98c614aa8dd2c3429aa2e25dc0e9ccadffa Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 12 Dec 2018 17:24:01 +0800 Subject: can: flexcan: fix 'passing zero to ERR_PTR()' warning Fix a static code checker warning: drivers/net/can/flexcan.c:1435 flexcan_setup_stop_mode() warn: passing zero to 'PTR_ERR' Fixes: de3578c198c6 ("can: flexcan: add self wakeup support") Signed-off-by: YueHaibing Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 0f36eafe3ac1..5f097648d12d 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -1432,7 +1432,7 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) gpr_np = of_find_node_by_phandle(phandle); if (!gpr_np) { dev_dbg(&pdev->dev, "could not find gpr node by phandle\n"); - return PTR_ERR(gpr_np); + return -ENODEV; } priv = netdev_priv(dev); -- cgit v1.2.3-58-ga151 From a55234dabe1f72cf22f9197980751d37e38ba020 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 11 Jan 2019 12:20:41 +0100 Subject: can: flexcan: fix NULL pointer exception during bringup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit cbffaf7aa09e ("can: flexcan: Always use last mailbox for TX") introduced a loop letting i run up to (including) ARRAY_SIZE(regs->mb) and in the body accessed regs->mb[i] which is an out-of-bounds array access that then resulted in an access to an reserved register area. Later this was changed by commit 0517961ccdf1 ("can: flexcan: Add provision for variable payload size") to iterate a bit differently but still runs one iteration too much resulting to call flexcan_get_mb(priv, priv->mb_count) which results in a WARN_ON and then a NULL pointer exception. This only affects devices compatible with "fsl,p1010-flexcan", "fsl,imx53-flexcan", "fsl,imx35-flexcan", "fsl,imx25-flexcan", "fsl,imx28-flexcan", so newer i.MX SoCs are not affected. Fixes: cbffaf7aa09e ("can: flexcan: Always use last mailbox for TX") Signed-off-by: Uwe Kleine-König Cc: linux-stable # >= 4.20 Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 5f097648d12d..1c66fb2ad76b 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -1106,7 +1106,7 @@ static int flexcan_chip_start(struct net_device *dev) } } else { /* clear and invalidate unused mailboxes first */ - for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i <= priv->mb_count; i++) { + for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i < priv->mb_count; i++) { mb = flexcan_get_mb(priv, i); priv->write(FLEXCAN_MB_CODE_RX_INACTIVE, &mb->can_ctrl); -- cgit v1.2.3-58-ga151 From 31eb79db420a3f94c4c45a8c0a05cd30e333f981 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Fri, 18 Jan 2019 10:37:44 -0800 Subject: staging: android: ion: Support cpu access during dma_buf_detach Often userspace doesn't know when the kernel will be calling dma_buf_detach on the buffer. If userpace starts its CPU access at the same time as the sg list is being freed it could end up accessing the sg list after it has been freed. Thread A Thread B - DMA_BUF_IOCTL_SYNC IOCT - ion_dma_buf_begin_cpu_access - list_for_each_entry - ion_dma_buf_detatch - free_duped_table - dma_sync_sg_for_cpu Fix this by getting the ion_buffer lock before freeing the sg table memory. Fixes: 2a55e7b5e544 ("staging: android: ion: Call dma_map_sg for syncing and mapping") Signed-off-by: Liam Mark Acked-by: Laura Abbott Acked-by: Andrew F. Davis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index a0802de8c3a1..6f5afab7c1a1 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -248,10 +248,10 @@ static void ion_dma_buf_detatch(struct dma_buf *dmabuf, struct ion_dma_buf_attachment *a = attachment->priv; struct ion_buffer *buffer = dmabuf->priv; - free_duped_table(a->table); mutex_lock(&buffer->lock); list_del(&a->list); mutex_unlock(&buffer->lock); + free_duped_table(a->table); kfree(a); } -- cgit v1.2.3-58-ga151 From 6fc23b6ed8fa0ba6cc47b2f8756df1199abc3a5c Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 12:01:19 +0100 Subject: binderfs: use correct include guards in header When we switched over from binder_ctl.h to binderfs.h we forgot to change the include guards. It's minor but it's obviously correct. Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/android/binderfs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/android/binderfs.h b/include/uapi/linux/android/binderfs.h index 65b2efd1a0a5..b41628b77120 100644 --- a/include/uapi/linux/android/binderfs.h +++ b/include/uapi/linux/android/binderfs.h @@ -4,8 +4,8 @@ * */ -#ifndef _UAPI_LINUX_BINDER_CTL_H -#define _UAPI_LINUX_BINDER_CTL_H +#ifndef _UAPI_LINUX_BINDERFS_H +#define _UAPI_LINUX_BINDERFS_H #include #include @@ -31,5 +31,5 @@ struct binderfs_device { */ #define BINDER_CTL_ADD _IOWR('b', 1, struct binderfs_device) -#endif /* _UAPI_LINUX_BINDER_CTL_H */ +#endif /* _UAPI_LINUX_BINDERFS_H */ -- cgit v1.2.3-58-ga151 From 7d0174065f4903fb0ce0bab3d5047284faa7226d Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 12:01:20 +0100 Subject: binderfs: use __u32 for device numbers We allow more then 255 binderfs binder devices to be created since there are workloads that require more than that. If we use __u8 we'll overflow after 255. So let's use a __u32. Note that there's no released kernel with binderfs out there so this is not a regression. Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/android/binderfs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/android/binderfs.h b/include/uapi/linux/android/binderfs.h index b41628b77120..87410477aea9 100644 --- a/include/uapi/linux/android/binderfs.h +++ b/include/uapi/linux/android/binderfs.h @@ -22,8 +22,8 @@ */ struct binderfs_device { char name[BINDERFS_MAX_NAME + 1]; - __u8 major; - __u8 minor; + __u32 major; + __u32 minor; }; /** -- cgit v1.2.3-58-ga151 From 7c4d08fc4d5aca073bd4ebecbb9eda5e4d858b71 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:02 +0100 Subject: binderfs: remove outdated comment The comment stems from an early version of that patchset and is just confusing now. Cc: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index e4ff4c3fa371..898d847f8505 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -373,10 +373,6 @@ static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry, static int binderfs_unlink(struct inode *dir, struct dentry *dentry) { - /* - * The control dentry is only ever touched during mount so checking it - * here should not require us to take lock. - */ if (BINDERFS_I(dir)->control_dentry == dentry) return -EPERM; -- cgit v1.2.3-58-ga151 From e98e6fa18636609f14a7f866524950a783cf4fbf Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:03 +0100 Subject: binderfs: prevent renaming the control dentry - make binderfs control dentry immutable: We don't allow to unlink it since it is crucial for binderfs to be useable but if we allow to rename it we make the unlink trivial to bypass. So prevent renaming too and simply treat the control dentry as immutable. - add is_binderfs_control_device() helper: Take the opportunity and turn the check for the control dentry into a separate helper is_binderfs_control_device() since it's now used in two places. - simplify binderfs_rename(): Instead of hand-rolling our custom version of simple_rename() just dumb the whole function down to first check whether we're trying to rename the control dentry. If we do EPERM the caller and if not call simple_rename(). Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 898d847f8505..e73f9dbee099 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -346,34 +346,26 @@ static const struct super_operations binderfs_super_ops = { .statfs = simple_statfs, }; +static inline bool is_binderfs_control_device(const struct dentry *dentry) +{ + struct binderfs_info *info = dentry->d_sb->s_fs_info; + return info->control_dentry == dentry; +} + static int binderfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { - struct inode *inode = d_inode(old_dentry); - - /* binderfs doesn't support directories. */ - if (d_is_dir(old_dentry)) + if (is_binderfs_control_device(old_dentry) || + is_binderfs_control_device(new_dentry)) return -EPERM; - if (flags & ~RENAME_NOREPLACE) - return -EINVAL; - - if (!simple_empty(new_dentry)) - return -ENOTEMPTY; - - if (d_really_is_positive(new_dentry)) - simple_unlink(new_dir, new_dentry); - - old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime = - new_dir->i_mtime = inode->i_ctime = current_time(old_dir); - - return 0; + return simple_rename(old_dir, old_dentry, new_dir, new_dentry, flags); } static int binderfs_unlink(struct inode *dir, struct dentry *dentry) { - if (BINDERFS_I(dir)->control_dentry == dentry) + if (is_binderfs_control_device(dentry)) return -EPERM; return simple_unlink(dir, dentry); -- cgit v1.2.3-58-ga151 From 36975fc3e5f241cc4f45df4ab4624d7d5199d9ed Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:04 +0100 Subject: binderfs: rework binderfs_fill_super() Al pointed out that on binderfs_fill_super() error deactivate_locked_super() will call binderfs_kill_super() so all of the freeing and putting we currently do in binderfs_fill_super() is unnecessary and buggy. Let's simply return errors and let binderfs_fill_super() take care of cleaning up on error. Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index e73f9dbee099..89a2ee1a02f6 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -461,12 +461,9 @@ static const struct inode_operations binderfs_dir_inode_operations = { static int binderfs_fill_super(struct super_block *sb, void *data, int silent) { + int ret; struct binderfs_info *info; - int ret = -ENOMEM; struct inode *inode = NULL; - struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; - - get_ipc_ns(ipc_ns); sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; @@ -488,15 +485,17 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_op = &binderfs_super_ops; sb->s_time_gran = 1; - info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); - if (!info) - goto err_without_dentry; + sb->s_fs_info = kzalloc(sizeof(struct binderfs_info), GFP_KERNEL); + if (!sb->s_fs_info) + return -ENOMEM; + info = sb->s_fs_info; + + info->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns); ret = binderfs_parse_mount_opts(data, &info->mount_opts); if (ret) - goto err_without_dentry; + return ret; - info->ipc_ns = ipc_ns; info->root_gid = make_kgid(sb->s_user_ns, 0); if (!gid_valid(info->root_gid)) info->root_gid = GLOBAL_ROOT_GID; @@ -504,12 +503,9 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) if (!uid_valid(info->root_uid)) info->root_uid = GLOBAL_ROOT_UID; - sb->s_fs_info = info; - - ret = -ENOMEM; inode = new_inode(sb); if (!inode) - goto err_without_dentry; + return -ENOMEM; inode->i_ino = FIRST_INODE; inode->i_fop = &simple_dir_operations; @@ -520,24 +516,9 @@ static int binderfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_root = d_make_root(inode); if (!sb->s_root) - goto err_without_dentry; - - ret = binderfs_binder_ctl_create(sb); - if (ret) - goto err_with_dentry; - - return 0; - -err_with_dentry: - dput(sb->s_root); - sb->s_root = NULL; - -err_without_dentry: - put_ipc_ns(ipc_ns); - iput(inode); - kfree(info); + return -ENOMEM; - return ret; + return binderfs_binder_ctl_create(sb); } static struct dentry *binderfs_mount(struct file_system_type *fs_type, -- cgit v1.2.3-58-ga151 From 01b3f1fc568352a1ffdcd3ee82a0297f16cc9bd9 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:05 +0100 Subject: binderfs: rework binderfs_binder_device_create() - switch from d_alloc_name() + d_lookup() to lookup_one_len(): Instead of using d_alloc_name() and then doing a d_lookup() with the allocated dentry to find whether a device with the name we're trying to create already exists switch to using lookup_one_len(). The latter will either return the existing dentry or a new one. - switch from kmalloc() + strscpy() to kmemdup(): Use a more idiomatic way to copy the name for the new dentry that userspace gave us. Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 89a2ee1a02f6..1e077498a507 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -106,7 +107,7 @@ bool is_binderfs_device(const struct inode *inode) * @userp: buffer to copy information about new device for userspace to * @req: struct binderfs_device as copied from userspace * - * This function allocated a new binder_device and reserves a new minor + * This function allocates a new binder_device and reserves a new minor * number for it. * Minor numbers are limited and tracked globally in binderfs_minors. The * function will stash a struct binder_device for the specific binder @@ -122,10 +123,10 @@ static int binderfs_binder_device_create(struct inode *ref_inode, struct binderfs_device *req) { int minor, ret; - struct dentry *dentry, *dup, *root; + struct dentry *dentry, *root; struct binder_device *device; - size_t name_len = BINDERFS_MAX_NAME + 1; char *name = NULL; + size_t name_len; struct inode *inode = NULL; struct super_block *sb = ref_inode->i_sb; struct binderfs_info *info = sb->s_fs_info; @@ -168,12 +169,13 @@ static int binderfs_binder_device_create(struct inode *ref_inode, inode->i_uid = info->root_uid; inode->i_gid = info->root_gid; - name = kmalloc(name_len, GFP_KERNEL); + req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */ + name_len = strlen(req->name); + /* Make sure to include terminating NUL byte */ + name = kmemdup(req->name, name_len + 1, GFP_KERNEL); if (!name) goto err; - strscpy(name, req->name, name_len); - device->binderfs_inode = inode; device->context.binder_context_mgr_uid = INVALID_UID; device->context.name = name; @@ -192,24 +194,21 @@ static int binderfs_binder_device_create(struct inode *ref_inode, root = sb->s_root; inode_lock(d_inode(root)); - dentry = d_alloc_name(root, name); - if (!dentry) { + + /* look it up */ + dentry = lookup_one_len(name, root, name_len); + if (IS_ERR(dentry)) { inode_unlock(d_inode(root)); - ret = -ENOMEM; + ret = PTR_ERR(dentry); goto err; } - /* Verify that the name userspace gave us is not already in use. */ - dup = d_lookup(root, &dentry->d_name); - if (dup) { - if (d_really_is_positive(dup)) { - dput(dup); - dput(dentry); - inode_unlock(d_inode(root)); - ret = -EEXIST; - goto err; - } - dput(dup); + if (d_really_is_positive(dentry)) { + /* already exists */ + dput(dentry); + inode_unlock(d_inode(root)); + ret = -EEXIST; + goto err; } inode->i_private = device; -- cgit v1.2.3-58-ga151 From 4198479524aeccaf53c3a4cc73784982535573fa Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:06 +0100 Subject: binderfs: kill_litter_super() before cleanup Al pointed out that first calling kill_litter_super() before cleaning up info is more correct since destroying info doesn't depend on the state of the dentries and inodes. That the opposite remains true is not guaranteed. Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 1e077498a507..ba88be172aee 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -531,11 +531,12 @@ static void binderfs_kill_super(struct super_block *sb) { struct binderfs_info *info = sb->s_fs_info; + kill_litter_super(sb); + if (info && info->ipc_ns) put_ipc_ns(info->ipc_ns); kfree(info); - kill_litter_super(sb); } static struct file_system_type binder_fs_type = { -- cgit v1.2.3-58-ga151 From 29ef1c8e16aed079ac09989d752e38d412b6e1a8 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:07 +0100 Subject: binderfs: drop lock in binderfs_binder_ctl_create The binderfs_binder_ctl_create() call is a no-op on subsequent calls and the first call is done before we unlock the suberblock. Hence, there is no need to take inode_lock() in there. Let's remove it. Suggested-by: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index ba88be172aee..d537dcdb5d65 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -400,8 +400,6 @@ static int binderfs_binder_ctl_create(struct super_block *sb) if (!device) return -ENOMEM; - inode_lock(d_inode(root)); - /* If we have already created a binder-control node, return. */ if (info->control_dentry) { ret = 0; @@ -440,12 +438,10 @@ static int binderfs_binder_ctl_create(struct super_block *sb) inode->i_private = device; info->control_dentry = dentry; d_add(dentry, inode); - inode_unlock(d_inode(root)); return 0; out: - inode_unlock(d_inode(root)); kfree(device); iput(inode); -- cgit v1.2.3-58-ga151 From 01684db950ea2b840531ab9298a8785776b6f6e8 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 21 Jan 2019 11:48:08 +0100 Subject: binderfs: switch from d_add() to d_instantiate() In a previous commit we switched from a d_alloc_name() + d_lookup() combination to setup a new dentry and find potential duplicates to the more idiomatic lookup_one_len(). As far as I understand, this also means we need to switch from d_add() to d_instantiate() since lookup_one_len() will create a new dentry when it doesn't find an existing one and add the new dentry to the hash queues. So we only need to call d_instantiate() to connect the dentry to the inode and turn it into a positive dentry. If we were to use d_add() we sure see stack traces like the following indicating that adding the same dentry twice over the same inode: [ 744.441889] CPU: 4 PID: 2849 Comm: landscape-sysin Not tainted 5.0.0-rc1-brauner-binderfs #243 [ 744.441889] Hardware name: Dell DCS XS24-SC2 /XS24-SC2 , BIOS S59_3C20 04/07/2011 [ 744.441889] RIP: 0010:__d_lookup_rcu+0x76/0x190 [ 744.441889] Code: 89 75 c0 49 c1 e9 20 49 89 fd 45 89 ce 41 83 e6 07 42 8d 04 f5 00 00 00 00 89 45 c8 eb 0c 48 8b 1b 48 85 db 0f 84 81 00 00 00 <44> 8b 63 fc 4c 3b 6b 10 75 ea 48 83 7b 08 00 74 e3 41 83 e4 fe 41 [ 744.441889] RSP: 0018:ffffb8c984e27ad0 EFLAGS: 00000282 ORIG_RAX: ffffffffffffff13 [ 744.441889] RAX: 0000000000000038 RBX: ffff9407ef770c08 RCX: ffffb8c980011000 [ 744.441889] RDX: ffffb8c984e27b54 RSI: ffffb8c984e27ce0 RDI: ffff9407e6689600 [ 744.441889] RBP: ffffb8c984e27b28 R08: ffffb8c984e27ba4 R09: 0000000000000007 [ 744.441889] R10: ffff9407e5c4f05c R11: 973f3eb9d84a94e5 R12: 0000000000000002 [ 744.441889] R13: ffff9407e6689600 R14: 0000000000000007 R15: 00000007bfef7a13 [ 744.441889] FS: 00007f0db13bb740(0000) GS:ffff9407f3b00000(0000) knlGS:0000000000000000 [ 744.441889] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 744.441889] CR2: 00007f0dacc51024 CR3: 000000032961a000 CR4: 00000000000006e0 [ 744.441889] Call Trace: [ 744.441889] lookup_fast+0x53/0x300 [ 744.441889] walk_component+0x49/0x350 [ 744.441889] ? inode_permission+0x63/0x1a0 [ 744.441889] link_path_walk.part.33+0x1bc/0x5a0 [ 744.441889] ? path_init+0x190/0x310 [ 744.441889] path_lookupat+0x95/0x210 [ 744.441889] filename_lookup+0xb6/0x190 [ 744.441889] ? __check_object_size+0xb8/0x1b0 [ 744.441889] ? strncpy_from_user+0x50/0x1a0 [ 744.441889] user_path_at_empty+0x36/0x40 [ 744.441889] ? user_path_at_empty+0x36/0x40 [ 744.441889] vfs_statx+0x76/0xe0 [ 744.441889] __do_sys_newstat+0x3d/0x70 [ 744.441889] __x64_sys_newstat+0x16/0x20 [ 744.441889] do_syscall_64+0x5a/0x120 [ 744.441889] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 744.441889] RIP: 0033:0x7f0db0ec2775 [ 744.441889] Code: 00 00 00 75 05 48 83 c4 18 c3 e8 26 55 02 00 66 0f 1f 44 00 00 83 ff 01 48 89 f0 77 30 48 89 c7 48 89 d6 b8 04 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 03 f3 c3 90 48 8b 15 e1 b6 2d 00 f7 d8 64 89 [ 744.441889] RSP: 002b:00007ffc36bc9388 EFLAGS: 00000246 ORIG_RAX: 0000000000000004 [ 744.441889] RAX: ffffffffffffffda RBX: 00007ffc36bc9300 RCX: 00007f0db0ec2775 [ 744.441889] RDX: 00007ffc36bc9400 RSI: 00007ffc36bc9400 RDI: 00007f0dad26f050 [ 744.441889] RBP: 0000000000c0bc60 R08: 0000000000000000 R09: 0000000000000001 [ 744.441889] R10: 0000000000000000 R11: 0000000000000246 R12: 00007ffc36bc9400 [ 744.441889] R13: 0000000000000001 R14: 00000000ffffff9c R15: 0000000000c0bc60 Cc: Al Viro Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index d537dcdb5d65..6a2185eb66c5 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -212,7 +212,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode, } inode->i_private = device; - d_add(dentry, inode); + d_instantiate(dentry, inode); fsnotify_create(root->d_inode, dentry); inode_unlock(d_inode(root)); -- cgit v1.2.3-58-ga151 From 52768f324241b2d9624d32787cff63ec3e0e420a Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 29 Dec 2018 01:05:40 +0100 Subject: i3c: master: Fix an error checking typo in 'cdns_i3c_master_probe()' Fix a cut'n'paste typo. Checking 'master->sysclk' is expected here. Fixes: 603f2bee2c54 ("i3c: master: Add driver for Cadence IP") Signed-off-by: Christophe JAILLET Signed-off-by: Greg Kroah-Hartman --- drivers/i3c/master/i3c-master-cdns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index bbd79b8b1a80..8889a4fdb454 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -1556,8 +1556,8 @@ static int cdns_i3c_master_probe(struct platform_device *pdev) return PTR_ERR(master->pclk); master->sysclk = devm_clk_get(&pdev->dev, "sysclk"); - if (IS_ERR(master->pclk)) - return PTR_ERR(master->pclk); + if (IS_ERR(master->sysclk)) + return PTR_ERR(master->sysclk); irq = platform_get_irq(pdev, 0); if (irq < 0) -- cgit v1.2.3-58-ga151 From 8b9433eb4de3c26a9226c981c283f9f4896ae030 Mon Sep 17 00:00:00 2001 From: "Ernesto A. Fernández" Date: Mon, 8 Oct 2018 20:58:23 -0300 Subject: direct-io: allow direct writes to empty inodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a DIO_SKIP_HOLES filesystem, the ->get_block() method is currently not allowed to create blocks for an empty inode. This confusion comes from trying to bit shift a negative number, so check the size of the inode first. The problem is most visible for hfsplus, because the fallback to buffered I/O doesn't happen and the write fails with EIO. This is in part the fault of the module, because it gives a wrong return value on ->get_block(); that will be fixed in a separate patch. Reviewed-by: Jeff Moyer Reviewed-by: Jan Kara Signed-off-by: Ernesto A. Fernández Signed-off-by: Jens Axboe --- fs/direct-io.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/direct-io.c b/fs/direct-io.c index dbc1a1f080ce..ec2fb6fe6d37 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -679,6 +679,7 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio, unsigned long fs_count; /* Number of filesystem-sized blocks */ int create; unsigned int i_blkbits = sdio->blkbits + sdio->blkfactor; + loff_t i_size; /* * If there was a memory error and we've overwritten all the @@ -708,8 +709,8 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio, */ create = dio->op == REQ_OP_WRITE; if (dio->flags & DIO_SKIP_HOLES) { - if (fs_startblk <= ((i_size_read(dio->inode) - 1) >> - i_blkbits)) + i_size = i_size_read(dio->inode); + if (i_size && fs_startblk <= (i_size - 1) >> i_blkbits) create = 0; } -- cgit v1.2.3-58-ga151 From 8077ec011b1ea26abb7ca786f28ecccfb352717f Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 22 Jan 2019 15:50:09 +0800 Subject: ASoC: rt5682: Correct the setting while select ASRC clk for AD/DA filter AD/DA ASRC function control two ASRC clock sources separately. Whether AD/DA filter select which clock source, we enable AD/DA ASRC function for all cases. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 89c43b26c379..a9b91bcfcc09 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1778,7 +1778,9 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, {"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc}, {"ADC STO1 ASRC", NULL, "AD ASRC"}, + {"ADC STO1 ASRC", NULL, "DA ASRC"}, {"ADC STO1 ASRC", NULL, "CLKDET"}, + {"DAC STO1 ASRC", NULL, "AD ASRC"}, {"DAC STO1 ASRC", NULL, "DA ASRC"}, {"DAC STO1 ASRC", NULL, "CLKDET"}, -- cgit v1.2.3-58-ga151 From 625210cfa6c0c26ea422f655bf68288176f174e6 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Mon, 21 Jan 2019 23:19:58 +0000 Subject: x86/Kconfig: Select PCI_LOCKLESS_CONFIG if PCI is enabled After commit 5d32a66541c4 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. PCI_LOCKLESS_CONFIG depends on PCI but this dependency has not been mentioned in the Kconfig so add an explicit dependency here and fix WARNING: unmet direct dependencies detected for PCI_LOCKLESS_CONFIG Depends on [n]: PCI [=n] Selected by [y]: - X86 [=y] Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Signed-off-by: Borislav Petkov Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Thomas Gleixner Cc: linux-acpi@vger.kernel.org Cc: x86-ml Link: https://lkml.kernel.org/r/20190121231958.28255-2-okaya@kernel.org --- arch/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4b4a7f32b68e..26387c7bf305 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -198,7 +198,7 @@ config X86 select IRQ_FORCED_THREADING select NEED_SG_DMA_LENGTH select PCI_DOMAINS if PCI - select PCI_LOCKLESS_CONFIG + select PCI_LOCKLESS_CONFIG if PCI select PERF_EVENTS select RTC_LIB select RTC_MC146818_LIB -- cgit v1.2.3-58-ga151 From 698cef173983b086977e633e46476e0f925ca01e Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 22 Jan 2019 16:20:17 +0800 Subject: block: cover another queue enter recursion via BIO_QUEUE_ENTERED Except for blk_queue_split(), bio_split() is used for splitting bio too, then the remained bio is often resubmit to queue via generic_make_request(). So the same queue enter recursion exits in this case too. Unfortunatley commit cd4a4ae4683dc2 doesn't help this case. This patch covers the above case by setting BIO_QUEUE_ENTERED before calling q->make_request_fn. In theory the per-bio flag is used to simulate one stack variable, it is just fine to clear it after q->make_request_fn is returned. Especially the same bio can't be submitted from another context. Fixes: cd4a4ae4683dc2 ("block: don't use blocking queue entered for recursive bio submits") Cc: Tetsuo Handa Cc: NeilBrown Reviewed-by: Mike Snitzer Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- block/blk-core.c | 11 +++++++++++ block/blk-merge.c | 10 ---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 3c5f61ceeb67..1ccec27d20c3 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1083,7 +1083,18 @@ blk_qc_t generic_make_request(struct bio *bio) /* Create a fresh bio_list for all subordinate requests */ bio_list_on_stack[1] = bio_list_on_stack[0]; bio_list_init(&bio_list_on_stack[0]); + + /* + * Since we're recursing into make_request here, ensure + * that we mark this bio as already having entered the queue. + * If not, and the queue is going away, we can get stuck + * forever on waiting for the queue reference to drop. But + * that will never happen, as we're already holding a + * reference to it. + */ + bio_set_flag(bio, BIO_QUEUE_ENTERED); ret = q->make_request_fn(q, bio); + bio_clear_flag(bio, BIO_QUEUE_ENTERED); /* sort new bios into those for a lower level * and those for the same level diff --git a/block/blk-merge.c b/block/blk-merge.c index 71e9ac03f621..d79a22f111d1 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -272,16 +272,6 @@ void blk_queue_split(struct request_queue *q, struct bio **bio) /* there isn't chance to merge the splitted bio */ split->bi_opf |= REQ_NOMERGE; - /* - * Since we're recursing into make_request here, ensure - * that we mark this bio as already having entered the queue. - * If not, and the queue is going away, we can get stuck - * forever on waiting for the queue reference to drop. But - * that will never happen, as we're already holding a - * reference to it. - */ - bio_set_flag(*bio, BIO_QUEUE_ENTERED); - bio_chain(split, *bio); trace_block_split(q, split, (*bio)->bi_iter.bi_sector); generic_make_request(*bio); -- cgit v1.2.3-58-ga151 From 3f6a125230d8bfcbfe0c06ff0b8eaccbc727acd7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 22 Jan 2019 17:36:11 +0000 Subject: ASoC: core: Fix multi-CODEC setups Revert 10dff9b0d (ASoC: soc-core: use for_each_link_codecs() for dai_link codecs) for now as Sylwester Nawrocki reports that it causes oopses on at least Odroid boards. Reported-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1c92b4aff57b..8a58fa86675a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,8 +905,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for_each_link_codecs(dai_link, i, codecs) { + for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", -- cgit v1.2.3-58-ga151 From 33e5ee780e37bcf494013e2497580b00b7676507 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 18 Jan 2019 00:14:25 +0100 Subject: vfio/pci: Cleanup license mess The recently added nvlink2 VFIO driver introduced a license conflict in two files. In both cases the SPDX license identifier is: SPDX-License-Identifier: GPL-2.0+ but the files contain also the following license boiler plate text: * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation The latter is GPL-2.9-only and not GPL-2.0=. Looking deeper. The nvlink source file is derived from vfio_pci_igd.c which is also licensed under GPL-2.0-only and it can be assumed that the file was copied and modified. As the original file is licensed GPL-2.0-only it's not possible to relicense derivative work to GPL-2.0-or-later. Fix the SPDX identifier and remove the boiler plate as it is redundant. Fixes: 7f92891778df ("vfio_pci: Add NVIDIA GV100GL [Tesla V100 SXM2] subdriver") Signed-off-by: Thomas Gleixner Cc: Alexey Kardashevskiy Cc: Alex Williamson Cc: Michael Ellerman Cc: kvm@vger.kernel.org Signed-off-by: Alex Williamson --- drivers/vfio/pci/trace.h | 6 +----- drivers/vfio/pci/vfio_pci_nvlink2.c | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/vfio/pci/trace.h b/drivers/vfio/pci/trace.h index 4d13e510590e..b2aa986ab9ed 100644 --- a/drivers/vfio/pci/trace.h +++ b/drivers/vfio/pci/trace.h @@ -1,13 +1,9 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * VFIO PCI mmap/mmap_fault tracepoints * * Copyright (C) 2018 IBM Corp. All rights reserved. * Author: Alexey Kardashevskiy - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #undef TRACE_SYSTEM diff --git a/drivers/vfio/pci/vfio_pci_nvlink2.c b/drivers/vfio/pci/vfio_pci_nvlink2.c index 054a2cf9dd8e..fd6afbd14e77 100644 --- a/drivers/vfio/pci/vfio_pci_nvlink2.c +++ b/drivers/vfio/pci/vfio_pci_nvlink2.c @@ -1,14 +1,10 @@ -// SPDX-License-Identifier: GPL-2.0+ +// SPDX-License-Identifier: GPL-2.0-only /* * VFIO PCI NVIDIA Whitherspoon GPU support a.k.a. NVLink2. * * Copyright (C) 2018 IBM Corp. All rights reserved. * Author: Alexey Kardashevskiy * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Register an on-GPU RAM region for cacheable access. * * Derived from original vfio_pci_igd.c: -- cgit v1.2.3-58-ga151 From 6548c7c538e5658cbce686c2dd1a9b4f5398bf34 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 17 Jan 2019 14:33:01 -0500 Subject: dm: fix dm_wq_work() to only use __split_and_process_bio() if appropriate Otherwise targets that don't support/expect IO splitting could resubmit bios using code paths with unnecessary IO splitting complexity. Depends-on: 24113d487843 ("dm: avoid indirect call in __dm_make_request") Fixes: 978e51ba38e00 ("dm: optimize bio-based NVMe IO submission") Signed-off-by: Mike Snitzer --- drivers/md/dm.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index fbadda68e23b..a010002d892b 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1725,6 +1725,15 @@ out: return ret; } +static blk_qc_t dm_process_bio(struct mapped_device *md, + struct dm_table *map, struct bio *bio) +{ + if (dm_get_md_type(md) == DM_TYPE_NVME_BIO_BASED) + return __process_bio(md, map, bio); + else + return __split_and_process_bio(md, map, bio); +} + static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio) { struct mapped_device *md = q->queuedata; @@ -1745,10 +1754,7 @@ static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio) return ret; } - if (dm_get_md_type(md) == DM_TYPE_NVME_BIO_BASED) - ret = __process_bio(md, map, bio); - else - ret = __split_and_process_bio(md, map, bio); + ret = dm_process_bio(md, map, bio); dm_put_live_table(md, srcu_idx); return ret; @@ -2427,9 +2433,9 @@ static void dm_wq_work(struct work_struct *work) break; if (dm_request_based(md)) - generic_make_request(c); + (void) generic_make_request(c); else - __split_and_process_bio(md, map, c); + (void) dm_process_bio(md, map, c); } dm_put_live_table(md, srcu_idx); -- cgit v1.2.3-58-ga151 From 075c18c3e124a1511ebc10a89f1858c8a77dcb01 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Fri, 18 Jan 2019 01:21:11 -0500 Subject: dm: add missing trace_block_split() to __split_and_process_bio() Provides useful context about bio splits in blktrace. Signed-off-by: Mike Snitzer --- drivers/md/dm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index a010002d892b..2b53c3841b53 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1655,6 +1655,7 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md, part_stat_unlock(); bio_chain(b, bio); + trace_block_split(md->queue, b, bio->bi_iter.bi_sector); ret = generic_make_request(bio); break; } -- cgit v1.2.3-58-ga151 From 56cb4e5034998b5522a657957321ca64ca2ea0a0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 18 Jan 2019 11:49:58 +0100 Subject: net: sun: cassini: Cleanup license conflict The recent addition of SPDX license identifiers to the files in drivers/net/ethernet/sun created a licensing conflict. The cassini driver files contain a proper license notice: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. but the SPDX change added: SPDX-License-Identifier: GPL-2.0 So the file got tagged GPL v2 only while in fact it is licensed under GPL v2 or later. It's nice that people care about the SPDX tags, but they need to be more careful about it. Not everything under (the) sun belongs to ... Fix up the SPDX identifier and remove the boiler plate text as it is redundant. Fixes: c861ef83d771 ("sun: Add SPDX license tags to Sun network drivers") Signed-off-by: Thomas Gleixner Cc: Shannon Nelson Cc: Zhu Yanjun Cc: David S. Miller Cc: netdev@vger.kernel.org Cc: stable@vger.kernel.org Acked-by: Shannon Nelson Reviewed-by: Zhu Yanjun Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/cassini.c | 15 +-------------- drivers/net/ethernet/sun/cassini.h | 15 +-------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c index 9020b084b953..7ec4eb74fe21 100644 --- a/drivers/net/ethernet/sun/cassini.c +++ b/drivers/net/ethernet/sun/cassini.c @@ -1,22 +1,9 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0+ /* cassini.c: Sun Microsystems Cassini(+) ethernet driver. * * Copyright (C) 2004 Sun Microsystems Inc. * Copyright (C) 2003 Adrian Sun (asun@darksunrising.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - * * This driver uses the sungem driver (c) David Miller * (davem@redhat.com) as its basis. * diff --git a/drivers/net/ethernet/sun/cassini.h b/drivers/net/ethernet/sun/cassini.h index 13f3860496a8..ae5f05f03f88 100644 --- a/drivers/net/ethernet/sun/cassini.h +++ b/drivers/net/ethernet/sun/cassini.h @@ -1,23 +1,10 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0+ */ /* $Id: cassini.h,v 1.16 2004/08/17 21:15:16 zaumen Exp $ * cassini.h: Definitions for Sun Microsystems Cassini(+) ethernet driver. * * Copyright (C) 2004 Sun Microsystems Inc. * Copyright (c) 2003 Adrian Sun (asun@darksunrising.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - * * vendor id: 0x108E (Sun Microsystems, Inc.) * device id: 0xabba (Cassini) * revision ids: 0x01 = Cassini -- cgit v1.2.3-58-ga151 From cb73ee40b1b381eaf3749e6dbeed567bb38e5258 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Jan 2019 12:05:39 +0100 Subject: net: ip_gre: use erspan key field for tunnel lookup Use ERSPAN key header field as tunnel key in gre_parse_header routine since ERSPAN protocol sets the key field of the external GRE header to 0 resulting in a tunnel lookup fail in ip6gre_err. In addition remove key field parsing and pskb_may_pull check in erspan_rcv and ip6erspan_rcv Fixes: 5a963eb61b7c ("ip6_gre: Add ERSPAN native tunnel support") Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller --- net/ipv4/gre_demux.c | 17 +++++++++++++++++ net/ipv4/ip_gre.c | 9 --------- net/ipv6/ip6_gre.c | 4 ---- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c index a4bf22ee3aed..7c4a41dc04bb 100644 --- a/net/ipv4/gre_demux.c +++ b/net/ipv4/gre_demux.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -119,6 +120,22 @@ int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, hdr_len += 4; } tpi->hdr_len = hdr_len; + + /* ERSPAN ver 1 and 2 protocol sets GRE key field + * to 0 and sets the configured key in the + * inner erspan header field + */ + if (greh->protocol == htons(ETH_P_ERSPAN) || + greh->protocol == htons(ETH_P_ERSPAN2)) { + struct erspan_base_hdr *ershdr; + + if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr))) + return -EINVAL; + + ershdr = (struct erspan_base_hdr *)options; + tpi->key = cpu_to_be32(get_session_id(ershdr)); + } + return hdr_len; } EXPORT_SYMBOL(gre_parse_header); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index b1a74d80d868..20a64fe6254b 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -268,20 +268,11 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, int len; itn = net_generic(net, erspan_net_id); - len = gre_hdr_len + sizeof(*ershdr); - - /* Check based hdr len */ - if (unlikely(!pskb_may_pull(skb, len))) - return PACKET_REJECT; iph = ip_hdr(skb); ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); ver = ershdr->ver; - /* The original GRE header does not have key field, - * Use ERSPAN 10-bit session ID as key. - */ - tpi->key = cpu_to_be32(get_session_id(ershdr)); tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags | TUNNEL_KEY, iph->saddr, iph->daddr, tpi->key); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index b1be67ca6768..4416368dbd49 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -534,13 +534,9 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len, struct ip6_tnl *tunnel; u8 ver; - if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr)))) - return PACKET_REJECT; - ipv6h = ipv6_hdr(skb); ershdr = (struct erspan_base_hdr *)skb->data; ver = ershdr->ver; - tpi->key = cpu_to_be32(get_session_id(ershdr)); tunnel = ip6gre_tunnel_lookup(skb->dev, &ipv6h->saddr, &ipv6h->daddr, tpi->key, -- cgit v1.2.3-58-ga151 From 7fc5854f8c6efae9e7624970ab49a1eac2faefb1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 12 Dec 2017 08:38:30 -0800 Subject: writeback: synchronize sync(2) against cgroup writeback membership switches sync_inodes_sb() can race against cgwb (cgroup writeback) membership switches and fail to writeback some inodes. For example, if an inode switches to another wb while sync_inodes_sb() is in progress, the new wb might not be visible to bdi_split_work_to_wbs() at all or the inode might jump from a wb which hasn't issued writebacks yet to one which already has. This patch adds backing_dev_info->wb_switch_rwsem to synchronize cgwb switch path against sync_inodes_sb() so that sync_inodes_sb() is guaranteed to see all the target wbs and inodes can't jump wbs to escape syncing. v2: Fixed misplaced rwsem init. Spotted by Jiufei. Signed-off-by: Tejun Heo Reported-by: Jiufei Xue Link: http://lkml.kernel.org/r/dc694ae2-f07f-61e1-7097-7c8411cee12d@gmail.com Acked-by: Jan Kara Signed-off-by: Jens Axboe --- fs/fs-writeback.c | 40 ++++++++++++++++++++++++++++++++++++++-- include/linux/backing-dev-defs.h | 1 + mm/backing-dev.c | 1 + 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index b40168fcc94a..36855c1f8daf 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -331,11 +331,22 @@ struct inode_switch_wbs_context { struct work_struct work; }; +static void bdi_down_write_wb_switch_rwsem(struct backing_dev_info *bdi) +{ + down_write(&bdi->wb_switch_rwsem); +} + +static void bdi_up_write_wb_switch_rwsem(struct backing_dev_info *bdi) +{ + up_write(&bdi->wb_switch_rwsem); +} + static void inode_switch_wbs_work_fn(struct work_struct *work) { struct inode_switch_wbs_context *isw = container_of(work, struct inode_switch_wbs_context, work); struct inode *inode = isw->inode; + struct backing_dev_info *bdi = inode_to_bdi(inode); struct address_space *mapping = inode->i_mapping; struct bdi_writeback *old_wb = inode->i_wb; struct bdi_writeback *new_wb = isw->new_wb; @@ -343,6 +354,12 @@ static void inode_switch_wbs_work_fn(struct work_struct *work) struct page *page; bool switched = false; + /* + * If @inode switches cgwb membership while sync_inodes_sb() is + * being issued, sync_inodes_sb() might miss it. Synchronize. + */ + down_read(&bdi->wb_switch_rwsem); + /* * By the time control reaches here, RCU grace period has passed * since I_WB_SWITCH assertion and all wb stat update transactions @@ -428,6 +445,8 @@ skip_switch: spin_unlock(&new_wb->list_lock); spin_unlock(&old_wb->list_lock); + up_read(&bdi->wb_switch_rwsem); + if (switched) { wb_wakeup(new_wb); wb_put(old_wb); @@ -468,9 +487,18 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) if (inode->i_state & I_WB_SWITCH) return; + /* + * Avoid starting new switches while sync_inodes_sb() is in + * progress. Otherwise, if the down_write protected issue path + * blocks heavily, we might end up starting a large number of + * switches which will block on the rwsem. + */ + if (!down_read_trylock(&bdi->wb_switch_rwsem)) + return; + isw = kzalloc(sizeof(*isw), GFP_ATOMIC); if (!isw) - return; + goto out_unlock; /* find and pin the new wb */ rcu_read_lock(); @@ -504,12 +532,14 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) * Let's continue after I_WB_SWITCH is guaranteed to be visible. */ call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn); - return; + goto out_unlock; out_free: if (isw->new_wb) wb_put(isw->new_wb); kfree(isw); +out_unlock: + up_read(&bdi->wb_switch_rwsem); } /** @@ -887,6 +917,9 @@ fs_initcall(cgroup_writeback_init); #else /* CONFIG_CGROUP_WRITEBACK */ +static void bdi_down_write_wb_switch_rwsem(struct backing_dev_info *bdi) { } +static void bdi_up_write_wb_switch_rwsem(struct backing_dev_info *bdi) { } + static struct bdi_writeback * locked_inode_to_wb_and_lock_list(struct inode *inode) __releases(&inode->i_lock) @@ -2413,8 +2446,11 @@ void sync_inodes_sb(struct super_block *sb) return; WARN_ON(!rwsem_is_locked(&sb->s_umount)); + /* protect against inode wb switch, see inode_switch_wbs_work_fn() */ + bdi_down_write_wb_switch_rwsem(bdi); bdi_split_work_to_wbs(bdi, &work, false); wb_wait_for_completion(bdi, &done); + bdi_up_write_wb_switch_rwsem(bdi); wait_sb_inodes(sb); } diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index c31157135598..07e02d6df5ad 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h @@ -190,6 +190,7 @@ struct backing_dev_info { struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */ struct rb_root cgwb_congested_tree; /* their congested states */ struct mutex cgwb_release_mutex; /* protect shutdown of wb structs */ + struct rw_semaphore wb_switch_rwsem; /* no cgwb switch while syncing */ #else struct bdi_writeback_congested *wb_congested; #endif diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 8a8bb8796c6c..72e6d0c55cfa 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -689,6 +689,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi) INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC); bdi->cgwb_congested_tree = RB_ROOT; mutex_init(&bdi->cgwb_release_mutex); + init_rwsem(&bdi->wb_switch_rwsem); ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); if (!ret) { -- cgit v1.2.3-58-ga151 From 1518039f6b5ac794313c24c76f85cead0cd60f6c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 22 Jan 2019 14:47:19 -0800 Subject: net/ipv6: don't return positive numbers when nothing was dumped in6_dump_addrs() returns a positive 1 if there was nothing to dump. This return value can not be passed as return from inet6_dump_addr() as is, because it will confuse rtnetlink, resulting in NLMSG_DONE never getting set: $ ip addr list dev lo EOF on netlink Dump terminated v2: flip condition to avoid a new goto (DaveA) Fixes: 7c1e8a3817c5 ("netlink: fixup regression in RTM_GETADDR") Reported-by: Brendan Galloway Signed-off-by: Jakub Kicinski Reviewed-by: David Ahern Tested-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 93d5ad2b1a69..0c9e20ac01ab 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -5120,6 +5120,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, if (idev) { err = in6_dump_addrs(idev, skb, cb, s_ip_idx, &fillargs); + if (err > 0) + err = 0; } goto put_tgt_net; } -- cgit v1.2.3-58-ga151 From cfdb1b63eefe918e5c8419c9a88188fef1b9cc5e Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Sun, 20 Jan 2019 11:36:37 +0200 Subject: qed: Revise load sequence to avoid PCI errors Initiating final cleanup after an ungraceful driver unload can lead to bad PCI accesses towards the host. This patch revises the load sequence so final cleanup is sent while the internal master enable is cleared, to prevent the host accesses, and clears the internal error indications just before enabling the internal master enable. Signed-off-by: Tomer Tayar Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 1 - drivers/net/ethernet/qlogic/qed/qed_dev.c | 117 ++++++++++++++---------- drivers/net/ethernet/qlogic/qed/qed_dev_api.h | 12 +++ drivers/net/ethernet/qlogic/qed/qed_int.c | 126 +++++++++++++------------- drivers/net/ethernet/qlogic/qed/qed_int.h | 3 + drivers/net/ethernet/qlogic/qed/qed_mcp.c | 21 +++++ drivers/net/ethernet/qlogic/qed/qed_mcp.h | 10 ++ 7 files changed, 178 insertions(+), 112 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 24a90163775e..b352e313e1f6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -554,7 +554,6 @@ struct qed_hwfn { u8 dp_level; char name[NAME_SIZE]; - bool first_on_engine; bool hw_init_done; u8 num_funcs_on_engine; diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 8f6551421945..fa5f07e65672 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1959,11 +1959,6 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, (p_hwfn->hw_info.personality == QED_PCI_FCOE) ? 1 : 0); STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0); - /* Cleanup chip from previous driver if such remains exist */ - rc = qed_final_cleanup(p_hwfn, p_ptt, rel_pf_id, false); - if (rc) - return rc; - /* Sanity check before the PF init sequence that uses DMAE */ rc = qed_dmae_sanity(p_hwfn, p_ptt, "pf_phase"); if (rc) @@ -2007,17 +2002,15 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, return rc; } -static int qed_change_pci_hwfn(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - u8 enable) +int qed_pglueb_set_pfid_enable(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, bool b_enable) { - u32 delay_idx = 0, val, set_val = enable ? 1 : 0; + u32 delay_idx = 0, val, set_val = b_enable ? 1 : 0; - /* Change PF in PXP */ - qed_wr(p_hwfn, p_ptt, - PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val); + /* Configure the PF's internal FID_enable for master transactions */ + qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val); - /* wait until value is set - try for 1 second every 50us */ + /* Wait until value is set - try for 1 second every 50us */ for (delay_idx = 0; delay_idx < 20000; delay_idx++) { val = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER); @@ -2071,13 +2064,19 @@ static int qed_vf_start(struct qed_hwfn *p_hwfn, return 0; } +static void qed_pglueb_clear_err(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR, + BIT(p_hwfn->abs_pf_id)); +} + int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) { struct qed_load_req_params load_req_params; u32 load_code, resp, param, drv_mb_param; bool b_default_mtu = true; struct qed_hwfn *p_hwfn; - int rc = 0, mfw_rc, i; + int rc = 0, i; u16 ether_type; if ((p_params->int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { @@ -2092,7 +2091,7 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) } for_each_hwfn(cdev, i) { - struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; + p_hwfn = &cdev->hwfns[i]; /* If management didn't provide a default, set one of our own */ if (!p_hwfn->hw_info.mtu) { @@ -2105,9 +2104,6 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) continue; } - /* Enable DMAE in PXP */ - rc = qed_change_pci_hwfn(p_hwfn, p_hwfn->p_main_ptt, true); - rc = qed_calc_hw_mode(p_hwfn); if (rc) return rc; @@ -2148,8 +2144,34 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) qed_reset_mb_shadow(p_hwfn, p_hwfn->p_main_ptt); - p_hwfn->first_on_engine = (load_code == - FW_MSG_CODE_DRV_LOAD_ENGINE); + /* Clean up chip from previous driver if such remains exist. + * This is not needed when the PF is the first one on the + * engine, since afterwards we are going to init the FW. + */ + if (load_code != FW_MSG_CODE_DRV_LOAD_ENGINE) { + rc = qed_final_cleanup(p_hwfn, p_hwfn->p_main_ptt, + p_hwfn->rel_pf_id, false); + if (rc) { + DP_NOTICE(p_hwfn, "Final cleanup failed\n"); + goto load_err; + } + } + + /* Log and clear previous pglue_b errors if such exist */ + qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_main_ptt); + + /* Enable the PF's internal FID_enable in the PXP */ + rc = qed_pglueb_set_pfid_enable(p_hwfn, p_hwfn->p_main_ptt, + true); + if (rc) + goto load_err; + + /* Clear the pglue_b was_error indication. + * In E4 it must be done after the BME and the internal + * FID_enable for the PF are set, since VDMs may cause the + * indication to be set again. + */ + qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt); switch (load_code) { case FW_MSG_CODE_DRV_LOAD_ENGINE: @@ -2180,39 +2202,29 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) break; } - if (rc) + if (rc) { DP_NOTICE(p_hwfn, "init phase failed for loadcode 0x%x (rc %d)\n", - load_code, rc); + load_code, rc); + goto load_err; + } - /* ACK mfw regardless of success or failure of initialization */ - mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, - DRV_MSG_CODE_LOAD_DONE, - 0, &load_code, ¶m); + rc = qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt); if (rc) return rc; - if (mfw_rc) { - DP_NOTICE(p_hwfn, "Failed sending LOAD_DONE command\n"); - return mfw_rc; - } - - /* Check if there is a DID mismatch between nvm-cfg/efuse */ - if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) - DP_NOTICE(p_hwfn, - "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); /* send DCBX attention request command */ DP_VERBOSE(p_hwfn, QED_MSG_DCB, "sending phony dcbx set command to trigger DCBx attention handling\n"); - mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, - DRV_MSG_CODE_SET_DCBX, - 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT, - &load_code, ¶m); - if (mfw_rc) { + rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, + DRV_MSG_CODE_SET_DCBX, + 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT, + &resp, ¶m); + if (rc) { DP_NOTICE(p_hwfn, "Failed to send DCBX attention request\n"); - return mfw_rc; + return rc; } p_hwfn->hw_init_done = true; @@ -2261,6 +2273,12 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) } return 0; + +load_err: + /* The MFW load lock should be released also when initialization fails. + */ + qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt); + return rc; } #define QED_HW_STOP_RETRY_LIMIT (10) @@ -2395,14 +2413,16 @@ int qed_hw_stop(struct qed_dev *cdev) p_hwfn = QED_LEADING_HWFN(cdev); p_ptt = QED_LEADING_HWFN(cdev)->p_main_ptt; - /* Disable DMAE in PXP - in CMT, this should only be done for - * first hw-function, and only after all transactions have - * stopped for all active hw-functions. + /* Clear the PF's internal FID_enable in the PXP. + * In CMT this should only be done for first hw-function, and + * only after all transactions have stopped for all active + * hw-functions. */ - rc = qed_change_pci_hwfn(p_hwfn, p_ptt, false); + rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); if (rc) { DP_NOTICE(p_hwfn, - "qed_change_pci_hwfn failed. rc = %d.\n", rc); + "qed_pglueb_set_pfid_enable() failed. rc = %d.\n", + rc); rc2 = -EINVAL; } } @@ -2502,9 +2522,8 @@ static void qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn) PGLUE_B_REG_PGL_ADDR_94_F0_BB, 0); } - /* Clean Previous errors if such exist */ - qed_wr(p_hwfn, p_hwfn->p_main_ptt, - PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR, 1 << p_hwfn->abs_pf_id); + /* Clean previous pglue_b errors if such exist */ + qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt); /* enable internal target-read */ qed_wr(p_hwfn, p_hwfn->p_main_ptt, diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h index acccd85170aa..e4b4e3b78e8a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h @@ -472,6 +472,18 @@ int qed_get_queue_coalesce(struct qed_hwfn *p_hwfn, u16 *coal, void *handle); int qed_set_queue_coalesce(u16 rx_coal, u16 tx_coal, void *p_handle); +/** + * @brief qed_pglueb_set_pfid_enable - Enable or disable PCI BUS MASTER + * + * @param p_hwfn + * @param p_ptt + * @param b_enable - true/false + * + * @return int + */ +int qed_pglueb_set_pfid_enable(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, bool b_enable); + /** * @brief db_recovery_add - add doorbell information to the doorbell * recovery mechanism. diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 92340919d852..e23980e301b6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -255,112 +255,114 @@ out: #define PGLUE_ATTENTION_ICPL_VALID (1 << 23) #define PGLUE_ATTENTION_ZLR_VALID (1 << 25) #define PGLUE_ATTENTION_ILT_VALID (1 << 23) -static int qed_pglub_rbc_attn_cb(struct qed_hwfn *p_hwfn) + +int qed_pglueb_rbc_attn_handler(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) { u32 tmp; - tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - PGLUE_B_REG_TX_ERR_WR_DETAILS2); + tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_DETAILS2); if (tmp & PGLUE_ATTENTION_VALID) { u32 addr_lo, addr_hi, details; - addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + addr_lo = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_ADD_31_0); - addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + addr_hi = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_ADD_63_32); - details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + details = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_DETAILS); - DP_INFO(p_hwfn, - "Illegal write by chip to [%08x:%08x] blocked.\n" - "Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n" - "Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n", - addr_hi, addr_lo, details, - (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID), - (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID), - GET_FIELD(details, - PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0, - tmp, - GET_FIELD(tmp, - PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 : 0, - GET_FIELD(tmp, - PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0, - GET_FIELD(tmp, - PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 : 0); + DP_NOTICE(p_hwfn, + "Illegal write by chip to [%08x:%08x] blocked.\n" + "Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n" + "Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n", + addr_hi, addr_lo, details, + (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID), + (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID), + GET_FIELD(details, + PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0, + tmp, + GET_FIELD(tmp, + PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 : 0, + GET_FIELD(tmp, + PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0, + GET_FIELD(tmp, + PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 : 0); } - tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - PGLUE_B_REG_TX_ERR_RD_DETAILS2); + tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_RD_DETAILS2); if (tmp & PGLUE_ATTENTION_RD_VALID) { u32 addr_lo, addr_hi, details; - addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + addr_lo = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_RD_ADD_31_0); - addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + addr_hi = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_RD_ADD_63_32); - details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + details = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_RD_DETAILS); - DP_INFO(p_hwfn, - "Illegal read by chip from [%08x:%08x] blocked.\n" - " Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n" - " Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n", - addr_hi, addr_lo, details, - (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID), - (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID), - GET_FIELD(details, - PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0, - tmp, - GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 - : 0, - GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0, - GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 - : 0); + DP_NOTICE(p_hwfn, + "Illegal read by chip from [%08x:%08x] blocked.\n" + "Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n" + "Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n", + addr_hi, addr_lo, details, + (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID), + (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID), + GET_FIELD(details, + PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0, + tmp, + GET_FIELD(tmp, + PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 : 0, + GET_FIELD(tmp, + PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0, + GET_FIELD(tmp, + PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 : 0); } - tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - PGLUE_B_REG_TX_ERR_WR_DETAILS_ICPL); + tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_DETAILS_ICPL); if (tmp & PGLUE_ATTENTION_ICPL_VALID) - DP_INFO(p_hwfn, "ICPL error - %08x\n", tmp); + DP_NOTICE(p_hwfn, "ICPL error - %08x\n", tmp); - tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - PGLUE_B_REG_MASTER_ZLR_ERR_DETAILS); + tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_ZLR_ERR_DETAILS); if (tmp & PGLUE_ATTENTION_ZLR_VALID) { u32 addr_hi, addr_lo; - addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + addr_lo = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_ZLR_ERR_ADD_31_0); - addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + addr_hi = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_ZLR_ERR_ADD_63_32); - DP_INFO(p_hwfn, "ZLR eror - %08x [Address %08x:%08x]\n", - tmp, addr_hi, addr_lo); + DP_NOTICE(p_hwfn, "ZLR error - %08x [Address %08x:%08x]\n", + tmp, addr_hi, addr_lo); } - tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, - PGLUE_B_REG_VF_ILT_ERR_DETAILS2); + tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_VF_ILT_ERR_DETAILS2); if (tmp & PGLUE_ATTENTION_ILT_VALID) { u32 addr_hi, addr_lo, details; - addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + addr_lo = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_VF_ILT_ERR_ADD_31_0); - addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + addr_hi = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_VF_ILT_ERR_ADD_63_32); - details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + details = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_VF_ILT_ERR_DETAILS); - DP_INFO(p_hwfn, - "ILT error - Details %08x Details2 %08x [Address %08x:%08x]\n", - details, tmp, addr_hi, addr_lo); + DP_NOTICE(p_hwfn, + "ILT error - Details %08x Details2 %08x [Address %08x:%08x]\n", + details, tmp, addr_hi, addr_lo); } /* Clear the indications */ - qed_wr(p_hwfn, p_hwfn->p_dpc_ptt, - PGLUE_B_REG_LATCHED_ERRORS_CLR, (1 << 2)); + qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_LATCHED_ERRORS_CLR, BIT(2)); return 0; } +static int qed_pglueb_rbc_attn_cb(struct qed_hwfn *p_hwfn) +{ + return qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_dpc_ptt); +} + #define QED_DORQ_ATTENTION_REASON_MASK (0xfffff) #define QED_DORQ_ATTENTION_OPAQUE_MASK (0xffff) #define QED_DORQ_ATTENTION_OPAQUE_SHIFT (0x0) @@ -540,7 +542,7 @@ static struct aeu_invert_reg aeu_descs[NUM_ATTN_REGS] = { {"PGLUE misc_flr", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID}, {"PGLUE B RBC", ATTENTION_PAR_INT, - qed_pglub_rbc_attn_cb, BLOCK_PGLUE_B}, + qed_pglueb_rbc_attn_cb, BLOCK_PGLUE_B}, {"PGLUE misc_mctp", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID}, {"Flash event", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID}, diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index d81a62ebd524..1f356ed4f761 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -431,4 +431,7 @@ int qed_int_set_timer_res(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, #define QED_MAPPING_MEMORY_SIZE(dev) (NUM_OF_SBS(dev)) +int qed_pglueb_rbc_attn_handler(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index e7f18e34ff0d..1024484d7dd8 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1070,6 +1070,27 @@ int qed_mcp_load_req(struct qed_hwfn *p_hwfn, return 0; } +int qed_mcp_load_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + u32 resp = 0, param = 0; + int rc; + + rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_LOAD_DONE, 0, &resp, + ¶m); + if (rc) { + DP_NOTICE(p_hwfn, + "Failed to send a LOAD_DONE command, rc = %d\n", rc); + return rc; + } + + /* Check if there is a DID mismatch between nvm-cfg/efuse */ + if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) + DP_NOTICE(p_hwfn, + "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); + + return 0; +} + int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_mcp_mb_params mb_params; diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index eddf67798d6f..387c5e649136 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -800,6 +800,16 @@ int qed_mcp_load_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_load_req_params *p_params); +/** + * @brief Sends a LOAD_DONE message to the MFW + * + * @param p_hwfn + * @param p_ptt + * + * @return int - 0 - Operation was successful. + */ +int qed_mcp_load_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); + /** * @brief Sends a UNLOAD_REQ message to the MFW * -- cgit v1.2.3-58-ga151 From c75860e48a7634ff8dc050842211f79a0e4e6c46 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Sun, 20 Jan 2019 11:36:38 +0200 Subject: qed: Add infrastructure for error detection and recovery This patch adds the detection and handling of a parity error ("process kill event"), including the update of the protocol drivers, and the prevention of any HW access that will lead to device access towards the host while recovery is in progress. It also provides the means for the protocol drivers to trigger a recovery process on their decision. Signed-off-by: Tomer Tayar Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 4 ++ drivers/net/ethernet/qlogic/qed/qed_dev.c | 41 +++++++---- drivers/net/ethernet/qlogic/qed/qed_hsi.h | 2 +- drivers/net/ethernet/qlogic/qed/qed_hw.c | 11 +++ drivers/net/ethernet/qlogic/qed/qed_main.c | 30 ++++++++ drivers/net/ethernet/qlogic/qed/qed_mcp.c | 94 ++++++++++++++++++++++++++ drivers/net/ethernet/qlogic/qed/qed_mcp.h | 32 +++++++++ drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 2 + drivers/net/ethernet/qlogic/qed/qed_spq.c | 22 ++++++ drivers/net/ethernet/qlogic/qed/qed_sriov.c | 9 ++- include/linux/qed/qed_if.h | 20 ++++++ 11 files changed, 251 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index b352e313e1f6..3b0955d34716 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -804,6 +804,9 @@ struct qed_dev { u32 mcp_nvm_resp; + /* Recovery */ + bool recov_in_prog; + /* Linux specific here */ struct qede_dev *edev; struct pci_dev *pdev; @@ -943,6 +946,7 @@ void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt); u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, u8 *input_buf, u32 max_size, u8 *unzip_buf); +void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn); void qed_get_protocol_stats(struct qed_dev *cdev, enum qed_mcp_protocol_type type, union qed_mcp_protocol_stats *stats); diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index fa5f07e65672..b17003d9066c 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -2140,6 +2140,11 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) "Load request was sent. Load code: 0x%x\n", load_code); + /* Only relevant for recovery: + * Clear the indication after LOAD_REQ is responded by the MFW. + */ + cdev->recov_in_prog = false; + qed_mcp_set_capabilities(p_hwfn, p_hwfn->p_main_ptt); qed_reset_mb_shadow(p_hwfn, p_hwfn->p_main_ptt); @@ -2291,6 +2296,9 @@ static void qed_hw_timers_stop(struct qed_dev *cdev, qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0); qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0); + if (cdev->recov_in_prog) + return; + for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) { if ((!qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_CONN)) && @@ -2353,12 +2361,14 @@ int qed_hw_stop(struct qed_dev *cdev) p_hwfn->hw_init_done = false; /* Send unload command to MCP */ - rc = qed_mcp_unload_req(p_hwfn, p_ptt); - if (rc) { - DP_NOTICE(p_hwfn, - "Failed sending a UNLOAD_REQ command. rc = %d.\n", - rc); - rc2 = -EINVAL; + if (!cdev->recov_in_prog) { + rc = qed_mcp_unload_req(p_hwfn, p_ptt); + if (rc) { + DP_NOTICE(p_hwfn, + "Failed sending a UNLOAD_REQ command. rc = %d.\n", + rc); + rc2 = -EINVAL; + } } qed_slowpath_irq_sync(p_hwfn); @@ -2400,16 +2410,18 @@ int qed_hw_stop(struct qed_dev *cdev) qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DB_ENABLE, 0); qed_wr(p_hwfn, p_ptt, QM_REG_PF_EN, 0); - qed_mcp_unload_done(p_hwfn, p_ptt); - if (rc) { - DP_NOTICE(p_hwfn, - "Failed sending a UNLOAD_DONE command. rc = %d.\n", - rc); - rc2 = -EINVAL; + if (!cdev->recov_in_prog) { + rc = qed_mcp_unload_done(p_hwfn, p_ptt); + if (rc) { + DP_NOTICE(p_hwfn, + "Failed sending a UNLOAD_DONE command. rc = %d.\n", + rc); + rc2 = -EINVAL; + } } } - if (IS_PF(cdev)) { + if (IS_PF(cdev) && !cdev->recov_in_prog) { p_hwfn = QED_LEADING_HWFN(cdev); p_ptt = QED_LEADING_HWFN(cdev)->p_main_ptt; @@ -3459,6 +3471,7 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn, void __iomem *p_doorbells, enum qed_pci_personality personality) { + struct qed_dev *cdev = p_hwfn->cdev; int rc = 0; /* Split PCI bars evenly between hwfns */ @@ -3511,7 +3524,7 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn, /* Sending a mailbox to the MFW should be done after qed_get_hw_info() * is called as it sets the ports number in an engine. */ - if (IS_LEAD_HWFN(p_hwfn)) { + if (IS_LEAD_HWFN(p_hwfn) && !cdev->recov_in_prog) { rc = qed_mcp_initiate_pf_flr(p_hwfn, p_hwfn->p_main_ptt); if (rc) DP_NOTICE(p_hwfn, "Failed to initiate PF FLR\n"); diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index b13cfb449d8f..417121e74ee9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -12827,7 +12827,7 @@ enum MFW_DRV_MSG_TYPE { MFW_DRV_MSG_LLDP_DATA_UPDATED, MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED, MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED, - MFW_DRV_MSG_RESERVED4, + MFW_DRV_MSG_ERROR_RECOVERY, MFW_DRV_MSG_BW_UPDATE, MFW_DRV_MSG_S_TAG_UPDATE, MFW_DRV_MSG_GET_LAN_STATS, diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c index 70504dcf4087..72ec1c6bdf70 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hw.c +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c @@ -703,6 +703,17 @@ static int qed_dmae_execute_command(struct qed_hwfn *p_hwfn, int qed_status = 0; u32 offset = 0; + if (p_hwfn->cdev->recov_in_prog) { + DP_VERBOSE(p_hwfn, + NETIF_MSG_HW, + "Recovery is in progress. Avoid DMAE transaction [{src: addr 0x%llx, type %d}, {dst: addr 0x%llx, type %d}, size %d].\n", + src_addr, src_type, dst_addr, dst_type, + size_in_dwords); + + /* Let the flow complete w/o any error handling */ + return 0; + } + qed_dmae_opcode(p_hwfn, (src_type == QED_DMAE_ADDRESS_GRC), (dst_type == QED_DMAE_ADDRESS_GRC), diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 6adf5bda9811..b47352643fb5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -359,6 +359,8 @@ static struct qed_dev *qed_probe(struct pci_dev *pdev, qed_init_dp(cdev, params->dp_module, params->dp_level); + cdev->recov_in_prog = params->recov_in_prog; + rc = qed_init_pci(cdev, pdev); if (rc) { DP_ERR(cdev, "init pci failed\n"); @@ -2203,6 +2205,15 @@ static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, return qed_mcp_get_nvm_image(hwfn, type, buf, len); } +void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn) +{ + struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; + void *cookie = p_hwfn->cdev->ops_cookie; + + if (ops && ops->schedule_recovery_handler) + ops->schedule_recovery_handler(cookie); +} + static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, void *handle) { @@ -2226,6 +2237,23 @@ static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) return status; } +static int qed_recovery_process(struct qed_dev *cdev) +{ + struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); + struct qed_ptt *p_ptt; + int rc = 0; + + p_ptt = qed_ptt_acquire(p_hwfn); + if (!p_ptt) + return -EAGAIN; + + rc = qed_start_recovery_process(p_hwfn, p_ptt); + + qed_ptt_release(p_hwfn, p_ptt); + + return rc; +} + static int qed_update_wol(struct qed_dev *cdev, bool enabled) { struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); @@ -2380,6 +2408,8 @@ const struct qed_common_ops qed_common_ops_pass = { .nvm_get_image = &qed_nvm_get_image, .set_coalesce = &qed_set_coalesce, .set_led = &qed_set_led, + .recovery_process = &qed_recovery_process, + .recovery_prolog = &qed_recovery_prolog, .update_drv_state = &qed_update_drv_state, .update_mac = &qed_update_mac, .update_mtu = &qed_update_mtu, diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 1024484d7dd8..bb8541847aa5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1549,6 +1549,60 @@ int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) return 0; } +u32 qed_get_process_kill_counter(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 path_offsize_addr, path_offsize, path_addr, proc_kill_cnt; + + if (IS_VF(p_hwfn->cdev)) + return -EINVAL; + + path_offsize_addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, + PUBLIC_PATH); + path_offsize = qed_rd(p_hwfn, p_ptt, path_offsize_addr); + path_addr = SECTION_ADDR(path_offsize, QED_PATH_ID(p_hwfn)); + + proc_kill_cnt = qed_rd(p_hwfn, p_ptt, + path_addr + + offsetof(struct public_path, process_kill)) & + PROCESS_KILL_COUNTER_MASK; + + return proc_kill_cnt; +} + +static void qed_mcp_handle_process_kill(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + struct qed_dev *cdev = p_hwfn->cdev; + u32 proc_kill_cnt; + + /* Prevent possible attentions/interrupts during the recovery handling + * and till its load phase, during which they will be re-enabled. + */ + qed_int_igu_disable_int(p_hwfn, p_ptt); + + DP_NOTICE(p_hwfn, "Received a process kill indication\n"); + + /* The following operations should be done once, and thus in CMT mode + * are carried out by only the first HW function. + */ + if (p_hwfn != QED_LEADING_HWFN(cdev)) + return; + + if (cdev->recov_in_prog) { + DP_NOTICE(p_hwfn, + "Ignoring the indication since a recovery process is already in progress\n"); + return; + } + + cdev->recov_in_prog = true; + + proc_kill_cnt = qed_get_process_kill_counter(p_hwfn, p_ptt); + DP_NOTICE(p_hwfn, "Process kill counter: %d\n", proc_kill_cnt); + + qed_schedule_recovery_handler(p_hwfn); +} + static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, enum MFW_DRV_MSG_TYPE type) @@ -1779,6 +1833,9 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); break; + case MFW_DRV_MSG_ERROR_RECOVERY: + qed_mcp_handle_process_kill(p_hwfn, p_ptt); + break; case MFW_DRV_MSG_GET_LAN_STATS: case MFW_DRV_MSG_GET_FCOE_STATS: case MFW_DRV_MSG_GET_ISCSI_STATS: @@ -2324,6 +2381,43 @@ int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, return 0; } +int qed_start_recovery_process(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) +{ + struct qed_dev *cdev = p_hwfn->cdev; + + if (cdev->recov_in_prog) { + DP_NOTICE(p_hwfn, + "Avoid triggering a recovery since such a process is already in progress\n"); + return -EAGAIN; + } + + DP_NOTICE(p_hwfn, "Triggering a recovery process\n"); + qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_GENERAL_ATTN_35, 0x1); + + return 0; +} + +#define QED_RECOVERY_PROLOG_SLEEP_MS 100 + +int qed_recovery_prolog(struct qed_dev *cdev) +{ + struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); + struct qed_ptt *p_ptt = p_hwfn->p_main_ptt; + int rc; + + /* Allow ongoing PCIe transactions to complete */ + msleep(QED_RECOVERY_PROLOG_SLEEP_MS); + + /* Clear the PF's internal FID_enable in the PXP */ + rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); + if (rc) + DP_NOTICE(p_hwfn, + "qed_pglueb_set_pfid_enable() failed. rc = %d.\n", + rc); + + return rc; +} + static int qed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u8 vf_id, u8 num) diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 387c5e649136..6e1d72a669ae 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -440,6 +440,38 @@ qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_mcp_drv_version *p_ver); +/** + * @brief Read the MFW process kill counter + * + * @param p_hwfn + * @param p_ptt + * + * @return u32 + */ +u32 qed_get_process_kill_counter(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt); + +/** + * @brief Trigger a recovery process + * + * @param p_hwfn + * @param p_ptt + * + * @return int + */ +int qed_start_recovery_process(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); + +/** + * @brief A recovery handler must call this function as its first step. + * It is assumed that the handler is not run from an interrupt context. + * + * @param cdev + * @param p_ptt + * + * @return int + */ +int qed_recovery_prolog(struct qed_dev *cdev); + /** * @brief Notify MFW about the change in base device properties * diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 8939ed6e08b7..5ce825ca5f24 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -518,6 +518,8 @@ 0x180824UL #define MISC_REG_AEU_GENERAL_ATTN_0 \ 0x008400UL +#define MISC_REG_AEU_GENERAL_ATTN_35 \ + 0x00848cUL #define CAU_REG_SB_ADDR_MEMORY \ 0x1c8000UL #define CAU_REG_SB_VAR_MEMORY \ diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index eb88bbc6b193..3e0f7c46bb1b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -790,6 +790,17 @@ static int qed_spq_pend_post(struct qed_hwfn *p_hwfn) SPQ_HIGH_PRI_RESERVE_DEFAULT); } +static void qed_spq_recov_set_ret_code(struct qed_spq_entry *p_ent, + u8 *fw_return_code) +{ + if (!fw_return_code) + return; + + if (p_ent->elem.hdr.protocol_id == PROTOCOLID_ROCE || + p_ent->elem.hdr.protocol_id == PROTOCOLID_IWARP) + *fw_return_code = RDMA_RETURN_OK; +} + /* Avoid overriding of SPQ entries when getting out-of-order completions, by * marking the completions in a bitmap and increasing the chain consumer only * for the first successive completed entries. @@ -825,6 +836,17 @@ int qed_spq_post(struct qed_hwfn *p_hwfn, return -EINVAL; } + if (p_hwfn->cdev->recov_in_prog) { + DP_VERBOSE(p_hwfn, + QED_MSG_SPQ, + "Recovery is in progress. Skip spq post [cmd %02x protocol %02x]\n", + p_ent->elem.hdr.cmd_id, p_ent->elem.hdr.protocol_id); + + /* Let the flow complete w/o any error handling */ + qed_spq_recov_set_ret_code(p_ent, fw_return_code); + return 0; + } + /* Complete the entry */ rc = qed_spq_fill_entry(p_hwfn, p_ent); diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index ca6290fa0f30..71e28be58102 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -4447,6 +4447,13 @@ int qed_sriov_disable(struct qed_dev *cdev, bool pci_enabled) if (cdev->p_iov_info && cdev->p_iov_info->num_vfs && pci_enabled) pci_disable_sriov(cdev->pdev); + if (cdev->recov_in_prog) { + DP_VERBOSE(cdev, + QED_MSG_IOV, + "Skip SRIOV disable operations in the device since a recovery is in progress\n"); + goto out; + } + for_each_hwfn(cdev, i) { struct qed_hwfn *hwfn = &cdev->hwfns[i]; struct qed_ptt *ptt = qed_ptt_acquire(hwfn); @@ -4486,7 +4493,7 @@ int qed_sriov_disable(struct qed_dev *cdev, bool pci_enabled) qed_ptt_release(hwfn, ptt); } - +out: qed_iov_set_vfs_to_disable(cdev, false); return 0; diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index 91c536a01b56..c2a1b7dbe4eb 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h @@ -764,6 +764,7 @@ struct qed_probe_params { u32 dp_module; u8 dp_level; bool is_vf; + bool recov_in_prog; }; #define QED_DRV_VER_STR_SIZE 12 @@ -810,6 +811,7 @@ struct qed_common_cb_ops { void (*arfs_filter_op)(void *dev, void *fltr, u8 fw_rc); void (*link_update)(void *dev, struct qed_link_output *link); + void (*schedule_recovery_handler)(void *dev); void (*dcbx_aen)(void *dev, struct qed_dcbx_get *get, u32 mib_type); void (*get_generic_tlv_data)(void *dev, struct qed_generic_tlvs *data); void (*get_protocol_tlv_data)(void *dev, void *data); @@ -1057,6 +1059,24 @@ struct qed_common_ops { int (*db_recovery_del)(struct qed_dev *cdev, void __iomem *db_addr, void *db_data); +/** + * @brief recovery_process - Trigger a recovery process + * + * @param cdev + * + * @return 0 on success, error otherwise. + */ + int (*recovery_process)(struct qed_dev *cdev); + +/** + * @brief recovery_prolog - Execute the prolog operations of a recovery process + * + * @param cdev + * + * @return 0 on success, error otherwise. + */ + int (*recovery_prolog)(struct qed_dev *cdev); + /** * @brief update_drv_state - API to inform the change in the driver state. * -- cgit v1.2.3-58-ga151 From 278396de78a9b59a692bc140233bde3a9d8a8a31 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Sun, 20 Jan 2019 11:36:39 +0200 Subject: qede: Error recovery process This patch adds the error recovery process in the qede driver. The process includes a partial/customized driver unload and load, which allows it to look like a short suspend period to the kernel while preserving the net devices' state. Signed-off-by: Tomer Tayar Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qede/qede.h | 3 + drivers/net/ethernet/qlogic/qede/qede_main.c | 300 ++++++++++++++++++++++----- drivers/net/ethernet/qlogic/qede/qede_rdma.c | 64 ++++-- include/linux/qed/qede_rdma.h | 21 +- 4 files changed, 314 insertions(+), 74 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 613249d1e967..843416404aeb 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -162,6 +162,7 @@ struct qede_rdma_dev { struct list_head entry; struct list_head rdma_event_list; struct workqueue_struct *rdma_wq; + bool exp_recovery; }; struct qede_ptp; @@ -264,6 +265,7 @@ struct qede_dev { enum QEDE_STATE { QEDE_STATE_CLOSED, QEDE_STATE_OPEN, + QEDE_STATE_RECOVERY, }; #define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo)) @@ -462,6 +464,7 @@ struct qede_fastpath { #define QEDE_CSUM_UNNECESSARY BIT(1) #define QEDE_TUNN_CSUM_UNNECESSARY BIT(2) +#define QEDE_SP_RECOVERY 0 #define QEDE_SP_RX_MODE 1 #ifdef CONFIG_RFS_ACCEL diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 5a74fcbdbc2b..de955f2b2980 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -133,23 +133,12 @@ static int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void qede_remove(struct pci_dev *pdev); static void qede_shutdown(struct pci_dev *pdev); static void qede_link_update(void *dev, struct qed_link_output *link); +static void qede_schedule_recovery_handler(void *dev); +static void qede_recovery_handler(struct qede_dev *edev); static void qede_get_eth_tlv_data(void *edev, void *data); static void qede_get_generic_tlv_data(void *edev, struct qed_generic_tlvs *data); -/* The qede lock is used to protect driver state change and driver flows that - * are not reentrant. - */ -void __qede_lock(struct qede_dev *edev) -{ - mutex_lock(&edev->qede_lock); -} - -void __qede_unlock(struct qede_dev *edev) -{ - mutex_unlock(&edev->qede_lock); -} - #ifdef CONFIG_QED_SRIOV static int qede_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan, u8 qos, __be16 vlan_proto) @@ -231,6 +220,7 @@ static struct qed_eth_cb_ops qede_ll_ops = { .arfs_filter_op = qede_arfs_filter_op, #endif .link_update = qede_link_update, + .schedule_recovery_handler = qede_schedule_recovery_handler, .get_generic_tlv_data = qede_get_generic_tlv_data, .get_protocol_tlv_data = qede_get_eth_tlv_data, }, @@ -950,11 +940,57 @@ err: return -ENOMEM; } +/* The qede lock is used to protect driver state change and driver flows that + * are not reentrant. + */ +void __qede_lock(struct qede_dev *edev) +{ + mutex_lock(&edev->qede_lock); +} + +void __qede_unlock(struct qede_dev *edev) +{ + mutex_unlock(&edev->qede_lock); +} + +/* This version of the lock should be used when acquiring the RTNL lock is also + * needed in addition to the internal qede lock. + */ +void qede_lock(struct qede_dev *edev) +{ + rtnl_lock(); + __qede_lock(edev); +} + +void qede_unlock(struct qede_dev *edev) +{ + __qede_unlock(edev); + rtnl_unlock(); +} + static void qede_sp_task(struct work_struct *work) { struct qede_dev *edev = container_of(work, struct qede_dev, sp_task.work); + /* The locking scheme depends on the specific flag: + * In case of QEDE_SP_RECOVERY, acquiring the RTNL lock is required to + * ensure that ongoing flows are ended and new ones are not started. + * In other cases - only the internal qede lock should be acquired. + */ + + if (test_and_clear_bit(QEDE_SP_RECOVERY, &edev->sp_flags)) { +#ifdef CONFIG_QED_SRIOV + /* SRIOV must be disabled outside the lock to avoid a deadlock. + * The recovery of the active VFs is currently not supported. + */ + qede_sriov_configure(edev->pdev, 0); +#endif + qede_lock(edev); + qede_recovery_handler(edev); + qede_unlock(edev); + } + __qede_lock(edev); if (test_and_clear_bit(QEDE_SP_RX_MODE, &edev->sp_flags)) @@ -1031,8 +1067,13 @@ static void qede_log_probe(struct qede_dev *edev) enum qede_probe_mode { QEDE_PROBE_NORMAL, + QEDE_PROBE_RECOVERY, }; +#define QEDE_RDMA_PROBE_MODE(mode) \ + ((mode) == QEDE_PROBE_NORMAL ? QEDE_RDMA_PROBE_NORMAL \ + : QEDE_RDMA_PROBE_RECOVERY) + static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, bool is_vf, enum qede_probe_mode mode) { @@ -1051,6 +1092,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, probe_params.dp_module = dp_module; probe_params.dp_level = dp_level; probe_params.is_vf = is_vf; + probe_params.recov_in_prog = (mode == QEDE_PROBE_RECOVERY); cdev = qed_ops->common->probe(pdev, &probe_params); if (!cdev) { rc = -ENODEV; @@ -1078,11 +1120,20 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, if (rc) goto err2; - edev = qede_alloc_etherdev(cdev, pdev, &dev_info, dp_module, - dp_level); - if (!edev) { - rc = -ENOMEM; - goto err2; + if (mode != QEDE_PROBE_RECOVERY) { + edev = qede_alloc_etherdev(cdev, pdev, &dev_info, dp_module, + dp_level); + if (!edev) { + rc = -ENOMEM; + goto err2; + } + } else { + struct net_device *ndev = pci_get_drvdata(pdev); + + edev = netdev_priv(ndev); + edev->cdev = cdev; + memset(&edev->stats, 0, sizeof(edev->stats)); + memcpy(&edev->dev_info, &dev_info, sizeof(dev_info)); } if (is_vf) @@ -1090,28 +1141,31 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, qede_init_ndev(edev); - rc = qede_rdma_dev_add(edev); + rc = qede_rdma_dev_add(edev, QEDE_RDMA_PROBE_MODE(mode)); if (rc) goto err3; - /* Prepare the lock prior to the registration of the netdev, - * as once it's registered we might reach flows requiring it - * [it's even possible to reach a flow needing it directly - * from there, although it's unlikely]. - */ - INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task); - mutex_init(&edev->qede_lock); - rc = register_netdev(edev->ndev); - if (rc) { - DP_NOTICE(edev, "Cannot register net-device\n"); - goto err4; + if (mode != QEDE_PROBE_RECOVERY) { + /* Prepare the lock prior to the registration of the netdev, + * as once it's registered we might reach flows requiring it + * [it's even possible to reach a flow needing it directly + * from there, although it's unlikely]. + */ + INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task); + mutex_init(&edev->qede_lock); + + rc = register_netdev(edev->ndev); + if (rc) { + DP_NOTICE(edev, "Cannot register net-device\n"); + goto err4; + } } edev->ops->common->set_name(cdev, edev->ndev->name); /* PTP not supported on VFs */ if (!is_vf) - qede_ptp_enable(edev, true); + qede_ptp_enable(edev, (mode == QEDE_PROBE_NORMAL)); edev->ops->register_ops(cdev, &qede_ll_ops, edev); @@ -1126,7 +1180,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, return 0; err4: - qede_rdma_dev_remove(edev); + qede_rdma_dev_remove(edev, QEDE_RDMA_PROBE_MODE(mode)); err3: free_netdev(edev->ndev); err2: @@ -1162,8 +1216,13 @@ static int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id) enum qede_remove_mode { QEDE_REMOVE_NORMAL, + QEDE_REMOVE_RECOVERY, }; +#define QEDE_RDMA_REMOVE_MODE(mode) \ + ((mode) == QEDE_REMOVE_NORMAL ? QEDE_RDMA_REMOVE_NORMAL \ + : QEDE_RDMA_REMOVE_RECOVERY) + static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) { struct net_device *ndev = pci_get_drvdata(pdev); @@ -1172,15 +1231,19 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) DP_INFO(edev, "Starting qede_remove\n"); - qede_rdma_dev_remove(edev); - unregister_netdev(ndev); - cancel_delayed_work_sync(&edev->sp_task); + qede_rdma_dev_remove(edev, QEDE_RDMA_REMOVE_MODE(mode)); - qede_ptp_disable(edev); + if (mode != QEDE_REMOVE_RECOVERY) { + unregister_netdev(ndev); - edev->ops->common->set_power_state(cdev, PCI_D0); + cancel_delayed_work_sync(&edev->sp_task); - pci_set_drvdata(pdev, NULL); + edev->ops->common->set_power_state(cdev, PCI_D0); + + pci_set_drvdata(pdev, NULL); + } + + qede_ptp_disable(edev); /* Use global ops since we've freed edev */ qed_ops->common->slowpath_stop(cdev); @@ -1194,7 +1257,8 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) * [e.g., QED register callbacks] won't break anything when * accessing the netdevice. */ - free_netdev(ndev); + if (mode != QEDE_REMOVE_RECOVERY) + free_netdev(ndev); dev_info(&pdev->dev, "Ending qede_remove successfully\n"); } @@ -1539,6 +1603,58 @@ static int qede_alloc_mem_load(struct qede_dev *edev) return 0; } +static void qede_empty_tx_queue(struct qede_dev *edev, + struct qede_tx_queue *txq) +{ + unsigned int pkts_compl = 0, bytes_compl = 0; + struct netdev_queue *netdev_txq; + int rc, len = 0; + + netdev_txq = netdev_get_tx_queue(edev->ndev, txq->ndev_txq_id); + + while (qed_chain_get_cons_idx(&txq->tx_pbl) != + qed_chain_get_prod_idx(&txq->tx_pbl)) { + DP_VERBOSE(edev, NETIF_MSG_IFDOWN, + "Freeing a packet on tx queue[%d]: chain_cons 0x%x, chain_prod 0x%x\n", + txq->index, qed_chain_get_cons_idx(&txq->tx_pbl), + qed_chain_get_prod_idx(&txq->tx_pbl)); + + rc = qede_free_tx_pkt(edev, txq, &len); + if (rc) { + DP_NOTICE(edev, + "Failed to free a packet on tx queue[%d]: chain_cons 0x%x, chain_prod 0x%x\n", + txq->index, + qed_chain_get_cons_idx(&txq->tx_pbl), + qed_chain_get_prod_idx(&txq->tx_pbl)); + break; + } + + bytes_compl += len; + pkts_compl++; + txq->sw_tx_cons++; + } + + netdev_tx_completed_queue(netdev_txq, pkts_compl, bytes_compl); +} + +static void qede_empty_tx_queues(struct qede_dev *edev) +{ + int i; + + for_each_queue(i) + if (edev->fp_array[i].type & QEDE_FASTPATH_TX) { + int cos; + + for_each_cos_in_txq(edev, cos) { + struct qede_fastpath *fp; + + fp = &edev->fp_array[i]; + qede_empty_tx_queue(edev, + &fp->txq[cos]); + } + } +} + /* This function inits fp content and resets the SB, RXQ and TXQ structures */ static void qede_init_fp(struct qede_dev *edev) { @@ -2053,6 +2169,7 @@ out: enum qede_unload_mode { QEDE_UNLOAD_NORMAL, + QEDE_UNLOAD_RECOVERY, }; static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, @@ -2068,7 +2185,8 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, clear_bit(QEDE_FLAGS_LINK_REQUESTED, &edev->flags); - edev->state = QEDE_STATE_CLOSED; + if (mode != QEDE_UNLOAD_RECOVERY) + edev->state = QEDE_STATE_CLOSED; qede_rdma_dev_event_close(edev); @@ -2076,17 +2194,20 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, netif_tx_disable(edev->ndev); netif_carrier_off(edev->ndev); - /* Reset the link */ - memset(&link_params, 0, sizeof(link_params)); - link_params.link_up = false; - edev->ops->common->set_link(edev->cdev, &link_params); - rc = qede_stop_queues(edev); - if (rc) { - qede_sync_free_irqs(edev); - goto out; - } + if (mode != QEDE_UNLOAD_RECOVERY) { + /* Reset the link */ + memset(&link_params, 0, sizeof(link_params)); + link_params.link_up = false; + edev->ops->common->set_link(edev->cdev, &link_params); - DP_INFO(edev, "Stopped Queues\n"); + rc = qede_stop_queues(edev); + if (rc) { + qede_sync_free_irqs(edev); + goto out; + } + + DP_INFO(edev, "Stopped Queues\n"); + } qede_vlan_mark_nonconfigured(edev); edev->ops->fastpath_stop(edev->cdev); @@ -2102,18 +2223,26 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, qede_napi_disable_remove(edev); + if (mode == QEDE_UNLOAD_RECOVERY) + qede_empty_tx_queues(edev); + qede_free_mem_load(edev); qede_free_fp_array(edev); out: if (!is_locked) __qede_unlock(edev); + + if (mode != QEDE_UNLOAD_RECOVERY) + DP_NOTICE(edev, "Link is down\n"); + DP_INFO(edev, "Ending qede unload\n"); } enum qede_load_mode { QEDE_LOAD_NORMAL, QEDE_LOAD_RELOAD, + QEDE_LOAD_RECOVERY, }; static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, @@ -2293,6 +2422,77 @@ static void qede_link_update(void *dev, struct qed_link_output *link) } } +static void qede_schedule_recovery_handler(void *dev) +{ + struct qede_dev *edev = dev; + + if (edev->state == QEDE_STATE_RECOVERY) { + DP_NOTICE(edev, + "Avoid scheduling a recovery handling since already in recovery state\n"); + return; + } + + set_bit(QEDE_SP_RECOVERY, &edev->sp_flags); + schedule_delayed_work(&edev->sp_task, 0); + + DP_INFO(edev, "Scheduled a recovery handler\n"); +} + +static void qede_recovery_failed(struct qede_dev *edev) +{ + netdev_err(edev->ndev, "Recovery handling has failed. Power cycle is needed.\n"); + + netif_device_detach(edev->ndev); + + if (edev->cdev) + edev->ops->common->set_power_state(edev->cdev, PCI_D3hot); +} + +static void qede_recovery_handler(struct qede_dev *edev) +{ + u32 curr_state = edev->state; + int rc; + + DP_NOTICE(edev, "Starting a recovery process\n"); + + /* No need to acquire first the qede_lock since is done by qede_sp_task + * before calling this function. + */ + edev->state = QEDE_STATE_RECOVERY; + + edev->ops->common->recovery_prolog(edev->cdev); + + if (curr_state == QEDE_STATE_OPEN) + qede_unload(edev, QEDE_UNLOAD_RECOVERY, true); + + __qede_remove(edev->pdev, QEDE_REMOVE_RECOVERY); + + rc = __qede_probe(edev->pdev, edev->dp_module, edev->dp_level, + IS_VF(edev), QEDE_PROBE_RECOVERY); + if (rc) { + edev->cdev = NULL; + goto err; + } + + if (curr_state == QEDE_STATE_OPEN) { + rc = qede_load(edev, QEDE_LOAD_RECOVERY, true); + if (rc) + goto err; + + qede_config_rx_mode(edev->ndev); + udp_tunnel_get_rx_info(edev->ndev); + } + + edev->state = curr_state; + + DP_NOTICE(edev, "Recovery handling is done\n"); + + return; + +err: + qede_recovery_failed(edev); +} + static bool qede_is_txq_full(struct qede_dev *edev, struct qede_tx_queue *txq) { struct netdev_queue *netdev_txq; diff --git a/drivers/net/ethernet/qlogic/qede/qede_rdma.c b/drivers/net/ethernet/qlogic/qede/qede_rdma.c index 1900bf7e67d1..9668e5e47d5f 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_rdma.c +++ b/drivers/net/ethernet/qlogic/qede/qede_rdma.c @@ -50,6 +50,8 @@ static void _qede_rdma_dev_add(struct qede_dev *edev) if (!qedr_drv) return; + /* Leftovers from previous error recovery */ + edev->rdma_info.exp_recovery = false; edev->rdma_info.qedr_dev = qedr_drv->add(edev->cdev, edev->pdev, edev->ndev); } @@ -87,21 +89,26 @@ static void qede_rdma_destroy_wq(struct qede_dev *edev) destroy_workqueue(edev->rdma_info.rdma_wq); } -int qede_rdma_dev_add(struct qede_dev *edev) +int qede_rdma_dev_add(struct qede_dev *edev, enum qede_rdma_probe_mode mode) { - int rc = 0; + int rc; - if (qede_rdma_supported(edev)) { - rc = qede_rdma_create_wq(edev); - if (rc) - return rc; + if (!qede_rdma_supported(edev)) + return 0; - INIT_LIST_HEAD(&edev->rdma_info.entry); - mutex_lock(&qedr_dev_list_lock); - list_add_tail(&edev->rdma_info.entry, &qedr_dev_list); - _qede_rdma_dev_add(edev); - mutex_unlock(&qedr_dev_list_lock); - } + /* Cannot start qedr while recovering since it wasn't fully stopped */ + if (mode == QEDE_RDMA_PROBE_RECOVERY) + return 0; + + rc = qede_rdma_create_wq(edev); + if (rc) + return rc; + + INIT_LIST_HEAD(&edev->rdma_info.entry); + mutex_lock(&qedr_dev_list_lock); + list_add_tail(&edev->rdma_info.entry, &qedr_dev_list); + _qede_rdma_dev_add(edev); + mutex_unlock(&qedr_dev_list_lock); return rc; } @@ -110,19 +117,31 @@ static void _qede_rdma_dev_remove(struct qede_dev *edev) { if (qedr_drv && qedr_drv->remove && edev->rdma_info.qedr_dev) qedr_drv->remove(edev->rdma_info.qedr_dev); - edev->rdma_info.qedr_dev = NULL; } -void qede_rdma_dev_remove(struct qede_dev *edev) +void qede_rdma_dev_remove(struct qede_dev *edev, + enum qede_rdma_remove_mode mode) { if (!qede_rdma_supported(edev)) return; - qede_rdma_destroy_wq(edev); - mutex_lock(&qedr_dev_list_lock); - _qede_rdma_dev_remove(edev); - list_del(&edev->rdma_info.entry); - mutex_unlock(&qedr_dev_list_lock); + /* Cannot remove qedr while recovering since it wasn't fully stopped */ + if (mode == QEDE_RDMA_REMOVE_NORMAL) { + qede_rdma_destroy_wq(edev); + mutex_lock(&qedr_dev_list_lock); + if (!edev->rdma_info.exp_recovery) + _qede_rdma_dev_remove(edev); + edev->rdma_info.qedr_dev = NULL; + list_del(&edev->rdma_info.entry); + mutex_unlock(&qedr_dev_list_lock); + } else { + if (!edev->rdma_info.exp_recovery) { + mutex_lock(&qedr_dev_list_lock); + _qede_rdma_dev_remove(edev); + mutex_unlock(&qedr_dev_list_lock); + } + edev->rdma_info.exp_recovery = true; + } } static void _qede_rdma_dev_open(struct qede_dev *edev) @@ -204,7 +223,8 @@ void qede_rdma_unregister_driver(struct qedr_driver *drv) mutex_lock(&qedr_dev_list_lock); list_for_each_entry(edev, &qedr_dev_list, rdma_info.entry) { - if (edev->rdma_info.qedr_dev) + /* If device has experienced recovery it was already removed */ + if (edev->rdma_info.qedr_dev && !edev->rdma_info.exp_recovery) _qede_rdma_dev_remove(edev); } qedr_drv = NULL; @@ -284,6 +304,10 @@ static void qede_rdma_add_event(struct qede_dev *edev, { struct qede_rdma_event_work *event_node; + /* If a recovery was experienced avoid adding the event */ + if (edev->rdma_info.exp_recovery) + return; + if (!edev->rdma_info.qedr_dev) return; diff --git a/include/linux/qed/qede_rdma.h b/include/linux/qed/qede_rdma.h index 9904617a9730..e29d7199c10e 100644 --- a/include/linux/qed/qede_rdma.h +++ b/include/linux/qed/qede_rdma.h @@ -55,6 +55,16 @@ struct qede_rdma_event_work { enum qede_rdma_event event; }; +enum qede_rdma_probe_mode { + QEDE_RDMA_PROBE_NORMAL, + QEDE_RDMA_PROBE_RECOVERY, +}; + +enum qede_rdma_remove_mode { + QEDE_RDMA_REMOVE_NORMAL, + QEDE_RDMA_REMOVE_RECOVERY, +}; + struct qedr_driver { unsigned char name[32]; @@ -74,21 +84,24 @@ void qede_rdma_unregister_driver(struct qedr_driver *drv); bool qede_rdma_supported(struct qede_dev *dev); #if IS_ENABLED(CONFIG_QED_RDMA) -int qede_rdma_dev_add(struct qede_dev *dev); +int qede_rdma_dev_add(struct qede_dev *dev, enum qede_rdma_probe_mode mode); void qede_rdma_dev_event_open(struct qede_dev *dev); void qede_rdma_dev_event_close(struct qede_dev *dev); -void qede_rdma_dev_remove(struct qede_dev *dev); +void qede_rdma_dev_remove(struct qede_dev *dev, + enum qede_rdma_remove_mode mode); void qede_rdma_event_changeaddr(struct qede_dev *edr); #else -static inline int qede_rdma_dev_add(struct qede_dev *dev) +static inline int qede_rdma_dev_add(struct qede_dev *dev, + enum qede_rdma_probe_mode mode) { return 0; } static inline void qede_rdma_dev_event_open(struct qede_dev *dev) {} static inline void qede_rdma_dev_event_close(struct qede_dev *dev) {} -static inline void qede_rdma_dev_remove(struct qede_dev *dev) {} +static inline void qede_rdma_dev_remove(struct qede_dev *dev, + enum qede_rdma_remove_mode mode) {} static inline void qede_rdma_event_changeaddr(struct qede_dev *edr) {} #endif #endif -- cgit v1.2.3-58-ga151 From 5d9bf43357d5b0ef386bcaa2cafb94898364ff7d Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Mon, 21 Jan 2019 14:26:37 +0800 Subject: net: dpaa2: improve PTP Kconfig option Converted to use "imply" instead of "select" for PTP_1588_CLOCK driver selecting. This could break the hard dependency between the PTP clock subsystem and ethernet drivers. This patch also set "default y" for dpaa2 ptp driver building to provide user an available ptp clock in default. Signed-off-by: Yangbo Lu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig index 809a155eb193..f6d244c663fd 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig @@ -9,8 +9,9 @@ config FSL_DPAA2_ETH config FSL_DPAA2_PTP_CLOCK tristate "Freescale DPAA2 PTP Clock" - depends on FSL_DPAA2_ETH && POSIX_TIMERS - select PTP_1588_CLOCK + depends on FSL_DPAA2_ETH + imply PTP_1588_CLOCK + default y help This driver adds support for using the DPAA2 1588 timer module as a PTP clock. -- cgit v1.2.3-58-ga151 From a8cf59a6692c9c55a5a10257de97919fae6edef8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 16 Jan 2019 17:12:15 +0100 Subject: scsi: communicate max segment size to the DMA mapping code When a host driver sets a maximum segment size we should not only propagate that setting to the block layer, which can merge segments, but also to the DMA mapping layer which can merge segments as well. Fixes: 50c2e9107f ("scsi: introduce a max_segment_size host_template parameters") Signed-off-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/ata/pata_macio.c | 9 ++++----- drivers/ata/sata_inic162x.c | 22 +++++++++------------- drivers/firewire/sbp2.c | 5 +---- drivers/scsi/aacraid/linit.c | 9 ++++----- drivers/scsi/scsi_lib.c | 4 ++-- 5 files changed, 20 insertions(+), 29 deletions(-) diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c index 8cc9c429ad95..9e7fc302430f 100644 --- a/drivers/ata/pata_macio.c +++ b/drivers/ata/pata_macio.c @@ -915,6 +915,10 @@ static struct scsi_host_template pata_macio_sht = { .sg_tablesize = MAX_DCMDS, /* We may not need that strict one */ .dma_boundary = ATA_DMA_BOUNDARY, + /* Not sure what the real max is but we know it's less than 64K, let's + * use 64K minus 256 + */ + .max_segment_size = MAX_DBDMA_SEG, .slave_configure = pata_macio_slave_config, }; @@ -1044,11 +1048,6 @@ static int pata_macio_common_init(struct pata_macio_priv *priv, /* Make sure we have sane initial timings in the cache */ pata_macio_default_timings(priv); - /* Not sure what the real max is but we know it's less than 64K, let's - * use 64K minus 256 - */ - dma_set_max_seg_size(priv->dev, MAX_DBDMA_SEG); - /* Allocate libata host for 1 port */ memset(&pinfo, 0, sizeof(struct ata_port_info)); pmac_macio_calc_timing_masks(priv, &pinfo); diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index e0bcf9b2dab0..174e84ce4379 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -245,8 +245,15 @@ struct inic_port_priv { static struct scsi_host_template inic_sht = { ATA_BASE_SHT(DRV_NAME), - .sg_tablesize = LIBATA_MAX_PRD, /* maybe it can be larger? */ - .dma_boundary = INIC_DMA_BOUNDARY, + .sg_tablesize = LIBATA_MAX_PRD, /* maybe it can be larger? */ + + /* + * This controller is braindamaged. dma_boundary is 0xffff like others + * but it will lock up the whole machine HARD if 65536 byte PRD entry + * is fed. Reduce maximum segment size. + */ + .dma_boundary = INIC_DMA_BOUNDARY, + .max_segment_size = 65536 - 512, }; static const int scr_map[] = { @@ -868,17 +875,6 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; } - /* - * This controller is braindamaged. dma_boundary is 0xffff - * like others but it will lock up the whole machine HARD if - * 65536 byte PRD entry is fed. Reduce maximum segment size. - */ - rc = dma_set_max_seg_size(&pdev->dev, 65536 - 512); - if (rc) { - dev_err(&pdev->dev, "failed to set the maximum segment size\n"); - return rc; - } - rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl); if (rc) { dev_err(&pdev->dev, "failed to initialize controller\n"); diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 09b845e90114..a785ffd5af89 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -1144,10 +1144,6 @@ static int sbp2_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) if (device->is_local) return -ENODEV; - if (dma_get_max_seg_size(device->card->device) > SBP2_MAX_SEG_SIZE) - WARN_ON(dma_set_max_seg_size(device->card->device, - SBP2_MAX_SEG_SIZE)); - shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt)); if (shost == NULL) return -ENOMEM; @@ -1610,6 +1606,7 @@ static struct scsi_host_template scsi_driver_template = { .eh_abort_handler = sbp2_scsi_abort, .this_id = -1, .sg_tablesize = SG_ALL, + .max_segment_size = SBP2_MAX_SEG_SIZE, .can_queue = 1, .sdev_attrs = sbp2_scsi_sysfs_attrs, }; diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 634ddb90e7aa..7e56a11836c1 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1747,11 +1747,10 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) shost->max_sectors = (shost->sg_tablesize * 8) + 112; } - error = dma_set_max_seg_size(&pdev->dev, - (aac->adapter_info.options & AAC_OPT_NEW_COMM) ? - (shost->max_sectors << 9) : 65536); - if (error) - goto out_deinit; + if (aac->adapter_info.options & AAC_OPT_NEW_COMM) + shost->max_segment_size = shost->max_sectors << 9; + else + shost->max_segment_size = 65536; /* * Firmware printf works only with older firmware. diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index b13cc9288ba0..6d65ac584eba 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1842,8 +1842,8 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) blk_queue_segment_boundary(q, shost->dma_boundary); dma_set_seg_boundary(dev, shost->dma_boundary); - blk_queue_max_segment_size(q, - min(shost->max_segment_size, dma_get_max_seg_size(dev))); + blk_queue_max_segment_size(q, shost->max_segment_size); + dma_set_max_seg_size(dev, shost->max_segment_size); /* * Set a reasonable default alignment: The larger of 32-byte (dword), -- cgit v1.2.3-58-ga151 From 7961cba6f7d8215fa632df3d220e5154bb825249 Mon Sep 17 00:00:00 2001 From: "Ewan D. Milne" Date: Thu, 17 Jan 2019 11:14:44 -0500 Subject: scsi: lpfc: nvme: avoid hang / use-after-free when destroying localport We cannot wait on a completion object in the lpfc_nvme_lport structure in the _destroy_localport() code path because the NVMe/fc transport will free that structure immediately after the .localport_delete() callback. This results in a use-after-free, and a hang if slub_debug=FZPU is enabled. Fix this by putting the completion on the stack. Signed-off-by: Ewan D. Milne Acked-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvme.c | 16 +++++++++------- drivers/scsi/lpfc/lpfc_nvme.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 4c66b19e6199..8c9f79042228 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -297,7 +297,8 @@ lpfc_nvme_localport_delete(struct nvme_fc_local_port *localport) lport); /* release any threads waiting for the unreg to complete */ - complete(&lport->lport_unreg_done); + if (lport->vport->localport) + complete(lport->lport_unreg_cmp); } /* lpfc_nvme_remoteport_delete @@ -2545,7 +2546,8 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) */ void lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, - struct lpfc_nvme_lport *lport) + struct lpfc_nvme_lport *lport, + struct completion *lport_unreg_cmp) { #if (IS_ENABLED(CONFIG_NVME_FC)) u32 wait_tmo; @@ -2557,8 +2559,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, */ wait_tmo = msecs_to_jiffies(LPFC_NVME_WAIT_TMO * 1000); while (true) { - ret = wait_for_completion_timeout(&lport->lport_unreg_done, - wait_tmo); + ret = wait_for_completion_timeout(lport_unreg_cmp, wait_tmo); if (unlikely(!ret)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, "6176 Lport %p Localport %p wait " @@ -2592,12 +2593,12 @@ lpfc_nvme_destroy_localport(struct lpfc_vport *vport) struct lpfc_nvme_lport *lport; struct lpfc_nvme_ctrl_stat *cstat; int ret; + DECLARE_COMPLETION_ONSTACK(lport_unreg_cmp); if (vport->nvmei_support == 0) return; localport = vport->localport; - vport->localport = NULL; lport = (struct lpfc_nvme_lport *)localport->private; cstat = lport->cstat; @@ -2608,13 +2609,14 @@ lpfc_nvme_destroy_localport(struct lpfc_vport *vport) /* lport's rport list is clear. Unregister * lport and release resources. */ - init_completion(&lport->lport_unreg_done); + lport->lport_unreg_cmp = &lport_unreg_cmp; ret = nvme_fc_unregister_localport(localport); /* Wait for completion. This either blocks * indefinitely or succeeds */ - lpfc_nvme_lport_unreg_wait(vport, lport); + lpfc_nvme_lport_unreg_wait(vport, lport, &lport_unreg_cmp); + vport->localport = NULL; kfree(cstat); /* Regardless of the unregister upcall response, clear diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h index cfd4719be25c..b234d0298994 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.h +++ b/drivers/scsi/lpfc/lpfc_nvme.h @@ -50,7 +50,7 @@ struct lpfc_nvme_ctrl_stat { /* Declare nvme-based local and remote port definitions. */ struct lpfc_nvme_lport { struct lpfc_vport *vport; - struct completion lport_unreg_done; + struct completion *lport_unreg_cmp; /* Add stats counters here */ struct lpfc_nvme_ctrl_stat *cstat; atomic_t fc4NvmeLsRequests; -- cgit v1.2.3-58-ga151 From c41f59884be5cca293ed61f3d64637dbba3a6381 Mon Sep 17 00:00:00 2001 From: "Ewan D. Milne" Date: Thu, 17 Jan 2019 11:14:45 -0500 Subject: scsi: lpfc: nvmet: avoid hang / use-after-free when destroying targetport We cannot wait on a completion object in the lpfc_nvme_targetport structure in the _destroy_targetport() code path because the NVMe/fc transport will free that structure immediately after the .targetport_delete() callback. This results in a use-after-free, and a hang if slub_debug=FZPU is enabled. Fix this by putting the completion on the stack. Signed-off-by: Ewan D. Milne Acked-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvmet.c | 8 +++++--- drivers/scsi/lpfc/lpfc_nvmet.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 6245f442d784..95fee83090eb 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1003,7 +1003,8 @@ lpfc_nvmet_targetport_delete(struct nvmet_fc_target_port *targetport) struct lpfc_nvmet_tgtport *tport = targetport->private; /* release any threads waiting for the unreg to complete */ - complete(&tport->tport_unreg_done); + if (tport->phba->targetport) + complete(tport->tport_unreg_cmp); } static void @@ -1692,6 +1693,7 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) struct lpfc_nvmet_tgtport *tgtp; struct lpfc_queue *wq; uint32_t qidx; + DECLARE_COMPLETION_ONSTACK(tport_unreg_cmp); if (phba->nvmet_support == 0) return; @@ -1701,9 +1703,9 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) wq = phba->sli4_hba.nvme_wq[qidx]; lpfc_nvmet_wqfull_flush(phba, wq, NULL); } - init_completion(&tgtp->tport_unreg_done); + tgtp->tport_unreg_cmp = &tport_unreg_cmp; nvmet_fc_unregister_targetport(phba->targetport); - wait_for_completion_timeout(&tgtp->tport_unreg_done, 5); + wait_for_completion_timeout(&tport_unreg_cmp, 5); lpfc_nvmet_cleanup_io_context(phba); } phba->targetport = NULL; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h index 1aaff63f1f41..0ec1082ce7ef 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.h +++ b/drivers/scsi/lpfc/lpfc_nvmet.h @@ -34,7 +34,7 @@ /* Used for NVME Target */ struct lpfc_nvmet_tgtport { struct lpfc_hba *phba; - struct completion tport_unreg_done; + struct completion *tport_unreg_cmp; /* Stats counters - lpfc_nvmet_unsol_ls_buffer */ atomic_t rcv_ls_req_in; -- cgit v1.2.3-58-ga151 From fe35a40e675473eb65f2f5462b82770f324b5689 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Sat, 12 Jan 2019 22:14:30 +0530 Subject: scsi: csiostor: fix NULL pointer dereference in csio_vport_set_state() Assign fc_vport to ln->fc_vport before calling csio_fcoe_alloc_vnp() to avoid a NULL pointer dereference in csio_vport_set_state(). ln->fc_vport is dereferenced in csio_vport_set_state(). Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/csiostor/csio_attr.c b/drivers/scsi/csiostor/csio_attr.c index 8a004036e3d7..9bd2bd8dc2be 100644 --- a/drivers/scsi/csiostor/csio_attr.c +++ b/drivers/scsi/csiostor/csio_attr.c @@ -594,12 +594,12 @@ csio_vport_create(struct fc_vport *fc_vport, bool disable) } fc_vport_set_state(fc_vport, FC_VPORT_INITIALIZING); + ln->fc_vport = fc_vport; if (csio_fcoe_alloc_vnp(hw, ln)) goto error; *(struct csio_lnode **)fc_vport->dd_data = ln; - ln->fc_vport = fc_vport; if (!fc_vport->node_name) fc_vport->node_name = wwn_to_u64(csio_ln_wwnn(ln)); if (!fc_vport->port_name) -- cgit v1.2.3-58-ga151 From 17b42a20d7ca59377788c6a2409e77569570cc10 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Mon, 21 Jan 2019 17:26:41 +0900 Subject: net: altera_tse: fix connect_local_phy error path The connect_local_phy should return NULL (not negative errno) on error, since its caller expects it. Signed-off-by: Atsushi Nemoto Acked-by: Thor Thayer Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/altera_tse_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 02921d877c08..aa1d1f5339d2 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -714,8 +714,10 @@ static struct phy_device *connect_local_phy(struct net_device *dev) phydev = phy_connect(dev, phy_id_fmt, &altera_tse_adjust_link, priv->phy_iface); - if (IS_ERR(phydev)) + if (IS_ERR(phydev)) { netdev_err(dev, "Could not attach to PHY\n"); + phydev = NULL; + } } else { int ret; -- cgit v1.2.3-58-ga151 From 40d883b091758472c79b81fa1c0e0347e24a9cff Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 22 Jan 2019 18:10:51 +0800 Subject: scsi: tcmu: fix use after free Fixes: a94a2572b977 ("scsi: tcmu: avoid cmd/qfull timers updated whenever a new cmd comes") Reported-by: Dan Carpenter Cc: Mike Christie Signed-off-by: Xiubo Li Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index c34c88ef3319..5831e0eecea1 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1317,12 +1317,13 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data) * target_complete_cmd will translate this to LUN COMM FAILURE */ scsi_status = SAM_STAT_CHECK_CONDITION; + list_del_init(&cmd->queue_entry); } else { + list_del_init(&cmd->queue_entry); idr_remove(&udev->commands, id); tcmu_free_cmd(cmd); scsi_status = SAM_STAT_TASK_SET_FULL; } - list_del_init(&cmd->queue_entry); pr_debug("Timing out cmd %u on dev %s that is %s.\n", id, udev->name, is_running ? "inflight" : "queued"); -- cgit v1.2.3-58-ga151 From d67247566450cf89a693307c9bc9f05a32d96cea Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Tue, 22 Jan 2019 18:29:22 +0100 Subject: scsi: ufs: Use explicit access size in ufshcd_dump_regs memcpy_fromio() doesn't provide any control over access size. For example, on arm64, it is implemented using readb and readq. This may trigger a synchronous external abort: [ 3.729943] Internal error: synchronous external abort: 96000210 [#1] PREEMPT SMP [ 3.737000] Modules linked in: [ 3.744371] CPU: 2 PID: 1 Comm: swapper/0 Tainted: G S 4.20.0-rc4 #16 [ 3.747413] Hardware name: Qualcomm Technologies, Inc. MSM8998 v1 MTP (DT) [ 3.755295] pstate: 00000005 (nzcv daif -PAN -UAO) [ 3.761978] pc : __memcpy_fromio+0x68/0x80 [ 3.766718] lr : ufshcd_dump_regs+0x50/0xb0 [ 3.770767] sp : ffff00000807ba00 [ 3.774830] x29: ffff00000807ba00 x28: 00000000fffffffb [ 3.778344] x27: ffff0000089db068 x26: ffff8000f6e58000 [ 3.783728] x25: 000000000000000e x24: 0000000000000800 [ 3.789023] x23: ffff8000f6e587c8 x22: 0000000000000800 [ 3.794319] x21: ffff000008908368 x20: ffff8000f6e1ab80 [ 3.799615] x19: 000000000000006c x18: ffffffffffffffff [ 3.804910] x17: 0000000000000000 x16: 0000000000000000 [ 3.810206] x15: ffff000009199648 x14: ffff000089244187 [ 3.815502] x13: ffff000009244195 x12: ffff0000091ab000 [ 3.820797] x11: 0000000005f5e0ff x10: ffff0000091998a0 [ 3.826093] x9 : 0000000000000000 x8 : ffff8000f6e1ac00 [ 3.831389] x7 : 0000000000000000 x6 : 0000000000000068 [ 3.836676] x5 : ffff8000f6e1abe8 x4 : 0000000000000000 [ 3.841971] x3 : ffff00000928c868 x2 : ffff8000f6e1abec [ 3.847267] x1 : ffff00000928c868 x0 : ffff8000f6e1abe8 [ 3.852567] Process swapper/0 (pid: 1, stack limit = 0x(____ptrval____)) [ 3.857900] Call trace: [ 3.864473] __memcpy_fromio+0x68/0x80 [ 3.866683] ufs_qcom_dump_dbg_regs+0x1c0/0x370 [ 3.870522] ufshcd_print_host_regs+0x168/0x190 [ 3.874946] ufshcd_init+0xd4c/0xde0 [ 3.879459] ufshcd_pltfrm_init+0x3c8/0x550 [ 3.883264] ufs_qcom_probe+0x24/0x60 [ 3.887188] platform_drv_probe+0x50/0xa0 Assuming aligned 32-bit registers, let's use readl, after making sure that 'offset' and 'len' are indeed multiples of 4. Fixes: ba80917d9932d ("scsi: ufs: ufshcd_dump_regs to use memcpy_fromio") Cc: Signed-off-by: Marc Gonzalez Acked-by: Tomas Winkler Reviewed-by: Jeffrey Hugo Reviewed-by: Bjorn Andersson Tested-by: Evan Green Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 71334aaf1447..2ddf24466a62 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -108,13 +108,19 @@ int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len, const char *prefix) { - u8 *regs; + u32 *regs; + size_t pos; + + if (offset % 4 != 0 || len % 4 != 0) /* keep readl happy */ + return -EINVAL; regs = kzalloc(len, GFP_KERNEL); if (!regs) return -ENOMEM; - memcpy_fromio(regs, hba->mmio_base + offset, len); + for (pos = 0; pos < len; pos += 4) + regs[pos / 4] = ufshcd_readl(hba, offset + pos); + ufshcd_hex_dump(prefix, regs, len); kfree(regs); -- cgit v1.2.3-58-ga151 From 7c62b8dd5ca89dabd9f455d19e663bad60951bd5 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 21 Jan 2019 14:54:20 +0100 Subject: net/ipv6: lower the level of "link is not ready" messages This message gets logged far too often for how interesting is it. Most distributions nowadays configure NetworkManager to use randomly generated MAC addresses for Wi-Fi network scans. The interfaces end up being periodically brought down for the address change. When they're subsequently brought back up, the message is logged, eventually flooding the log. Perhaps the message is not all that helpful: it seems to be more interesting to hear when the addrconf actually start, not when it does not. Let's lower its level. Signed-off-by: Lubomir Rintel Acked-By: Thomas Haller Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0c9e20ac01ab..84c358804355 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3495,8 +3495,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, if (!addrconf_link_ready(dev)) { /* device is not ready yet. */ - pr_info("ADDRCONF(NETDEV_UP): %s: link is not ready\n", - dev->name); + pr_debug("ADDRCONF(NETDEV_UP): %s: link is not ready\n", + dev->name); break; } -- cgit v1.2.3-58-ga151 From 25974d8af1bc5116f0d79fc6722425930fd8c0e9 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 21 Jan 2019 15:58:47 +0100 Subject: net: fec: get regulator optional According to the device tree binding the phy-supply property is optional. Use the regulator_get_optional API accordingly. The code already handles NULL just fine. This gets rid of the following warning: fec 2188000.ethernet: 2188000.ethernet supply phy not found, using dummy regulator Signed-off-by: Stefan Agner Reviewed-by: Marcel Ziswiler Acked-by: Fugang Duan Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index ae0f88bce9aa..2370dc204202 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3467,7 +3467,7 @@ fec_probe(struct platform_device *pdev) if (ret) goto failed_clk_ipg; - fep->reg_phy = devm_regulator_get(&pdev->dev, "phy"); + fep->reg_phy = devm_regulator_get_optional(&pdev->dev, "phy"); if (!IS_ERR(fep->reg_phy)) { ret = regulator_enable(fep->reg_phy); if (ret) { -- cgit v1.2.3-58-ga151 From ab06418b7fb8cc1bf82cbce3ebd74e1bbf446d06 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 21 Jan 2019 19:08:49 +0100 Subject: net: phy: Fixup GPLv2+ SPDX tags based on license text A few PHY drivers have the GPLv2+ license text. They then either have a MODULE_LICENSE() of GPLv2 only, or an SPDX tag of GPLv2 only. Since the license text is much easier to understand than either the SPDX tag or the MODULE_LICENSE, use it as the definitive source of the licence, and fixup the others when there are contradictions. Cc: David Wu Cc: Dongpo Li Cc: Michael Schmitz Signed-off-by: Andrew Lunn Acked-by: Michael Schmitz Signed-off-by: David S. Miller --- drivers/net/phy/asix.c | 8 +------- drivers/net/phy/mdio-hisi-femac.c | 16 ++-------------- drivers/net/phy/rockchip.c | 9 ++------- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/drivers/net/phy/asix.c b/drivers/net/phy/asix.c index 8ebe7f5484ae..f14ba5366b91 100644 --- a/drivers/net/phy/asix.c +++ b/drivers/net/phy/asix.c @@ -1,13 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0+ /* Driver for Asix PHYs * * Author: Michael Schmitz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ #include #include diff --git a/drivers/net/phy/mdio-hisi-femac.c b/drivers/net/phy/mdio-hisi-femac.c index b03fedd6c1d8..287f3ccf1da1 100644 --- a/drivers/net/phy/mdio-hisi-femac.c +++ b/drivers/net/phy/mdio-hisi-femac.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Hisilicon Fast Ethernet MDIO Bus Driver * * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ #include @@ -163,4 +151,4 @@ module_platform_driver(hisi_femac_mdio_driver); MODULE_DESCRIPTION("Hisilicon Fast Ethernet MAC MDIO interface driver"); MODULE_AUTHOR("Dongpo Li "); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/rockchip.c b/drivers/net/phy/rockchip.c index f1da70b9b55f..95abf7072f32 100644 --- a/drivers/net/phy/rockchip.c +++ b/drivers/net/phy/rockchip.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /** * drivers/net/phy/rockchip.c * @@ -6,12 +7,6 @@ * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd * * David Wu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * */ #include @@ -229,4 +224,4 @@ MODULE_DEVICE_TABLE(mdio, rockchip_phy_tbl); MODULE_AUTHOR("David Wu "); MODULE_DESCRIPTION("Rockchip Ethernet PHY driver"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-58-ga151 From 0f75551216091223efe1f18295f655aff6415385 Mon Sep 17 00:00:00 2001 From: Weinan Li Date: Tue, 22 Jan 2019 13:46:27 +0800 Subject: drm/i915/gvt: release shadow batch buffer and wa_ctx before destroy one workload GVT-g will shadow the privilege batch buffer and the indirect context during command scan, move the release process into intel_vgpu_destroy_workload() to ensure the resources are recycled properly. Fixes: 0cce2823ed37 ("drm/i915/gvt/kvmgt:Refine error handling for prepare_execlist_workload") Reviewed-by: Zhenyu Wang Signed-off-by: Weinan Li Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/scheduler.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index 5567ddc7760f..55bb7885e228 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -332,6 +332,9 @@ static void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx) i915_gem_object_unpin_map(wa_ctx->indirect_ctx.obj); i915_gem_object_put(wa_ctx->indirect_ctx.obj); + + wa_ctx->indirect_ctx.obj = NULL; + wa_ctx->indirect_ctx.shadow_va = NULL; } static int set_context_ppgtt_from_shadow(struct intel_vgpu_workload *workload, @@ -911,11 +914,6 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) list_del_init(&workload->list); - if (!workload->status) { - release_shadow_batch_buffer(workload); - release_shadow_wa_ctx(&workload->wa_ctx); - } - if (workload->status || (vgpu->resetting_eng & ENGINE_MASK(ring_id))) { /* if workload->status is not successful means HW GPU * has occurred GPU hang or something wrong with i915/GVT, @@ -1283,6 +1281,9 @@ void intel_vgpu_destroy_workload(struct intel_vgpu_workload *workload) { struct intel_vgpu_submission *s = &workload->vgpu->submission; + release_shadow_batch_buffer(workload); + release_shadow_wa_ctx(&workload->wa_ctx); + if (workload->shadow_mm) intel_vgpu_mm_put(workload->shadow_mm); -- cgit v1.2.3-58-ga151 From 9a71ac7e15a723e90fc40388b4b92eefaabf747c Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 23 Jan 2019 15:07:11 +1100 Subject: vfio-pci/nvlink2: Fix ancient gcc warnings Using the {0} construct as a generic initializer is perfectly fine in C, however due to a bug in old gcc there is a warning: + /kisskb/src/drivers/vfio/pci/vfio_pci_nvlink2.c: warning: (near initialization for 'cap.header') [-Wmissing-braces]: => 181:9 Since for whatever reason we still want to compile the modern kernel with such an old gcc without warnings, this changes the capabilities initialization. The gcc bugzilla: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119 Fixes: 7f92891778df ("vfio_pci: Add NVIDIA GV100GL [Tesla V100 SXM2] subdriver") Signed-off-by: Alexey Kardashevskiy Reported-by: Geert Uytterhoeven Signed-off-by: Alex Williamson --- drivers/vfio/pci/vfio_pci_nvlink2.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_nvlink2.c b/drivers/vfio/pci/vfio_pci_nvlink2.c index fd6afbd14e77..32f695ffe128 100644 --- a/drivers/vfio/pci/vfio_pci_nvlink2.c +++ b/drivers/vfio/pci/vfio_pci_nvlink2.c @@ -174,11 +174,11 @@ static int vfio_pci_nvgpu_add_capability(struct vfio_pci_device *vdev, struct vfio_pci_region *region, struct vfio_info_cap *caps) { struct vfio_pci_nvgpu_data *data = region->data; - struct vfio_region_info_cap_nvlink2_ssatgt cap = { 0 }; - - cap.header.id = VFIO_REGION_INFO_CAP_NVLINK2_SSATGT; - cap.header.version = 1; - cap.tgt = data->gpu_tgt; + struct vfio_region_info_cap_nvlink2_ssatgt cap = { + .header.id = VFIO_REGION_INFO_CAP_NVLINK2_SSATGT, + .header.version = 1, + .tgt = data->gpu_tgt + }; return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); } @@ -361,18 +361,18 @@ static int vfio_pci_npu2_add_capability(struct vfio_pci_device *vdev, struct vfio_pci_region *region, struct vfio_info_cap *caps) { struct vfio_pci_npu2_data *data = region->data; - struct vfio_region_info_cap_nvlink2_ssatgt captgt = { 0 }; - struct vfio_region_info_cap_nvlink2_lnkspd capspd = { 0 }; + struct vfio_region_info_cap_nvlink2_ssatgt captgt = { + .header.id = VFIO_REGION_INFO_CAP_NVLINK2_SSATGT, + .header.version = 1, + .tgt = data->gpu_tgt + }; + struct vfio_region_info_cap_nvlink2_lnkspd capspd = { + .header.id = VFIO_REGION_INFO_CAP_NVLINK2_LNKSPD, + .header.version = 1, + .link_speed = data->link_speed + }; int ret; - captgt.header.id = VFIO_REGION_INFO_CAP_NVLINK2_SSATGT; - captgt.header.version = 1; - captgt.tgt = data->gpu_tgt; - - capspd.header.id = VFIO_REGION_INFO_CAP_NVLINK2_LNKSPD; - capspd.header.version = 1; - capspd.link_speed = data->link_speed; - ret = vfio_info_add_capability(caps, &captgt.header, sizeof(captgt)); if (ret) return ret; -- cgit v1.2.3-58-ga151 From 7d6380cd40f7993f75c4bde5b36f6019237e8719 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 16 Nov 2018 09:59:21 -0600 Subject: ipmi:ssif: Fix handling of multi-part return messages The block number was not being compared right, it was off by one when checking the response. Some statistics wouldn't be incremented properly in some cases. Check to see if that middle-part messages always have 31 bytes of data. Signed-off-by: Corey Minyard Cc: stable@vger.kernel.org # 4.4 --- drivers/char/ipmi/ipmi_ssif.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index ca9528c4f183..b7a1ae2afaea 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -632,8 +632,9 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, /* Remove the multi-part read marker. */ len -= 2; + data += 2; for (i = 0; i < len; i++) - ssif_info->data[i] = data[i+2]; + ssif_info->data[i] = data[i]; ssif_info->multi_len = len; ssif_info->multi_pos = 1; @@ -661,8 +662,19 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, } blocknum = data[0]; + len--; + data++; + + if (blocknum != 0xff && len != 31) { + /* All blocks but the last must have 31 data bytes. */ + result = -EIO; + if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) + pr_info("Received middle message <31\n"); - if (ssif_info->multi_len + len - 1 > IPMI_MAX_MSG_LENGTH) { + goto continue_op; + } + + if (ssif_info->multi_len + len > IPMI_MAX_MSG_LENGTH) { /* Received message too big, abort the operation. */ result = -E2BIG; if (ssif_info->ssif_debug & SSIF_DEBUG_MSG) @@ -671,16 +683,14 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, goto continue_op; } - /* Remove the blocknum from the data. */ - len--; for (i = 0; i < len; i++) - ssif_info->data[i + ssif_info->multi_len] = data[i + 1]; + ssif_info->data[i + ssif_info->multi_len] = data[i]; ssif_info->multi_len += len; if (blocknum == 0xff) { /* End of read */ len = ssif_info->multi_len; data = ssif_info->data; - } else if (blocknum + 1 != ssif_info->multi_pos) { + } else if (blocknum != ssif_info->multi_pos) { /* * Out of sequence block, just abort. Block * numbers start at zero for the second block, @@ -707,6 +717,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, } } + continue_op: if (result < 0) { ssif_inc_stat(ssif_info, receive_errors); } else { @@ -714,8 +725,6 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result, ssif_inc_stat(ssif_info, received_message_parts); } - - continue_op: if (ssif_info->ssif_debug & SSIF_DEBUG_STATE) pr_info("DONE 1: state = %d, result=%d\n", ssif_info->ssif_state, result); -- cgit v1.2.3-58-ga151 From a7102c7461794a5bb31af24b08e9e0f50038897a Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Jan 2019 17:39:06 -0600 Subject: ipmi: msghandler: Fix potential Spectre v1 vulnerabilities channel and addr->channel are indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. These issues were detected with the help of Smatch: drivers/char/ipmi/ipmi_msghandler.c:1381 ipmi_set_my_address() warn: potential spectre issue 'user->intf->addrinfo' [w] (local cap) drivers/char/ipmi/ipmi_msghandler.c:1401 ipmi_get_my_address() warn: potential spectre issue 'user->intf->addrinfo' [r] (local cap) drivers/char/ipmi/ipmi_msghandler.c:1421 ipmi_set_my_LUN() warn: potential spectre issue 'user->intf->addrinfo' [w] (local cap) drivers/char/ipmi/ipmi_msghandler.c:1441 ipmi_get_my_LUN() warn: potential spectre issue 'user->intf->addrinfo' [r] (local cap) drivers/char/ipmi/ipmi_msghandler.c:2260 check_addr() warn: potential spectre issue 'intf->addrinfo' [r] (local cap) Fix this by sanitizing channel and addr->channel before using them to index user->intf->addrinfo and intf->addrinfo, correspondingly. Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://lore.kernel.org/lkml/20180423164740.GY17484@dhcp22.suse.cz/ Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index a74ce885b541..7a9fbe60a840 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -32,6 +32,7 @@ #include #include #include +#include #define IPMI_DRIVER_VERSION "39.2" @@ -1298,10 +1299,12 @@ int ipmi_set_my_address(struct ipmi_user *user, if (!user) return -ENODEV; - if (channel >= IPMI_MAX_CHANNELS) + if (channel >= IPMI_MAX_CHANNELS) { rv = -EINVAL; - else + } else { + channel = array_index_nospec(channel, IPMI_MAX_CHANNELS); user->intf->addrinfo[channel].address = address; + } release_ipmi_user(user, index); return rv; @@ -1318,10 +1321,12 @@ int ipmi_get_my_address(struct ipmi_user *user, if (!user) return -ENODEV; - if (channel >= IPMI_MAX_CHANNELS) + if (channel >= IPMI_MAX_CHANNELS) { rv = -EINVAL; - else + } else { + channel = array_index_nospec(channel, IPMI_MAX_CHANNELS); *address = user->intf->addrinfo[channel].address; + } release_ipmi_user(user, index); return rv; @@ -1338,10 +1343,12 @@ int ipmi_set_my_LUN(struct ipmi_user *user, if (!user) return -ENODEV; - if (channel >= IPMI_MAX_CHANNELS) + if (channel >= IPMI_MAX_CHANNELS) { rv = -EINVAL; - else + } else { + channel = array_index_nospec(channel, IPMI_MAX_CHANNELS); user->intf->addrinfo[channel].lun = LUN & 0x3; + } release_ipmi_user(user, index); return rv; @@ -1358,10 +1365,12 @@ int ipmi_get_my_LUN(struct ipmi_user *user, if (!user) return -ENODEV; - if (channel >= IPMI_MAX_CHANNELS) + if (channel >= IPMI_MAX_CHANNELS) { rv = -EINVAL; - else + } else { + channel = array_index_nospec(channel, IPMI_MAX_CHANNELS); *address = user->intf->addrinfo[channel].lun; + } release_ipmi_user(user, index); return rv; @@ -2184,6 +2193,7 @@ static int check_addr(struct ipmi_smi *intf, { if (addr->channel >= IPMI_MAX_CHANNELS) return -EINVAL; + addr->channel = array_index_nospec(addr->channel, IPMI_MAX_CHANNELS); *lun = intf->addrinfo[addr->channel].lun; *saddr = intf->addrinfo[addr->channel].address; return 0; -- cgit v1.2.3-58-ga151 From 479d6b39b9e0d2de648ebf146f23a1e40962068f Mon Sep 17 00:00:00 2001 From: Fred Klassen Date: Sat, 19 Jan 2019 14:28:18 -0800 Subject: ipmi: Prevent use-after-free in deliver_response Some IPMI modules (e.g. ibmpex_msg_handler()) will have ipmi_usr_hdlr handlers that call ipmi_free_recv_msg() directly. This will essentially kfree(msg), leading to use-after-free. This does not happen in the ipmi_devintf module, which will queue the message and run ipmi_free_recv_msg() later. BUG: KASAN: use-after-free in deliver_response+0x12f/0x1b0 Read of size 8 at addr ffff888a7bf20018 by task ksoftirqd/3/27 CPU: 3 PID: 27 Comm: ksoftirqd/3 Tainted: G O 4.19.11-amd64-ani99-debug #12.0.1.601133+pv Hardware name: AppNeta r1000/X11SPW-TF, BIOS 2.1a-AP 09/17/2018 Call Trace: dump_stack+0x92/0xeb print_address_description+0x73/0x290 kasan_report+0x258/0x380 deliver_response+0x12f/0x1b0 ? ipmi_free_recv_msg+0x50/0x50 deliver_local_response+0xe/0x50 handle_one_recv_msg+0x37a/0x21d0 handle_new_recv_msgs+0x1ce/0x440 ... Allocated by task 9885: kasan_kmalloc+0xa0/0xd0 kmem_cache_alloc_trace+0x116/0x290 ipmi_alloc_recv_msg+0x28/0x70 i_ipmi_request+0xb4a/0x1640 ipmi_request_settime+0x1b8/0x1e0 ... Freed by task 27: __kasan_slab_free+0x12e/0x180 kfree+0xe9/0x280 deliver_response+0x122/0x1b0 deliver_local_response+0xe/0x50 handle_one_recv_msg+0x37a/0x21d0 handle_new_recv_msgs+0x1ce/0x440 tasklet_action_common.isra.19+0xc4/0x250 __do_softirq+0x11f/0x51f Fixes: e86ee2d44b44 ("ipmi: Rework locking and shutdown for hot remove") Cc: stable@vger.kernel.org # 4.18 Signed-off-by: Fred Klassen Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 7a9fbe60a840..cc5665c47a0e 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -885,7 +885,7 @@ static int deliver_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) if (user) { user->handler->ipmi_recv_hndl(msg, user->handler_data); - release_ipmi_user(msg->user, index); + release_ipmi_user(user, index); } else { /* User went away, give up. */ ipmi_free_recv_msg(msg); -- cgit v1.2.3-58-ga151 From 77f8269606bf95fcb232ee86f6da80886f1dfae8 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 16 Jan 2019 13:33:22 +0800 Subject: ipmi: fix use-after-free of user->release_barrier.rda When we do the following test, we got oops in ipmi_msghandler driver while((1)) do service ipmievd restart & service ipmievd restart done --------------------------------------------------------------- [ 294.230186] Unable to handle kernel paging request at virtual address 0000803fea6ea008 [ 294.230188] Mem abort info: [ 294.230190] ESR = 0x96000004 [ 294.230191] Exception class = DABT (current EL), IL = 32 bits [ 294.230193] SET = 0, FnV = 0 [ 294.230194] EA = 0, S1PTW = 0 [ 294.230195] Data abort info: [ 294.230196] ISV = 0, ISS = 0x00000004 [ 294.230197] CM = 0, WnR = 0 [ 294.230199] user pgtable: 4k pages, 48-bit VAs, pgdp = 00000000a1c1b75a [ 294.230201] [0000803fea6ea008] pgd=0000000000000000 [ 294.230204] Internal error: Oops: 96000004 [#1] SMP [ 294.235211] Modules linked in: nls_utf8 isofs rpcrdma ib_iser ib_srpt target_core_mod ib_srp scsi_transport_srp ib_ipoib rdma_ucm ib_umad rdma_cm ib_cm iw_cm dm_mirror dm_region_hash dm_log dm_mod aes_ce_blk crypto_simd cryptd aes_ce_cipher ghash_ce sha2_ce ses sha256_arm64 sha1_ce hibmc_drm hisi_sas_v2_hw enclosure sg hisi_sas_main sbsa_gwdt ip_tables mlx5_ib ib_uverbs marvell ib_core mlx5_core ixgbe ipmi_si mdio hns_dsaf ipmi_devintf ipmi_msghandler hns_enet_drv hns_mdio [ 294.277745] CPU: 3 PID: 0 Comm: swapper/3 Kdump: loaded Not tainted 5.0.0-rc2+ #113 [ 294.285511] Hardware name: Huawei TaiShan 2280 /BC11SPCD, BIOS 1.37 11/21/2017 [ 294.292835] pstate: 80000005 (Nzcv daif -PAN -UAO) [ 294.297695] pc : __srcu_read_lock+0x38/0x58 [ 294.301940] lr : acquire_ipmi_user+0x2c/0x70 [ipmi_msghandler] [ 294.307853] sp : ffff00001001bc80 [ 294.311208] x29: ffff00001001bc80 x28: ffff0000117e5000 [ 294.316594] x27: 0000000000000000 x26: dead000000000100 [ 294.321980] x25: dead000000000200 x24: ffff803f6bd06800 [ 294.327366] x23: 0000000000000000 x22: 0000000000000000 [ 294.332752] x21: ffff00001001bd04 x20: ffff80df33d19018 [ 294.338137] x19: ffff80df33d19018 x18: 0000000000000000 [ 294.343523] x17: 0000000000000000 x16: 0000000000000000 [ 294.348908] x15: 0000000000000000 x14: 0000000000000002 [ 294.354293] x13: 0000000000000000 x12: 0000000000000000 [ 294.359679] x11: 0000000000000000 x10: 0000000000100000 [ 294.365065] x9 : 0000000000000000 x8 : 0000000000000004 [ 294.370451] x7 : 0000000000000000 x6 : ffff80df34558678 [ 294.375836] x5 : 000000000000000c x4 : 0000000000000000 [ 294.381221] x3 : 0000000000000001 x2 : 0000803fea6ea000 [ 294.386607] x1 : 0000803fea6ea008 x0 : 0000000000000001 [ 294.391994] Process swapper/3 (pid: 0, stack limit = 0x0000000083087293) [ 294.398791] Call trace: [ 294.401266] __srcu_read_lock+0x38/0x58 [ 294.405154] acquire_ipmi_user+0x2c/0x70 [ipmi_msghandler] [ 294.410716] deliver_response+0x80/0xf8 [ipmi_msghandler] [ 294.416189] deliver_local_response+0x28/0x68 [ipmi_msghandler] [ 294.422193] handle_one_recv_msg+0x158/0xcf8 [ipmi_msghandler] [ 294.432050] handle_new_recv_msgs+0xc0/0x210 [ipmi_msghandler] [ 294.441984] smi_recv_tasklet+0x8c/0x158 [ipmi_msghandler] [ 294.451618] tasklet_action_common.isra.5+0x88/0x138 [ 294.460661] tasklet_action+0x2c/0x38 [ 294.468191] __do_softirq+0x120/0x2f8 [ 294.475561] irq_exit+0x134/0x140 [ 294.482445] __handle_domain_irq+0x6c/0xc0 [ 294.489954] gic_handle_irq+0xb8/0x178 [ 294.497037] el1_irq+0xb0/0x140 [ 294.503381] arch_cpu_idle+0x34/0x1a8 [ 294.510096] do_idle+0x1d4/0x290 [ 294.516322] cpu_startup_entry+0x28/0x30 [ 294.523230] secondary_start_kernel+0x184/0x1d0 [ 294.530657] Code: d538d082 d2800023 8b010c81 8b020021 (c85f7c25) [ 294.539746] ---[ end trace 8a7a880dee570b29 ]--- [ 294.547341] Kernel panic - not syncing: Fatal exception in interrupt [ 294.556837] SMP: stopping secondary CPUs [ 294.563996] Kernel Offset: disabled [ 294.570515] CPU features: 0x002,21006008 [ 294.577638] Memory Limit: none [ 294.587178] Starting crashdump kernel... [ 294.594314] Bye! Because the user->release_barrier.rda is freed in ipmi_destroy_user(), but the refcount is not zero, when acquire_ipmi_user() uses user->release_barrier.rda in __srcu_read_lock(), it causes oops. Fix this by calling cleanup_srcu_struct() when the refcount is zero. Fixes: e86ee2d44b44 ("ipmi: Rework locking and shutdown for hot remove") Cc: stable@vger.kernel.org # 4.18 Signed-off-by: Yang Yingliang Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index cc5665c47a0e..e43c27ff59b4 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -1184,6 +1184,7 @@ EXPORT_SYMBOL(ipmi_get_smi_info); static void free_user(struct kref *ref) { struct ipmi_user *user = container_of(ref, struct ipmi_user, refcount); + cleanup_srcu_struct(&user->release_barrier); kfree(user); } @@ -1260,7 +1261,6 @@ int ipmi_destroy_user(struct ipmi_user *user) { _ipmi_destroy_user(user); - cleanup_srcu_struct(&user->release_barrier); kref_put(&user->refcount, free_user); return 0; -- cgit v1.2.3-58-ga151 From 913a89f009d98c85a902d718cd54bb32ab11d167 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 20 Dec 2018 16:50:23 -0600 Subject: ipmi: Don't initialize anything in the core until something uses it The IPMI driver was recently modified to use SRCU, but it turns out this uses a chunk of percpu memory, even if IPMI is never used. So modify thing to on initialize on the first use. There was already code to sort of handle this for handling init races, so piggy back on top of that, and simplify it in the process. Signed-off-by: Corey Minyard Reported-by: Tejun Heo Cc: Paul E. McKenney Reviewed-by: Paul E. McKenney Cc: stable@vger.kernel.org # 4.18 --- drivers/char/ipmi/ipmi_msghandler.c | 143 ++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 63 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e43c27ff59b4..c518659b4d9f 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -63,7 +63,8 @@ static void ipmi_debug_msg(const char *title, unsigned char *data, { } #endif -static int initialized; +static bool initialized; +static bool drvregistered; enum ipmi_panic_event_op { IPMI_SEND_PANIC_EVENT_NONE, @@ -613,7 +614,7 @@ static DEFINE_MUTEX(ipmidriver_mutex); static LIST_HEAD(ipmi_interfaces); static DEFINE_MUTEX(ipmi_interfaces_mutex); -DEFINE_STATIC_SRCU(ipmi_interfaces_srcu); +struct srcu_struct ipmi_interfaces_srcu; /* * List of watchers that want to know when smi's are added and deleted. @@ -721,7 +722,15 @@ struct watcher_entry { int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) { struct ipmi_smi *intf; - int index; + int index, rv; + + /* + * Make sure the driver is actually initialized, this handles + * problems with initialization order. + */ + rv = ipmi_init_msghandler(); + if (rv) + return rv; mutex_lock(&smi_watchers_mutex); @@ -1077,7 +1086,7 @@ int ipmi_create_user(unsigned int if_num, { unsigned long flags; struct ipmi_user *new_user; - int rv = 0, index; + int rv, index; struct ipmi_smi *intf; /* @@ -1095,18 +1104,9 @@ int ipmi_create_user(unsigned int if_num, * Make sure the driver is actually initialized, this handles * problems with initialization order. */ - if (!initialized) { - rv = ipmi_init_msghandler(); - if (rv) - return rv; - - /* - * The init code doesn't return an error if it was turned - * off, but it won't initialize. Check that. - */ - if (!initialized) - return -ENODEV; - } + rv = ipmi_init_msghandler(); + if (rv) + return rv; new_user = kmalloc(sizeof(*new_user), GFP_KERNEL); if (!new_user) @@ -3301,17 +3301,9 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, * Make sure the driver is actually initialized, this handles * problems with initialization order. */ - if (!initialized) { - rv = ipmi_init_msghandler(); - if (rv) - return rv; - /* - * The init code doesn't return an error if it was turned - * off, but it won't initialize. Check that. - */ - if (!initialized) - return -ENODEV; - } + rv = ipmi_init_msghandler(); + if (rv) + return rv; intf = kzalloc(sizeof(*intf), GFP_KERNEL); if (!intf) @@ -5027,6 +5019,22 @@ static int panic_event(struct notifier_block *this, return NOTIFY_DONE; } +/* Must be called with ipmi_interfaces_mutex held. */ +static int ipmi_register_driver(void) +{ + int rv; + + if (drvregistered) + return 0; + + rv = driver_register(&ipmidriver.driver); + if (rv) + pr_err("Could not register IPMI driver\n"); + else + drvregistered = true; + return rv; +} + static struct notifier_block panic_block = { .notifier_call = panic_event, .next = NULL, @@ -5037,66 +5045,75 @@ static int ipmi_init_msghandler(void) { int rv; + mutex_lock(&ipmi_interfaces_mutex); + rv = ipmi_register_driver(); + if (rv) + goto out; if (initialized) - return 0; + goto out; - rv = driver_register(&ipmidriver.driver); - if (rv) { - pr_err("Could not register IPMI driver\n"); - return rv; - } - - pr_info("version " IPMI_DRIVER_VERSION "\n"); + init_srcu_struct(&ipmi_interfaces_srcu); timer_setup(&ipmi_timer, ipmi_timeout, 0); mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); atomic_notifier_chain_register(&panic_notifier_list, &panic_block); - initialized = 1; + initialized = true; - return 0; +out: + mutex_unlock(&ipmi_interfaces_mutex); + return rv; } static int __init ipmi_init_msghandler_mod(void) { - ipmi_init_msghandler(); - return 0; + int rv; + + pr_info("version " IPMI_DRIVER_VERSION "\n"); + + mutex_lock(&ipmi_interfaces_mutex); + rv = ipmi_register_driver(); + mutex_unlock(&ipmi_interfaces_mutex); + + return rv; } static void __exit cleanup_ipmi(void) { int count; - if (!initialized) - return; - - atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block); + if (initialized) { + atomic_notifier_chain_unregister(&panic_notifier_list, + &panic_block); - /* - * This can't be called if any interfaces exist, so no worry - * about shutting down the interfaces. - */ + /* + * This can't be called if any interfaces exist, so no worry + * about shutting down the interfaces. + */ - /* - * Tell the timer to stop, then wait for it to stop. This - * avoids problems with race conditions removing the timer - * here. - */ - atomic_inc(&stop_operation); - del_timer_sync(&ipmi_timer); + /* + * Tell the timer to stop, then wait for it to stop. This + * avoids problems with race conditions removing the timer + * here. + */ + atomic_inc(&stop_operation); + del_timer_sync(&ipmi_timer); - driver_unregister(&ipmidriver.driver); + initialized = false; - initialized = 0; + /* Check for buffer leaks. */ + count = atomic_read(&smi_msg_inuse_count); + if (count != 0) + pr_warn("SMI message count %d at exit\n", count); + count = atomic_read(&recv_msg_inuse_count); + if (count != 0) + pr_warn("recv message count %d at exit\n", count); - /* Check for buffer leaks. */ - count = atomic_read(&smi_msg_inuse_count); - if (count != 0) - pr_warn("SMI message count %d at exit\n", count); - count = atomic_read(&recv_msg_inuse_count); - if (count != 0) - pr_warn("recv message count %d at exit\n", count); + cleanup_srcu_struct(&ipmi_interfaces_srcu); + } + if (drvregistered) + driver_unregister(&ipmidriver.driver); } module_exit(cleanup_ipmi); -- cgit v1.2.3-58-ga151 From 12da64300fbc76b875900445f4146c3dc617d43e Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 23 Jan 2019 12:14:52 +0100 Subject: ravb: expand rx descriptor data to accommodate hw checksum EtherAVB may provide a checksum of packet data appended to packet data. In order to allow this checksum to be received by the host descriptor data needs to be enlarged by 2 bytes to accommodate the checksum. In the case of MTU-sized packets without a VLAN tag the checksum were already accommodated by virtue of the space reserved for the VLAN tag. However, a packet of MTU-size with a VLAN tag consumed all packet data space provided by a descriptor leaving no space for the trailing checksum. This was not detected by the driver which incorrectly used the last two bytes of packet data as the checksum and truncate the packet by two bytes. This resulted all such packets being dropped. A work around is to disable RX checksum offload # ethtool -K eth0 rx off This patch resolves this problem by increasing the size available for packet data in RX descriptors by two bytes. Tested on R-Car E3 (r8a77990) ES1.0 based Ebisu-4D board v2 * Use sizeof(__sum16) directly rather than adding a driver-local #define for the size of the checksum provided by the hw (2 bytes). Fixes: 4d86d3818627 ("ravb: RX checksum offload") Signed-off-by: Simon Horman Reviewed-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index ffc1ada4e6da..d28c8f9ca55b 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -343,7 +343,7 @@ static int ravb_ring_init(struct net_device *ndev, int q) int i; priv->rx_buf_sz = (ndev->mtu <= 1492 ? PKT_BUF_SZ : ndev->mtu) + - ETH_HLEN + VLAN_HLEN; + ETH_HLEN + VLAN_HLEN + sizeof(__sum16); /* Allocate RX and TX skb rings */ priv->rx_skb[q] = kcalloc(priv->num_rx_ring[q], @@ -524,13 +524,15 @@ static void ravb_rx_csum(struct sk_buff *skb) { u8 *hw_csum; - /* The hardware checksum is 2 bytes appended to packet data */ - if (unlikely(skb->len < 2)) + /* The hardware checksum is contained in sizeof(__sum16) (2) bytes + * appended to packet data + */ + if (unlikely(skb->len < sizeof(__sum16))) return; - hw_csum = skb_tail_pointer(skb) - 2; + hw_csum = skb_tail_pointer(skb) - sizeof(__sum16); skb->csum = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum)); skb->ip_summed = CHECKSUM_COMPLETE; - skb_trim(skb, skb->len - 2); + skb_trim(skb, skb->len - sizeof(__sum16)); } /* Packet receive function for Ethernet AVB */ -- cgit v1.2.3-58-ga151 From b4a10c750424e01b5e37372fef0a574ebf7b56c3 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 15 Jan 2019 00:51:42 +0000 Subject: hv_netvsc: Fix ethtool change hash key error Hyper-V hosts require us to disable RSS before changing RSS key, otherwise the changing request will fail. This patch fixes the coding error. Fixes: ff4a44199012 ("netvsc: allow get/set of RSS indirection table") Reported-by: Wei Hu Signed-off-by: Haiyang Zhang Reviewed-by: Michael Kelley [sl: fix up subject line] Signed-off-by: Sasha Levin --- drivers/net/hyperv/rndis_filter.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 8b537a049c1e..a4661d396e3c 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -774,8 +774,8 @@ cleanup: return ret; } -int rndis_filter_set_rss_param(struct rndis_device *rdev, - const u8 *rss_key) +static int rndis_set_rss_param_msg(struct rndis_device *rdev, + const u8 *rss_key, u16 flag) { struct net_device *ndev = rdev->ndev; struct rndis_request *request; @@ -804,7 +804,7 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev, rssp->hdr.type = NDIS_OBJECT_TYPE_RSS_PARAMETERS; rssp->hdr.rev = NDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2; rssp->hdr.size = sizeof(struct ndis_recv_scale_param); - rssp->flag = 0; + rssp->flag = flag; rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 | NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6; @@ -829,9 +829,12 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev, wait_for_completion(&request->wait_event); set_complete = &request->response_msg.msg.set_complete; - if (set_complete->status == RNDIS_STATUS_SUCCESS) - memcpy(rdev->rss_key, rss_key, NETVSC_HASH_KEYLEN); - else { + if (set_complete->status == RNDIS_STATUS_SUCCESS) { + if (!(flag & NDIS_RSS_PARAM_FLAG_DISABLE_RSS) && + !(flag & NDIS_RSS_PARAM_FLAG_HASH_KEY_UNCHANGED)) + memcpy(rdev->rss_key, rss_key, NETVSC_HASH_KEYLEN); + + } else { netdev_err(ndev, "Fail to set RSS parameters:0x%x\n", set_complete->status); ret = -EINVAL; @@ -842,6 +845,16 @@ cleanup: return ret; } +int rndis_filter_set_rss_param(struct rndis_device *rdev, + const u8 *rss_key) +{ + /* Disable RSS before change */ + rndis_set_rss_param_msg(rdev, rss_key, + NDIS_RSS_PARAM_FLAG_DISABLE_RSS); + + return rndis_set_rss_param_msg(rdev, rss_key, 0); +} + static int rndis_filter_query_device_link_status(struct rndis_device *dev, struct netvsc_device *net_device) { -- cgit v1.2.3-58-ga151 From 7c9f335a3ff20557a92584199f3d35c7e992bbe5 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 15 Jan 2019 00:51:43 +0000 Subject: hv_netvsc: Refactor assignments of struct netvsc_device_info These assignments occur in multiple places. The patch refactor them to a function for simplicity. It also puts the struct to heap area for future expension. Signed-off-by: Haiyang Zhang Reviewed-by: Michael Kelley [sl: fix up subject line] Signed-off-by: Sasha Levin --- drivers/net/hyperv/netvsc_drv.c | 134 +++++++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 49 deletions(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 91ed15ea5883..f424327f7206 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -858,6 +858,36 @@ static void netvsc_get_channels(struct net_device *net, } } +/* Alloc struct netvsc_device_info, and initialize it from either existing + * struct netvsc_device, or from default values. + */ +static struct netvsc_device_info *netvsc_devinfo_get + (struct netvsc_device *nvdev) +{ + struct netvsc_device_info *dev_info; + + dev_info = kzalloc(sizeof(*dev_info), GFP_ATOMIC); + + if (!dev_info) + return NULL; + + if (nvdev) { + dev_info->num_chn = nvdev->num_chn; + dev_info->send_sections = nvdev->send_section_cnt; + dev_info->send_section_size = nvdev->send_section_size; + dev_info->recv_sections = nvdev->recv_section_cnt; + dev_info->recv_section_size = nvdev->recv_section_size; + } else { + dev_info->num_chn = VRSS_CHANNEL_DEFAULT; + dev_info->send_sections = NETVSC_DEFAULT_TX; + dev_info->send_section_size = NETVSC_SEND_SECTION_SIZE; + dev_info->recv_sections = NETVSC_DEFAULT_RX; + dev_info->recv_section_size = NETVSC_RECV_SECTION_SIZE; + } + + return dev_info; +} + static int netvsc_detach(struct net_device *ndev, struct netvsc_device *nvdev) { @@ -943,7 +973,7 @@ static int netvsc_set_channels(struct net_device *net, struct net_device_context *net_device_ctx = netdev_priv(net); struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev); unsigned int orig, count = channels->combined_count; - struct netvsc_device_info device_info; + struct netvsc_device_info *device_info; int ret; /* We do not support separate count for rx, tx, or other */ @@ -962,24 +992,26 @@ static int netvsc_set_channels(struct net_device *net, orig = nvdev->num_chn; - memset(&device_info, 0, sizeof(device_info)); - device_info.num_chn = count; - device_info.send_sections = nvdev->send_section_cnt; - device_info.send_section_size = nvdev->send_section_size; - device_info.recv_sections = nvdev->recv_section_cnt; - device_info.recv_section_size = nvdev->recv_section_size; + device_info = netvsc_devinfo_get(nvdev); + + if (!device_info) + return -ENOMEM; + + device_info->num_chn = count; ret = netvsc_detach(net, nvdev); if (ret) - return ret; + goto out; - ret = netvsc_attach(net, &device_info); + ret = netvsc_attach(net, device_info); if (ret) { - device_info.num_chn = orig; - if (netvsc_attach(net, &device_info)) + device_info->num_chn = orig; + if (netvsc_attach(net, device_info)) netdev_err(net, "restoring channel setting failed\n"); } +out: + kfree(device_info); return ret; } @@ -1048,48 +1080,45 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev); struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); int orig_mtu = ndev->mtu; - struct netvsc_device_info device_info; + struct netvsc_device_info *device_info; int ret = 0; if (!nvdev || nvdev->destroy) return -ENODEV; + device_info = netvsc_devinfo_get(nvdev); + + if (!device_info) + return -ENOMEM; + /* Change MTU of underlying VF netdev first. */ if (vf_netdev) { ret = dev_set_mtu(vf_netdev, mtu); if (ret) - return ret; + goto out; } - memset(&device_info, 0, sizeof(device_info)); - device_info.num_chn = nvdev->num_chn; - device_info.send_sections = nvdev->send_section_cnt; - device_info.send_section_size = nvdev->send_section_size; - device_info.recv_sections = nvdev->recv_section_cnt; - device_info.recv_section_size = nvdev->recv_section_size; - ret = netvsc_detach(ndev, nvdev); if (ret) goto rollback_vf; ndev->mtu = mtu; - ret = netvsc_attach(ndev, &device_info); - if (ret) - goto rollback; - - return 0; + ret = netvsc_attach(ndev, device_info); + if (!ret) + goto out; -rollback: /* Attempt rollback to original MTU */ ndev->mtu = orig_mtu; - if (netvsc_attach(ndev, &device_info)) + if (netvsc_attach(ndev, device_info)) netdev_err(ndev, "restoring mtu failed\n"); rollback_vf: if (vf_netdev) dev_set_mtu(vf_netdev, orig_mtu); +out: + kfree(device_info); return ret; } @@ -1674,7 +1703,7 @@ static int netvsc_set_ringparam(struct net_device *ndev, { struct net_device_context *ndevctx = netdev_priv(ndev); struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev); - struct netvsc_device_info device_info; + struct netvsc_device_info *device_info; struct ethtool_ringparam orig; u32 new_tx, new_rx; int ret = 0; @@ -1694,26 +1723,29 @@ static int netvsc_set_ringparam(struct net_device *ndev, new_rx == orig.rx_pending) return 0; /* no change */ - memset(&device_info, 0, sizeof(device_info)); - device_info.num_chn = nvdev->num_chn; - device_info.send_sections = new_tx; - device_info.send_section_size = nvdev->send_section_size; - device_info.recv_sections = new_rx; - device_info.recv_section_size = nvdev->recv_section_size; + device_info = netvsc_devinfo_get(nvdev); + + if (!device_info) + return -ENOMEM; + + device_info->send_sections = new_tx; + device_info->recv_sections = new_rx; ret = netvsc_detach(ndev, nvdev); if (ret) - return ret; + goto out; - ret = netvsc_attach(ndev, &device_info); + ret = netvsc_attach(ndev, device_info); if (ret) { - device_info.send_sections = orig.tx_pending; - device_info.recv_sections = orig.rx_pending; + device_info->send_sections = orig.tx_pending; + device_info->recv_sections = orig.rx_pending; - if (netvsc_attach(ndev, &device_info)) + if (netvsc_attach(ndev, device_info)) netdev_err(ndev, "restoring ringparam failed"); } +out: + kfree(device_info); return ret; } @@ -2167,7 +2199,7 @@ static int netvsc_probe(struct hv_device *dev, { struct net_device *net = NULL; struct net_device_context *net_device_ctx; - struct netvsc_device_info device_info; + struct netvsc_device_info *device_info = NULL; struct netvsc_device *nvdev; int ret = -ENOMEM; @@ -2214,21 +2246,21 @@ static int netvsc_probe(struct hv_device *dev, netif_set_real_num_rx_queues(net, 1); /* Notify the netvsc driver of the new device */ - memset(&device_info, 0, sizeof(device_info)); - device_info.num_chn = VRSS_CHANNEL_DEFAULT; - device_info.send_sections = NETVSC_DEFAULT_TX; - device_info.send_section_size = NETVSC_SEND_SECTION_SIZE; - device_info.recv_sections = NETVSC_DEFAULT_RX; - device_info.recv_section_size = NETVSC_RECV_SECTION_SIZE; - - nvdev = rndis_filter_device_add(dev, &device_info); + device_info = netvsc_devinfo_get(NULL); + + if (!device_info) { + ret = -ENOMEM; + goto devinfo_failed; + } + + nvdev = rndis_filter_device_add(dev, device_info); if (IS_ERR(nvdev)) { ret = PTR_ERR(nvdev); netdev_err(net, "unable to add netvsc device (ret %d)\n", ret); goto rndis_failed; } - memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); + memcpy(net->dev_addr, device_info->mac_adr, ETH_ALEN); /* We must get rtnl lock before scheduling nvdev->subchan_work, * otherwise netvsc_subchan_work() can get rtnl lock first and wait @@ -2266,12 +2298,16 @@ static int netvsc_probe(struct hv_device *dev, list_add(&net_device_ctx->list, &netvsc_dev_list); rtnl_unlock(); + + kfree(device_info); return 0; register_failed: rtnl_unlock(); rndis_filter_device_remove(dev, nvdev); rndis_failed: + kfree(device_info); +devinfo_failed: free_percpu(net_device_ctx->vf_stats); no_stats: hv_set_drvdata(dev, NULL); -- cgit v1.2.3-58-ga151 From 17d91256898402daf4425cc541ac9cbf64574d9a Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Tue, 15 Jan 2019 00:51:44 +0000 Subject: hv_netvsc: Fix hash key value reset after other ops Changing mtu, channels, or buffer sizes ops call to netvsc_attach(), rndis_set_subchannel(), which always reset the hash key to default value. That will override hash key changed previously. This patch fixes the problem by save the hash key, then restore it when we re- add the netvsc device. Fixes: ff4a44199012 ("netvsc: allow get/set of RSS indirection table") Signed-off-by: Haiyang Zhang Reviewed-by: Michael Kelley [sl: fix up subject line] Signed-off-by: Sasha Levin --- drivers/net/hyperv/hyperv_net.h | 10 +++++++--- drivers/net/hyperv/netvsc.c | 2 +- drivers/net/hyperv/netvsc_drv.c | 5 ++++- drivers/net/hyperv/rndis_filter.c | 9 +++++++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index ef6f766f6389..e598a684700b 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -144,6 +144,8 @@ struct hv_netvsc_packet { u32 total_data_buflen; }; +#define NETVSC_HASH_KEYLEN 40 + struct netvsc_device_info { unsigned char mac_adr[ETH_ALEN]; u32 num_chn; @@ -151,6 +153,8 @@ struct netvsc_device_info { u32 recv_sections; u32 send_section_size; u32 recv_section_size; + + u8 rss_key[NETVSC_HASH_KEYLEN]; }; enum rndis_device_state { @@ -160,8 +164,6 @@ enum rndis_device_state { RNDIS_DEV_DATAINITIALIZED, }; -#define NETVSC_HASH_KEYLEN 40 - struct rndis_device { struct net_device *ndev; @@ -209,7 +211,9 @@ int netvsc_recv_callback(struct net_device *net, void netvsc_channel_cb(void *context); int netvsc_poll(struct napi_struct *napi, int budget); -int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev); +int rndis_set_subchannel(struct net_device *ndev, + struct netvsc_device *nvdev, + struct netvsc_device_info *dev_info); int rndis_filter_open(struct netvsc_device *nvdev); int rndis_filter_close(struct netvsc_device *nvdev); struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 922054c1d544..1910810e55bd 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -84,7 +84,7 @@ static void netvsc_subchan_work(struct work_struct *w) rdev = nvdev->extension; if (rdev) { - ret = rndis_set_subchannel(rdev->ndev, nvdev); + ret = rndis_set_subchannel(rdev->ndev, nvdev, NULL); if (ret == 0) { netif_device_attach(rdev->ndev); } else { diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index f424327f7206..e281829a04ef 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -877,6 +877,9 @@ static struct netvsc_device_info *netvsc_devinfo_get dev_info->send_section_size = nvdev->send_section_size; dev_info->recv_sections = nvdev->recv_section_cnt; dev_info->recv_section_size = nvdev->recv_section_size; + + memcpy(dev_info->rss_key, nvdev->extension->rss_key, + NETVSC_HASH_KEYLEN); } else { dev_info->num_chn = VRSS_CHANNEL_DEFAULT; dev_info->send_sections = NETVSC_DEFAULT_TX; @@ -939,7 +942,7 @@ static int netvsc_attach(struct net_device *ndev, return PTR_ERR(nvdev); if (nvdev->num_chn > 1) { - ret = rndis_set_subchannel(ndev, nvdev); + ret = rndis_set_subchannel(ndev, nvdev, dev_info); /* if unavailable, just proceed with one queue */ if (ret) { diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index a4661d396e3c..db81378e6624 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1134,7 +1134,9 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) * This breaks overlap of processing the host message for the * new primary channel with the initialization of sub-channels. */ -int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev) +int rndis_set_subchannel(struct net_device *ndev, + struct netvsc_device *nvdev, + struct netvsc_device_info *dev_info) { struct nvsp_message *init_packet = &nvdev->channel_init_pkt; struct net_device_context *ndev_ctx = netdev_priv(ndev); @@ -1175,7 +1177,10 @@ int rndis_set_subchannel(struct net_device *ndev, struct netvsc_device *nvdev) atomic_read(&nvdev->open_chn) == nvdev->num_chn); /* ignore failues from setting rss parameters, still have channels */ - rndis_filter_set_rss_param(rdev, netvsc_hash_key); + if (dev_info) + rndis_filter_set_rss_param(rdev, dev_info->rss_key); + else + rndis_filter_set_rss_param(rdev, netvsc_hash_key); netif_set_real_num_tx_queues(ndev, nvdev->num_chn); netif_set_real_num_rx_queues(ndev, nvdev->num_chn); -- cgit v1.2.3-58-ga151 From 52d3b4949192e93b948daaa40678fcd4b94bcbd0 Mon Sep 17 00:00:00 2001 From: Adrian Vladu Date: Thu, 3 Jan 2019 19:43:08 +0000 Subject: hv_netvsc: fix typos in code comments Fix all typos from hyperv netvsc code comments. Signed-off-by: Adrian Vladu Cc: "K. Y. Srinivasan" Cc: Haiyang Zhang Cc: Stephen Hemminger Cc: Sasha Levin Cc: "David S. Miller" Cc: "Alessandro Pilotti" Signed-off-by: Sasha Levin --- drivers/net/hyperv/hyperv_net.h | 2 +- drivers/net/hyperv/netvsc.c | 2 +- drivers/net/hyperv/netvsc_drv.c | 6 +++--- drivers/net/hyperv/rndis_filter.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index e598a684700b..e859ae2e42d5 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -1181,7 +1181,7 @@ enum ndis_per_pkt_info_type { enum rndis_per_pkt_info_interal_type { RNDIS_PKTINFO_ID = 1, - /* Add more memebers here */ + /* Add more members here */ RNDIS_PKTINFO_MAX }; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 1910810e55bd..813d195bbd57 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1331,7 +1331,7 @@ void netvsc_channel_cb(void *context) prefetch(hv_get_ring_buffer(rbi) + rbi->priv_read_index); if (napi_schedule_prep(&nvchan->napi)) { - /* disable interupts from host */ + /* disable interrupts from host */ hv_begin_read(rbi); __napi_schedule_irqoff(&nvchan->napi); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index e281829a04ef..256adbd044f5 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -370,7 +370,7 @@ static u32 fill_pg_buf(struct page *page, u32 offset, u32 len, { int j = 0; - /* Deal with compund pages by ignoring unused part + /* Deal with compound pages by ignoring unused part * of the page. */ page += (offset >> PAGE_SHIFT); @@ -2123,7 +2123,7 @@ static int netvsc_register_vf(struct net_device *vf_netdev) if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev)) return NOTIFY_DONE; - /* if syntihetic interface is a different namespace, + /* if synthetic interface is a different namespace, * then move the VF to that namespace; join will be * done again in that context. */ @@ -2271,7 +2271,7 @@ static int netvsc_probe(struct hv_device *dev, * netvsc_probe() can't get rtnl lock and as a result vmbus_onoffer() * -> ... -> device_add() -> ... -> __device_attach() can't get * the device lock, so all the subchannels can't be processed -- - * finally netvsc_subchan_work() hangs for ever. + * finally netvsc_subchan_work() hangs forever. */ rtnl_lock(); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index db81378e6624..73b60592de06 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1176,7 +1176,7 @@ int rndis_set_subchannel(struct net_device *ndev, wait_event(nvdev->subchan_open, atomic_read(&nvdev->open_chn) == nvdev->num_chn); - /* ignore failues from setting rss parameters, still have channels */ + /* ignore failures from setting rss parameters, still have channels */ if (dev_info) rndis_filter_set_rss_param(rdev, dev_info->rss_key); else -- cgit v1.2.3-58-ga151 From 3366463513f544c12c6b88c13da4462ee9e7a1a1 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Tue, 22 Jan 2019 19:02:17 +0000 Subject: sfc: suppress duplicate nvmem partition types in efx_ef10_mtd_probe Use a bitmap to keep track of which partition types we've already seen; for duplicates, return -EEXIST from efx_ef10_mtd_probe_partition() and thus skip adding that partition. Duplicate partitions occur because of the A/B backup scheme used by newer sfc NICs. Prior to this patch they cause sysfs_warn_dup errors because they have the same name, causing us not to expose any MTDs at all. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index b6a50058bb8d..2f2bda68d861 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -6046,22 +6046,25 @@ static const struct efx_ef10_nvram_type_info efx_ef10_nvram_types[] = { { NVRAM_PARTITION_TYPE_EXPANSION_UEFI, 0, 0, "sfc_uefi" }, { NVRAM_PARTITION_TYPE_STATUS, 0, 0, "sfc_status" } }; +#define EF10_NVRAM_PARTITION_COUNT ARRAY_SIZE(efx_ef10_nvram_types) static int efx_ef10_mtd_probe_partition(struct efx_nic *efx, struct efx_mcdi_mtd_partition *part, - unsigned int type) + unsigned int type, + unsigned long *found) { MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_METADATA_OUT_LENMAX); const struct efx_ef10_nvram_type_info *info; size_t size, erase_size, outlen; + int type_idx = 0; bool protected; int rc; - for (info = efx_ef10_nvram_types; ; info++) { - if (info == - efx_ef10_nvram_types + ARRAY_SIZE(efx_ef10_nvram_types)) + for (type_idx = 0; ; type_idx++) { + if (type_idx == EF10_NVRAM_PARTITION_COUNT) return -ENODEV; + info = efx_ef10_nvram_types + type_idx; if ((type & ~info->type_mask) == info->type) break; } @@ -6074,6 +6077,13 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx, if (protected) return -ENODEV; /* hide it */ + /* If we've already exposed a partition of this type, hide this + * duplicate. All operations on MTDs are keyed by the type anyway, + * so we can't act on the duplicate. + */ + if (__test_and_set_bit(type_idx, found)) + return -EEXIST; + part->nvram_type = type; MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type); @@ -6105,6 +6115,7 @@ static int efx_ef10_mtd_probe_partition(struct efx_nic *efx, static int efx_ef10_mtd_probe(struct efx_nic *efx) { MCDI_DECLARE_BUF(outbuf, MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX); + DECLARE_BITMAP(found, EF10_NVRAM_PARTITION_COUNT); struct efx_mcdi_mtd_partition *parts; size_t outlen, n_parts_total, i, n_parts; unsigned int type; @@ -6133,11 +6144,13 @@ static int efx_ef10_mtd_probe(struct efx_nic *efx) for (i = 0; i < n_parts_total; i++) { type = MCDI_ARRAY_DWORD(outbuf, NVRAM_PARTITIONS_OUT_TYPE_ID, i); - rc = efx_ef10_mtd_probe_partition(efx, &parts[n_parts], type); - if (rc == 0) - n_parts++; - else if (rc != -ENODEV) + rc = efx_ef10_mtd_probe_partition(efx, &parts[n_parts], type, + found); + if (rc == -EEXIST || rc == -ENODEV) + continue; + if (rc) goto fail; + n_parts++; } rc = efx_mtd_add(efx, &parts[0].common, n_parts, sizeof(*parts)); -- cgit v1.2.3-58-ga151 From 63530aba7826a0f8e129874df9c4d264f9db3f9e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 22 Jan 2019 10:40:59 -0800 Subject: ax25: fix possible use-after-free syzbot found that ax25 routes where not properly protected against concurrent use [1]. In this particular report the bug happened while copying ax25->digipeat. Fix this problem by making sure we call ax25_get_route() while ax25_route_lock is held, so that no modification could happen while using the route. The current two ax25_get_route() callers do not sleep, so this change should be fine. Once we do that, ax25_get_route() no longer needs to grab a reference on the found route. [1] ax25_connect(): syz-executor0 uses autobind, please contact jreuter@yaina.de BUG: KASAN: use-after-free in memcpy include/linux/string.h:352 [inline] BUG: KASAN: use-after-free in kmemdup+0x42/0x60 mm/util.c:113 Read of size 66 at addr ffff888066641a80 by task syz-executor2/531 ax25_connect(): syz-executor0 uses autobind, please contact jreuter@yaina.de CPU: 1 PID: 531 Comm: syz-executor2 Not tainted 5.0.0-rc2+ #10 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1db/0x2d0 lib/dump_stack.c:113 print_address_description.cold+0x7c/0x20d mm/kasan/report.c:187 kasan_report.cold+0x1b/0x40 mm/kasan/report.c:317 check_memory_region_inline mm/kasan/generic.c:185 [inline] check_memory_region+0x123/0x190 mm/kasan/generic.c:191 memcpy+0x24/0x50 mm/kasan/common.c:130 memcpy include/linux/string.h:352 [inline] kmemdup+0x42/0x60 mm/util.c:113 kmemdup include/linux/string.h:425 [inline] ax25_rt_autobind+0x25d/0x750 net/ax25/ax25_route.c:424 ax25_connect.cold+0x30/0xa4 net/ax25/af_ax25.c:1224 __sys_connect+0x357/0x490 net/socket.c:1664 __do_sys_connect net/socket.c:1675 [inline] __se_sys_connect net/socket.c:1672 [inline] __x64_sys_connect+0x73/0xb0 net/socket.c:1672 do_syscall_64+0x1a3/0x800 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x458099 Code: 6d b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 3b b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f870ee22c78 EFLAGS: 00000246 ORIG_RAX: 000000000000002a RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000458099 RDX: 0000000000000048 RSI: 0000000020000080 RDI: 0000000000000005 RBP: 000000000073bf00 R08: 0000000000000000 R09: 0000000000000000 ax25_connect(): syz-executor4 uses autobind, please contact jreuter@yaina.de R10: 0000000000000000 R11: 0000000000000246 R12: 00007f870ee236d4 R13: 00000000004be48e R14: 00000000004ce9a8 R15: 00000000ffffffff Allocated by task 526: save_stack+0x45/0xd0 mm/kasan/common.c:73 set_track mm/kasan/common.c:85 [inline] __kasan_kmalloc mm/kasan/common.c:496 [inline] __kasan_kmalloc.constprop.0+0xcf/0xe0 mm/kasan/common.c:469 kasan_kmalloc+0x9/0x10 mm/kasan/common.c:504 ax25_connect(): syz-executor5 uses autobind, please contact jreuter@yaina.de kmem_cache_alloc_trace+0x151/0x760 mm/slab.c:3609 kmalloc include/linux/slab.h:545 [inline] ax25_rt_add net/ax25/ax25_route.c:95 [inline] ax25_rt_ioctl+0x3b9/0x1270 net/ax25/ax25_route.c:233 ax25_ioctl+0x322/0x10b0 net/ax25/af_ax25.c:1763 sock_do_ioctl+0xe2/0x400 net/socket.c:950 sock_ioctl+0x32f/0x6c0 net/socket.c:1074 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:509 [inline] do_vfs_ioctl+0x107b/0x17d0 fs/ioctl.c:696 ksys_ioctl+0xab/0xd0 fs/ioctl.c:713 __do_sys_ioctl fs/ioctl.c:720 [inline] __se_sys_ioctl fs/ioctl.c:718 [inline] __x64_sys_ioctl+0x73/0xb0 fs/ioctl.c:718 do_syscall_64+0x1a3/0x800 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe ax25_connect(): syz-executor5 uses autobind, please contact jreuter@yaina.de Freed by task 550: save_stack+0x45/0xd0 mm/kasan/common.c:73 set_track mm/kasan/common.c:85 [inline] __kasan_slab_free+0x102/0x150 mm/kasan/common.c:458 kasan_slab_free+0xe/0x10 mm/kasan/common.c:466 __cache_free mm/slab.c:3487 [inline] kfree+0xcf/0x230 mm/slab.c:3806 ax25_rt_add net/ax25/ax25_route.c:92 [inline] ax25_rt_ioctl+0x304/0x1270 net/ax25/ax25_route.c:233 ax25_ioctl+0x322/0x10b0 net/ax25/af_ax25.c:1763 sock_do_ioctl+0xe2/0x400 net/socket.c:950 sock_ioctl+0x32f/0x6c0 net/socket.c:1074 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:509 [inline] do_vfs_ioctl+0x107b/0x17d0 fs/ioctl.c:696 ksys_ioctl+0xab/0xd0 fs/ioctl.c:713 __do_sys_ioctl fs/ioctl.c:720 [inline] __se_sys_ioctl fs/ioctl.c:718 [inline] __x64_sys_ioctl+0x73/0xb0 fs/ioctl.c:718 do_syscall_64+0x1a3/0x800 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe The buggy address belongs to the object at ffff888066641a80 which belongs to the cache kmalloc-96 of size 96 The buggy address is located 0 bytes inside of 96-byte region [ffff888066641a80, ffff888066641ae0) The buggy address belongs to the page: page:ffffea0001999040 count:1 mapcount:0 mapping:ffff88812c3f04c0 index:0x0 flags: 0x1fffc0000000200(slab) ax25_connect(): syz-executor4 uses autobind, please contact jreuter@yaina.de raw: 01fffc0000000200 ffffea0001817948 ffffea0002341dc8 ffff88812c3f04c0 raw: 0000000000000000 ffff888066641000 0000000100000020 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff888066641980: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc ffff888066641a00: 00 00 00 00 00 00 00 00 02 fc fc fc fc fc fc fc >ffff888066641a80: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc ^ ffff888066641b00: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc ffff888066641b80: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc Signed-off-by: Eric Dumazet Cc: Ralf Baechle Reported-by: syzbot Signed-off-by: David S. Miller --- include/net/ax25.h | 12 ++++++++++++ net/ax25/ax25_ip.c | 4 ++-- net/ax25/ax25_route.c | 19 ++++++++----------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/include/net/ax25.h b/include/net/ax25.h index 3f9aea8087e3..8b7eb46ad72d 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -201,6 +201,18 @@ static inline void ax25_hold_route(ax25_route *ax25_rt) void __ax25_put_route(ax25_route *ax25_rt); +extern rwlock_t ax25_route_lock; + +static inline void ax25_route_lock_use(void) +{ + read_lock(&ax25_route_lock); +} + +static inline void ax25_route_lock_unuse(void) +{ + read_unlock(&ax25_route_lock); +} + static inline void ax25_put_route(ax25_route *ax25_rt) { if (refcount_dec_and_test(&ax25_rt->refcount)) diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c index 70417e9b932d..314bbc8010fb 100644 --- a/net/ax25/ax25_ip.c +++ b/net/ax25/ax25_ip.c @@ -114,6 +114,7 @@ netdev_tx_t ax25_ip_xmit(struct sk_buff *skb) dst = (ax25_address *)(bp + 1); src = (ax25_address *)(bp + 8); + ax25_route_lock_use(); route = ax25_get_route(dst, NULL); if (route) { digipeat = route->digipeat; @@ -206,9 +207,8 @@ netdev_tx_t ax25_ip_xmit(struct sk_buff *skb) ax25_queue_xmit(skb, dev); put: - if (route) - ax25_put_route(route); + ax25_route_lock_unuse(); return NETDEV_TX_OK; } diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index a0eff323af12..66f74c85cf6b 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -40,7 +40,7 @@ #include static ax25_route *ax25_route_list; -static DEFINE_RWLOCK(ax25_route_lock); +DEFINE_RWLOCK(ax25_route_lock); void ax25_rt_device_down(struct net_device *dev) { @@ -335,6 +335,7 @@ const struct seq_operations ax25_rt_seqops = { * Find AX.25 route * * Only routes with a reference count of zero can be destroyed. + * Must be called with ax25_route_lock read locked. */ ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) { @@ -342,7 +343,6 @@ ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) ax25_route *ax25_def_rt = NULL; ax25_route *ax25_rt; - read_lock(&ax25_route_lock); /* * Bind to the physical interface we heard them on, or the default * route if none is found; @@ -365,11 +365,6 @@ ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev) if (ax25_spe_rt != NULL) ax25_rt = ax25_spe_rt; - if (ax25_rt != NULL) - ax25_hold_route(ax25_rt); - - read_unlock(&ax25_route_lock); - return ax25_rt; } @@ -400,9 +395,12 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) ax25_route *ax25_rt; int err = 0; - if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL) + ax25_route_lock_use(); + ax25_rt = ax25_get_route(addr, NULL); + if (!ax25_rt) { + ax25_route_lock_unuse(); return -EHOSTUNREACH; - + } if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) { err = -EHOSTUNREACH; goto put; @@ -437,8 +435,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) } put: - ax25_put_route(ax25_rt); - + ax25_route_lock_unuse(); return err; } -- cgit v1.2.3-58-ga151 From 30bac164aca750892b93eef350439a0562a68647 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 24 Jan 2019 09:04:37 +1300 Subject: Revert "Change mincore() to count "mapped" pages rather than "cached" pages" This reverts commit 574823bfab82d9d8fa47f422778043fbb4b4f50e. It turns out that my hope that we could just remove the code that exposes the cache residency status from mincore() was too optimistic. There are various random users that want it, and one example would be the Netflix database cluster maintenance. To quote Josh Snyder: "For Netflix, losing accurate information from the mincore syscall would lengthen database cluster maintenance operations from days to months. We rely on cross-process mincore to migrate the contents of a page cache from machine to machine, and across reboots. To do this, I wrote and maintain happycache [1], a page cache dumper/loader tool. It is quite similar in architecture to pgfincore, except that it is agnostic to workload. The gist of happycache's operation is "produce a dump of residence status for each page, do some operation, then reload exactly the same pages which were present before." happycache is entirely dependent on accurate reporting of the in-core status of file-backed pages, as accessed by another process. We primarily use happycache with Cassandra, which (like Postgres + pgfincore) relies heavily on OS page cache to reduce disk accesses. Because our workloads never experience a cold page cache, we are able to provision hardware for a peak utilization level that is far lower than the hypothetical "every query is a cache miss" peak. A database warmed by happycache can be ready for service in seconds (bounded only by the performance of the drives and the I/O subsystem), with no period of in-service degradation. By contrast, putting a database in service without a page cache entails a potentially unbounded period of degradation (at Netflix, the time to populate a single node's cache via natural cache misses varies by workload from hours to weeks). If a single node upgrade were to take weeks, then upgrading an entire cluster would take months. Since we want to apply security upgrades (and other things) on a somewhat tighter schedule, we would have to develop more complex solutions to provide the same functionality already provided by mincore. At the bottom line, happycache is designed to benignly exploit the same information leak documented in the paper [2]. I think it makes perfect sense to remove cross-process mincore functionality from unprivileged users, but not to remove it entirely" We do have an alternate approach that limits the cache residency reporting only to processes that have write permissions to the file, so we can fix the original information leak issue that way. It involves _adding_ code rather than removing it, which is sad, but hey, at least we haven't found any users that would find the restrictions unacceptable. So revert the optimistic first approach to make room for that alternate fix instead. Reported-by: Josh Snyder Cc: Jiri Kosina Cc: Dominique Martinet Cc: Andy Lutomirski Cc: Dave Chinner Cc: Kevin Easton Cc: Matthew Wilcox Cc: Cyril Hrubis Cc: Vlastimil Babka Cc: Tejun Heo Cc: Kirill A. Shutemov Cc: Daniel Gruss Signed-off-by: Linus Torvalds --- mm/mincore.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 13 deletions(-) diff --git a/mm/mincore.c b/mm/mincore.c index f0f91461a9f4..218099b5ed31 100644 --- a/mm/mincore.c +++ b/mm/mincore.c @@ -42,14 +42,72 @@ static int mincore_hugetlb(pte_t *pte, unsigned long hmask, unsigned long addr, return 0; } -static int mincore_unmapped_range(unsigned long addr, unsigned long end, - struct mm_walk *walk) +/* + * Later we can get more picky about what "in core" means precisely. + * For now, simply check to see if the page is in the page cache, + * and is up to date; i.e. that no page-in operation would be required + * at this time if an application were to map and access this page. + */ +static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff) +{ + unsigned char present = 0; + struct page *page; + + /* + * When tmpfs swaps out a page from a file, any process mapping that + * file will not get a swp_entry_t in its pte, but rather it is like + * any other file mapping (ie. marked !present and faulted in with + * tmpfs's .fault). So swapped out tmpfs mappings are tested here. + */ +#ifdef CONFIG_SWAP + if (shmem_mapping(mapping)) { + page = find_get_entry(mapping, pgoff); + /* + * shmem/tmpfs may return swap: account for swapcache + * page too. + */ + if (xa_is_value(page)) { + swp_entry_t swp = radix_to_swp_entry(page); + page = find_get_page(swap_address_space(swp), + swp_offset(swp)); + } + } else + page = find_get_page(mapping, pgoff); +#else + page = find_get_page(mapping, pgoff); +#endif + if (page) { + present = PageUptodate(page); + put_page(page); + } + + return present; +} + +static int __mincore_unmapped_range(unsigned long addr, unsigned long end, + struct vm_area_struct *vma, unsigned char *vec) { - unsigned char *vec = walk->private; unsigned long nr = (end - addr) >> PAGE_SHIFT; + int i; - memset(vec, 0, nr); - walk->private += nr; + if (vma->vm_file) { + pgoff_t pgoff; + + pgoff = linear_page_index(vma, addr); + for (i = 0; i < nr; i++, pgoff++) + vec[i] = mincore_page(vma->vm_file->f_mapping, pgoff); + } else { + for (i = 0; i < nr; i++) + vec[i] = 0; + } + return nr; +} + +static int mincore_unmapped_range(unsigned long addr, unsigned long end, + struct mm_walk *walk) +{ + walk->private += __mincore_unmapped_range(addr, end, + walk->vma, walk->private); return 0; } @@ -69,9 +127,8 @@ static int mincore_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, goto out; } - /* We'll consider a THP page under construction to be there */ if (pmd_trans_unstable(pmd)) { - memset(vec, 1, nr); + __mincore_unmapped_range(addr, end, vma, vec); goto out; } @@ -80,17 +137,28 @@ static int mincore_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, pte_t pte = *ptep; if (pte_none(pte)) - *vec = 0; + __mincore_unmapped_range(addr, addr + PAGE_SIZE, + vma, vec); else if (pte_present(pte)) *vec = 1; else { /* pte is a swap entry */ swp_entry_t entry = pte_to_swp_entry(pte); - /* - * migration or hwpoison entries are always - * uptodate - */ - *vec = !!non_swap_entry(entry); + if (non_swap_entry(entry)) { + /* + * migration or hwpoison entries are always + * uptodate + */ + *vec = 1; + } else { +#ifdef CONFIG_SWAP + *vec = mincore_page(swap_address_space(entry), + swp_offset(entry)); +#else + WARN_ON(1); + *vec = 1; +#endif + } } vec++; } -- cgit v1.2.3-58-ga151 From 60d8cd572f655aac6107a2330dced004ad1fe3d7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 16 Jan 2019 19:01:48 +0100 Subject: arm64/xen: fix xen-swiotlb cache flushing Xen-swiotlb hooks into the arm/arm64 arch code through a copy of the DMA DMA mapping operations stored in the struct device arch data. Switching arm64 to use the direct calls for the merged DMA direct / swiotlb code broke this scheme. Replace the indirect calls with direct-calls in xen-swiotlb as well to fix this problem. Fixes: 356da6d0cde3 ("dma-mapping: bypass indirect calls for dma-direct") Reported-by: Julien Grall Signed-off-by: Christoph Hellwig Reviewed-by: Stefano Stabellini --- arch/arm/include/asm/xen/page-coherent.h | 94 +++++++++++++++++++++++++++++ arch/arm64/include/asm/device.h | 3 - arch/arm64/include/asm/xen/page-coherent.h | 76 +++++++++++++++++++++++ arch/arm64/mm/dma-mapping.c | 4 +- drivers/xen/swiotlb-xen.c | 4 +- include/xen/arm/page-coherent.h | 97 +----------------------------- 6 files changed, 176 insertions(+), 102 deletions(-) diff --git a/arch/arm/include/asm/xen/page-coherent.h b/arch/arm/include/asm/xen/page-coherent.h index b3ef061d8b74..2c403e7c782d 100644 --- a/arch/arm/include/asm/xen/page-coherent.h +++ b/arch/arm/include/asm/xen/page-coherent.h @@ -1 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_ARM_XEN_PAGE_COHERENT_H +#define _ASM_ARM_XEN_PAGE_COHERENT_H + +#include +#include #include + +static inline const struct dma_map_ops *xen_get_dma_ops(struct device *dev) +{ + if (dev && dev->archdata.dev_dma_ops) + return dev->archdata.dev_dma_ops; + return get_arch_dma_ops(NULL); +} + +static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size, + dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs) +{ + return xen_get_dma_ops(hwdev)->alloc(hwdev, size, dma_handle, flags, attrs); +} + +static inline void xen_free_coherent_pages(struct device *hwdev, size_t size, + void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs) +{ + xen_get_dma_ops(hwdev)->free(hwdev, size, cpu_addr, dma_handle, attrs); +} + +static inline void xen_dma_map_page(struct device *hwdev, struct page *page, + dma_addr_t dev_addr, unsigned long offset, size_t size, + enum dma_data_direction dir, unsigned long attrs) +{ + unsigned long page_pfn = page_to_xen_pfn(page); + unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr); + unsigned long compound_pages = + (1<map_page(hwdev, page, offset, size, dir, attrs); + else + __xen_dma_map_page(hwdev, page, dev_addr, offset, size, dir, attrs); +} + +static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle, + size_t size, enum dma_data_direction dir, unsigned long attrs) +{ + unsigned long pfn = PFN_DOWN(handle); + /* + * Dom0 is mapped 1:1, while the Linux page can be spanned accross + * multiple Xen page, it's not possible to have a mix of local and + * foreign Xen page. Dom0 is mapped 1:1, so calling pfn_valid on a + * foreign mfn will always return false. If the page is local we can + * safely call the native dma_ops function, otherwise we call the xen + * specific function. + */ + if (pfn_valid(pfn)) { + if (xen_get_dma_ops(hwdev)->unmap_page) + xen_get_dma_ops(hwdev)->unmap_page(hwdev, handle, size, dir, attrs); + } else + __xen_dma_unmap_page(hwdev, handle, size, dir, attrs); +} + +static inline void xen_dma_sync_single_for_cpu(struct device *hwdev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + unsigned long pfn = PFN_DOWN(handle); + if (pfn_valid(pfn)) { + if (xen_get_dma_ops(hwdev)->sync_single_for_cpu) + xen_get_dma_ops(hwdev)->sync_single_for_cpu(hwdev, handle, size, dir); + } else + __xen_dma_sync_single_for_cpu(hwdev, handle, size, dir); +} + +static inline void xen_dma_sync_single_for_device(struct device *hwdev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + unsigned long pfn = PFN_DOWN(handle); + if (pfn_valid(pfn)) { + if (xen_get_dma_ops(hwdev)->sync_single_for_device) + xen_get_dma_ops(hwdev)->sync_single_for_device(hwdev, handle, size, dir); + } else + __xen_dma_sync_single_for_device(hwdev, handle, size, dir); +} + +#endif /* _ASM_ARM_XEN_PAGE_COHERENT_H */ diff --git a/arch/arm64/include/asm/device.h b/arch/arm64/include/asm/device.h index 3dd3d664c5c5..4658c937e173 100644 --- a/arch/arm64/include/asm/device.h +++ b/arch/arm64/include/asm/device.h @@ -20,9 +20,6 @@ struct dev_archdata { #ifdef CONFIG_IOMMU_API void *iommu; /* private IOMMU data */ #endif -#ifdef CONFIG_XEN - const struct dma_map_ops *dev_dma_ops; -#endif }; struct pdev_archdata { diff --git a/arch/arm64/include/asm/xen/page-coherent.h b/arch/arm64/include/asm/xen/page-coherent.h index b3ef061d8b74..d88e56b90b93 100644 --- a/arch/arm64/include/asm/xen/page-coherent.h +++ b/arch/arm64/include/asm/xen/page-coherent.h @@ -1 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_ARM64_XEN_PAGE_COHERENT_H +#define _ASM_ARM64_XEN_PAGE_COHERENT_H + +#include +#include #include + +static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size, + dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs) +{ + return dma_direct_alloc(hwdev, size, dma_handle, flags, attrs); +} + +static inline void xen_free_coherent_pages(struct device *hwdev, size_t size, + void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs) +{ + dma_direct_free(hwdev, size, cpu_addr, dma_handle, attrs); +} + +static inline void xen_dma_sync_single_for_cpu(struct device *hwdev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + unsigned long pfn = PFN_DOWN(handle); + + if (pfn_valid(pfn)) + dma_direct_sync_single_for_cpu(hwdev, handle, size, dir); + else + __xen_dma_sync_single_for_cpu(hwdev, handle, size, dir); +} + +static inline void xen_dma_sync_single_for_device(struct device *hwdev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + unsigned long pfn = PFN_DOWN(handle); + if (pfn_valid(pfn)) + dma_direct_sync_single_for_device(hwdev, handle, size, dir); + else + __xen_dma_sync_single_for_device(hwdev, handle, size, dir); +} + +static inline void xen_dma_map_page(struct device *hwdev, struct page *page, + dma_addr_t dev_addr, unsigned long offset, size_t size, + enum dma_data_direction dir, unsigned long attrs) +{ + unsigned long page_pfn = page_to_xen_pfn(page); + unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr); + unsigned long compound_pages = + (1<archdata.dev_dma_ops = dev->dma_ops; + if (xen_initial_domain()) dev->dma_ops = xen_dma_ops; - } #endif } diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 989cf872b98c..bb7888429be6 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -645,7 +645,7 @@ xen_swiotlb_dma_mmap(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, dma_addr_t dma_addr, size_t size, unsigned long attrs) { -#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) +#ifdef CONFIG_ARM if (xen_get_dma_ops(dev)->mmap) return xen_get_dma_ops(dev)->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); @@ -662,7 +662,7 @@ xen_swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt, void *cpu_addr, dma_addr_t handle, size_t size, unsigned long attrs) { -#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) +#ifdef CONFIG_ARM if (xen_get_dma_ops(dev)->get_sgtable) { #if 0 /* diff --git a/include/xen/arm/page-coherent.h b/include/xen/arm/page-coherent.h index 59a260712a56..2ca9164a79bf 100644 --- a/include/xen/arm/page-coherent.h +++ b/include/xen/arm/page-coherent.h @@ -1,17 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_ARM_XEN_PAGE_COHERENT_H -#define _ASM_ARM_XEN_PAGE_COHERENT_H - -#include -#include -#include - -static inline const struct dma_map_ops *xen_get_dma_ops(struct device *dev) -{ - if (dev && dev->archdata.dev_dma_ops) - return dev->archdata.dev_dma_ops; - return get_arch_dma_ops(NULL); -} +#ifndef _XEN_ARM_PAGE_COHERENT_H +#define _XEN_ARM_PAGE_COHERENT_H void __xen_dma_map_page(struct device *hwdev, struct page *page, dma_addr_t dev_addr, unsigned long offset, size_t size, @@ -21,87 +10,7 @@ void __xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle, unsigned long attrs); void __xen_dma_sync_single_for_cpu(struct device *hwdev, dma_addr_t handle, size_t size, enum dma_data_direction dir); - void __xen_dma_sync_single_for_device(struct device *hwdev, dma_addr_t handle, size_t size, enum dma_data_direction dir); -static inline void *xen_alloc_coherent_pages(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, gfp_t flags, unsigned long attrs) -{ - return xen_get_dma_ops(hwdev)->alloc(hwdev, size, dma_handle, flags, attrs); -} - -static inline void xen_free_coherent_pages(struct device *hwdev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, unsigned long attrs) -{ - xen_get_dma_ops(hwdev)->free(hwdev, size, cpu_addr, dma_handle, attrs); -} - -static inline void xen_dma_map_page(struct device *hwdev, struct page *page, - dma_addr_t dev_addr, unsigned long offset, size_t size, - enum dma_data_direction dir, unsigned long attrs) -{ - unsigned long page_pfn = page_to_xen_pfn(page); - unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr); - unsigned long compound_pages = - (1<map_page(hwdev, page, offset, size, dir, attrs); - else - __xen_dma_map_page(hwdev, page, dev_addr, offset, size, dir, attrs); -} - -static inline void xen_dma_unmap_page(struct device *hwdev, dma_addr_t handle, - size_t size, enum dma_data_direction dir, unsigned long attrs) -{ - unsigned long pfn = PFN_DOWN(handle); - /* - * Dom0 is mapped 1:1, while the Linux page can be spanned accross - * multiple Xen page, it's not possible to have a mix of local and - * foreign Xen page. Dom0 is mapped 1:1, so calling pfn_valid on a - * foreign mfn will always return false. If the page is local we can - * safely call the native dma_ops function, otherwise we call the xen - * specific function. - */ - if (pfn_valid(pfn)) { - if (xen_get_dma_ops(hwdev)->unmap_page) - xen_get_dma_ops(hwdev)->unmap_page(hwdev, handle, size, dir, attrs); - } else - __xen_dma_unmap_page(hwdev, handle, size, dir, attrs); -} - -static inline void xen_dma_sync_single_for_cpu(struct device *hwdev, - dma_addr_t handle, size_t size, enum dma_data_direction dir) -{ - unsigned long pfn = PFN_DOWN(handle); - if (pfn_valid(pfn)) { - if (xen_get_dma_ops(hwdev)->sync_single_for_cpu) - xen_get_dma_ops(hwdev)->sync_single_for_cpu(hwdev, handle, size, dir); - } else - __xen_dma_sync_single_for_cpu(hwdev, handle, size, dir); -} - -static inline void xen_dma_sync_single_for_device(struct device *hwdev, - dma_addr_t handle, size_t size, enum dma_data_direction dir) -{ - unsigned long pfn = PFN_DOWN(handle); - if (pfn_valid(pfn)) { - if (xen_get_dma_ops(hwdev)->sync_single_for_device) - xen_get_dma_ops(hwdev)->sync_single_for_device(hwdev, handle, size, dir); - } else - __xen_dma_sync_single_for_device(hwdev, handle, size, dir); -} - -#endif /* _ASM_ARM_XEN_PAGE_COHERENT_H */ +#endif /* _XEN_ARM_PAGE_COHERENT_H */ -- cgit v1.2.3-58-ga151 From 4c174e6366746ae8d49f9cc409f728eebb7a9ac9 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Tue, 8 Jan 2019 00:53:22 -0800 Subject: nvme-rdma: fix timeout handler Currently, we have several problems with the timeout handler: 1. If we timeout on the controller establishment flow, we will hang because we don't execute the error recovery (and we shouldn't because the create_ctrl flow needs to fail and cleanup on its own) 2. We might also hang if we get a disconnet on a queue while the controller is already deleting. This racy flow can cause the controller disable/shutdown admin command to hang. We cannot complete a timed out request from the timeout handler without mutual exclusion from the teardown flow (e.g. nvme_rdma_error_recovery_work). So we serialize it in the timeout handler and teardown io and admin queues to guarantee that no one races with us from completing the request. Reported-by: Jaesoo Lee Reviewed-by: Christoph Hellwig Signed-off-by: Sagi Grimberg Signed-off-by: Jens Axboe --- drivers/nvme/host/rdma.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 0a2fd2949ad7..4101961feb44 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -1689,18 +1689,28 @@ static enum blk_eh_timer_return nvme_rdma_timeout(struct request *rq, bool reserved) { struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq); + struct nvme_rdma_queue *queue = req->queue; + struct nvme_rdma_ctrl *ctrl = queue->ctrl; - dev_warn(req->queue->ctrl->ctrl.device, - "I/O %d QID %d timeout, reset controller\n", - rq->tag, nvme_rdma_queue_idx(req->queue)); + dev_warn(ctrl->ctrl.device, "I/O %d QID %d timeout\n", + rq->tag, nvme_rdma_queue_idx(queue)); - /* queue error recovery */ - nvme_rdma_error_recovery(req->queue->ctrl); + if (ctrl->ctrl.state != NVME_CTRL_LIVE) { + /* + * Teardown immediately if controller times out while starting + * or we are already started error recovery. all outstanding + * requests are completed on shutdown, so we return BLK_EH_DONE. + */ + flush_work(&ctrl->err_work); + nvme_rdma_teardown_io_queues(ctrl, false); + nvme_rdma_teardown_admin_queue(ctrl, false); + return BLK_EH_DONE; + } - /* fail with DNR on cmd timeout */ - nvme_req(rq)->status = NVME_SC_ABORT_REQ | NVME_SC_DNR; + dev_warn(ctrl->ctrl.device, "starting error recovery\n"); + nvme_rdma_error_recovery(ctrl); - return BLK_EH_DONE; + return BLK_EH_RESET_TIMER; } static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, -- cgit v1.2.3-58-ga151 From 39d57757467b6346bbc1a1f416e3057f681cf903 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Tue, 8 Jan 2019 01:01:30 -0800 Subject: nvme-tcp: fix timeout handler Currently, we have several problems with the timeout handler: 1. If we timeout on the controller establishment flow, we will hang because we don't execute the error recovery (and we shouldn't because the create_ctrl flow needs to fail and cleanup on its own) 2. We might also hang if we get a disconnet on a queue while the controller is already deleting. This racy flow can cause the controller disable/shutdown admin command to hang. We cannot complete a timed out request from the timeout handler without mutual exclusion from the teardown flow (e.g. nvme_rdma_error_recovery_work). So we serialize it in the timeout handler and teardown io and admin queues to guarantee that no one races with us from completing the request. Reviewed-by: Christoph Hellwig Signed-off-by: Sagi Grimberg Signed-off-by: Jens Axboe --- drivers/nvme/host/tcp.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 265a0543b381..5f0a00425242 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1948,20 +1948,23 @@ nvme_tcp_timeout(struct request *rq, bool reserved) struct nvme_tcp_ctrl *ctrl = req->queue->ctrl; struct nvme_tcp_cmd_pdu *pdu = req->pdu; - dev_dbg(ctrl->ctrl.device, + dev_warn(ctrl->ctrl.device, "queue %d: timeout request %#x type %d\n", - nvme_tcp_queue_id(req->queue), rq->tag, - pdu->hdr.type); + nvme_tcp_queue_id(req->queue), rq->tag, pdu->hdr.type); if (ctrl->ctrl.state != NVME_CTRL_LIVE) { - union nvme_result res = {}; - - nvme_req(rq)->flags |= NVME_REQ_CANCELLED; - nvme_end_request(rq, cpu_to_le16(NVME_SC_ABORT_REQ), res); + /* + * Teardown immediately if controller times out while starting + * or we are already started error recovery. all outstanding + * requests are completed on shutdown, so we return BLK_EH_DONE. + */ + flush_work(&ctrl->err_work); + nvme_tcp_teardown_io_queues(&ctrl->ctrl, false); + nvme_tcp_teardown_admin_queue(&ctrl->ctrl, false); return BLK_EH_DONE; } - /* queue error recovery */ + dev_warn(ctrl->ctrl.device, "starting error recovery\n"); nvme_tcp_error_recovery(&ctrl->ctrl); return BLK_EH_RESET_TIMER; -- cgit v1.2.3-58-ga151 From b1064d3e337b4d0b67d641b5f771187d8f1f027d Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Fri, 18 Jan 2019 16:43:24 -0800 Subject: nvme-rdma: rework queue maps handling If the device supports less queues than provided (if the device has less completion vectors), we might hit a bug due to the fact that we ignore that in nvme_rdma_map_queues (we override the maps nr_queues with user opts). Instead, keep track of how many default/read/poll queues we actually allocated (rather than asked by the user) and use that to assign our queue mappings. Fixes: b65bb777ef22 (" nvme-rdma: support separate queue maps for read and write") Reported-by: Saleem, Shiraz Reviewed-by: Christoph Hellwig Signed-off-by: Sagi Grimberg Signed-off-by: Jens Axboe --- drivers/nvme/host/rdma.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 4101961feb44..52abc3a6de12 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -119,6 +119,7 @@ struct nvme_rdma_ctrl { struct nvme_ctrl ctrl; bool use_inline_data; + u32 io_queues[HCTX_MAX_TYPES]; }; static inline struct nvme_rdma_ctrl *to_rdma_ctrl(struct nvme_ctrl *ctrl) @@ -165,8 +166,8 @@ static inline int nvme_rdma_queue_idx(struct nvme_rdma_queue *queue) static bool nvme_rdma_poll_queue(struct nvme_rdma_queue *queue) { return nvme_rdma_queue_idx(queue) > - queue->ctrl->ctrl.opts->nr_io_queues + - queue->ctrl->ctrl.opts->nr_write_queues; + queue->ctrl->io_queues[HCTX_TYPE_DEFAULT] + + queue->ctrl->io_queues[HCTX_TYPE_READ]; } static inline size_t nvme_rdma_inline_data_size(struct nvme_rdma_queue *queue) @@ -661,8 +662,21 @@ static int nvme_rdma_alloc_io_queues(struct nvme_rdma_ctrl *ctrl) nr_io_queues = min_t(unsigned int, nr_io_queues, ibdev->num_comp_vectors); - nr_io_queues += min(opts->nr_write_queues, num_online_cpus()); - nr_io_queues += min(opts->nr_poll_queues, num_online_cpus()); + if (opts->nr_write_queues) { + ctrl->io_queues[HCTX_TYPE_DEFAULT] = + min(opts->nr_write_queues, nr_io_queues); + nr_io_queues += ctrl->io_queues[HCTX_TYPE_DEFAULT]; + } else { + ctrl->io_queues[HCTX_TYPE_DEFAULT] = nr_io_queues; + } + + ctrl->io_queues[HCTX_TYPE_READ] = nr_io_queues; + + if (opts->nr_poll_queues) { + ctrl->io_queues[HCTX_TYPE_POLL] = + min(opts->nr_poll_queues, num_online_cpus()); + nr_io_queues += ctrl->io_queues[HCTX_TYPE_POLL]; + } ret = nvme_set_queue_count(&ctrl->ctrl, &nr_io_queues); if (ret) @@ -1789,17 +1803,15 @@ static int nvme_rdma_map_queues(struct blk_mq_tag_set *set) struct nvme_rdma_ctrl *ctrl = set->driver_data; set->map[HCTX_TYPE_DEFAULT].queue_offset = 0; - set->map[HCTX_TYPE_READ].nr_queues = ctrl->ctrl.opts->nr_io_queues; + set->map[HCTX_TYPE_DEFAULT].nr_queues = + ctrl->io_queues[HCTX_TYPE_DEFAULT]; + set->map[HCTX_TYPE_READ].nr_queues = ctrl->io_queues[HCTX_TYPE_READ]; if (ctrl->ctrl.opts->nr_write_queues) { /* separate read/write queues */ - set->map[HCTX_TYPE_DEFAULT].nr_queues = - ctrl->ctrl.opts->nr_write_queues; set->map[HCTX_TYPE_READ].queue_offset = - ctrl->ctrl.opts->nr_write_queues; + ctrl->io_queues[HCTX_TYPE_DEFAULT]; } else { /* mixed read/write queues */ - set->map[HCTX_TYPE_DEFAULT].nr_queues = - ctrl->ctrl.opts->nr_io_queues; set->map[HCTX_TYPE_READ].queue_offset = 0; } blk_mq_rdma_map_queues(&set->map[HCTX_TYPE_DEFAULT], @@ -1809,12 +1821,12 @@ static int nvme_rdma_map_queues(struct blk_mq_tag_set *set) if (ctrl->ctrl.opts->nr_poll_queues) { set->map[HCTX_TYPE_POLL].nr_queues = - ctrl->ctrl.opts->nr_poll_queues; + ctrl->io_queues[HCTX_TYPE_POLL]; set->map[HCTX_TYPE_POLL].queue_offset = - ctrl->ctrl.opts->nr_io_queues; + ctrl->io_queues[HCTX_TYPE_DEFAULT]; if (ctrl->ctrl.opts->nr_write_queues) set->map[HCTX_TYPE_POLL].queue_offset += - ctrl->ctrl.opts->nr_write_queues; + ctrl->io_queues[HCTX_TYPE_READ]; blk_mq_map_queues(&set->map[HCTX_TYPE_POLL]); } return 0; -- cgit v1.2.3-58-ga151 From 5cbab6303b4791a3e6713dfe2c5fda6a867f9adc Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Thu, 3 Jan 2019 23:05:31 +0530 Subject: nvmet-rdma: fix null dereference under heavy load Under heavy load if we don't have any pre-allocated rsps left, we dynamically allocate a rsp, but we are not actually allocating memory for nvme_completion (rsp->req.rsp). In such a case, accessing pointer fields (req->rsp->status) in nvmet_req_init() will result in crash. To fix this, allocate the memory for nvme_completion by calling nvmet_rdma_alloc_rsp() Fixes: 8407879c("nvmet-rdma:fix possible bogus dereference under heavy load") Cc: Reviewed-by: Max Gurtovoy Reviewed-by: Christoph Hellwig Signed-off-by: Raju Rangoju Signed-off-by: Sagi Grimberg Signed-off-by: Jens Axboe --- drivers/nvme/target/rdma.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index a8d23eb80192..a884e3a0e8af 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -139,6 +139,10 @@ static void nvmet_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc); static void nvmet_rdma_read_data_done(struct ib_cq *cq, struct ib_wc *wc); static void nvmet_rdma_qp_event(struct ib_event *event, void *priv); static void nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue); +static void nvmet_rdma_free_rsp(struct nvmet_rdma_device *ndev, + struct nvmet_rdma_rsp *r); +static int nvmet_rdma_alloc_rsp(struct nvmet_rdma_device *ndev, + struct nvmet_rdma_rsp *r); static const struct nvmet_fabrics_ops nvmet_rdma_ops; @@ -182,9 +186,17 @@ nvmet_rdma_get_rsp(struct nvmet_rdma_queue *queue) spin_unlock_irqrestore(&queue->rsps_lock, flags); if (unlikely(!rsp)) { - rsp = kmalloc(sizeof(*rsp), GFP_KERNEL); + int ret; + + rsp = kzalloc(sizeof(*rsp), GFP_KERNEL); if (unlikely(!rsp)) return NULL; + ret = nvmet_rdma_alloc_rsp(queue->dev, rsp); + if (unlikely(ret)) { + kfree(rsp); + return NULL; + } + rsp->allocated = true; } @@ -197,6 +209,7 @@ nvmet_rdma_put_rsp(struct nvmet_rdma_rsp *rsp) unsigned long flags; if (unlikely(rsp->allocated)) { + nvmet_rdma_free_rsp(rsp->queue->dev, rsp); kfree(rsp); return; } -- cgit v1.2.3-58-ga151 From 78a61cd42a64f3587862b372a79e1d6aaf131fd7 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 9 Jan 2019 09:45:15 +0100 Subject: nvme-multipath: drop optimization for static ANA group IDs Bit 6 in the ANACAP field is used to indicate that the ANA group ID doesn't change while the namespace is attached to the controller. There is an optimisation in the code to only allocate space for the ANA group header, as the namespace list won't change and hence would not need to be refreshed. However, this optimisation was never carried over to the actual workflow, which always assumes that the buffer is large enough to hold the ANA header _and_ the namespace list. So drop this optimisation and always allocate enough space. Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke Signed-off-by: Sagi Grimberg Signed-off-by: Jens Axboe --- drivers/nvme/host/multipath.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index df4b3a6db51b..b9fff3b8ed1b 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -545,8 +545,7 @@ int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) timer_setup(&ctrl->anatt_timer, nvme_anatt_timeout, 0); ctrl->ana_log_size = sizeof(struct nvme_ana_rsp_hdr) + ctrl->nanagrpid * sizeof(struct nvme_ana_group_desc); - if (!(ctrl->anacap & (1 << 6))) - ctrl->ana_log_size += ctrl->max_namespaces * sizeof(__le32); + ctrl->ana_log_size += ctrl->max_namespaces * sizeof(__le32); if (ctrl->ana_log_size > ctrl->max_hw_sectors << SECTOR_SHIFT) { dev_err(ctrl->device, -- cgit v1.2.3-58-ga151 From 2b24408158276faf0f4a71eb97a2364686d5b06c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 23 Jan 2019 13:51:55 +0000 Subject: drm/i915/execlists: Mark up priority boost on preemption Record the priority boost we giving to the preempted client or else we may end up in a situation where the priority queue no longer matches the request priority order and so we can end up in an infinite loop of preempting the same pair of requests. Fixes: e9eaf82d97a2 ("drm/i915: Priority boost for waiting clients") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Reviewed-by: Tvrtko Ursulin Link: https://patchwork.freedesktop.org/patch/msgid/20190123135155.21562-1-chris@chris-wilson.co.uk (cherry picked from commit 6e062b60b0b1bd82cac475e63cdb8c451647182b) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_lrc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 4796f40a6d4f..eab9341a5152 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -303,6 +303,7 @@ static void __unwind_incomplete_requests(struct intel_engine_cs *engine) */ if (!(prio & I915_PRIORITY_NEWCLIENT)) { prio |= I915_PRIORITY_NEWCLIENT; + active->sched.attr.priority = prio; list_move_tail(&active->sched.link, i915_sched_lookup_priolist(engine, prio)); } @@ -645,6 +646,9 @@ static void execlists_dequeue(struct intel_engine_cs *engine) int i; priolist_for_each_request_consume(rq, rn, p, i) { + GEM_BUG_ON(last && + need_preempt(engine, last, rq_prio(rq))); + /* * Can we combine this request with the current port? * It has to be the same context/ringbuffer and not -- cgit v1.2.3-58-ga151 From 141e5dcaa7356077028b4cd48ec351a38c70e5e5 Mon Sep 17 00:00:00 2001 From: Deepa Dinamani Date: Thu, 24 Jan 2019 00:29:20 -0800 Subject: Input: input_event - fix the CONFIG_SPARC64 mixup Arnd Bergmann pointed out that CONFIG_* cannot be used in a uapi header. Override with an equivalent conditional. Fixes: 2e746942ebac ("Input: input_event - provide override for sparc64") Fixes: 152194fe9c3f ("Input: extend usable life of event timestamps to 2106 on 32 bit systems") Signed-off-by: Deepa Dinamani Signed-off-by: Dmitry Torokhov --- include/uapi/linux/input.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index ffab958bc512..f056b2a00d5c 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -32,7 +32,7 @@ struct input_event { #define input_event_usec time.tv_usec #else __kernel_ulong_t __sec; -#ifdef CONFIG_SPARC64 +#if defined(__sparc__) && defined(__arch64__) unsigned int __usec; #else __kernel_ulong_t __usec; -- cgit v1.2.3-58-ga151 From 73aaf920cc72024c4a4460cfa46d56e5014172f3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 16 Jan 2019 16:28:59 +0000 Subject: cifs: fix memory leak of an allocated cifs_ntsd structure The call to SMB2_queary_acl can allocate memory to pntsd and also return a failure via a call to SMB2_query_acl (and then query_info). This occurs when query_info allocates the structure and then in query_info the call to smb2_validate_and_copy_iov fails. Currently the failure just returns without kfree'ing pntsd hence causing a memory leak. Currently, *data is allocated if it's not already pointing to a buffer, so it needs to be kfree'd only if was allocated in query_info, so the fix adds an allocated flag to track this. Also set *dlen to zero on an error just to be safe since *data is kfree'd. Also set errno to -ENOMEM if the allocation of *data fails. Signed-off-by: Colin Ian King Signed-off-by: Steve French Reviewed-by: Dan Carpener --- fs/cifs/smb2pdu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 50811a7dc0e0..0af87bd0dc49 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2816,6 +2816,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, int resp_buftype = CIFS_NO_BUFFER; struct cifs_ses *ses = tcon->ses; int flags = 0; + bool allocated = false; cifs_dbg(FYI, "Query Info\n"); @@ -2855,14 +2856,21 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, "Error %d allocating memory for acl\n", rc); *dlen = 0; + rc = -ENOMEM; goto qinf_exit; } + allocated = true; } } rc = smb2_validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset), le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, min_len, *data); + if (rc && allocated) { + kfree(*data); + *data = NULL; + *dlen = 0; + } qinf_exit: SMB2_query_info_free(&rqst); -- cgit v1.2.3-58-ga151 From acc58d0bab55a50e02c25f00bd6a210ee121595f Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 17 Jan 2019 08:21:24 -0800 Subject: CIFS: Fix possible hang during async MTU reads and writes When doing MTU i/o we need to leave some credits for possible reopen requests and other operations happening in parallel. Currently we leave 1 credit which is not enough even for reopen only: we need at least 2 credits if durable handle reconnect fails. Also there may be other operations at the same time including compounding ones which require 3 credits at a time each. Fix this by leaving 8 credits which is big enough to cover most scenarios. Was able to reproduce this when server was configured to give out fewer credits than usual. The proper fix would be to reconnect a file handle first and then obtain credits for an MTU request but this leads to bigger code changes and should happen in other patches. Cc: Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index cf7eb891804f..1d3ce127b02e 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -165,14 +165,14 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, scredits = server->credits; /* can deadlock with reopen */ - if (scredits == 1) { + if (scredits <= 8) { *num = SMB2_MAX_BUFFER_SIZE; *credits = 0; break; } - /* leave one credit for a possible reopen */ - scredits--; + /* leave some credits for reopen and other ops */ + scredits -= 8; *num = min_t(unsigned int, size, scredits * SMB2_MAX_BUFFER_SIZE); -- cgit v1.2.3-58-ga151 From b0b2cac7e244629e1a84a26d7eabb885fed7ff68 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 18 Jan 2019 00:14:23 +0100 Subject: smb3: Cleanup license mess Precise and non-ambiguous license information is important. The recently added aegis header file has a SPDX license identifier, which is nice, but at the same time it has a contradictionary license boiler plate text. SPDX-License-Identifier: GPL-2.0 versus * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. Oh well. Assuming that the SPDX identifier is correct and according to x86/hyper-v contributions from Microsoft GPL V2 only is the usual license. Remove the boiler plate as it is wrong and even if correct it is redundant. Fixes: eccb4422cf97 ("smb3: Add ftrace tracepoints for improved SMB3 debugging") Signed-off-by: Thomas Gleixner Cc: Steve French Cc: linux-cifs@vger.kernel.org Signed-off-by: Steve French --- fs/cifs/trace.c | 10 ---------- fs/cifs/trace.h | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/fs/cifs/trace.c b/fs/cifs/trace.c index bd4a546feec1..465483787193 100644 --- a/fs/cifs/trace.c +++ b/fs/cifs/trace.c @@ -3,16 +3,6 @@ * Copyright (C) 2018, Microsoft Corporation. * * Author(s): Steve French - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. */ #define CREATE_TRACE_POINTS #include "trace.h" diff --git a/fs/cifs/trace.h b/fs/cifs/trace.h index fb049809555f..59be48206932 100644 --- a/fs/cifs/trace.h +++ b/fs/cifs/trace.h @@ -3,16 +3,6 @@ * Copyright (C) 2018, Microsoft Corporation. * * Author(s): Steve French - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. */ #undef TRACE_SYSTEM #define TRACE_SYSTEM cifs -- cgit v1.2.3-58-ga151 From 1c26010c5e1b9ad22a77968428b68150d27ae65f Mon Sep 17 00:00:00 2001 From: Jianchao Wang Date: Thu, 24 Jan 2019 18:28:55 +0800 Subject: blk-mq: fix the cmd_flag_name array Swap REQ_NOWAIT and REQ_NOUNMAP and add REQ_HIPRI. Acked-by: Jeff Moyer Signed-off-by: Jianchao Wang Signed-off-by: Jens Axboe --- block/blk-mq-debugfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c index 90d68760af08..f8120832ca7b 100644 --- a/block/blk-mq-debugfs.c +++ b/block/blk-mq-debugfs.c @@ -308,8 +308,9 @@ static const char *const cmd_flag_name[] = { CMD_FLAG_NAME(PREFLUSH), CMD_FLAG_NAME(RAHEAD), CMD_FLAG_NAME(BACKGROUND), - CMD_FLAG_NAME(NOUNMAP), CMD_FLAG_NAME(NOWAIT), + CMD_FLAG_NAME(NOUNMAP), + CMD_FLAG_NAME(HIPRI), }; #undef CMD_FLAG_NAME -- cgit v1.2.3-58-ga151 From 245b6c6558128327d330549b23d09594c46f58df Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Tue, 22 Jan 2019 11:48:04 -0600 Subject: EDAC, altera: Fix S10 persistent register offset Correct the persistent register offset where address and status are stored. Fixes: 08f08bfb7b4c ("EDAC, altera: Merge Stratix10 into the Arria10 SDRAM probe routine") Signed-off-by: Thor Thayer Signed-off-by: Borislav Petkov Cc: James Morse Cc: Mauro Carvalho Chehab Cc: devicetree@vger.kernel.org Cc: dinguyen@kernel.org Cc: linux-edac Cc: mark.rutland@arm.com Cc: robh+dt@kernel.org Cc: stable Link: https://lkml.kernel.org/r/1548179287-21760-2-git-send-email-thor.thayer@linux.intel.com --- drivers/edac/altera_edac.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index 4213cb0bb2a7..f8664bac9fa8 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -295,8 +295,8 @@ struct altr_sdram_mc_data { #define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xA0 /* Sticky registers for Uncorrected Errors */ -#define S10_SYSMGR_UE_VAL_OFST 0x120 -#define S10_SYSMGR_UE_ADDR_OFST 0x124 +#define S10_SYSMGR_UE_VAL_OFST 0x220 +#define S10_SYSMGR_UE_ADDR_OFST 0x224 #define S10_DDR0_IRQ_MASK BIT(16) -- cgit v1.2.3-58-ga151 From c83f536a87d9dd6d6bf989c0b0882459a902eb07 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 23 Jan 2019 11:05:57 -0800 Subject: blk-wbt: Declare local functions static This patch avoids that sparse reports the following warnings: CHECK block/blk-wbt.c block/blk-wbt.c:600:6: warning: symbol 'wbt_issue' was not declared. Should it be static? block/blk-wbt.c:620:6: warning: symbol 'wbt_requeue' was not declared. Should it be static? CC block/blk-wbt.o block/blk-wbt.c:600:6: warning: no previous prototype for wbt_issue [-Wmissing-prototypes] void wbt_issue(struct rq_qos *rqos, struct request *rq) ^~~~~~~~~ block/blk-wbt.c:620:6: warning: no previous prototype for wbt_requeue [-Wmissing-prototypes] void wbt_requeue(struct rq_qos *rqos, struct request *rq) ^~~~~~~~~~~ Reviewed-by: Chaitanya Kulkarni Signed-off-by: Bart Van Assche Signed-off-by: Jens Axboe --- block/blk-wbt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/blk-wbt.c b/block/blk-wbt.c index f0c56649775f..fd166fbb0f65 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -597,7 +597,7 @@ static void wbt_track(struct rq_qos *rqos, struct request *rq, struct bio *bio) rq->wbt_flags |= bio_to_wbt_flags(rwb, bio); } -void wbt_issue(struct rq_qos *rqos, struct request *rq) +static void wbt_issue(struct rq_qos *rqos, struct request *rq) { struct rq_wb *rwb = RQWB(rqos); @@ -617,7 +617,7 @@ void wbt_issue(struct rq_qos *rqos, struct request *rq) } } -void wbt_requeue(struct rq_qos *rqos, struct request *rq) +static void wbt_requeue(struct rq_qos *rqos, struct request *rq) { struct rq_wb *rwb = RQWB(rqos); if (!rwb_enabled(rwb)) -- cgit v1.2.3-58-ga151 From 745815f955f65f22d378d69822da11043d00aaff Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 24 Jan 2019 18:20:13 +0900 Subject: uapi: fix ioctl documentation The description of the BLKGETNRZONES zoned block device ioctl was not added as a comment together with this ioctl definition in commit 65e4e3eee83d7 ("block: Introduce BLKGETNRZONES ioctl"). Add its description here. Signed-off-by: Damien Le Moal Signed-off-by: Jens Axboe --- include/uapi/linux/blkzoned.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/blkzoned.h b/include/uapi/linux/blkzoned.h index 6fa38d001d84..498eec813494 100644 --- a/include/uapi/linux/blkzoned.h +++ b/include/uapi/linux/blkzoned.h @@ -138,6 +138,7 @@ struct blk_zone_range { * @BLKRESETZONE: Reset the write pointer of the zones in the specified * sector range. The sector range must be zone aligned. * @BLKGETZONESZ: Get the device zone size in number of 512 B sectors. + * @BLKGETNRZONES: Get the total number of zones of the device. */ #define BLKREPORTZONE _IOWR(0x12, 130, struct blk_zone_report) #define BLKRESETZONE _IOW(0x12, 131, struct blk_zone_range) -- cgit v1.2.3-58-ga151 From 8367de2c99a13d35960a51d6084631c883e93a4d Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Thu, 24 Jan 2019 18:20:14 +0900 Subject: block: Fix comment typo Fix typo in REQ_OP_ZONE_RESET description. Signed-off-by: Damien Le Moal Signed-off-by: Jens Axboe --- include/linux/blk_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 5c7e7f859a24..d66bf5f32610 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -287,7 +287,7 @@ enum req_opf { REQ_OP_DISCARD = 3, /* securely erase sectors */ REQ_OP_SECURE_ERASE = 5, - /* seset a zone write pointer */ + /* reset a zone write pointer */ REQ_OP_ZONE_RESET = 6, /* write the same sector many times */ REQ_OP_WRITE_SAME = 7, -- cgit v1.2.3-58-ga151 From 4ffdca62e2deee7a27613571c9bd18c95b8eac84 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jan 2019 17:37:35 +0000 Subject: ASoC: Intel: make const arrays static, reduces object code size Don't populate the const arrays on the stack but instead make it static. Makes the object code smaller, for example: Before: text data bss dec hex filename 14107 8832 224 23163 5a7b bytcht_es8316.o After: text data bss dec hex filename 14015 8896 224 23135 5a5f bytcht_es8316.o (gcc version 8.2.0 x86_64) Signed-off-by: Colin Ian King Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 2 +- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index fa9c4cf97686..1364e4e601d8 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -437,7 +437,7 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { - const char * const mic_name[] = { "in1", "in2" }; + static const char * const mic_name[] = { "in1", "in2" }; struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index ca8b4d5ff70f..a79466c8fb29 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1149,7 +1149,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { - const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; + static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index b618d984e2d5..e6945d11c8ab 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -919,7 +919,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) { - const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; + static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; struct device *codec_dev; -- cgit v1.2.3-58-ga151 From c878a628e0c483ec36fa70f4590e4a58e34a6e49 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 13 Aug 2018 23:23:44 +0200 Subject: drm/msm/gpu: fix building without debugfs When debugfs is disabled, but coredump is turned on, the adreno driver fails to build: drivers/gpu/drm/msm/adreno/a3xx_gpu.c:460:4: error: 'struct msm_gpu_funcs' has no member named 'show' .show = adreno_show, ^~~~ drivers/gpu/drm/msm/adreno/a3xx_gpu.c:460:11: note: (near initialization for 'funcs.base') drivers/gpu/drm/msm/adreno/a3xx_gpu.c:460:11: error: initialization of 'void (*)(struct msm_gpu *, struct msm_gem_submit *, struct msm_file_private *)' from incompatible pointer type 'void (*)(struct msm_gpu *, struct msm_gpu_state *, struct drm_printer *)' [-Werror=incompatible-pointer-types] drivers/gpu/drm/msm/adreno/a3xx_gpu.c:460:11: note: (near initialization for 'funcs.base.submit') drivers/gpu/drm/msm/adreno/a4xx_gpu.c:546:4: error: 'struct msm_gpu_funcs' has no member named 'show' drivers/gpu/drm/msm/adreno/a5xx_gpu.c:1460:4: error: 'struct msm_gpu_funcs' has no member named 'show' drivers/gpu/drm/msm/adreno/a6xx_gpu.c:769:4: error: 'struct msm_gpu_funcs' has no member named 'show' drivers/gpu/drm/msm/msm_gpu.c: In function 'msm_gpu_devcoredump_read': drivers/gpu/drm/msm/msm_gpu.c:289:12: error: 'const struct msm_gpu_funcs' has no member named 'show' Adjust the #ifdef to make it build again. Fixes: c0fec7f562ec ("drm/msm/gpu: Capture the GPU state on a GPU hang") Signed-off-by: Arnd Bergmann Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index efb49bb64191..95170dee9d7a 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -63,7 +63,7 @@ struct msm_gpu_funcs { struct msm_ringbuffer *(*active_ring)(struct msm_gpu *gpu); void (*recover)(struct msm_gpu *gpu); void (*destroy)(struct msm_gpu *gpu); -#ifdef CONFIG_DEBUG_FS +#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP) /* show GPU status in debugfs: */ void (*show)(struct msm_gpu *gpu, struct msm_gpu_state *state, struct drm_printer *p); -- cgit v1.2.3-58-ga151 From 878411aef631e4e2dd8d6c7cdb01e95a076cbcb9 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Tue, 18 Dec 2018 11:32:36 -0700 Subject: drm/msm/gpu: Remove hardcoded interrupt name Every GPU core only has one interrupt so there isn't any value in looking up the interrupt by name. Remove the name (which is legacy anyway) and use platform_get_irq() instead. Signed-off-by: Jordan Crouse Reviewed-by: Douglas Anderson Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 1 - drivers/gpu/drm/msm/msm_gpu.c | 2 +- drivers/gpu/drm/msm/msm_gpu.h | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 2e4372ef17a3..2cfee1a4fe0b 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -765,7 +765,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, adreno_gpu->rev = config->rev; adreno_gpu_config.ioname = "kgsl_3d0_reg_memory"; - adreno_gpu_config.irqname = "kgsl_3d0_irq"; adreno_gpu_config.va_start = SZ_16M; adreno_gpu_config.va_end = 0xffffffff; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 6e079a83bd36..abefba5b14e7 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -897,7 +897,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, } /* Get Interrupt: */ - gpu->irq = platform_get_irq_byname(pdev, config->irqname); + gpu->irq = platform_get_irq(pdev, 0); if (gpu->irq < 0) { ret = gpu->irq; DRM_DEV_ERROR(drm->dev, "failed to get irq: %d\n", ret); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 95170dee9d7a..ca17086f72c9 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -31,7 +31,6 @@ struct msm_gpu_state; struct msm_gpu_config { const char *ioname; - const char *irqname; uint64_t va_start; uint64_t va_end; unsigned int nr_rings; -- cgit v1.2.3-58-ga151 From 895ad6b0ccf71ec1f8d5bc4d9f15b525feb160a8 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Tue, 18 Dec 2018 11:32:37 -0700 Subject: drm/msm: drop interrupt-names Each GPU core only uses one interrupt so we don't to look up an interrupt by name and thereby we don't need interrupt-names. Signed-off-by: Jordan Crouse Reviewed-by: Rob Herring Signed-off-by: Rob Clark --- Documentation/devicetree/bindings/display/msm/gpu.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/msm/gpu.txt b/Documentation/devicetree/bindings/display/msm/gpu.txt index ac8df3b871f9..f8759145ce1a 100644 --- a/Documentation/devicetree/bindings/display/msm/gpu.txt +++ b/Documentation/devicetree/bindings/display/msm/gpu.txt @@ -27,7 +27,6 @@ Example: reg = <0x04300000 0x20000>; reg-names = "kgsl_3d0_reg_memory"; interrupts = ; - interrupt-names = "kgsl_3d0_irq"; clock-names = "core", "iface", -- cgit v1.2.3-58-ga151 From bbc2cd07c5100514f25ac6e09d2a94521b46b35b Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 9 Jan 2019 14:25:05 -0500 Subject: drm/msm: honor GPU_READONLY flag Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.h | 3 ++- drivers/gpu/drm/msm/msm_gem.c | 8 ++++++-- drivers/gpu/drm/msm/msm_gem_vma.c | 5 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 9cd6a96c6bf2..9f51be5a637c 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -250,7 +250,8 @@ void msm_gem_purge_vma(struct msm_gem_address_space *aspace, void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma); int msm_gem_map_vma(struct msm_gem_address_space *aspace, - struct msm_gem_vma *vma, struct sg_table *sgt, int npages); + struct msm_gem_vma *vma, int prot, + struct sg_table *sgt, int npages); void msm_gem_close_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 51a95da694d8..c8886d3071fa 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -391,6 +391,10 @@ static int msm_gem_pin_iova(struct drm_gem_object *obj, struct msm_gem_object *msm_obj = to_msm_bo(obj); struct msm_gem_vma *vma; struct page **pages; + int prot = IOMMU_READ; + + if (!(msm_obj->flags & MSM_BO_GPU_READONLY)) + prot |= IOMMU_WRITE; WARN_ON(!mutex_is_locked(&msm_obj->lock)); @@ -405,8 +409,8 @@ static int msm_gem_pin_iova(struct drm_gem_object *obj, if (IS_ERR(pages)) return PTR_ERR(pages); - return msm_gem_map_vma(aspace, vma, msm_obj->sgt, - obj->size >> PAGE_SHIFT); + return msm_gem_map_vma(aspace, vma, prot, + msm_obj->sgt, obj->size >> PAGE_SHIFT); } /* get iova and pin it. Should have a matching put */ diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 557360788084..49c04829cf34 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -68,7 +68,8 @@ void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, int msm_gem_map_vma(struct msm_gem_address_space *aspace, - struct msm_gem_vma *vma, struct sg_table *sgt, int npages) + struct msm_gem_vma *vma, int prot, + struct sg_table *sgt, int npages) { unsigned size = npages << PAGE_SHIFT; int ret = 0; @@ -86,7 +87,7 @@ msm_gem_map_vma(struct msm_gem_address_space *aspace, if (aspace->mmu) ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt, - size, IOMMU_READ | IOMMU_WRITE); + size, prot); if (ret) vma->mapped = false; -- cgit v1.2.3-58-ga151 From a3c5e2cd79753121f49a8662c1e0a60ddb5486ca Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 16 Jan 2019 10:46:21 -0800 Subject: drm/msm: Fix A6XX support for opp-level The bindings for Qualcomm opp levels changed after being Acked but before landing. Thus the code in the GPU driver that was relying on the old bindings is now broken. Let's change the code to match the new bindings by adjusting the old string 'qcom,level' to the new string 'opp-level'. See the patch ("dt-bindings: opp: Introduce opp-level bindings"). NOTE: we will do additional cleanup to totally remove the string from the code and use the new dev_pm_opp_get_level() but we'll do it in a future patch. This will facilitate getting the important code fix in sooner without having to deal with cross-maintainer dependencies. This patch needs to land before the patch ("arm64: dts: sdm845: Add gpu and gmu device nodes") since if a tree contains the device tree patch but not this one you'll get a crash at bootup. Fixes: 4b565ca5a2cb ("drm/msm: Add A6XX device support") Signed-off-by: Douglas Anderson Reviewed-by: Jordan Crouse Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index c58e953fefa3..e942316b3ba7 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -964,7 +964,7 @@ static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) np = dev_pm_opp_get_of_node(opp); if (np) { - of_property_read_u32(np, "qcom,level", &val); + of_property_read_u32(np, "opp-level", &val); of_node_put(np); } -- cgit v1.2.3-58-ga151 From 023014e72e0a6e4c188a6ecb67cc744d90866327 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 17 Jan 2019 14:17:36 -0800 Subject: drm/msm: Add __printf verification Add a few __printf attribute specifiers to routines that could use them. Signed-off-by: Joe Perches Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 9f51be5a637c..927e5d86f7c1 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -334,6 +334,7 @@ void msm_gem_kernel_put(struct drm_gem_object *bo, struct drm_gem_object *msm_gem_import(struct drm_device *dev, struct dma_buf *dmabuf, struct sg_table *sgt); +__printf(2, 3) void msm_gem_object_set_name(struct drm_gem_object *bo, const char *fmt, ...); int msm_framebuffer_prepare(struct drm_framebuffer *fb, @@ -397,12 +398,14 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m); int msm_debugfs_late_init(struct drm_device *dev); int msm_rd_debugfs_init(struct drm_minor *minor); void msm_rd_debugfs_cleanup(struct msm_drm_private *priv); +__printf(3, 4) void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit, const char *fmt, ...); int msm_perf_debugfs_init(struct drm_minor *minor); void msm_perf_debugfs_cleanup(struct msm_drm_private *priv); #else static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; } +__printf(3, 4) static inline void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit, const char *fmt, ...) {} static inline void msm_rd_debugfs_cleanup(struct msm_drm_private *priv) {} -- cgit v1.2.3-58-ga151 From a840f690d3c6f2f27425ca7e7bd2d635cdec07d7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 10 Jan 2019 15:14:03 +0100 Subject: drm/msm: avoid unused function warning drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c:368:13: error: 'dpu_plane_danger_signal_ctrl' defined but not used [-Werror=unused-function] Fixes: 7b2e7adea732 ("drm/msm/dpu: Make dpu_plane_danger_signal_ctrl void") Signed-off-by: Arnd Bergmann Signed-off-by: Anders Roxell Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index fd75870eb17f..6aefcd6db46b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -365,19 +365,6 @@ static void _dpu_plane_set_qos_ctrl(struct drm_plane *plane, &pdpu->pipe_qos_cfg); } -static void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) -{ - struct dpu_plane *pdpu = to_dpu_plane(plane); - struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); - - if (!pdpu->is_rt_pipe) - return; - - pm_runtime_get_sync(&dpu_kms->pdev->dev); - _dpu_plane_set_qos_ctrl(plane, enable, DPU_PLANE_QOS_PANIC_CTRL); - pm_runtime_put_sync(&dpu_kms->pdev->dev); -} - /** * _dpu_plane_set_ot_limit - set OT limit for the given plane * @plane: Pointer to drm plane @@ -1248,6 +1235,19 @@ static void dpu_plane_reset(struct drm_plane *plane) } #ifdef CONFIG_DEBUG_FS +static void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) +{ + struct dpu_plane *pdpu = to_dpu_plane(plane); + struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); + + if (!pdpu->is_rt_pipe) + return; + + pm_runtime_get_sync(&dpu_kms->pdev->dev); + _dpu_plane_set_qos_ctrl(plane, enable, DPU_PLANE_QOS_PANIC_CTRL); + pm_runtime_put_sync(&dpu_kms->pdev->dev); +} + static ssize_t _dpu_plane_danger_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { -- cgit v1.2.3-58-ga151 From ef68e831840c40c7d01b328b3c0f5d8c4796c232 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 18 Jan 2019 17:25:36 -0800 Subject: CIFS: Do not reconnect TCP session in add_credits() When executing add_credits() we currently call cifs_reconnect() if the number of credits is zero and there are no requests in flight. In this case we may call cifs_reconnect() recursively twice and cause memory corruption given the following sequence of functions: mid1.callback() -> add_credits() -> cifs_reconnect() -> -> mid2.callback() -> add_credits() -> cifs_reconnect(). Fix this by avoiding to call cifs_reconnect() in add_credits() and checking for zero credits in the demultiplex thread. Cc: Signed-off-by: Pavel Shilovsky Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/connect.c | 21 +++++++++++++++++++++ fs/cifs/smb2ops.c | 32 +++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 683310f26171..8463c940e0e5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -720,6 +720,21 @@ server_unresponsive(struct TCP_Server_Info *server) return false; } +static inline bool +zero_credits(struct TCP_Server_Info *server) +{ + int val; + + spin_lock(&server->req_lock); + val = server->credits + server->echo_credits + server->oplock_credits; + if (server->in_flight == 0 && val == 0) { + spin_unlock(&server->req_lock); + return true; + } + spin_unlock(&server->req_lock); + return false; +} + static int cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg) { @@ -732,6 +747,12 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg) for (total_read = 0; msg_data_left(smb_msg); total_read += length) { try_to_freeze(); + /* reconnect if no credits and no requests in flight */ + if (zero_credits(server)) { + cifs_reconnect(server); + return -ECONNABORTED; + } + if (server_unresponsive(server)) return -ECONNABORTED; if (cifs_rdma_enabled(server) && server->smbd_conn) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 1d3ce127b02e..fa8d2e1076c8 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -34,6 +34,7 @@ #include "cifs_ioctl.h" #include "smbdirect.h" +/* Change credits for different ops and return the total number of credits */ static int change_conf(struct TCP_Server_Info *server) { @@ -41,17 +42,15 @@ change_conf(struct TCP_Server_Info *server) server->oplock_credits = server->echo_credits = 0; switch (server->credits) { case 0: - return -1; + return 0; case 1: server->echoes = false; server->oplocks = false; - cifs_dbg(VFS, "disabling echoes and oplocks\n"); break; case 2: server->echoes = true; server->oplocks = false; server->echo_credits = 1; - cifs_dbg(FYI, "disabling oplocks\n"); break; default: server->echoes = true; @@ -64,14 +63,15 @@ change_conf(struct TCP_Server_Info *server) server->echo_credits = 1; } server->credits -= server->echo_credits + server->oplock_credits; - return 0; + return server->credits + server->echo_credits + server->oplock_credits; } static void smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, const int optype) { - int *val, rc = 0; + int *val, rc = -1; + spin_lock(&server->req_lock); val = server->ops->get_credits_field(server, optype); @@ -101,8 +101,26 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, } spin_unlock(&server->req_lock); wake_up(&server->request_q); - if (rc) - cifs_reconnect(server); + + if (server->tcpStatus == CifsNeedReconnect) + return; + + switch (rc) { + case -1: + /* change_conf hasn't been executed */ + break; + case 0: + cifs_dbg(VFS, "Possible client or server bug - zero credits\n"); + break; + case 1: + cifs_dbg(VFS, "disabling echoes and oplocks\n"); + break; + case 2: + cifs_dbg(FYI, "disabling oplocks\n"); + break; + default: + cifs_dbg(FYI, "add %u credits total=%d\n", add, rc); + } } static void -- cgit v1.2.3-58-ga151 From 8004c78c68e894e4fd5ac3c22cc22eb7dc24cabc Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 17 Jan 2019 15:29:26 -0800 Subject: CIFS: Fix credits calculations for reads with errors Currently we mark MID as malformed if we get an error from server in a read response. This leads to not properly processing credits in the readv callback. Fix this by marking such a response as normal received response and process it appropriately. Cc: Signed-off-by: Pavel Shilovsky Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e18915415e13..bb54ccf8481c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1549,18 +1549,26 @@ cifs_discard_remaining_data(struct TCP_Server_Info *server) } static int -cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) +__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid, + bool malformed) { int length; - struct cifs_readdata *rdata = mid->callback_data; length = cifs_discard_remaining_data(server); - dequeue_mid(mid, rdata->result); + dequeue_mid(mid, malformed); mid->resp_buf = server->smallbuf; server->smallbuf = NULL; return length; } +static int +cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) +{ + struct cifs_readdata *rdata = mid->callback_data; + + return __cifs_readv_discard(server, mid, rdata->result); +} + int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) { @@ -1602,12 +1610,23 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) return -1; } + /* set up first two iov for signature check and to get credits */ + rdata->iov[0].iov_base = buf; + rdata->iov[0].iov_len = 4; + rdata->iov[1].iov_base = buf + 4; + rdata->iov[1].iov_len = server->total_read - 4; + cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", + rdata->iov[0].iov_base, rdata->iov[0].iov_len); + cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", + rdata->iov[1].iov_base, rdata->iov[1].iov_len); + /* Was the SMB read successful? */ rdata->result = server->ops->map_error(buf, false); if (rdata->result != 0) { cifs_dbg(FYI, "%s: server returned error %d\n", __func__, rdata->result); - return cifs_readv_discard(server, mid); + /* normal error on read response */ + return __cifs_readv_discard(server, mid, false); } /* Is there enough to get to the rest of the READ_RSP header? */ @@ -1651,14 +1670,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) server->total_read += length; } - /* set up first iov for signature check */ - rdata->iov[0].iov_base = buf; - rdata->iov[0].iov_len = 4; - rdata->iov[1].iov_base = buf + 4; - rdata->iov[1].iov_len = server->total_read - 4; - cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n", - rdata->iov[0].iov_base, server->total_read); - /* how much data is in the response? */ #ifdef CONFIG_CIFS_SMB_DIRECT use_rdma_mr = rdata->mr; -- cgit v1.2.3-58-ga151 From ec678eae746dd25766a61c4095e2b649d3b20b09 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 18 Jan 2019 15:38:11 -0800 Subject: CIFS: Fix credit calculation for encrypted reads with errors We do need to account for credits received in error responses to read requests on encrypted sessions. Cc: Signed-off-by: Pavel Shilovsky Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index fa8d2e1076c8..73f9c6af4065 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -3207,11 +3207,23 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, server->ops->is_status_pending(buf, server, 0)) return -1; - rdata->result = server->ops->map_error(buf, false); + /* set up first two iov to get credits */ + rdata->iov[0].iov_base = buf; + rdata->iov[0].iov_len = 4; + rdata->iov[1].iov_base = buf + 4; + rdata->iov[1].iov_len = + min_t(unsigned int, buf_len, server->vals->read_rsp_size) - 4; + cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", + rdata->iov[0].iov_base, rdata->iov[0].iov_len); + cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", + rdata->iov[1].iov_base, rdata->iov[1].iov_len); + + rdata->result = server->ops->map_error(buf, true); if (rdata->result != 0) { cifs_dbg(FYI, "%s: server returned error %d\n", __func__, rdata->result); - dequeue_mid(mid, rdata->result); + /* normal error on read response */ + dequeue_mid(mid, false); return 0; } @@ -3284,14 +3296,6 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, return 0; } - /* set up first iov for signature check */ - rdata->iov[0].iov_base = buf; - rdata->iov[0].iov_len = 4; - rdata->iov[1].iov_base = buf + 4; - rdata->iov[1].iov_len = server->vals->read_rsp_size - 4; - cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", - rdata->iov[0].iov_base, server->vals->read_rsp_size); - length = rdata->copy_into_pages(server, rdata, &iter); kfree(bvec); -- cgit v1.2.3-58-ga151 From 3d3003fce8e837acc4e3960fe3cbabebc356dcb5 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 22 Jan 2019 16:50:21 -0800 Subject: CIFS: Fix credit calculations in compound mid callback The current code doesn't do proper accounting for credits in SMB1 case: it adds one credit per response only if we get a complete response while it needs to return it unconditionally. Fix this and also include malformed responses for SMB2+ into accounting for credits because such responses have Credit Granted field, thus nothing prevents to get a proper credit value from them. Signed-off-by: Pavel Shilovsky Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 6 +++++- fs/cifs/transport.c | 11 +---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 73f9c6af4065..153238fc4fa9 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -154,7 +154,11 @@ smb2_get_credits(struct mid_q_entry *mid) { struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)mid->resp_buf; - return le16_to_cpu(shdr->CreditRequest); + if (mid->mid_state == MID_RESPONSE_RECEIVED + || mid->mid_state == MID_RESPONSE_MALFORMED) + return le16_to_cpu(shdr->CreditRequest); + + return 0; } static int diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 202e0e84efdd..53532bd3f50d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -786,17 +786,8 @@ static void cifs_compound_callback(struct mid_q_entry *mid) { struct TCP_Server_Info *server = mid->server; - unsigned int optype = mid->optype; - unsigned int credits_received = 0; - if (mid->mid_state == MID_RESPONSE_RECEIVED) { - if (mid->resp_buf) - credits_received = server->ops->get_credits(mid); - else - cifs_dbg(FYI, "Bad state for cancelled MID\n"); - } - - add_credits(server, credits_received, optype); + add_credits(server, server->ops->get_credits(mid), mid->optype); } static void -- cgit v1.2.3-58-ga151 From 0fd1d37b0501efc6e295f56ab55cdaff784aa50c Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 15 Jan 2019 15:08:48 -0800 Subject: CIFS: Do not assume one credit for async responses If we don't receive a response we can't assume that the server granted one credit. Assume zero credits in such cases. Signed-off-by: Pavel Shilovsky Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/smb2pdu.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 0af87bd0dc49..2ff209ec4fab 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2924,9 +2924,10 @@ smb2_echo_callback(struct mid_q_entry *mid) { struct TCP_Server_Info *server = mid->callback_data; struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf; - unsigned int credits_received = 1; + unsigned int credits_received = 0; - if (mid->mid_state == MID_RESPONSE_RECEIVED) + if (mid->mid_state == MID_RESPONSE_RECEIVED + || mid->mid_state == MID_RESPONSE_MALFORMED) credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); DeleteMidQEntry(mid); @@ -3183,7 +3184,7 @@ smb2_readv_callback(struct mid_q_entry *mid) struct TCP_Server_Info *server = tcon->ses->server; struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)rdata->iov[0].iov_base; - unsigned int credits_received = 1; + unsigned int credits_received = 0; struct smb_rqst rqst = { .rq_iov = rdata->iov, .rq_nvec = 2, .rq_pages = rdata->pages, @@ -3222,6 +3223,9 @@ smb2_readv_callback(struct mid_q_entry *mid) task_io_account_read(rdata->got_bytes); cifs_stats_bytes_read(tcon, rdata->got_bytes); break; + case MID_RESPONSE_MALFORMED: + credits_received = le16_to_cpu(shdr->CreditRequest); + /* fall through */ default: if (rdata->result != -ENODATA) rdata->result = -EIO; @@ -3407,7 +3411,7 @@ smb2_writev_callback(struct mid_q_entry *mid) struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); unsigned int written; struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; - unsigned int credits_received = 1; + unsigned int credits_received = 0; switch (mid->mid_state) { case MID_RESPONSE_RECEIVED: @@ -3435,6 +3439,9 @@ smb2_writev_callback(struct mid_q_entry *mid) case MID_RETRY_NEEDED: wdata->result = -EAGAIN; break; + case MID_RESPONSE_MALFORMED: + credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); + /* fall through */ default: wdata->result = -EIO; break; -- cgit v1.2.3-58-ga151 From 6a9cbdd1ceca1dc2359ddf082efe61b97c3e752b Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Wed, 16 Jan 2019 11:48:42 -0800 Subject: CIFS: Fix mounts if the client is low on credits If the server doesn't grant us at least 3 credits during the mount we won't be able to complete it because query path info operation requires 3 credits. Use the cached file handle if possible to allow the mount to succeed. Signed-off-by: Pavel Shilovsky Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/smb2inode.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index f14533da3a93..01a76bccdb8d 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -293,6 +293,8 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, int rc; struct smb2_file_all_info *smb2_data; __u32 create_options = 0; + struct cifs_fid fid; + bool no_cached_open = tcon->nohandlecache; *adjust_tz = false; *symlink = false; @@ -301,6 +303,21 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, GFP_KERNEL); if (smb2_data == NULL) return -ENOMEM; + + /* If it is a root and its handle is cached then use it */ + if (!strlen(full_path) && !no_cached_open) { + rc = open_shroot(xid, tcon, &fid); + if (rc) + goto out; + rc = SMB2_query_info(xid, tcon, fid.persistent_fid, + fid.volatile_fid, smb2_data); + close_shroot(&tcon->crfid); + if (rc) + goto out; + move_smb2_info_to_cifs(data, smb2_data); + goto out; + } + if (backup_cred(cifs_sb)) create_options |= CREATE_OPEN_BACKUP_INTENT; -- cgit v1.2.3-58-ga151 From 2e5700bdde438ed708b36d8acd0398dc73cbf759 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 23 Jan 2019 16:20:38 +1000 Subject: smb3: add credits we receive from oplock/break PDUs Otherwise we gradually leak credits leading to potential hung session. Signed-off-by: Ronnie Sahlberg CC: Stable Reviewed-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/smb2misc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 6a9c47541c53..7b8b58fb4d3f 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -648,6 +648,13 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) if (rsp->sync_hdr.Command != SMB2_OPLOCK_BREAK) return false; + if (rsp->sync_hdr.CreditRequest) { + spin_lock(&server->req_lock); + server->credits += le16_to_cpu(rsp->sync_hdr.CreditRequest); + spin_unlock(&server->req_lock); + wake_up(&server->request_q); + } + if (rsp->StructureSize != smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { if (le16_to_cpu(rsp->StructureSize) == 44) -- cgit v1.2.3-58-ga151 From a5f1a81f701c594194eb70c679785882ab15f138 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Thu, 24 Jan 2019 16:19:31 +1000 Subject: cifs: print CIFSMaxBufSize as part of /proc/fs/cifs/DebugData Was helpful in debug for some recent problems. Signed-off-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 593fb422d0f3..e92a2fee3c57 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -252,6 +252,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) seq_printf(m, ",ACL"); #endif seq_putc(m, '\n'); + seq_printf(m, "CIFSMaxBufSize: %d\n", CIFSMaxBufSize); seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); seq_printf(m, "Servers:"); -- cgit v1.2.3-58-ga151 From d71b57532d70c03f4671dd04e84157ac6bf021b0 Mon Sep 17 00:00:00 2001 From: wenxu Date: Sat, 19 Jan 2019 13:11:25 +0800 Subject: ip_tunnel: Make none-tunnel-dst tunnel port work with lwtunnel ip l add dev tun type gretap key 1000 ip a a dev tun 10.0.0.1/24 Packets with tun-id 1000 can be recived by tun dev. But packet can't be sent through dev tun for non-tunnel-dst With this patch: tunnel-dst can be get through lwtunnel like beflow: ip r a 10.0.0.7 encap ip dst 172.168.0.11 dev tun Signed-off-by: wenxu Signed-off-by: David S. Miller --- net/ipv4/ip_tunnel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index c4f5602308ed..054d01c16dc6 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -644,13 +644,19 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, dst = tnl_params->daddr; if (dst == 0) { /* NBMA tunnel */ + struct ip_tunnel_info *tun_info; if (!skb_dst(skb)) { dev->stats.tx_fifo_errors++; goto tx_error; } - if (skb->protocol == htons(ETH_P_IP)) { + tun_info = skb_tunnel_info(skb); + if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX) && + ip_tunnel_info_af(tun_info) == AF_INET && + tun_info->key.u.ipv4.dst) + dst = tun_info->key.u.ipv4.dst; + else if (skb->protocol == htons(ETH_P_IP)) { rt = skb_rtable(skb); dst = rt_nexthop(rt, inner_iph->daddr); } -- cgit v1.2.3-58-ga151 From 2e6dc4d95110becfe0ff4c3d4749c33ea166e9e7 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 22 Jan 2019 02:39:34 +0800 Subject: sctp: improve the events for sctp stream reset This patch is to improve sctp stream reset events in 4 places: 1. In sctp_process_strreset_outreq(), the flag should always be set with SCTP_STREAM_RESET_INCOMING_SSN instead of OUTGOING, as receiver's in stream is reset here. 2. In sctp_process_strreset_outreq(), move up SCTP_STRRESET_ERR_WRONG_SSN check, as the reset has to succeed after reconf_timer stops for the in stream reset request retransmission. 3. In sctp_process_strreset_inreq(), no event should be sent, as no in or out stream is reset here. 4. In sctp_process_strreset_resp(), SCTP_STREAM_RESET_INCOMING_SSN or OUTGOING event should always be sent for stream reset requests, no matter it fails or succeeds to process the request. Fixes: 810544764536 ("sctp: implement receiver-side procedures for the Outgoing SSN Reset Request Parameter") Fixes: 16e1a91965b0 ("sctp: implement receiver-side procedures for the Incoming SSN Reset Request Parameter") Fixes: 11ae76e67a17 ("sctp: implement receiver-side procedures for the Reconf Response Parameter") Reported-by: Ying Xu Signed-off-by: Xin Long Signed-off-by: David S. Miller --- net/sctp/stream.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 3892e7630f3a..6c188b06e5e1 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c @@ -585,9 +585,9 @@ struct sctp_chunk *sctp_process_strreset_outreq( struct sctp_strreset_outreq *outreq = param.v; struct sctp_stream *stream = &asoc->stream; __u32 result = SCTP_STRRESET_DENIED; - __u16 i, nums, flags = 0; __be16 *str_p = NULL; __u32 request_seq; + __u16 i, nums; request_seq = ntohl(outreq->request_seq); @@ -615,6 +615,15 @@ struct sctp_chunk *sctp_process_strreset_outreq( if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) goto out; + nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16); + str_p = outreq->list_of_streams; + for (i = 0; i < nums; i++) { + if (ntohs(str_p[i]) >= stream->incnt) { + result = SCTP_STRRESET_ERR_WRONG_SSN; + goto out; + } + } + if (asoc->strreset_chunk) { if (!sctp_chunk_lookup_strreset_param( asoc, outreq->response_seq, @@ -637,32 +646,19 @@ struct sctp_chunk *sctp_process_strreset_outreq( sctp_chunk_put(asoc->strreset_chunk); asoc->strreset_chunk = NULL; } - - flags = SCTP_STREAM_RESET_INCOMING_SSN; } - nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16); - if (nums) { - str_p = outreq->list_of_streams; - for (i = 0; i < nums; i++) { - if (ntohs(str_p[i]) >= stream->incnt) { - result = SCTP_STRRESET_ERR_WRONG_SSN; - goto out; - } - } - + if (nums) for (i = 0; i < nums; i++) SCTP_SI(stream, ntohs(str_p[i]))->mid = 0; - } else { + else for (i = 0; i < stream->incnt; i++) SCTP_SI(stream, i)->mid = 0; - } result = SCTP_STRRESET_PERFORMED; *evp = sctp_ulpevent_make_stream_reset_event(asoc, - flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p, - GFP_ATOMIC); + SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC); out: sctp_update_strreset_result(asoc, result); @@ -738,9 +734,6 @@ struct sctp_chunk *sctp_process_strreset_inreq( result = SCTP_STRRESET_PERFORMED; - *evp = sctp_ulpevent_make_stream_reset_event(asoc, - SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC); - out: sctp_update_strreset_result(asoc, result); err: @@ -1036,10 +1029,10 @@ struct sctp_chunk *sctp_process_strreset_resp( sout->mid_uo = 0; } } - - flags = SCTP_STREAM_RESET_OUTGOING_SSN; } + flags |= SCTP_STREAM_RESET_OUTGOING_SSN; + for (i = 0; i < stream->outcnt; i++) SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN; @@ -1058,6 +1051,8 @@ struct sctp_chunk *sctp_process_strreset_resp( nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / sizeof(__u16); + flags |= SCTP_STREAM_RESET_INCOMING_SSN; + *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags, nums, str_p, GFP_ATOMIC); } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) { -- cgit v1.2.3-58-ga151 From 8220c870cb0f4eaa4e335c9645dbd9a1c461c1dd Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 22 Jan 2019 02:40:12 +0800 Subject: sctp: improve the events for sctp stream adding This patch is to improve sctp stream adding events in 2 places: 1. In sctp_process_strreset_addstrm_out(), move up SCTP_MAX_STREAM and in stream allocation failure checks, as the adding has to succeed after reconf_timer stops for the in stream adding request retransmission. 3. In sctp_process_strreset_addstrm_in(), no event should be sent, as no in or out stream is added here. Fixes: 50a41591f110 ("sctp: implement receiver-side procedures for the Add Outgoing Streams Request Parameter") Fixes: c5c4ebb3ab87 ("sctp: implement receiver-side procedures for the Add Incoming Streams Request Parameter") Reported-by: Ying Xu Signed-off-by: Xin Long Signed-off-by: David S. Miller --- net/sctp/stream.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 6c188b06e5e1..80e0ae5534ec 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c @@ -866,6 +866,14 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out( if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) goto out; + in = ntohs(addstrm->number_of_streams); + incnt = stream->incnt + in; + if (!in || incnt > SCTP_MAX_STREAM) + goto out; + + if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC)) + goto out; + if (asoc->strreset_chunk) { if (!sctp_chunk_lookup_strreset_param( asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) { @@ -889,14 +897,6 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out( } } - in = ntohs(addstrm->number_of_streams); - incnt = stream->incnt + in; - if (!in || incnt > SCTP_MAX_STREAM) - goto out; - - if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC)) - goto out; - stream->incnt = incnt; result = SCTP_STRRESET_PERFORMED; @@ -966,9 +966,6 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in( result = SCTP_STRRESET_PERFORMED; - *evp = sctp_ulpevent_make_stream_change_event(asoc, - 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC); - out: sctp_update_strreset_result(asoc, result); err: -- cgit v1.2.3-58-ga151 From 4ff40b86262b73553ee47cc3784ce8ba0f220bd8 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 22 Jan 2019 02:42:09 +0800 Subject: sctp: set chunk transport correctly when it's a new asoc In the paths: sctp_sf_do_unexpected_init() -> sctp_make_init_ack() sctp_sf_do_dupcook_a/b()() -> sctp_sf_do_5_1D_ce() The new chunk 'retval' transport is set from the incoming chunk 'chunk' transport. However, 'retval' transport belong to the new asoc, which is a different one from 'chunk' transport's asoc. It will cause that the 'retval' chunk gets set with a wrong transport. Later when sending it and because of Commit b9fd683982c9 ("sctp: add sctp_packet_singleton"), sctp_packet_singleton() will set some fields, like vtag to 'retval' chunk from that wrong transport's asoc. This patch is to fix it by setting 'retval' transport correctly which belongs to the right asoc in sctp_make_init_ack() and sctp_sf_do_5_1D_ce(). Fixes: b9fd683982c9 ("sctp: add sctp_packet_singleton") Reported-by: Ying Xu Signed-off-by: Xin Long Signed-off-by: David S. Miller --- net/sctp/sm_make_chunk.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index f4ac6c592e13..d05c57664e36 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -495,7 +495,10 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, * * [INIT ACK back to where the INIT came from.] */ - retval->transport = chunk->transport; + if (chunk->transport) + retval->transport = + sctp_assoc_lookup_paddr(asoc, + &chunk->transport->ipaddr); retval->subh.init_hdr = sctp_addto_chunk(retval, sizeof(initack), &initack); @@ -642,8 +645,10 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc, * * [COOKIE ACK back to where the COOKIE ECHO came from.] */ - if (retval && chunk) - retval->transport = chunk->transport; + if (retval && chunk && chunk->transport) + retval->transport = + sctp_assoc_lookup_paddr(asoc, + &chunk->transport->ipaddr); return retval; } -- cgit v1.2.3-58-ga151 From ecf938fe7d0088077ee1280419a2b3c5429b47c8 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 22 Jan 2019 02:42:41 +0800 Subject: sctp: set flow sport from saddr only when it's 0 Now sctp_transport_pmtu() passes transport->saddr into .get_dst() to set flow sport from 'saddr'. However, transport->saddr is set only when transport->dst exists in sctp_transport_route(). If sctp_transport_pmtu() is called without transport->saddr set, like when transport->dst doesn't exists, the flow sport will be set to 0 from transport->saddr, which will cause a wrong route to be got. Commit 6e91b578bf3f ("sctp: re-use sctp_transport_pmtu in sctp_transport_route") made the issue be triggered more easily since sctp_transport_pmtu() would be called in sctp_transport_route() after that. In gerneral, fl4->fl4_sport should always be set to htons(asoc->base.bind_addr.port), unless transport->asoc doesn't exist in sctp_v4/6_get_dst(), which is the case: sctp_ootb_pkt_new() -> sctp_transport_route() For that, we can simply handle it by setting flow sport from saddr only when it's 0 in sctp_v4/6_get_dst(). Fixes: 6e91b578bf3f ("sctp: re-use sctp_transport_pmtu in sctp_transport_route") Reported-by: Ying Xu Signed-off-by: Xin Long Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 3 ++- net/sctp/protocol.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index ed8e006dae85..6200cd2b4b99 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -280,7 +280,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, if (saddr) { fl6->saddr = saddr->v6.sin6_addr; - fl6->fl6_sport = saddr->v6.sin6_port; + if (!fl6->fl6_sport) + fl6->fl6_sport = saddr->v6.sin6_port; pr_debug("src=%pI6 - ", &fl6->saddr); } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 4e0eeb113ef5..6abc8b274270 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -440,7 +440,8 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, } if (saddr) { fl4->saddr = saddr->v4.sin_addr.s_addr; - fl4->fl4_sport = saddr->v4.sin_port; + if (!fl4->fl4_sport) + fl4->fl4_sport = saddr->v4.sin_port; } pr_debug("%s: dst:%pI4, src:%pI4 - ", __func__, &fl4->daddr, -- cgit v1.2.3-58-ga151 From a40ded6043658444ee4dd6ee374119e4e98b33fc Mon Sep 17 00:00:00 2001 From: Aya Levin Date: Tue, 22 Jan 2019 15:19:44 +0200 Subject: net/mlx4_core: Add masking for a few queries on HCA caps Driver reads the query HCA capabilities without the corresponding masks. Without the correct masks, the base addresses of the queues are unaligned. In addition some reserved bits were wrongly read. Using the correct masks, ensures alignment of the base addresses and allows future firmware versions safe use of the reserved bits. Fixes: ab9c17a009ee ("mlx4_core: Modify driver initialization flow to accommodate SRIOV for Ethernet") Fixes: 0ff1fb654bec ("{NET, IB}/mlx4: Add device managed flow steering firmware API") Signed-off-by: Aya Levin Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 75 ++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 7df728f1e5b5..6e501af0e532 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -2067,9 +2067,11 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev, { struct mlx4_cmd_mailbox *mailbox; __be32 *outbox; + u64 qword_field; u32 dword_field; - int err; + u16 word_field; u8 byte_field; + int err; static const u8 a0_dmfs_query_hw_steering[] = { [0] = MLX4_STEERING_DMFS_A0_DEFAULT, [1] = MLX4_STEERING_DMFS_A0_DYNAMIC, @@ -2097,19 +2099,32 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev, /* QPC/EEC/CQC/EQC/RDMARC attributes */ - MLX4_GET(param->qpc_base, outbox, INIT_HCA_QPC_BASE_OFFSET); - MLX4_GET(param->log_num_qps, outbox, INIT_HCA_LOG_QP_OFFSET); - MLX4_GET(param->srqc_base, outbox, INIT_HCA_SRQC_BASE_OFFSET); - MLX4_GET(param->log_num_srqs, outbox, INIT_HCA_LOG_SRQ_OFFSET); - MLX4_GET(param->cqc_base, outbox, INIT_HCA_CQC_BASE_OFFSET); - MLX4_GET(param->log_num_cqs, outbox, INIT_HCA_LOG_CQ_OFFSET); - MLX4_GET(param->altc_base, outbox, INIT_HCA_ALTC_BASE_OFFSET); - MLX4_GET(param->auxc_base, outbox, INIT_HCA_AUXC_BASE_OFFSET); - MLX4_GET(param->eqc_base, outbox, INIT_HCA_EQC_BASE_OFFSET); - MLX4_GET(param->log_num_eqs, outbox, INIT_HCA_LOG_EQ_OFFSET); - MLX4_GET(param->num_sys_eqs, outbox, INIT_HCA_NUM_SYS_EQS_OFFSET); - MLX4_GET(param->rdmarc_base, outbox, INIT_HCA_RDMARC_BASE_OFFSET); - MLX4_GET(param->log_rd_per_qp, outbox, INIT_HCA_LOG_RD_OFFSET); + MLX4_GET(qword_field, outbox, INIT_HCA_QPC_BASE_OFFSET); + param->qpc_base = qword_field & ~((u64)0x1f); + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_QP_OFFSET); + param->log_num_qps = byte_field & 0x1f; + MLX4_GET(qword_field, outbox, INIT_HCA_SRQC_BASE_OFFSET); + param->srqc_base = qword_field & ~((u64)0x1f); + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_SRQ_OFFSET); + param->log_num_srqs = byte_field & 0x1f; + MLX4_GET(qword_field, outbox, INIT_HCA_CQC_BASE_OFFSET); + param->cqc_base = qword_field & ~((u64)0x1f); + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_CQ_OFFSET); + param->log_num_cqs = byte_field & 0x1f; + MLX4_GET(qword_field, outbox, INIT_HCA_ALTC_BASE_OFFSET); + param->altc_base = qword_field; + MLX4_GET(qword_field, outbox, INIT_HCA_AUXC_BASE_OFFSET); + param->auxc_base = qword_field; + MLX4_GET(qword_field, outbox, INIT_HCA_EQC_BASE_OFFSET); + param->eqc_base = qword_field & ~((u64)0x1f); + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_EQ_OFFSET); + param->log_num_eqs = byte_field & 0x1f; + MLX4_GET(word_field, outbox, INIT_HCA_NUM_SYS_EQS_OFFSET); + param->num_sys_eqs = word_field & 0xfff; + MLX4_GET(qword_field, outbox, INIT_HCA_RDMARC_BASE_OFFSET); + param->rdmarc_base = qword_field & ~((u64)0x1f); + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_RD_OFFSET); + param->log_rd_per_qp = byte_field & 0x7; MLX4_GET(dword_field, outbox, INIT_HCA_FLAGS_OFFSET); if (dword_field & (1 << INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN)) { @@ -2128,22 +2143,21 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev, /* steering attributes */ if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET); - MLX4_GET(param->log_mc_entry_sz, outbox, - INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET); - MLX4_GET(param->log_mc_table_sz, outbox, - INIT_HCA_FS_LOG_TABLE_SZ_OFFSET); - MLX4_GET(byte_field, outbox, - INIT_HCA_FS_A0_OFFSET); + MLX4_GET(byte_field, outbox, INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET); + param->log_mc_entry_sz = byte_field & 0x1f; + MLX4_GET(byte_field, outbox, INIT_HCA_FS_LOG_TABLE_SZ_OFFSET); + param->log_mc_table_sz = byte_field & 0x1f; + MLX4_GET(byte_field, outbox, INIT_HCA_FS_A0_OFFSET); param->dmfs_high_steer_mode = a0_dmfs_query_hw_steering[(byte_field >> 6) & 3]; } else { MLX4_GET(param->mc_base, outbox, INIT_HCA_MC_BASE_OFFSET); - MLX4_GET(param->log_mc_entry_sz, outbox, - INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); - MLX4_GET(param->log_mc_hash_sz, outbox, - INIT_HCA_LOG_MC_HASH_SZ_OFFSET); - MLX4_GET(param->log_mc_table_sz, outbox, - INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); + param->log_mc_entry_sz = byte_field & 0x1f; + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MC_HASH_SZ_OFFSET); + param->log_mc_hash_sz = byte_field & 0x1f; + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); + param->log_mc_table_sz = byte_field & 0x1f; } /* CX3 is capable of extending CQEs/EQEs from 32 to 64 bytes */ @@ -2167,15 +2181,18 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev, /* TPT attributes */ MLX4_GET(param->dmpt_base, outbox, INIT_HCA_DMPT_BASE_OFFSET); - MLX4_GET(param->mw_enabled, outbox, INIT_HCA_TPT_MW_OFFSET); - MLX4_GET(param->log_mpt_sz, outbox, INIT_HCA_LOG_MPT_SZ_OFFSET); + MLX4_GET(byte_field, outbox, INIT_HCA_TPT_MW_OFFSET); + param->mw_enabled = byte_field >> 7; + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_MPT_SZ_OFFSET); + param->log_mpt_sz = byte_field & 0x3f; MLX4_GET(param->mtt_base, outbox, INIT_HCA_MTT_BASE_OFFSET); MLX4_GET(param->cmpt_base, outbox, INIT_HCA_CMPT_BASE_OFFSET); /* UAR attributes */ MLX4_GET(param->uar_page_sz, outbox, INIT_HCA_UAR_PAGE_SZ_OFFSET); - MLX4_GET(param->log_uar_sz, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET); + MLX4_GET(byte_field, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET); + param->log_uar_sz = byte_field & 0xf; /* phv_check enable */ MLX4_GET(byte_field, outbox, INIT_HCA_CACHELINE_SZ_OFFSET); -- cgit v1.2.3-58-ga151 From ffe4cfc3da5e61555aca189e2432ee637fd12eec Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 22 Jan 2019 15:19:45 +0200 Subject: net/mlx4_core: Fix error handling when initializing CQ bufs in the driver Procedure mlx4_init_user_cqes() handles returns by copy_to_user incorrectly. copy_to_user() returns the number of bytes not copied. Thus, a non-zero return should be treated as a -EFAULT error (as is done elsewhere in the kernel). However, mlx4_init_user_cqes() error handling simply returns the number of bytes not copied (instead of -EFAULT). Note, though, that this is a harmless bug: procedure mlx4_alloc_cq() (which is the only caller of mlx4_init_user_cqes()) treats any non-zero return as an error, but that returned error value is processed internally, and not passed further up the call stack. In addition, fixes the following sparse warning: warning: incorrect type in argument 1 (different address spaces) expected void [noderef] *to got void *buf Fixes: e45678973dcb ("{net, IB}/mlx4: Initialize CQ buffers in the driver when possible") Reported by: Dan Carpenter Signed-off-by: Jack Morgenstein Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index db909b6069b5..65f8a4b6ed0c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c @@ -306,14 +306,16 @@ static int mlx4_init_user_cqes(void *buf, int entries, int cqe_size) if (entries_per_copy < entries) { for (i = 0; i < entries / entries_per_copy; i++) { - err = copy_to_user(buf, init_ents, PAGE_SIZE); + err = copy_to_user((void __user *)buf, init_ents, PAGE_SIZE) ? + -EFAULT : 0; if (err) goto out; buf += PAGE_SIZE; } } else { - err = copy_to_user(buf, init_ents, entries * cqe_size); + err = copy_to_user((void __user *)buf, init_ents, entries * cqe_size) ? + -EFAULT : 0; } out: -- cgit v1.2.3-58-ga151 From d524e6416aeb2854bbeef2bb596803914fe286c0 Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Wed, 23 Jan 2019 18:03:20 -0800 Subject: MAINTAINERS: Update cavium networking drivers Following Marvell's acquisition of Cavium, we need to update all the Cavium drivers maintainer's entries to point to our new e-mail addresses. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Ameen Rahman Signed-off-by: David S. Miller --- MAINTAINERS | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 51029a425dbe..95be8f0779a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3052,8 +3052,8 @@ F: include/linux/bcm963xx_nvram.h F: include/linux/bcm963xx_tag.h BROADCOM BNX2 GIGABIT ETHERNET DRIVER -M: Rasesh Mody -M: Dept-GELinuxNICDev@cavium.com +M: Rasesh Mody +M: GR-Linux-NIC-Dev@marvell.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/broadcom/bnx2.* @@ -3072,9 +3072,9 @@ S: Supported F: drivers/scsi/bnx2i/ BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER -M: Ariel Elior -M: Sudarsana Kalluru -M: everest-linux-l2@cavium.com +M: Ariel Elior +M: Sudarsana Kalluru +M: GR-everest-linux-l2@marvell.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/broadcom/bnx2x/ @@ -3249,9 +3249,9 @@ S: Supported F: drivers/scsi/bfa/ BROCADE BNA 10 GIGABIT ETHERNET DRIVER -M: Rasesh Mody -M: Sudarsana Kalluru -M: Dept-GELinuxNICDev@cavium.com +M: Rasesh Mody +M: Sudarsana Kalluru +M: GR-Linux-NIC-Dev@marvell.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/brocade/bna/ @@ -10688,9 +10688,9 @@ S: Maintained F: drivers/net/netdevsim/* NETXEN (1/10) GbE SUPPORT -M: Manish Chopra -M: Rahul Verma -M: Dept-GELinuxNICDev@cavium.com +M: Manish Chopra +M: Rahul Verma +M: GR-Linux-NIC-Dev@marvell.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/qlogic/netxen/ @@ -12474,8 +12474,8 @@ S: Supported F: drivers/scsi/qedi/ QLOGIC QL4xxx ETHERNET DRIVER -M: Ariel Elior -M: everest-linux-l2@cavium.com +M: Ariel Elior +M: GR-everest-linux-l2@marvell.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/qlogic/qed/ @@ -12483,8 +12483,8 @@ F: include/linux/qed/ F: drivers/net/ethernet/qlogic/qede/ QLOGIC QL4xxx RDMA DRIVER -M: Michal Kalderon -M: Ariel Elior +M: Michal Kalderon +M: Ariel Elior L: linux-rdma@vger.kernel.org S: Supported F: drivers/infiniband/hw/qedr/ @@ -12504,7 +12504,7 @@ F: Documentation/scsi/LICENSE.qla2xxx F: drivers/scsi/qla2xxx/ QLOGIC QLA3XXX NETWORK DRIVER -M: Dept-GELinuxNICDev@cavium.com +M: GR-Linux-NIC-Dev@marvell.com L: netdev@vger.kernel.org S: Supported F: Documentation/networking/device_drivers/qlogic/LICENSE.qla3xxx @@ -12518,16 +12518,16 @@ F: Documentation/scsi/LICENSE.qla4xxx F: drivers/scsi/qla4xxx/ QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER -M: Shahed Shaikh -M: Manish Chopra -M: Dept-GELinuxNICDev@cavium.com +M: Shahed Shaikh +M: Manish Chopra +M: GR-Linux-NIC-Dev@marvell.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/qlogic/qlcnic/ QLOGIC QLGE 10Gb ETHERNET DRIVER -M: Manish Chopra -M: Dept-GELinuxNICDev@cavium.com +M: Manish Chopra +M: GR-Linux-NIC-Dev@marvell.com L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/qlogic/qlge/ -- cgit v1.2.3-58-ga151 From 6eea3527e68acc22483f4763c8682f223eb90029 Mon Sep 17 00:00:00 2001 From: Zhang Run Date: Thu, 24 Jan 2019 13:48:49 +0800 Subject: net: usb: asix: ax88772_bind return error when hw_reset fail The ax88772_bind() should return error code immediately when the PHY was not reset properly through ax88772a_hw_reset(). Otherwise, The asix_get_phyid() will block when get the PHY Identifier from the PHYSID1 MII registers through asix_mdio_read() due to the PHY isn't ready. Furthermore, it will produce a lot of error message cause system crash.As follows: asix 1-1:1.0 (unnamed net_device) (uninitialized): Failed to write reg index 0x0000: -71 asix 1-1:1.0 (unnamed net_device) (uninitialized): Failed to send software reset: ffffffb9 asix 1-1:1.0 (unnamed net_device) (uninitialized): Failed to write reg index 0x0000: -71 asix 1-1:1.0 (unnamed net_device) (uninitialized): Failed to enable software MII access asix 1-1:1.0 (unnamed net_device) (uninitialized): Failed to read reg index 0x0000: -71 asix 1-1:1.0 (unnamed net_device) (uninitialized): Failed to write reg index 0x0000: -71 asix 1-1:1.0 (unnamed net_device) (uninitialized): Failed to enable software MII access asix 1-1:1.0 (unnamed net_device) (uninitialized): Failed to read reg index 0x0000: -71 ... Signed-off-by: Zhang Run Reviewed-by: Yang Wei Tested-by: Marcel Ziswiler Signed-off-by: David S. Miller --- drivers/net/usb/asix_devices.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index b654f05b2ccd..3d93993e74da 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -739,8 +739,13 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &chipcode, 0); chipcode &= AX_CHIPCODE_MASK; - (chipcode == AX_AX88772_CHIPCODE) ? ax88772_hw_reset(dev, 0) : - ax88772a_hw_reset(dev, 0); + ret = (chipcode == AX_AX88772_CHIPCODE) ? ax88772_hw_reset(dev, 0) : + ax88772a_hw_reset(dev, 0); + + if (ret < 0) { + netdev_dbg(dev->net, "Failed to reset AX88772: %d\n", ret); + return ret; + } /* Read PHYID register *AFTER* the PHY was reset properly */ phyid = asix_get_phyid(dev); -- cgit v1.2.3-58-ga151 From 3b707c3008cad04604c1f50e39f456621821c414 Mon Sep 17 00:00:00 2001 From: Maciej Żenczykowski Date: Thu, 24 Jan 2019 03:07:02 -0800 Subject: net: dev_is_mac_header_xmit() true for ARPHRD_RAWIP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __bpf_redirect() and act_mirred checks this boolean to determine whether to prefix an ethernet header. Signed-off-by: Maciej Żenczykowski Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/if_arp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 6756fea18b69..e44746de95cd 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -54,6 +54,7 @@ static inline bool dev_is_mac_header_xmit(const struct net_device *dev) case ARPHRD_IPGRE: case ARPHRD_VOID: case ARPHRD_NONE: + case ARPHRD_RAWIP: return false; default: return true; -- cgit v1.2.3-58-ga151 From e95d22c69b2c130ccce257b84daf283fd82d611e Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Thu, 24 Jan 2019 11:17:01 -0600 Subject: ibmveth: Do not process frames after calling napi_reschedule The IBM virtual ethernet driver's polling function continues to process frames after rescheduling NAPI, resulting in a warning if it exhausted its budget. Do not restart polling after calling napi_reschedule. Instead let frames be processed in the following instance. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmveth.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 098d8764c0ea..dd71d5db7274 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1313,7 +1313,6 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) unsigned long lpar_rc; u16 mss = 0; -restart_poll: while (frames_processed < budget) { if (!ibmveth_rxq_pending_buffer(adapter)) break; @@ -1401,7 +1400,6 @@ restart_poll: napi_reschedule(napi)) { lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); - goto restart_poll; } } -- cgit v1.2.3-58-ga151 From a8b5c6d69261889e022e9d64ac7ee8741db730bf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 25 Jan 2019 09:26:32 +0100 Subject: nl80211: fix NLA_POLICY_NESTED() arguments syzbot reported an out-of-bounds read when passing certain malformed messages into nl80211. The specific place where this happened isn't interesting, the problem is that nested policy parsing was referring to the wrong maximum attribute and thus the policy wasn't long enough. Fix this by referring to the correct attribute. Since this is really not necessary, I'll come up with a separate patch to just pass the policy instead of both, in the common case we can infer the maxattr from the size of the policy array. Reported-by: syzbot+4157b036c5f4713b1f2f@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Fixes: 9bb7e0f24e7e ("cfg80211: add peer measurement with FTM initiator API") Signed-off-by: Johannes Berg --- net/wireless/nl80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5e49492d5911..74150ad95823 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -555,7 +555,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { }, [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1), [NL80211_ATTR_PEER_MEASUREMENTS] = - NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX, + NLA_POLICY_NESTED(NL80211_PMSR_ATTR_MAX, nl80211_pmsr_attr_policy), }; -- cgit v1.2.3-58-ga151 From 7ed5285396c257fd4070b1e29e7b2341aae2a1ce Mon Sep 17 00:00:00 2001 From: Balaji Pothunoori Date: Mon, 21 Jan 2019 12:30:43 +0530 Subject: mac80211: don't initiate TDLS connection if station is not associated to AP Following call trace is observed while adding TDLS peer entry in driver during TDLS setup. Call Trace: [] dump_stack+0x47/0x61 [] __warn+0xe2/0x100 [] ? sta_apply_parameters+0x49f/0x550 [mac80211] [] warn_slowpath_null+0x25/0x30 [] sta_apply_parameters+0x49f/0x550 [mac80211] [] ? sta_info_alloc+0x1c2/0x450 [mac80211] [] ieee80211_add_station+0xe3/0x160 [mac80211] [] nl80211_new_station+0x273/0x420 [] genl_rcv_msg+0x219/0x3c0 [] ? genl_rcv+0x30/0x30 [] netlink_rcv_skb+0x8e/0xb0 [] genl_rcv+0x1c/0x30 [] netlink_unicast+0x13a/0x1d0 [] netlink_sendmsg+0x2d8/0x390 [] sock_sendmsg+0x2d/0x40 [] ___sys_sendmsg+0x1d9/0x1e0 Fixing this by allowing TDLS setup request only when we have completed association. Signed-off-by: Balaji Pothunoori Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index de65fe3ed9cc..2493c74c2d37 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1490,6 +1490,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) sta->sta.tdls = true; + if (sta->sta.tdls && sdata->vif.type == NL80211_IFTYPE_STATION && + !sdata->u.mgd.associated) + return -EINVAL; + err = sta_apply_parameters(local, sta, params); if (err) { sta_info_free(local, sta); -- cgit v1.2.3-58-ga151 From 7c53eb5d87bc21464da4268c3c0c47457b6d9c9b Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Thu, 24 Jan 2019 19:19:57 +0100 Subject: mac80211: Add attribute aligned(2) to struct 'action' During refactor in commit 9e478066eae4 ("mac80211: fix MU-MIMO follow-MAC mode") a new struct 'action' was declared with packed attribute as: struct { struct ieee80211_hdr_3addr hdr; u8 category; u8 action_code; } __packed action; But since struct 'ieee80211_hdr_3addr' is declared with an aligned keyword as: struct ieee80211_hdr { __le16 frame_control; __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; __le16 seq_ctrl; u8 addr4[ETH_ALEN]; } __packed __aligned(2); Solve the ambiguity of placing aligned structure in a packed one by adding the aligned(2) attribute to struct 'action'. This removes the following warning (W=1): net/mac80211/rx.c:234:2: warning: alignment 1 of 'struct ' is less than 2 [-Wpacked-not-aligned] Cc: Johannes Berg Suggested-by: Johannes Berg Signed-off-by: Mathieu Malaterre Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 27a337bc8acf..bb4d71efb6fb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -231,7 +231,7 @@ static void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata, struct ieee80211_hdr_3addr hdr; u8 category; u8 action_code; - } __packed action; + } __packed __aligned(2) action; if (!sdata) return; -- cgit v1.2.3-58-ga151 From faae54ad4151f120bde60fd6e2b2a40e0de8ac73 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Thu, 24 Jan 2019 16:13:02 +0530 Subject: cfg80211: reg: remove warn_on for a normal case If there are simulatenous queries of regdb, then there might be a case where multiple queries can trigger request_firmware_no_wait and can have parallel callbacks being executed asynchronously. In this scenario we might hit the WARN_ON. So remove the warn_on, as the code already handles multiple callbacks gracefully. Signed-off-by: Chaitanya Tata Signed-off-by: Johannes Berg --- net/wireless/reg.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ecfb1a06dbb2..35399a825aed 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1024,8 +1024,13 @@ static void regdb_fw_cb(const struct firmware *fw, void *context) } rtnl_lock(); - if (WARN_ON(regdb && !IS_ERR(regdb))) { - /* just restore and free new db */ + if (regdb && !IS_ERR(regdb)) { + /* negative case - a bug + * positive case - can happen due to race in case of multiple cb's in + * queue, due to usage of asynchronous callback + * + * Either case, just restore and free new db. + */ } else if (set_error) { regdb = ERR_PTR(set_error); } else if (fw) { -- cgit v1.2.3-58-ga151 From 93183bdbe73bbdd03e9566c8dc37c9d06b0d0db6 Mon Sep 17 00:00:00 2001 From: Chaitanya Tata Date: Sat, 19 Jan 2019 03:17:47 +0530 Subject: cfg80211: extend range deviation for DMG Recently, DMG frequency bands have been extended till 71GHz, so extend the range check till 20GHz (45-71GHZ), else some channels will be marked as disabled. Signed-off-by: Chaitanya Tata Signed-off-by: Johannes Berg --- net/wireless/reg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 35399a825aed..dd58b9909ac9 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1260,7 +1260,7 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd) * definitions (the "2.4 GHz band", the "5 GHz band" and the "60GHz band"), * however it is safe for now to assume that a frequency rule should not be * part of a frequency's band if the start freq or end freq are off by more - * than 2 GHz for the 2.4 and 5 GHz bands, and by more than 10 GHz for the + * than 2 GHz for the 2.4 and 5 GHz bands, and by more than 20 GHz for the * 60 GHz band. * This resolution can be lowered and should be considered as we add * regulatory rule support for other "bands". @@ -1275,7 +1275,7 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, * with the Channel starting frequency above 45 GHz. */ u32 limit = freq_khz > 45 * ONE_GHZ_IN_KHZ ? - 10 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; + 20 * ONE_GHZ_IN_KHZ : 2 * ONE_GHZ_IN_KHZ; if (abs(freq_khz - freq_range->start_freq_khz) <= limit) return true; if (abs(freq_khz - freq_range->end_freq_khz) <= limit) -- cgit v1.2.3-58-ga151 From 9699f970de84292a766709029e5135ea0b6c9aa9 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 24 Jan 2019 15:27:09 +0100 Subject: x86/kvm/hyper-v: don't announce GUEST IDLE MSR support HV_X64_MSR_GUEST_IDLE_AVAILABLE appeared in kvm_vcpu_ioctl_get_hv_cpuid() by mistake: it announces support for HV_X64_MSR_GUEST_IDLE (0x400000F0) which we don't support in KVM (yet). Fixes: 2bc39970e932 ("x86/kvm/hyper-v: Introduce KVM_GET_SUPPORTED_HV_CPUID") Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index c90a5352d158..ac44a681f065 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1832,7 +1832,6 @@ int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, ent->eax |= HV_X64_MSR_VP_INDEX_AVAILABLE; ent->eax |= HV_X64_MSR_RESET_AVAILABLE; ent->eax |= HV_MSR_REFERENCE_TSC_AVAILABLE; - ent->eax |= HV_X64_MSR_GUEST_IDLE_AVAILABLE; ent->eax |= HV_X64_ACCESS_FREQUENCY_MSRS; ent->eax |= HV_X64_ACCESS_REENLIGHTENMENT; -- cgit v1.2.3-58-ga151 From 5cc244a20b86090c087073c124284381cdf47234 Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Mon, 21 Jan 2019 15:48:40 +0300 Subject: KVM: x86: Fix single-step debugging The single-step debugging of KVM guests on x86 is broken: if we run gdb 'stepi' command at the breakpoint when the guest interrupts are enabled, RIP always jumps to native_apic_mem_write(). Then other nasty effects follow. Long investigation showed that on Jun 7, 2017 the commit c8401dda2f0a00cd25c0 ("KVM: x86: fix singlestepping over syscall") introduced the kvm_run.debug corruption: kvm_vcpu_do_singlestep() can be called without X86_EFLAGS_TF set. Let's fix it. Please consider that for -stable. Signed-off-by: Alexander Popov Cc: stable@vger.kernel.org Fixes: c8401dda2f0a00cd25c0 ("KVM: x86: fix singlestepping over syscall") Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 02c8e095a239..f14bb806aeed 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6480,8 +6480,7 @@ restart: toggle_interruptibility(vcpu, ctxt->interruptibility); vcpu->arch.emulate_regs_need_sync_to_vcpu = false; kvm_rip_write(vcpu, ctxt->eip); - if (r == EMULATE_DONE && - (ctxt->tf || (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP))) + if (r == EMULATE_DONE && ctxt->tf) kvm_vcpu_do_singlestep(vcpu, &r); if (!ctxt->have_exception || exception_type(ctxt->exception.vector) == EXCPT_TRAP) -- cgit v1.2.3-58-ga151 From 85ba2b165d11029c0c57a58640d4cf41f9d9fa0d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 14 Jan 2019 12:12:02 -0800 Subject: KVM: VMX: Use the correct field var when clearing VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL Fix a recently introduced bug that results in the wrong VMCS control field being updated when applying a IA32_PERF_GLOBAL_CTRL errata. Fixes: c73da3fcab43 ("KVM: VMX: Properly handle dynamic VM Entry/Exit controls") Reported-by: Harald Arnesen Tested-by: Harald Arnesen Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index f6915f10e584..0762fcab8fc9 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2344,7 +2344,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, case 37: /* AAT100 */ case 44: /* BC86,AAY89,BD102 */ case 46: /* BA97 */ - _vmexit_control &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; + _vmentry_control &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; _vmexit_control &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL; pr_warn_once("kvm: VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL " "does not work properly. Using workaround\n"); -- cgit v1.2.3-58-ga151 From 3a33d030daaa7c507e1c12d5adcf828248429593 Mon Sep 17 00:00:00 2001 From: Tom Roeder Date: Thu, 24 Jan 2019 13:48:20 -0800 Subject: kvm: x86/vmx: Use kzalloc for cached_vmcs12 This changes the allocation of cached_vmcs12 to use kzalloc instead of kmalloc. This removes the information leak found by Syzkaller (see Reported-by) in this case and prevents similar leaks from happening based on cached_vmcs12. It also changes vmx_get_nested_state to copy out the full 4k VMCS12_SIZE in copy_to_user rather than only the size of the struct. Tested: rebuilt against head, booted, and ran the syszkaller repro https://syzkaller.appspot.com/text?tag=ReproC&x=174efca3400000 without observing any problems. Reported-by: syzbot+ded1696f6b50b615b630@syzkaller.appspotmail.com Fixes: 8fcc4b5923af5de58b80b53a069453b135693304 Cc: stable@vger.kernel.org Signed-off-by: Tom Roeder Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 2616bd2c7f2c..ce8153923854 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4140,11 +4140,11 @@ static int enter_vmx_operation(struct kvm_vcpu *vcpu) if (r < 0) goto out_vmcs02; - vmx->nested.cached_vmcs12 = kmalloc(VMCS12_SIZE, GFP_KERNEL); + vmx->nested.cached_vmcs12 = kzalloc(VMCS12_SIZE, GFP_KERNEL); if (!vmx->nested.cached_vmcs12) goto out_cached_vmcs12; - vmx->nested.cached_shadow_vmcs12 = kmalloc(VMCS12_SIZE, GFP_KERNEL); + vmx->nested.cached_shadow_vmcs12 = kzalloc(VMCS12_SIZE, GFP_KERNEL); if (!vmx->nested.cached_shadow_vmcs12) goto out_cached_shadow_vmcs12; @@ -5263,13 +5263,17 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, copy_shadow_to_vmcs12(vmx); } - if (copy_to_user(user_kvm_nested_state->data, vmcs12, sizeof(*vmcs12))) + /* + * Copy over the full allocated size of vmcs12 rather than just the size + * of the struct. + */ + if (copy_to_user(user_kvm_nested_state->data, vmcs12, VMCS12_SIZE)) return -EFAULT; if (nested_cpu_has_shadow_vmcs(vmcs12) && vmcs12->vmcs_link_pointer != -1ull) { if (copy_to_user(user_kvm_nested_state->data + VMCS12_SIZE, - get_shadow_vmcs12(vcpu), sizeof(*vmcs12))) + get_shadow_vmcs12(vcpu), VMCS12_SIZE)) return -EFAULT; } -- cgit v1.2.3-58-ga151 From 1998fd32aa62fbf22cd1d8258e6a9deffd6bc466 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 25 Jan 2019 12:19:33 +0100 Subject: x86/kvm/hyper-v: don't recommend doing reset via synthetic MSR System reset through synthetic MSR is not recommended neither by genuine Hyper-V nor my QEMU. Fixes: 2bc39970e932 ("x86/kvm/hyper-v: Introduce KVM_GET_SUPPORTED_HV_CPUID") Signed-off-by: Vitaly Kuznetsov Reviewed-by: Liran Alon Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index ac44a681f065..4840f5b3c88f 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1847,7 +1847,6 @@ int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, case HYPERV_CPUID_ENLIGHTMENT_INFO: ent->eax |= HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED; ent->eax |= HV_X64_APIC_ACCESS_RECOMMENDED; - ent->eax |= HV_X64_SYSTEM_RESET_RECOMMENDED; ent->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED; ent->eax |= HV_X64_CLUSTER_IPI_RECOMMENDED; ent->eax |= HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED; -- cgit v1.2.3-58-ga151 From d0b95e6cd298a785c126e75a085af6dd7b7b1f60 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 25 Jan 2019 16:04:06 +0000 Subject: ASoC: core: Allow soc_find_component lookups to match parent of_node For devices implemented as a MFD it is common to only have a single node in devicetree representing the whole device. As such when looking up components in soc_find_components we should match against both the devices of_node and the devices parent's of_node, as is already done in the rest of the ASoC core. This causes regressions for some DAI links at the moment as soc_find_component was recently added as a check in soc_init_dai_link. Fixes: 8780cf1142a5 ("ASoC: soc-core: defer card probe until all component is added to list") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index aae450ba4f08..ea16c2b199ce 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -735,12 +735,17 @@ static struct snd_soc_component *soc_find_component( const struct device_node *of_node, const char *name) { struct snd_soc_component *component; + struct device_node *component_of_node; lockdep_assert_held(&client_mutex); for_each_component(component) { if (of_node) { - if (component->dev->of_node == of_node) + component_of_node = component->dev->of_node; + if (!component_of_node && component->dev->parent) + component_of_node = component->dev->parent->of_node; + + if (component_of_node == of_node) return component; } else if (name && strcmp(component->name, name) == 0) { return component; -- cgit v1.2.3-58-ga151 From a94aec035a122bf6d1a05b14f02f34c34b99506a Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 22 Jan 2019 14:39:08 +0800 Subject: ASoC: mediatek: mt8183: add platform driver add mt8183 audio platform and affiliated drivers. Signed-off-by: Shunli Wang Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 10 + sound/soc/mediatek/Makefile | 1 + sound/soc/mediatek/mt8183/Makefile | 13 + sound/soc/mediatek/mt8183/mt8183-afe-clk.c | 611 +++++++ sound/soc/mediatek/mt8183/mt8183-afe-clk.h | 38 + sound/soc/mediatek/mt8183/mt8183-afe-common.h | 108 ++ sound/soc/mediatek/mt8183/mt8183-afe-pcm.c | 1237 +++++++++++++++ sound/soc/mediatek/mt8183/mt8183-dai-adda.c | 501 ++++++ sound/soc/mediatek/mt8183/mt8183-dai-hostless.c | 118 ++ sound/soc/mediatek/mt8183/mt8183-dai-i2s.c | 1040 ++++++++++++ sound/soc/mediatek/mt8183/mt8183-dai-pcm.c | 318 ++++ sound/soc/mediatek/mt8183/mt8183-dai-tdm.c | 639 ++++++++ sound/soc/mediatek/mt8183/mt8183-interconnection.h | 33 + sound/soc/mediatek/mt8183/mt8183-reg.h | 1666 ++++++++++++++++++++ 14 files changed, 6333 insertions(+) create mode 100644 sound/soc/mediatek/mt8183/Makefile create mode 100644 sound/soc/mediatek/mt8183/mt8183-afe-clk.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-afe-clk.h create mode 100644 sound/soc/mediatek/mt8183/mt8183-afe-common.h create mode 100644 sound/soc/mediatek/mt8183/mt8183-afe-pcm.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-adda.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-hostless.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-i2s.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-pcm.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-dai-tdm.c create mode 100644 sound/soc/mediatek/mt8183/mt8183-interconnection.h create mode 100644 sound/soc/mediatek/mt8183/mt8183-reg.h diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index e731d40afcce..8bb360ee7234 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -105,3 +105,13 @@ config SND_SOC_MT8173_RT5650_RT5676 with the RT5650 and RT5676 codecs. Select Y if you have such device. If unsure select "N". + +config SND_SOC_MT8183 + tristate "ASoC support for Mediatek MT8183 chip" + depends on ARCH_MEDIATEK + select SND_SOC_MEDIATEK + help + This adds ASoC platform driver support for Mediatek MT8183 chip + that can be used with other codecs. + Select Y if you have such device. + If unsure select "N". diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index 3bb2c47532f4..76032cae6d51 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_SND_SOC_MEDIATEK) += common/ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ +obj-$(CONFIG_SND_SOC_MT8183) += mt8183/ diff --git a/sound/soc/mediatek/mt8183/Makefile b/sound/soc/mediatek/mt8183/Makefile new file mode 100644 index 000000000000..f3ee6ac98fe8 --- /dev/null +++ b/sound/soc/mediatek/mt8183/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0 + +# platform driver +snd-soc-mt8183-afe-objs := \ + mt8183-afe-pcm.o \ + mt8183-afe-clk.o \ + mt8183-dai-i2s.o \ + mt8183-dai-tdm.o \ + mt8183-dai-pcm.o \ + mt8183-dai-hostless.o \ + mt8183-dai-adda.o + +obj-$(CONFIG_SND_SOC_MT8183) += snd-soc-mt8183-afe.o diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-clk.c b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c new file mode 100644 index 000000000000..f523ad103acc --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c @@ -0,0 +1,611 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt8183-afe-clk.c -- Mediatek 8183 afe clock ctrl +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include + +#include "mt8183-afe-common.h" +#include "mt8183-afe-clk.h" +#include "mt8183-reg.h" + +enum { + CLK_AFE = 0, + CLK_TML, + CLK_APLL22M, + CLK_APLL24M, + CLK_APLL1_TUNER, + CLK_APLL2_TUNER, + CLK_I2S1_BCLK_SW, + CLK_I2S2_BCLK_SW, + CLK_I2S3_BCLK_SW, + CLK_I2S4_BCLK_SW, + CLK_INFRA_SYS_AUDIO, + CLK_MUX_AUDIO, + CLK_MUX_AUDIOINTBUS, + CLK_TOP_SYSPLL_D2_D4, + /* apll related mux */ + CLK_TOP_MUX_AUD_1, + CLK_TOP_APLL1_CK, + CLK_TOP_MUX_AUD_2, + CLK_TOP_APLL2_CK, + CLK_TOP_MUX_AUD_ENG1, + CLK_TOP_APLL1_D8, + CLK_TOP_MUX_AUD_ENG2, + CLK_TOP_APLL2_D8, + CLK_TOP_I2S0_M_SEL, + CLK_TOP_I2S1_M_SEL, + CLK_TOP_I2S2_M_SEL, + CLK_TOP_I2S3_M_SEL, + CLK_TOP_I2S4_M_SEL, + CLK_TOP_I2S5_M_SEL, + CLK_TOP_APLL12_DIV0, + CLK_TOP_APLL12_DIV1, + CLK_TOP_APLL12_DIV2, + CLK_TOP_APLL12_DIV3, + CLK_TOP_APLL12_DIV4, + CLK_TOP_APLL12_DIVB, + CLK_CLK26M, + CLK_NUM +}; + +static const char *aud_clks[CLK_NUM] = { + [CLK_AFE] = "aud_afe_clk", + [CLK_TML] = "aud_tml_clk", + [CLK_APLL22M] = "aud_apll22m_clk", + [CLK_APLL24M] = "aud_apll24m_clk", + [CLK_APLL1_TUNER] = "aud_apll1_tuner_clk", + [CLK_APLL2_TUNER] = "aud_apll2_tuner_clk", + [CLK_I2S1_BCLK_SW] = "aud_i2s1_bclk_sw", + [CLK_I2S2_BCLK_SW] = "aud_i2s2_bclk_sw", + [CLK_I2S3_BCLK_SW] = "aud_i2s3_bclk_sw", + [CLK_I2S4_BCLK_SW] = "aud_i2s4_bclk_sw", + [CLK_INFRA_SYS_AUDIO] = "aud_infra_clk", + [CLK_MUX_AUDIO] = "top_mux_audio", + [CLK_MUX_AUDIOINTBUS] = "top_mux_aud_intbus", + [CLK_TOP_SYSPLL_D2_D4] = "top_syspll_d2_d4", + [CLK_TOP_MUX_AUD_1] = "top_mux_aud_1", + [CLK_TOP_APLL1_CK] = "top_apll1_ck", + [CLK_TOP_MUX_AUD_2] = "top_mux_aud_2", + [CLK_TOP_APLL2_CK] = "top_apll2_ck", + [CLK_TOP_MUX_AUD_ENG1] = "top_mux_aud_eng1", + [CLK_TOP_APLL1_D8] = "top_apll1_d8", + [CLK_TOP_MUX_AUD_ENG2] = "top_mux_aud_eng2", + [CLK_TOP_APLL2_D8] = "top_apll2_d8", + [CLK_TOP_I2S0_M_SEL] = "top_i2s0_m_sel", + [CLK_TOP_I2S1_M_SEL] = "top_i2s1_m_sel", + [CLK_TOP_I2S2_M_SEL] = "top_i2s2_m_sel", + [CLK_TOP_I2S3_M_SEL] = "top_i2s3_m_sel", + [CLK_TOP_I2S4_M_SEL] = "top_i2s4_m_sel", + [CLK_TOP_I2S5_M_SEL] = "top_i2s5_m_sel", + [CLK_TOP_APLL12_DIV0] = "top_apll12_div0", + [CLK_TOP_APLL12_DIV1] = "top_apll12_div1", + [CLK_TOP_APLL12_DIV2] = "top_apll12_div2", + [CLK_TOP_APLL12_DIV3] = "top_apll12_div3", + [CLK_TOP_APLL12_DIV4] = "top_apll12_div4", + [CLK_TOP_APLL12_DIVB] = "top_apll12_divb", + [CLK_CLK26M] = "top_clk26m_clk", +}; + +int mt8183_init_clock(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int i; + + afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk), + GFP_KERNEL); + if (!afe_priv->clk) + return -ENOMEM; + + for (i = 0; i < CLK_NUM; i++) { + afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]); + if (IS_ERR(afe_priv->clk[i])) { + dev_err(afe->dev, "%s(), devm_clk_get %s fail, ret %ld\n", + __func__, aud_clks[i], + PTR_ERR(afe_priv->clk[i])); + return PTR_ERR(afe_priv->clk[i]); + } + } + + return 0; +} + +int mt8183_afe_enable_clock(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = clk_prepare_enable(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_INFRA_SYS_AUDIO], ret); + goto CLK_INFRA_SYS_AUDIO_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIO]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], ret); + goto CLK_MUX_AUDIO_ERR; + } + + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIO], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIO], + aud_clks[CLK_CLK26M], ret); + goto CLK_MUX_AUDIO_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); + goto CLK_MUX_AUDIO_INTBUS_ERR; + } + + ret = clk_set_parent(afe_priv->clk[CLK_MUX_AUDIOINTBUS], + afe_priv->clk[CLK_TOP_SYSPLL_D2_D4]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_MUX_AUDIOINTBUS], + aud_clks[CLK_TOP_SYSPLL_D2_D4], ret); + goto CLK_MUX_AUDIO_INTBUS_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_AFE]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_AFE], ret); + goto CLK_AFE_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_I2S1_BCLK_SW]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_I2S1_BCLK_SW], ret); + goto CLK_I2S1_BCLK_SW_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_I2S2_BCLK_SW]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_I2S2_BCLK_SW], ret); + goto CLK_I2S2_BCLK_SW_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_I2S3_BCLK_SW]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_I2S3_BCLK_SW], ret); + goto CLK_I2S3_BCLK_SW_ERR; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_I2S4_BCLK_SW]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_I2S4_BCLK_SW], ret); + goto CLK_I2S4_BCLK_SW_ERR; + } + + return 0; + +CLK_I2S4_BCLK_SW_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_I2S3_BCLK_SW]); +CLK_I2S3_BCLK_SW_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_I2S2_BCLK_SW]); +CLK_I2S2_BCLK_SW_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_I2S1_BCLK_SW]); +CLK_I2S1_BCLK_SW_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_AFE]); +CLK_AFE_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); +CLK_MUX_AUDIO_INTBUS_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]); +CLK_MUX_AUDIO_ERR: + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); +CLK_INFRA_SYS_AUDIO_ERR: + return ret; +} + +int mt8183_afe_disable_clock(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + clk_disable_unprepare(afe_priv->clk[CLK_I2S4_BCLK_SW]); + clk_disable_unprepare(afe_priv->clk[CLK_I2S3_BCLK_SW]); + clk_disable_unprepare(afe_priv->clk[CLK_I2S2_BCLK_SW]); + clk_disable_unprepare(afe_priv->clk[CLK_I2S1_BCLK_SW]); + clk_disable_unprepare(afe_priv->clk[CLK_AFE]); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); + clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIO]); + clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); + + return 0; +} + +/* apll */ +static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], ret); + goto ERR_ENABLE_CLK_TOP_MUX_AUD_1; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_TOP_APLL1_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_TOP_APLL1_CK], ret); + goto ERR_SELECT_CLK_TOP_MUX_AUD_1; + } + + /* 180.6336 / 8 = 22.5792MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], ret); + goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_TOP_APLL1_D8]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_TOP_APLL1_D8], ret); + goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG1; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_1], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]); + } + + return 0; + +ERR_SELECT_CLK_TOP_MUX_AUD_ENG1: + clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1], + afe_priv->clk[CLK_CLK26M]); + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1]); +ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1: +ERR_SELECT_CLK_TOP_MUX_AUD_1: + clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_1], + afe_priv->clk[CLK_CLK26M]); + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_1]); +ERR_ENABLE_CLK_TOP_MUX_AUD_1: +EXIT: + return ret; +} + +static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + if (enable) { + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], ret); + goto ERR_ENABLE_CLK_TOP_MUX_AUD_2; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_TOP_APLL2_CK]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_TOP_APLL2_CK], ret); + goto ERR_SELECT_CLK_TOP_MUX_AUD_2; + } + + /* 196.608 / 8 = 24.576MHz */ + ret = clk_prepare_enable(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], ret); + goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2; + } + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_TOP_APLL2_D8]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_TOP_APLL2_D8], ret); + goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG2; + } + } else { + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); + + ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_CLK26M]); + if (ret) { + dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[CLK_TOP_MUX_AUD_2], + aud_clks[CLK_CLK26M], ret); + goto EXIT; + } + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]); + } + + return 0; + +ERR_SELECT_CLK_TOP_MUX_AUD_ENG2: + clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2], + afe_priv->clk[CLK_CLK26M]); + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2]); +ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2: +ERR_SELECT_CLK_TOP_MUX_AUD_2: + clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_2], + afe_priv->clk[CLK_CLK26M]); + clk_disable_unprepare(afe_priv->clk[CLK_TOP_MUX_AUD_2]); +ERR_ENABLE_CLK_TOP_MUX_AUD_2: +EXIT: + return ret; +} + +int mt8183_apll1_enable(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll1_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL22M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL22M], ret); + goto ERR_CLK_APLL22M; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL1_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL1_TUNER], ret); + goto ERR_CLK_APLL1_TUNER; + } + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, + 0x0000FFF7, 0x00000832); + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, + 0x1 << AFE_22M_ON_SFT); + + return 0; + +ERR_CLK_APLL1_TUNER: + clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]); +ERR_CLK_APLL22M: + return ret; +} + +void mt8183_apll1_disable(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_22M_ON_MASK_SFT, + 0x0 << AFE_22M_ON_SFT); + + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG, 0x1, 0x0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL1_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL22M]); + + apll1_mux_setting(afe, false); +} + +int mt8183_apll2_enable(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + /* setting for APLL */ + apll2_mux_setting(afe, true); + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL24M]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL24M], ret); + goto ERR_CLK_APLL24M; + } + + ret = clk_prepare_enable(afe_priv->clk[CLK_APLL2_TUNER]); + if (ret) { + dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", + __func__, aud_clks[CLK_APLL2_TUNER], ret); + goto ERR_CLK_APLL2_TUNER; + } + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, + 0x0000FFF7, 0x00000634); + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x1); + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, + 0x1 << AFE_24M_ON_SFT); + + return 0; + +ERR_CLK_APLL2_TUNER: + clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]); +ERR_CLK_APLL24M: + return ret; +} + +void mt8183_apll2_disable(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + regmap_update_bits(afe->regmap, AFE_HD_ENGEN_ENABLE, + AFE_24M_ON_MASK_SFT, + 0x0 << AFE_24M_ON_SFT); + + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG, 0x1, 0x0); + + clk_disable_unprepare(afe_priv->clk[CLK_APLL2_TUNER]); + clk_disable_unprepare(afe_priv->clk[CLK_APLL24M]); + + apll2_mux_setting(afe, false); +} + +int mt8183_get_apll_rate(struct mtk_base_afe *afe, int apll) +{ + return (apll == MT8183_APLL1) ? 180633600 : 196608000; +} + +int mt8183_get_apll_by_rate(struct mtk_base_afe *afe, int rate) +{ + return ((rate % 8000) == 0) ? MT8183_APLL2 : MT8183_APLL1; +} + +int mt8183_get_apll_by_name(struct mtk_base_afe *afe, const char *name) +{ + if (strcmp(name, APLL1_W_NAME) == 0) + return MT8183_APLL1; + else + return MT8183_APLL2; +} + +/* mck */ +struct mt8183_mck_div { + int m_sel_id; + int div_clk_id; +}; + +static const struct mt8183_mck_div mck_div[MT8183_MCK_NUM] = { + [MT8183_I2S0_MCK] = { + .m_sel_id = CLK_TOP_I2S0_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV0, + }, + [MT8183_I2S1_MCK] = { + .m_sel_id = CLK_TOP_I2S1_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV1, + }, + [MT8183_I2S2_MCK] = { + .m_sel_id = CLK_TOP_I2S2_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV2, + }, + [MT8183_I2S3_MCK] = { + .m_sel_id = CLK_TOP_I2S3_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV3, + }, + [MT8183_I2S4_MCK] = { + .m_sel_id = CLK_TOP_I2S4_M_SEL, + .div_clk_id = CLK_TOP_APLL12_DIV4, + }, + [MT8183_I2S4_BCK] = { + .m_sel_id = -1, + .div_clk_id = CLK_TOP_APLL12_DIVB, + }, + [MT8183_I2S5_MCK] = { + .m_sel_id = -1, + .div_clk_id = -1, + }, +}; + +int mt8183_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int apll = mt8183_get_apll_by_rate(afe, rate); + int apll_clk_id = apll == MT8183_APLL1 ? + CLK_TOP_MUX_AUD_1 : CLK_TOP_MUX_AUD_2; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + int ret; + + /* i2s5 mck not support */ + if (mck_id == MT8183_I2S5_MCK) + return 0; + + /* select apll */ + if (m_sel_id >= 0) { + ret = clk_prepare_enable(afe_priv->clk[m_sel_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[m_sel_id], ret); + goto ERR_ENABLE_MCLK; + } + ret = clk_set_parent(afe_priv->clk[m_sel_id], + afe_priv->clk[apll_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_parent %s-%s fail %d\n", + __func__, aud_clks[m_sel_id], + aud_clks[apll_clk_id], ret); + goto ERR_SELECT_MCLK; + } + } + + /* enable div, set rate */ + ret = clk_prepare_enable(afe_priv->clk[div_clk_id]); + if (ret) { + dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n", + __func__, aud_clks[div_clk_id], ret); + goto ERR_ENABLE_MCLK_DIV; + } + ret = clk_set_rate(afe_priv->clk[div_clk_id], rate); + if (ret) { + dev_err(afe->dev, "%s(), clk_set_rate %s, rate %d, fail %d\n", + __func__, aud_clks[div_clk_id], + rate, ret); + goto ERR_SET_MCLK_RATE; + return ret; + } + + return 0; + +ERR_SET_MCLK_RATE: + clk_disable_unprepare(afe_priv->clk[div_clk_id]); +ERR_ENABLE_MCLK_DIV: +ERR_SELECT_MCLK: + if (m_sel_id >= 0) + clk_disable_unprepare(afe_priv->clk[m_sel_id]); +ERR_ENABLE_MCLK: + return ret; +} + +void mt8183_mck_disable(struct mtk_base_afe *afe, int mck_id) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int m_sel_id = mck_div[mck_id].m_sel_id; + int div_clk_id = mck_div[mck_id].div_clk_id; + + clk_disable_unprepare(afe_priv->clk[div_clk_id]); + if (m_sel_id >= 0) + clk_disable_unprepare(afe_priv->clk[m_sel_id]); +} diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-clk.h b/sound/soc/mediatek/mt8183/mt8183-afe-clk.h new file mode 100644 index 000000000000..2c510aa80fc7 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-afe-clk.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8183-afe-clk.h -- Mediatek 8183 afe clock ctrl definition + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef _MT8183_AFE_CLK_H_ +#define _MT8183_AFE_CLK_H_ + +/* APLL */ +#define APLL1_W_NAME "APLL1" +#define APLL2_W_NAME "APLL2" +enum { + MT8183_APLL1 = 0, + MT8183_APLL2, +}; + +struct mtk_base_afe; + +int mt8183_init_clock(struct mtk_base_afe *afe); +int mt8183_afe_enable_clock(struct mtk_base_afe *afe); +int mt8183_afe_disable_clock(struct mtk_base_afe *afe); + +int mt8183_apll1_enable(struct mtk_base_afe *afe); +void mt8183_apll1_disable(struct mtk_base_afe *afe); + +int mt8183_apll2_enable(struct mtk_base_afe *afe); +void mt8183_apll2_disable(struct mtk_base_afe *afe); + +int mt8183_get_apll_rate(struct mtk_base_afe *afe, int apll); +int mt8183_get_apll_by_rate(struct mtk_base_afe *afe, int rate); +int mt8183_get_apll_by_name(struct mtk_base_afe *afe, const char *name); + +int mt8183_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate); +void mt8183_mck_disable(struct mtk_base_afe *afe, int mck_id); +#endif diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-common.h b/sound/soc/mediatek/mt8183/mt8183-afe-common.h new file mode 100644 index 000000000000..b220e7a7db7e --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-afe-common.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8183-afe-common.h -- Mediatek 8183 audio driver definitions + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef _MT_8183_AFE_COMMON_H_ +#define _MT_8183_AFE_COMMON_H_ + +#include +#include +#include +#include "../common/mtk-base-afe.h" + +enum { + MT8183_MEMIF_DL1, + MT8183_MEMIF_DL2, + MT8183_MEMIF_DL3, + MT8183_MEMIF_VUL12, + MT8183_MEMIF_VUL2, + MT8183_MEMIF_AWB, + MT8183_MEMIF_AWB2, + MT8183_MEMIF_MOD_DAI, + MT8183_MEMIF_HDMI, + MT8183_MEMIF_NUM, + MT8183_DAI_ADDA = MT8183_MEMIF_NUM, + MT8183_DAI_PCM_1, + MT8183_DAI_PCM_2, + MT8183_DAI_I2S_0, + MT8183_DAI_I2S_1, + MT8183_DAI_I2S_2, + MT8183_DAI_I2S_3, + MT8183_DAI_I2S_5, + MT8183_DAI_TDM, + MT8183_DAI_HOSTLESS_LPBK, + MT8183_DAI_HOSTLESS_SPEECH, + MT8183_DAI_NUM, +}; + +enum { + MT8183_IRQ_0, + MT8183_IRQ_1, + MT8183_IRQ_2, + MT8183_IRQ_3, + MT8183_IRQ_4, + MT8183_IRQ_5, + MT8183_IRQ_6, + MT8183_IRQ_7, + MT8183_IRQ_8, /* hw bundle to TDM */ + MT8183_IRQ_11, + MT8183_IRQ_12, + MT8183_IRQ_NUM, +}; + +enum { + MT8183_MTKAIF_PROTOCOL_1 = 0, + MT8183_MTKAIF_PROTOCOL_2, + MT8183_MTKAIF_PROTOCOL_2_CLK_P2, +}; + +/* MCLK */ +enum { + MT8183_I2S0_MCK = 0, + MT8183_I2S1_MCK, + MT8183_I2S2_MCK, + MT8183_I2S3_MCK, + MT8183_I2S4_MCK, + MT8183_I2S4_BCK, + MT8183_I2S5_MCK, + MT8183_MCK_NUM, +}; + +struct clk; + +struct mt8183_afe_private { + struct clk **clk; + + int pm_runtime_bypass_reg_ctl; + + /* dai */ + void *dai_priv[MT8183_DAI_NUM]; + + /* adda */ + int mtkaif_protocol; + int mtkaif_calibration_ok; + int mtkaif_chosen_phase[4]; + int mtkaif_phase_cycle[4]; + int mtkaif_calibration_num_phase; + int mtkaif_dmic; + + /* mck */ + int mck_rate[MT8183_MCK_NUM]; +}; + +unsigned int mt8183_general_rate_transform(struct device *dev, + unsigned int rate); +unsigned int mt8183_rate_transform(struct device *dev, + unsigned int rate, int aud_blk); + +/* dai register */ +int mt8183_dai_adda_register(struct mtk_base_afe *afe); +int mt8183_dai_pcm_register(struct mtk_base_afe *afe); +int mt8183_dai_i2s_register(struct mtk_base_afe *afe); +int mt8183_dai_tdm_register(struct mtk_base_afe *afe); +int mt8183_dai_hostless_register(struct mtk_base_afe *afe); +#endif diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c new file mode 100644 index 000000000000..ff3111ec876c --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -0,0 +1,1237 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Mediatek ALSA SoC AFE platform driver for 8183 +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include +#include +#include +#include + +#include "mt8183-afe-common.h" +#include "mt8183-afe-clk.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" +#include "../common/mtk-afe-platform-driver.h" +#include "../common/mtk-afe-fe-dai.h" + +enum { + MTK_AFE_RATE_8K = 0, + MTK_AFE_RATE_11K = 1, + MTK_AFE_RATE_12K = 2, + MTK_AFE_RATE_384K = 3, + MTK_AFE_RATE_16K = 4, + MTK_AFE_RATE_22K = 5, + MTK_AFE_RATE_24K = 6, + MTK_AFE_RATE_130K = 7, + MTK_AFE_RATE_32K = 8, + MTK_AFE_RATE_44K = 9, + MTK_AFE_RATE_48K = 10, + MTK_AFE_RATE_88K = 11, + MTK_AFE_RATE_96K = 12, + MTK_AFE_RATE_176K = 13, + MTK_AFE_RATE_192K = 14, + MTK_AFE_RATE_260K = 15, +}; + +enum { + MTK_AFE_DAI_MEMIF_RATE_8K = 0, + MTK_AFE_DAI_MEMIF_RATE_16K = 1, + MTK_AFE_DAI_MEMIF_RATE_32K = 2, + MTK_AFE_DAI_MEMIF_RATE_48K = 3, +}; + +enum { + MTK_AFE_PCM_RATE_8K = 0, + MTK_AFE_PCM_RATE_16K = 1, + MTK_AFE_PCM_RATE_32K = 2, + MTK_AFE_PCM_RATE_48K = 3, +}; + +unsigned int mt8183_general_rate_transform(struct device *dev, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_RATE_8K; + case 11025: + return MTK_AFE_RATE_11K; + case 12000: + return MTK_AFE_RATE_12K; + case 16000: + return MTK_AFE_RATE_16K; + case 22050: + return MTK_AFE_RATE_22K; + case 24000: + return MTK_AFE_RATE_24K; + case 32000: + return MTK_AFE_RATE_32K; + case 44100: + return MTK_AFE_RATE_44K; + case 48000: + return MTK_AFE_RATE_48K; + case 88200: + return MTK_AFE_RATE_88K; + case 96000: + return MTK_AFE_RATE_96K; + case 130000: + return MTK_AFE_RATE_130K; + case 176400: + return MTK_AFE_RATE_176K; + case 192000: + return MTK_AFE_RATE_192K; + case 260000: + return MTK_AFE_RATE_260K; + default: + dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, rate, MTK_AFE_RATE_48K); + return MTK_AFE_RATE_48K; + } +} + +static unsigned int dai_memif_rate_transform(struct device *dev, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_DAI_MEMIF_RATE_8K; + case 16000: + return MTK_AFE_DAI_MEMIF_RATE_16K; + case 32000: + return MTK_AFE_DAI_MEMIF_RATE_32K; + case 48000: + return MTK_AFE_DAI_MEMIF_RATE_48K; + default: + dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n", + __func__, rate, MTK_AFE_DAI_MEMIF_RATE_16K); + return MTK_AFE_DAI_MEMIF_RATE_16K; + } +} + +unsigned int mt8183_rate_transform(struct device *dev, + unsigned int rate, int aud_blk) +{ + switch (aud_blk) { + case MT8183_MEMIF_MOD_DAI: + return dai_memif_rate_transform(dev, rate); + default: + return mt8183_general_rate_transform(dev, rate); + } +} + +static const struct snd_pcm_hardware mt8183_afe_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .period_bytes_min = 256, + .period_bytes_max = 4 * 48 * 1024, + .periods_min = 2, + .periods_max = 256, + .buffer_bytes_max = 8 * 48 * 1024, + .fifo_size = 0, +}; + +static int mt8183_memif_fs(struct snd_pcm_substream *substream, + unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + int id = rtd->cpu_dai->id; + + return mt8183_rate_transform(afe->dev, rate, id); +} + +static int mt8183_irq_fs(struct snd_pcm_substream *substream, unsigned int rate) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + + return mt8183_general_rate_transform(afe->dev, rate); +} + +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_PCM_DAI_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mt8183_memif_dai_driver[] = { + /* FE DAIs: memory intefaces to CPU */ + { + .name = "DL1", + .id = MT8183_MEMIF_DL1, + .playback = { + .stream_name = "DL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL2", + .id = MT8183_MEMIF_DL2, + .playback = { + .stream_name = "DL2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "DL3", + .id = MT8183_MEMIF_DL3, + .playback = { + .stream_name = "DL3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL1", + .id = MT8183_MEMIF_VUL12, + .capture = { + .stream_name = "UL1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL2", + .id = MT8183_MEMIF_AWB, + .capture = { + .stream_name = "UL2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL3", + .id = MT8183_MEMIF_VUL2, + .capture = { + .stream_name = "UL3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL4", + .id = MT8183_MEMIF_AWB2, + .capture = { + .stream_name = "UL4", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "UL_MONO_1", + .id = MT8183_MEMIF_MOD_DAI, + .capture = { + .stream_name = "UL_MONO_1", + .channels_min = 1, + .channels_max = 1, + .rates = MTK_PCM_DAI_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, + { + .name = "HDMI", + .id = MT8183_MEMIF_HDMI, + .playback = { + .stream_name = "HDMI", + .channels_min = 2, + .channels_max = 8, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_afe_fe_ops, + }, +}; + +/* dma widget & routes*/ +static const struct snd_kcontrol_new memif_ul1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN21, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN22, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul2_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN5, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN5, + I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN5, + I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN5, + I_DL3_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul2_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN6, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN6, + I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN6, + I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN6, + I_DL3_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul3_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN32, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul3_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN33, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul4_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN38, + I_ADDA_UL_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul4_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN39, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new memif_ul_mono_1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN12, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN12, + I_ADDA_UL_CH2, 1, 0), +}; + +static const struct snd_soc_dapm_widget mt8183_memif_widgets[] = { + /* memif */ + SND_SOC_DAPM_MIXER("UL1_CH1", SND_SOC_NOPM, 0, 0, + memif_ul1_ch1_mix, ARRAY_SIZE(memif_ul1_ch1_mix)), + SND_SOC_DAPM_MIXER("UL1_CH2", SND_SOC_NOPM, 0, 0, + memif_ul1_ch2_mix, ARRAY_SIZE(memif_ul1_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL2_CH1", SND_SOC_NOPM, 0, 0, + memif_ul2_ch1_mix, ARRAY_SIZE(memif_ul2_ch1_mix)), + SND_SOC_DAPM_MIXER("UL2_CH2", SND_SOC_NOPM, 0, 0, + memif_ul2_ch2_mix, ARRAY_SIZE(memif_ul2_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL3_CH1", SND_SOC_NOPM, 0, 0, + memif_ul3_ch1_mix, ARRAY_SIZE(memif_ul3_ch1_mix)), + SND_SOC_DAPM_MIXER("UL3_CH2", SND_SOC_NOPM, 0, 0, + memif_ul3_ch2_mix, ARRAY_SIZE(memif_ul3_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL4_CH1", SND_SOC_NOPM, 0, 0, + memif_ul4_ch1_mix, ARRAY_SIZE(memif_ul4_ch1_mix)), + SND_SOC_DAPM_MIXER("UL4_CH2", SND_SOC_NOPM, 0, 0, + memif_ul4_ch2_mix, ARRAY_SIZE(memif_ul4_ch2_mix)), + + SND_SOC_DAPM_MIXER("UL_MONO_1_CH1", SND_SOC_NOPM, 0, 0, + memif_ul_mono_1_mix, + ARRAY_SIZE(memif_ul_mono_1_mix)), +}; + +static const struct snd_soc_dapm_route mt8183_memif_routes[] = { + /* capture */ + {"UL1", NULL, "UL1_CH1"}, + {"UL1", NULL, "UL1_CH2"}, + {"UL1_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL1_CH2", "ADDA_UL_CH2", "ADDA Capture"}, + + {"UL2", NULL, "UL2_CH1"}, + {"UL2", NULL, "UL2_CH2"}, + {"UL2_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL2_CH2", "ADDA_UL_CH2", "ADDA Capture"}, + + {"UL3", NULL, "UL3_CH1"}, + {"UL3", NULL, "UL3_CH2"}, + {"UL3_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL3_CH2", "ADDA_UL_CH2", "ADDA Capture"}, + + {"UL4", NULL, "UL4_CH1"}, + {"UL4", NULL, "UL4_CH2"}, + {"UL4_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL4_CH2", "ADDA_UL_CH2", "ADDA Capture"}, + + {"UL_MONO_1", NULL, "UL_MONO_1_CH1"}, + {"UL_MONO_1_CH1", "ADDA_UL_CH1", "ADDA Capture"}, + {"UL_MONO_1_CH1", "ADDA_UL_CH2", "ADDA Capture"}, +}; + +static const struct snd_soc_component_driver mt8183_afe_pcm_dai_component = { + .name = "mt8183-afe-pcm-dai", +}; + +static const struct mtk_base_memif_data memif_data[MT8183_MEMIF_NUM] = { + [MT8183_MEMIF_DL1] = { + .name = "DL1", + .id = MT8183_MEMIF_DL1, + .reg_ofs_base = AFE_DL1_BASE, + .reg_ofs_cur = AFE_DL1_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = DL1_MODE_SFT, + .fs_maskbit = DL1_MODE_MASK, + .mono_reg = AFE_DAC_CON1, + .mono_shift = DL1_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL1_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = DL1_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_DL2] = { + .name = "DL2", + .id = MT8183_MEMIF_DL2, + .reg_ofs_base = AFE_DL2_BASE, + .reg_ofs_cur = AFE_DL2_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = DL2_MODE_SFT, + .fs_maskbit = DL2_MODE_MASK, + .mono_reg = AFE_DAC_CON1, + .mono_shift = DL2_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL2_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = DL2_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_DL3] = { + .name = "DL3", + .id = MT8183_MEMIF_DL3, + .reg_ofs_base = AFE_DL3_BASE, + .reg_ofs_cur = AFE_DL3_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = DL3_MODE_SFT, + .fs_maskbit = DL3_MODE_MASK, + .mono_reg = AFE_DAC_CON1, + .mono_shift = DL3_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = DL3_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = DL3_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_VUL2] = { + .name = "VUL2", + .id = MT8183_MEMIF_VUL2, + .reg_ofs_base = AFE_VUL2_BASE, + .reg_ofs_cur = AFE_VUL2_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = VUL2_MODE_SFT, + .fs_maskbit = VUL2_MODE_MASK, + .mono_reg = AFE_DAC_CON2, + .mono_shift = VUL2_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL2_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = VUL2_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_AWB] = { + .name = "AWB", + .id = MT8183_MEMIF_AWB, + .reg_ofs_base = AFE_AWB_BASE, + .reg_ofs_cur = AFE_AWB_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = AWB_MODE_SFT, + .fs_maskbit = AWB_MODE_MASK, + .mono_reg = AFE_DAC_CON1, + .mono_shift = AWB_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = AWB_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = AWB_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_AWB2] = { + .name = "AWB2", + .id = MT8183_MEMIF_AWB2, + .reg_ofs_base = AFE_AWB2_BASE, + .reg_ofs_cur = AFE_AWB2_CUR, + .fs_reg = AFE_DAC_CON2, + .fs_shift = AWB2_MODE_SFT, + .fs_maskbit = AWB2_MODE_MASK, + .mono_reg = AFE_DAC_CON2, + .mono_shift = AWB2_DATA_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = AWB2_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = AWB2_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_VUL12] = { + .name = "VUL12", + .id = MT8183_MEMIF_VUL12, + .reg_ofs_base = AFE_VUL_D2_BASE, + .reg_ofs_cur = AFE_VUL_D2_CUR, + .fs_reg = AFE_DAC_CON0, + .fs_shift = VUL12_MODE_SFT, + .fs_maskbit = VUL12_MODE_MASK, + .mono_reg = AFE_DAC_CON0, + .mono_shift = VUL12_MONO_SFT, + .enable_reg = AFE_DAC_CON0, + .enable_shift = VUL12_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = VUL12_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_MOD_DAI] = { + .name = "MOD_DAI", + .id = MT8183_MEMIF_MOD_DAI, + .reg_ofs_base = AFE_MOD_DAI_BASE, + .reg_ofs_cur = AFE_MOD_DAI_CUR, + .fs_reg = AFE_DAC_CON1, + .fs_shift = MOD_DAI_MODE_SFT, + .fs_maskbit = MOD_DAI_MODE_MASK, + .mono_reg = -1, + .mono_shift = 0, + .enable_reg = AFE_DAC_CON0, + .enable_shift = MOD_DAI_ON_SFT, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = MOD_DAI_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, + [MT8183_MEMIF_HDMI] = { + .name = "HDMI", + .id = MT8183_MEMIF_HDMI, + .reg_ofs_base = AFE_HDMI_OUT_BASE, + .reg_ofs_cur = AFE_HDMI_OUT_CUR, + .fs_reg = -1, + .fs_shift = -1, + .fs_maskbit = -1, + .mono_reg = -1, + .mono_shift = -1, + .enable_reg = -1, /* control in tdm for sync start */ + .enable_shift = -1, + .hd_reg = AFE_MEMIF_HD_MODE, + .hd_shift = HDMI_HD_SFT, + .agent_disable_reg = -1, + .agent_disable_shift = -1, + .msb_reg = -1, + .msb_shift = -1, + }, +}; + +static const struct mtk_base_irq_data irq_data[MT8183_IRQ_NUM] = { + [MT8183_IRQ_0] = { + .id = MT8183_IRQ_0, + .irq_cnt_reg = AFE_IRQ_MCU_CNT0, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ0_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ0_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ0_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ0_MCU_CLR_SFT, + }, + [MT8183_IRQ_1] = { + .id = MT8183_IRQ_1, + .irq_cnt_reg = AFE_IRQ_MCU_CNT1, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ1_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ1_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ1_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ1_MCU_CLR_SFT, + }, + [MT8183_IRQ_2] = { + .id = MT8183_IRQ_2, + .irq_cnt_reg = AFE_IRQ_MCU_CNT2, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ2_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ2_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ2_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ2_MCU_CLR_SFT, + }, + [MT8183_IRQ_3] = { + .id = MT8183_IRQ_3, + .irq_cnt_reg = AFE_IRQ_MCU_CNT3, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ3_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ3_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ3_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ3_MCU_CLR_SFT, + }, + [MT8183_IRQ_4] = { + .id = MT8183_IRQ_4, + .irq_cnt_reg = AFE_IRQ_MCU_CNT4, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ4_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ4_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ4_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ4_MCU_CLR_SFT, + }, + [MT8183_IRQ_5] = { + .id = MT8183_IRQ_5, + .irq_cnt_reg = AFE_IRQ_MCU_CNT5, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ5_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ5_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ5_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ5_MCU_CLR_SFT, + }, + [MT8183_IRQ_6] = { + .id = MT8183_IRQ_6, + .irq_cnt_reg = AFE_IRQ_MCU_CNT6, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ6_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ6_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ6_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ6_MCU_CLR_SFT, + }, + [MT8183_IRQ_7] = { + .id = MT8183_IRQ_7, + .irq_cnt_reg = AFE_IRQ_MCU_CNT7, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON1, + .irq_fs_shift = IRQ7_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ7_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ7_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ7_MCU_CLR_SFT, + }, + [MT8183_IRQ_8] = { + .id = MT8183_IRQ_8, + .irq_cnt_reg = AFE_IRQ_MCU_CNT8, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = -1, + .irq_fs_shift = -1, + .irq_fs_maskbit = -1, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ8_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ8_MCU_CLR_SFT, + }, + [MT8183_IRQ_11] = { + .id = MT8183_IRQ_11, + .irq_cnt_reg = AFE_IRQ_MCU_CNT11, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ11_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ11_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ11_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ11_MCU_CLR_SFT, + }, + [MT8183_IRQ_12] = { + .id = MT8183_IRQ_12, + .irq_cnt_reg = AFE_IRQ_MCU_CNT12, + .irq_cnt_shift = 0, + .irq_cnt_maskbit = 0x3ffff, + .irq_fs_reg = AFE_IRQ_MCU_CON2, + .irq_fs_shift = IRQ12_MCU_MODE_SFT, + .irq_fs_maskbit = IRQ12_MCU_MODE_MASK, + .irq_en_reg = AFE_IRQ_MCU_CON0, + .irq_en_shift = IRQ12_MCU_ON_SFT, + .irq_clr_reg = AFE_IRQ_MCU_CLR, + .irq_clr_shift = IRQ12_MCU_CLR_SFT, + }, +}; + +static bool mt8183_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* these auto-gen reg has read-only bit, so put it as volatile */ + /* volatile reg cannot be cached, so cannot be set when power off */ + switch (reg) { + case AUDIO_TOP_CON0: /* reg bit controlled by CCF */ + case AUDIO_TOP_CON1: /* reg bit controlled by CCF */ + case AUDIO_TOP_CON3: + case AFE_DL1_CUR: + case AFE_DL1_END: + case AFE_DL2_CUR: + case AFE_DL2_END: + case AFE_AWB_END: + case AFE_AWB_CUR: + case AFE_VUL_END: + case AFE_VUL_CUR: + case AFE_MEMIF_MON0: + case AFE_MEMIF_MON1: + case AFE_MEMIF_MON2: + case AFE_MEMIF_MON3: + case AFE_MEMIF_MON4: + case AFE_MEMIF_MON5: + case AFE_MEMIF_MON6: + case AFE_MEMIF_MON7: + case AFE_MEMIF_MON8: + case AFE_MEMIF_MON9: + case AFE_ADDA_SRC_DEBUG_MON0: + case AFE_ADDA_SRC_DEBUG_MON1: + case AFE_ADDA_UL_SRC_MON0: + case AFE_ADDA_UL_SRC_MON1: + case AFE_SIDETONE_MON: + case AFE_SIDETONE_CON0: + case AFE_SIDETONE_COEFF: + case AFE_BUS_MON0: + case AFE_MRGIF_MON0: + case AFE_MRGIF_MON1: + case AFE_MRGIF_MON2: + case AFE_I2S_MON: + case AFE_DAC_MON: + case AFE_VUL2_END: + case AFE_VUL2_CUR: + case AFE_IRQ0_MCU_CNT_MON: + case AFE_IRQ6_MCU_CNT_MON: + case AFE_MOD_DAI_END: + case AFE_MOD_DAI_CUR: + case AFE_VUL_D2_END: + case AFE_VUL_D2_CUR: + case AFE_DL3_CUR: + case AFE_DL3_END: + case AFE_HDMI_OUT_CON0: + case AFE_HDMI_OUT_CUR: + case AFE_HDMI_OUT_END: + case AFE_IRQ3_MCU_CNT_MON: + case AFE_IRQ4_MCU_CNT_MON: + case AFE_IRQ_MCU_STATUS: + case AFE_IRQ_MCU_CLR: + case AFE_IRQ_MCU_MON2: + case AFE_IRQ1_MCU_CNT_MON: + case AFE_IRQ2_MCU_CNT_MON: + case AFE_IRQ1_MCU_EN_CNT_MON: + case AFE_IRQ5_MCU_CNT_MON: + case AFE_IRQ7_MCU_CNT_MON: + case AFE_GAIN1_CUR: + case AFE_GAIN2_CUR: + case AFE_SRAM_DELSEL_CON0: + case AFE_SRAM_DELSEL_CON2: + case AFE_SRAM_DELSEL_CON3: + case AFE_ASRC_2CH_CON12: + case AFE_ASRC_2CH_CON13: + case PCM_INTF_CON2: + case FPGA_CFG0: + case FPGA_CFG1: + case FPGA_CFG2: + case FPGA_CFG3: + case AUDIO_TOP_DBG_MON0: + case AUDIO_TOP_DBG_MON1: + case AFE_IRQ8_MCU_CNT_MON: + case AFE_IRQ11_MCU_CNT_MON: + case AFE_IRQ12_MCU_CNT_MON: + case AFE_CBIP_MON0: + case AFE_CBIP_SLV_MUX_MON0: + case AFE_CBIP_SLV_DECODER_MON0: + case AFE_ADDA6_SRC_DEBUG_MON0: + case AFE_ADD6A_UL_SRC_MON0: + case AFE_ADDA6_UL_SRC_MON1: + case AFE_DL1_CUR_MSB: + case AFE_DL2_CUR_MSB: + case AFE_AWB_CUR_MSB: + case AFE_VUL_CUR_MSB: + case AFE_VUL2_CUR_MSB: + case AFE_MOD_DAI_CUR_MSB: + case AFE_VUL_D2_CUR_MSB: + case AFE_DL3_CUR_MSB: + case AFE_HDMI_OUT_CUR_MSB: + case AFE_AWB2_END: + case AFE_AWB2_CUR: + case AFE_AWB2_CUR_MSB: + case AFE_ADDA_DL_SDM_FIFO_MON: + case AFE_ADDA_DL_SRC_LCH_MON: + case AFE_ADDA_DL_SRC_RCH_MON: + case AFE_ADDA_DL_SDM_OUT_MON: + case AFE_CONNSYS_I2S_MON: + case AFE_ASRC_2CH_CON0: + case AFE_ASRC_2CH_CON2: + case AFE_ASRC_2CH_CON3: + case AFE_ASRC_2CH_CON4: + case AFE_ASRC_2CH_CON5: + case AFE_ASRC_2CH_CON7: + case AFE_ASRC_2CH_CON8: + case AFE_MEMIF_MON12: + case AFE_MEMIF_MON13: + case AFE_MEMIF_MON14: + case AFE_MEMIF_MON15: + case AFE_MEMIF_MON16: + case AFE_MEMIF_MON17: + case AFE_MEMIF_MON18: + case AFE_MEMIF_MON19: + case AFE_MEMIF_MON20: + case AFE_MEMIF_MON21: + case AFE_MEMIF_MON22: + case AFE_MEMIF_MON23: + case AFE_MEMIF_MON24: + case AFE_ADDA_MTKAIF_MON0: + case AFE_ADDA_MTKAIF_MON1: + case AFE_AUD_PAD_TOP: + case AFE_GENERAL1_ASRC_2CH_CON0: + case AFE_GENERAL1_ASRC_2CH_CON2: + case AFE_GENERAL1_ASRC_2CH_CON3: + case AFE_GENERAL1_ASRC_2CH_CON4: + case AFE_GENERAL1_ASRC_2CH_CON5: + case AFE_GENERAL1_ASRC_2CH_CON7: + case AFE_GENERAL1_ASRC_2CH_CON8: + case AFE_GENERAL1_ASRC_2CH_CON12: + case AFE_GENERAL1_ASRC_2CH_CON13: + case AFE_GENERAL2_ASRC_2CH_CON0: + case AFE_GENERAL2_ASRC_2CH_CON2: + case AFE_GENERAL2_ASRC_2CH_CON3: + case AFE_GENERAL2_ASRC_2CH_CON4: + case AFE_GENERAL2_ASRC_2CH_CON5: + case AFE_GENERAL2_ASRC_2CH_CON7: + case AFE_GENERAL2_ASRC_2CH_CON8: + case AFE_GENERAL2_ASRC_2CH_CON12: + case AFE_GENERAL2_ASRC_2CH_CON13: + return true; + default: + return false; + }; +} + +static const struct regmap_config mt8183_afe_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .volatile_reg = mt8183_is_volatile_reg, + + .max_register = AFE_MAX_REGISTER, + .num_reg_defaults_raw = AFE_MAX_REGISTER, + + .cache_type = REGCACHE_FLAT, +}; + +static irqreturn_t mt8183_afe_irq_handler(int irq_id, void *dev) +{ + struct mtk_base_afe *afe = dev; + struct mtk_base_afe_irq *irq; + unsigned int status; + unsigned int status_mcu; + unsigned int mcu_en; + int ret; + int i; + irqreturn_t irq_ret = IRQ_HANDLED; + + /* get irq that is sent to MCU */ + regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en); + + ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status); + /* only care IRQ which is sent to MCU */ + status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS; + + if (ret || status_mcu == 0) { + dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n", + __func__, ret, status, mcu_en); + + irq_ret = IRQ_NONE; + goto err_irq; + } + + for (i = 0; i < MT8183_MEMIF_NUM; i++) { + struct mtk_base_afe_memif *memif = &afe->memif[i]; + + if (!memif->substream) + continue; + + if (memif->irq_usage < 0) + continue; + + irq = &afe->irqs[memif->irq_usage]; + + if (status_mcu & (1 << irq->irq_data->irq_en_shift)) + snd_pcm_period_elapsed(memif->substream); + } + +err_irq: + /* clear irq */ + regmap_write(afe->regmap, + AFE_IRQ_MCU_CLR, + status_mcu); + + return irq_ret; +} + +static int mt8183_afe_runtime_suspend(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + unsigned int value; + int ret; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + /* disable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, AFE_ON_MASK_SFT, 0x0); + + ret = regmap_read_poll_timeout(afe->regmap, + AFE_DAC_MON, + value, + (value & AFE_ON_RETM_MASK_SFT) == 0, + 20, + 1 * 1000 * 1000); + if (ret) + dev_warn(afe->dev, "%s(), ret %d\n", __func__, ret); + + /* make sure all irq status are cleared, twice intended */ + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff); + regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff); + + /* cache only */ + regcache_cache_only(afe->regmap, true); + regcache_mark_dirty(afe->regmap); + +skip_regmap: + return mt8183_afe_disable_clock(afe); +} + +static int mt8183_afe_runtime_resume(struct device *dev) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int ret; + + ret = mt8183_afe_enable_clock(afe); + if (ret) + return ret; + + if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl) + goto skip_regmap; + + regcache_cache_only(afe->regmap, false); + regcache_sync(afe->regmap); + + /* enable audio sys DCM for power saving */ + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, 0x1 << 29, 0x1 << 29); + + /* force cpu use 8_24 format when writing 32bit data */ + regmap_update_bits(afe->regmap, AFE_MEMIF_MSB, + CPU_HD_ALIGN_MASK_SFT, 0 << CPU_HD_ALIGN_SFT); + + /* set all output port to 24bit */ + regmap_write(afe->regmap, AFE_CONN_24BIT, 0xffffffff); + regmap_write(afe->regmap, AFE_CONN_24BIT_1, 0xffffffff); + + /* enable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); + +skip_regmap: + return 0; +} + +static int mt8183_afe_component_probe(struct snd_soc_component *component) +{ + return mtk_afe_add_sub_dai_control(component); +} + +static const struct snd_soc_component_driver mt8183_afe_component = { + .name = AFE_PCM_NAME, + .ops = &mtk_afe_pcm_ops, + .pcm_new = mtk_afe_pcm_new, + .pcm_free = mtk_afe_pcm_free, + .probe = mt8183_afe_component_probe, +}; + +static int mt8183_dai_memif_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mt8183_memif_dai_driver; + dai->num_dai_drivers = ARRAY_SIZE(mt8183_memif_dai_driver); + + dai->dapm_widgets = mt8183_memif_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mt8183_memif_widgets); + dai->dapm_routes = mt8183_memif_routes; + dai->num_dapm_routes = ARRAY_SIZE(mt8183_memif_routes); + return 0; +} + +typedef int (*dai_register_cb)(struct mtk_base_afe *); +static const dai_register_cb dai_register_cbs[] = { + mt8183_dai_adda_register, + mt8183_dai_i2s_register, + mt8183_dai_pcm_register, + mt8183_dai_tdm_register, + mt8183_dai_hostless_register, + mt8183_dai_memif_register, +}; + +static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev) +{ + struct mtk_base_afe *afe; + struct mt8183_afe_private *afe_priv; + struct device *dev; + int i, irq_id, ret; + + afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + platform_set_drvdata(pdev, afe); + + afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), + GFP_KERNEL); + if (!afe->platform_priv) + return -ENOMEM; + + afe_priv = afe->platform_priv; + afe->dev = &pdev->dev; + dev = afe->dev; + + /* initial audio related clock */ + ret = mt8183_init_clock(afe); + if (ret) { + dev_err(dev, "init clock error\n"); + return ret; + } + + pm_runtime_enable(dev); + + /* regmap init */ + afe->regmap = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(afe->regmap)) { + dev_err(dev, "could not get regmap from parent\n"); + return PTR_ERR(afe->regmap); + } + ret = regmap_attach_dev(dev, afe->regmap, &mt8183_afe_regmap_config); + if (ret) { + dev_warn(dev, "regmap_attach_dev fail, ret %d\n", ret); + return ret; + } + + /* enable clock for regcache get default value from hw */ + afe_priv->pm_runtime_bypass_reg_ctl = true; + pm_runtime_get_sync(&pdev->dev); + + ret = regmap_reinit_cache(afe->regmap, &mt8183_afe_regmap_config); + if (ret) { + dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret); + return ret; + } + + pm_runtime_put_sync(&pdev->dev); + afe_priv->pm_runtime_bypass_reg_ctl = false; + + regcache_cache_only(afe->regmap, true); + regcache_mark_dirty(afe->regmap); + + pm_runtime_get_sync(&pdev->dev); + + /* init memif */ + afe->memif_size = MT8183_MEMIF_NUM; + afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), + GFP_KERNEL); + if (!afe->memif) + return -ENOMEM; + + for (i = 0; i < afe->memif_size; i++) { + afe->memif[i].data = &memif_data[i]; + afe->memif[i].irq_usage = -1; + } + + afe->memif[MT8183_MEMIF_HDMI].irq_usage = MT8183_IRQ_8; + afe->memif[MT8183_MEMIF_HDMI].const_irq = 1; + + mutex_init(&afe->irq_alloc_lock); + + /* init memif */ + /* irq initialize */ + afe->irqs_size = MT8183_IRQ_NUM; + afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), + GFP_KERNEL); + if (!afe->irqs) + return -ENOMEM; + + for (i = 0; i < afe->irqs_size; i++) + afe->irqs[i].irq_data = &irq_data[i]; + + /* request irq */ + irq_id = platform_get_irq(pdev, 0); + if (!irq_id) { + dev_err(dev, "%s no irq found\n", dev->of_node->name); + return -ENXIO; + } + ret = devm_request_irq(dev, irq_id, mt8183_afe_irq_handler, + IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); + if (ret) { + dev_err(dev, "could not request_irq for asys-isr\n"); + return ret; + } + + /* init sub_dais */ + INIT_LIST_HEAD(&afe->sub_dais); + + for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) { + ret = dai_register_cbs[i](afe); + if (ret) { + dev_warn(afe->dev, "dai register i %d fail, ret %d\n", + i, ret); + return ret; + } + } + + /* init dai_driver and component_driver */ + ret = mtk_afe_combine_sub_dai(afe); + if (ret) { + dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n", + ret); + return ret; + } + + afe->mtk_afe_hardware = &mt8183_afe_hardware; + afe->memif_fs = mt8183_memif_fs; + afe->irq_fs = mt8183_irq_fs; + + afe->runtime_resume = mt8183_afe_runtime_resume; + afe->runtime_suspend = mt8183_afe_runtime_suspend; + + /* register component */ + ret = devm_snd_soc_register_component(&pdev->dev, + &mt8183_afe_component, + NULL, 0); + if (ret) { + dev_warn(dev, "err_platform\n"); + return ret; + } + + ret = devm_snd_soc_register_component(afe->dev, + &mt8183_afe_pcm_dai_component, + afe->dai_drivers, + afe->num_dai_drivers); + if (ret) { + dev_warn(dev, "err_dai_component\n"); + return ret; + } + + return ret; +} + +static int mt8183_afe_pcm_dev_remove(struct platform_device *pdev) +{ + pm_runtime_put_sync(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + mt8183_afe_runtime_suspend(&pdev->dev); + return 0; +} + +static const struct of_device_id mt8183_afe_pcm_dt_match[] = { + { .compatible = "mediatek,mt8183-audio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt8183_afe_pcm_dt_match); + +static const struct dev_pm_ops mt8183_afe_pm_ops = { + SET_RUNTIME_PM_OPS(mt8183_afe_runtime_suspend, + mt8183_afe_runtime_resume, NULL) +}; + +static struct platform_driver mt8183_afe_pcm_driver = { + .driver = { + .name = "mt8183-audio", + .of_match_table = mt8183_afe_pcm_dt_match, +#ifdef CONFIG_PM + .pm = &mt8183_afe_pm_ops, +#endif + }, + .probe = mt8183_afe_pcm_dev_probe, + .remove = mt8183_afe_pcm_dev_remove, +}; + +module_platform_driver(mt8183_afe_pcm_driver); + +MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 8183"); +MODULE_AUTHOR("KaiChieh Chuang "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-adda.c b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c new file mode 100644 index 000000000000..017d7d1d9148 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-adda.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI ADDA Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include "mt8183-afe-common.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" + +enum { + AUDIO_SDM_LEVEL_MUTE = 0, + AUDIO_SDM_LEVEL_NORMAL = 0x1d, + /* if you change level normal */ + /* you need to change formula of hp impedance and dc trim too */ +}; + +enum { + DELAY_DATA_MISO1 = 0, + DELAY_DATA_MISO2, +}; + +enum { + MTK_AFE_ADDA_DL_RATE_8K = 0, + MTK_AFE_ADDA_DL_RATE_11K = 1, + MTK_AFE_ADDA_DL_RATE_12K = 2, + MTK_AFE_ADDA_DL_RATE_16K = 3, + MTK_AFE_ADDA_DL_RATE_22K = 4, + MTK_AFE_ADDA_DL_RATE_24K = 5, + MTK_AFE_ADDA_DL_RATE_32K = 6, + MTK_AFE_ADDA_DL_RATE_44K = 7, + MTK_AFE_ADDA_DL_RATE_48K = 8, + MTK_AFE_ADDA_DL_RATE_96K = 9, + MTK_AFE_ADDA_DL_RATE_192K = 10, +}; + +enum { + MTK_AFE_ADDA_UL_RATE_8K = 0, + MTK_AFE_ADDA_UL_RATE_16K = 1, + MTK_AFE_ADDA_UL_RATE_32K = 2, + MTK_AFE_ADDA_UL_RATE_48K = 3, + MTK_AFE_ADDA_UL_RATE_96K = 4, + MTK_AFE_ADDA_UL_RATE_192K = 5, + MTK_AFE_ADDA_UL_RATE_48K_HD = 6, +}; + +static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_DL_RATE_8K; + case 11025: + return MTK_AFE_ADDA_DL_RATE_11K; + case 12000: + return MTK_AFE_ADDA_DL_RATE_12K; + case 16000: + return MTK_AFE_ADDA_DL_RATE_16K; + case 22050: + return MTK_AFE_ADDA_DL_RATE_22K; + case 24000: + return MTK_AFE_ADDA_DL_RATE_24K; + case 32000: + return MTK_AFE_ADDA_DL_RATE_32K; + case 44100: + return MTK_AFE_ADDA_DL_RATE_44K; + case 48000: + return MTK_AFE_ADDA_DL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_DL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_DL_RATE_192K; + default: + dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_ADDA_DL_RATE_48K; + } +} + +static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe, + unsigned int rate) +{ + switch (rate) { + case 8000: + return MTK_AFE_ADDA_UL_RATE_8K; + case 16000: + return MTK_AFE_ADDA_UL_RATE_16K; + case 32000: + return MTK_AFE_ADDA_UL_RATE_32K; + case 48000: + return MTK_AFE_ADDA_UL_RATE_48K; + case 96000: + return MTK_AFE_ADDA_UL_RATE_96K; + case 192000: + return MTK_AFE_ADDA_UL_RATE_192K; + default: + dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", + __func__, rate); + return MTK_AFE_ADDA_UL_RATE_48K; + } +} + +/* dai component */ +static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN3, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN3, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN3, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN3, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN3, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN3, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN4, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN4, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN4, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN4, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN4, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN4, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN4, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN4, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN4, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN4, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN4, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN4, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* update setting to dmic */ + if (afe_priv->mtkaif_dmic) { + /* mtkaif_rxif_data_mode = 1, dmic */ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + 0x1, 0x1); + + /* dmic mode, 3.25M*/ + regmap_update_bits(afe->regmap, AFE_ADDA_MTKAIF_RX_CFG0, + 0x0, 0xf << 20); + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, + 0x0, 0x1 << 5); + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, + 0x0, 0x3 << 14); + + /* turn on dmic, ch1, ch2 */ + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, + 0x1 << 1, 0x1 << 1); + regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, + 0x3 << 21, 0x3 << 21); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 135); + + /* reset dmic */ + afe_priv->mtkaif_dmic = 0; + break; + default: + break; + } + + return 0; +} + +/* mtkaif dmic */ +static const char * const mt8183_adda_off_on_str[] = { + "Off", "On" +}; + +static const struct soc_enum mt8183_adda_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8183_adda_off_on_str), + mt8183_adda_off_on_str), +}; + +static int mt8183_adda_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + + ucontrol->value.integer.value[0] = afe_priv->mtkaif_dmic; + + return 0; +} + +static int mt8183_adda_dmic_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + afe_priv->mtkaif_dmic = ucontrol->value.integer.value[0]; + + dev_info(afe->dev, "%s(), kcontrol name %s, mtkaif_dmic %d\n", + __func__, kcontrol->id.name, afe_priv->mtkaif_dmic); + + return 0; +} + +static const struct snd_kcontrol_new mtk_adda_controls[] = { + SOC_ENUM_EXT("MTKAIF_DMIC", mt8183_adda_enum[0], + mt8183_adda_dmic_get, mt8183_adda_dmic_set), +}; + +enum { + SUPPLY_SEQ_ADDA_AFE_ON, + SUPPLY_SEQ_ADDA_DL_ON, + SUPPLY_SEQ_ADDA_UL_ON, +}; + +static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { + /* adda */ + SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch1_mix, + ARRAY_SIZE(mtk_adda_dl_ch1_mix)), + SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0, + mtk_adda_dl_ch2_mix, + ARRAY_SIZE(mtk_adda_dl_ch2_mix)), + + SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON, + AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON, + AFE_ADDA_DL_SRC2_CON0, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, + AFE_ADDA_UL_SRC_CON0, + UL_SRC_ON_TMP_CTL_SFT, 0, + mtk_adda_ul_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_dac_predis_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("aud_adc_clk"), + SND_SOC_DAPM_CLOCK_SUPPLY("mtkaif_26m_clk"), +}; + +static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { + /* playback */ + {"ADDA_DL_CH1", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH1", "DL1"}, + {"ADDA_DL_CH2", "DL1_CH2", "DL1"}, + + {"ADDA_DL_CH1", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH1", "DL2"}, + {"ADDA_DL_CH2", "DL2_CH2", "DL2"}, + + {"ADDA_DL_CH1", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH1", "DL3"}, + {"ADDA_DL_CH2", "DL3_CH2", "DL3"}, + + {"ADDA Playback", NULL, "ADDA_DL_CH1"}, + {"ADDA Playback", NULL, "ADDA_DL_CH2"}, + + /* adda enable */ + {"ADDA Playback", NULL, "ADDA Enable"}, + {"ADDA Playback", NULL, "ADDA Playback Enable"}, + {"ADDA Capture", NULL, "ADDA Enable"}, + {"ADDA Capture", NULL, "ADDA Capture Enable"}, + + /* clk */ + {"ADDA Playback", NULL, "mtkaif_26m_clk"}, + {"ADDA Playback", NULL, "aud_dac_clk"}, + {"ADDA Playback", NULL, "aud_dac_predis_clk"}, + + {"ADDA Capture", NULL, "mtkaif_26m_clk"}, + {"ADDA Capture", NULL, "aud_adc_clk"}, +}; + +static int set_mtkaif_rx(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int delay_data; + int delay_cycle; + + switch (afe_priv->mtkaif_protocol) { + case MT8183_MTKAIF_PROTOCOL_2_CLK_P2: + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x38); + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x39); + /* mtkaif_rxif_clkinv_adc inverse for calibration */ + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, + 0x80010000); + + if (afe_priv->mtkaif_phase_cycle[0] >= + afe_priv->mtkaif_phase_cycle[1]) { + delay_data = DELAY_DATA_MISO1; + delay_cycle = afe_priv->mtkaif_phase_cycle[0] - + afe_priv->mtkaif_phase_cycle[1]; + } else { + delay_data = DELAY_DATA_MISO2; + delay_cycle = afe_priv->mtkaif_phase_cycle[1] - + afe_priv->mtkaif_phase_cycle[0]; + } + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_DATA_MASK_SFT, + delay_data << MTKAIF_RXIF_DELAY_DATA_SFT); + + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG2, + MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT, + delay_cycle << MTKAIF_RXIF_DELAY_CYCLE_SFT); + break; + case MT8183_MTKAIF_PROTOCOL_2: + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31); + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, + 0x00010000); + break; + case MT8183_MTKAIF_PROTOCOL_1: + regmap_write(afe->regmap, AFE_AUD_PAD_TOP, 0x31); + regmap_write(afe->regmap, AFE_ADDA_MTKAIF_CFG0, 0x0); + default: + break; + } + + return 0; +} + +/* dai ops */ +static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", + __func__, dai->id, substream->stream, rate); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + unsigned int dl_src2_con0 = 0; + unsigned int dl_src2_con1 = 0; + + /* clean predistortion */ + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0); + regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0); + + /* set sampling rate */ + dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28; + + /* set output mode */ + switch (rate) { + case 192000: + dl_src2_con0 |= (0x1 << 24); /* UP_SAMPLING_RATE_X2 */ + dl_src2_con0 |= 1 << 14; + break; + case 96000: + dl_src2_con0 |= (0x2 << 24); /* UP_SAMPLING_RATE_X4 */ + dl_src2_con0 |= 1 << 14; + break; + default: + dl_src2_con0 |= (0x3 << 24); /* UP_SAMPLING_RATE_X8 */ + break; + } + + /* turn off mute function */ + dl_src2_con0 |= (0x03 << 11); + + /* set voice input data if input sample rate is 8k or 16k */ + if (rate == 8000 || rate == 16000) + dl_src2_con0 |= 0x01 << 5; + + /* SA suggest apply -0.3db to audio/speech path */ + dl_src2_con1 = 0xf74f0000; + + /* turn on down-link gain */ + dl_src2_con0 = dl_src2_con0 | (0x01 << 1); + + regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON0, dl_src2_con0); + regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON1, dl_src2_con1); + + /* set sdm gain */ + regmap_update_bits(afe->regmap, + AFE_ADDA_DL_SDM_DCCOMP_CON, + ATTGAIN_CTL_MASK_SFT, + AUDIO_SDM_LEVEL_NORMAL << ATTGAIN_CTL_SFT); + } else { + unsigned int voice_mode = 0; + unsigned int ul_src_con0 = 0; /* default value */ + + /* set mtkaif protocol */ + set_mtkaif_rx(afe); + + /* Using Internal ADC */ + regmap_update_bits(afe->regmap, + AFE_ADDA_TOP_CON0, + 0x1 << 0, + 0x0 << 0); + + voice_mode = adda_ul_rate_transform(afe, rate); + + ul_src_con0 |= (voice_mode << 17) & (0x7 << 17); + + regmap_write(afe->regmap, AFE_ADDA_UL_SRC_CON0, ul_src_con0); + + /* mtkaif_rxif_data_mode = 0, amic */ + regmap_update_bits(afe->regmap, + AFE_ADDA_MTKAIF_RX_CFG0, + 0x1 << 0, + 0x0 << 0); + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_adda_ops = { + .hw_params = mtk_dai_adda_hw_params, +}; + +/* dai driver */ +#define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_adda_driver[] = { + { + .name = "ADDA", + .id = MT8183_DAI_ADDA, + .playback = { + .stream_name = "ADDA Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_PLAYBACK_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .capture = { + .stream_name = "ADDA Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_ADDA_CAPTURE_RATES, + .formats = MTK_ADDA_FORMATS, + }, + .ops = &mtk_dai_adda_ops, + }, +}; + +int mt8183_dai_adda_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_adda_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver); + + dai->controls = mtk_adda_controls; + dai->num_controls = ARRAY_SIZE(mtk_adda_controls); + dai->dapm_widgets = mtk_dai_adda_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets); + dai->dapm_routes = mtk_dai_adda_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes); + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-hostless.c b/sound/soc/mediatek/mt8183/mt8183-dai-hostless.c new file mode 100644 index 000000000000..1667ad352d34 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-hostless.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI Hostless Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include "mt8183-afe-common.h" + +/* dai component */ +static const struct snd_soc_dapm_route mtk_dai_hostless_routes[] = { + /* Hostless ADDA Loopback */ + {"ADDA_DL_CH1", "ADDA_UL_CH1", "Hostless LPBK DL"}, + {"ADDA_DL_CH1", "ADDA_UL_CH2", "Hostless LPBK DL"}, + {"ADDA_DL_CH2", "ADDA_UL_CH1", "Hostless LPBK DL"}, + {"ADDA_DL_CH2", "ADDA_UL_CH2", "Hostless LPBK DL"}, + {"Hostless LPBK UL", NULL, "ADDA Capture"}, + + /* Hostless Speech */ + {"ADDA_DL_CH1", "PCM_1_CAP_CH1", "Hostless Speech DL"}, + {"ADDA_DL_CH2", "PCM_1_CAP_CH1", "Hostless Speech DL"}, + {"ADDA_DL_CH2", "PCM_1_CAP_CH2", "Hostless Speech DL"}, + {"ADDA_DL_CH1", "PCM_2_CAP_CH1", "Hostless Speech DL"}, + {"ADDA_DL_CH2", "PCM_2_CAP_CH1", "Hostless Speech DL"}, + {"ADDA_DL_CH2", "PCM_2_CAP_CH2", "Hostless Speech DL"}, + {"PCM_1_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"}, + {"PCM_1_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"}, + {"PCM_2_PB_CH1", "ADDA_UL_CH1", "Hostless Speech DL"}, + {"PCM_2_PB_CH2", "ADDA_UL_CH2", "Hostless Speech DL"}, + + {"Hostless Speech UL", NULL, "PCM 1 Capture"}, + {"Hostless Speech UL", NULL, "PCM 2 Capture"}, + {"Hostless Speech UL", NULL, "ADDA Capture"}, +}; + +/* dai ops */ +static int mtk_dai_hostless_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + return snd_soc_set_runtime_hwparams(substream, afe->mtk_afe_hardware); +} + +static const struct snd_soc_dai_ops mtk_dai_hostless_ops = { + .startup = mtk_dai_hostless_startup, +}; + +/* dai driver */ +#define MTK_HOSTLESS_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_HOSTLESS_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = { + { + .name = "Hostless LPBK DAI", + .id = MT8183_DAI_HOSTLESS_LPBK, + .playback = { + .stream_name = "Hostless LPBK DL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .capture = { + .stream_name = "Hostless LPBK UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, + { + .name = "Hostless Speech DAI", + .id = MT8183_DAI_HOSTLESS_SPEECH, + .playback = { + .stream_name = "Hostless Speech DL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .capture = { + .stream_name = "Hostless Speech UL", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_HOSTLESS_RATES, + .formats = MTK_HOSTLESS_FORMATS, + }, + .ops = &mtk_dai_hostless_ops, + }, +}; + +int mt8183_dai_hostless_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_hostless_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver); + + dai->dapm_routes = mtk_dai_hostless_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes); + + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c new file mode 100644 index 000000000000..c25024f72e72 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c @@ -0,0 +1,1040 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI I2S Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include +#include "mt8183-afe-clk.h" +#include "mt8183-afe-common.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" + +enum { + I2S_FMT_EIAJ = 0, + I2S_FMT_I2S = 1, +}; + +enum { + I2S_WLEN_16_BIT = 0, + I2S_WLEN_32_BIT = 1, +}; + +enum { + I2S_HD_NORMAL = 0, + I2S_HD_LOW_JITTER = 1, +}; + +enum { + I2S1_SEL_O28_O29 = 0, + I2S1_SEL_O03_O04 = 1, +}; + +enum { + I2S_IN_PAD_CONNSYS = 0, + I2S_IN_PAD_IO_MUX = 1, +}; + +struct mtk_afe_i2s_priv { + int id; + int rate; /* for determine which apll to use */ + int low_jitter_en; + + const char *share_property_name; + int share_i2s_id; + + int mclk_id; + int mclk_rate; + int mclk_apll; +}; + +static unsigned int get_i2s_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + I2S_WLEN_16_BIT : I2S_WLEN_32_BIT; +} + +#define MTK_AFE_I2S0_KCONTROL_NAME "I2S0_HD_Mux" +#define MTK_AFE_I2S1_KCONTROL_NAME "I2S1_HD_Mux" +#define MTK_AFE_I2S2_KCONTROL_NAME "I2S2_HD_Mux" +#define MTK_AFE_I2S3_KCONTROL_NAME "I2S3_HD_Mux" +#define MTK_AFE_I2S5_KCONTROL_NAME "I2S5_HD_Mux" + +#define I2S0_HD_EN_W_NAME "I2S0_HD_EN" +#define I2S1_HD_EN_W_NAME "I2S1_HD_EN" +#define I2S2_HD_EN_W_NAME "I2S2_HD_EN" +#define I2S3_HD_EN_W_NAME "I2S3_HD_EN" +#define I2S5_HD_EN_W_NAME "I2S5_HD_EN" + +#define I2S0_MCLK_EN_W_NAME "I2S0_MCLK_EN" +#define I2S1_MCLK_EN_W_NAME "I2S1_MCLK_EN" +#define I2S2_MCLK_EN_W_NAME "I2S2_MCLK_EN" +#define I2S3_MCLK_EN_W_NAME "I2S3_MCLK_EN" +#define I2S5_MCLK_EN_W_NAME "I2S5_MCLK_EN" + +static int get_i2s_id_by_name(struct mtk_base_afe *afe, + const char *name) +{ + if (strncmp(name, "I2S0", 4) == 0) + return MT8183_DAI_I2S_0; + else if (strncmp(name, "I2S1", 4) == 0) + return MT8183_DAI_I2S_1; + else if (strncmp(name, "I2S2", 4) == 0) + return MT8183_DAI_I2S_2; + else if (strncmp(name, "I2S3", 4) == 0) + return MT8183_DAI_I2S_3; + else if (strncmp(name, "I2S5", 4) == 0) + return MT8183_DAI_I2S_5; + else + return -EINVAL; +} + +static struct mtk_afe_i2s_priv *get_i2s_priv_by_name(struct mtk_base_afe *afe, + const char *name) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int dai_id = get_i2s_id_by_name(afe, name); + + if (dai_id < 0) + return NULL; + + return afe_priv->dai_priv[dai_id]; +} + +/* low jitter control */ +static const char * const mt8183_i2s_hd_str[] = { + "Normal", "Low_Jitter" +}; + +static const struct soc_enum mt8183_i2s_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mt8183_i2s_hd_str), + mt8183_i2s_hd_str), +}; + +static int mt8183_i2s_hd_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = i2s_priv->low_jitter_en; + + return 0; +} + +static int mt8183_i2s_hd_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int hd_en; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + hd_en = ucontrol->value.integer.value[0]; + + dev_info(afe->dev, "%s(), kcontrol name %s, hd_en %d\n", + __func__, kcontrol->id.name, hd_en); + + i2s_priv = get_i2s_priv_by_name(afe, kcontrol->id.name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + i2s_priv->low_jitter_en = hd_en; + + return 0; +} + +static const struct snd_kcontrol_new mtk_dai_i2s_controls[] = { + SOC_ENUM_EXT(MTK_AFE_I2S0_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S1_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S2_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S3_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), + SOC_ENUM_EXT(MTK_AFE_I2S5_KCONTROL_NAME, mt8183_i2s_enum[0], + mt8183_i2s_hd_get, mt8183_i2s_hd_set), +}; + +/* dai component */ +/* interconnection */ +static const struct snd_kcontrol_new mtk_i2s3_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN0, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN0, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN0, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN0, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN0, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN0, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s3_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN1, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN1, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN1, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN1, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN1, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN1, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN1, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN1, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN28, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN28, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN28, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN28, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN28, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN28, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s1_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN29, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN29, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN29, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN29, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN29, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN29, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN29, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN29, + I_PCM_2_CAP_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s5_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN30, I_DL1_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN30, I_DL2_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN30, I_DL3_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN30, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN30, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN30, + I_PCM_2_CAP_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_i2s5_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN31, I_DL1_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN31, I_DL2_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN31, I_DL3_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN31, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN31, + I_PCM_1_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN31, + I_PCM_2_CAP_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN31, + I_PCM_1_CAP_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN31, + I_PCM_2_CAP_CH2, 1, 0), +}; + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_I2S_MCLK_EN, + SUPPLY_SEQ_I2S_HD_EN, + SUPPLY_SEQ_I2S_EN, +}; + +static int mtk_apll_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8183_apll1_enable(afe); + else + mt8183_apll2_enable(afe); + break; + case SND_SOC_DAPM_POST_PMD: + if (strcmp(w->name, APLL1_W_NAME) == 0) + mt8183_apll1_disable(afe); + else + mt8183_apll2_disable(afe); + break; + default: + break; + } + + return 0; +} + +static int mtk_mclk_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8183_mck_enable(afe, i2s_priv->mclk_id, i2s_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + i2s_priv->mclk_rate = 0; + mt8183_mck_disable(afe, i2s_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_i2s_widgets[] = { + SND_SOC_DAPM_MIXER("I2S1_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch1_mix, + ARRAY_SIZE(mtk_i2s1_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S1_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s1_ch2_mix, + ARRAY_SIZE(mtk_i2s1_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S3_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch1_mix, + ARRAY_SIZE(mtk_i2s3_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S3_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s3_ch2_mix, + ARRAY_SIZE(mtk_i2s3_ch2_mix)), + + SND_SOC_DAPM_MIXER("I2S5_CH1", SND_SOC_NOPM, 0, 0, + mtk_i2s5_ch1_mix, + ARRAY_SIZE(mtk_i2s5_ch1_mix)), + SND_SOC_DAPM_MIXER("I2S5_CH2", SND_SOC_NOPM, 0, 0, + mtk_i2s5_ch2_mix, + ARRAY_SIZE(mtk_i2s5_ch2_mix)), + + /* i2s en*/ + SND_SOC_DAPM_SUPPLY_S("I2S0_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON, I2S_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S1_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON1, I2S_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON2, I2S_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S3_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON3, I2S_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S5_EN", SUPPLY_SEQ_I2S_EN, + AFE_I2S_CON4, I2S5_EN_SFT, 0, + NULL, 0), + /* i2s hd en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON, I2S1_HD_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S1_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON1, I2S2_HD_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S2_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON2, I2S3_HD_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S3_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON3, I2S4_HD_EN_SFT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY_S(I2S5_HD_EN_W_NAME, SUPPLY_SEQ_I2S_HD_EN, + AFE_I2S_CON4, I2S5_HD_EN_SFT, 0, + NULL, 0), + + /* i2s mclk en */ + SND_SOC_DAPM_SUPPLY_S(I2S0_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S1_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S2_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S3_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(I2S5_MCLK_EN_W_NAME, SUPPLY_SEQ_I2S_MCLK_EN, + SND_SOC_NOPM, 0, 0, + mtk_mclk_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* apll */ + SND_SOC_DAPM_SUPPLY_S(APLL1_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S(APLL2_W_NAME, SUPPLY_SEQ_APLL, + SND_SOC_NOPM, 0, 0, + mtk_apll_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static int mtk_afe_i2s_share_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (i2s_priv->share_i2s_id < 0) + return 0; + + return i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name); +} + +static int mtk_afe_i2s_hd_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + /* check if share i2s need hd en */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return i2s_priv->low_jitter_en; + + return 0; +} + +static int mtk_afe_i2s_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + int i2s_need_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8183_get_apll_by_name(afe, source->name); + + /* choose APLL from i2s rate */ + i2s_need_apll = mt8183_get_apll_by_rate(afe, i2s_priv->rate); + + return (i2s_need_apll == cur_apll) ? 1 : 0; +} + +static int mtk_afe_i2s_mclk_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + + i2s_priv = get_i2s_priv_by_name(afe, sink->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + if (get_i2s_id_by_name(afe, sink->name) == + get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + /* check if share i2s need mclk */ + if (i2s_priv->share_i2s_id < 0) + return 0; + + if (i2s_priv->share_i2s_id == get_i2s_id_by_name(afe, source->name)) + return (i2s_priv->mclk_rate > 0) ? 1 : 0; + + return 0; +} + +static int mtk_afe_mclk_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mtk_afe_i2s_priv *i2s_priv; + int cur_apll; + + i2s_priv = get_i2s_priv_by_name(afe, w->name); + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return 0; + } + + /* which apll */ + cur_apll = mt8183_get_apll_by_name(afe, source->name); + + return (i2s_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_i2s_routes[] = { + /* i2s0 */ + {"I2S0", NULL, "I2S0_EN"}, + {"I2S0", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S0", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + + {"I2S0", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S0", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S0_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S0", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S0", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S0_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s1 */ + {"I2S1_CH1", "DL1_CH1", "DL1"}, + {"I2S1_CH2", "DL1_CH2", "DL1"}, + + {"I2S1_CH1", "DL2_CH1", "DL2"}, + {"I2S1_CH2", "DL2_CH2", "DL2"}, + + {"I2S1_CH1", "DL3_CH1", "DL3"}, + {"I2S1_CH2", "DL3_CH2", "DL3"}, + + {"I2S1", NULL, "I2S1_CH1"}, + {"I2S1", NULL, "I2S1_CH2"}, + + {"I2S1", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S1_EN"}, + {"I2S1", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S1", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + + {"I2S1", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S1", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S1_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S1", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S1", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S1_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s2 */ + {"I2S2", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S2_EN"}, + {"I2S2", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S2", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + + {"I2S2", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S2", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S2_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S2", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S2", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S2_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s3 */ + {"I2S3_CH1", "DL1_CH1", "DL1"}, + {"I2S3_CH2", "DL1_CH2", "DL1"}, + + {"I2S3_CH1", "DL2_CH1", "DL2"}, + {"I2S3_CH2", "DL2_CH2", "DL2"}, + + {"I2S3_CH1", "DL3_CH1", "DL3"}, + {"I2S3_CH2", "DL3_CH2", "DL3"}, + + {"I2S3", NULL, "I2S3_CH1"}, + {"I2S3", NULL, "I2S3_CH2"}, + + {"I2S3", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S3", NULL, "I2S3_EN"}, + {"I2S3", NULL, "I2S5_EN", mtk_afe_i2s_share_connect}, + + {"I2S3", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S3", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S3_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S3", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S3", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S3_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, + + /* i2s5 */ + {"I2S5_CH1", "DL1_CH1", "DL1"}, + {"I2S5_CH2", "DL1_CH2", "DL1"}, + + {"I2S5_CH1", "DL2_CH1", "DL2"}, + {"I2S5_CH2", "DL2_CH2", "DL2"}, + + {"I2S5_CH1", "DL3_CH1", "DL3"}, + {"I2S5_CH2", "DL3_CH2", "DL3"}, + + {"I2S5", NULL, "I2S5_CH1"}, + {"I2S5", NULL, "I2S5_CH2"}, + + {"I2S5", NULL, "I2S0_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S1_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S2_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S3_EN", mtk_afe_i2s_share_connect}, + {"I2S5", NULL, "I2S5_EN"}, + + {"I2S5", NULL, I2S0_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S1_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S2_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S3_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {"I2S5", NULL, I2S5_HD_EN_W_NAME, mtk_afe_i2s_hd_connect}, + {I2S5_HD_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_i2s_apll_connect}, + {I2S5_HD_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_i2s_apll_connect}, + + {"I2S5", NULL, I2S0_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S1_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S2_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S3_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {"I2S5", NULL, I2S5_MCLK_EN_W_NAME, mtk_afe_i2s_mclk_connect}, + {I2S5_MCLK_EN_W_NAME, NULL, APLL1_W_NAME, mtk_afe_mclk_apll_connect}, + {I2S5_MCLK_EN_W_NAME, NULL, APLL2_W_NAME, mtk_afe_mclk_apll_connect}, +}; + +/* dai ops */ +static int mtk_dai_i2s_config(struct mtk_base_afe *afe, + struct snd_pcm_hw_params *params, + int i2s_id) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[i2s_id]; + + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8183_rate_transform(afe->dev, + rate, i2s_id); + snd_pcm_format_t format = params_format(params); + unsigned int i2s_con = 0; + int ret = 0; + + dev_info(afe->dev, "%s(), id %d, rate %d, format %d\n", + __func__, + i2s_id, + rate, format); + + if (i2s_priv) + i2s_priv->rate = rate; + else + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + + switch (i2s_id) { + case MT8183_DAI_I2S_0: + regmap_update_bits(afe->regmap, AFE_DAC_CON1, + I2S_MODE_MASK_SFT, rate_reg << I2S_MODE_SFT); + i2s_con = I2S_IN_PAD_IO_MUX << I2SIN_PAD_SEL_SFT; + i2s_con |= I2S_FMT_I2S << I2S_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON, + 0xffffeffe, i2s_con); + break; + case MT8183_DAI_I2S_1: + i2s_con = I2S1_SEL_O28_O29 << I2S2_SEL_O03_O04_SFT; + i2s_con |= rate_reg << I2S2_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S2_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S2_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON1, + 0xffffeffe, i2s_con); + break; + case MT8183_DAI_I2S_2: + i2s_con = 8 << I2S3_UPDATE_WORD_SFT; + i2s_con |= rate_reg << I2S3_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S3_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S3_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON2, + 0xffffeffe, i2s_con); + break; + case MT8183_DAI_I2S_3: + i2s_con = rate_reg << I2S4_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S4_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S4_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON3, + 0xffffeffe, i2s_con); + break; + case MT8183_DAI_I2S_5: + i2s_con = rate_reg << I2S5_OUT_MODE_SFT; + i2s_con |= I2S_FMT_I2S << I2S5_FMT_SFT; + i2s_con |= get_i2s_wlen(format) << I2S5_WLEN_SFT; + regmap_update_bits(afe->regmap, AFE_I2S_CON4, + 0xffffeffe, i2s_con); + break; + default: + dev_warn(afe->dev, "%s(), id %d not support\n", + __func__, i2s_id); + return -EINVAL; + } + + /* set share i2s */ + if (i2s_priv && i2s_priv->share_i2s_id >= 0) + ret = mtk_dai_i2s_config(afe, params, i2s_priv->share_i2s_id); + + return ret; +} + +static int mtk_dai_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + return mtk_dai_i2s_config(afe, params, dai->id); +} + +static int mtk_dai_i2s_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv = afe_priv->dai_priv[dai->id]; + int apll; + int apll_rate; + + if (!i2s_priv) { + dev_warn(afe->dev, "%s(), i2s_priv == NULL", __func__); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_OUT) { + dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); + return -EINVAL; + } + + dev_info(afe->dev, "%s(), freq %d\n", __func__, freq); + + apll = mt8183_get_apll_by_rate(afe, freq); + apll_rate = mt8183_get_apll_rate(afe, apll); + + if (freq > apll_rate) { + dev_warn(afe->dev, "%s(), freq > apll rate", __func__); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + dev_warn(afe->dev, "%s(), APLL cannot generate freq Hz", + __func__); + return -EINVAL; + } + + i2s_priv->mclk_rate = freq; + i2s_priv->mclk_apll = apll; + + if (i2s_priv->share_i2s_id > 0) { + struct mtk_afe_i2s_priv *share_i2s_priv; + + share_i2s_priv = afe_priv->dai_priv[i2s_priv->share_i2s_id]; + if (!share_i2s_priv) { + dev_warn(afe->dev, "%s(), share_i2s_priv == NULL", + __func__); + return -EINVAL; + } + + share_i2s_priv->mclk_rate = i2s_priv->mclk_rate; + share_i2s_priv->mclk_apll = i2s_priv->mclk_apll; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_i2s_ops = { + .hw_params = mtk_dai_i2s_hw_params, + .set_sysclk = mtk_dai_i2s_set_sysclk, +}; + +/* dai driver */ +#define MTK_I2S_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_i2s_driver[] = { + { + .name = "I2S0", + .id = MT8183_DAI_I2S_0, + .capture = { + .stream_name = "I2S0", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S1", + .id = MT8183_DAI_I2S_1, + .playback = { + .stream_name = "I2S1", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S2", + .id = MT8183_DAI_I2S_2, + .capture = { + .stream_name = "I2S2", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S3", + .id = MT8183_DAI_I2S_3, + .playback = { + .stream_name = "I2S3", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, + { + .name = "I2S5", + .id = MT8183_DAI_I2S_5, + .playback = { + .stream_name = "I2S5", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_I2S_RATES, + .formats = MTK_I2S_FORMATS, + }, + .ops = &mtk_dai_i2s_ops, + }, +}; + +/* this enum is merely for mtk_afe_i2s_priv declare */ +enum { + DAI_I2S0 = 0, + DAI_I2S1, + DAI_I2S2, + DAI_I2S3, + DAI_I2S5, + DAI_I2S_NUM, +}; + +static const struct mtk_afe_i2s_priv mt8183_i2s_priv[DAI_I2S_NUM] = { + [DAI_I2S0] = { + .id = MT8183_DAI_I2S_0, + .mclk_id = MT8183_I2S0_MCK, + .share_property_name = "i2s0-share", + .share_i2s_id = -1, + }, + [DAI_I2S1] = { + .id = MT8183_DAI_I2S_1, + .mclk_id = MT8183_I2S1_MCK, + .share_property_name = "i2s1-share", + .share_i2s_id = -1, + }, + [DAI_I2S2] = { + .id = MT8183_DAI_I2S_2, + .mclk_id = MT8183_I2S2_MCK, + .share_property_name = "i2s2-share", + .share_i2s_id = -1, + }, + [DAI_I2S3] = { + .id = MT8183_DAI_I2S_3, + .mclk_id = MT8183_I2S3_MCK, + .share_property_name = "i2s3-share", + .share_i2s_id = -1, + }, + [DAI_I2S5] = { + .id = MT8183_DAI_I2S_5, + .mclk_id = MT8183_I2S5_MCK, + .share_property_name = "i2s5-share", + .share_i2s_id = -1, + }, +}; + +int mt8183_dai_i2s_get_share(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + const struct device_node *of_node = afe->dev->of_node; + const char *of_str; + const char *property_name; + struct mtk_afe_i2s_priv *i2s_priv; + int i; + + for (i = 0; i < DAI_I2S_NUM; i++) { + i2s_priv = afe_priv->dai_priv[mt8183_i2s_priv[i].id]; + property_name = mt8183_i2s_priv[i].share_property_name; + if (of_property_read_string(of_node, property_name, &of_str)) + continue; + i2s_priv->share_i2s_id = get_i2s_id_by_name(afe, of_str); + } + + return 0; +} + +int mt8183_dai_i2s_set_priv(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_i2s_priv *i2s_priv; + int i; + + for (i = 0; i < DAI_I2S_NUM; i++) { + i2s_priv = devm_kzalloc(afe->dev, + sizeof(struct mtk_afe_i2s_priv), + GFP_KERNEL); + if (!i2s_priv) + return -ENOMEM; + + memcpy(i2s_priv, &mt8183_i2s_priv[i], + sizeof(struct mtk_afe_i2s_priv)); + + afe_priv->dai_priv[mt8183_i2s_priv[i].id] = i2s_priv; + } + + return 0; +} + +int mt8183_dai_i2s_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + int ret; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_i2s_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_i2s_driver); + + dai->controls = mtk_dai_i2s_controls; + dai->num_controls = ARRAY_SIZE(mtk_dai_i2s_controls); + dai->dapm_widgets = mtk_dai_i2s_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_i2s_widgets); + dai->dapm_routes = mtk_dai_i2s_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes); + + /* set all dai i2s private data */ + ret = mt8183_dai_i2s_set_priv(afe); + if (ret) + return ret; + + /* parse share i2s */ + ret = mt8183_dai_i2s_get_share(afe); + if (ret) + return ret; + + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c b/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c new file mode 100644 index 000000000000..bc3ba3228f08 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-pcm.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI I2S Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include "mt8183-afe-common.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" + +enum AUD_TX_LCH_RPT { + AUD_TX_LCH_RPT_NO_REPEAT = 0, + AUD_TX_LCH_RPT_REPEAT = 1 +}; + +enum AUD_VBT_16K_MODE { + AUD_VBT_16K_MODE_DISABLE = 0, + AUD_VBT_16K_MODE_ENABLE = 1 +}; + +enum AUD_EXT_MODEM { + AUD_EXT_MODEM_SELECT_INTERNAL = 0, + AUD_EXT_MODEM_SELECT_EXTERNAL = 1 +}; + +enum AUD_PCM_SYNC_TYPE { + /* bck sync length = 1 */ + AUD_PCM_ONE_BCK_CYCLE_SYNC = 0, + /* bck sync length = PCM_INTF_CON1[9:13] */ + AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1 +}; + +enum AUD_BT_MODE { + AUD_BT_MODE_DUAL_MIC_ON_TX = 0, + AUD_BT_MODE_SINGLE_MIC_ON_TX = 1 +}; + +enum AUD_PCM_AFIFO_SRC { + /* slave mode & external modem uses different crystal */ + AUD_PCM_AFIFO_ASRC = 0, + /* slave mode & external modem uses the same crystal */ + AUD_PCM_AFIFO_AFIFO = 1 +}; + +enum AUD_PCM_CLOCK_SOURCE { + AUD_PCM_CLOCK_MASTER_MODE = 0, + AUD_PCM_CLOCK_SLAVE_MODE = 1 +}; + +enum AUD_PCM_WLEN { + AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0, + AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1 +}; + +enum AUD_PCM_MODE { + AUD_PCM_MODE_PCM_MODE_8K = 0, + AUD_PCM_MODE_PCM_MODE_16K = 1, + AUD_PCM_MODE_PCM_MODE_32K = 2, + AUD_PCM_MODE_PCM_MODE_48K = 3, +}; + +enum AUD_PCM_FMT { + AUD_PCM_FMT_I2S = 0, + AUD_PCM_FMT_EIAJ = 1, + AUD_PCM_FMT_PCM_MODE_A = 2, + AUD_PCM_FMT_PCM_MODE_B = 3 +}; + +enum AUD_BCLK_OUT_INV { + AUD_BCLK_OUT_INV_NO_INVERSE = 0, + AUD_BCLK_OUT_INV_INVERSE = 1 +}; + +enum AUD_PCM_EN { + AUD_PCM_EN_DISABLE = 0, + AUD_PCM_EN_ENABLE = 1 +}; + +/* dai component */ +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7, + I_DL2_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8, + I_DL2_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27, + I_DL1_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17, + I_ADDA_UL_CH1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17, + I_DL2_CH1, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18, + I_ADDA_UL_CH2, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18, + I_DL2_CH2, 1, 0), +}; + +static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24, + I_DL1_CH1, 1, 0), +}; + +static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = { + /* inter-connections */ + SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch1_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)), + SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch2_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)), + SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0, + mtk_pcm_1_playback_ch4_mix, + ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch1_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch2_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)), + SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0, + mtk_pcm_2_playback_ch4_mix, + ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)), + + SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, PCM_EN_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY("PCM_2_EN", PCM2_INTF_CON, PCM2_EN_SFT, 0, + NULL, 0), + + SND_SOC_DAPM_INPUT("MD1_TO_AFE"), + SND_SOC_DAPM_INPUT("MD2_TO_AFE"), + SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"), + SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"), +}; + +static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = { + {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"}, + {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"}, + {"PCM 1 Playback", NULL, "PCM_1_PB_CH4"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH1"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH2"}, + {"PCM 2 Playback", NULL, "PCM_2_PB_CH4"}, + + {"PCM 1 Playback", NULL, "PCM_1_EN"}, + {"PCM 2 Playback", NULL, "PCM_2_EN"}, + {"PCM 1 Capture", NULL, "PCM_1_EN"}, + {"PCM 2 Capture", NULL, "PCM_2_EN"}, + + {"AFE_TO_MD1", NULL, "PCM 2 Playback"}, + {"AFE_TO_MD2", NULL, "PCM 1 Playback"}, + {"PCM 2 Capture", NULL, "MD1_TO_AFE"}, + {"PCM 1 Capture", NULL, "MD2_TO_AFE"}, + + {"PCM_1_PB_CH1", "DL2_CH1", "DL2"}, + {"PCM_1_PB_CH2", "DL2_CH2", "DL2"}, + {"PCM_1_PB_CH4", "DL1_CH1", "DL1"}, + {"PCM_2_PB_CH1", "DL2_CH1", "DL2"}, + {"PCM_2_PB_CH2", "DL2_CH2", "DL2"}, + {"PCM_2_PB_CH4", "DL1_CH1", "DL1"}, +}; + +/* dai ops */ +static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + unsigned int rate = params_rate(params); + unsigned int rate_reg = mt8183_rate_transform(afe->dev, rate, dai->id); + unsigned int pcm_con = 0; + + dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n", + __func__, + dai->id, + substream->stream, + rate, + rate_reg, + dai->playback_widget->active, + dai->capture_widget->active); + + if (dai->playback_widget->active || dai->capture_widget->active) + return 0; + + switch (dai->id) { + case MT8183_DAI_PCM_1: + pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT; + pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT; + pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT; + pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT; + pcm_con |= 0 << PCM_SYNC_LENGTH_SFT; + pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT; + pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT; + pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT; + pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT; + pcm_con |= rate_reg << PCM_MODE_SFT; + pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT; + + regmap_update_bits(afe->regmap, PCM_INTF_CON1, + 0xfffffffe, pcm_con); + break; + case MT8183_DAI_PCM_2: + pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT; + pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT; + pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT; + pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT; + pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT; + pcm_con |= rate_reg << PCM2_MODE_SFT; + pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT; + + regmap_update_bits(afe->regmap, PCM2_INTF_CON, + 0xfffffffe, pcm_con); + break; + default: + dev_warn(afe->dev, "%s(), id %d not support\n", + __func__, dai->id); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_pcm_ops = { + .hw_params = mtk_dai_pcm_hw_params, +}; + +/* dai driver */ +#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000) + +#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = { + { + .name = "PCM 1", + .id = MT8183_DAI_PCM_1, + .playback = { + .stream_name = "PCM 1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .capture = { + .stream_name = "PCM 1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_dai_pcm_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "PCM 2", + .id = MT8183_DAI_PCM_2, + .playback = { + .stream_name = "PCM 2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .capture = { + .stream_name = "PCM 2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MTK_PCM_RATES, + .formats = MTK_PCM_FORMATS, + }, + .ops = &mtk_dai_pcm_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, +}; + +int mt8183_dai_pcm_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_pcm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver); + + dai->dapm_widgets = mtk_dai_pcm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets); + dai->dapm_routes = mtk_dai_pcm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes); + + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c new file mode 100644 index 000000000000..8983d54a9b67 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c @@ -0,0 +1,639 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// MediaTek ALSA SoC Audio DAI TDM Control +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include "mt8183-afe-clk.h" +#include "mt8183-afe-common.h" +#include "mt8183-interconnection.h" +#include "mt8183-reg.h" + +struct mtk_afe_tdm_priv { + int bck_id; + int bck_rate; + + int mclk_id; + int mclk_multiple; /* according to sample rate */ + int mclk_rate; + int mclk_apll; +}; + +enum { + TDM_WLEN_16_BIT = 1, + TDM_WLEN_32_BIT = 2, +}; + +enum { + TDM_CHANNEL_BCK_16 = 0, + TDM_CHANNEL_BCK_24 = 1, + TDM_CHANNEL_BCK_32 = 2, +}; + +enum { + TDM_CHANNEL_NUM_2 = 0, + TDM_CHANNEL_NUM_4 = 1, + TDM_CHANNEL_NUM_8 = 2, +}; + +enum { + TDM_CH_START_O30_O31 = 0, + TDM_CH_START_O32_O33, + TDM_CH_START_O34_O35, + TDM_CH_START_O36_O37, + TDM_CH_ZERO, +}; + +enum { + HDMI_BIT_WIDTH_16_BIT = 0, + HDMI_BIT_WIDTH_32_BIT = 1, +}; + +static unsigned int get_hdmi_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + HDMI_BIT_WIDTH_16_BIT : HDMI_BIT_WIDTH_32_BIT; +} + +static unsigned int get_tdm_wlen(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + TDM_WLEN_16_BIT : TDM_WLEN_32_BIT; +} + +static unsigned int get_tdm_channel_bck(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) <= 16 ? + TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32; +} + +static unsigned int get_tdm_lrck_width(snd_pcm_format_t format) +{ + return snd_pcm_format_physical_width(format) - 1; +} + +static unsigned int get_tdm_ch(unsigned int ch) +{ + switch (ch) { + case 1: + case 2: + return TDM_CHANNEL_NUM_2; + case 3: + case 4: + return TDM_CHANNEL_NUM_4; + case 5: + case 6: + case 7: + case 8: + default: + return TDM_CHANNEL_NUM_8; + } +} + +/* interconnection */ +enum { + HDMI_CONN_CH0 = 0, + HDMI_CONN_CH1, + HDMI_CONN_CH2, + HDMI_CONN_CH3, + HDMI_CONN_CH4, + HDMI_CONN_CH5, + HDMI_CONN_CH6, + HDMI_CONN_CH7, +}; + +static const char *const hdmi_conn_mux_map[] = { + "CH0", "CH1", "CH2", "CH3", + "CH4", "CH5", "CH6", "CH7", +}; + +static int hdmi_conn_mux_map_value[] = { + HDMI_CONN_CH0, + HDMI_CONN_CH1, + HDMI_CONN_CH2, + HDMI_CONN_CH3, + HDMI_CONN_CH4, + HDMI_CONN_CH5, + HDMI_CONN_CH6, + HDMI_CONN_CH7, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_0_SFT, + HDMI_O_0_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch0_mux_control = + SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_1_SFT, + HDMI_O_1_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch1_mux_control = + SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_2_SFT, + HDMI_O_2_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch2_mux_control = + SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_3_SFT, + HDMI_O_3_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch3_mux_control = + SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_4_SFT, + HDMI_O_4_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch4_mux_control = + SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_5_SFT, + HDMI_O_5_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch5_mux_control = + SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_6_SFT, + HDMI_O_6_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch6_mux_control = + SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum, + AFE_HDMI_CONN0, + HDMI_O_7_SFT, + HDMI_O_7_MASK, + hdmi_conn_mux_map, + hdmi_conn_mux_map_value); + +static const struct snd_kcontrol_new hdmi_ch7_mux_control = + SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum); + +enum { + SUPPLY_SEQ_APLL, + SUPPLY_SEQ_TDM_MCK_EN, + SUPPLY_SEQ_TDM_BCK_EN, +}; + +static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM]; + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8183_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate); + break; + case SND_SOC_DAPM_POST_PMD: + mt8183_mck_disable(afe, tdm_priv->bck_id); + break; + default: + break; + } + + return 0; +} + +static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM]; + + dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mt8183_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate); + break; + case SND_SOC_DAPM_POST_PMD: + tdm_priv->mclk_rate = 0; + mt8183_mck_disable(afe, tdm_priv->mclk_id); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = { + SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch0_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch1_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch2_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch3_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch4_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch5_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch6_mux_control), + SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0, + &hdmi_ch7_mux_control), + + SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"), + + SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_bck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN, + SND_SOC_NOPM, 0, 0, + mtk_tdm_mck_en_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_dapm_widget *w = sink; + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM]; + int cur_apll; + + /* which apll */ + cur_apll = mt8183_get_apll_by_name(afe, source->name); + + return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0; +} + +static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = { + {"HDMI_CH0_MUX", "CH0", "HDMI"}, + {"HDMI_CH0_MUX", "CH1", "HDMI"}, + {"HDMI_CH0_MUX", "CH2", "HDMI"}, + {"HDMI_CH0_MUX", "CH3", "HDMI"}, + {"HDMI_CH0_MUX", "CH4", "HDMI"}, + {"HDMI_CH0_MUX", "CH5", "HDMI"}, + {"HDMI_CH0_MUX", "CH6", "HDMI"}, + {"HDMI_CH0_MUX", "CH7", "HDMI"}, + + {"HDMI_CH1_MUX", "CH0", "HDMI"}, + {"HDMI_CH1_MUX", "CH1", "HDMI"}, + {"HDMI_CH1_MUX", "CH2", "HDMI"}, + {"HDMI_CH1_MUX", "CH3", "HDMI"}, + {"HDMI_CH1_MUX", "CH4", "HDMI"}, + {"HDMI_CH1_MUX", "CH5", "HDMI"}, + {"HDMI_CH1_MUX", "CH6", "HDMI"}, + {"HDMI_CH1_MUX", "CH7", "HDMI"}, + + {"HDMI_CH2_MUX", "CH0", "HDMI"}, + {"HDMI_CH2_MUX", "CH1", "HDMI"}, + {"HDMI_CH2_MUX", "CH2", "HDMI"}, + {"HDMI_CH2_MUX", "CH3", "HDMI"}, + {"HDMI_CH2_MUX", "CH4", "HDMI"}, + {"HDMI_CH2_MUX", "CH5", "HDMI"}, + {"HDMI_CH2_MUX", "CH6", "HDMI"}, + {"HDMI_CH2_MUX", "CH7", "HDMI"}, + + {"HDMI_CH3_MUX", "CH0", "HDMI"}, + {"HDMI_CH3_MUX", "CH1", "HDMI"}, + {"HDMI_CH3_MUX", "CH2", "HDMI"}, + {"HDMI_CH3_MUX", "CH3", "HDMI"}, + {"HDMI_CH3_MUX", "CH4", "HDMI"}, + {"HDMI_CH3_MUX", "CH5", "HDMI"}, + {"HDMI_CH3_MUX", "CH6", "HDMI"}, + {"HDMI_CH3_MUX", "CH7", "HDMI"}, + + {"HDMI_CH4_MUX", "CH0", "HDMI"}, + {"HDMI_CH4_MUX", "CH1", "HDMI"}, + {"HDMI_CH4_MUX", "CH2", "HDMI"}, + {"HDMI_CH4_MUX", "CH3", "HDMI"}, + {"HDMI_CH4_MUX", "CH4", "HDMI"}, + {"HDMI_CH4_MUX", "CH5", "HDMI"}, + {"HDMI_CH4_MUX", "CH6", "HDMI"}, + {"HDMI_CH4_MUX", "CH7", "HDMI"}, + + {"HDMI_CH5_MUX", "CH0", "HDMI"}, + {"HDMI_CH5_MUX", "CH1", "HDMI"}, + {"HDMI_CH5_MUX", "CH2", "HDMI"}, + {"HDMI_CH5_MUX", "CH3", "HDMI"}, + {"HDMI_CH5_MUX", "CH4", "HDMI"}, + {"HDMI_CH5_MUX", "CH5", "HDMI"}, + {"HDMI_CH5_MUX", "CH6", "HDMI"}, + {"HDMI_CH5_MUX", "CH7", "HDMI"}, + + {"HDMI_CH6_MUX", "CH0", "HDMI"}, + {"HDMI_CH6_MUX", "CH1", "HDMI"}, + {"HDMI_CH6_MUX", "CH2", "HDMI"}, + {"HDMI_CH6_MUX", "CH3", "HDMI"}, + {"HDMI_CH6_MUX", "CH4", "HDMI"}, + {"HDMI_CH6_MUX", "CH5", "HDMI"}, + {"HDMI_CH6_MUX", "CH6", "HDMI"}, + {"HDMI_CH6_MUX", "CH7", "HDMI"}, + + {"HDMI_CH7_MUX", "CH0", "HDMI"}, + {"HDMI_CH7_MUX", "CH1", "HDMI"}, + {"HDMI_CH7_MUX", "CH2", "HDMI"}, + {"HDMI_CH7_MUX", "CH3", "HDMI"}, + {"HDMI_CH7_MUX", "CH4", "HDMI"}, + {"HDMI_CH7_MUX", "CH5", "HDMI"}, + {"HDMI_CH7_MUX", "CH6", "HDMI"}, + {"HDMI_CH7_MUX", "CH7", "HDMI"}, + + {"TDM", NULL, "HDMI_CH0_MUX"}, + {"TDM", NULL, "HDMI_CH1_MUX"}, + {"TDM", NULL, "HDMI_CH2_MUX"}, + {"TDM", NULL, "HDMI_CH3_MUX"}, + {"TDM", NULL, "HDMI_CH4_MUX"}, + {"TDM", NULL, "HDMI_CH5_MUX"}, + {"TDM", NULL, "HDMI_CH6_MUX"}, + {"TDM", NULL, "HDMI_CH7_MUX"}, + + {"TDM", NULL, "aud_tdm_clk"}, + {"TDM", NULL, "TDM_BCK"}, + {"TDM_BCK", NULL, "TDM_MCK"}, + {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect}, + {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect}, +}; + +/* dai ops */ +static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe, + struct mtk_afe_tdm_priv *tdm_priv, + int freq) +{ + int apll; + int apll_rate; + + apll = mt8183_get_apll_by_rate(afe, freq); + apll_rate = mt8183_get_apll_rate(afe, apll); + + if (!freq || freq > apll_rate) { + dev_warn(afe->dev, + "%s(), freq(%d Hz) invalid\n", __func__, freq); + return -EINVAL; + } + + if (apll_rate % freq != 0) { + dev_warn(afe->dev, + "%s(), APLL cannot generate %d Hz", __func__, freq); + return -EINVAL; + } + + tdm_priv->mclk_rate = freq; + tdm_priv->mclk_apll = apll; + + return 0; +} + +static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + int tdm_id = dai->id; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id]; + unsigned int rate = params_rate(params); + unsigned int channels = params_channels(params); + snd_pcm_format_t format = params_format(params); + unsigned int tdm_con = 0; + + /* calculate mclk_rate, if not set explicitly */ + if (!tdm_priv->mclk_rate) { + tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple; + mtk_dai_tdm_cal_mclk(afe, + tdm_priv, + tdm_priv->mclk_rate); + } + + /* calculate bck */ + tdm_priv->bck_rate = rate * + channels * + snd_pcm_format_physical_width(format); + + if (tdm_priv->bck_rate > tdm_priv->mclk_rate) + dev_warn(afe->dev, "%s(), bck_rate > mclk_rate rate", __func__); + + if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0) + dev_warn(afe->dev, "%s(), bck cannot generate", __func__); + + dev_info(afe->dev, "%s(), id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n", + __func__, + tdm_id, rate, channels, format, + tdm_priv->mclk_rate, tdm_priv->bck_rate); + + /* set tdm */ + tdm_con = 1 << BCK_INVERSE_SFT; + tdm_con |= 1 << LRCK_INVERSE_SFT; + tdm_con |= 1 << DELAY_DATA_SFT; + tdm_con |= 1 << LEFT_ALIGN_SFT; + tdm_con |= get_tdm_wlen(format) << WLEN_SFT; + tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT; + tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT; + tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; + regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con); + + switch (channels) { + case 1: + case 2: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 3: + case 4: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 5: + case 6: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; + break; + case 7: + case 8: + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; + tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; + break; + default: + tdm_con = 0; + } + regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con); + + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + AFE_HDMI_OUT_CH_NUM_MASK_SFT, + channels << AFE_HDMI_OUT_CH_NUM_SFT); + + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + AFE_HDMI_OUT_BIT_WIDTH_MASK_SFT, + get_hdmi_wlen(format) << AFE_HDMI_OUT_BIT_WIDTH_SFT); + return 0; +} + +static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream, + int cmd, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /* enable Out control */ + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + AFE_HDMI_OUT_ON_MASK_SFT, + 0x1 << AFE_HDMI_OUT_ON_SFT); + /* enable tdm */ + regmap_update_bits(afe->regmap, AFE_TDM_CON1, + TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + /* disable tdm */ + regmap_update_bits(afe->regmap, AFE_TDM_CON1, + TDM_EN_MASK_SFT, 0); + /* disable Out control */ + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, + AFE_HDMI_OUT_ON_MASK_SFT, + 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id]; + + if (!tdm_priv) { + dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__); + return -EINVAL; + } + + if (dir != SND_SOC_CLOCK_OUT) { + dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__); + return -EINVAL; + } + + dev_info(afe->dev, "%s(), freq %d\n", __func__, freq); + + return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); +} + +static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { + .hw_params = mtk_dai_tdm_hw_params, + .trigger = mtk_dai_tdm_trigger, + .set_sysclk = mtk_dai_tdm_set_sysclk, +}; + +/* dai driver */ +#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ + SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 |\ + SNDRV_PCM_RATE_192000) + +#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = { + { + .name = "TDM", + .id = MT8183_DAI_TDM, + .playback = { + .stream_name = "TDM", + .channels_min = 2, + .channels_max = 8, + .rates = MTK_TDM_RATES, + .formats = MTK_TDM_FORMATS, + }, + .ops = &mtk_dai_tdm_ops, + }, +}; + +int mt8183_dai_tdm_register(struct mtk_base_afe *afe) +{ + struct mt8183_afe_private *afe_priv = afe->platform_priv; + struct mtk_afe_tdm_priv *tdm_priv; + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_tdm_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver); + + dai->dapm_widgets = mtk_dai_tdm_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets); + dai->dapm_routes = mtk_dai_tdm_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes); + + tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv), + GFP_KERNEL); + if (!tdm_priv) + return -ENOMEM; + + tdm_priv->mclk_multiple = 128; + tdm_priv->bck_id = MT8183_I2S4_BCK; + tdm_priv->mclk_id = MT8183_I2S4_MCK; + + afe_priv->dai_priv[MT8183_DAI_TDM] = tdm_priv; + return 0; +} diff --git a/sound/soc/mediatek/mt8183/mt8183-interconnection.h b/sound/soc/mediatek/mt8183/mt8183-interconnection.h new file mode 100644 index 000000000000..6332f5f3e987 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-interconnection.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Mediatek MT8183 audio driver interconnection definition + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef _MT8183_INTERCONNECTION_H_ +#define _MT8183_INTERCONNECTION_H_ + +#define I_I2S0_CH1 0 +#define I_I2S0_CH2 1 +#define I_ADDA_UL_CH1 3 +#define I_ADDA_UL_CH2 4 +#define I_DL1_CH1 5 +#define I_DL1_CH2 6 +#define I_DL2_CH1 7 +#define I_DL2_CH2 8 +#define I_PCM_1_CAP_CH1 9 +#define I_GAIN1_OUT_CH1 10 +#define I_GAIN1_OUT_CH2 11 +#define I_GAIN2_OUT_CH1 12 +#define I_GAIN2_OUT_CH2 13 +#define I_PCM_2_CAP_CH1 14 +#define I_PCM_2_CAP_CH2 21 +#define I_PCM_1_CAP_CH2 22 +#define I_DL3_CH1 23 +#define I_DL3_CH2 24 +#define I_I2S2_CH1 25 +#define I_I2S2_CH2 26 + +#endif diff --git a/sound/soc/mediatek/mt8183/mt8183-reg.h b/sound/soc/mediatek/mt8183/mt8183-reg.h new file mode 100644 index 000000000000..e0482f2826da --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-reg.h @@ -0,0 +1,1666 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt8183-reg.h -- Mediatek 8183 audio driver reg definition + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef _MT8183_REG_H_ +#define _MT8183_REG_H_ + +#define AUDIO_TOP_CON0 0x0000 +#define AUDIO_TOP_CON1 0x0004 +#define AUDIO_TOP_CON3 0x000c +#define AFE_DAC_CON0 0x0010 +#define AFE_DAC_CON1 0x0014 +#define AFE_I2S_CON 0x0018 +#define AFE_DAIBT_CON0 0x001c +#define AFE_CONN0 0x0020 +#define AFE_CONN1 0x0024 +#define AFE_CONN2 0x0028 +#define AFE_CONN3 0x002c +#define AFE_CONN4 0x0030 +#define AFE_I2S_CON1 0x0034 +#define AFE_I2S_CON2 0x0038 +#define AFE_MRGIF_CON 0x003c +#define AFE_DL1_BASE 0x0040 +#define AFE_DL1_CUR 0x0044 +#define AFE_DL1_END 0x0048 +#define AFE_I2S_CON3 0x004c +#define AFE_DL2_BASE 0x0050 +#define AFE_DL2_CUR 0x0054 +#define AFE_DL2_END 0x0058 +#define AFE_CONN5 0x005c +#define AFE_CONN_24BIT 0x006c +#define AFE_AWB_BASE 0x0070 +#define AFE_AWB_END 0x0078 +#define AFE_AWB_CUR 0x007c +#define AFE_VUL_BASE 0x0080 +#define AFE_VUL_END 0x0088 +#define AFE_VUL_CUR 0x008c +#define AFE_CONN6 0x00bc +#define AFE_MEMIF_MSB 0x00cc +#define AFE_MEMIF_MON0 0x00d0 +#define AFE_MEMIF_MON1 0x00d4 +#define AFE_MEMIF_MON2 0x00d8 +#define AFE_MEMIF_MON3 0x00dc +#define AFE_MEMIF_MON4 0x00e0 +#define AFE_MEMIF_MON5 0x00e4 +#define AFE_MEMIF_MON6 0x00e8 +#define AFE_MEMIF_MON7 0x00ec +#define AFE_MEMIF_MON8 0x00f0 +#define AFE_MEMIF_MON9 0x00f4 +#define AFE_ADDA_DL_SRC2_CON0 0x0108 +#define AFE_ADDA_DL_SRC2_CON1 0x010c +#define AFE_ADDA_UL_SRC_CON0 0x0114 +#define AFE_ADDA_UL_SRC_CON1 0x0118 +#define AFE_ADDA_TOP_CON0 0x0120 +#define AFE_ADDA_UL_DL_CON0 0x0124 +#define AFE_ADDA_SRC_DEBUG 0x012c +#define AFE_ADDA_SRC_DEBUG_MON0 0x0130 +#define AFE_ADDA_SRC_DEBUG_MON1 0x0134 +#define AFE_ADDA_UL_SRC_MON0 0x0148 +#define AFE_ADDA_UL_SRC_MON1 0x014c +#define AFE_SIDETONE_DEBUG 0x01d0 +#define AFE_SIDETONE_MON 0x01d4 +#define AFE_SINEGEN_CON2 0x01dc +#define AFE_SIDETONE_CON0 0x01e0 +#define AFE_SIDETONE_COEFF 0x01e4 +#define AFE_SIDETONE_CON1 0x01e8 +#define AFE_SIDETONE_GAIN 0x01ec +#define AFE_SINEGEN_CON0 0x01f0 +#define AFE_TOP_CON0 0x0200 +#define AFE_BUS_CFG 0x0240 +#define AFE_BUS_MON0 0x0244 +#define AFE_ADDA_PREDIS_CON0 0x0260 +#define AFE_ADDA_PREDIS_CON1 0x0264 +#define AFE_MRGIF_MON0 0x0270 +#define AFE_MRGIF_MON1 0x0274 +#define AFE_MRGIF_MON2 0x0278 +#define AFE_I2S_MON 0x027c +#define AFE_ADDA_IIR_COEF_02_01 0x0290 +#define AFE_ADDA_IIR_COEF_04_03 0x0294 +#define AFE_ADDA_IIR_COEF_06_05 0x0298 +#define AFE_ADDA_IIR_COEF_08_07 0x029c +#define AFE_ADDA_IIR_COEF_10_09 0x02a0 +#define AFE_DAC_CON2 0x02e0 +#define AFE_IRQ_MCU_CON1 0x02e4 +#define AFE_IRQ_MCU_CON2 0x02e8 +#define AFE_DAC_MON 0x02ec +#define AFE_VUL2_BASE 0x02f0 +#define AFE_VUL2_END 0x02f8 +#define AFE_VUL2_CUR 0x02fc +#define AFE_IRQ_MCU_CNT0 0x0300 +#define AFE_IRQ_MCU_CNT6 0x0304 +#define AFE_IRQ_MCU_CNT8 0x0308 +#define AFE_IRQ_MCU_EN1 0x030c +#define AFE_IRQ0_MCU_CNT_MON 0x0310 +#define AFE_IRQ6_MCU_CNT_MON 0x0314 +#define AFE_MOD_DAI_BASE 0x0330 +#define AFE_MOD_DAI_END 0x0338 +#define AFE_MOD_DAI_CUR 0x033c +#define AFE_VUL_D2_BASE 0x0350 +#define AFE_VUL_D2_END 0x0358 +#define AFE_VUL_D2_CUR 0x035c +#define AFE_DL3_BASE 0x0360 +#define AFE_DL3_CUR 0x0364 +#define AFE_DL3_END 0x0368 +#define AFE_HDMI_OUT_CON0 0x0370 +#define AFE_HDMI_OUT_BASE 0x0374 +#define AFE_HDMI_OUT_CUR 0x0378 +#define AFE_HDMI_OUT_END 0x037c +#define AFE_HDMI_CONN0 0x0390 +#define AFE_IRQ3_MCU_CNT_MON 0x0398 +#define AFE_IRQ4_MCU_CNT_MON 0x039c +#define AFE_IRQ_MCU_CON0 0x03a0 +#define AFE_IRQ_MCU_STATUS 0x03a4 +#define AFE_IRQ_MCU_CLR 0x03a8 +#define AFE_IRQ_MCU_CNT1 0x03ac +#define AFE_IRQ_MCU_CNT2 0x03b0 +#define AFE_IRQ_MCU_EN 0x03b4 +#define AFE_IRQ_MCU_MON2 0x03b8 +#define AFE_IRQ_MCU_CNT5 0x03bc +#define AFE_IRQ1_MCU_CNT_MON 0x03c0 +#define AFE_IRQ2_MCU_CNT_MON 0x03c4 +#define AFE_IRQ1_MCU_EN_CNT_MON 0x03c8 +#define AFE_IRQ5_MCU_CNT_MON 0x03cc +#define AFE_MEMIF_MINLEN 0x03d0 +#define AFE_MEMIF_MAXLEN 0x03d4 +#define AFE_MEMIF_PBUF_SIZE 0x03d8 +#define AFE_IRQ_MCU_CNT7 0x03dc +#define AFE_IRQ7_MCU_CNT_MON 0x03e0 +#define AFE_IRQ_MCU_CNT3 0x03e4 +#define AFE_IRQ_MCU_CNT4 0x03e8 +#define AFE_IRQ_MCU_CNT11 0x03ec +#define AFE_APLL1_TUNER_CFG 0x03f0 +#define AFE_APLL2_TUNER_CFG 0x03f4 +#define AFE_MEMIF_HD_MODE 0x03f8 +#define AFE_MEMIF_HDALIGN 0x03fc +#define AFE_CONN33 0x0408 +#define AFE_IRQ_MCU_CNT12 0x040c +#define AFE_GAIN1_CON0 0x0410 +#define AFE_GAIN1_CON1 0x0414 +#define AFE_GAIN1_CON2 0x0418 +#define AFE_GAIN1_CON3 0x041c +#define AFE_CONN7 0x0420 +#define AFE_GAIN1_CUR 0x0424 +#define AFE_GAIN2_CON0 0x0428 +#define AFE_GAIN2_CON1 0x042c +#define AFE_GAIN2_CON2 0x0430 +#define AFE_GAIN2_CON3 0x0434 +#define AFE_CONN8 0x0438 +#define AFE_GAIN2_CUR 0x043c +#define AFE_CONN9 0x0440 +#define AFE_CONN10 0x0444 +#define AFE_CONN11 0x0448 +#define AFE_CONN12 0x044c +#define AFE_CONN13 0x0450 +#define AFE_CONN14 0x0454 +#define AFE_CONN15 0x0458 +#define AFE_CONN16 0x045c +#define AFE_CONN17 0x0460 +#define AFE_CONN18 0x0464 +#define AFE_CONN19 0x0468 +#define AFE_CONN20 0x046c +#define AFE_CONN21 0x0470 +#define AFE_CONN22 0x0474 +#define AFE_CONN23 0x0478 +#define AFE_CONN24 0x047c +#define AFE_CONN_RS 0x0494 +#define AFE_CONN_DI 0x0498 +#define AFE_CONN25 0x04b0 +#define AFE_CONN26 0x04b4 +#define AFE_CONN27 0x04b8 +#define AFE_CONN28 0x04bc +#define AFE_CONN29 0x04c0 +#define AFE_CONN30 0x04c4 +#define AFE_CONN31 0x04c8 +#define AFE_CONN32 0x04cc +#define AFE_SRAM_DELSEL_CON0 0x04f0 +#define AFE_SRAM_DELSEL_CON2 0x04f8 +#define AFE_SRAM_DELSEL_CON3 0x04fc +#define AFE_ASRC_2CH_CON12 0x0528 +#define AFE_ASRC_2CH_CON13 0x052c +#define PCM_INTF_CON1 0x0530 +#define PCM_INTF_CON2 0x0538 +#define PCM2_INTF_CON 0x053c +#define AFE_TDM_CON1 0x0548 +#define AFE_TDM_CON2 0x054c +#define AFE_CONN34 0x0580 +#define FPGA_CFG0 0x05b0 +#define FPGA_CFG1 0x05b4 +#define FPGA_CFG2 0x05c0 +#define FPGA_CFG3 0x05c4 +#define AUDIO_TOP_DBG_CON 0x05c8 +#define AUDIO_TOP_DBG_MON0 0x05cc +#define AUDIO_TOP_DBG_MON1 0x05d0 +#define AFE_IRQ8_MCU_CNT_MON 0x05e4 +#define AFE_IRQ11_MCU_CNT_MON 0x05e8 +#define AFE_IRQ12_MCU_CNT_MON 0x05ec +#define AFE_GENERAL_REG0 0x0800 +#define AFE_GENERAL_REG1 0x0804 +#define AFE_GENERAL_REG2 0x0808 +#define AFE_GENERAL_REG3 0x080c +#define AFE_GENERAL_REG4 0x0810 +#define AFE_GENERAL_REG5 0x0814 +#define AFE_GENERAL_REG6 0x0818 +#define AFE_GENERAL_REG7 0x081c +#define AFE_GENERAL_REG8 0x0820 +#define AFE_GENERAL_REG9 0x0824 +#define AFE_GENERAL_REG10 0x0828 +#define AFE_GENERAL_REG11 0x082c +#define AFE_GENERAL_REG12 0x0830 +#define AFE_GENERAL_REG13 0x0834 +#define AFE_GENERAL_REG14 0x0838 +#define AFE_GENERAL_REG15 0x083c +#define AFE_CBIP_CFG0 0x0840 +#define AFE_CBIP_MON0 0x0844 +#define AFE_CBIP_SLV_MUX_MON0 0x0848 +#define AFE_CBIP_SLV_DECODER_MON0 0x084c +#define AFE_CONN0_1 0x0900 +#define AFE_CONN1_1 0x0904 +#define AFE_CONN2_1 0x0908 +#define AFE_CONN3_1 0x090c +#define AFE_CONN4_1 0x0910 +#define AFE_CONN5_1 0x0914 +#define AFE_CONN6_1 0x0918 +#define AFE_CONN7_1 0x091c +#define AFE_CONN8_1 0x0920 +#define AFE_CONN9_1 0x0924 +#define AFE_CONN10_1 0x0928 +#define AFE_CONN11_1 0x092c +#define AFE_CONN12_1 0x0930 +#define AFE_CONN13_1 0x0934 +#define AFE_CONN14_1 0x0938 +#define AFE_CONN15_1 0x093c +#define AFE_CONN16_1 0x0940 +#define AFE_CONN17_1 0x0944 +#define AFE_CONN18_1 0x0948 +#define AFE_CONN19_1 0x094c +#define AFE_CONN20_1 0x0950 +#define AFE_CONN21_1 0x0954 +#define AFE_CONN22_1 0x0958 +#define AFE_CONN23_1 0x095c +#define AFE_CONN24_1 0x0960 +#define AFE_CONN25_1 0x0964 +#define AFE_CONN26_1 0x0968 +#define AFE_CONN27_1 0x096c +#define AFE_CONN28_1 0x0970 +#define AFE_CONN29_1 0x0974 +#define AFE_CONN30_1 0x0978 +#define AFE_CONN31_1 0x097c +#define AFE_CONN32_1 0x0980 +#define AFE_CONN33_1 0x0984 +#define AFE_CONN34_1 0x0988 +#define AFE_CONN_RS_1 0x098c +#define AFE_CONN_DI_1 0x0990 +#define AFE_CONN_24BIT_1 0x0994 +#define AFE_CONN_REG 0x0998 +#define AFE_CONN35 0x09a0 +#define AFE_CONN36 0x09a4 +#define AFE_CONN37 0x09a8 +#define AFE_CONN38 0x09ac +#define AFE_CONN35_1 0x09b0 +#define AFE_CONN36_1 0x09b4 +#define AFE_CONN37_1 0x09b8 +#define AFE_CONN38_1 0x09bc +#define AFE_CONN39 0x09c0 +#define AFE_CONN40 0x09c4 +#define AFE_CONN41 0x09c8 +#define AFE_CONN42 0x09cc +#define AFE_CONN39_1 0x09e0 +#define AFE_CONN40_1 0x09e4 +#define AFE_CONN41_1 0x09e8 +#define AFE_CONN42_1 0x09ec +#define AFE_I2S_CON4 0x09f8 +#define AFE_ADDA6_TOP_CON0 0x0a80 +#define AFE_ADDA6_UL_SRC_CON0 0x0a84 +#define AFE_ADD6_UL_SRC_CON1 0x0a88 +#define AFE_ADDA6_SRC_DEBUG 0x0a8c +#define AFE_ADDA6_SRC_DEBUG_MON0 0x0a90 +#define AFE_ADDA6_ULCF_CFG_02_01 0x0aa0 +#define AFE_ADDA6_ULCF_CFG_04_03 0x0aa4 +#define AFE_ADDA6_ULCF_CFG_06_05 0x0aa8 +#define AFE_ADDA6_ULCF_CFG_08_07 0x0aac +#define AFE_ADDA6_ULCF_CFG_10_09 0x0ab0 +#define AFE_ADDA6_ULCF_CFG_12_11 0x0ab4 +#define AFE_ADDA6_ULCF_CFG_14_13 0x0ab8 +#define AFE_ADDA6_ULCF_CFG_16_15 0x0abc +#define AFE_ADDA6_ULCF_CFG_18_17 0x0ac0 +#define AFE_ADDA6_ULCF_CFG_20_19 0x0ac4 +#define AFE_ADDA6_ULCF_CFG_22_21 0x0ac8 +#define AFE_ADDA6_ULCF_CFG_24_23 0x0acc +#define AFE_ADDA6_ULCF_CFG_26_25 0x0ad0 +#define AFE_ADDA6_ULCF_CFG_28_27 0x0ad4 +#define AFE_ADDA6_ULCF_CFG_30_29 0x0ad8 +#define AFE_ADD6A_UL_SRC_MON0 0x0ae4 +#define AFE_ADDA6_UL_SRC_MON1 0x0ae8 +#define AFE_CONN43 0x0af8 +#define AFE_CONN43_1 0x0afc +#define AFE_DL1_BASE_MSB 0x0b00 +#define AFE_DL1_CUR_MSB 0x0b04 +#define AFE_DL1_END_MSB 0x0b08 +#define AFE_DL2_BASE_MSB 0x0b10 +#define AFE_DL2_CUR_MSB 0x0b14 +#define AFE_DL2_END_MSB 0x0b18 +#define AFE_AWB_BASE_MSB 0x0b20 +#define AFE_AWB_END_MSB 0x0b28 +#define AFE_AWB_CUR_MSB 0x0b2c +#define AFE_VUL_BASE_MSB 0x0b30 +#define AFE_VUL_END_MSB 0x0b38 +#define AFE_VUL_CUR_MSB 0x0b3c +#define AFE_VUL2_BASE_MSB 0x0b50 +#define AFE_VUL2_END_MSB 0x0b58 +#define AFE_VUL2_CUR_MSB 0x0b5c +#define AFE_MOD_DAI_BASE_MSB 0x0b60 +#define AFE_MOD_DAI_END_MSB 0x0b68 +#define AFE_MOD_DAI_CUR_MSB 0x0b6c +#define AFE_VUL_D2_BASE_MSB 0x0b80 +#define AFE_VUL_D2_END_MSB 0x0b88 +#define AFE_VUL_D2_CUR_MSB 0x0b8c +#define AFE_DL3_BASE_MSB 0x0b90 +#define AFE_DL3_CUR_MSB 0x0b94 +#define AFE_DL3_END_MSB 0x0b98 +#define AFE_HDMI_OUT_BASE_MSB 0x0ba4 +#define AFE_HDMI_OUT_CUR_MSB 0x0ba8 +#define AFE_HDMI_OUT_END_MSB 0x0bac +#define AFE_AWB2_BASE 0x0bd0 +#define AFE_AWB2_END 0x0bd8 +#define AFE_AWB2_CUR 0x0bdc +#define AFE_AWB2_BASE_MSB 0x0be0 +#define AFE_AWB2_END_MSB 0x0be8 +#define AFE_AWB2_CUR_MSB 0x0bec +#define AFE_ADDA_DL_SDM_DCCOMP_CON 0x0c50 +#define AFE_ADDA_DL_SDM_TEST 0x0c54 +#define AFE_ADDA_DL_DC_COMP_CFG0 0x0c58 +#define AFE_ADDA_DL_DC_COMP_CFG1 0x0c5c +#define AFE_ADDA_DL_SDM_FIFO_MON 0x0c60 +#define AFE_ADDA_DL_SRC_LCH_MON 0x0c64 +#define AFE_ADDA_DL_SRC_RCH_MON 0x0c68 +#define AFE_ADDA_DL_SDM_OUT_MON 0x0c6c +#define AFE_CONNSYS_I2S_CON 0x0c78 +#define AFE_CONNSYS_I2S_MON 0x0c7c +#define AFE_ASRC_2CH_CON0 0x0c80 +#define AFE_ASRC_2CH_CON1 0x0c84 +#define AFE_ASRC_2CH_CON2 0x0c88 +#define AFE_ASRC_2CH_CON3 0x0c8c +#define AFE_ASRC_2CH_CON4 0x0c90 +#define AFE_ASRC_2CH_CON5 0x0c94 +#define AFE_ASRC_2CH_CON6 0x0c98 +#define AFE_ASRC_2CH_CON7 0x0c9c +#define AFE_ASRC_2CH_CON8 0x0ca0 +#define AFE_ASRC_2CH_CON9 0x0ca4 +#define AFE_ASRC_2CH_CON10 0x0ca8 +#define AFE_ADDA6_IIR_COEF_02_01 0x0ce0 +#define AFE_ADDA6_IIR_COEF_04_03 0x0ce4 +#define AFE_ADDA6_IIR_COEF_06_05 0x0ce8 +#define AFE_ADDA6_IIR_COEF_08_07 0x0cec +#define AFE_ADDA6_IIR_COEF_10_09 0x0cf0 +#define AFE_ADDA_PREDIS_CON2 0x0d40 +#define AFE_ADDA_PREDIS_CON3 0x0d44 +#define AFE_MEMIF_MON12 0x0d70 +#define AFE_MEMIF_MON13 0x0d74 +#define AFE_MEMIF_MON14 0x0d78 +#define AFE_MEMIF_MON15 0x0d7c +#define AFE_MEMIF_MON16 0x0d80 +#define AFE_MEMIF_MON17 0x0d84 +#define AFE_MEMIF_MON18 0x0d88 +#define AFE_MEMIF_MON19 0x0d8c +#define AFE_MEMIF_MON20 0x0d90 +#define AFE_MEMIF_MON21 0x0d94 +#define AFE_MEMIF_MON22 0x0d98 +#define AFE_MEMIF_MON23 0x0d9c +#define AFE_MEMIF_MON24 0x0da0 +#define AFE_HD_ENGEN_ENABLE 0x0dd0 +#define AFE_ADDA_MTKAIF_CFG0 0x0e00 +#define AFE_ADDA_MTKAIF_TX_CFG1 0x0e14 +#define AFE_ADDA_MTKAIF_RX_CFG0 0x0e20 +#define AFE_ADDA_MTKAIF_RX_CFG1 0x0e24 +#define AFE_ADDA_MTKAIF_RX_CFG2 0x0e28 +#define AFE_ADDA_MTKAIF_MON0 0x0e34 +#define AFE_ADDA_MTKAIF_MON1 0x0e38 +#define AFE_AUD_PAD_TOP 0x0e40 +#define AFE_GENERAL1_ASRC_2CH_CON0 0x0e80 +#define AFE_GENERAL1_ASRC_2CH_CON1 0x0e84 +#define AFE_GENERAL1_ASRC_2CH_CON2 0x0e88 +#define AFE_GENERAL1_ASRC_2CH_CON3 0x0e8c +#define AFE_GENERAL1_ASRC_2CH_CON4 0x0e90 +#define AFE_GENERAL1_ASRC_2CH_CON5 0x0e94 +#define AFE_GENERAL1_ASRC_2CH_CON6 0x0e98 +#define AFE_GENERAL1_ASRC_2CH_CON7 0x0e9c +#define AFE_GENERAL1_ASRC_2CH_CON8 0x0ea0 +#define AFE_GENERAL1_ASRC_2CH_CON9 0x0ea4 +#define AFE_GENERAL1_ASRC_2CH_CON10 0x0ea8 +#define AFE_GENERAL1_ASRC_2CH_CON12 0x0eb0 +#define AFE_GENERAL1_ASRC_2CH_CON13 0x0eb4 +#define GENERAL_ASRC_MODE 0x0eb8 +#define GENERAL_ASRC_EN_ON 0x0ebc +#define AFE_GENERAL2_ASRC_2CH_CON0 0x0f00 +#define AFE_GENERAL2_ASRC_2CH_CON1 0x0f04 +#define AFE_GENERAL2_ASRC_2CH_CON2 0x0f08 +#define AFE_GENERAL2_ASRC_2CH_CON3 0x0f0c +#define AFE_GENERAL2_ASRC_2CH_CON4 0x0f10 +#define AFE_GENERAL2_ASRC_2CH_CON5 0x0f14 +#define AFE_GENERAL2_ASRC_2CH_CON6 0x0f18 +#define AFE_GENERAL2_ASRC_2CH_CON7 0x0f1c +#define AFE_GENERAL2_ASRC_2CH_CON8 0x0f20 +#define AFE_GENERAL2_ASRC_2CH_CON9 0x0f24 +#define AFE_GENERAL2_ASRC_2CH_CON10 0x0f28 +#define AFE_GENERAL2_ASRC_2CH_CON12 0x0f30 +#define AFE_GENERAL2_ASRC_2CH_CON13 0x0f34 + +#define AFE_MAX_REGISTER AFE_GENERAL2_ASRC_2CH_CON13 +#define AFE_IRQ_STATUS_BITS 0x1fff + +/* AFE_DAC_CON0 */ +#define AWB2_ON_SFT 29 +#define AWB2_ON_MASK 0x1 +#define AWB2_ON_MASK_SFT (0x1 << 29) +#define VUL2_ON_SFT 27 +#define VUL2_ON_MASK 0x1 +#define VUL2_ON_MASK_SFT (0x1 << 27) +#define MOD_DAI_DUP_WR_SFT 26 +#define MOD_DAI_DUP_WR_MASK 0x1 +#define MOD_DAI_DUP_WR_MASK_SFT (0x1 << 26) +#define VUL12_MODE_SFT 20 +#define VUL12_MODE_MASK 0xf +#define VUL12_MODE_MASK_SFT (0xf << 20) +#define VUL12_R_MONO_SFT 11 +#define VUL12_R_MONO_MASK 0x1 +#define VUL12_R_MONO_MASK_SFT (0x1 << 11) +#define VUL12_MONO_SFT 10 +#define VUL12_MONO_MASK 0x1 +#define VUL12_MONO_MASK_SFT (0x1 << 10) +#define VUL12_ON_SFT 9 +#define VUL12_ON_MASK 0x1 +#define VUL12_ON_MASK_SFT (0x1 << 9) +#define MOD_DAI_ON_SFT 7 +#define MOD_DAI_ON_MASK 0x1 +#define MOD_DAI_ON_MASK_SFT (0x1 << 7) +#define AWB_ON_SFT 6 +#define AWB_ON_MASK 0x1 +#define AWB_ON_MASK_SFT (0x1 << 6) +#define DL3_ON_SFT 5 +#define DL3_ON_MASK 0x1 +#define DL3_ON_MASK_SFT (0x1 << 5) +#define VUL_ON_SFT 3 +#define VUL_ON_MASK 0x1 +#define VUL_ON_MASK_SFT (0x1 << 3) +#define DL2_ON_SFT 2 +#define DL2_ON_MASK 0x1 +#define DL2_ON_MASK_SFT (0x1 << 2) +#define DL1_ON_SFT 1 +#define DL1_ON_MASK 0x1 +#define DL1_ON_MASK_SFT (0x1 << 1) +#define AFE_ON_SFT 0 +#define AFE_ON_MASK 0x1 +#define AFE_ON_MASK_SFT (0x1 << 0) + +/* AFE_DAC_CON1 */ +#define MOD_DAI_MODE_SFT 30 +#define MOD_DAI_MODE_MASK 0x3 +#define MOD_DAI_MODE_MASK_SFT (0x3 << 30) +#define VUL_R_MONO_SFT 28 +#define VUL_R_MONO_MASK 0x1 +#define VUL_R_MONO_MASK_SFT (0x1 << 28) +#define VUL_DATA_SFT 27 +#define VUL_DATA_MASK 0x1 +#define VUL_DATA_MASK_SFT (0x1 << 27) +#define AWB_R_MONO_SFT 25 +#define AWB_R_MONO_MASK 0x1 +#define AWB_R_MONO_MASK_SFT (0x1 << 25) +#define AWB_DATA_SFT 24 +#define AWB_DATA_MASK 0x1 +#define AWB_DATA_MASK_SFT (0x1 << 24) +#define DL3_DATA_SFT 23 +#define DL3_DATA_MASK 0x1 +#define DL3_DATA_MASK_SFT (0x1 << 23) +#define DL2_DATA_SFT 22 +#define DL2_DATA_MASK 0x1 +#define DL2_DATA_MASK_SFT (0x1 << 22) +#define DL1_DATA_SFT 21 +#define DL1_DATA_MASK 0x1 +#define DL1_DATA_MASK_SFT (0x1 << 21) +#define VUL_MODE_SFT 16 +#define VUL_MODE_MASK 0xf +#define VUL_MODE_MASK_SFT (0xf << 16) +#define AWB_MODE_SFT 12 +#define AWB_MODE_MASK 0xf +#define AWB_MODE_MASK_SFT (0xf << 12) +#define I2S_MODE_SFT 8 +#define I2S_MODE_MASK 0xf +#define I2S_MODE_MASK_SFT (0xf << 8) +#define DL2_MODE_SFT 4 +#define DL2_MODE_MASK 0xf +#define DL2_MODE_MASK_SFT (0xf << 4) +#define DL1_MODE_SFT 0 +#define DL1_MODE_MASK 0xf +#define DL1_MODE_MASK_SFT (0xf << 0) + +/* AFE_DAC_CON2 */ +#define AWB2_R_MONO_SFT 21 +#define AWB2_R_MONO_MASK 0x1 +#define AWB2_R_MONO_MASK_SFT (0x1 << 21) +#define AWB2_DATA_SFT 20 +#define AWB2_DATA_MASK 0x1 +#define AWB2_DATA_MASK_SFT (0x1 << 20) +#define AWB2_MODE_SFT 16 +#define AWB2_MODE_MASK 0xf +#define AWB2_MODE_MASK_SFT (0xf << 16) +#define DL3_MODE_SFT 8 +#define DL3_MODE_MASK 0xf +#define DL3_MODE_MASK_SFT (0xf << 8) +#define VUL2_MODE_SFT 4 +#define VUL2_MODE_MASK 0xf +#define VUL2_MODE_MASK_SFT (0xf << 4) +#define VUL2_R_MONO_SFT 1 +#define VUL2_R_MONO_MASK 0x1 +#define VUL2_R_MONO_MASK_SFT (0x1 << 1) +#define VUL2_DATA_SFT 0 +#define VUL2_DATA_MASK 0x1 +#define VUL2_DATA_MASK_SFT (0x1 << 0) + +/* AFE_DAC_MON */ +#define AFE_ON_RETM_SFT 0 +#define AFE_ON_RETM_MASK 0x1 +#define AFE_ON_RETM_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON */ +#define BCK_NEG_EG_LATCH_SFT 30 +#define BCK_NEG_EG_LATCH_MASK 0x1 +#define BCK_NEG_EG_LATCH_MASK_SFT (0x1 << 30) +#define BCK_INV_SFT 29 +#define BCK_INV_MASK 0x1 +#define BCK_INV_MASK_SFT (0x1 << 29) +#define I2SIN_PAD_SEL_SFT 28 +#define I2SIN_PAD_SEL_MASK 0x1 +#define I2SIN_PAD_SEL_MASK_SFT (0x1 << 28) +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK 0x1 +#define I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S1_HD_EN_SFT 12 +#define I2S1_HD_EN_MASK 0x1 +#define I2S1_HD_EN_MASK_SFT (0x1 << 12) +#define INV_PAD_CTRL_SFT 7 +#define INV_PAD_CTRL_MASK 0x1 +#define INV_PAD_CTRL_MASK_SFT (0x1 << 7) +#define I2S_BYPSRC_SFT 6 +#define I2S_BYPSRC_MASK 0x1 +#define I2S_BYPSRC_MASK_SFT (0x1 << 6) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S_FMT_SFT 3 +#define I2S_FMT_MASK 0x1 +#define I2S_FMT_MASK_SFT (0x1 << 3) +#define I2S_SRC_SFT 2 +#define I2S_SRC_MASK 0x1 +#define I2S_SRC_MASK_SFT (0x1 << 2) +#define I2S_WLEN_SFT 1 +#define I2S_WLEN_MASK 0x1 +#define I2S_WLEN_MASK_SFT (0x1 << 1) +#define I2S_EN_SFT 0 +#define I2S_EN_MASK 0x1 +#define I2S_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON1 */ +#define I2S2_LR_SWAP_SFT 31 +#define I2S2_LR_SWAP_MASK 0x1 +#define I2S2_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S2_SEL_O19_O20_SFT 18 +#define I2S2_SEL_O19_O20_MASK 0x1 +#define I2S2_SEL_O19_O20_MASK_SFT (0x1 << 18) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S2_SEL_O03_O04_SFT 16 +#define I2S2_SEL_O03_O04_MASK 0x1 +#define I2S2_SEL_O03_O04_MASK_SFT (0x1 << 16) +#define I2S2_32BIT_EN_SFT 13 +#define I2S2_32BIT_EN_MASK 0x1 +#define I2S2_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S2_HD_EN_SFT 12 +#define I2S2_HD_EN_MASK 0x1 +#define I2S2_HD_EN_MASK_SFT (0x1 << 12) +#define I2S2_OUT_MODE_SFT 8 +#define I2S2_OUT_MODE_MASK 0xf +#define I2S2_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S2_FMT_SFT 3 +#define I2S2_FMT_MASK 0x1 +#define I2S2_FMT_MASK_SFT (0x1 << 3) +#define I2S2_WLEN_SFT 1 +#define I2S2_WLEN_MASK 0x1 +#define I2S2_WLEN_MASK_SFT (0x1 << 1) +#define I2S2_EN_SFT 0 +#define I2S2_EN_MASK 0x1 +#define I2S2_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON2 */ +#define I2S3_LR_SWAP_SFT 31 +#define I2S3_LR_SWAP_MASK 0x1 +#define I2S3_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S3_UPDATE_WORD_SFT 24 +#define I2S3_UPDATE_WORD_MASK 0x1f +#define I2S3_UPDATE_WORD_MASK_SFT (0x1f << 24) +#define I2S3_BCK_INV_SFT 23 +#define I2S3_BCK_INV_MASK 0x1 +#define I2S3_BCK_INV_MASK_SFT (0x1 << 23) +#define I2S3_FPGA_BIT_TEST_SFT 22 +#define I2S3_FPGA_BIT_TEST_MASK 0x1 +#define I2S3_FPGA_BIT_TEST_MASK_SFT (0x1 << 22) +#define I2S3_FPGA_BIT_SFT 21 +#define I2S3_FPGA_BIT_MASK 0x1 +#define I2S3_FPGA_BIT_MASK_SFT (0x1 << 21) +#define I2S3_LOOPBACK_SFT 20 +#define I2S3_LOOPBACK_MASK 0x1 +#define I2S3_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S3_HD_EN_SFT 12 +#define I2S3_HD_EN_MASK 0x1 +#define I2S3_HD_EN_MASK_SFT (0x1 << 12) +#define I2S3_OUT_MODE_SFT 8 +#define I2S3_OUT_MODE_MASK 0xf +#define I2S3_OUT_MODE_MASK_SFT (0xf << 8) +#define I2S3_FMT_SFT 3 +#define I2S3_FMT_MASK 0x1 +#define I2S3_FMT_MASK_SFT (0x1 << 3) +#define I2S3_WLEN_SFT 1 +#define I2S3_WLEN_MASK 0x1 +#define I2S3_WLEN_MASK_SFT (0x1 << 1) +#define I2S3_EN_SFT 0 +#define I2S3_EN_MASK 0x1 +#define I2S3_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON3 */ +#define I2S4_LR_SWAP_SFT 31 +#define I2S4_LR_SWAP_MASK 0x1 +#define I2S4_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S4_32BIT_EN_SFT 13 +#define I2S4_32BIT_EN_MASK 0x1 +#define I2S4_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S4_HD_EN_SFT 12 +#define I2S4_HD_EN_MASK 0x1 +#define I2S4_HD_EN_MASK_SFT (0x1 << 12) +#define I2S4_OUT_MODE_SFT 8 +#define I2S4_OUT_MODE_MASK 0xf +#define I2S4_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S4_FMT_SFT 3 +#define I2S4_FMT_MASK 0x1 +#define I2S4_FMT_MASK_SFT (0x1 << 3) +#define I2S4_WLEN_SFT 1 +#define I2S4_WLEN_MASK 0x1 +#define I2S4_WLEN_MASK_SFT (0x1 << 1) +#define I2S4_EN_SFT 0 +#define I2S4_EN_MASK 0x1 +#define I2S4_EN_MASK_SFT (0x1 << 0) + +/* AFE_I2S_CON4 */ +#define I2S5_LR_SWAP_SFT 31 +#define I2S5_LR_SWAP_MASK 0x1 +#define I2S5_LR_SWAP_MASK_SFT (0x1 << 31) +#define I2S_LOOPBACK_SFT 20 +#define I2S_LOOPBACK_MASK 0x1 +#define I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_SFT 17 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK 0x1 +#define I2S_ONOFF_NOT_RESET_CK_ENABLE_MASK_SFT (0x1 << 17) +#define I2S5_32BIT_EN_SFT 13 +#define I2S5_32BIT_EN_MASK 0x1 +#define I2S5_32BIT_EN_MASK_SFT (0x1 << 13) +#define I2S5_HD_EN_SFT 12 +#define I2S5_HD_EN_MASK 0x1 +#define I2S5_HD_EN_MASK_SFT (0x1 << 12) +#define I2S5_OUT_MODE_SFT 8 +#define I2S5_OUT_MODE_MASK 0xf +#define I2S5_OUT_MODE_MASK_SFT (0xf << 8) +#define INV_LRCK_SFT 5 +#define INV_LRCK_MASK 0x1 +#define INV_LRCK_MASK_SFT (0x1 << 5) +#define I2S5_FMT_SFT 3 +#define I2S5_FMT_MASK 0x1 +#define I2S5_FMT_MASK_SFT (0x1 << 3) +#define I2S5_WLEN_SFT 1 +#define I2S5_WLEN_MASK 0x1 +#define I2S5_WLEN_MASK_SFT (0x1 << 1) +#define I2S5_EN_SFT 0 +#define I2S5_EN_MASK 0x1 +#define I2S5_EN_MASK_SFT (0x1 << 0) + +/* AFE_GAIN1_CON0 */ +#define GAIN1_SAMPLE_PER_STEP_SFT 8 +#define GAIN1_SAMPLE_PER_STEP_MASK 0xff +#define GAIN1_SAMPLE_PER_STEP_MASK_SFT (0xff << 8) +#define GAIN1_MODE_SFT 4 +#define GAIN1_MODE_MASK 0xf +#define GAIN1_MODE_MASK_SFT (0xf << 4) +#define GAIN1_ON_SFT 0 +#define GAIN1_ON_MASK 0x1 +#define GAIN1_ON_MASK_SFT (0x1 << 0) + +/* AFE_GAIN1_CON1 */ +#define GAIN1_TARGET_SFT 0 +#define GAIN1_TARGET_MASK 0xfffff +#define GAIN1_TARGET_MASK_SFT (0xfffff << 0) + +/* AFE_GAIN2_CON0 */ +#define GAIN2_SAMPLE_PER_STEP_SFT 8 +#define GAIN2_SAMPLE_PER_STEP_MASK 0xff +#define GAIN2_SAMPLE_PER_STEP_MASK_SFT (0xff << 8) +#define GAIN2_MODE_SFT 4 +#define GAIN2_MODE_MASK 0xf +#define GAIN2_MODE_MASK_SFT (0xf << 4) +#define GAIN2_ON_SFT 0 +#define GAIN2_ON_MASK 0x1 +#define GAIN2_ON_MASK_SFT (0x1 << 0) + +/* AFE_GAIN2_CON1 */ +#define GAIN2_TARGET_SFT 0 +#define GAIN2_TARGET_MASK 0xfffff +#define GAIN2_TARGET_MASK_SFT (0xfffff << 0) + +/* AFE_GAIN1_CUR */ +#define AFE_GAIN1_CUR_SFT 0 +#define AFE_GAIN1_CUR_MASK 0xfffff +#define AFE_GAIN1_CUR_MASK_SFT (0xfffff << 0) + +/* AFE_GAIN2_CUR */ +#define AFE_GAIN2_CUR_SFT 0 +#define AFE_GAIN2_CUR_MASK 0xfffff +#define AFE_GAIN2_CUR_MASK_SFT (0xfffff << 0) + +/* AFE_MEMIF_HD_MODE */ +#define AWB2_HD_SFT 28 +#define AWB2_HD_MASK 0x3 +#define AWB2_HD_MASK_SFT (0x3 << 28) +#define HDMI_HD_SFT 20 +#define HDMI_HD_MASK 0x3 +#define HDMI_HD_MASK_SFT (0x3 << 20) +#define MOD_DAI_HD_SFT 18 +#define MOD_DAI_HD_MASK 0x3 +#define MOD_DAI_HD_MASK_SFT (0x3 << 18) +#define DAI_HD_SFT 16 +#define DAI_HD_MASK 0x3 +#define DAI_HD_MASK_SFT (0x3 << 16) +#define VUL2_HD_SFT 14 +#define VUL2_HD_MASK 0x3 +#define VUL2_HD_MASK_SFT (0x3 << 14) +#define VUL12_HD_SFT 12 +#define VUL12_HD_MASK 0x3 +#define VUL12_HD_MASK_SFT (0x3 << 12) +#define VUL_HD_SFT 10 +#define VUL_HD_MASK 0x3 +#define VUL_HD_MASK_SFT (0x3 << 10) +#define AWB_HD_SFT 8 +#define AWB_HD_MASK 0x3 +#define AWB_HD_MASK_SFT (0x3 << 8) +#define DL3_HD_SFT 6 +#define DL3_HD_MASK 0x3 +#define DL3_HD_MASK_SFT (0x3 << 6) +#define DL2_HD_SFT 4 +#define DL2_HD_MASK 0x3 +#define DL2_HD_MASK_SFT (0x3 << 4) +#define DL1_HD_SFT 0 +#define DL1_HD_MASK 0x3 +#define DL1_HD_MASK_SFT (0x3 << 0) + +/* AFE_MEMIF_HDALIGN */ +#define AWB2_NORMAL_MODE_SFT 30 +#define AWB2_NORMAL_MODE_MASK 0x1 +#define AWB2_NORMAL_MODE_MASK_SFT (0x1 << 30) +#define HDMI_NORMAL_MODE_SFT 26 +#define HDMI_NORMAL_MODE_MASK 0x1 +#define HDMI_NORMAL_MODE_MASK_SFT (0x1 << 26) +#define MOD_DAI_NORMAL_MODE_SFT 25 +#define MOD_DAI_NORMAL_MODE_MASK 0x1 +#define MOD_DAI_NORMAL_MODE_MASK_SFT (0x1 << 25) +#define DAI_NORMAL_MODE_SFT 24 +#define DAI_NORMAL_MODE_MASK 0x1 +#define DAI_NORMAL_MODE_MASK_SFT (0x1 << 24) +#define VUL2_NORMAL_MODE_SFT 23 +#define VUL2_NORMAL_MODE_MASK 0x1 +#define VUL2_NORMAL_MODE_MASK_SFT (0x1 << 23) +#define VUL12_NORMAL_MODE_SFT 22 +#define VUL12_NORMAL_MODE_MASK 0x1 +#define VUL12_NORMAL_MODE_MASK_SFT (0x1 << 22) +#define VUL_NORMAL_MODE_SFT 21 +#define VUL_NORMAL_MODE_MASK 0x1 +#define VUL_NORMAL_MODE_MASK_SFT (0x1 << 21) +#define AWB_NORMAL_MODE_SFT 20 +#define AWB_NORMAL_MODE_MASK 0x1 +#define AWB_NORMAL_MODE_MASK_SFT (0x1 << 20) +#define DL3_NORMAL_MODE_SFT 19 +#define DL3_NORMAL_MODE_MASK 0x1 +#define DL3_NORMAL_MODE_MASK_SFT (0x1 << 19) +#define DL2_NORMAL_MODE_SFT 18 +#define DL2_NORMAL_MODE_MASK 0x1 +#define DL2_NORMAL_MODE_MASK_SFT (0x1 << 18) +#define DL1_NORMAL_MODE_SFT 16 +#define DL1_NORMAL_MODE_MASK 0x1 +#define DL1_NORMAL_MODE_MASK_SFT (0x1 << 16) +#define RESERVED1_SFT 15 +#define RESERVED1_MASK 0x1 +#define RESERVED1_MASK_SFT (0x1 << 15) +#define AWB2_ALIGN_SFT 14 +#define AWB2_ALIGN_MASK 0x1 +#define AWB2_ALIGN_MASK_SFT (0x1 << 14) +#define HDMI_HD_ALIGN_SFT 10 +#define HDMI_HD_ALIGN_MASK 0x1 +#define HDMI_HD_ALIGN_MASK_SFT (0x1 << 10) +#define MOD_DAI_HD_ALIGN_SFT 9 +#define MOD_DAI_HD_ALIGN_MASK 0x1 +#define MOD_DAI_HD_ALIGN_MASK_SFT (0x1 << 9) +#define VUL2_HD_ALIGN_SFT 7 +#define VUL2_HD_ALIGN_MASK 0x1 +#define VUL2_HD_ALIGN_MASK_SFT (0x1 << 7) +#define VUL12_HD_ALIGN_SFT 6 +#define VUL12_HD_ALIGN_MASK 0x1 +#define VUL12_HD_ALIGN_MASK_SFT (0x1 << 6) +#define VUL_HD_ALIGN_SFT 5 +#define VUL_HD_ALIGN_MASK 0x1 +#define VUL_HD_ALIGN_MASK_SFT (0x1 << 5) +#define AWB_HD_ALIGN_SFT 4 +#define AWB_HD_ALIGN_MASK 0x1 +#define AWB_HD_ALIGN_MASK_SFT (0x1 << 4) +#define DL3_HD_ALIGN_SFT 3 +#define DL3_HD_ALIGN_MASK 0x1 +#define DL3_HD_ALIGN_MASK_SFT (0x1 << 3) +#define DL2_HD_ALIGN_SFT 2 +#define DL2_HD_ALIGN_MASK 0x1 +#define DL2_HD_ALIGN_MASK_SFT (0x1 << 2) +#define DL1_HD_ALIGN_SFT 0 +#define DL1_HD_ALIGN_MASK 0x1 +#define DL1_HD_ALIGN_MASK_SFT (0x1 << 0) + +/* PCM_INTF_CON1 */ +#define PCM_FIX_VALUE_SEL_SFT 31 +#define PCM_FIX_VALUE_SEL_MASK 0x1 +#define PCM_FIX_VALUE_SEL_MASK_SFT (0x1 << 31) +#define PCM_BUFFER_LOOPBACK_SFT 30 +#define PCM_BUFFER_LOOPBACK_MASK 0x1 +#define PCM_BUFFER_LOOPBACK_MASK_SFT (0x1 << 30) +#define PCM_PARALLEL_LOOPBACK_SFT 29 +#define PCM_PARALLEL_LOOPBACK_MASK 0x1 +#define PCM_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 29) +#define PCM_SERIAL_LOOPBACK_SFT 28 +#define PCM_SERIAL_LOOPBACK_MASK 0x1 +#define PCM_SERIAL_LOOPBACK_MASK_SFT (0x1 << 28) +#define PCM_DAI_PCM_LOOPBACK_SFT 27 +#define PCM_DAI_PCM_LOOPBACK_MASK 0x1 +#define PCM_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 27) +#define PCM_I2S_PCM_LOOPBACK_SFT 26 +#define PCM_I2S_PCM_LOOPBACK_MASK 0x1 +#define PCM_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 26) +#define PCM_SYNC_DELSEL_SFT 25 +#define PCM_SYNC_DELSEL_MASK 0x1 +#define PCM_SYNC_DELSEL_MASK_SFT (0x1 << 25) +#define PCM_TX_LR_SWAP_SFT 24 +#define PCM_TX_LR_SWAP_MASK 0x1 +#define PCM_TX_LR_SWAP_MASK_SFT (0x1 << 24) +#define PCM_SYNC_OUT_INV_SFT 23 +#define PCM_SYNC_OUT_INV_MASK 0x1 +#define PCM_SYNC_OUT_INV_MASK_SFT (0x1 << 23) +#define PCM_BCLK_OUT_INV_SFT 22 +#define PCM_BCLK_OUT_INV_MASK 0x1 +#define PCM_BCLK_OUT_INV_MASK_SFT (0x1 << 22) +#define PCM_SYNC_IN_INV_SFT 21 +#define PCM_SYNC_IN_INV_MASK 0x1 +#define PCM_SYNC_IN_INV_MASK_SFT (0x1 << 21) +#define PCM_BCLK_IN_INV_SFT 20 +#define PCM_BCLK_IN_INV_MASK 0x1 +#define PCM_BCLK_IN_INV_MASK_SFT (0x1 << 20) +#define PCM_TX_LCH_RPT_SFT 19 +#define PCM_TX_LCH_RPT_MASK 0x1 +#define PCM_TX_LCH_RPT_MASK_SFT (0x1 << 19) +#define PCM_VBT_16K_MODE_SFT 18 +#define PCM_VBT_16K_MODE_MASK 0x1 +#define PCM_VBT_16K_MODE_MASK_SFT (0x1 << 18) +#define PCM_EXT_MODEM_SFT 17 +#define PCM_EXT_MODEM_MASK 0x1 +#define PCM_EXT_MODEM_MASK_SFT (0x1 << 17) +#define PCM_24BIT_SFT 16 +#define PCM_24BIT_MASK 0x1 +#define PCM_24BIT_MASK_SFT (0x1 << 16) +#define PCM_WLEN_SFT 14 +#define PCM_WLEN_MASK 0x3 +#define PCM_WLEN_MASK_SFT (0x3 << 14) +#define PCM_SYNC_LENGTH_SFT 9 +#define PCM_SYNC_LENGTH_MASK 0x1f +#define PCM_SYNC_LENGTH_MASK_SFT (0x1f << 9) +#define PCM_SYNC_TYPE_SFT 8 +#define PCM_SYNC_TYPE_MASK 0x1 +#define PCM_SYNC_TYPE_MASK_SFT (0x1 << 8) +#define PCM_BT_MODE_SFT 7 +#define PCM_BT_MODE_MASK 0x1 +#define PCM_BT_MODE_MASK_SFT (0x1 << 7) +#define PCM_BYP_ASRC_SFT 6 +#define PCM_BYP_ASRC_MASK 0x1 +#define PCM_BYP_ASRC_MASK_SFT (0x1 << 6) +#define PCM_SLAVE_SFT 5 +#define PCM_SLAVE_MASK 0x1 +#define PCM_SLAVE_MASK_SFT (0x1 << 5) +#define PCM_MODE_SFT 3 +#define PCM_MODE_MASK 0x3 +#define PCM_MODE_MASK_SFT (0x3 << 3) +#define PCM_FMT_SFT 1 +#define PCM_FMT_MASK 0x3 +#define PCM_FMT_MASK_SFT (0x3 << 1) +#define PCM_EN_SFT 0 +#define PCM_EN_MASK 0x1 +#define PCM_EN_MASK_SFT (0x1 << 0) + +/* PCM_INTF_CON2 */ +#define PCM1_TX_FIFO_OV_SFT 31 +#define PCM1_TX_FIFO_OV_MASK 0x1 +#define PCM1_TX_FIFO_OV_MASK_SFT (0x1 << 31) +#define PCM1_RX_FIFO_OV_SFT 30 +#define PCM1_RX_FIFO_OV_MASK 0x1 +#define PCM1_RX_FIFO_OV_MASK_SFT (0x1 << 30) +#define PCM2_TX_FIFO_OV_SFT 29 +#define PCM2_TX_FIFO_OV_MASK 0x1 +#define PCM2_TX_FIFO_OV_MASK_SFT (0x1 << 29) +#define PCM2_RX_FIFO_OV_SFT 28 +#define PCM2_RX_FIFO_OV_MASK 0x1 +#define PCM2_RX_FIFO_OV_MASK_SFT (0x1 << 28) +#define PCM1_SYNC_GLITCH_SFT 27 +#define PCM1_SYNC_GLITCH_MASK 0x1 +#define PCM1_SYNC_GLITCH_MASK_SFT (0x1 << 27) +#define PCM2_SYNC_GLITCH_SFT 26 +#define PCM2_SYNC_GLITCH_MASK 0x1 +#define PCM2_SYNC_GLITCH_MASK_SFT (0x1 << 26) +#define TX3_RCH_DBG_MODE_SFT 17 +#define TX3_RCH_DBG_MODE_MASK 0x1 +#define TX3_RCH_DBG_MODE_MASK_SFT (0x1 << 17) +#define PCM1_PCM2_LOOPBACK_SFT 16 +#define PCM1_PCM2_LOOPBACK_MASK 0x1 +#define PCM1_PCM2_LOOPBACK_MASK_SFT (0x1 << 16) +#define DAI_PCM_LOOPBACK_CH_SFT 14 +#define DAI_PCM_LOOPBACK_CH_MASK 0x3 +#define DAI_PCM_LOOPBACK_CH_MASK_SFT (0x3 << 14) +#define I2S_PCM_LOOPBACK_CH_SFT 12 +#define I2S_PCM_LOOPBACK_CH_MASK 0x3 +#define I2S_PCM_LOOPBACK_CH_MASK_SFT (0x3 << 12) +#define TX_FIX_VALUE_SFT 0 +#define TX_FIX_VALUE_MASK 0xff +#define TX_FIX_VALUE_MASK_SFT (0xff << 0) + +/* PCM2_INTF_CON */ +#define PCM2_TX_FIX_VALUE_SFT 24 +#define PCM2_TX_FIX_VALUE_MASK 0xff +#define PCM2_TX_FIX_VALUE_MASK_SFT (0xff << 24) +#define PCM2_FIX_VALUE_SEL_SFT 23 +#define PCM2_FIX_VALUE_SEL_MASK 0x1 +#define PCM2_FIX_VALUE_SEL_MASK_SFT (0x1 << 23) +#define PCM2_BUFFER_LOOPBACK_SFT 22 +#define PCM2_BUFFER_LOOPBACK_MASK 0x1 +#define PCM2_BUFFER_LOOPBACK_MASK_SFT (0x1 << 22) +#define PCM2_PARALLEL_LOOPBACK_SFT 21 +#define PCM2_PARALLEL_LOOPBACK_MASK 0x1 +#define PCM2_PARALLEL_LOOPBACK_MASK_SFT (0x1 << 21) +#define PCM2_SERIAL_LOOPBACK_SFT 20 +#define PCM2_SERIAL_LOOPBACK_MASK 0x1 +#define PCM2_SERIAL_LOOPBACK_MASK_SFT (0x1 << 20) +#define PCM2_DAI_PCM_LOOPBACK_SFT 19 +#define PCM2_DAI_PCM_LOOPBACK_MASK 0x1 +#define PCM2_DAI_PCM_LOOPBACK_MASK_SFT (0x1 << 19) +#define PCM2_I2S_PCM_LOOPBACK_SFT 18 +#define PCM2_I2S_PCM_LOOPBACK_MASK 0x1 +#define PCM2_I2S_PCM_LOOPBACK_MASK_SFT (0x1 << 18) +#define PCM2_SYNC_DELSEL_SFT 17 +#define PCM2_SYNC_DELSEL_MASK 0x1 +#define PCM2_SYNC_DELSEL_MASK_SFT (0x1 << 17) +#define PCM2_TX_LR_SWAP_SFT 16 +#define PCM2_TX_LR_SWAP_MASK 0x1 +#define PCM2_TX_LR_SWAP_MASK_SFT (0x1 << 16) +#define PCM2_SYNC_IN_INV_SFT 15 +#define PCM2_SYNC_IN_INV_MASK 0x1 +#define PCM2_SYNC_IN_INV_MASK_SFT (0x1 << 15) +#define PCM2_BCLK_IN_INV_SFT 14 +#define PCM2_BCLK_IN_INV_MASK 0x1 +#define PCM2_BCLK_IN_INV_MASK_SFT (0x1 << 14) +#define PCM2_TX_LCH_RPT_SFT 13 +#define PCM2_TX_LCH_RPT_MASK 0x1 +#define PCM2_TX_LCH_RPT_MASK_SFT (0x1 << 13) +#define PCM2_VBT_16K_MODE_SFT 12 +#define PCM2_VBT_16K_MODE_MASK 0x1 +#define PCM2_VBT_16K_MODE_MASK_SFT (0x1 << 12) +#define PCM2_LOOPBACK_CH_SEL_SFT 10 +#define PCM2_LOOPBACK_CH_SEL_MASK 0x3 +#define PCM2_LOOPBACK_CH_SEL_MASK_SFT (0x3 << 10) +#define PCM2_TX2_BT_MODE_SFT 8 +#define PCM2_TX2_BT_MODE_MASK 0x1 +#define PCM2_TX2_BT_MODE_MASK_SFT (0x1 << 8) +#define PCM2_BT_MODE_SFT 7 +#define PCM2_BT_MODE_MASK 0x1 +#define PCM2_BT_MODE_MASK_SFT (0x1 << 7) +#define PCM2_AFIFO_SFT 6 +#define PCM2_AFIFO_MASK 0x1 +#define PCM2_AFIFO_MASK_SFT (0x1 << 6) +#define PCM2_WLEN_SFT 5 +#define PCM2_WLEN_MASK 0x1 +#define PCM2_WLEN_MASK_SFT (0x1 << 5) +#define PCM2_MODE_SFT 3 +#define PCM2_MODE_MASK 0x3 +#define PCM2_MODE_MASK_SFT (0x3 << 3) +#define PCM2_FMT_SFT 1 +#define PCM2_FMT_MASK 0x3 +#define PCM2_FMT_MASK_SFT (0x3 << 1) +#define PCM2_EN_SFT 0 +#define PCM2_EN_MASK 0x1 +#define PCM2_EN_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_CFG0 */ +#define MTKAIF_RXIF_CLKINV_ADC_SFT 31 +#define MTKAIF_RXIF_CLKINV_ADC_MASK 0x1 +#define MTKAIF_RXIF_CLKINV_ADC_MASK_SFT (0x1 << 31) +#define MTKAIF_RXIF_BYPASS_SRC_SFT 17 +#define MTKAIF_RXIF_BYPASS_SRC_MASK 0x1 +#define MTKAIF_RXIF_BYPASS_SRC_MASK_SFT (0x1 << 17) +#define MTKAIF_RXIF_PROTOCOL2_SFT 16 +#define MTKAIF_RXIF_PROTOCOL2_MASK 0x1 +#define MTKAIF_RXIF_PROTOCOL2_MASK_SFT (0x1 << 16) +#define MTKAIF_TXIF_BYPASS_SRC_SFT 5 +#define MTKAIF_TXIF_BYPASS_SRC_MASK 0x1 +#define MTKAIF_TXIF_BYPASS_SRC_MASK_SFT (0x1 << 5) +#define MTKAIF_TXIF_PROTOCOL2_SFT 4 +#define MTKAIF_TXIF_PROTOCOL2_MASK 0x1 +#define MTKAIF_TXIF_PROTOCOL2_MASK_SFT (0x1 << 4) +#define MTKAIF_TXIF_8TO5_SFT 2 +#define MTKAIF_TXIF_8TO5_MASK 0x1 +#define MTKAIF_TXIF_8TO5_MASK_SFT (0x1 << 2) +#define MTKAIF_RXIF_8TO5_SFT 1 +#define MTKAIF_RXIF_8TO5_MASK 0x1 +#define MTKAIF_RXIF_8TO5_MASK_SFT (0x1 << 1) +#define MTKAIF_IF_LOOPBACK1_SFT 0 +#define MTKAIF_IF_LOOPBACK1_MASK 0x1 +#define MTKAIF_IF_LOOPBACK1_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_MTKAIF_RX_CFG2 */ +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT 16 +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK 0x1 +#define MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT (0x1 << 16) +#define MTKAIF_RXIF_DELAY_CYCLE_SFT 12 +#define MTKAIF_RXIF_DELAY_CYCLE_MASK 0xf +#define MTKAIF_RXIF_DELAY_CYCLE_MASK_SFT (0xf << 12) +#define MTKAIF_RXIF_DELAY_DATA_SFT 8 +#define MTKAIF_RXIF_DELAY_DATA_MASK 0x1 +#define MTKAIF_RXIF_DELAY_DATA_MASK_SFT (0x1 << 8) +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT 4 +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK 0x7 +#define MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT (0x7 << 4) + +/* AFE_ADDA_DL_SRC2_CON0 */ +#define DL_2_INPUT_MODE_CTL_SFT 28 +#define DL_2_INPUT_MODE_CTL_MASK 0xf +#define DL_2_INPUT_MODE_CTL_MASK_SFT (0xf << 28) +#define DL_2_CH1_SATURATION_EN_CTL_SFT 27 +#define DL_2_CH1_SATURATION_EN_CTL_MASK 0x1 +#define DL_2_CH1_SATURATION_EN_CTL_MASK_SFT (0x1 << 27) +#define DL_2_CH2_SATURATION_EN_CTL_SFT 26 +#define DL_2_CH2_SATURATION_EN_CTL_MASK 0x1 +#define DL_2_CH2_SATURATION_EN_CTL_MASK_SFT (0x1 << 26) +#define DL_2_OUTPUT_SEL_CTL_SFT 24 +#define DL_2_OUTPUT_SEL_CTL_MASK 0x3 +#define DL_2_OUTPUT_SEL_CTL_MASK_SFT (0x3 << 24) +#define DL_2_FADEIN_0START_EN_SFT 16 +#define DL_2_FADEIN_0START_EN_MASK 0x3 +#define DL_2_FADEIN_0START_EN_MASK_SFT (0x3 << 16) +#define DL_DISABLE_HW_CG_CTL_SFT 15 +#define DL_DISABLE_HW_CG_CTL_MASK 0x1 +#define DL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 15) +#define C_DATA_EN_SEL_CTL_PRE_SFT 14 +#define C_DATA_EN_SEL_CTL_PRE_MASK 0x1 +#define C_DATA_EN_SEL_CTL_PRE_MASK_SFT (0x1 << 14) +#define DL_2_SIDE_TONE_ON_CTL_PRE_SFT 13 +#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK 0x1 +#define DL_2_SIDE_TONE_ON_CTL_PRE_MASK_SFT (0x1 << 13) +#define DL_2_MUTE_CH1_OFF_CTL_PRE_SFT 12 +#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK 0x1 +#define DL_2_MUTE_CH1_OFF_CTL_PRE_MASK_SFT (0x1 << 12) +#define DL_2_MUTE_CH2_OFF_CTL_PRE_SFT 11 +#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK 0x1 +#define DL_2_MUTE_CH2_OFF_CTL_PRE_MASK_SFT (0x1 << 11) +#define DL2_ARAMPSP_CTL_PRE_SFT 9 +#define DL2_ARAMPSP_CTL_PRE_MASK 0x3 +#define DL2_ARAMPSP_CTL_PRE_MASK_SFT (0x3 << 9) +#define DL_2_IIRMODE_CTL_PRE_SFT 6 +#define DL_2_IIRMODE_CTL_PRE_MASK 0x7 +#define DL_2_IIRMODE_CTL_PRE_MASK_SFT (0x7 << 6) +#define DL_2_VOICE_MODE_CTL_PRE_SFT 5 +#define DL_2_VOICE_MODE_CTL_PRE_MASK 0x1 +#define DL_2_VOICE_MODE_CTL_PRE_MASK_SFT (0x1 << 5) +#define D2_2_MUTE_CH1_ON_CTL_PRE_SFT 4 +#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK 0x1 +#define D2_2_MUTE_CH1_ON_CTL_PRE_MASK_SFT (0x1 << 4) +#define D2_2_MUTE_CH2_ON_CTL_PRE_SFT 3 +#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK 0x1 +#define D2_2_MUTE_CH2_ON_CTL_PRE_MASK_SFT (0x1 << 3) +#define DL_2_IIR_ON_CTL_PRE_SFT 2 +#define DL_2_IIR_ON_CTL_PRE_MASK 0x1 +#define DL_2_IIR_ON_CTL_PRE_MASK_SFT (0x1 << 2) +#define DL_2_GAIN_ON_CTL_PRE_SFT 1 +#define DL_2_GAIN_ON_CTL_PRE_MASK 0x1 +#define DL_2_GAIN_ON_CTL_PRE_MASK_SFT (0x1 << 1) +#define DL_2_SRC_ON_TMP_CTL_PRE_SFT 0 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK 0x1 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_DL_SRC2_CON1 */ +#define DL_2_GAIN_CTL_PRE_SFT 16 +#define DL_2_GAIN_CTL_PRE_MASK 0xffff +#define DL_2_GAIN_CTL_PRE_MASK_SFT (0xffff << 16) +#define DL_2_GAIN_MODE_CTL_SFT 0 +#define DL_2_GAIN_MODE_CTL_MASK 0x1 +#define DL_2_GAIN_MODE_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_UL_SRC_CON0 */ +#define ULCF_CFG_EN_CTL_SFT 31 +#define ULCF_CFG_EN_CTL_MASK 0x1 +#define ULCF_CFG_EN_CTL_MASK_SFT (0x1 << 31) +#define UL_MODE_3P25M_CH2_CTL_SFT 22 +#define UL_MODE_3P25M_CH2_CTL_MASK 0x1 +#define UL_MODE_3P25M_CH2_CTL_MASK_SFT (0x1 << 22) +#define UL_MODE_3P25M_CH1_CTL_SFT 21 +#define UL_MODE_3P25M_CH1_CTL_MASK 0x1 +#define UL_MODE_3P25M_CH1_CTL_MASK_SFT (0x1 << 21) +#define UL_VOICE_MODE_CH1_CH2_CTL_SFT 17 +#define UL_VOICE_MODE_CH1_CH2_CTL_MASK 0x7 +#define UL_VOICE_MODE_CH1_CH2_CTL_MASK_SFT (0x7 << 17) +#define DMIC_LOW_POWER_MODE_CTL_SFT 14 +#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3 +#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14) +#define UL_DISABLE_HW_CG_CTL_SFT 12 +#define UL_DISABLE_HW_CG_CTL_MASK 0x1 +#define UL_DISABLE_HW_CG_CTL_MASK_SFT (0x1 << 12) +#define UL_IIR_ON_TMP_CTL_SFT 10 +#define UL_IIR_ON_TMP_CTL_MASK 0x1 +#define UL_IIR_ON_TMP_CTL_MASK_SFT (0x1 << 10) +#define UL_IIRMODE_CTL_SFT 7 +#define UL_IIRMODE_CTL_MASK 0x7 +#define UL_IIRMODE_CTL_MASK_SFT (0x7 << 7) +#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5) +#define UL_LOOP_BACK_MODE_CTL_SFT 2 +#define UL_LOOP_BACK_MODE_CTL_MASK 0x1 +#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2) +#define UL_SDM_3_LEVEL_CTL_SFT 1 +#define UL_SDM_3_LEVEL_CTL_MASK 0x1 +#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1) +#define UL_SRC_ON_TMP_CTL_SFT 0 +#define UL_SRC_ON_TMP_CTL_MASK 0x1 +#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_UL_SRC_CON1 */ +#define C_DAC_EN_CTL_SFT 27 +#define C_DAC_EN_CTL_MASK 0x1 +#define C_DAC_EN_CTL_MASK_SFT (0x1 << 27) +#define C_MUTE_SW_CTL_SFT 26 +#define C_MUTE_SW_CTL_MASK 0x1 +#define C_MUTE_SW_CTL_MASK_SFT (0x1 << 26) +#define ASDM_SRC_SEL_CTL_SFT 25 +#define ASDM_SRC_SEL_CTL_MASK 0x1 +#define ASDM_SRC_SEL_CTL_MASK_SFT (0x1 << 25) +#define C_AMP_DIV_CH2_CTL_SFT 21 +#define C_AMP_DIV_CH2_CTL_MASK 0x7 +#define C_AMP_DIV_CH2_CTL_MASK_SFT (0x7 << 21) +#define C_FREQ_DIV_CH2_CTL_SFT 16 +#define C_FREQ_DIV_CH2_CTL_MASK 0x1f +#define C_FREQ_DIV_CH2_CTL_MASK_SFT (0x1f << 16) +#define C_SINE_MODE_CH2_CTL_SFT 12 +#define C_SINE_MODE_CH2_CTL_MASK 0xf +#define C_SINE_MODE_CH2_CTL_MASK_SFT (0xf << 12) +#define C_AMP_DIV_CH1_CTL_SFT 9 +#define C_AMP_DIV_CH1_CTL_MASK 0x7 +#define C_AMP_DIV_CH1_CTL_MASK_SFT (0x7 << 9) +#define C_FREQ_DIV_CH1_CTL_SFT 4 +#define C_FREQ_DIV_CH1_CTL_MASK 0x1f +#define C_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 4) +#define C_SINE_MODE_CH1_CTL_SFT 0 +#define C_SINE_MODE_CH1_CTL_MASK 0xf +#define C_SINE_MODE_CH1_CTL_MASK_SFT (0xf << 0) + +/* AFE_ADDA_TOP_CON0 */ +#define C_LOOP_BACK_MODE_CTL_SFT 12 +#define C_LOOP_BACK_MODE_CTL_MASK 0xf +#define C_LOOP_BACK_MODE_CTL_MASK_SFT (0xf << 12) +#define C_EXT_ADC_CTL_SFT 0 +#define C_EXT_ADC_CTL_MASK 0x1 +#define C_EXT_ADC_CTL_MASK_SFT (0x1 << 0) + +/* AFE_ADDA_UL_DL_CON0 */ +#define AFE_ADDA6_UL_LR_SWAP_SFT 15 +#define AFE_ADDA6_UL_LR_SWAP_MASK 0x1 +#define AFE_ADDA6_UL_LR_SWAP_MASK_SFT (0x1 << 15) +#define AFE_ADDA6_CKDIV_RST_SFT 14 +#define AFE_ADDA6_CKDIV_RST_MASK 0x1 +#define AFE_ADDA6_CKDIV_RST_MASK_SFT (0x1 << 14) +#define AFE_ADDA6_FIFO_AUTO_RST_SFT 13 +#define AFE_ADDA6_FIFO_AUTO_RST_MASK 0x1 +#define AFE_ADDA6_FIFO_AUTO_RST_MASK_SFT (0x1 << 13) +#define UL_FIFO_DIGMIC_TESTIN_SFT 5 +#define UL_FIFO_DIGMIC_TESTIN_MASK 0x3 +#define UL_FIFO_DIGMIC_TESTIN_MASK_SFT (0x3 << 5) +#define UL_FIFO_DIGMIC_WDATA_TESTEN_SFT 4 +#define UL_FIFO_DIGMIC_WDATA_TESTEN_MASK 0x1 +#define UL_FIFO_DIGMIC_WDATA_TESTEN_MASK_SFT (0x1 << 4) +#define ADDA_AFE_ON_SFT 0 +#define ADDA_AFE_ON_MASK 0x1 +#define ADDA_AFE_ON_MASK_SFT (0x1 << 0) + +/* AFE_SIDETONE_CON0 */ +#define R_RDY_SFT 30 +#define R_RDY_MASK 0x1 +#define R_RDY_MASK_SFT (0x1 << 30) +#define W_RDY_SFT 29 +#define W_RDY_MASK 0x1 +#define W_RDY_MASK_SFT (0x1 << 29) +#define R_W_EN_SFT 25 +#define R_W_EN_MASK 0x1 +#define R_W_EN_MASK_SFT (0x1 << 25) +#define R_W_SEL_SFT 24 +#define R_W_SEL_MASK 0x1 +#define R_W_SEL_MASK_SFT (0x1 << 24) +#define SEL_CH2_SFT 23 +#define SEL_CH2_MASK 0x1 +#define SEL_CH2_MASK_SFT (0x1 << 23) +#define SIDE_TONE_COEFFICIENT_ADDR_SFT 16 +#define SIDE_TONE_COEFFICIENT_ADDR_MASK 0x1f +#define SIDE_TONE_COEFFICIENT_ADDR_MASK_SFT (0x1f << 16) +#define SIDE_TONE_COEFFICIENT_SFT 0 +#define SIDE_TONE_COEFFICIENT_MASK 0xffff +#define SIDE_TONE_COEFFICIENT_MASK_SFT (0xffff << 0) + +/* AFE_SIDETONE_COEFF */ +#define SIDE_TONE_COEFF_SFT 0 +#define SIDE_TONE_COEFF_MASK 0xffff +#define SIDE_TONE_COEFF_MASK_SFT (0xffff << 0) + +/* AFE_SIDETONE_CON1 */ +#define STF_BYPASS_MODE_SFT 31 +#define STF_BYPASS_MODE_MASK 0x1 +#define STF_BYPASS_MODE_MASK_SFT (0x1 << 31) +#define STF_BYPASS_MODE_O28_O29_SFT 30 +#define STF_BYPASS_MODE_O28_O29_MASK 0x1 +#define STF_BYPASS_MODE_O28_O29_MASK_SFT (0x1 << 30) +#define STF_BYPASS_MODE_I2S4_SFT 29 +#define STF_BYPASS_MODE_I2S4_MASK 0x1 +#define STF_BYPASS_MODE_I2S4_MASK_SFT (0x1 << 29) +#define STF_BYPASS_MODE_I2S5_SFT 28 +#define STF_BYPASS_MODE_I2S5_MASK 0x1 +#define STF_BYPASS_MODE_I2S5_MASK_SFT (0x1 << 28) +#define STF_INPUT_EN_SEL_SFT 13 +#define STF_INPUT_EN_SEL_MASK 0x1 +#define STF_INPUT_EN_SEL_MASK_SFT (0x1 << 13) +#define STF_SOURCE_FROM_O19O20_SFT 12 +#define STF_SOURCE_FROM_O19O20_MASK 0x1 +#define STF_SOURCE_FROM_O19O20_MASK_SFT (0x1 << 12) +#define SIDE_TONE_ON_SFT 8 +#define SIDE_TONE_ON_MASK 0x1 +#define SIDE_TONE_ON_MASK_SFT (0x1 << 8) +#define SIDE_TONE_HALF_TAP_NUM_SFT 0 +#define SIDE_TONE_HALF_TAP_NUM_MASK 0x3f +#define SIDE_TONE_HALF_TAP_NUM_MASK_SFT (0x3f << 0) + +/* AFE_SIDETONE_GAIN */ +#define POSITIVE_GAIN_SFT 16 +#define POSITIVE_GAIN_MASK 0x7 +#define POSITIVE_GAIN_MASK_SFT (0x7 << 16) +#define SIDE_TONE_GAIN_SFT 0 +#define SIDE_TONE_GAIN_MASK 0xffff +#define SIDE_TONE_GAIN_MASK_SFT (0xffff << 0) + +/* AFE_ADDA_DL_SDM_DCCOMP_CON */ +#define AUD_DC_COMP_EN_SFT 8 +#define AUD_DC_COMP_EN_MASK 0x1 +#define AUD_DC_COMP_EN_MASK_SFT (0x1 << 8) +#define ATTGAIN_CTL_SFT 0 +#define ATTGAIN_CTL_MASK 0x3f +#define ATTGAIN_CTL_MASK_SFT (0x3f << 0) + +/* AFE_SINEGEN_CON0 */ +#define DAC_EN_SFT 26 +#define DAC_EN_MASK 0x1 +#define DAC_EN_MASK_SFT (0x1 << 26) +#define MUTE_SW_CH2_SFT 25 +#define MUTE_SW_CH2_MASK 0x1 +#define MUTE_SW_CH2_MASK_SFT (0x1 << 25) +#define MUTE_SW_CH1_SFT 24 +#define MUTE_SW_CH1_MASK 0x1 +#define MUTE_SW_CH1_MASK_SFT (0x1 << 24) +#define SINE_MODE_CH2_SFT 20 +#define SINE_MODE_CH2_MASK 0xf +#define SINE_MODE_CH2_MASK_SFT (0xf << 20) +#define AMP_DIV_CH2_SFT 17 +#define AMP_DIV_CH2_MASK 0x7 +#define AMP_DIV_CH2_MASK_SFT (0x7 << 17) +#define FREQ_DIV_CH2_SFT 12 +#define FREQ_DIV_CH2_MASK 0x1f +#define FREQ_DIV_CH2_MASK_SFT (0x1f << 12) +#define SINE_MODE_CH1_SFT 8 +#define SINE_MODE_CH1_MASK 0xf +#define SINE_MODE_CH1_MASK_SFT (0xf << 8) +#define AMP_DIV_CH1_SFT 5 +#define AMP_DIV_CH1_MASK 0x7 +#define AMP_DIV_CH1_MASK_SFT (0x7 << 5) +#define FREQ_DIV_CH1_SFT 0 +#define FREQ_DIV_CH1_MASK 0x1f +#define FREQ_DIV_CH1_MASK_SFT (0x1f << 0) + +/* AFE_SINEGEN_CON2 */ +#define INNER_LOOP_BACK_MODE_SFT 0 +#define INNER_LOOP_BACK_MODE_MASK 0x3f +#define INNER_LOOP_BACK_MODE_MASK_SFT (0x3f << 0) + +/* AFE_MEMIF_MINLEN */ +#define HDMI_MINLEN_SFT 24 +#define HDMI_MINLEN_MASK 0xf +#define HDMI_MINLEN_MASK_SFT (0xf << 24) +#define DL3_MINLEN_SFT 12 +#define DL3_MINLEN_MASK 0xf +#define DL3_MINLEN_MASK_SFT (0xf << 12) +#define DL2_MINLEN_SFT 8 +#define DL2_MINLEN_MASK 0xf +#define DL2_MINLEN_MASK_SFT (0xf << 8) +#define DL1_DATA2_MINLEN_SFT 4 +#define DL1_DATA2_MINLEN_MASK 0xf +#define DL1_DATA2_MINLEN_MASK_SFT (0xf << 4) +#define DL1_MINLEN_SFT 0 +#define DL1_MINLEN_MASK 0xf +#define DL1_MINLEN_MASK_SFT (0xf << 0) + +/* AFE_MEMIF_MAXLEN */ +#define HDMI_MAXLEN_SFT 24 +#define HDMI_MAXLEN_MASK 0xf +#define HDMI_MAXLEN_MASK_SFT (0xf << 24) +#define DL3_MAXLEN_SFT 8 +#define DL3_MAXLEN_MASK 0xf +#define DL3_MAXLEN_MASK_SFT (0xf << 8) +#define DL2_MAXLEN_SFT 4 +#define DL2_MAXLEN_MASK 0xf +#define DL2_MAXLEN_MASK_SFT (0xf << 4) +#define DL1_MAXLEN_SFT 0 +#define DL1_MAXLEN_MASK 0x3 +#define DL1_MAXLEN_MASK_SFT (0x3 << 0) + +/* AFE_MEMIF_PBUF_SIZE */ +#define VUL12_4CH_SFT 17 +#define VUL12_4CH_MASK 0x1 +#define VUL12_4CH_MASK_SFT (0x1 << 17) +#define DL3_PBUF_SIZE_SFT 10 +#define DL3_PBUF_SIZE_MASK 0x3 +#define DL3_PBUF_SIZE_MASK_SFT (0x3 << 10) +#define HDMI_PBUF_SIZE_SFT 4 +#define HDMI_PBUF_SIZE_MASK 0x3 +#define HDMI_PBUF_SIZE_MASK_SFT (0x3 << 4) +#define DL2_PBUF_SIZE_SFT 2 +#define DL2_PBUF_SIZE_MASK 0x3 +#define DL2_PBUF_SIZE_MASK_SFT (0x3 << 2) +#define DL1_PBUF_SIZE_SFT 0 +#define DL1_PBUF_SIZE_MASK 0x3 +#define DL1_PBUF_SIZE_MASK_SFT (0x3 << 0) + +/* AFE_HD_ENGEN_ENABLE */ +#define AFE_24M_ON_SFT 1 +#define AFE_24M_ON_MASK 0x1 +#define AFE_24M_ON_MASK_SFT (0x1 << 1) +#define AFE_22M_ON_SFT 0 +#define AFE_22M_ON_MASK 0x1 +#define AFE_22M_ON_MASK_SFT (0x1 << 0) + +/* AFE_IRQ_MCU_CON0 */ +#define IRQ12_MCU_ON_SFT 12 +#define IRQ12_MCU_ON_MASK 0x1 +#define IRQ12_MCU_ON_MASK_SFT (0x1 << 12) +#define IRQ11_MCU_ON_SFT 11 +#define IRQ11_MCU_ON_MASK 0x1 +#define IRQ11_MCU_ON_MASK_SFT (0x1 << 11) +#define IRQ10_MCU_ON_SFT 10 +#define IRQ10_MCU_ON_MASK 0x1 +#define IRQ10_MCU_ON_MASK_SFT (0x1 << 10) +#define IRQ9_MCU_ON_SFT 9 +#define IRQ9_MCU_ON_MASK 0x1 +#define IRQ9_MCU_ON_MASK_SFT (0x1 << 9) +#define IRQ8_MCU_ON_SFT 8 +#define IRQ8_MCU_ON_MASK 0x1 +#define IRQ8_MCU_ON_MASK_SFT (0x1 << 8) +#define IRQ7_MCU_ON_SFT 7 +#define IRQ7_MCU_ON_MASK 0x1 +#define IRQ7_MCU_ON_MASK_SFT (0x1 << 7) +#define IRQ6_MCU_ON_SFT 6 +#define IRQ6_MCU_ON_MASK 0x1 +#define IRQ6_MCU_ON_MASK_SFT (0x1 << 6) +#define IRQ5_MCU_ON_SFT 5 +#define IRQ5_MCU_ON_MASK 0x1 +#define IRQ5_MCU_ON_MASK_SFT (0x1 << 5) +#define IRQ4_MCU_ON_SFT 4 +#define IRQ4_MCU_ON_MASK 0x1 +#define IRQ4_MCU_ON_MASK_SFT (0x1 << 4) +#define IRQ3_MCU_ON_SFT 3 +#define IRQ3_MCU_ON_MASK 0x1 +#define IRQ3_MCU_ON_MASK_SFT (0x1 << 3) +#define IRQ2_MCU_ON_SFT 2 +#define IRQ2_MCU_ON_MASK 0x1 +#define IRQ2_MCU_ON_MASK_SFT (0x1 << 2) +#define IRQ1_MCU_ON_SFT 1 +#define IRQ1_MCU_ON_MASK 0x1 +#define IRQ1_MCU_ON_MASK_SFT (0x1 << 1) +#define IRQ0_MCU_ON_SFT 0 +#define IRQ0_MCU_ON_MASK 0x1 +#define IRQ0_MCU_ON_MASK_SFT (0x1 << 0) + +/* AFE_IRQ_MCU_CON1 */ +#define IRQ7_MCU_MODE_SFT 28 +#define IRQ7_MCU_MODE_MASK 0xf +#define IRQ7_MCU_MODE_MASK_SFT (0xf << 28) +#define IRQ6_MCU_MODE_SFT 24 +#define IRQ6_MCU_MODE_MASK 0xf +#define IRQ6_MCU_MODE_MASK_SFT (0xf << 24) +#define IRQ5_MCU_MODE_SFT 20 +#define IRQ5_MCU_MODE_MASK 0xf +#define IRQ5_MCU_MODE_MASK_SFT (0xf << 20) +#define IRQ4_MCU_MODE_SFT 16 +#define IRQ4_MCU_MODE_MASK 0xf +#define IRQ4_MCU_MODE_MASK_SFT (0xf << 16) +#define IRQ3_MCU_MODE_SFT 12 +#define IRQ3_MCU_MODE_MASK 0xf +#define IRQ3_MCU_MODE_MASK_SFT (0xf << 12) +#define IRQ2_MCU_MODE_SFT 8 +#define IRQ2_MCU_MODE_MASK 0xf +#define IRQ2_MCU_MODE_MASK_SFT (0xf << 8) +#define IRQ1_MCU_MODE_SFT 4 +#define IRQ1_MCU_MODE_MASK 0xf +#define IRQ1_MCU_MODE_MASK_SFT (0xf << 4) +#define IRQ0_MCU_MODE_SFT 0 +#define IRQ0_MCU_MODE_MASK 0xf +#define IRQ0_MCU_MODE_MASK_SFT (0xf << 0) + +/* AFE_IRQ_MCU_CON2 */ +#define IRQ12_MCU_MODE_SFT 4 +#define IRQ12_MCU_MODE_MASK 0xf +#define IRQ12_MCU_MODE_MASK_SFT (0xf << 4) +#define IRQ11_MCU_MODE_SFT 0 +#define IRQ11_MCU_MODE_MASK 0xf +#define IRQ11_MCU_MODE_MASK_SFT (0xf << 0) + +/* AFE_IRQ_MCU_CLR */ +#define IRQ12_MCU_MISS_CNT_CLR_SFT 28 +#define IRQ12_MCU_MISS_CNT_CLR_MASK 0x1 +#define IRQ12_MCU_MISS_CNT_CLR_MASK_SFT (0x1 << 28) +#define IRQ11_MCU_MISS_CNT_CLR_SFT 27 +#define IRQ11_MCU_MISS_CNT_CLR_MASK 0x1 +#define IRQ11_MCU_MISS_CNT_CLR_MASK_SFT (0x1 << 27) +#define IRQ10_MCU_MISS_CLR_SFT 26 +#define IRQ10_MCU_MISS_CLR_MASK 0x1 +#define IRQ10_MCU_MISS_CLR_MASK_SFT (0x1 << 26) +#define IRQ9_MCU_MISS_CLR_SFT 25 +#define IRQ9_MCU_MISS_CLR_MASK 0x1 +#define IRQ9_MCU_MISS_CLR_MASK_SFT (0x1 << 25) +#define IRQ8_MCU_MISS_CLR_SFT 24 +#define IRQ8_MCU_MISS_CLR_MASK 0x1 +#define IRQ8_MCU_MISS_CLR_MASK_SFT (0x1 << 24) +#define IRQ7_MCU_MISS_CLR_SFT 23 +#define IRQ7_MCU_MISS_CLR_MASK 0x1 +#define IRQ7_MCU_MISS_CLR_MASK_SFT (0x1 << 23) +#define IRQ6_MCU_MISS_CLR_SFT 22 +#define IRQ6_MCU_MISS_CLR_MASK 0x1 +#define IRQ6_MCU_MISS_CLR_MASK_SFT (0x1 << 22) +#define IRQ5_MCU_MISS_CLR_SFT 21 +#define IRQ5_MCU_MISS_CLR_MASK 0x1 +#define IRQ5_MCU_MISS_CLR_MASK_SFT (0x1 << 21) +#define IRQ4_MCU_MISS_CLR_SFT 20 +#define IRQ4_MCU_MISS_CLR_MASK 0x1 +#define IRQ4_MCU_MISS_CLR_MASK_SFT (0x1 << 20) +#define IRQ3_MCU_MISS_CLR_SFT 19 +#define IRQ3_MCU_MISS_CLR_MASK 0x1 +#define IRQ3_MCU_MISS_CLR_MASK_SFT (0x1 << 19) +#define IRQ2_MCU_MISS_CLR_SFT 18 +#define IRQ2_MCU_MISS_CLR_MASK 0x1 +#define IRQ2_MCU_MISS_CLR_MASK_SFT (0x1 << 18) +#define IRQ1_MCU_MISS_CLR_SFT 17 +#define IRQ1_MCU_MISS_CLR_MASK 0x1 +#define IRQ1_MCU_MISS_CLR_MASK_SFT (0x1 << 17) +#define IRQ0_MCU_MISS_CLR_SFT 16 +#define IRQ0_MCU_MISS_CLR_MASK 0x1 +#define IRQ0_MCU_MISS_CLR_MASK_SFT (0x1 << 16) +#define IRQ12_MCU_CLR_SFT 12 +#define IRQ12_MCU_CLR_MASK 0x1 +#define IRQ12_MCU_CLR_MASK_SFT (0x1 << 12) +#define IRQ11_MCU_CLR_SFT 11 +#define IRQ11_MCU_CLR_MASK 0x1 +#define IRQ11_MCU_CLR_MASK_SFT (0x1 << 11) +#define IRQ10_MCU_CLR_SFT 10 +#define IRQ10_MCU_CLR_MASK 0x1 +#define IRQ10_MCU_CLR_MASK_SFT (0x1 << 10) +#define IRQ9_MCU_CLR_SFT 9 +#define IRQ9_MCU_CLR_MASK 0x1 +#define IRQ9_MCU_CLR_MASK_SFT (0x1 << 9) +#define IRQ8_MCU_CLR_SFT 8 +#define IRQ8_MCU_CLR_MASK 0x1 +#define IRQ8_MCU_CLR_MASK_SFT (0x1 << 8) +#define IRQ7_MCU_CLR_SFT 7 +#define IRQ7_MCU_CLR_MASK 0x1 +#define IRQ7_MCU_CLR_MASK_SFT (0x1 << 7) +#define IRQ6_MCU_CLR_SFT 6 +#define IRQ6_MCU_CLR_MASK 0x1 +#define IRQ6_MCU_CLR_MASK_SFT (0x1 << 6) +#define IRQ5_MCU_CLR_SFT 5 +#define IRQ5_MCU_CLR_MASK 0x1 +#define IRQ5_MCU_CLR_MASK_SFT (0x1 << 5) +#define IRQ4_MCU_CLR_SFT 4 +#define IRQ4_MCU_CLR_MASK 0x1 +#define IRQ4_MCU_CLR_MASK_SFT (0x1 << 4) +#define IRQ3_MCU_CLR_SFT 3 +#define IRQ3_MCU_CLR_MASK 0x1 +#define IRQ3_MCU_CLR_MASK_SFT (0x1 << 3) +#define IRQ2_MCU_CLR_SFT 2 +#define IRQ2_MCU_CLR_MASK 0x1 +#define IRQ2_MCU_CLR_MASK_SFT (0x1 << 2) +#define IRQ1_MCU_CLR_SFT 1 +#define IRQ1_MCU_CLR_MASK 0x1 +#define IRQ1_MCU_CLR_MASK_SFT (0x1 << 1) +#define IRQ0_MCU_CLR_SFT 0 +#define IRQ0_MCU_CLR_MASK 0x1 +#define IRQ0_MCU_CLR_MASK_SFT (0x1 << 0) + +/* AFE_MEMIF_MSB */ +#define CPU_COMPACT_MODE_SFT 29 +#define CPU_COMPACT_MODE_MASK 0x1 +#define CPU_COMPACT_MODE_MASK_SFT (0x1 << 29) +#define CPU_HD_ALIGN_SFT 28 +#define CPU_HD_ALIGN_MASK 0x1 +#define CPU_HD_ALIGN_MASK_SFT (0x1 << 28) +#define AWB2_AXI_WR_SIGN_SFT 24 +#define AWB2_AXI_WR_SIGN_MASK 0x1 +#define AWB2_AXI_WR_SIGN_MASK_SFT (0x1 << 24) +#define VUL2_AXI_WR_SIGN_SFT 22 +#define VUL2_AXI_WR_SIGN_MASK 0x1 +#define VUL2_AXI_WR_SIGN_MASK_SFT (0x1 << 22) +#define VUL12_AXI_WR_SIGN_SFT 21 +#define VUL12_AXI_WR_SIGN_MASK 0x1 +#define VUL12_AXI_WR_SIGN_MASK_SFT (0x1 << 21) +#define VUL_AXI_WR_SIGN_SFT 20 +#define VUL_AXI_WR_SIGN_MASK 0x1 +#define VUL_AXI_WR_SIGN_MASK_SFT (0x1 << 20) +#define MOD_DAI_AXI_WR_SIGN_SFT 18 +#define MOD_DAI_AXI_WR_SIGN_MASK 0x1 +#define MOD_DAI_AXI_WR_SIGN_MASK_SFT (0x1 << 18) +#define AWB_MSTR_SIGN_SFT 17 +#define AWB_MSTR_SIGN_MASK 0x1 +#define AWB_MSTR_SIGN_MASK_SFT (0x1 << 17) +#define SYSRAM_SIGN_SFT 16 +#define SYSRAM_SIGN_MASK 0x1 +#define SYSRAM_SIGN_MASK_SFT (0x1 << 16) + +/* AFE_HDMI_CONN0 */ +#define HDMI_O_7_SFT 21 +#define HDMI_O_7_MASK 0x7 +#define HDMI_O_7_MASK_SFT (0x7 << 21) +#define HDMI_O_6_SFT 18 +#define HDMI_O_6_MASK 0x7 +#define HDMI_O_6_MASK_SFT (0x7 << 18) +#define HDMI_O_5_SFT 15 +#define HDMI_O_5_MASK 0x7 +#define HDMI_O_5_MASK_SFT (0x7 << 15) +#define HDMI_O_4_SFT 12 +#define HDMI_O_4_MASK 0x7 +#define HDMI_O_4_MASK_SFT (0x7 << 12) +#define HDMI_O_3_SFT 9 +#define HDMI_O_3_MASK 0x7 +#define HDMI_O_3_MASK_SFT (0x7 << 9) +#define HDMI_O_2_SFT 6 +#define HDMI_O_2_MASK 0x7 +#define HDMI_O_2_MASK_SFT (0x7 << 6) +#define HDMI_O_1_SFT 3 +#define HDMI_O_1_MASK 0x7 +#define HDMI_O_1_MASK_SFT (0x7 << 3) +#define HDMI_O_0_SFT 0 +#define HDMI_O_0_MASK 0x7 +#define HDMI_O_0_MASK_SFT (0x7 << 0) + +/* AFE_TDM_CON1 */ +#define TDM_EN_SFT 0 +#define TDM_EN_MASK 0x1 +#define TDM_EN_MASK_SFT (0x1 << 0) +#define BCK_INVERSE_SFT 1 +#define BCK_INVERSE_MASK 0x1 +#define BCK_INVERSE_MASK_SFT (0x1 << 1) +#define LRCK_INVERSE_SFT 2 +#define LRCK_INVERSE_MASK 0x1 +#define LRCK_INVERSE_MASK_SFT (0x1 << 2) +#define DELAY_DATA_SFT 3 +#define DELAY_DATA_MASK 0x1 +#define DELAY_DATA_MASK_SFT (0x1 << 3) +#define LEFT_ALIGN_SFT 4 +#define LEFT_ALIGN_MASK 0x1 +#define LEFT_ALIGN_MASK_SFT (0x1 << 4) +#define WLEN_SFT 8 +#define WLEN_MASK 0x3 +#define WLEN_MASK_SFT (0x3 << 8) +#define CHANNEL_NUM_SFT 10 +#define CHANNEL_NUM_MASK 0x3 +#define CHANNEL_NUM_MASK_SFT (0x3 << 10) +#define CHANNEL_BCK_CYCLES_SFT 12 +#define CHANNEL_BCK_CYCLES_MASK 0x3 +#define CHANNEL_BCK_CYCLES_MASK_SFT (0x3 << 12) +#define DAC_BIT_NUM_SFT 16 +#define DAC_BIT_NUM_MASK 0x1f +#define DAC_BIT_NUM_MASK_SFT (0x1f << 16) +#define LRCK_TDM_WIDTH_SFT 24 +#define LRCK_TDM_WIDTH_MASK 0xff +#define LRCK_TDM_WIDTH_MASK_SFT (0xff << 24) + +/* AFE_TDM_CON2 */ +#define ST_CH_PAIR_SOUT0_SFT 0 +#define ST_CH_PAIR_SOUT0_MASK 0x7 +#define ST_CH_PAIR_SOUT0_MASK_SFT (0x7 << 0) +#define ST_CH_PAIR_SOUT1_SFT 4 +#define ST_CH_PAIR_SOUT1_MASK 0x7 +#define ST_CH_PAIR_SOUT1_MASK_SFT (0x7 << 4) +#define ST_CH_PAIR_SOUT2_SFT 8 +#define ST_CH_PAIR_SOUT2_MASK 0x7 +#define ST_CH_PAIR_SOUT2_MASK_SFT (0x7 << 8) +#define ST_CH_PAIR_SOUT3_SFT 12 +#define ST_CH_PAIR_SOUT3_MASK 0x7 +#define ST_CH_PAIR_SOUT3_MASK_SFT (0x7 << 12) +#define TDM_FIX_VALUE_SEL_SFT 16 +#define TDM_FIX_VALUE_SEL_MASK 0x1 +#define TDM_FIX_VALUE_SEL_MASK_SFT (0x1 << 16) +#define TDM_I2S_LOOPBACK_SFT 20 +#define TDM_I2S_LOOPBACK_MASK 0x1 +#define TDM_I2S_LOOPBACK_MASK_SFT (0x1 << 20) +#define TDM_I2S_LOOPBACK_CH_SFT 21 +#define TDM_I2S_LOOPBACK_CH_MASK 0x3 +#define TDM_I2S_LOOPBACK_CH_MASK_SFT (0x3 << 21) +#define TDM_FIX_VALUE_SFT 24 +#define TDM_FIX_VALUE_MASK 0xff +#define TDM_FIX_VALUE_MASK_SFT (0xff << 24) + +/* AFE_HDMI_OUT_CON0 */ +#define AFE_HDMI_OUT_ON_RETM_SFT 8 +#define AFE_HDMI_OUT_ON_RETM_MASK 0x1 +#define AFE_HDMI_OUT_ON_RETM_MASK_SFT (0x1 << 8) +#define AFE_HDMI_OUT_CH_NUM_SFT 4 +#define AFE_HDMI_OUT_CH_NUM_MASK 0xf +#define AFE_HDMI_OUT_CH_NUM_MASK_SFT (0xf << 4) +#define AFE_HDMI_OUT_BIT_WIDTH_SFT 1 +#define AFE_HDMI_OUT_BIT_WIDTH_MASK 0x1 +#define AFE_HDMI_OUT_BIT_WIDTH_MASK_SFT (0x1 << 1) +#define AFE_HDMI_OUT_ON_SFT 0 +#define AFE_HDMI_OUT_ON_MASK 0x1 +#define AFE_HDMI_OUT_ON_MASK_SFT (0x1 << 0) +#endif -- cgit v1.2.3-58-ga151 From bfd74e65c47ff325924fe5bd90789b1db422c9cc Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 22 Jan 2019 14:39:09 +0800 Subject: ASoC: mediatek: mt8183: add audio afe document Signed-off-by: Shunli Wang Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mt8183-afe-pcm.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mt8183-afe-pcm.txt diff --git a/Documentation/devicetree/bindings/sound/mt8183-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mt8183-afe-pcm.txt new file mode 100644 index 000000000000..396ba38619f6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt8183-afe-pcm.txt @@ -0,0 +1,36 @@ +Mediatek AFE PCM controller for mt8183 + +Required properties: +- compatible = "mediatek,mt68183-audio"; +- reg: register location and size +- interrupts: should contain AFE interrupt +- power-domains: should define the power domain +- clocks: Must contain an entry for each entry in clock-names +- clock-names: should have these clock names: + "infra_sys_audio_clk", + "mtkaif_26m_clk", + "top_mux_audio", + "top_mux_aud_intbus", + "top_sys_pll3_d4", + "top_clk26m_clk"; + +Example: + + afe: mt8183-afe-pcm@11220000 { + compatible = "mediatek,mt8183-audio"; + reg = <0 0x11220000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8183_POWER_DOMAIN_AUDIO>; + clocks = <&infrasys CLK_INFRA_AUDIO>, + <&infrasys CLK_INFRA_AUDIO_26M_BCLK>, + <&topckgen CLK_TOP_MUX_AUDIO>, + <&topckgen CLK_TOP_MUX_AUD_INTBUS>, + <&topckgen CLK_TOP_SYSPLL_D2_D4>, + <&clk26m>; + clock-names = "infra_sys_audio_clk", + "mtkaif_26m_clk", + "top_mux_audio", + "top_mux_aud_intbus", + "top_sys_pll_d2_d4", + "top_clk26m_clk"; + }; -- cgit v1.2.3-58-ga151 From 6a8d4198ca80deb2f978260a096fa651229cf4a2 Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 22 Jan 2019 14:39:10 +0800 Subject: ASoC: mediatek: mt6358: add codec driver add the mt6358 codec driver. Signed-off-by: Shunli Wang Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/mt6358.c | 2336 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/mt6358.h | 2314 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 4659 insertions(+) create mode 100644 sound/soc/codecs/mt6358.c create mode 100644 sound/soc/codecs/mt6358.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 71e6e123a115..55fd58015c2d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -110,6 +110,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C select SND_SOC_MT6351 if MTK_PMIC_WRAP + select SND_SOC_MT6358 if MTK_PMIC_WRAP select SND_SOC_NAU8540 if I2C select SND_SOC_NAU8810 if I2C select SND_SOC_NAU8822 if I2C @@ -1339,6 +1340,12 @@ config SND_SOC_ML26124 config SND_SOC_MT6351 tristate "MediaTek MT6351 Codec" +config SND_SOC_MT6358 + tristate "MediaTek MT6358 Codec" + help + Enable support for the platform which uses MT6358 as + external codec device. + config SND_SOC_NAU8540 tristate "Nuvoton Technology Corporation NAU85L40 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9bb3346fab2f..457f9ff5a2d4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -107,6 +107,7 @@ snd-soc-ml26124-objs := ml26124.o snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o snd-soc-mt6351-objs := mt6351.o +snd-soc-mt6358-objs := mt6358.o snd-soc-nau8540-objs := nau8540.o snd-soc-nau8810-objs := nau8810.o snd-soc-nau8822-objs := nau8822.o @@ -375,6 +376,7 @@ obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o +obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c new file mode 100644 index 000000000000..d4c4fee6d3d9 --- /dev/null +++ b/sound/soc/codecs/mt6358.c @@ -0,0 +1,2336 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt6358.c -- mt6358 ALSA SoC audio codec driver +// +// Copyright (c) 2018 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mt6358.h" + +enum { + AUDIO_ANALOG_VOLUME_HSOUTL, + AUDIO_ANALOG_VOLUME_HSOUTR, + AUDIO_ANALOG_VOLUME_HPOUTL, + AUDIO_ANALOG_VOLUME_HPOUTR, + AUDIO_ANALOG_VOLUME_LINEOUTL, + AUDIO_ANALOG_VOLUME_LINEOUTR, + AUDIO_ANALOG_VOLUME_MICAMP1, + AUDIO_ANALOG_VOLUME_MICAMP2, + AUDIO_ANALOG_VOLUME_TYPE_MAX +}; + +enum { + MUX_ADC_L, + MUX_ADC_R, + MUX_PGA_L, + MUX_PGA_R, + MUX_MIC_TYPE, + MUX_HP_L, + MUX_HP_R, + MUX_NUM, +}; + +enum { + DEVICE_HP, + DEVICE_LO, + DEVICE_RCV, + DEVICE_MIC1, + DEVICE_MIC2, + DEVICE_NUM +}; + +/* Supply widget subseq */ +enum { + /* common */ + SUPPLY_SEQ_CLK_BUF, + SUPPLY_SEQ_AUD_GLB, + SUPPLY_SEQ_CLKSQ, + SUPPLY_SEQ_VOW_AUD_LPW, + SUPPLY_SEQ_AUD_VOW, + SUPPLY_SEQ_VOW_CLK, + SUPPLY_SEQ_VOW_LDO, + SUPPLY_SEQ_TOP_CK, + SUPPLY_SEQ_TOP_CK_LAST, + SUPPLY_SEQ_AUD_TOP, + SUPPLY_SEQ_AUD_TOP_LAST, + SUPPLY_SEQ_AFE, + /* capture */ + SUPPLY_SEQ_ADC_SUPPLY, +}; + +enum { + CH_L = 0, + CH_R, + NUM_CH, +}; + +#define REG_STRIDE 2 + +struct mt6358_priv { + struct device *dev; + struct regmap *regmap; + + unsigned int dl_rate; + unsigned int ul_rate; + + int ana_gain[AUDIO_ANALOG_VOLUME_TYPE_MAX]; + unsigned int mux_select[MUX_NUM]; + + int dev_counter[DEVICE_NUM]; + + int mtkaif_protocol; + + struct regulator *avdd_reg; +}; + +int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, + int mtkaif_protocol) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + priv->mtkaif_protocol = mtkaif_protocol; + return 0; +} + +static void playback_gpio_set(struct mt6358_priv *priv) +{ + /* set gpio mosi mode */ + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2_CLR, + 0x01f8, 0x01f8); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2_SET, + 0xffff, 0x0249); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2, + 0xffff, 0x0249); +} + +static void playback_gpio_reset(struct mt6358_priv *priv) +{ + /* set pad_aud_*_mosi to GPIO mode and dir input + * reason: + * pad_aud_dat_mosi*, because the pin is used as boot strap + * don't clean clk/sync, for mtkaif protocol 2 + */ + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2_CLR, + 0x01f8, 0x01f8); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE2, + 0x01f8, 0x0000); + regmap_update_bits(priv->regmap, MT6358_GPIO_DIR0, + 0xf << 8, 0x0); +} + +static void capture_gpio_set(struct mt6358_priv *priv) +{ + /* set gpio miso mode */ + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_CLR, + 0xffff, 0xffff); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_SET, + 0xffff, 0x0249); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3, + 0xffff, 0x0249); +} + +static void capture_gpio_reset(struct mt6358_priv *priv) +{ + /* set pad_aud_*_miso to GPIO mode and dir input + * reason: + * pad_aud_clk_miso, because when playback only the miso_clk + * will also have 26m, so will have power leak + * pad_aud_dat_miso*, because the pin is used as boot strap + */ + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3_CLR, + 0xffff, 0xffff); + regmap_update_bits(priv->regmap, MT6358_GPIO_MODE3, + 0xffff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_GPIO_DIR0, + 0xf << 12, 0x0); +} + +/* use only when not govern by DAPM */ +static int mt6358_set_dcxo(struct mt6358_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6358_DCXO_CW14, + 0x1 << RG_XO_AUDIO_EN_M_SFT, + (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT); + return 0; +} + +/* use only when not govern by DAPM */ +static int mt6358_set_clksq(struct mt6358_priv *priv, bool enable) +{ + /* audio clk source from internal dcxo */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6, + RG_CLKSQ_IN_SEL_TEST_MASK_SFT, + 0x0); + + /* Enable/disable CLKSQ 26MHz */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6, + RG_CLKSQ_EN_MASK_SFT, + (enable ? 1 : 0) << RG_CLKSQ_EN_SFT); + return 0; +} + +/* use only when not govern by DAPM */ +static int mt6358_set_aud_global_bias(struct mt6358_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + RG_AUDGLB_PWRDN_VA28_MASK_SFT, + (enable ? 0 : 1) << RG_AUDGLB_PWRDN_VA28_SFT); + return 0; +} + +/* use only when not govern by DAPM */ +static int mt6358_set_topck(struct mt6358_priv *priv, bool enable) +{ + regmap_update_bits(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0, + 0x0066, enable ? 0x0 : 0x66); + return 0; +} + +static int mt6358_mtkaif_tx_enable(struct mt6358_priv *priv) +{ + switch (priv->mtkaif_protocol) { + case MT6358_MTKAIF_PROTOCOL_2_CLK_P2: + /* MTKAIF TX format setting */ + regmap_update_bits(priv->regmap, + MT6358_AFE_ADDA_MTKAIF_CFG0, + 0xffff, 0x0010); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, + MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3800); + regmap_update_bits(priv->regmap, + MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3900); + break; + case MT6358_MTKAIF_PROTOCOL_2: + /* MTKAIF TX format setting */ + regmap_update_bits(priv->regmap, + MT6358_AFE_ADDA_MTKAIF_CFG0, + 0xffff, 0x0010); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, + MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3100); + break; + case MT6358_MTKAIF_PROTOCOL_1: + default: + /* MTKAIF TX format setting */ + regmap_update_bits(priv->regmap, + MT6358_AFE_ADDA_MTKAIF_CFG0, + 0xffff, 0x0000); + /* enable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, + MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3100); + break; + } + return 0; +} + +static int mt6358_mtkaif_tx_disable(struct mt6358_priv *priv) +{ + /* disable aud_pad TX fifos */ + regmap_update_bits(priv->regmap, MT6358_AFE_AUD_PAD_TOP, + 0xff00, 0x3000); + return 0; +} + +int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + playback_gpio_set(priv); + capture_gpio_set(priv); + mt6358_mtkaif_tx_enable(priv); + + mt6358_set_dcxo(priv, true); + mt6358_set_aud_global_bias(priv, true); + mt6358_set_clksq(priv, true); + mt6358_set_topck(priv, true); + + /* set dat_miso_loopback on */ + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT, + 1 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT, + 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); + return 0; +} + +int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + /* set dat_miso_loopback off */ + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT, + 0 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT, + 0 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); + + mt6358_set_topck(priv, false); + mt6358_set_clksq(priv, false); + mt6358_set_aud_global_bias(priv, false); + mt6358_set_dcxo(priv, false); + + mt6358_mtkaif_tx_disable(priv); + playback_gpio_reset(priv); + capture_gpio_reset(priv); + return 0; +} + +int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, + int phase_1, int phase_2) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT, + phase_1 << RG_AUD_PAD_TOP_PHASE_MODE_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, + RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT, + phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT); + return 0; +} + +/* dl pga gain */ +enum { + DL_GAIN_8DB = 0, + DL_GAIN_0DB = 8, + DL_GAIN_N_1DB = 9, + DL_GAIN_N_10DB = 18, + DL_GAIN_N_40DB = 0x1f, +}; + +#define DL_GAIN_N_10DB_REG (DL_GAIN_N_10DB << 7 | DL_GAIN_N_10DB) +#define DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB) +#define DL_GAIN_REG_MASK 0x0f9f + +static void lo_store_gain(struct mt6358_priv *priv) +{ + unsigned int reg; + unsigned int gain_l, gain_r; + + regmap_read(priv->regmap, MT6358_ZCD_CON1, ®); + gain_l = (reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK; + gain_r = (reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK; + + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] = gain_l; + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] = gain_r; +} + +static void hp_store_gain(struct mt6358_priv *priv) +{ + unsigned int reg; + unsigned int gain_l, gain_r; + + regmap_read(priv->regmap, MT6358_ZCD_CON2, ®); + gain_l = (reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK; + gain_r = (reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK; + + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = gain_l; + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = gain_r; +} + +static void hp_zcd_disable(struct mt6358_priv *priv) +{ + regmap_write(priv->regmap, MT6358_ZCD_CON0, 0x0000); +} + +static void hp_main_output_ramp(struct mt6358_priv *priv, bool up) +{ + int i = 0, stage = 0; + int target = 7; + + /* Enable/Reduce HPL/R main output stage step by step */ + for (i = 0; i <= target; i++) { + stage = up ? i : target - i; + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x7 << 8, stage << 8); + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x7 << 11, stage << 11); + usleep_range(100, 150); + } +} + +static void hp_aux_feedback_loop_gain_ramp(struct mt6358_priv *priv, bool up) +{ + int i = 0, stage = 0; + + /* Reduce HP aux feedback loop gain step by step */ + for (i = 0; i <= 0xf; i++) { + stage = up ? i : 0xf - i; + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0xf << 12, stage << 12); + usleep_range(100, 150); + } +} + +static void hp_pull_down(struct mt6358_priv *priv, bool enable) +{ + int i; + + if (enable) { + for (i = 0x0; i <= 0x6; i++) { + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x7, i); + usleep_range(600, 700); + } + } else { + for (i = 0x6; i >= 0x1; i--) { + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x7, i); + usleep_range(600, 700); + } + } +} + +static bool is_valid_hp_pga_idx(int reg_idx) +{ + return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_10DB) || + reg_idx == DL_GAIN_N_40DB; +} + +static void headset_volume_ramp(struct mt6358_priv *priv, + int from, int to) +{ + int offset = 0, count = 1, reg_idx; + + if (!is_valid_hp_pga_idx(from) || !is_valid_hp_pga_idx(to)) + dev_warn(priv->dev, "%s(), volume index is not valid, from %d, to %d\n", + __func__, from, to); + + dev_info(priv->dev, "%s(), from %d, to %d\n", + __func__, from, to); + + if (to > from) + offset = to - from; + else + offset = from - to; + + while (offset > 0) { + if (to > from) + reg_idx = from + count; + else + reg_idx = from - count; + + if (is_valid_hp_pga_idx(reg_idx)) { + regmap_update_bits(priv->regmap, + MT6358_ZCD_CON2, + DL_GAIN_REG_MASK, + (reg_idx << 7) | reg_idx); + usleep_range(200, 300); + } + offset--; + count++; + } +} + +static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0); +static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0); + +static const struct snd_kcontrol_new mt6358_snd_controls[] = { + /* dl pga gain */ + SOC_DOUBLE_TLV("Headphone Volume", + MT6358_ZCD_CON2, 0, 7, 0x12, 1, + playback_tlv), + SOC_DOUBLE_TLV("Lineout Volume", + MT6358_ZCD_CON1, 0, 7, 0x12, 1, + playback_tlv), + SOC_SINGLE_TLV("Handset Volume", + MT6358_ZCD_CON3, 0, 0x12, 1, + playback_tlv), + /* ul pga gain */ + SOC_DOUBLE_R_TLV("PGA Volume", + MT6358_AUDENC_ANA_CON0, MT6358_AUDENC_ANA_CON1, + 8, 4, 0, + pga_tlv), +}; + +/* MUX */ +/* LOL MUX */ +static const char * const lo_in_mux_map[] = { + "Open", "Mute", "Playback", "Test Mode" +}; + +static int lo_in_mux_map_value[] = { + 0x0, 0x1, 0x2, 0x3, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(lo_in_mux_map_enum, + MT6358_AUDDEC_ANA_CON7, + RG_AUDLOLMUXINPUTSEL_VAUDP15_SFT, + RG_AUDLOLMUXINPUTSEL_VAUDP15_MASK, + lo_in_mux_map, + lo_in_mux_map_value); + +static const struct snd_kcontrol_new lo_in_mux_control = + SOC_DAPM_ENUM("In Select", lo_in_mux_map_enum); + +/*HP MUX */ +enum { + HP_MUX_OPEN = 0, + HP_MUX_HPSPK, + HP_MUX_HP, + HP_MUX_TEST_MODE, + HP_MUX_HP_IMPEDANCE, + HP_MUX_MASK = 0x7, +}; + +static const char * const hp_in_mux_map[] = { + "Open", + "LoudSPK Playback", + "Audio Playback", + "Test Mode", + "HP Impedance", + "undefined1", + "undefined2", + "undefined3", +}; + +static int hp_in_mux_map_value[] = { + HP_MUX_OPEN, + HP_MUX_HPSPK, + HP_MUX_HP, + HP_MUX_TEST_MODE, + HP_MUX_HP_IMPEDANCE, + HP_MUX_OPEN, + HP_MUX_OPEN, + HP_MUX_OPEN, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(hpl_in_mux_map_enum, + SND_SOC_NOPM, + 0, + HP_MUX_MASK, + hp_in_mux_map, + hp_in_mux_map_value); + +static const struct snd_kcontrol_new hpl_in_mux_control = + SOC_DAPM_ENUM("HPL Select", hpl_in_mux_map_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(hpr_in_mux_map_enum, + SND_SOC_NOPM, + 0, + HP_MUX_MASK, + hp_in_mux_map, + hp_in_mux_map_value); + +static const struct snd_kcontrol_new hpr_in_mux_control = + SOC_DAPM_ENUM("HPR Select", hpr_in_mux_map_enum); + +/* RCV MUX */ +enum { + RCV_MUX_OPEN = 0, + RCV_MUX_MUTE, + RCV_MUX_VOICE_PLAYBACK, + RCV_MUX_TEST_MODE, + RCV_MUX_MASK = 0x3, +}; + +static const char * const rcv_in_mux_map[] = { + "Open", "Mute", "Voice Playback", "Test Mode" +}; + +static int rcv_in_mux_map_value[] = { + RCV_MUX_OPEN, + RCV_MUX_MUTE, + RCV_MUX_VOICE_PLAYBACK, + RCV_MUX_TEST_MODE, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(rcv_in_mux_map_enum, + SND_SOC_NOPM, + 0, + RCV_MUX_MASK, + rcv_in_mux_map, + rcv_in_mux_map_value); + +static const struct snd_kcontrol_new rcv_in_mux_control = + SOC_DAPM_ENUM("RCV Select", rcv_in_mux_map_enum); + +/* DAC In MUX */ +static const char * const dac_in_mux_map[] = { + "Normal Path", "Sgen" +}; + +static int dac_in_mux_map_value[] = { + 0x0, 0x1, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(dac_in_mux_map_enum, + MT6358_AFE_TOP_CON0, + DL_SINE_ON_SFT, + DL_SINE_ON_MASK, + dac_in_mux_map, + dac_in_mux_map_value); + +static const struct snd_kcontrol_new dac_in_mux_control = + SOC_DAPM_ENUM("DAC Select", dac_in_mux_map_enum); + +/* AIF Out MUX */ +static SOC_VALUE_ENUM_SINGLE_DECL(aif_out_mux_map_enum, + MT6358_AFE_TOP_CON0, + UL_SINE_ON_SFT, + UL_SINE_ON_MASK, + dac_in_mux_map, + dac_in_mux_map_value); + +static const struct snd_kcontrol_new aif_out_mux_control = + SOC_DAPM_ENUM("AIF Out Select", aif_out_mux_map_enum); + +/* Mic Type MUX */ +enum { + MIC_TYPE_MUX_IDLE = 0, + MIC_TYPE_MUX_ACC, + MIC_TYPE_MUX_DMIC, + MIC_TYPE_MUX_DCC, + MIC_TYPE_MUX_DCC_ECM_DIFF, + MIC_TYPE_MUX_DCC_ECM_SINGLE, + MIC_TYPE_MUX_MASK = 0x7, +}; + +#define IS_DCC_BASE(type) ((type) == MIC_TYPE_MUX_DCC || \ + (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \ + (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE) + +static const char * const mic_type_mux_map[] = { + "Idle", + "ACC", + "DMIC", + "DCC", + "DCC_ECM_DIFF", + "DCC_ECM_SINGLE", +}; + +static int mic_type_mux_map_value[] = { + MIC_TYPE_MUX_IDLE, + MIC_TYPE_MUX_ACC, + MIC_TYPE_MUX_DMIC, + MIC_TYPE_MUX_DCC, + MIC_TYPE_MUX_DCC_ECM_DIFF, + MIC_TYPE_MUX_DCC_ECM_SINGLE, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(mic_type_mux_map_enum, + SND_SOC_NOPM, + 0, + MIC_TYPE_MUX_MASK, + mic_type_mux_map, + mic_type_mux_map_value); + +static const struct snd_kcontrol_new mic_type_mux_control = + SOC_DAPM_ENUM("Mic Type Select", mic_type_mux_map_enum); + +/* ADC L MUX */ +enum { + ADC_MUX_IDLE = 0, + ADC_MUX_AIN0, + ADC_MUX_PREAMPLIFIER, + ADC_MUX_IDLE1, + ADC_MUX_MASK = 0x3, +}; + +static const char * const adc_left_mux_map[] = { + "Idle", "AIN0", "Left Preamplifier", "Idle_1" +}; + +static int adc_mux_map_value[] = { + ADC_MUX_IDLE, + ADC_MUX_AIN0, + ADC_MUX_PREAMPLIFIER, + ADC_MUX_IDLE1, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adc_left_mux_map_enum, + SND_SOC_NOPM, + 0, + ADC_MUX_MASK, + adc_left_mux_map, + adc_mux_map_value); + +static const struct snd_kcontrol_new adc_left_mux_control = + SOC_DAPM_ENUM("ADC L Select", adc_left_mux_map_enum); + +/* ADC R MUX */ +static const char * const adc_right_mux_map[] = { + "Idle", "AIN0", "Right Preamplifier", "Idle_1" +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(adc_right_mux_map_enum, + SND_SOC_NOPM, + 0, + ADC_MUX_MASK, + adc_right_mux_map, + adc_mux_map_value); + +static const struct snd_kcontrol_new adc_right_mux_control = + SOC_DAPM_ENUM("ADC R Select", adc_right_mux_map_enum); + +/* PGA L MUX */ +enum { + PGA_MUX_NONE = 0, + PGA_MUX_AIN0, + PGA_MUX_AIN1, + PGA_MUX_AIN2, + PGA_MUX_MASK = 0x3, +}; + +static const char * const pga_mux_map[] = { + "None", "AIN0", "AIN1", "AIN2" +}; + +static int pga_mux_map_value[] = { + PGA_MUX_NONE, + PGA_MUX_AIN0, + PGA_MUX_AIN1, + PGA_MUX_AIN2, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(pga_left_mux_map_enum, + SND_SOC_NOPM, + 0, + PGA_MUX_MASK, + pga_mux_map, + pga_mux_map_value); + +static const struct snd_kcontrol_new pga_left_mux_control = + SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum); + +/* PGA R MUX */ +static SOC_VALUE_ENUM_SINGLE_DECL(pga_right_mux_map_enum, + SND_SOC_NOPM, + 0, + PGA_MUX_MASK, + pga_mux_map, + pga_mux_map_value); + +static const struct snd_kcontrol_new pga_right_mux_control = + SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum); + +static int mt_clksq_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* audio clk source from internal dcxo */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6, + RG_CLKSQ_IN_SEL_TEST_MASK_SFT, + 0x0); + break; + default: + break; + } + + return 0; +} + +static int mt_sgen_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event = 0x%x\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* sdm audio fifo clock power on */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0006); + /* scrambler clock on enable */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xCBA1); + /* sdm power on */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0003); + /* sdm fifo enable */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x000B); + + regmap_update_bits(priv->regmap, MT6358_AFE_SGEN_CFG0, + 0xff3f, + 0x0000); + regmap_update_bits(priv->regmap, MT6358_AFE_SGEN_CFG1, + 0xffff, + 0x0001); + break; + case SND_SOC_DAPM_POST_PMD: + /* DL scrambler disabling sequence */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0000); + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba0); + break; + default: + break; + } + + return 0; +} + +static int mt_aif_in_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_info(priv->dev, "%s(), event 0x%x, rate %d\n", + __func__, event, priv->dl_rate); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + playback_gpio_set(priv); + + /* sdm audio fifo clock power on */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0006); + /* scrambler clock on enable */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xCBA1); + /* sdm power on */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0003); + /* sdm fifo enable */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x000B); + break; + case SND_SOC_DAPM_POST_PMD: + /* DL scrambler disabling sequence */ + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON2, 0x0000); + regmap_write(priv->regmap, MT6358_AFUNC_AUD_CON0, 0xcba0); + + playback_gpio_reset(priv); + break; + default: + break; + } + + return 0; +} + +static int mtk_hp_enable(struct mt6358_priv *priv) +{ + /* Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, true); + /* release HP CMFB gate rstb */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x1 << 6, 0x1 << 6); + + /* Reduce ESD resistance of AU_REFN */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000); + + /* save target gain to restore after hardware open complete */ + hp_store_gain(priv); + /* Set HPR/HPL gain as minimum (~ -40dB) */ + regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_40DB_REG); + + /* Turn on DA_600K_NCP_VA18 */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001); + /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c); + /* Toggle RG_DIVCKS_CHG */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001); + /* Set NCP soft start mode as default mode: 100us */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0003); + /* Enable NCP */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000); + usleep_range(250, 270); + + /* Enable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x1055); + /* Enable NV regulator (-1.2V) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001); + usleep_range(100, 120); + + /* Disable AUD_ZCD */ + hp_zcd_disable(priv); + + /* Disable headphone short-circuit protection */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000); + + /* Enable IBIST */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + + /* Set HP DR bias current optimization, 010: 6uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON11, 0x4900); + /* Set HP & ZCD bias current optimization */ + /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + /* Set HPP/N STB enhance circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4033); + + /* Enable HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x000c); + /* Enable HP aux feedback loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x003c); + /* Enable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0c00); + /* Enable HP driver bias circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0); + /* Enable HP driver core circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30f0); + /* Short HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x00fc); + + /* Enable HP main CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0e00); + /* Disable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0200); + + /* Select CMFB resistor bulk to AC mode */ + /* Selec HS/LO cap size (6.5pF default) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000); + + /* Enable HP main output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x00ff); + /* Enable HPR/L main output stage step by step */ + hp_main_output_ramp(priv, true); + + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, true); + /* Disable HP aux feedback loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf); + + /* apply volume setting */ + headset_volume_ramp(priv, + DL_GAIN_N_10DB, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]); + + /* Disable HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3); + /* Unshort HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3f03); + usleep_range(100, 120); + + /* Enable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1); + /* Enable Audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30ff); + /* Enable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0xf201); + usleep_range(100, 120); + + /* Switch HPL MUX to audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x32ff); + /* Switch HPR MUX to audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3aff); + + /* Disable Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, false); + + return 0; +} + +static int mtk_hp_disable(struct mt6358_priv *priv) +{ + /* Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, true); + + /* HPR/HPL mux to open */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x0f00, 0x0000); + + /* Disable low-noise mode of DAC */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0x0001, 0x0000); + + /* Disable Audio DAC */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x000f, 0x0000); + + /* Disable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0); + + /* Short HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3); + /* Enable HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf); + + /* decrease HPL/R gain to normal gain step by step */ + headset_volume_ramp(priv, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL], + DL_GAIN_N_40DB); + + /* Enable HP aux feedback loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fff); + + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, false); + + /* decrease HPR/L main output stage step by step */ + hp_main_output_ramp(priv, false); + + /* Disable HP main output stage */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0); + + /* Enable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0e00); + + /* Disable HP main CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0c00); + + /* Unshort HP main output to HP aux output stage */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x3 << 6, 0x0); + + /* Disable HP driver core circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x3 << 4, 0x0); + + /* Disable HP driver bias circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x3 << 6, 0x0); + + /* Disable HP aux CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0000); + + /* Disable HP aux feedback loop */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x3 << 4, 0x0); + + /* Disable HP aux output stage */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, + 0x3 << 2, 0x0); + + /* Disable IBIST */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12, + 0x1 << 8, 0x1 << 8); + + /* Disable NV regulator (-1.2V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0); + /* Disable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x0); + /* Disable NCP */ + regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, + 0x1, 0x1); + + /* Increase ESD resistance of AU_REFN */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON2, + 0x1 << 14, 0x0); + + /* Set HP CMFB gate rstb */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x1 << 6, 0x0); + /* disable Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, false); + + return 0; +} + +static int mtk_hp_spk_enable(struct mt6358_priv *priv) +{ + /* Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, true); + /* release HP CMFB gate rstb */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x1 << 6, 0x1 << 6); + + /* Reduce ESD resistance of AU_REFN */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000); + + /* save target gain to restore after hardware open complete */ + hp_store_gain(priv); + /* Set HPR/HPL gain to -10dB */ + regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG); + + /* Turn on DA_600K_NCP_VA18 */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001); + /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c); + /* Toggle RG_DIVCKS_CHG */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001); + /* Set NCP soft start mode as default mode: 100us */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0003); + /* Enable NCP */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000); + usleep_range(250, 270); + + /* Enable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x1055); + /* Enable NV regulator (-1.2V) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001); + usleep_range(100, 120); + + /* Disable AUD_ZCD */ + hp_zcd_disable(priv); + + /* Disable headphone short-circuit protection */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x3000); + + /* Enable IBIST */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + + /* Set HP DR bias current optimization, 010: 6uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON11, 0x4900); + /* Set HP & ZCD bias current optimization */ + /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + /* Set HPP/N STB enhance circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4033); + + /* Disable Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, false); + + /* Enable HP driver bias circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30c0); + /* Enable HP driver core circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30f0); + /* Enable HP main CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0200); + + /* Select CMFB resistor bulk to AC mode */ + /* Selec HS/LO cap size (6.5pF default) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000); + + /* Enable HP main output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x0003); + /* Enable HPR/L main output stage step by step */ + hp_main_output_ramp(priv, true); + + /* Set LO gain as minimum (~ -40dB) */ + lo_store_gain(priv); + regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_40DB_REG); + /* apply volume setting */ + headset_volume_ramp(priv, + DL_GAIN_N_10DB, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL]); + + /* Set LO STB enhance circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0110); + /* Enable LO driver bias circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0112); + /* Enable LO driver core circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x0113); + + /* Set LOL gain to normal gain step by step */ + regmap_update_bits(priv->regmap, MT6358_ZCD_CON1, + RG_AUDLOLGAIN_MASK_SFT, + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] << + RG_AUDLOLGAIN_SFT); + regmap_update_bits(priv->regmap, MT6358_ZCD_CON1, + RG_AUDLORGAIN_MASK_SFT, + priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] << + RG_AUDLORGAIN_SFT); + + /* Enable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x1); + /* Enable Audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x30f9); + /* Enable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0201); + /* Switch LOL MUX to audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON7, 0x011b); + /* Switch HPL/R MUX to Line-out */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x35f9); + + return 0; +} + +static int mtk_hp_spk_disable(struct mt6358_priv *priv) +{ + /* HPR/HPL mux to open */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x0f00, 0x0000); + /* LOL mux to open */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7, + 0x3 << 2, 0x0000); + + /* Disable Audio DAC */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x000f, 0x0000); + + /* Disable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, 0x1, 0x0); + + /* decrease HPL/R gain to normal gain step by step */ + headset_volume_ramp(priv, + priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL], + DL_GAIN_N_40DB); + + /* decrease LOL gain to minimum gain step by step */ + regmap_update_bits(priv->regmap, MT6358_ZCD_CON1, + DL_GAIN_REG_MASK, DL_GAIN_N_40DB_REG); + + /* decrease HPR/L main output stage step by step */ + hp_main_output_ramp(priv, false); + + /* Disable HP main output stage */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3, 0x0); + + /* Short HP main output to HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fc3); + /* Enable HP aux output stage */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fcf); + + /* Enable HP aux feedback loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON1, 0x3fff); + + /* Reduce HP aux feedback loop gain */ + hp_aux_feedback_loop_gain_ramp(priv, false); + + /* Disable HP driver core circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x3 << 4, 0x0); + /* Disable LO driver core circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7, + 0x1, 0x0); + + /* Disable HP driver bias circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x3 << 6, 0x0); + /* Disable LO driver bias circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7, + 0x1 << 1, 0x0); + + /* Disable HP aux CMFB loop */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0xff << 8, 0x0000); + + /* Disable IBIST */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12, + 0x1 << 8, 0x1 << 8); + /* Disable NV regulator (-1.2V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x1, 0x0); + /* Disable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, 0x1055, 0x0); + /* Disable NCP */ + regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x1, 0x1); + + /* Set HP CMFB gate rstb */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON4, + 0x1 << 6, 0x0); + /* disable Pull-down HPL/R to AVSS28_AUD */ + hp_pull_down(priv, false); + + return 0; +} + +static int mt_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + int device = DEVICE_HP; + + dev_info(priv->dev, "%s(), event 0x%x, dev_counter[DEV_HP] %d, mux %u\n", + __func__, + event, + priv->dev_counter[device], + mux); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + priv->dev_counter[device]++; + if (priv->dev_counter[device] > 1) + break; /* already enabled, do nothing */ + else if (priv->dev_counter[device] <= 0) + dev_warn(priv->dev, "%s(), dev_counter[DEV_HP] %d <= 0\n", + __func__, + priv->dev_counter[device]); + + priv->mux_select[MUX_HP_L] = mux; + + if (mux == HP_MUX_HP) + mtk_hp_enable(priv); + else if (mux == HP_MUX_HPSPK) + mtk_hp_spk_enable(priv); + break; + case SND_SOC_DAPM_PRE_PMD: + priv->dev_counter[device]--; + if (priv->dev_counter[device] > 0) { + break; /* still being used, don't close */ + } else if (priv->dev_counter[device] < 0) { + dev_warn(priv->dev, "%s(), dev_counter[DEV_HP] %d < 0\n", + __func__, + priv->dev_counter[device]); + priv->dev_counter[device] = 0; + break; + } + + if (priv->mux_select[MUX_HP_L] == HP_MUX_HP) + mtk_hp_disable(priv); + else if (priv->mux_select[MUX_HP_L] == HP_MUX_HPSPK) + mtk_hp_spk_disable(priv); + + priv->mux_select[MUX_HP_L] = mux; + break; + default: + break; + } + + return 0; +} + +static int mt_rcv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_info(priv->dev, "%s(), event 0x%x, mux %u\n", + __func__, + event, + dapm_kcontrol_get_value(w->kcontrols[0])); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reduce ESD resistance of AU_REFN */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000); + + /* Turn on DA_600K_NCP_VA18 */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON1, 0x0001); + /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON2, 0x002c); + /* Toggle RG_DIVCKS_CHG */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON0, 0x0001); + /* Set NCP soft start mode as default mode: 100us */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON4, 0x0003); + /* Enable NCP */ + regmap_write(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, 0x0000); + usleep_range(250, 270); + + /* Enable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x1055); + /* Enable NV regulator (-1.2V) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON15, 0x0001); + usleep_range(100, 120); + + /* Disable AUD_ZCD */ + hp_zcd_disable(priv); + + /* Disable handset short-circuit protection */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0010); + + /* Enable IBIST */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + /* Set HP DR bias current optimization, 010: 6uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON11, 0x4900); + /* Set HP & ZCD bias current optimization */ + /* 01: ZCD: 4uA, HP/HS/LO: 5uA */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON12, 0x0055); + /* Set HS STB enhance circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0090); + + /* Disable HP main CMFB loop */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0000); + /* Select CMFB resistor bulk to AC mode */ + /* Selec HS/LO cap size (6.5pF default) */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON10, 0x0000); + + /* Enable HS driver bias circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0092); + /* Enable HS driver core circuits */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x0093); + + /* Enable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0x1, 0x1); + + /* Enable Audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON0, 0x0009); + /* Enable low-noise mode of DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON9, 0x0001); + /* Switch HS MUX to audio DAC */ + regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON6, 0x009b); + break; + case SND_SOC_DAPM_PRE_PMD: + /* HS mux to open */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6, + RG_AUDHSMUXINPUTSEL_VAUDP15_MASK_SFT, + RCV_MUX_OPEN); + + /* Disable Audio DAC */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + 0x000f, 0x0000); + + /* Disable AUD_CLK */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0x1, 0x0); + + /* decrease HS gain to minimum gain step by step */ + regmap_write(priv->regmap, MT6358_ZCD_CON3, DL_GAIN_N_40DB); + + /* Disable HS driver core circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6, + 0x1, 0x0); + + /* Disable HS driver bias circuits */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6, + 0x1 << 1, 0x0000); + + /* Disable HP aux CMFB loop */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0xff << 8, 0x0); + + /* Enable HP main CMFB Switch */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON9, + 0xff << 8, 0x2 << 8); + + /* Disable IBIST */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON12, + 0x1 << 8, 0x1 << 8); + + /* Disable NV regulator (-1.2V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON15, + 0x1, 0x0); + /* Disable cap-less LDOs (1.5V) */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x1055, 0x0); + /* Disable NCP */ + regmap_update_bits(priv->regmap, MT6358_AUDNCP_CLKDIV_CON3, + 0x1, 0x1); + break; + default: + break; + } + + return 0; +} + +static int mt_aif_out_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event 0x%x, rate %d\n", + __func__, event, priv->ul_rate); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + capture_gpio_set(priv); + break; + case SND_SOC_DAPM_POST_PMD: + capture_gpio_reset(priv); + break; + default: + break; + } + + return 0; +} + +static int mt_adc_supply_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + + dev_dbg(priv->dev, "%s(), event 0x%x\n", + __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable audio ADC CLKGEN */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0x1 << 5, 0x1 << 5); + /* ADC CLK from CLKGEN (13MHz) */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON3, + 0x0000); + /* Enable LCLDO_ENC 1P8V */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x2500, 0x0100); + /* LCLDO_ENC remote sense */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x2500, 0x2500); + break; + case SND_SOC_DAPM_POST_PMD: + /* LCLDO_ENC remote sense off */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x2500, 0x0100); + /* disable LCLDO_ENC 1P8V */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON14, + 0x2500, 0x0000); + + /* ADC CLK from CLKGEN (13MHz) */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON3, 0x0000); + /* disable audio ADC CLKGEN */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, + 0x1 << 5, 0x0 << 5); + break; + default: + break; + } + + return 0; +} + +static int mt6358_amic_enable(struct mt6358_priv *priv) +{ + unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE]; + unsigned int mux_pga_l = priv->mux_select[MUX_PGA_L]; + unsigned int mux_pga_r = priv->mux_select[MUX_PGA_R]; + + dev_info(priv->dev, "%s(), mux, mic %u, pga l %u, pga r %u\n", + __func__, mic_type, mux_pga_l, mux_pga_r); + + if (IS_DCC_BASE(mic_type)) { + /* DCC 50k CLK (from 26M) */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2060); + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2061); + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG1, 0x0100); + } + + /* mic bias 0 */ + if (mux_pga_l == PGA_MUX_AIN0 || mux_pga_l == PGA_MUX_AIN2 || + mux_pga_r == PGA_MUX_AIN0 || mux_pga_r == PGA_MUX_AIN2) { + switch (mic_type) { + case MIC_TYPE_MUX_DCC_ECM_DIFF: + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xff00, 0x7700); + break; + case MIC_TYPE_MUX_DCC_ECM_SINGLE: + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xff00, 0x1100); + break; + default: + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xff00, 0x0000); + break; + } + /* Enable MICBIAS0, MISBIAS0 = 1P9V */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON9, + 0xff, 0x21); + } + + /* mic bias 1 */ + if (mux_pga_l == PGA_MUX_AIN1 || mux_pga_r == PGA_MUX_AIN1) { + /* Enable MICBIAS1, MISBIAS1 = 2P6V */ + if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE) + regmap_write(priv->regmap, + MT6358_AUDENC_ANA_CON10, 0x0161); + else + regmap_write(priv->regmap, + MT6358_AUDENC_ANA_CON10, 0x0061); + } + + if (IS_DCC_BASE(mic_type)) { + /* Audio L/R preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0xf8ff, 0x0004); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0xf8ff, 0x0004); + } else { + /* reset reg */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0xf8ff, 0x0000); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0xf8ff, 0x0000); + } + + if (mux_pga_l != PGA_MUX_NONE) { + /* L preamplifier input sel */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDPREAMPLINPUTSEL_MASK_SFT, + mux_pga_l << RG_AUDPREAMPLINPUTSEL_SFT); + + /* L preamplifier enable */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDPREAMPLON_MASK_SFT, + 0x1 << RG_AUDPREAMPLON_SFT); + + if (IS_DCC_BASE(mic_type)) { + /* L preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDPREAMPLDCCEN_MASK_SFT, + 0x1 << RG_AUDPREAMPLDCCEN_SFT); + } + + /* L ADC input sel : L PGA. Enable audio L ADC */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDADCLINPUTSEL_MASK_SFT, + ADC_MUX_PREAMPLIFIER << + RG_AUDADCLINPUTSEL_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDADCLPWRUP_MASK_SFT, + 0x1 << RG_AUDADCLPWRUP_SFT); + } + + if (mux_pga_r != PGA_MUX_NONE) { + /* R preamplifier input sel */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDPREAMPRINPUTSEL_MASK_SFT, + mux_pga_r << RG_AUDPREAMPRINPUTSEL_SFT); + + /* R preamplifier enable */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDPREAMPRON_MASK_SFT, + 0x1 << RG_AUDPREAMPRON_SFT); + + if (IS_DCC_BASE(mic_type)) { + /* R preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDPREAMPRDCCEN_MASK_SFT, + 0x1 << RG_AUDPREAMPRDCCEN_SFT); + } + + /* R ADC input sel : R PGA. Enable audio R ADC */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDADCRINPUTSEL_MASK_SFT, + ADC_MUX_PREAMPLIFIER << + RG_AUDADCRINPUTSEL_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDADCRPWRUP_MASK_SFT, + 0x1 << RG_AUDADCRPWRUP_SFT); + } + + if (IS_DCC_BASE(mic_type)) { + usleep_range(100, 150); + /* Audio L preamplifier DCC precharge off */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDPREAMPLDCPRECHARGE_MASK_SFT, 0x0); + /* Audio R preamplifier DCC precharge off */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDPREAMPRDCPRECHARGE_MASK_SFT, 0x0); + + /* Short body to ground in PGA */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON3, + 0x1 << 12, 0x0); + } + + /* here to set digital part */ + mt6358_mtkaif_tx_enable(priv); + + /* UL dmic setting off */ + regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_H, 0x0000); + + /* UL turn on */ + regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0001); + + return 0; +} + +static void mt6358_amic_disable(struct mt6358_priv *priv) +{ + unsigned int mic_type = priv->mux_select[MUX_MIC_TYPE]; + unsigned int mux_pga_l = priv->mux_select[MUX_PGA_L]; + unsigned int mux_pga_r = priv->mux_select[MUX_PGA_R]; + + dev_info(priv->dev, "%s(), mux, mic %u, pga l %u, pga r %u\n", + __func__, mic_type, mux_pga_l, mux_pga_r); + + /* UL turn off */ + regmap_update_bits(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, + 0x0001, 0x0000); + + /* disable aud_pad TX fifos */ + mt6358_mtkaif_tx_disable(priv); + + /* L ADC input sel : off, disable L ADC */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0xf000, 0x0000); + /* L preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0x1 << 1, 0x0); + /* L preamplifier input sel : off, L PGA 0 dB gain */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0xfffb, 0x0000); + + /* disable L preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + 0x1 << 2, 0x0); + + /* R ADC input sel : off, disable R ADC */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0xf000, 0x0000); + /* R preamplifier DCCEN */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0x1 << 1, 0x0); + /* R preamplifier input sel : off, R PGA 0 dB gain */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0x0ffb, 0x0000); + + /* disable R preamplifier DCC precharge */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + 0x1 << 2, 0x0); + + /* mic bias */ + /* Disable MICBIAS0, MISBIAS0 = 1P7V */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000); + + /* Disable MICBIAS1 */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON10, + 0x0001, 0x0000); + + if (IS_DCC_BASE(mic_type)) { + /* dcclk_gen_on=1'b0 */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2060); + /* dcclk_pdn=1'b1 */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + /* dcclk_ref_ck_sel=2'b00 */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + /* dcclk_div=11'b00100000011 */ + regmap_write(priv->regmap, MT6358_AFE_DCCLK_CFG0, 0x2062); + } +} + +static int mt6358_dmic_enable(struct mt6358_priv *priv) +{ + dev_info(priv->dev, "%s()\n", __func__); + + /* mic bias */ + /* Enable MICBIAS0, MISBIAS0 = 1P9V */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0021); + + /* RG_BANDGAPGEN=1'b0 */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON10, + 0x1 << 12, 0x0); + + /* DMIC enable */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0005); + + /* here to set digital part */ + mt6358_mtkaif_tx_enable(priv); + + /* UL dmic setting */ + regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_H, 0x0080); + + /* UL turn on */ + regmap_write(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, 0x0003); + return 0; +} + +static void mt6358_dmic_disable(struct mt6358_priv *priv) +{ + dev_info(priv->dev, "%s()\n", __func__); + + /* UL turn off */ + regmap_update_bits(priv->regmap, MT6358_AFE_UL_SRC_CON0_L, + 0x0003, 0x0000); + + /* disable aud_pad TX fifos */ + mt6358_mtkaif_tx_disable(priv); + + /* DMIC disable */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON8, 0x0000); + + /* mic bias */ + /* MISBIAS0 = 1P7V */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0001); + + /* RG_BANDGAPGEN=1'b0 */ + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON10, + 0x1 << 12, 0x0); + + /* MICBIA0 disable */ + regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000); +} + +static int mt_mic_type_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n", + __func__, event, mux); + + switch (event) { + case SND_SOC_DAPM_WILL_PMU: + priv->mux_select[MUX_MIC_TYPE] = mux; + break; + case SND_SOC_DAPM_PRE_PMU: + switch (mux) { + case MIC_TYPE_MUX_DMIC: + mt6358_dmic_enable(priv); + break; + default: + mt6358_amic_enable(priv); + break; + } + + break; + case SND_SOC_DAPM_POST_PMD: + switch (priv->mux_select[MUX_MIC_TYPE]) { + case MIC_TYPE_MUX_DMIC: + mt6358_dmic_disable(priv); + break; + default: + mt6358_amic_disable(priv); + break; + } + + priv->mux_select[MUX_MIC_TYPE] = mux; + break; + default: + break; + } + + return 0; +} + +static int mt_adc_l_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n", + __func__, event, mux); + + priv->mux_select[MUX_ADC_L] = mux; + + return 0; +} + +static int mt_adc_r_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n", + __func__, event, mux); + + priv->mux_select[MUX_ADC_R] = mux; + + return 0; +} + +static int mt_pga_left_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n", + __func__, event, mux); + + priv->mux_select[MUX_PGA_L] = mux; + + return 0; +} + +static int mt_pga_right_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]); + + dev_dbg(priv->dev, "%s(), event = 0x%x, mux %u\n", + __func__, event, mux); + + priv->mux_select[MUX_PGA_R] = mux; + + return 0; +} + +static int mt_delay_250_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + usleep_range(250, 270); + break; + case SND_SOC_DAPM_PRE_PMD: + usleep_range(250, 270); + break; + default: + break; + } + + return 0; +} + +/* DAPM Widgets */ +static const struct snd_soc_dapm_widget mt6358_dapm_widgets[] = { + /* Global Supply*/ + SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF, + MT6358_DCXO_CW14, + RG_XO_AUDIO_EN_M_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB, + MT6358_AUDDEC_ANA_CON13, + RG_AUDGLB_PWRDN_VA28_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("CLKSQ Audio", SUPPLY_SEQ_CLKSQ, + MT6358_AUDENC_ANA_CON6, + RG_CLKSQ_EN_SFT, 0, + mt_clksq_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("AUDNCP_CK", SUPPLY_SEQ_TOP_CK, + MT6358_AUD_TOP_CKPDN_CON0, + RG_AUDNCP_CK_PDN_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ZCD13M_CK", SUPPLY_SEQ_TOP_CK, + MT6358_AUD_TOP_CKPDN_CON0, + RG_ZCD13M_CK_PDN_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUD_CK", SUPPLY_SEQ_TOP_CK_LAST, + MT6358_AUD_TOP_CKPDN_CON0, + RG_AUD_CK_PDN_SFT, 1, + mt_delay_250_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK, + MT6358_AUD_TOP_CKPDN_CON0, + RG_AUDIF_CK_PDN_SFT, 1, NULL, 0), + + /* Digital Clock */ + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST, + MT6358_AUDIO_TOP_CON0, + PDN_AFE_CTL_SFT, 1, + mt_delay_250_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_DAC_CTL", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_DAC_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADC_CTL", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_ADC_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_I2S_DL", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_I2S_DL_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PWR_CLK", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PWR_CLK_DIS_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_AFE_TESTMODEL", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_AFE_TESTMODEL_CTL_SFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_RESERVED", SUPPLY_SEQ_AUD_TOP, + MT6358_AUDIO_TOP_CON0, + PDN_RESERVED_SFT, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DL Digital Clock", SND_SOC_NOPM, + 0, 0, NULL, 0), + + /* AFE ON */ + SND_SOC_DAPM_SUPPLY_S("AFE_ON", SUPPLY_SEQ_AFE, + MT6358_AFE_UL_DL_CON0, AFE_ON_SFT, 0, + NULL, 0), + + /* AIF Rx*/ + SND_SOC_DAPM_AIF_IN_E("AIF_RX", "AIF1 Playback", 0, + MT6358_AFE_DL_SRC2_CON0_L, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, + mt_aif_in_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* DL Supply */ + SND_SOC_DAPM_SUPPLY("DL Power Supply", SND_SOC_NOPM, + 0, 0, NULL, 0), + + /* DAC */ + SND_SOC_DAPM_MUX("DAC In Mux", SND_SOC_NOPM, 0, 0, &dac_in_mux_control), + + SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), + + /* LOL */ + SND_SOC_DAPM_MUX("LOL Mux", SND_SOC_NOPM, 0, 0, &lo_in_mux_control), + + SND_SOC_DAPM_SUPPLY("LO Stability Enh", MT6358_AUDDEC_ANA_CON7, + RG_LOOUTPUTSTBENH_VAUDP15_SFT, 0, NULL, 0), + + SND_SOC_DAPM_OUT_DRV("LOL Buffer", MT6358_AUDDEC_ANA_CON7, + RG_AUDLOLPWRUP_VAUDP15_SFT, 0, NULL, 0), + + /* Headphone */ + SND_SOC_DAPM_MUX_E("HPL Mux", SND_SOC_NOPM, 0, 0, + &hpl_in_mux_control, + mt_hp_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MUX_E("HPR Mux", SND_SOC_NOPM, 0, 0, + &hpr_in_mux_control, + mt_hp_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_PRE_PMD), + + /* Receiver */ + SND_SOC_DAPM_MUX_E("RCV Mux", SND_SOC_NOPM, 0, 0, + &rcv_in_mux_control, + mt_rcv_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_PRE_PMD), + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("Receiver"), + SND_SOC_DAPM_OUTPUT("Headphone L"), + SND_SOC_DAPM_OUTPUT("Headphone R"), + SND_SOC_DAPM_OUTPUT("Headphone L Ext Spk Amp"), + SND_SOC_DAPM_OUTPUT("Headphone R Ext Spk Amp"), + SND_SOC_DAPM_OUTPUT("LINEOUT L"), + SND_SOC_DAPM_OUTPUT("LINEOUT L HSSPK"), + + /* SGEN */ + SND_SOC_DAPM_SUPPLY("SGEN DL Enable", MT6358_AFE_SGEN_CFG0, + SGEN_DAC_EN_CTL_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("SGEN MUTE", MT6358_AFE_SGEN_CFG0, + SGEN_MUTE_SW_CTL_SFT, 1, + mt_sgen_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("SGEN DL SRC", MT6358_AFE_DL_SRC2_CON0_L, + DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, NULL, 0), + + SND_SOC_DAPM_INPUT("SGEN DL"), + + /* Uplinks */ + SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "AIF1 Capture", 0, + SND_SOC_NOPM, 0, 0, + mt_aif_out_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("ADC Supply", SUPPLY_SEQ_ADC_SUPPLY, + SND_SOC_NOPM, 0, 0, + mt_adc_supply_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + /* Uplinks MUX */ + SND_SOC_DAPM_MUX("AIF Out Mux", SND_SOC_NOPM, 0, 0, + &aif_out_mux_control), + + SND_SOC_DAPM_MUX_E("Mic Type Mux", SND_SOC_NOPM, 0, 0, + &mic_type_mux_control, + mt_mic_type_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_WILL_PMU), + + SND_SOC_DAPM_MUX_E("ADC L Mux", SND_SOC_NOPM, 0, 0, + &adc_left_mux_control, + mt_adc_l_event, + SND_SOC_DAPM_WILL_PMU), + SND_SOC_DAPM_MUX_E("ADC R Mux", SND_SOC_NOPM, 0, 0, + &adc_right_mux_control, + mt_adc_r_event, + SND_SOC_DAPM_WILL_PMU), + + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MUX_E("PGA L Mux", SND_SOC_NOPM, 0, 0, + &pga_left_mux_control, + mt_pga_left_event, + SND_SOC_DAPM_WILL_PMU), + SND_SOC_DAPM_MUX_E("PGA R Mux", SND_SOC_NOPM, 0, 0, + &pga_right_mux_control, + mt_pga_right_event, + SND_SOC_DAPM_WILL_PMU), + + SND_SOC_DAPM_PGA("PGA L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("PGA R", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* UL input */ + SND_SOC_DAPM_INPUT("AIN0"), + SND_SOC_DAPM_INPUT("AIN1"), + SND_SOC_DAPM_INPUT("AIN2"), +}; + +static const struct snd_soc_dapm_route mt6358_dapm_routes[] = { + /* Capture */ + {"AIF1TX", NULL, "AIF Out Mux"}, + {"AIF1TX", NULL, "CLK_BUF"}, + {"AIF1TX", NULL, "AUDGLB"}, + {"AIF1TX", NULL, "CLKSQ Audio"}, + + {"AIF1TX", NULL, "AUD_CK"}, + {"AIF1TX", NULL, "AUDIF_CK"}, + + {"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"}, + {"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"}, + {"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"}, + {"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"}, + {"AIF1TX", NULL, "AUDIO_TOP_I2S_DL"}, + + {"AIF1TX", NULL, "AFE_ON"}, + + {"AIF Out Mux", NULL, "Mic Type Mux"}, + + {"Mic Type Mux", "ACC", "ADC L"}, + {"Mic Type Mux", "ACC", "ADC R"}, + {"Mic Type Mux", "DCC", "ADC L"}, + {"Mic Type Mux", "DCC", "ADC R"}, + {"Mic Type Mux", "DCC_ECM_DIFF", "ADC L"}, + {"Mic Type Mux", "DCC_ECM_DIFF", "ADC R"}, + {"Mic Type Mux", "DCC_ECM_SINGLE", "ADC L"}, + {"Mic Type Mux", "DCC_ECM_SINGLE", "ADC R"}, + {"Mic Type Mux", "DMIC", "AIN0"}, + {"Mic Type Mux", "DMIC", "AIN2"}, + + {"ADC L", NULL, "ADC L Mux"}, + {"ADC L", NULL, "ADC Supply"}, + {"ADC R", NULL, "ADC R Mux"}, + {"ADC R", NULL, "ADC Supply"}, + + {"ADC L Mux", "Left Preamplifier", "PGA L"}, + + {"ADC R Mux", "Right Preamplifier", "PGA R"}, + + {"PGA L", NULL, "PGA L Mux"}, + {"PGA R", NULL, "PGA R Mux"}, + + {"PGA L Mux", "AIN0", "AIN0"}, + {"PGA L Mux", "AIN1", "AIN1"}, + {"PGA L Mux", "AIN2", "AIN2"}, + + {"PGA R Mux", "AIN0", "AIN0"}, + {"PGA R Mux", "AIN1", "AIN1"}, + {"PGA R Mux", "AIN2", "AIN2"}, + + /* DL Supply */ + {"DL Power Supply", NULL, "CLK_BUF"}, + {"DL Power Supply", NULL, "AUDGLB"}, + {"DL Power Supply", NULL, "CLKSQ Audio"}, + + {"DL Power Supply", NULL, "AUDNCP_CK"}, + {"DL Power Supply", NULL, "ZCD13M_CK"}, + {"DL Power Supply", NULL, "AUD_CK"}, + {"DL Power Supply", NULL, "AUDIF_CK"}, + + /* DL Digital Supply */ + {"DL Digital Clock", NULL, "AUDIO_TOP_AFE_CTL"}, + {"DL Digital Clock", NULL, "AUDIO_TOP_DAC_CTL"}, + {"DL Digital Clock", NULL, "AUDIO_TOP_PWR_CLK"}, + + {"DL Digital Clock", NULL, "AFE_ON"}, + + {"AIF_RX", NULL, "DL Digital Clock"}, + + /* DL Path */ + {"DAC In Mux", "Normal Path", "AIF_RX"}, + + {"DAC In Mux", "Sgen", "SGEN DL"}, + {"SGEN DL", NULL, "SGEN DL SRC"}, + {"SGEN DL", NULL, "SGEN MUTE"}, + {"SGEN DL", NULL, "SGEN DL Enable"}, + {"SGEN DL", NULL, "DL Digital Clock"}, + {"SGEN DL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"}, + + {"DACL", NULL, "DAC In Mux"}, + {"DACL", NULL, "DL Power Supply"}, + + {"DACR", NULL, "DAC In Mux"}, + {"DACR", NULL, "DL Power Supply"}, + + /* Lineout Path */ + {"LOL Mux", "Playback", "DACL"}, + + {"LOL Buffer", NULL, "LOL Mux"}, + {"LOL Buffer", NULL, "LO Stability Enh"}, + + {"LINEOUT L", NULL, "LOL Buffer"}, + + /* Headphone Path */ + {"HPL Mux", "Audio Playback", "DACL"}, + {"HPR Mux", "Audio Playback", "DACR"}, + {"HPL Mux", "HP Impedance", "DACL"}, + {"HPR Mux", "HP Impedance", "DACR"}, + {"HPL Mux", "LoudSPK Playback", "DACL"}, + {"HPR Mux", "LoudSPK Playback", "DACR"}, + + {"Headphone L", NULL, "HPL Mux"}, + {"Headphone R", NULL, "HPR Mux"}, + {"Headphone L Ext Spk Amp", NULL, "HPL Mux"}, + {"Headphone R Ext Spk Amp", NULL, "HPR Mux"}, + {"LINEOUT L HSSPK", NULL, "HPL Mux"}, + + /* Receiver Path */ + {"RCV Mux", "Voice Playback", "DACL"}, + {"Receiver", NULL, "RCV Mux"}, +}; + +static int mt6358_codec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *cmpnt = dai->component; + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + unsigned int rate = params_rate(params); + + dev_info(priv->dev, "%s(), substream->stream %d, rate %d, number %d\n", + __func__, + substream->stream, + rate, + substream->number); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + priv->dl_rate = rate; + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + priv->ul_rate = rate; + + return 0; +} + +static const struct snd_soc_dai_ops mt6358_codec_dai_ops = { + .hw_params = mt6358_codec_dai_hw_params, +}; + +#define MT6358_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ + SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ + SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ + SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE) + +static struct snd_soc_dai_driver mt6358_dai_driver[] = { + { + .name = "mt6358-snd-codec-aif1", + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = MT6358_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000, + .formats = MT6358_FORMATS, + }, + .ops = &mt6358_codec_dai_ops, + }, +}; + +static int mt6358_codec_init_reg(struct mt6358_priv *priv) +{ + int ret = 0; + + /* Disable HeadphoneL/HeadphoneR short circuit protection */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + RG_AUDHPLSCDISABLE_VAUDP15_MASK_SFT, + 0x1 << RG_AUDHPLSCDISABLE_VAUDP15_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON0, + RG_AUDHPRSCDISABLE_VAUDP15_MASK_SFT, + 0x1 << RG_AUDHPRSCDISABLE_VAUDP15_SFT); + /* Disable voice short circuit protection */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON6, + RG_AUDHSSCDISABLE_VAUDP15_MASK_SFT, + 0x1 << RG_AUDHSSCDISABLE_VAUDP15_SFT); + /* disable LO buffer left short circuit protection */ + regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON7, + RG_AUDLOLSCDISABLE_VAUDP15_MASK_SFT, + 0x1 << RG_AUDLOLSCDISABLE_VAUDP15_SFT); + + /* accdet s/w enable */ + regmap_update_bits(priv->regmap, MT6358_ACCDET_CON13, + 0xFFFF, 0x700E); + + /* gpio miso driving set to 4mA */ + regmap_write(priv->regmap, MT6358_DRV_CON3, 0x8888); + + /* set gpio */ + playback_gpio_reset(priv); + capture_gpio_reset(priv); + + return ret; +} + +static int mt6358_codec_probe(struct snd_soc_component *cmpnt) +{ + struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); + int ret; + + snd_soc_component_init_regmap(cmpnt, priv->regmap); + + mt6358_codec_init_reg(priv); + + priv->avdd_reg = devm_regulator_get(priv->dev, "Avdd"); + if (IS_ERR(priv->avdd_reg)) { + dev_err(priv->dev, "%s() have no Avdd supply", __func__); + return PTR_ERR(priv->avdd_reg); + } + + ret = regulator_enable(priv->avdd_reg); + if (ret) + return ret; + + return 0; +} + +static const struct snd_soc_component_driver mt6358_soc_component_driver = { + .probe = mt6358_codec_probe, + .controls = mt6358_snd_controls, + .num_controls = ARRAY_SIZE(mt6358_snd_controls), + .dapm_widgets = mt6358_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(mt6358_dapm_widgets), + .dapm_routes = mt6358_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(mt6358_dapm_routes), +}; + +static int mt6358_platform_driver_probe(struct platform_device *pdev) +{ + struct mt6358_priv *priv; + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + + priv = devm_kzalloc(&pdev->dev, + sizeof(struct mt6358_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev_set_drvdata(&pdev->dev, priv); + + priv->dev = &pdev->dev; + + priv->regmap = mt6397->regmap; + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + dev_info(priv->dev, "%s(), dev name %s\n", + __func__, dev_name(&pdev->dev)); + + return devm_snd_soc_register_component(&pdev->dev, + &mt6358_soc_component_driver, + mt6358_dai_driver, + ARRAY_SIZE(mt6358_dai_driver)); +} + +static const struct of_device_id mt6358_of_match[] = { + {.compatible = "mediatek,mt6358-sound",}, + {} +}; +MODULE_DEVICE_TABLE(of, mt6358_of_match); + +static struct platform_driver mt6358_platform_driver = { + .driver = { + .name = "mt6358-sound", + .of_match_table = mt6358_of_match, + }, + .probe = mt6358_platform_driver_probe, +}; + +module_platform_driver(mt6358_platform_driver) + +/* Module information */ +MODULE_DESCRIPTION("MT6358 ALSA SoC codec driver"); +MODULE_AUTHOR("KaiChieh Chuang "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/mt6358.h b/sound/soc/codecs/mt6358.h new file mode 100644 index 000000000000..a5953315eaa2 --- /dev/null +++ b/sound/soc/codecs/mt6358.h @@ -0,0 +1,2314 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * mt6358.h -- mt6358 ALSA SoC audio codec driver + * + * Copyright (c) 2018 MediaTek Inc. + * Author: KaiChieh Chuang + */ + +#ifndef __MT6358_H__ +#define __MT6358_H__ + +/* Reg bit define */ +/* MT6358_DCXO_CW14 */ +#define RG_XO_AUDIO_EN_M_SFT 13 + +/* MT6358_DCXO_CW13 */ +#define RG_XO_VOW_EN_SFT 8 + +/* MT6358_AUD_TOP_CKPDN_CON0 */ +#define RG_VOW13M_CK_PDN_SFT 13 +#define RG_VOW13M_CK_PDN_MASK 0x1 +#define RG_VOW13M_CK_PDN_MASK_SFT (0x1 << 13) +#define RG_VOW32K_CK_PDN_SFT 12 +#define RG_VOW32K_CK_PDN_MASK 0x1 +#define RG_VOW32K_CK_PDN_MASK_SFT (0x1 << 12) +#define RG_AUD_INTRP_CK_PDN_SFT 8 +#define RG_AUD_INTRP_CK_PDN_MASK 0x1 +#define RG_AUD_INTRP_CK_PDN_MASK_SFT (0x1 << 8) +#define RG_PAD_AUD_CLK_MISO_CK_PDN_SFT 7 +#define RG_PAD_AUD_CLK_MISO_CK_PDN_MASK 0x1 +#define RG_PAD_AUD_CLK_MISO_CK_PDN_MASK_SFT (0x1 << 7) +#define RG_AUDNCP_CK_PDN_SFT 6 +#define RG_AUDNCP_CK_PDN_MASK 0x1 +#define RG_AUDNCP_CK_PDN_MASK_SFT (0x1 << 6) +#define RG_ZCD13M_CK_PDN_SFT 5 +#define RG_ZCD13M_CK_PDN_MASK 0x1 +#define RG_ZCD13M_CK_PDN_MASK_SFT (0x1 << 5) +#define RG_AUDIF_CK_PDN_SFT 2 +#define RG_AUDIF_CK_PDN_MASK 0x1 +#define RG_AUDIF_CK_PDN_MASK_SFT (0x1 << 2) +#define RG_AUD_CK_PDN_SFT 1 +#define RG_AUD_CK_PDN_MASK 0x1 +#define RG_AUD_CK_PDN_MASK_SFT (0x1 << 1) +#define RG_ACCDET_CK_PDN_SFT 0 +#define RG_ACCDET_CK_PDN_MASK 0x1 +#define RG_ACCDET_CK_PDN_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_CKPDN_CON0_SET */ +#define RG_AUD_TOP_CKPDN_CON0_SET_SFT 0 +#define RG_AUD_TOP_CKPDN_CON0_SET_MASK 0x3fff +#define RG_AUD_TOP_CKPDN_CON0_SET_MASK_SFT (0x3fff << 0) + +/* MT6358_AUD_TOP_CKPDN_CON0_CLR */ +#define RG_AUD_TOP_CKPDN_CON0_CLR_SFT 0 +#define RG_AUD_TOP_CKPDN_CON0_CLR_MASK 0x3fff +#define RG_AUD_TOP_CKPDN_CON0_CLR_MASK_SFT (0x3fff << 0) + +/* MT6358_AUD_TOP_CKSEL_CON0 */ +#define RG_AUDIF_CK_CKSEL_SFT 3 +#define RG_AUDIF_CK_CKSEL_MASK 0x1 +#define RG_AUDIF_CK_CKSEL_MASK_SFT (0x1 << 3) +#define RG_AUD_CK_CKSEL_SFT 2 +#define RG_AUD_CK_CKSEL_MASK 0x1 +#define RG_AUD_CK_CKSEL_MASK_SFT (0x1 << 2) + +/* MT6358_AUD_TOP_CKSEL_CON0_SET */ +#define RG_AUD_TOP_CKSEL_CON0_SET_SFT 0 +#define RG_AUD_TOP_CKSEL_CON0_SET_MASK 0xf +#define RG_AUD_TOP_CKSEL_CON0_SET_MASK_SFT (0xf << 0) + +/* MT6358_AUD_TOP_CKSEL_CON0_CLR */ +#define RG_AUD_TOP_CKSEL_CON0_CLR_SFT 0 +#define RG_AUD_TOP_CKSEL_CON0_CLR_MASK 0xf +#define RG_AUD_TOP_CKSEL_CON0_CLR_MASK_SFT (0xf << 0) + +/* MT6358_AUD_TOP_CKTST_CON0 */ +#define RG_VOW13M_CK_TSTSEL_SFT 9 +#define RG_VOW13M_CK_TSTSEL_MASK 0x1 +#define RG_VOW13M_CK_TSTSEL_MASK_SFT (0x1 << 9) +#define RG_VOW13M_CK_TST_DIS_SFT 8 +#define RG_VOW13M_CK_TST_DIS_MASK 0x1 +#define RG_VOW13M_CK_TST_DIS_MASK_SFT (0x1 << 8) +#define RG_AUD26M_CK_TSTSEL_SFT 4 +#define RG_AUD26M_CK_TSTSEL_MASK 0x1 +#define RG_AUD26M_CK_TSTSEL_MASK_SFT (0x1 << 4) +#define RG_AUDIF_CK_TSTSEL_SFT 3 +#define RG_AUDIF_CK_TSTSEL_MASK 0x1 +#define RG_AUDIF_CK_TSTSEL_MASK_SFT (0x1 << 3) +#define RG_AUD_CK_TSTSEL_SFT 2 +#define RG_AUD_CK_TSTSEL_MASK 0x1 +#define RG_AUD_CK_TSTSEL_MASK_SFT (0x1 << 2) +#define RG_AUD26M_CK_TST_DIS_SFT 0 +#define RG_AUD26M_CK_TST_DIS_MASK 0x1 +#define RG_AUD26M_CK_TST_DIS_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_CLK_HWEN_CON0 */ +#define RG_AUD_INTRP_CK_PDN_HWEN_SFT 0 +#define RG_AUD_INTRP_CK_PDN_HWEN_MASK 0x1 +#define RG_AUD_INTRP_CK_PDN_HWEN_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_CLK_HWEN_CON0_SET */ +#define RG_AUD_INTRP_CK_PND_HWEN_CON0_SET_SFT 0 +#define RG_AUD_INTRP_CK_PND_HWEN_CON0_SET_MASK 0xffff +#define RG_AUD_INTRP_CK_PND_HWEN_CON0_SET_MASK_SFT (0xffff << 0) + +/* MT6358_AUD_TOP_CLK_HWEN_CON0_CLR */ +#define RG_AUD_INTRP_CLK_PDN_HWEN_CON0_CLR_SFT 0 +#define RG_AUD_INTRP_CLK_PDN_HWEN_CON0_CLR_MASK 0xffff +#define RG_AUD_INTRP_CLK_PDN_HWEN_CON0_CLR_MASK_SFT (0xffff << 0) + +/* MT6358_AUD_TOP_RST_CON0 */ +#define RG_AUDNCP_RST_SFT 3 +#define RG_AUDNCP_RST_MASK 0x1 +#define RG_AUDNCP_RST_MASK_SFT (0x1 << 3) +#define RG_ZCD_RST_SFT 2 +#define RG_ZCD_RST_MASK 0x1 +#define RG_ZCD_RST_MASK_SFT (0x1 << 2) +#define RG_ACCDET_RST_SFT 1 +#define RG_ACCDET_RST_MASK 0x1 +#define RG_ACCDET_RST_MASK_SFT (0x1 << 1) +#define RG_AUDIO_RST_SFT 0 +#define RG_AUDIO_RST_MASK 0x1 +#define RG_AUDIO_RST_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_RST_CON0_SET */ +#define RG_AUD_TOP_RST_CON0_SET_SFT 0 +#define RG_AUD_TOP_RST_CON0_SET_MASK 0xf +#define RG_AUD_TOP_RST_CON0_SET_MASK_SFT (0xf << 0) + +/* MT6358_AUD_TOP_RST_CON0_CLR */ +#define RG_AUD_TOP_RST_CON0_CLR_SFT 0 +#define RG_AUD_TOP_RST_CON0_CLR_MASK 0xf +#define RG_AUD_TOP_RST_CON0_CLR_MASK_SFT (0xf << 0) + +/* MT6358_AUD_TOP_RST_BANK_CON0 */ +#define BANK_AUDZCD_SWRST_SFT 2 +#define BANK_AUDZCD_SWRST_MASK 0x1 +#define BANK_AUDZCD_SWRST_MASK_SFT (0x1 << 2) +#define BANK_AUDIO_SWRST_SFT 1 +#define BANK_AUDIO_SWRST_MASK 0x1 +#define BANK_AUDIO_SWRST_MASK_SFT (0x1 << 1) +#define BANK_ACCDET_SWRST_SFT 0 +#define BANK_ACCDET_SWRST_MASK 0x1 +#define BANK_ACCDET_SWRST_MASK_SFT (0x1 << 0) + +/* MT6358_AUD_TOP_INT_CON0 */ +#define RG_INT_EN_AUDIO_SFT 0 +#define RG_INT_EN_AUDIO_MASK 0x1 +#define RG_INT_EN_AUDIO_MASK_SFT (0x1 << 0) +#define RG_INT_EN_ACCDET_SFT 5 +#define RG_INT_EN_ACCDET_MASK 0x1 +#define RG_INT_EN_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_EN_ACCDET_EINT0_SFT 6 +#define RG_INT_EN_ACCDET_EINT0_MASK 0x1 +#define RG_INT_EN_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_EN_ACCDET_EINT1_SFT 7 +#define RG_INT_EN_ACCDET_EINT1_MASK 0x1 +#define RG_INT_EN_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +/* MT6358_AUD_TOP_INT_CON0_SET */ +#define RG_AUD_INT_CON0_SET_SFT 0 +#define RG_AUD_INT_CON0_SET_MASK 0xffff +#define RG_AUD_INT_CON0_SET_MASK_SFT (0xffff << 0) + +/* MT6358_AUD_TOP_INT_CON0_CLR */ +#define RG_AUD_INT_CON0_CLR_SFT 0 +#define RG_AUD_INT_CON0_CLR_MASK 0xffff +#define RG_AUD_INT_CON0_CLR_MASK_SFT (0xffff << 0) + +/* MT6358_AUD_TOP_INT_MASK_CON0 */ +#define RG_INT_MASK_AUDIO_SFT 0 +#define RG_INT_MASK_AUDIO_MASK 0x1 +#define RG_INT_MASK_AUDIO_MASK_SFT (0x1 << 0) +#define RG_INT_MASK_ACCDET_SFT 5 +#define RG_INT_MASK_ACCDET_MASK 0x1 +#define RG_INT_MASK_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_MASK_ACCDET_EINT0_SFT 6 +#define RG_INT_MASK_ACCDET_EINT0_MASK 0x1 +#define RG_INT_MASK_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_MASK_ACCDET_EINT1_SFT 7 +#define RG_INT_MASK_ACCDET_EINT1_MASK 0x1 +#define RG_INT_MASK_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +/* MT6358_AUD_TOP_INT_MASK_CON0_SET */ +#define RG_AUD_INT_MASK_CON0_SET_SFT 0 +#define RG_AUD_INT_MASK_CON0_SET_MASK 0xff +#define RG_AUD_INT_MASK_CON0_SET_MASK_SFT (0xff << 0) + +/* MT6358_AUD_TOP_INT_MASK_CON0_CLR */ +#define RG_AUD_INT_MASK_CON0_CLR_SFT 0 +#define RG_AUD_INT_MASK_CON0_CLR_MASK 0xff +#define RG_AUD_INT_MASK_CON0_CLR_MASK_SFT (0xff << 0) + +/* MT6358_AUD_TOP_INT_STATUS0 */ +#define RG_INT_STATUS_AUDIO_SFT 0 +#define RG_INT_STATUS_AUDIO_MASK 0x1 +#define RG_INT_STATUS_AUDIO_MASK_SFT (0x1 << 0) +#define RG_INT_STATUS_ACCDET_SFT 5 +#define RG_INT_STATUS_ACCDET_MASK 0x1 +#define RG_INT_STATUS_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_STATUS_ACCDET_EINT0_SFT 6 +#define RG_INT_STATUS_ACCDET_EINT0_MASK 0x1 +#define RG_INT_STATUS_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_STATUS_ACCDET_EINT1_SFT 7 +#define RG_INT_STATUS_ACCDET_EINT1_MASK 0x1 +#define RG_INT_STATUS_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +/* MT6358_AUD_TOP_INT_RAW_STATUS0 */ +#define RG_INT_RAW_STATUS_AUDIO_SFT 0 +#define RG_INT_RAW_STATUS_AUDIO_MASK 0x1 +#define RG_INT_RAW_STATUS_AUDIO_MASK_SFT (0x1 << 0) +#define RG_INT_RAW_STATUS_ACCDET_SFT 5 +#define RG_INT_RAW_STATUS_ACCDET_MASK 0x1 +#define RG_INT_RAW_STATUS_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_RAW_STATUS_ACCDET_EINT0_SFT 6 +#define RG_INT_RAW_STATUS_ACCDET_EINT0_MASK 0x1 +#define RG_INT_RAW_STATUS_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_RAW_STATUS_ACCDET_EINT1_SFT 7 +#define RG_INT_RAW_STATUS_ACCDET_EINT1_MASK 0x1 +#define RG_INT_RAW_STATUS_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +/* MT6358_AUD_TOP_INT_MISC_CON0 */ +#define RG_AUD_TOP_INT_POLARITY_SFT 0 +#define RG_AUD_TOP_INT_POLARITY_MASK 0x1 +#define RG_AUD_TOP_INT_POLARITY_MASK_SFT (0x1 << 0) + +/* MT6358_AUDNCP_CLKDIV_CON0 */ +#define RG_DIVCKS_CHG_SFT 0 +#define RG_DIVCKS_CHG_MASK 0x1 +#define RG_DIVCKS_CHG_MASK_SFT (0x1 << 0) + +/* MT6358_AUDNCP_CLKDIV_CON1 */ +#define RG_DIVCKS_ON_SFT 0 +#define RG_DIVCKS_ON_MASK 0x1 +#define RG_DIVCKS_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AUDNCP_CLKDIV_CON2 */ +#define RG_DIVCKS_PRG_SFT 0 +#define RG_DIVCKS_PRG_MASK 0x1ff +#define RG_DIVCKS_PRG_MASK_SFT (0x1ff << 0) + +/* MT6358_AUDNCP_CLKDIV_CON3 */ +#define RG_DIVCKS_PWD_NCP_SFT 0 +#define RG_DIVCKS_PWD_NCP_MASK 0x1 +#define RG_DIVCKS_PWD_NCP_MASK_SFT (0x1 << 0) + +/* MT6358_AUDNCP_CLKDIV_CON4 */ +#define RG_DIVCKS_PWD_NCP_ST_SEL_SFT 0 +#define RG_DIVCKS_PWD_NCP_ST_SEL_MASK 0x3 +#define RG_DIVCKS_PWD_NCP_ST_SEL_MASK_SFT (0x3 << 0) + +/* MT6358_AUD_TOP_MON_CON0 */ +#define RG_AUD_TOP_MON_SEL_SFT 0 +#define RG_AUD_TOP_MON_SEL_MASK 0x7 +#define RG_AUD_TOP_MON_SEL_MASK_SFT (0x7 << 0) +#define RG_AUD_CLK_INT_MON_FLAG_SEL_SFT 3 +#define RG_AUD_CLK_INT_MON_FLAG_SEL_MASK 0xff +#define RG_AUD_CLK_INT_MON_FLAG_SEL_MASK_SFT (0xff << 3) +#define RG_AUD_CLK_INT_MON_FLAG_EN_SFT 11 +#define RG_AUD_CLK_INT_MON_FLAG_EN_MASK 0x1 +#define RG_AUD_CLK_INT_MON_FLAG_EN_MASK_SFT (0x1 << 11) + +/* MT6358_AUDIO_DIG_DSN_ID */ +#define AUDIO_DIG_ANA_ID_SFT 0 +#define AUDIO_DIG_ANA_ID_MASK 0xff +#define AUDIO_DIG_ANA_ID_MASK_SFT (0xff << 0) +#define AUDIO_DIG_DIG_ID_SFT 8 +#define AUDIO_DIG_DIG_ID_MASK 0xff +#define AUDIO_DIG_DIG_ID_MASK_SFT (0xff << 8) + +/* MT6358_AUDIO_DIG_DSN_REV0 */ +#define AUDIO_DIG_ANA_MINOR_REV_SFT 0 +#define AUDIO_DIG_ANA_MINOR_REV_MASK 0xf +#define AUDIO_DIG_ANA_MINOR_REV_MASK_SFT (0xf << 0) +#define AUDIO_DIG_ANA_MAJOR_REV_SFT 4 +#define AUDIO_DIG_ANA_MAJOR_REV_MASK 0xf +#define AUDIO_DIG_ANA_MAJOR_REV_MASK_SFT (0xf << 4) +#define AUDIO_DIG_DIG_MINOR_REV_SFT 8 +#define AUDIO_DIG_DIG_MINOR_REV_MASK 0xf +#define AUDIO_DIG_DIG_MINOR_REV_MASK_SFT (0xf << 8) +#define AUDIO_DIG_DIG_MAJOR_REV_SFT 12 +#define AUDIO_DIG_DIG_MAJOR_REV_MASK 0xf +#define AUDIO_DIG_DIG_MAJOR_REV_MASK_SFT (0xf << 12) + +/* MT6358_AUDIO_DIG_DSN_DBI */ +#define AUDIO_DIG_DSN_CBS_SFT 0 +#define AUDIO_DIG_DSN_CBS_MASK 0x3 +#define AUDIO_DIG_DSN_CBS_MASK_SFT (0x3 << 0) +#define AUDIO_DIG_DSN_BIX_SFT 2 +#define AUDIO_DIG_DSN_BIX_MASK 0x3 +#define AUDIO_DIG_DSN_BIX_MASK_SFT (0x3 << 2) +#define AUDIO_DIG_ESP_SFT 8 +#define AUDIO_DIG_ESP_MASK 0xff +#define AUDIO_DIG_ESP_MASK_SFT (0xff << 8) + +/* MT6358_AUDIO_DIG_DSN_DXI */ +#define AUDIO_DIG_DSN_FPI_SFT 0 +#define AUDIO_DIG_DSN_FPI_MASK 0xff +#define AUDIO_DIG_DSN_FPI_MASK_SFT (0xff << 0) + +/* MT6358_AFE_UL_DL_CON0 */ +#define AFE_UL_LR_SWAP_SFT 15 +#define AFE_UL_LR_SWAP_MASK 0x1 +#define AFE_UL_LR_SWAP_MASK_SFT (0x1 << 15) +#define AFE_DL_LR_SWAP_SFT 14 +#define AFE_DL_LR_SWAP_MASK 0x1 +#define AFE_DL_LR_SWAP_MASK_SFT (0x1 << 14) +#define AFE_ON_SFT 0 +#define AFE_ON_MASK 0x1 +#define AFE_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_DL_SRC2_CON0_L */ +#define DL_2_SRC_ON_TMP_CTL_PRE_SFT 0 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK 0x1 +#define DL_2_SRC_ON_TMP_CTL_PRE_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_UL_SRC_CON0_H */ +#define C_DIGMIC_PHASE_SEL_CH1_CTL_SFT 11 +#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK 0x7 +#define C_DIGMIC_PHASE_SEL_CH1_CTL_MASK_SFT (0x7 << 11) +#define C_DIGMIC_PHASE_SEL_CH2_CTL_SFT 8 +#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK 0x7 +#define C_DIGMIC_PHASE_SEL_CH2_CTL_MASK_SFT (0x7 << 8) +#define C_TWO_DIGITAL_MIC_CTL_SFT 7 +#define C_TWO_DIGITAL_MIC_CTL_MASK 0x1 +#define C_TWO_DIGITAL_MIC_CTL_MASK_SFT (0x1 << 7) + +/* MT6358_AFE_UL_SRC_CON0_L */ +#define DMIC_LOW_POWER_MODE_CTL_SFT 14 +#define DMIC_LOW_POWER_MODE_CTL_MASK 0x3 +#define DMIC_LOW_POWER_MODE_CTL_MASK_SFT (0x3 << 14) +#define DIGMIC_3P25M_1P625M_SEL_CTL_SFT 5 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK 0x1 +#define DIGMIC_3P25M_1P625M_SEL_CTL_MASK_SFT (0x1 << 5) +#define UL_LOOP_BACK_MODE_CTL_SFT 2 +#define UL_LOOP_BACK_MODE_CTL_MASK 0x1 +#define UL_LOOP_BACK_MODE_CTL_MASK_SFT (0x1 << 2) +#define UL_SDM_3_LEVEL_CTL_SFT 1 +#define UL_SDM_3_LEVEL_CTL_MASK 0x1 +#define UL_SDM_3_LEVEL_CTL_MASK_SFT (0x1 << 1) +#define UL_SRC_ON_TMP_CTL_SFT 0 +#define UL_SRC_ON_TMP_CTL_MASK 0x1 +#define UL_SRC_ON_TMP_CTL_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_TOP_CON0 */ +#define MTKAIF_SINE_ON_SFT 2 +#define MTKAIF_SINE_ON_MASK 0x1 +#define MTKAIF_SINE_ON_MASK_SFT (0x1 << 2) +#define UL_SINE_ON_SFT 1 +#define UL_SINE_ON_MASK 0x1 +#define UL_SINE_ON_MASK_SFT (0x1 << 1) +#define DL_SINE_ON_SFT 0 +#define DL_SINE_ON_MASK 0x1 +#define DL_SINE_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AUDIO_TOP_CON0 */ +#define PDN_AFE_CTL_SFT 7 +#define PDN_AFE_CTL_MASK 0x1 +#define PDN_AFE_CTL_MASK_SFT (0x1 << 7) +#define PDN_DAC_CTL_SFT 6 +#define PDN_DAC_CTL_MASK 0x1 +#define PDN_DAC_CTL_MASK_SFT (0x1 << 6) +#define PDN_ADC_CTL_SFT 5 +#define PDN_ADC_CTL_MASK 0x1 +#define PDN_ADC_CTL_MASK_SFT (0x1 << 5) +#define PDN_I2S_DL_CTL_SFT 3 +#define PDN_I2S_DL_CTL_MASK 0x1 +#define PDN_I2S_DL_CTL_MASK_SFT (0x1 << 3) +#define PWR_CLK_DIS_CTL_SFT 2 +#define PWR_CLK_DIS_CTL_MASK 0x1 +#define PWR_CLK_DIS_CTL_MASK_SFT (0x1 << 2) +#define PDN_AFE_TESTMODEL_CTL_SFT 1 +#define PDN_AFE_TESTMODEL_CTL_MASK 0x1 +#define PDN_AFE_TESTMODEL_CTL_MASK_SFT (0x1 << 1) +#define PDN_RESERVED_SFT 0 +#define PDN_RESERVED_MASK 0x1 +#define PDN_RESERVED_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_MON_DEBUG0 */ +#define AUDIO_SYS_TOP_MON_SWAP_SFT 14 +#define AUDIO_SYS_TOP_MON_SWAP_MASK 0x3 +#define AUDIO_SYS_TOP_MON_SWAP_MASK_SFT (0x3 << 14) +#define AUDIO_SYS_TOP_MON_SEL_SFT 8 +#define AUDIO_SYS_TOP_MON_SEL_MASK 0x1f +#define AUDIO_SYS_TOP_MON_SEL_MASK_SFT (0x1f << 8) +#define AFE_MON_SEL_SFT 0 +#define AFE_MON_SEL_MASK 0xff +#define AFE_MON_SEL_MASK_SFT (0xff << 0) + +/* MT6358_AFUNC_AUD_CON0 */ +#define CCI_AUD_ANACK_SEL_SFT 15 +#define CCI_AUD_ANACK_SEL_MASK 0x1 +#define CCI_AUD_ANACK_SEL_MASK_SFT (0x1 << 15) +#define CCI_AUDIO_FIFO_WPTR_SFT 12 +#define CCI_AUDIO_FIFO_WPTR_MASK 0x7 +#define CCI_AUDIO_FIFO_WPTR_MASK_SFT (0x7 << 12) +#define CCI_SCRAMBLER_CG_EN_SFT 11 +#define CCI_SCRAMBLER_CG_EN_MASK 0x1 +#define CCI_SCRAMBLER_CG_EN_MASK_SFT (0x1 << 11) +#define CCI_LCH_INV_SFT 10 +#define CCI_LCH_INV_MASK 0x1 +#define CCI_LCH_INV_MASK_SFT (0x1 << 10) +#define CCI_RAND_EN_SFT 9 +#define CCI_RAND_EN_MASK 0x1 +#define CCI_RAND_EN_MASK_SFT (0x1 << 9) +#define CCI_SPLT_SCRMB_CLK_ON_SFT 8 +#define CCI_SPLT_SCRMB_CLK_ON_MASK 0x1 +#define CCI_SPLT_SCRMB_CLK_ON_MASK_SFT (0x1 << 8) +#define CCI_SPLT_SCRMB_ON_SFT 7 +#define CCI_SPLT_SCRMB_ON_MASK 0x1 +#define CCI_SPLT_SCRMB_ON_MASK_SFT (0x1 << 7) +#define CCI_AUD_IDAC_TEST_EN_SFT 6 +#define CCI_AUD_IDAC_TEST_EN_MASK 0x1 +#define CCI_AUD_IDAC_TEST_EN_MASK_SFT (0x1 << 6) +#define CCI_ZERO_PAD_DISABLE_SFT 5 +#define CCI_ZERO_PAD_DISABLE_MASK 0x1 +#define CCI_ZERO_PAD_DISABLE_MASK_SFT (0x1 << 5) +#define CCI_AUD_SPLIT_TEST_EN_SFT 4 +#define CCI_AUD_SPLIT_TEST_EN_MASK 0x1 +#define CCI_AUD_SPLIT_TEST_EN_MASK_SFT (0x1 << 4) +#define CCI_AUD_SDM_MUTEL_SFT 3 +#define CCI_AUD_SDM_MUTEL_MASK 0x1 +#define CCI_AUD_SDM_MUTEL_MASK_SFT (0x1 << 3) +#define CCI_AUD_SDM_MUTER_SFT 2 +#define CCI_AUD_SDM_MUTER_MASK 0x1 +#define CCI_AUD_SDM_MUTER_MASK_SFT (0x1 << 2) +#define CCI_AUD_SDM_7BIT_SEL_SFT 1 +#define CCI_AUD_SDM_7BIT_SEL_MASK 0x1 +#define CCI_AUD_SDM_7BIT_SEL_MASK_SFT (0x1 << 1) +#define CCI_SCRAMBLER_EN_SFT 0 +#define CCI_SCRAMBLER_EN_MASK 0x1 +#define CCI_SCRAMBLER_EN_MASK_SFT (0x1 << 0) + +/* MT6358_AFUNC_AUD_CON1 */ +#define AUD_SDM_TEST_L_SFT 8 +#define AUD_SDM_TEST_L_MASK 0xff +#define AUD_SDM_TEST_L_MASK_SFT (0xff << 8) +#define AUD_SDM_TEST_R_SFT 0 +#define AUD_SDM_TEST_R_MASK 0xff +#define AUD_SDM_TEST_R_MASK_SFT (0xff << 0) + +/* MT6358_AFUNC_AUD_CON2 */ +#define CCI_AUD_DAC_ANA_MUTE_SFT 7 +#define CCI_AUD_DAC_ANA_MUTE_MASK 0x1 +#define CCI_AUD_DAC_ANA_MUTE_MASK_SFT (0x1 << 7) +#define CCI_AUD_DAC_ANA_RSTB_SEL_SFT 6 +#define CCI_AUD_DAC_ANA_RSTB_SEL_MASK 0x1 +#define CCI_AUD_DAC_ANA_RSTB_SEL_MASK_SFT (0x1 << 6) +#define CCI_AUDIO_FIFO_CLKIN_INV_SFT 4 +#define CCI_AUDIO_FIFO_CLKIN_INV_MASK 0x1 +#define CCI_AUDIO_FIFO_CLKIN_INV_MASK_SFT (0x1 << 4) +#define CCI_AUDIO_FIFO_ENABLE_SFT 3 +#define CCI_AUDIO_FIFO_ENABLE_MASK 0x1 +#define CCI_AUDIO_FIFO_ENABLE_MASK_SFT (0x1 << 3) +#define CCI_ACD_MODE_SFT 2 +#define CCI_ACD_MODE_MASK 0x1 +#define CCI_ACD_MODE_MASK_SFT (0x1 << 2) +#define CCI_AFIFO_CLK_PWDB_SFT 1 +#define CCI_AFIFO_CLK_PWDB_MASK 0x1 +#define CCI_AFIFO_CLK_PWDB_MASK_SFT (0x1 << 1) +#define CCI_ACD_FUNC_RSTB_SFT 0 +#define CCI_ACD_FUNC_RSTB_MASK 0x1 +#define CCI_ACD_FUNC_RSTB_MASK_SFT (0x1 << 0) + +/* MT6358_AFUNC_AUD_CON3 */ +#define SDM_ANA13M_TESTCK_SEL_SFT 15 +#define SDM_ANA13M_TESTCK_SEL_MASK 0x1 +#define SDM_ANA13M_TESTCK_SEL_MASK_SFT (0x1 << 15) +#define SDM_ANA13M_TESTCK_SRC_SEL_SFT 12 +#define SDM_ANA13M_TESTCK_SRC_SEL_MASK 0x7 +#define SDM_ANA13M_TESTCK_SRC_SEL_MASK_SFT (0x7 << 12) +#define SDM_TESTCK_SRC_SEL_SFT 8 +#define SDM_TESTCK_SRC_SEL_MASK 0x7 +#define SDM_TESTCK_SRC_SEL_MASK_SFT (0x7 << 8) +#define DIGMIC_TESTCK_SRC_SEL_SFT 4 +#define DIGMIC_TESTCK_SRC_SEL_MASK 0x7 +#define DIGMIC_TESTCK_SRC_SEL_MASK_SFT (0x7 << 4) +#define DIGMIC_TESTCK_SEL_SFT 0 +#define DIGMIC_TESTCK_SEL_MASK 0x1 +#define DIGMIC_TESTCK_SEL_MASK_SFT (0x1 << 0) + +/* MT6358_AFUNC_AUD_CON4 */ +#define UL_FIFO_WCLK_INV_SFT 8 +#define UL_FIFO_WCLK_INV_MASK 0x1 +#define UL_FIFO_WCLK_INV_MASK_SFT (0x1 << 8) +#define UL_FIFO_DIGMIC_WDATA_TESTSRC_SEL_SFT 6 +#define UL_FIFO_DIGMIC_WDATA_TESTSRC_SEL_MASK 0x1 +#define UL_FIFO_DIGMIC_WDATA_TESTSRC_SEL_MASK_SFT (0x1 << 6) +#define UL_FIFO_WDATA_TESTEN_SFT 5 +#define UL_FIFO_WDATA_TESTEN_MASK 0x1 +#define UL_FIFO_WDATA_TESTEN_MASK_SFT (0x1 << 5) +#define UL_FIFO_WDATA_TESTSRC_SEL_SFT 4 +#define UL_FIFO_WDATA_TESTSRC_SEL_MASK 0x1 +#define UL_FIFO_WDATA_TESTSRC_SEL_MASK_SFT (0x1 << 4) +#define UL_FIFO_WCLK_6P5M_TESTCK_SEL_SFT 3 +#define UL_FIFO_WCLK_6P5M_TESTCK_SEL_MASK 0x1 +#define UL_FIFO_WCLK_6P5M_TESTCK_SEL_MASK_SFT (0x1 << 3) +#define UL_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_SFT 0 +#define UL_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_MASK 0x7 +#define UL_FIFO_WCLK_6P5M_TESTCK_SRC_SEL_MASK_SFT (0x7 << 0) + +/* MT6358_AFUNC_AUD_CON5 */ +#define R_AUD_DAC_POS_LARGE_MONO_SFT 8 +#define R_AUD_DAC_POS_LARGE_MONO_MASK 0xff +#define R_AUD_DAC_POS_LARGE_MONO_MASK_SFT (0xff << 8) +#define R_AUD_DAC_NEG_LARGE_MONO_SFT 0 +#define R_AUD_DAC_NEG_LARGE_MONO_MASK 0xff +#define R_AUD_DAC_NEG_LARGE_MONO_MASK_SFT (0xff << 0) + +/* MT6358_AFUNC_AUD_CON6 */ +#define R_AUD_DAC_POS_SMALL_MONO_SFT 12 +#define R_AUD_DAC_POS_SMALL_MONO_MASK 0xf +#define R_AUD_DAC_POS_SMALL_MONO_MASK_SFT (0xf << 12) +#define R_AUD_DAC_NEG_SMALL_MONO_SFT 8 +#define R_AUD_DAC_NEG_SMALL_MONO_MASK 0xf +#define R_AUD_DAC_NEG_SMALL_MONO_MASK_SFT (0xf << 8) +#define R_AUD_DAC_POS_TINY_MONO_SFT 6 +#define R_AUD_DAC_POS_TINY_MONO_MASK 0x3 +#define R_AUD_DAC_POS_TINY_MONO_MASK_SFT (0x3 << 6) +#define R_AUD_DAC_NEG_TINY_MONO_SFT 4 +#define R_AUD_DAC_NEG_TINY_MONO_MASK 0x3 +#define R_AUD_DAC_NEG_TINY_MONO_MASK_SFT (0x3 << 4) +#define R_AUD_DAC_MONO_SEL_SFT 3 +#define R_AUD_DAC_MONO_SEL_MASK 0x1 +#define R_AUD_DAC_MONO_SEL_MASK_SFT (0x1 << 3) +#define R_AUD_DAC_SW_RSTB_SFT 0 +#define R_AUD_DAC_SW_RSTB_MASK 0x1 +#define R_AUD_DAC_SW_RSTB_MASK_SFT (0x1 << 0) + +/* MT6358_AFUNC_AUD_MON0 */ +#define AUD_SCR_OUT_L_SFT 8 +#define AUD_SCR_OUT_L_MASK 0xff +#define AUD_SCR_OUT_L_MASK_SFT (0xff << 8) +#define AUD_SCR_OUT_R_SFT 0 +#define AUD_SCR_OUT_R_MASK 0xff +#define AUD_SCR_OUT_R_MASK_SFT (0xff << 0) + +/* MT6358_AUDRC_TUNE_MON0 */ +#define ASYNC_TEST_OUT_BCK_SFT 15 +#define ASYNC_TEST_OUT_BCK_MASK 0x1 +#define ASYNC_TEST_OUT_BCK_MASK_SFT (0x1 << 15) +#define RGS_AUDRCTUNE1READ_SFT 8 +#define RGS_AUDRCTUNE1READ_MASK 0x1f +#define RGS_AUDRCTUNE1READ_MASK_SFT (0x1f << 8) +#define RGS_AUDRCTUNE0READ_SFT 0 +#define RGS_AUDRCTUNE0READ_MASK 0x1f +#define RGS_AUDRCTUNE0READ_MASK_SFT (0x1f << 0) + +/* MT6358_AFE_ADDA_MTKAIF_FIFO_CFG0 */ +#define AFE_RESERVED_SFT 1 +#define AFE_RESERVED_MASK 0x7fff +#define AFE_RESERVED_MASK_SFT (0x7fff << 1) +#define RG_MTKAIF_RXIF_FIFO_INTEN_SFT 0 +#define RG_MTKAIF_RXIF_FIFO_INTEN_MASK 0x1 +#define RG_MTKAIF_RXIF_FIFO_INTEN_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_ADDA_MTKAIF_FIFO_LOG_MON1 */ +#define MTKAIF_RXIF_WR_FULL_STATUS_SFT 1 +#define MTKAIF_RXIF_WR_FULL_STATUS_MASK 0x1 +#define MTKAIF_RXIF_WR_FULL_STATUS_MASK_SFT (0x1 << 1) +#define MTKAIF_RXIF_RD_EMPTY_STATUS_SFT 0 +#define MTKAIF_RXIF_RD_EMPTY_STATUS_MASK 0x1 +#define MTKAIF_RXIF_RD_EMPTY_STATUS_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_ADDA_MTKAIF_MON0 */ +#define MTKAIFTX_V3_SYNC_OUT_SFT 14 +#define MTKAIFTX_V3_SYNC_OUT_MASK 0x1 +#define MTKAIFTX_V3_SYNC_OUT_MASK_SFT (0x1 << 14) +#define MTKAIFTX_V3_SDATA_OUT2_SFT 13 +#define MTKAIFTX_V3_SDATA_OUT2_MASK 0x1 +#define MTKAIFTX_V3_SDATA_OUT2_MASK_SFT (0x1 << 13) +#define MTKAIFTX_V3_SDATA_OUT1_SFT 12 +#define MTKAIFTX_V3_SDATA_OUT1_MASK 0x1 +#define MTKAIFTX_V3_SDATA_OUT1_MASK_SFT (0x1 << 12) +#define MTKAIF_RXIF_FIFO_STATUS_SFT 0 +#define MTKAIF_RXIF_FIFO_STATUS_MASK 0xfff +#define MTKAIF_RXIF_FIFO_STATUS_MASK_SFT (0xfff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_MON1 */ +#define MTKAIFRX_V3_SYNC_IN_SFT 14 +#define MTKAIFRX_V3_SYNC_IN_MASK 0x1 +#define MTKAIFRX_V3_SYNC_IN_MASK_SFT (0x1 << 14) +#define MTKAIFRX_V3_SDATA_IN2_SFT 13 +#define MTKAIFRX_V3_SDATA_IN2_MASK 0x1 +#define MTKAIFRX_V3_SDATA_IN2_MASK_SFT (0x1 << 13) +#define MTKAIFRX_V3_SDATA_IN1_SFT 12 +#define MTKAIFRX_V3_SDATA_IN1_MASK 0x1 +#define MTKAIFRX_V3_SDATA_IN1_MASK_SFT (0x1 << 12) +#define MTKAIF_RXIF_SEARCH_FAIL_FLAG_SFT 11 +#define MTKAIF_RXIF_SEARCH_FAIL_FLAG_MASK 0x1 +#define MTKAIF_RXIF_SEARCH_FAIL_FLAG_MASK_SFT (0x1 << 11) +#define MTKAIF_RXIF_INVALID_FLAG_SFT 8 +#define MTKAIF_RXIF_INVALID_FLAG_MASK 0x1 +#define MTKAIF_RXIF_INVALID_FLAG_MASK_SFT (0x1 << 8) +#define MTKAIF_RXIF_INVALID_CYCLE_SFT 0 +#define MTKAIF_RXIF_INVALID_CYCLE_MASK 0xff +#define MTKAIF_RXIF_INVALID_CYCLE_MASK_SFT (0xff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_MON2 */ +#define MTKAIF_TXIF_IN_CH2_SFT 8 +#define MTKAIF_TXIF_IN_CH2_MASK 0xff +#define MTKAIF_TXIF_IN_CH2_MASK_SFT (0xff << 8) +#define MTKAIF_TXIF_IN_CH1_SFT 0 +#define MTKAIF_TXIF_IN_CH1_MASK 0xff +#define MTKAIF_TXIF_IN_CH1_MASK_SFT (0xff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_MON3 */ +#define MTKAIF_RXIF_OUT_CH2_SFT 8 +#define MTKAIF_RXIF_OUT_CH2_MASK 0xff +#define MTKAIF_RXIF_OUT_CH2_MASK_SFT (0xff << 8) +#define MTKAIF_RXIF_OUT_CH1_SFT 0 +#define MTKAIF_RXIF_OUT_CH1_MASK 0xff +#define MTKAIF_RXIF_OUT_CH1_MASK_SFT (0xff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_CFG0 */ +#define RG_MTKAIF_RXIF_CLKINV_SFT 15 +#define RG_MTKAIF_RXIF_CLKINV_MASK 0x1 +#define RG_MTKAIF_RXIF_CLKINV_MASK_SFT (0x1 << 15) +#define RG_MTKAIF_RXIF_PROTOCOL2_SFT 8 +#define RG_MTKAIF_RXIF_PROTOCOL2_MASK 0x1 +#define RG_MTKAIF_RXIF_PROTOCOL2_MASK_SFT (0x1 << 8) +#define RG_MTKAIF_BYPASS_SRC_MODE_SFT 6 +#define RG_MTKAIF_BYPASS_SRC_MODE_MASK 0x3 +#define RG_MTKAIF_BYPASS_SRC_MODE_MASK_SFT (0x3 << 6) +#define RG_MTKAIF_BYPASS_SRC_TEST_SFT 5 +#define RG_MTKAIF_BYPASS_SRC_TEST_MASK 0x1 +#define RG_MTKAIF_BYPASS_SRC_TEST_MASK_SFT (0x1 << 5) +#define RG_MTKAIF_TXIF_PROTOCOL2_SFT 4 +#define RG_MTKAIF_TXIF_PROTOCOL2_MASK 0x1 +#define RG_MTKAIF_TXIF_PROTOCOL2_MASK_SFT (0x1 << 4) +#define RG_MTKAIF_PMIC_TXIF_8TO5_SFT 2 +#define RG_MTKAIF_PMIC_TXIF_8TO5_MASK 0x1 +#define RG_MTKAIF_PMIC_TXIF_8TO5_MASK_SFT (0x1 << 2) +#define RG_MTKAIF_LOOPBACK_TEST2_SFT 1 +#define RG_MTKAIF_LOOPBACK_TEST2_MASK 0x1 +#define RG_MTKAIF_LOOPBACK_TEST2_MASK_SFT (0x1 << 1) +#define RG_MTKAIF_LOOPBACK_TEST1_SFT 0 +#define RG_MTKAIF_LOOPBACK_TEST1_MASK 0x1 +#define RG_MTKAIF_LOOPBACK_TEST1_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_ADDA_MTKAIF_RX_CFG0 */ +#define RG_MTKAIF_RXIF_VOICE_MODE_SFT 12 +#define RG_MTKAIF_RXIF_VOICE_MODE_MASK 0xf +#define RG_MTKAIF_RXIF_VOICE_MODE_MASK_SFT (0xf << 12) +#define RG_MTKAIF_RXIF_DATA_BIT_SFT 8 +#define RG_MTKAIF_RXIF_DATA_BIT_MASK 0x7 +#define RG_MTKAIF_RXIF_DATA_BIT_MASK_SFT (0x7 << 8) +#define RG_MTKAIF_RXIF_FIFO_RSP_SFT 4 +#define RG_MTKAIF_RXIF_FIFO_RSP_MASK 0x7 +#define RG_MTKAIF_RXIF_FIFO_RSP_MASK_SFT (0x7 << 4) +#define RG_MTKAIF_RXIF_DETECT_ON_SFT 3 +#define RG_MTKAIF_RXIF_DETECT_ON_MASK 0x1 +#define RG_MTKAIF_RXIF_DETECT_ON_MASK_SFT (0x1 << 3) +#define RG_MTKAIF_RXIF_DATA_MODE_SFT 0 +#define RG_MTKAIF_RXIF_DATA_MODE_MASK 0x1 +#define RG_MTKAIF_RXIF_DATA_MODE_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_ADDA_MTKAIF_RX_CFG1 */ +#define RG_MTKAIF_RXIF_SYNC_SEARCH_TABLE_SFT 12 +#define RG_MTKAIF_RXIF_SYNC_SEARCH_TABLE_MASK 0xf +#define RG_MTKAIF_RXIF_SYNC_SEARCH_TABLE_MASK_SFT (0xf << 12) +#define RG_MTKAIF_RXIF_INVALID_SYNC_CHECK_ROUND_SFT 8 +#define RG_MTKAIF_RXIF_INVALID_SYNC_CHECK_ROUND_MASK 0xf +#define RG_MTKAIF_RXIF_INVALID_SYNC_CHECK_ROUND_MASK_SFT (0xf << 8) +#define RG_MTKAIF_RXIF_SYNC_CHECK_ROUND_SFT 4 +#define RG_MTKAIF_RXIF_SYNC_CHECK_ROUND_MASK 0xf +#define RG_MTKAIF_RXIF_SYNC_CHECK_ROUND_MASK_SFT (0xf << 4) +#define RG_MTKAIF_RXIF_VOICE_MODE_PROTOCOL2_SFT 0 +#define RG_MTKAIF_RXIF_VOICE_MODE_PROTOCOL2_MASK 0xf +#define RG_MTKAIF_RXIF_VOICE_MODE_PROTOCOL2_MASK_SFT (0xf << 0) + +/* MT6358_AFE_ADDA_MTKAIF_RX_CFG2 */ +#define RG_MTKAIF_RXIF_CLEAR_SYNC_FAIL_SFT 12 +#define RG_MTKAIF_RXIF_CLEAR_SYNC_FAIL_MASK 0x1 +#define RG_MTKAIF_RXIF_CLEAR_SYNC_FAIL_MASK_SFT (0x1 << 12) +#define RG_MTKAIF_RXIF_SYNC_CNT_TABLE_SFT 0 +#define RG_MTKAIF_RXIF_SYNC_CNT_TABLE_MASK 0xfff +#define RG_MTKAIF_RXIF_SYNC_CNT_TABLE_MASK_SFT (0xfff << 0) + +/* MT6358_AFE_ADDA_MTKAIF_RX_CFG3 */ +#define RG_MTKAIF_RXIF_LOOPBACK_USE_NLE_SFT 7 +#define RG_MTKAIF_RXIF_LOOPBACK_USE_NLE_MASK 0x1 +#define RG_MTKAIF_RXIF_LOOPBACK_USE_NLE_MASK_SFT (0x1 << 7) +#define RG_MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_SFT 4 +#define RG_MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK 0x7 +#define RG_MTKAIF_RXIF_FIFO_RSP_PROTOCOL2_MASK_SFT (0x7 << 4) +#define RG_MTKAIF_RXIF_DETECT_ON_PROTOCOL2_SFT 3 +#define RG_MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK 0x1 +#define RG_MTKAIF_RXIF_DETECT_ON_PROTOCOL2_MASK_SFT (0x1 << 3) + +/* MT6358_AFE_ADDA_MTKAIF_TX_CFG1 */ +#define RG_MTKAIF_SYNC_WORD2_SFT 4 +#define RG_MTKAIF_SYNC_WORD2_MASK 0x7 +#define RG_MTKAIF_SYNC_WORD2_MASK_SFT (0x7 << 4) +#define RG_MTKAIF_SYNC_WORD1_SFT 0 +#define RG_MTKAIF_SYNC_WORD1_MASK 0x7 +#define RG_MTKAIF_SYNC_WORD1_MASK_SFT (0x7 << 0) + +/* MT6358_AFE_SGEN_CFG0 */ +#define SGEN_AMP_DIV_CH1_CTL_SFT 12 +#define SGEN_AMP_DIV_CH1_CTL_MASK 0xf +#define SGEN_AMP_DIV_CH1_CTL_MASK_SFT (0xf << 12) +#define SGEN_DAC_EN_CTL_SFT 7 +#define SGEN_DAC_EN_CTL_MASK 0x1 +#define SGEN_DAC_EN_CTL_MASK_SFT (0x1 << 7) +#define SGEN_MUTE_SW_CTL_SFT 6 +#define SGEN_MUTE_SW_CTL_MASK 0x1 +#define SGEN_MUTE_SW_CTL_MASK_SFT (0x1 << 6) +#define R_AUD_SDM_MUTE_L_SFT 5 +#define R_AUD_SDM_MUTE_L_MASK 0x1 +#define R_AUD_SDM_MUTE_L_MASK_SFT (0x1 << 5) +#define R_AUD_SDM_MUTE_R_SFT 4 +#define R_AUD_SDM_MUTE_R_MASK 0x1 +#define R_AUD_SDM_MUTE_R_MASK_SFT (0x1 << 4) + +/* MT6358_AFE_SGEN_CFG1 */ +#define C_SGEN_RCH_INV_5BIT_SFT 15 +#define C_SGEN_RCH_INV_5BIT_MASK 0x1 +#define C_SGEN_RCH_INV_5BIT_MASK_SFT (0x1 << 15) +#define C_SGEN_RCH_INV_8BIT_SFT 14 +#define C_SGEN_RCH_INV_8BIT_MASK 0x1 +#define C_SGEN_RCH_INV_8BIT_MASK_SFT (0x1 << 14) +#define SGEN_FREQ_DIV_CH1_CTL_SFT 0 +#define SGEN_FREQ_DIV_CH1_CTL_MASK 0x1f +#define SGEN_FREQ_DIV_CH1_CTL_MASK_SFT (0x1f << 0) + +/* MT6358_AFE_ADC_ASYNC_FIFO_CFG */ +#define RG_UL_ASYNC_FIFO_SOFT_RST_EN_SFT 5 +#define RG_UL_ASYNC_FIFO_SOFT_RST_EN_MASK 0x1 +#define RG_UL_ASYNC_FIFO_SOFT_RST_EN_MASK_SFT (0x1 << 5) +#define RG_UL_ASYNC_FIFO_SOFT_RST_SFT 4 +#define RG_UL_ASYNC_FIFO_SOFT_RST_MASK 0x1 +#define RG_UL_ASYNC_FIFO_SOFT_RST_MASK_SFT (0x1 << 4) +#define RG_AMIC_UL_ADC_CLK_SEL_SFT 1 +#define RG_AMIC_UL_ADC_CLK_SEL_MASK 0x1 +#define RG_AMIC_UL_ADC_CLK_SEL_MASK_SFT (0x1 << 1) + +/* MT6358_AFE_DCCLK_CFG0 */ +#define DCCLK_DIV_SFT 5 +#define DCCLK_DIV_MASK 0x7ff +#define DCCLK_DIV_MASK_SFT (0x7ff << 5) +#define DCCLK_INV_SFT 4 +#define DCCLK_INV_MASK 0x1 +#define DCCLK_INV_MASK_SFT (0x1 << 4) +#define DCCLK_PDN_SFT 1 +#define DCCLK_PDN_MASK 0x1 +#define DCCLK_PDN_MASK_SFT (0x1 << 1) +#define DCCLK_GEN_ON_SFT 0 +#define DCCLK_GEN_ON_MASK 0x1 +#define DCCLK_GEN_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_DCCLK_CFG1 */ +#define RESYNC_SRC_SEL_SFT 10 +#define RESYNC_SRC_SEL_MASK 0x3 +#define RESYNC_SRC_SEL_MASK_SFT (0x3 << 10) +#define RESYNC_SRC_CK_INV_SFT 9 +#define RESYNC_SRC_CK_INV_MASK 0x1 +#define RESYNC_SRC_CK_INV_MASK_SFT (0x1 << 9) +#define DCCLK_RESYNC_BYPASS_SFT 8 +#define DCCLK_RESYNC_BYPASS_MASK 0x1 +#define DCCLK_RESYNC_BYPASS_MASK_SFT (0x1 << 8) +#define DCCLK_PHASE_SEL_SFT 4 +#define DCCLK_PHASE_SEL_MASK 0xf +#define DCCLK_PHASE_SEL_MASK_SFT (0xf << 4) + +/* MT6358_AUDIO_DIG_CFG */ +#define RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT 15 +#define RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK 0x1 +#define RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT (0x1 << 15) +#define RG_AUD_PAD_TOP_PHASE_MODE2_SFT 8 +#define RG_AUD_PAD_TOP_PHASE_MODE2_MASK 0x7f +#define RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT (0x7f << 8) +#define RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT 7 +#define RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK 0x1 +#define RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT (0x1 << 7) +#define RG_AUD_PAD_TOP_PHASE_MODE_SFT 0 +#define RG_AUD_PAD_TOP_PHASE_MODE_MASK 0x7f +#define RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT (0x7f << 0) + +/* MT6358_AFE_AUD_PAD_TOP */ +#define RG_AUD_PAD_TOP_TX_FIFO_RSP_SFT 12 +#define RG_AUD_PAD_TOP_TX_FIFO_RSP_MASK 0x7 +#define RG_AUD_PAD_TOP_TX_FIFO_RSP_MASK_SFT (0x7 << 12) +#define RG_AUD_PAD_TOP_MTKAIF_CLK_PROTOCOL2_SFT 11 +#define RG_AUD_PAD_TOP_MTKAIF_CLK_PROTOCOL2_MASK 0x1 +#define RG_AUD_PAD_TOP_MTKAIF_CLK_PROTOCOL2_MASK_SFT (0x1 << 11) +#define RG_AUD_PAD_TOP_TX_FIFO_ON_SFT 8 +#define RG_AUD_PAD_TOP_TX_FIFO_ON_MASK 0x1 +#define RG_AUD_PAD_TOP_TX_FIFO_ON_MASK_SFT (0x1 << 8) + +/* MT6358_AFE_AUD_PAD_TOP_MON */ +#define ADDA_AUD_PAD_TOP_MON_SFT 0 +#define ADDA_AUD_PAD_TOP_MON_MASK 0xffff +#define ADDA_AUD_PAD_TOP_MON_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_AUD_PAD_TOP_MON1 */ +#define ADDA_AUD_PAD_TOP_MON1_SFT 0 +#define ADDA_AUD_PAD_TOP_MON1_MASK 0xffff +#define ADDA_AUD_PAD_TOP_MON1_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_DL_NLE_CFG */ +#define NLE_RCH_HPGAIN_SEL_SFT 10 +#define NLE_RCH_HPGAIN_SEL_MASK 0x1 +#define NLE_RCH_HPGAIN_SEL_MASK_SFT (0x1 << 10) +#define NLE_RCH_CH_SEL_SFT 9 +#define NLE_RCH_CH_SEL_MASK 0x1 +#define NLE_RCH_CH_SEL_MASK_SFT (0x1 << 9) +#define NLE_RCH_ON_SFT 8 +#define NLE_RCH_ON_MASK 0x1 +#define NLE_RCH_ON_MASK_SFT (0x1 << 8) +#define NLE_LCH_HPGAIN_SEL_SFT 2 +#define NLE_LCH_HPGAIN_SEL_MASK 0x1 +#define NLE_LCH_HPGAIN_SEL_MASK_SFT (0x1 << 2) +#define NLE_LCH_CH_SEL_SFT 1 +#define NLE_LCH_CH_SEL_MASK 0x1 +#define NLE_LCH_CH_SEL_MASK_SFT (0x1 << 1) +#define NLE_LCH_ON_SFT 0 +#define NLE_LCH_ON_MASK 0x1 +#define NLE_LCH_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_DL_NLE_MON */ +#define NLE_MONITOR_SFT 0 +#define NLE_MONITOR_MASK 0x3fff +#define NLE_MONITOR_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_CG_EN_MON */ +#define CK_CG_EN_MON_SFT 0 +#define CK_CG_EN_MON_MASK 0x3f +#define CK_CG_EN_MON_MASK_SFT (0x3f << 0) + +/* MT6358_AFE_VOW_TOP */ +#define PDN_VOW_SFT 15 +#define PDN_VOW_MASK 0x1 +#define PDN_VOW_MASK_SFT (0x1 << 15) +#define VOW_1P6M_800K_SEL_SFT 14 +#define VOW_1P6M_800K_SEL_MASK 0x1 +#define VOW_1P6M_800K_SEL_MASK_SFT (0x1 << 14) +#define VOW_DIGMIC_ON_SFT 13 +#define VOW_DIGMIC_ON_MASK 0x1 +#define VOW_DIGMIC_ON_MASK_SFT (0x1 << 13) +#define VOW_CK_DIV_RST_SFT 12 +#define VOW_CK_DIV_RST_MASK 0x1 +#define VOW_CK_DIV_RST_MASK_SFT (0x1 << 12) +#define VOW_ON_SFT 11 +#define VOW_ON_MASK 0x1 +#define VOW_ON_MASK_SFT (0x1 << 11) +#define VOW_DIGMIC_CK_PHASE_SEL_SFT 8 +#define VOW_DIGMIC_CK_PHASE_SEL_MASK 0x7 +#define VOW_DIGMIC_CK_PHASE_SEL_MASK_SFT (0x7 << 8) +#define MAIN_DMIC_CK_VOW_SEL_SFT 7 +#define MAIN_DMIC_CK_VOW_SEL_MASK 0x1 +#define MAIN_DMIC_CK_VOW_SEL_MASK_SFT (0x1 << 7) +#define VOW_SDM_3_LEVEL_SFT 6 +#define VOW_SDM_3_LEVEL_MASK 0x1 +#define VOW_SDM_3_LEVEL_MASK_SFT (0x1 << 6) +#define VOW_LOOP_BACK_MODE_SFT 5 +#define VOW_LOOP_BACK_MODE_MASK 0x1 +#define VOW_LOOP_BACK_MODE_MASK_SFT (0x1 << 5) +#define VOW_INTR_SOURCE_SEL_SFT 4 +#define VOW_INTR_SOURCE_SEL_MASK 0x1 +#define VOW_INTR_SOURCE_SEL_MASK_SFT (0x1 << 4) +#define VOW_INTR_CLR_SFT 3 +#define VOW_INTR_CLR_MASK 0x1 +#define VOW_INTR_CLR_MASK_SFT (0x1 << 3) +#define S_N_VALUE_RST_SFT 2 +#define S_N_VALUE_RST_MASK 0x1 +#define S_N_VALUE_RST_MASK_SFT (0x1 << 2) +#define SAMPLE_BASE_MODE_SFT 1 +#define SAMPLE_BASE_MODE_MASK 0x1 +#define SAMPLE_BASE_MODE_MASK_SFT (0x1 << 1) +#define VOW_INTR_FLAG_SFT 0 +#define VOW_INTR_FLAG_MASK 0x1 +#define VOW_INTR_FLAG_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_VOW_CFG0 */ +#define AMPREF_SFT 0 +#define AMPREF_MASK 0xffff +#define AMPREF_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_CFG1 */ +#define TIMERINI_SFT 0 +#define TIMERINI_MASK 0xffff +#define TIMERINI_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_CFG2 */ +#define B_DEFAULT_SFT 12 +#define B_DEFAULT_MASK 0x7 +#define B_DEFAULT_MASK_SFT (0x7 << 12) +#define A_DEFAULT_SFT 8 +#define A_DEFAULT_MASK 0x7 +#define A_DEFAULT_MASK_SFT (0x7 << 8) +#define B_INI_SFT 4 +#define B_INI_MASK 0x7 +#define B_INI_MASK_SFT (0x7 << 4) +#define A_INI_SFT 0 +#define A_INI_MASK 0x7 +#define A_INI_MASK_SFT (0x7 << 0) + +/* MT6358_AFE_VOW_CFG3 */ +#define K_BETA_RISE_SFT 12 +#define K_BETA_RISE_MASK 0xf +#define K_BETA_RISE_MASK_SFT (0xf << 12) +#define K_BETA_FALL_SFT 8 +#define K_BETA_FALL_MASK 0xf +#define K_BETA_FALL_MASK_SFT (0xf << 8) +#define K_ALPHA_RISE_SFT 4 +#define K_ALPHA_RISE_MASK 0xf +#define K_ALPHA_RISE_MASK_SFT (0xf << 4) +#define K_ALPHA_FALL_SFT 0 +#define K_ALPHA_FALL_MASK 0xf +#define K_ALPHA_FALL_MASK_SFT (0xf << 0) + +/* MT6358_AFE_VOW_CFG4 */ +#define VOW_TXIF_SCK_INV_SFT 15 +#define VOW_TXIF_SCK_INV_MASK 0x1 +#define VOW_TXIF_SCK_INV_MASK_SFT (0x1 << 15) +#define VOW_ADC_TESTCK_SRC_SEL_SFT 12 +#define VOW_ADC_TESTCK_SRC_SEL_MASK 0x7 +#define VOW_ADC_TESTCK_SRC_SEL_MASK_SFT (0x7 << 12) +#define VOW_ADC_TESTCK_SEL_SFT 11 +#define VOW_ADC_TESTCK_SEL_MASK 0x1 +#define VOW_ADC_TESTCK_SEL_MASK_SFT (0x1 << 11) +#define VOW_ADC_CLK_INV_SFT 10 +#define VOW_ADC_CLK_INV_MASK 0x1 +#define VOW_ADC_CLK_INV_MASK_SFT (0x1 << 10) +#define VOW_TXIF_MONO_SFT 9 +#define VOW_TXIF_MONO_MASK 0x1 +#define VOW_TXIF_MONO_MASK_SFT (0x1 << 9) +#define VOW_TXIF_SCK_DIV_SFT 4 +#define VOW_TXIF_SCK_DIV_MASK 0x1f +#define VOW_TXIF_SCK_DIV_MASK_SFT (0x1f << 4) +#define K_GAMMA_SFT 0 +#define K_GAMMA_MASK 0xf +#define K_GAMMA_MASK_SFT (0xf << 0) + +/* MT6358_AFE_VOW_CFG5 */ +#define N_MIN_SFT 0 +#define N_MIN_MASK 0xffff +#define N_MIN_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_CFG6 */ +#define RG_WINDOW_SIZE_SEL_SFT 12 +#define RG_WINDOW_SIZE_SEL_MASK 0x1 +#define RG_WINDOW_SIZE_SEL_MASK_SFT (0x1 << 12) +#define RG_FLR_BYPASS_SFT 11 +#define RG_FLR_BYPASS_MASK 0x1 +#define RG_FLR_BYPASS_MASK_SFT (0x1 << 11) +#define RG_FLR_RATIO_SFT 8 +#define RG_FLR_RATIO_MASK 0x7 +#define RG_FLR_RATIO_MASK_SFT (0x7 << 8) +#define RG_BUCK_DVFS_DONE_SW_CTL_SFT 7 +#define RG_BUCK_DVFS_DONE_SW_CTL_MASK 0x1 +#define RG_BUCK_DVFS_DONE_SW_CTL_MASK_SFT (0x1 << 7) +#define RG_BUCK_DVFS_DONE_HW_MODE_SFT 6 +#define RG_BUCK_DVFS_DONE_HW_MODE_MASK 0x1 +#define RG_BUCK_DVFS_DONE_HW_MODE_MASK_SFT (0x1 << 6) +#define RG_BUCK_DVFS_HW_CNT_THR_SFT 0 +#define RG_BUCK_DVFS_HW_CNT_THR_MASK 0x3f +#define RG_BUCK_DVFS_HW_CNT_THR_MASK_SFT (0x3f << 0) + +/* MT6358_AFE_VOW_MON0 */ +#define VOW_DOWNCNT_SFT 0 +#define VOW_DOWNCNT_MASK 0xffff +#define VOW_DOWNCNT_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_MON1 */ +#define K_TMP_MON_SFT 10 +#define K_TMP_MON_MASK 0xf +#define K_TMP_MON_MASK_SFT (0xf << 10) +#define SLT_COUNTER_MON_SFT 7 +#define SLT_COUNTER_MON_MASK 0x7 +#define SLT_COUNTER_MON_MASK_SFT (0x7 << 7) +#define VOW_B_SFT 4 +#define VOW_B_MASK 0x7 +#define VOW_B_MASK_SFT (0x7 << 4) +#define VOW_A_SFT 1 +#define VOW_A_MASK 0x7 +#define VOW_A_MASK_SFT (0x7 << 1) +#define SECOND_CNT_START_SFT 0 +#define SECOND_CNT_START_MASK 0x1 +#define SECOND_CNT_START_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_VOW_MON2 */ +#define VOW_S_L_SFT 0 +#define VOW_S_L_MASK 0xffff +#define VOW_S_L_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_MON3 */ +#define VOW_S_H_SFT 0 +#define VOW_S_H_MASK 0xffff +#define VOW_S_H_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_MON4 */ +#define VOW_N_L_SFT 0 +#define VOW_N_L_MASK 0xffff +#define VOW_N_L_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_MON5 */ +#define VOW_N_H_SFT 0 +#define VOW_N_H_MASK 0xffff +#define VOW_N_H_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_SN_INI_CFG */ +#define VOW_SN_INI_CFG_EN_SFT 15 +#define VOW_SN_INI_CFG_EN_MASK 0x1 +#define VOW_SN_INI_CFG_EN_MASK_SFT (0x1 << 15) +#define VOW_SN_INI_CFG_VAL_SFT 0 +#define VOW_SN_INI_CFG_VAL_MASK 0x7fff +#define VOW_SN_INI_CFG_VAL_MASK_SFT (0x7fff << 0) + +/* MT6358_AFE_VOW_TGEN_CFG0 */ +#define VOW_TGEN_EN_SFT 15 +#define VOW_TGEN_EN_MASK 0x1 +#define VOW_TGEN_EN_MASK_SFT (0x1 << 15) +#define VOW_TGEN_MUTE_SW_SFT 14 +#define VOW_TGEN_MUTE_SW_MASK 0x1 +#define VOW_TGEN_MUTE_SW_MASK_SFT (0x1 << 14) +#define VOW_TGEN_FREQ_DIV_SFT 0 +#define VOW_TGEN_FREQ_DIV_MASK 0x3fff +#define VOW_TGEN_FREQ_DIV_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_POSDIV_CFG0 */ +#define BUCK_DVFS_DONE_SFT 15 +#define BUCK_DVFS_DONE_MASK 0x1 +#define BUCK_DVFS_DONE_MASK_SFT (0x1 << 15) +#define VOW_32K_MODE_SFT 13 +#define VOW_32K_MODE_MASK 0x1 +#define VOW_32K_MODE_MASK_SFT (0x1 << 13) +#define RG_BUCK_CLK_DIV_SFT 8 +#define RG_BUCK_CLK_DIV_MASK 0x1f +#define RG_BUCK_CLK_DIV_MASK_SFT (0x1f << 8) +#define RG_A1P6M_EN_SEL_SFT 7 +#define RG_A1P6M_EN_SEL_MASK 0x1 +#define RG_A1P6M_EN_SEL_MASK_SFT (0x1 << 7) +#define VOW_CLK_SEL_SFT 6 +#define VOW_CLK_SEL_MASK 0x1 +#define VOW_CLK_SEL_MASK_SFT (0x1 << 6) +#define VOW_INTR_SW_MODE_SFT 5 +#define VOW_INTR_SW_MODE_MASK 0x1 +#define VOW_INTR_SW_MODE_MASK_SFT (0x1 << 5) +#define VOW_INTR_SW_VAL_SFT 4 +#define VOW_INTR_SW_VAL_MASK 0x1 +#define VOW_INTR_SW_VAL_MASK_SFT (0x1 << 4) +#define VOW_CIC_MODE_SEL_SFT 2 +#define VOW_CIC_MODE_SEL_MASK 0x3 +#define VOW_CIC_MODE_SEL_MASK_SFT (0x3 << 2) +#define RG_VOW_POSDIV_SFT 0 +#define RG_VOW_POSDIV_MASK 0x3 +#define RG_VOW_POSDIV_MASK_SFT (0x3 << 0) + +/* MT6358_AFE_VOW_HPF_CFG0 */ +#define VOW_HPF_DC_TEST_SFT 12 +#define VOW_HPF_DC_TEST_MASK 0xf +#define VOW_HPF_DC_TEST_MASK_SFT (0xf << 12) +#define VOW_IRQ_LATCH_SNR_EN_SFT 10 +#define VOW_IRQ_LATCH_SNR_EN_MASK 0x1 +#define VOW_IRQ_LATCH_SNR_EN_MASK_SFT (0x1 << 10) +#define VOW_DMICCLK_PDN_SFT 9 +#define VOW_DMICCLK_PDN_MASK 0x1 +#define VOW_DMICCLK_PDN_MASK_SFT (0x1 << 9) +#define VOW_POSDIVCLK_PDN_SFT 8 +#define VOW_POSDIVCLK_PDN_MASK 0x1 +#define VOW_POSDIVCLK_PDN_MASK_SFT (0x1 << 8) +#define RG_BASELINE_ALPHA_ORDER_SFT 4 +#define RG_BASELINE_ALPHA_ORDER_MASK 0xf +#define RG_BASELINE_ALPHA_ORDER_MASK_SFT (0xf << 4) +#define RG_MTKAIF_HPF_BYPASS_SFT 2 +#define RG_MTKAIF_HPF_BYPASS_MASK 0x1 +#define RG_MTKAIF_HPF_BYPASS_MASK_SFT (0x1 << 2) +#define RG_SNRDET_HPF_BYPASS_SFT 1 +#define RG_SNRDET_HPF_BYPASS_MASK 0x1 +#define RG_SNRDET_HPF_BYPASS_MASK_SFT (0x1 << 1) +#define RG_HPF_ON_SFT 0 +#define RG_HPF_ON_MASK 0x1 +#define RG_HPF_ON_MASK_SFT (0x1 << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG0 */ +#define RG_PERIODIC_EN_SFT 15 +#define RG_PERIODIC_EN_MASK 0x1 +#define RG_PERIODIC_EN_MASK_SFT (0x1 << 15) +#define RG_PERIODIC_CNT_CLR_SFT 14 +#define RG_PERIODIC_CNT_CLR_MASK 0x1 +#define RG_PERIODIC_CNT_CLR_MASK_SFT (0x1 << 14) +#define RG_PERIODIC_CNT_PERIOD_SFT 0 +#define RG_PERIODIC_CNT_PERIOD_MASK 0x3fff +#define RG_PERIODIC_CNT_PERIOD_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG1 */ +#define RG_PERIODIC_CNT_SET_SFT 15 +#define RG_PERIODIC_CNT_SET_MASK 0x1 +#define RG_PERIODIC_CNT_SET_MASK_SFT (0x1 << 15) +#define RG_PERIODIC_CNT_PAUSE_SFT 14 +#define RG_PERIODIC_CNT_PAUSE_MASK 0x1 +#define RG_PERIODIC_CNT_PAUSE_MASK_SFT (0x1 << 14) +#define RG_PERIODIC_CNT_SET_VALUE_SFT 0 +#define RG_PERIODIC_CNT_SET_VALUE_MASK 0x3fff +#define RG_PERIODIC_CNT_SET_VALUE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG2 */ +#define AUDPREAMPLON_PERIODIC_MODE_SFT 15 +#define AUDPREAMPLON_PERIODIC_MODE_MASK 0x1 +#define AUDPREAMPLON_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDPREAMPLON_PERIODIC_INVERSE_SFT 14 +#define AUDPREAMPLON_PERIODIC_INVERSE_MASK 0x1 +#define AUDPREAMPLON_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDPREAMPLON_PERIODIC_ON_CYCLE_SFT 0 +#define AUDPREAMPLON_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDPREAMPLON_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG3 */ +#define AUDPREAMPLDCPRECHARGE_PERIODIC_MODE_SFT 15 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_MODE_MASK 0x1 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDPREAMPLDCPRECHARGE_PERIODIC_INVERSE_SFT 14 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_INVERSE_MASK 0x1 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDPREAMPLDCPRECHARGE_PERIODIC_ON_CYCLE_SFT 0 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDPREAMPLDCPRECHARGE_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG4 */ +#define AUDADCLPWRUP_PERIODIC_MODE_SFT 15 +#define AUDADCLPWRUP_PERIODIC_MODE_MASK 0x1 +#define AUDADCLPWRUP_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDADCLPWRUP_PERIODIC_INVERSE_SFT 14 +#define AUDADCLPWRUP_PERIODIC_INVERSE_MASK 0x1 +#define AUDADCLPWRUP_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDADCLPWRUP_PERIODIC_ON_CYCLE_SFT 0 +#define AUDADCLPWRUP_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDADCLPWRUP_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG5 */ +#define AUDGLBVOWLPWEN_PERIODIC_MODE_SFT 15 +#define AUDGLBVOWLPWEN_PERIODIC_MODE_MASK 0x1 +#define AUDGLBVOWLPWEN_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDGLBVOWLPWEN_PERIODIC_INVERSE_SFT 14 +#define AUDGLBVOWLPWEN_PERIODIC_INVERSE_MASK 0x1 +#define AUDGLBVOWLPWEN_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDGLBVOWLPWEN_PERIODIC_ON_CYCLE_SFT 0 +#define AUDGLBVOWLPWEN_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDGLBVOWLPWEN_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG6 */ +#define AUDDIGMICEN_PERIODIC_MODE_SFT 15 +#define AUDDIGMICEN_PERIODIC_MODE_MASK 0x1 +#define AUDDIGMICEN_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDDIGMICEN_PERIODIC_INVERSE_SFT 14 +#define AUDDIGMICEN_PERIODIC_INVERSE_MASK 0x1 +#define AUDDIGMICEN_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDDIGMICEN_PERIODIC_ON_CYCLE_SFT 0 +#define AUDDIGMICEN_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDDIGMICEN_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG7 */ +#define AUDPWDBMICBIAS0_PERIODIC_MODE_SFT 15 +#define AUDPWDBMICBIAS0_PERIODIC_MODE_MASK 0x1 +#define AUDPWDBMICBIAS0_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDPWDBMICBIAS0_PERIODIC_INVERSE_SFT 14 +#define AUDPWDBMICBIAS0_PERIODIC_INVERSE_MASK 0x1 +#define AUDPWDBMICBIAS0_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDPWDBMICBIAS0_PERIODIC_ON_CYCLE_SFT 0 +#define AUDPWDBMICBIAS0_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDPWDBMICBIAS0_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG8 */ +#define AUDPWDBMICBIAS1_PERIODIC_MODE_SFT 15 +#define AUDPWDBMICBIAS1_PERIODIC_MODE_MASK 0x1 +#define AUDPWDBMICBIAS1_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDPWDBMICBIAS1_PERIODIC_INVERSE_SFT 14 +#define AUDPWDBMICBIAS1_PERIODIC_INVERSE_MASK 0x1 +#define AUDPWDBMICBIAS1_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDPWDBMICBIAS1_PERIODIC_ON_CYCLE_SFT 0 +#define AUDPWDBMICBIAS1_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDPWDBMICBIAS1_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG9 */ +#define XO_VOW_CK_EN_PERIODIC_MODE_SFT 15 +#define XO_VOW_CK_EN_PERIODIC_MODE_MASK 0x1 +#define XO_VOW_CK_EN_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define XO_VOW_CK_EN_PERIODIC_INVERSE_SFT 14 +#define XO_VOW_CK_EN_PERIODIC_INVERSE_MASK 0x1 +#define XO_VOW_CK_EN_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define XO_VOW_CK_EN_PERIODIC_ON_CYCLE_SFT 0 +#define XO_VOW_CK_EN_PERIODIC_ON_CYCLE_MASK 0x3fff +#define XO_VOW_CK_EN_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG10 */ +#define AUDGLB_PWRDN_PERIODIC_MODE_SFT 15 +#define AUDGLB_PWRDN_PERIODIC_MODE_MASK 0x1 +#define AUDGLB_PWRDN_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define AUDGLB_PWRDN_PERIODIC_INVERSE_SFT 14 +#define AUDGLB_PWRDN_PERIODIC_INVERSE_MASK 0x1 +#define AUDGLB_PWRDN_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define AUDGLB_PWRDN_PERIODIC_ON_CYCLE_SFT 0 +#define AUDGLB_PWRDN_PERIODIC_ON_CYCLE_MASK 0x3fff +#define AUDGLB_PWRDN_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG11 */ +#define VOW_ON_PERIODIC_MODE_SFT 15 +#define VOW_ON_PERIODIC_MODE_MASK 0x1 +#define VOW_ON_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define VOW_ON_PERIODIC_INVERSE_SFT 14 +#define VOW_ON_PERIODIC_INVERSE_MASK 0x1 +#define VOW_ON_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define VOW_ON_PERIODIC_ON_CYCLE_SFT 0 +#define VOW_ON_PERIODIC_ON_CYCLE_MASK 0x3fff +#define VOW_ON_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG12 */ +#define DMIC_ON_PERIODIC_MODE_SFT 15 +#define DMIC_ON_PERIODIC_MODE_MASK 0x1 +#define DMIC_ON_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define DMIC_ON_PERIODIC_INVERSE_SFT 14 +#define DMIC_ON_PERIODIC_INVERSE_MASK 0x1 +#define DMIC_ON_PERIODIC_INVERSE_MASK_SFT (0x1 << 14) +#define DMIC_ON_PERIODIC_ON_CYCLE_SFT 0 +#define DMIC_ON_PERIODIC_ON_CYCLE_MASK 0x3fff +#define DMIC_ON_PERIODIC_ON_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG13 */ +#define PDN_VOW_F32K_CK_SFT 15 +#define PDN_VOW_F32K_CK_MASK 0x1 +#define PDN_VOW_F32K_CK_MASK_SFT (0x1 << 15) +#define AUDPREAMPLON_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDPREAMPLON_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDPREAMPLON_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG14 */ +#define VOW_SNRDET_PERIODIC_CFG_SFT 15 +#define VOW_SNRDET_PERIODIC_CFG_MASK 0x1 +#define VOW_SNRDET_PERIODIC_CFG_MASK_SFT (0x1 << 15) +#define AUDPREAMPLDCPRECHARGE_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDPREAMPLDCPRECHARGE_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDPREAMPLDCPRECHARGE_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG15 */ +#define AUDADCLPWRUP_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDADCLPWRUP_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDADCLPWRUP_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG16 */ +#define AUDGLBVOWLPWEN_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDGLBVOWLPWEN_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDGLBVOWLPWEN_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG17 */ +#define AUDDIGMICEN_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDDIGMICEN_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDDIGMICEN_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG18 */ +#define AUDPWDBMICBIAS0_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDPWDBMICBIAS0_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDPWDBMICBIAS0_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG19 */ +#define AUDPWDBMICBIAS1_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDPWDBMICBIAS1_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDPWDBMICBIAS1_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG20 */ +#define CLKSQ_EN_VOW_PERIODIC_MODE_SFT 15 +#define CLKSQ_EN_VOW_PERIODIC_MODE_MASK 0x1 +#define CLKSQ_EN_VOW_PERIODIC_MODE_MASK_SFT (0x1 << 15) +#define XO_VOW_CK_EN_PERIODIC_OFF_CYCLE_SFT 0 +#define XO_VOW_CK_EN_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define XO_VOW_CK_EN_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG21 */ +#define AUDGLB_PWRDN_PERIODIC_OFF_CYCLE_SFT 0 +#define AUDGLB_PWRDN_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define AUDGLB_PWRDN_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG22 */ +#define VOW_ON_PERIODIC_OFF_CYCLE_SFT 0 +#define VOW_ON_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define VOW_ON_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_CFG23 */ +#define DMIC_ON_PERIODIC_OFF_CYCLE_SFT 0 +#define DMIC_ON_PERIODIC_OFF_CYCLE_MASK 0x3fff +#define DMIC_ON_PERIODIC_OFF_CYCLE_MASK_SFT (0x3fff << 0) + +/* MT6358_AFE_VOW_PERIODIC_MON0 */ +#define VOW_PERIODIC_MON_SFT 0 +#define VOW_PERIODIC_MON_MASK 0xffff +#define VOW_PERIODIC_MON_MASK_SFT (0xffff << 0) + +/* MT6358_AFE_VOW_PERIODIC_MON1 */ +#define VOW_PERIODIC_COUNT_MON_SFT 0 +#define VOW_PERIODIC_COUNT_MON_MASK 0xffff +#define VOW_PERIODIC_COUNT_MON_MASK_SFT (0xffff << 0) + +/* MT6358_AUDENC_DSN_ID */ +#define AUDENC_ANA_ID_SFT 0 +#define AUDENC_ANA_ID_MASK 0xff +#define AUDENC_ANA_ID_MASK_SFT (0xff << 0) +#define AUDENC_DIG_ID_SFT 8 +#define AUDENC_DIG_ID_MASK 0xff +#define AUDENC_DIG_ID_MASK_SFT (0xff << 8) + +/* MT6358_AUDENC_DSN_REV0 */ +#define AUDENC_ANA_MINOR_REV_SFT 0 +#define AUDENC_ANA_MINOR_REV_MASK 0xf +#define AUDENC_ANA_MINOR_REV_MASK_SFT (0xf << 0) +#define AUDENC_ANA_MAJOR_REV_SFT 4 +#define AUDENC_ANA_MAJOR_REV_MASK 0xf +#define AUDENC_ANA_MAJOR_REV_MASK_SFT (0xf << 4) +#define AUDENC_DIG_MINOR_REV_SFT 8 +#define AUDENC_DIG_MINOR_REV_MASK 0xf +#define AUDENC_DIG_MINOR_REV_MASK_SFT (0xf << 8) +#define AUDENC_DIG_MAJOR_REV_SFT 12 +#define AUDENC_DIG_MAJOR_REV_MASK 0xf +#define AUDENC_DIG_MAJOR_REV_MASK_SFT (0xf << 12) + +/* MT6358_AUDENC_DSN_DBI */ +#define AUDENC_DSN_CBS_SFT 0 +#define AUDENC_DSN_CBS_MASK 0x3 +#define AUDENC_DSN_CBS_MASK_SFT (0x3 << 0) +#define AUDENC_DSN_BIX_SFT 2 +#define AUDENC_DSN_BIX_MASK 0x3 +#define AUDENC_DSN_BIX_MASK_SFT (0x3 << 2) +#define AUDENC_DSN_ESP_SFT 8 +#define AUDENC_DSN_ESP_MASK 0xff +#define AUDENC_DSN_ESP_MASK_SFT (0xff << 8) + +/* MT6358_AUDENC_DSN_FPI */ +#define AUDENC_DSN_FPI_SFT 0 +#define AUDENC_DSN_FPI_MASK 0xff +#define AUDENC_DSN_FPI_MASK_SFT (0xff << 0) + +/* MT6358_AUDENC_ANA_CON0 */ +#define RG_AUDPREAMPLON_SFT 0 +#define RG_AUDPREAMPLON_MASK 0x1 +#define RG_AUDPREAMPLON_MASK_SFT (0x1 << 0) +#define RG_AUDPREAMPLDCCEN_SFT 1 +#define RG_AUDPREAMPLDCCEN_MASK 0x1 +#define RG_AUDPREAMPLDCCEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMPLDCPRECHARGE_SFT 2 +#define RG_AUDPREAMPLDCPRECHARGE_MASK 0x1 +#define RG_AUDPREAMPLDCPRECHARGE_MASK_SFT (0x1 << 2) +#define RG_AUDPREAMPLPGATEST_SFT 3 +#define RG_AUDPREAMPLPGATEST_MASK 0x1 +#define RG_AUDPREAMPLPGATEST_MASK_SFT (0x1 << 3) +#define RG_AUDPREAMPLVSCALE_SFT 4 +#define RG_AUDPREAMPLVSCALE_MASK 0x3 +#define RG_AUDPREAMPLVSCALE_MASK_SFT (0x3 << 4) +#define RG_AUDPREAMPLINPUTSEL_SFT 6 +#define RG_AUDPREAMPLINPUTSEL_MASK 0x3 +#define RG_AUDPREAMPLINPUTSEL_MASK_SFT (0x3 << 6) +#define RG_AUDPREAMPLGAIN_SFT 8 +#define RG_AUDPREAMPLGAIN_MASK 0x7 +#define RG_AUDPREAMPLGAIN_MASK_SFT (0x7 << 8) +#define RG_AUDADCLPWRUP_SFT 12 +#define RG_AUDADCLPWRUP_MASK 0x1 +#define RG_AUDADCLPWRUP_MASK_SFT (0x1 << 12) +#define RG_AUDADCLINPUTSEL_SFT 13 +#define RG_AUDADCLINPUTSEL_MASK 0x3 +#define RG_AUDADCLINPUTSEL_MASK_SFT (0x3 << 13) + +/* MT6358_AUDENC_ANA_CON1 */ +#define RG_AUDPREAMPRON_SFT 0 +#define RG_AUDPREAMPRON_MASK 0x1 +#define RG_AUDPREAMPRON_MASK_SFT (0x1 << 0) +#define RG_AUDPREAMPRDCCEN_SFT 1 +#define RG_AUDPREAMPRDCCEN_MASK 0x1 +#define RG_AUDPREAMPRDCCEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMPRDCPRECHARGE_SFT 2 +#define RG_AUDPREAMPRDCPRECHARGE_MASK 0x1 +#define RG_AUDPREAMPRDCPRECHARGE_MASK_SFT (0x1 << 2) +#define RG_AUDPREAMPRPGATEST_SFT 3 +#define RG_AUDPREAMPRPGATEST_MASK 0x1 +#define RG_AUDPREAMPRPGATEST_MASK_SFT (0x1 << 3) +#define RG_AUDPREAMPRVSCALE_SFT 4 +#define RG_AUDPREAMPRVSCALE_MASK 0x3 +#define RG_AUDPREAMPRVSCALE_MASK_SFT (0x3 << 4) +#define RG_AUDPREAMPRINPUTSEL_SFT 6 +#define RG_AUDPREAMPRINPUTSEL_MASK 0x3 +#define RG_AUDPREAMPRINPUTSEL_MASK_SFT (0x3 << 6) +#define RG_AUDPREAMPRGAIN_SFT 8 +#define RG_AUDPREAMPRGAIN_MASK 0x7 +#define RG_AUDPREAMPRGAIN_MASK_SFT (0x7 << 8) +#define RG_AUDIO_VOW_EN_SFT 11 +#define RG_AUDIO_VOW_EN_MASK 0x1 +#define RG_AUDIO_VOW_EN_MASK_SFT (0x1 << 11) +#define RG_AUDADCRPWRUP_SFT 12 +#define RG_AUDADCRPWRUP_MASK 0x1 +#define RG_AUDADCRPWRUP_MASK_SFT (0x1 << 12) +#define RG_AUDADCRINPUTSEL_SFT 13 +#define RG_AUDADCRINPUTSEL_MASK 0x3 +#define RG_AUDADCRINPUTSEL_MASK_SFT (0x3 << 13) +#define RG_CLKSQ_EN_VOW_SFT 15 +#define RG_CLKSQ_EN_VOW_MASK 0x1 +#define RG_CLKSQ_EN_VOW_MASK_SFT (0x1 << 15) + +/* MT6358_AUDENC_ANA_CON2 */ +#define RG_AUDULHALFBIAS_SFT 0 +#define RG_AUDULHALFBIAS_MASK 0x1 +#define RG_AUDULHALFBIAS_MASK_SFT (0x1 << 0) +#define RG_AUDGLBVOWLPWEN_SFT 1 +#define RG_AUDGLBVOWLPWEN_MASK 0x1 +#define RG_AUDGLBVOWLPWEN_MASK_SFT (0x1 << 1) +#define RG_AUDPREAMPLPEN_SFT 2 +#define RG_AUDPREAMPLPEN_MASK 0x1 +#define RG_AUDPREAMPLPEN_MASK_SFT (0x1 << 2) +#define RG_AUDADC1STSTAGELPEN_SFT 3 +#define RG_AUDADC1STSTAGELPEN_MASK 0x1 +#define RG_AUDADC1STSTAGELPEN_MASK_SFT (0x1 << 3) +#define RG_AUDADC2NDSTAGELPEN_SFT 4 +#define RG_AUDADC2NDSTAGELPEN_MASK 0x1 +#define RG_AUDADC2NDSTAGELPEN_MASK_SFT (0x1 << 4) +#define RG_AUDADCFLASHLPEN_SFT 5 +#define RG_AUDADCFLASHLPEN_MASK 0x1 +#define RG_AUDADCFLASHLPEN_MASK_SFT (0x1 << 5) +#define RG_AUDPREAMPIDDTEST_SFT 6 +#define RG_AUDPREAMPIDDTEST_MASK 0x3 +#define RG_AUDPREAMPIDDTEST_MASK_SFT (0x3 << 6) +#define RG_AUDADC1STSTAGEIDDTEST_SFT 8 +#define RG_AUDADC1STSTAGEIDDTEST_MASK 0x3 +#define RG_AUDADC1STSTAGEIDDTEST_MASK_SFT (0x3 << 8) +#define RG_AUDADC2NDSTAGEIDDTEST_SFT 10 +#define RG_AUDADC2NDSTAGEIDDTEST_MASK 0x3 +#define RG_AUDADC2NDSTAGEIDDTEST_MASK_SFT (0x3 << 10) +#define RG_AUDADCREFBUFIDDTEST_SFT 12 +#define RG_AUDADCREFBUFIDDTEST_MASK 0x3 +#define RG_AUDADCREFBUFIDDTEST_MASK_SFT (0x3 << 12) +#define RG_AUDADCFLASHIDDTEST_SFT 14 +#define RG_AUDADCFLASHIDDTEST_MASK 0x3 +#define RG_AUDADCFLASHIDDTEST_MASK_SFT (0x3 << 14) + +/* MT6358_AUDENC_ANA_CON3 */ +#define RG_AUDADCDAC0P25FS_SFT 0 +#define RG_AUDADCDAC0P25FS_MASK 0x1 +#define RG_AUDADCDAC0P25FS_MASK_SFT (0x1 << 0) +#define RG_AUDADCCLKSEL_SFT 1 +#define RG_AUDADCCLKSEL_MASK 0x1 +#define RG_AUDADCCLKSEL_MASK_SFT (0x1 << 1) +#define RG_AUDADCCLKSOURCE_SFT 2 +#define RG_AUDADCCLKSOURCE_MASK 0x3 +#define RG_AUDADCCLKSOURCE_MASK_SFT (0x3 << 2) +#define RG_AUDPREAMPAAFEN_SFT 8 +#define RG_AUDPREAMPAAFEN_MASK 0x1 +#define RG_AUDPREAMPAAFEN_MASK_SFT (0x1 << 8) +#define RG_DCCVCMBUFLPMODSEL_SFT 9 +#define RG_DCCVCMBUFLPMODSEL_MASK 0x1 +#define RG_DCCVCMBUFLPMODSEL_MASK_SFT (0x1 << 9) +#define RG_DCCVCMBUFLPSWEN_SFT 10 +#define RG_DCCVCMBUFLPSWEN_MASK 0x1 +#define RG_DCCVCMBUFLPSWEN_MASK_SFT (0x1 << 10) +#define RG_CMSTBENH_SFT 11 +#define RG_CMSTBENH_MASK 0x1 +#define RG_CMSTBENH_MASK_SFT (0x1 << 11) +#define RG_PGABODYSW_SFT 12 +#define RG_PGABODYSW_MASK 0x1 +#define RG_PGABODYSW_MASK_SFT (0x1 << 12) + +/* MT6358_AUDENC_ANA_CON4 */ +#define RG_AUDADC1STSTAGESDENB_SFT 0 +#define RG_AUDADC1STSTAGESDENB_MASK 0x1 +#define RG_AUDADC1STSTAGESDENB_MASK_SFT (0x1 << 0) +#define RG_AUDADC2NDSTAGERESET_SFT 1 +#define RG_AUDADC2NDSTAGERESET_MASK 0x1 +#define RG_AUDADC2NDSTAGERESET_MASK_SFT (0x1 << 1) +#define RG_AUDADC3RDSTAGERESET_SFT 2 +#define RG_AUDADC3RDSTAGERESET_MASK 0x1 +#define RG_AUDADC3RDSTAGERESET_MASK_SFT (0x1 << 2) +#define RG_AUDADCFSRESET_SFT 3 +#define RG_AUDADCFSRESET_MASK 0x1 +#define RG_AUDADCFSRESET_MASK_SFT (0x1 << 3) +#define RG_AUDADCWIDECM_SFT 4 +#define RG_AUDADCWIDECM_MASK 0x1 +#define RG_AUDADCWIDECM_MASK_SFT (0x1 << 4) +#define RG_AUDADCNOPATEST_SFT 5 +#define RG_AUDADCNOPATEST_MASK 0x1 +#define RG_AUDADCNOPATEST_MASK_SFT (0x1 << 5) +#define RG_AUDADCBYPASS_SFT 6 +#define RG_AUDADCBYPASS_MASK 0x1 +#define RG_AUDADCBYPASS_MASK_SFT (0x1 << 6) +#define RG_AUDADCFFBYPASS_SFT 7 +#define RG_AUDADCFFBYPASS_MASK 0x1 +#define RG_AUDADCFFBYPASS_MASK_SFT (0x1 << 7) +#define RG_AUDADCDACFBCURRENT_SFT 8 +#define RG_AUDADCDACFBCURRENT_MASK 0x1 +#define RG_AUDADCDACFBCURRENT_MASK_SFT (0x1 << 8) +#define RG_AUDADCDACIDDTEST_SFT 9 +#define RG_AUDADCDACIDDTEST_MASK 0x3 +#define RG_AUDADCDACIDDTEST_MASK_SFT (0x3 << 9) +#define RG_AUDADCDACNRZ_SFT 11 +#define RG_AUDADCDACNRZ_MASK 0x1 +#define RG_AUDADCDACNRZ_MASK_SFT (0x1 << 11) +#define RG_AUDADCNODEM_SFT 12 +#define RG_AUDADCNODEM_MASK 0x1 +#define RG_AUDADCNODEM_MASK_SFT (0x1 << 12) +#define RG_AUDADCDACTEST_SFT 13 +#define RG_AUDADCDACTEST_MASK 0x1 +#define RG_AUDADCDACTEST_MASK_SFT (0x1 << 13) + +/* MT6358_AUDENC_ANA_CON5 */ +#define RG_AUDRCTUNEL_SFT 0 +#define RG_AUDRCTUNEL_MASK 0x1f +#define RG_AUDRCTUNEL_MASK_SFT (0x1f << 0) +#define RG_AUDRCTUNELSEL_SFT 5 +#define RG_AUDRCTUNELSEL_MASK 0x1 +#define RG_AUDRCTUNELSEL_MASK_SFT (0x1 << 5) +#define RG_AUDRCTUNER_SFT 8 +#define RG_AUDRCTUNER_MASK 0x1f +#define RG_AUDRCTUNER_MASK_SFT (0x1f << 8) +#define RG_AUDRCTUNERSEL_SFT 13 +#define RG_AUDRCTUNERSEL_MASK 0x1 +#define RG_AUDRCTUNERSEL_MASK_SFT (0x1 << 13) + +/* MT6358_AUDENC_ANA_CON6 */ +#define RG_CLKSQ_EN_SFT 0 +#define RG_CLKSQ_EN_MASK 0x1 +#define RG_CLKSQ_EN_MASK_SFT (0x1 << 0) +#define RG_CLKSQ_IN_SEL_TEST_SFT 1 +#define RG_CLKSQ_IN_SEL_TEST_MASK 0x1 +#define RG_CLKSQ_IN_SEL_TEST_MASK_SFT (0x1 << 1) +#define RG_CM_REFGENSEL_SFT 2 +#define RG_CM_REFGENSEL_MASK 0x1 +#define RG_CM_REFGENSEL_MASK_SFT (0x1 << 2) +#define RG_AUDSPARE_SFT 4 +#define RG_AUDSPARE_MASK 0xf +#define RG_AUDSPARE_MASK_SFT (0xf << 4) +#define RG_AUDENCSPARE_SFT 8 +#define RG_AUDENCSPARE_MASK 0x3f +#define RG_AUDENCSPARE_MASK_SFT (0x3f << 8) + +/* MT6358_AUDENC_ANA_CON7 */ +#define RG_AUDENCSPARE2_SFT 0 +#define RG_AUDENCSPARE2_MASK 0xff +#define RG_AUDENCSPARE2_MASK_SFT (0xff << 0) + +/* MT6358_AUDENC_ANA_CON8 */ +#define RG_AUDDIGMICEN_SFT 0 +#define RG_AUDDIGMICEN_MASK 0x1 +#define RG_AUDDIGMICEN_MASK_SFT (0x1 << 0) +#define RG_AUDDIGMICBIAS_SFT 1 +#define RG_AUDDIGMICBIAS_MASK 0x3 +#define RG_AUDDIGMICBIAS_MASK_SFT (0x3 << 1) +#define RG_DMICHPCLKEN_SFT 3 +#define RG_DMICHPCLKEN_MASK 0x1 +#define RG_DMICHPCLKEN_MASK_SFT (0x1 << 3) +#define RG_AUDDIGMICPDUTY_SFT 4 +#define RG_AUDDIGMICPDUTY_MASK 0x3 +#define RG_AUDDIGMICPDUTY_MASK_SFT (0x3 << 4) +#define RG_AUDDIGMICNDUTY_SFT 6 +#define RG_AUDDIGMICNDUTY_MASK 0x3 +#define RG_AUDDIGMICNDUTY_MASK_SFT (0x3 << 6) +#define RG_DMICMONEN_SFT 8 +#define RG_DMICMONEN_MASK 0x1 +#define RG_DMICMONEN_MASK_SFT (0x1 << 8) +#define RG_DMICMONSEL_SFT 9 +#define RG_DMICMONSEL_MASK 0x7 +#define RG_DMICMONSEL_MASK_SFT (0x7 << 9) +#define RG_AUDSPAREVMIC_SFT 12 +#define RG_AUDSPAREVMIC_MASK 0xf +#define RG_AUDSPAREVMIC_MASK_SFT (0xf << 12) + +/* MT6358_AUDENC_ANA_CON9 */ +#define RG_AUDPWDBMICBIAS0_SFT 0 +#define RG_AUDPWDBMICBIAS0_MASK 0x1 +#define RG_AUDPWDBMICBIAS0_MASK_SFT (0x1 << 0) +#define RG_AUDMICBIAS0BYPASSEN_SFT 1 +#define RG_AUDMICBIAS0BYPASSEN_MASK 0x1 +#define RG_AUDMICBIAS0BYPASSEN_MASK_SFT (0x1 << 1) +#define RG_AUDMICBIAS0LOWPEN_SFT 2 +#define RG_AUDMICBIAS0LOWPEN_MASK 0x1 +#define RG_AUDMICBIAS0LOWPEN_MASK_SFT (0x1 << 2) +#define RG_AUDMICBIAS0VREF_SFT 4 +#define RG_AUDMICBIAS0VREF_MASK 0x7 +#define RG_AUDMICBIAS0VREF_MASK_SFT (0x7 << 4) +#define RG_AUDMICBIAS0DCSW0P1EN_SFT 8 +#define RG_AUDMICBIAS0DCSW0P1EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW0P1EN_MASK_SFT (0x1 << 8) +#define RG_AUDMICBIAS0DCSW0P2EN_SFT 9 +#define RG_AUDMICBIAS0DCSW0P2EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW0P2EN_MASK_SFT (0x1 << 9) +#define RG_AUDMICBIAS0DCSW0NEN_SFT 10 +#define RG_AUDMICBIAS0DCSW0NEN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW0NEN_MASK_SFT (0x1 << 10) +#define RG_AUDMICBIAS0DCSW2P1EN_SFT 12 +#define RG_AUDMICBIAS0DCSW2P1EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW2P1EN_MASK_SFT (0x1 << 12) +#define RG_AUDMICBIAS0DCSW2P2EN_SFT 13 +#define RG_AUDMICBIAS0DCSW2P2EN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW2P2EN_MASK_SFT (0x1 << 13) +#define RG_AUDMICBIAS0DCSW2NEN_SFT 14 +#define RG_AUDMICBIAS0DCSW2NEN_MASK 0x1 +#define RG_AUDMICBIAS0DCSW2NEN_MASK_SFT (0x1 << 14) + +/* MT6358_AUDENC_ANA_CON10 */ +#define RG_AUDPWDBMICBIAS1_SFT 0 +#define RG_AUDPWDBMICBIAS1_MASK 0x1 +#define RG_AUDPWDBMICBIAS1_MASK_SFT (0x1 << 0) +#define RG_AUDMICBIAS1BYPASSEN_SFT 1 +#define RG_AUDMICBIAS1BYPASSEN_MASK 0x1 +#define RG_AUDMICBIAS1BYPASSEN_MASK_SFT (0x1 << 1) +#define RG_AUDMICBIAS1LOWPEN_SFT 2 +#define RG_AUDMICBIAS1LOWPEN_MASK 0x1 +#define RG_AUDMICBIAS1LOWPEN_MASK_SFT (0x1 << 2) +#define RG_AUDMICBIAS1VREF_SFT 4 +#define RG_AUDMICBIAS1VREF_MASK 0x7 +#define RG_AUDMICBIAS1VREF_MASK_SFT (0x7 << 4) +#define RG_AUDMICBIAS1DCSW1PEN_SFT 8 +#define RG_AUDMICBIAS1DCSW1PEN_MASK 0x1 +#define RG_AUDMICBIAS1DCSW1PEN_MASK_SFT (0x1 << 8) +#define RG_AUDMICBIAS1DCSW1NEN_SFT 9 +#define RG_AUDMICBIAS1DCSW1NEN_MASK 0x1 +#define RG_AUDMICBIAS1DCSW1NEN_MASK_SFT (0x1 << 9) +#define RG_BANDGAPGEN_SFT 12 +#define RG_BANDGAPGEN_MASK 0x1 +#define RG_BANDGAPGEN_MASK_SFT (0x1 << 12) +#define RG_MTEST_EN_SFT 13 +#define RG_MTEST_EN_MASK 0x1 +#define RG_MTEST_EN_MASK_SFT (0x1 << 13) +#define RG_MTEST_SEL_SFT 14 +#define RG_MTEST_SEL_MASK 0x1 +#define RG_MTEST_SEL_MASK_SFT (0x1 << 14) +#define RG_MTEST_CURRENT_SFT 15 +#define RG_MTEST_CURRENT_MASK 0x1 +#define RG_MTEST_CURRENT_MASK_SFT (0x1 << 15) + +/* MT6358_AUDENC_ANA_CON11 */ +#define RG_AUDACCDETMICBIAS0PULLLOW_SFT 0 +#define RG_AUDACCDETMICBIAS0PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS0PULLLOW_MASK_SFT (0x1 << 0) +#define RG_AUDACCDETMICBIAS1PULLLOW_SFT 1 +#define RG_AUDACCDETMICBIAS1PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS1PULLLOW_MASK_SFT (0x1 << 1) +#define RG_AUDACCDETVIN1PULLLOW_SFT 2 +#define RG_AUDACCDETVIN1PULLLOW_MASK 0x1 +#define RG_AUDACCDETVIN1PULLLOW_MASK_SFT (0x1 << 2) +#define RG_AUDACCDETVTHACAL_SFT 4 +#define RG_AUDACCDETVTHACAL_MASK 0x1 +#define RG_AUDACCDETVTHACAL_MASK_SFT (0x1 << 4) +#define RG_AUDACCDETVTHBCAL_SFT 5 +#define RG_AUDACCDETVTHBCAL_MASK 0x1 +#define RG_AUDACCDETVTHBCAL_MASK_SFT (0x1 << 5) +#define RG_AUDACCDETTVDET_SFT 6 +#define RG_AUDACCDETTVDET_MASK 0x1 +#define RG_AUDACCDETTVDET_MASK_SFT (0x1 << 6) +#define RG_ACCDETSEL_SFT 7 +#define RG_ACCDETSEL_MASK 0x1 +#define RG_ACCDETSEL_MASK_SFT (0x1 << 7) +#define RG_SWBUFMODSEL_SFT 8 +#define RG_SWBUFMODSEL_MASK 0x1 +#define RG_SWBUFMODSEL_MASK_SFT (0x1 << 8) +#define RG_SWBUFSWEN_SFT 9 +#define RG_SWBUFSWEN_MASK 0x1 +#define RG_SWBUFSWEN_MASK_SFT (0x1 << 9) +#define RG_EINTCOMPVTH_SFT 10 +#define RG_EINTCOMPVTH_MASK 0x1 +#define RG_EINTCOMPVTH_MASK_SFT (0x1 << 10) +#define RG_EINTCONFIGACCDET_SFT 11 +#define RG_EINTCONFIGACCDET_MASK 0x1 +#define RG_EINTCONFIGACCDET_MASK_SFT (0x1 << 11) +#define RG_EINTHIRENB_SFT 12 +#define RG_EINTHIRENB_MASK 0x1 +#define RG_EINTHIRENB_MASK_SFT (0x1 << 12) +#define RG_ACCDET2AUXRESBYPASS_SFT 13 +#define RG_ACCDET2AUXRESBYPASS_MASK 0x1 +#define RG_ACCDET2AUXRESBYPASS_MASK_SFT (0x1 << 13) +#define RG_ACCDET2AUXBUFFERBYPASS_SFT 14 +#define RG_ACCDET2AUXBUFFERBYPASS_MASK 0x1 +#define RG_ACCDET2AUXBUFFERBYPASS_MASK_SFT (0x1 << 14) +#define RG_ACCDET2AUXSWEN_SFT 15 +#define RG_ACCDET2AUXSWEN_MASK 0x1 +#define RG_ACCDET2AUXSWEN_MASK_SFT (0x1 << 15) + +/* MT6358_AUDENC_ANA_CON12 */ +#define RGS_AUDRCTUNELREAD_SFT 0 +#define RGS_AUDRCTUNELREAD_MASK 0x1f +#define RGS_AUDRCTUNELREAD_MASK_SFT (0x1f << 0) +#define RGS_AUDRCTUNERREAD_SFT 8 +#define RGS_AUDRCTUNERREAD_MASK 0x1f +#define RGS_AUDRCTUNERREAD_MASK_SFT (0x1f << 8) + +/* MT6358_AUDDEC_DSN_ID */ +#define AUDDEC_ANA_ID_SFT 0 +#define AUDDEC_ANA_ID_MASK 0xff +#define AUDDEC_ANA_ID_MASK_SFT (0xff << 0) +#define AUDDEC_DIG_ID_SFT 8 +#define AUDDEC_DIG_ID_MASK 0xff +#define AUDDEC_DIG_ID_MASK_SFT (0xff << 8) + +/* MT6358_AUDDEC_DSN_REV0 */ +#define AUDDEC_ANA_MINOR_REV_SFT 0 +#define AUDDEC_ANA_MINOR_REV_MASK 0xf +#define AUDDEC_ANA_MINOR_REV_MASK_SFT (0xf << 0) +#define AUDDEC_ANA_MAJOR_REV_SFT 4 +#define AUDDEC_ANA_MAJOR_REV_MASK 0xf +#define AUDDEC_ANA_MAJOR_REV_MASK_SFT (0xf << 4) +#define AUDDEC_DIG_MINOR_REV_SFT 8 +#define AUDDEC_DIG_MINOR_REV_MASK 0xf +#define AUDDEC_DIG_MINOR_REV_MASK_SFT (0xf << 8) +#define AUDDEC_DIG_MAJOR_REV_SFT 12 +#define AUDDEC_DIG_MAJOR_REV_MASK 0xf +#define AUDDEC_DIG_MAJOR_REV_MASK_SFT (0xf << 12) + +/* MT6358_AUDDEC_DSN_DBI */ +#define AUDDEC_DSN_CBS_SFT 0 +#define AUDDEC_DSN_CBS_MASK 0x3 +#define AUDDEC_DSN_CBS_MASK_SFT (0x3 << 0) +#define AUDDEC_DSN_BIX_SFT 2 +#define AUDDEC_DSN_BIX_MASK 0x3 +#define AUDDEC_DSN_BIX_MASK_SFT (0x3 << 2) +#define AUDDEC_DSN_ESP_SFT 8 +#define AUDDEC_DSN_ESP_MASK 0xff +#define AUDDEC_DSN_ESP_MASK_SFT (0xff << 8) + +/* MT6358_AUDDEC_DSN_FPI */ +#define AUDDEC_DSN_FPI_SFT 0 +#define AUDDEC_DSN_FPI_MASK 0xff +#define AUDDEC_DSN_FPI_MASK_SFT (0xff << 0) + +/* MT6358_AUDDEC_ANA_CON0 */ +#define RG_AUDDACLPWRUP_VAUDP15_SFT 0 +#define RG_AUDDACLPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDDACLPWRUP_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_AUDDACRPWRUP_VAUDP15_SFT 1 +#define RG_AUDDACRPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDDACRPWRUP_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUD_DAC_PWR_UP_VA28_SFT 2 +#define RG_AUD_DAC_PWR_UP_VA28_MASK 0x1 +#define RG_AUD_DAC_PWR_UP_VA28_MASK_SFT (0x1 << 2) +#define RG_AUD_DAC_PWL_UP_VA28_SFT 3 +#define RG_AUD_DAC_PWL_UP_VA28_MASK 0x1 +#define RG_AUD_DAC_PWL_UP_VA28_MASK_SFT (0x1 << 3) +#define RG_AUDHPLPWRUP_VAUDP15_SFT 4 +#define RG_AUDHPLPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPLPWRUP_VAUDP15_MASK_SFT (0x1 << 4) +#define RG_AUDHPRPWRUP_VAUDP15_SFT 5 +#define RG_AUDHPRPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPRPWRUP_VAUDP15_MASK_SFT (0x1 << 5) +#define RG_AUDHPLPWRUP_IBIAS_VAUDP15_SFT 6 +#define RG_AUDHPLPWRUP_IBIAS_VAUDP15_MASK 0x1 +#define RG_AUDHPLPWRUP_IBIAS_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_AUDHPRPWRUP_IBIAS_VAUDP15_SFT 7 +#define RG_AUDHPRPWRUP_IBIAS_VAUDP15_MASK 0x1 +#define RG_AUDHPRPWRUP_IBIAS_VAUDP15_MASK_SFT (0x1 << 7) +#define RG_AUDHPLMUXINPUTSEL_VAUDP15_SFT 8 +#define RG_AUDHPLMUXINPUTSEL_VAUDP15_MASK 0x3 +#define RG_AUDHPLMUXINPUTSEL_VAUDP15_MASK_SFT (0x3 << 8) +#define RG_AUDHPRMUXINPUTSEL_VAUDP15_SFT 10 +#define RG_AUDHPRMUXINPUTSEL_VAUDP15_MASK 0x3 +#define RG_AUDHPRMUXINPUTSEL_VAUDP15_MASK_SFT (0x3 << 10) +#define RG_AUDHPLSCDISABLE_VAUDP15_SFT 12 +#define RG_AUDHPLSCDISABLE_VAUDP15_MASK 0x1 +#define RG_AUDHPLSCDISABLE_VAUDP15_MASK_SFT (0x1 << 12) +#define RG_AUDHPRSCDISABLE_VAUDP15_SFT 13 +#define RG_AUDHPRSCDISABLE_VAUDP15_MASK 0x1 +#define RG_AUDHPRSCDISABLE_VAUDP15_MASK_SFT (0x1 << 13) +#define RG_AUDHPLBSCCURRENT_VAUDP15_SFT 14 +#define RG_AUDHPLBSCCURRENT_VAUDP15_MASK 0x1 +#define RG_AUDHPLBSCCURRENT_VAUDP15_MASK_SFT (0x1 << 14) +#define RG_AUDHPRBSCCURRENT_VAUDP15_SFT 15 +#define RG_AUDHPRBSCCURRENT_VAUDP15_MASK 0x1 +#define RG_AUDHPRBSCCURRENT_VAUDP15_MASK_SFT (0x1 << 15) + +/* MT6358_AUDDEC_ANA_CON1 */ +#define RG_AUDHPLOUTPWRUP_VAUDP15_SFT 0 +#define RG_AUDHPLOUTPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPLOUTPWRUP_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_AUDHPROUTPWRUP_VAUDP15_SFT 1 +#define RG_AUDHPROUTPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPROUTPWRUP_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUDHPLOUTAUXPWRUP_VAUDP15_SFT 2 +#define RG_AUDHPLOUTAUXPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPLOUTAUXPWRUP_VAUDP15_MASK_SFT (0x1 << 2) +#define RG_AUDHPROUTAUXPWRUP_VAUDP15_SFT 3 +#define RG_AUDHPROUTAUXPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHPROUTAUXPWRUP_VAUDP15_MASK_SFT (0x1 << 3) +#define RG_HPLAUXFBRSW_EN_VAUDP15_SFT 4 +#define RG_HPLAUXFBRSW_EN_VAUDP15_MASK 0x1 +#define RG_HPLAUXFBRSW_EN_VAUDP15_MASK_SFT (0x1 << 4) +#define RG_HPRAUXFBRSW_EN_VAUDP15_SFT 5 +#define RG_HPRAUXFBRSW_EN_VAUDP15_MASK 0x1 +#define RG_HPRAUXFBRSW_EN_VAUDP15_MASK_SFT (0x1 << 5) +#define RG_HPLSHORT2HPLAUX_EN_VAUDP15_SFT 6 +#define RG_HPLSHORT2HPLAUX_EN_VAUDP15_MASK 0x1 +#define RG_HPLSHORT2HPLAUX_EN_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_HPRSHORT2HPRAUX_EN_VAUDP15_SFT 7 +#define RG_HPRSHORT2HPRAUX_EN_VAUDP15_MASK 0x1 +#define RG_HPRSHORT2HPRAUX_EN_VAUDP15_MASK_SFT (0x1 << 7) +#define RG_HPLOUTSTGCTRL_VAUDP15_SFT 8 +#define RG_HPLOUTSTGCTRL_VAUDP15_MASK 0x7 +#define RG_HPLOUTSTGCTRL_VAUDP15_MASK_SFT (0x7 << 8) +#define RG_HPROUTSTGCTRL_VAUDP15_SFT 11 +#define RG_HPROUTSTGCTRL_VAUDP15_MASK 0x7 +#define RG_HPROUTSTGCTRL_VAUDP15_MASK_SFT (0x7 << 11) + +/* MT6358_AUDDEC_ANA_CON2 */ +#define RG_HPLOUTPUTSTBENH_VAUDP15_SFT 0 +#define RG_HPLOUTPUTSTBENH_VAUDP15_MASK 0x7 +#define RG_HPLOUTPUTSTBENH_VAUDP15_MASK_SFT (0x7 << 0) +#define RG_HPROUTPUTSTBENH_VAUDP15_SFT 4 +#define RG_HPROUTPUTSTBENH_VAUDP15_MASK 0x7 +#define RG_HPROUTPUTSTBENH_VAUDP15_MASK_SFT (0x7 << 4) +#define RG_AUDHPSTARTUP_VAUDP15_SFT 13 +#define RG_AUDHPSTARTUP_VAUDP15_MASK 0x1 +#define RG_AUDHPSTARTUP_VAUDP15_MASK_SFT (0x1 << 13) +#define RG_AUDREFN_DERES_EN_VAUDP15_SFT 14 +#define RG_AUDREFN_DERES_EN_VAUDP15_MASK 0x1 +#define RG_AUDREFN_DERES_EN_VAUDP15_MASK_SFT (0x1 << 14) +#define RG_HPPSHORT2VCM_VAUDP15_SFT 15 +#define RG_HPPSHORT2VCM_VAUDP15_MASK 0x1 +#define RG_HPPSHORT2VCM_VAUDP15_MASK_SFT (0x1 << 15) + +/* MT6358_AUDDEC_ANA_CON3 */ +#define RG_HPINPUTSTBENH_VAUDP15_SFT 13 +#define RG_HPINPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_HPINPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 13) +#define RG_HPINPUTRESET0_VAUDP15_SFT 14 +#define RG_HPINPUTRESET0_VAUDP15_MASK 0x1 +#define RG_HPINPUTRESET0_VAUDP15_MASK_SFT (0x1 << 14) +#define RG_HPOUTPUTRESET0_VAUDP15_SFT 15 +#define RG_HPOUTPUTRESET0_VAUDP15_MASK 0x1 +#define RG_HPOUTPUTRESET0_VAUDP15_MASK_SFT (0x1 << 15) + +/* MT6358_AUDDEC_ANA_CON4 */ +#define RG_ABIDEC_RSVD0_VAUDP28_SFT 0 +#define RG_ABIDEC_RSVD0_VAUDP28_MASK 0xff +#define RG_ABIDEC_RSVD0_VAUDP28_MASK_SFT (0xff << 0) + +/* MT6358_AUDDEC_ANA_CON5 */ +#define RG_AUDHPDECMGAINADJ_VAUDP15_SFT 0 +#define RG_AUDHPDECMGAINADJ_VAUDP15_MASK 0x7 +#define RG_AUDHPDECMGAINADJ_VAUDP15_MASK_SFT (0x7 << 0) +#define RG_AUDHPDEDMGAINADJ_VAUDP15_SFT 4 +#define RG_AUDHPDEDMGAINADJ_VAUDP15_MASK 0x7 +#define RG_AUDHPDEDMGAINADJ_VAUDP15_MASK_SFT (0x7 << 4) + +/* MT6358_AUDDEC_ANA_CON6 */ +#define RG_AUDHSPWRUP_VAUDP15_SFT 0 +#define RG_AUDHSPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDHSPWRUP_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_AUDHSPWRUP_IBIAS_VAUDP15_SFT 1 +#define RG_AUDHSPWRUP_IBIAS_VAUDP15_MASK 0x1 +#define RG_AUDHSPWRUP_IBIAS_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUDHSMUXINPUTSEL_VAUDP15_SFT 2 +#define RG_AUDHSMUXINPUTSEL_VAUDP15_MASK 0x3 +#define RG_AUDHSMUXINPUTSEL_VAUDP15_MASK_SFT (0x3 << 2) +#define RG_AUDHSSCDISABLE_VAUDP15_SFT 4 +#define RG_AUDHSSCDISABLE_VAUDP15_MASK 0x1 +#define RG_AUDHSSCDISABLE_VAUDP15_MASK_SFT (0x1 << 4) +#define RG_AUDHSBSCCURRENT_VAUDP15_SFT 5 +#define RG_AUDHSBSCCURRENT_VAUDP15_MASK 0x1 +#define RG_AUDHSBSCCURRENT_VAUDP15_MASK_SFT (0x1 << 5) +#define RG_AUDHSSTARTUP_VAUDP15_SFT 6 +#define RG_AUDHSSTARTUP_VAUDP15_MASK 0x1 +#define RG_AUDHSSTARTUP_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_HSOUTPUTSTBENH_VAUDP15_SFT 7 +#define RG_HSOUTPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_HSOUTPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 7) +#define RG_HSINPUTSTBENH_VAUDP15_SFT 8 +#define RG_HSINPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_HSINPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 8) +#define RG_HSINPUTRESET0_VAUDP15_SFT 9 +#define RG_HSINPUTRESET0_VAUDP15_MASK 0x1 +#define RG_HSINPUTRESET0_VAUDP15_MASK_SFT (0x1 << 9) +#define RG_HSOUTPUTRESET0_VAUDP15_SFT 10 +#define RG_HSOUTPUTRESET0_VAUDP15_MASK 0x1 +#define RG_HSOUTPUTRESET0_VAUDP15_MASK_SFT (0x1 << 10) +#define RG_HSOUT_SHORTVCM_VAUDP15_SFT 11 +#define RG_HSOUT_SHORTVCM_VAUDP15_MASK 0x1 +#define RG_HSOUT_SHORTVCM_VAUDP15_MASK_SFT (0x1 << 11) + +/* MT6358_AUDDEC_ANA_CON7 */ +#define RG_AUDLOLPWRUP_VAUDP15_SFT 0 +#define RG_AUDLOLPWRUP_VAUDP15_MASK 0x1 +#define RG_AUDLOLPWRUP_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_AUDLOLPWRUP_IBIAS_VAUDP15_SFT 1 +#define RG_AUDLOLPWRUP_IBIAS_VAUDP15_MASK 0x1 +#define RG_AUDLOLPWRUP_IBIAS_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUDLOLMUXINPUTSEL_VAUDP15_SFT 2 +#define RG_AUDLOLMUXINPUTSEL_VAUDP15_MASK 0x3 +#define RG_AUDLOLMUXINPUTSEL_VAUDP15_MASK_SFT (0x3 << 2) +#define RG_AUDLOLSCDISABLE_VAUDP15_SFT 4 +#define RG_AUDLOLSCDISABLE_VAUDP15_MASK 0x1 +#define RG_AUDLOLSCDISABLE_VAUDP15_MASK_SFT (0x1 << 4) +#define RG_AUDLOLBSCCURRENT_VAUDP15_SFT 5 +#define RG_AUDLOLBSCCURRENT_VAUDP15_MASK 0x1 +#define RG_AUDLOLBSCCURRENT_VAUDP15_MASK_SFT (0x1 << 5) +#define RG_AUDLOSTARTUP_VAUDP15_SFT 6 +#define RG_AUDLOSTARTUP_VAUDP15_MASK 0x1 +#define RG_AUDLOSTARTUP_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_LOINPUTSTBENH_VAUDP15_SFT 7 +#define RG_LOINPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_LOINPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 7) +#define RG_LOOUTPUTSTBENH_VAUDP15_SFT 8 +#define RG_LOOUTPUTSTBENH_VAUDP15_MASK 0x1 +#define RG_LOOUTPUTSTBENH_VAUDP15_MASK_SFT (0x1 << 8) +#define RG_LOINPUTRESET0_VAUDP15_SFT 9 +#define RG_LOINPUTRESET0_VAUDP15_MASK 0x1 +#define RG_LOINPUTRESET0_VAUDP15_MASK_SFT (0x1 << 9) +#define RG_LOOUTPUTRESET0_VAUDP15_SFT 10 +#define RG_LOOUTPUTRESET0_VAUDP15_MASK 0x1 +#define RG_LOOUTPUTRESET0_VAUDP15_MASK_SFT (0x1 << 10) +#define RG_LOOUT_SHORTVCM_VAUDP15_SFT 11 +#define RG_LOOUT_SHORTVCM_VAUDP15_MASK 0x1 +#define RG_LOOUT_SHORTVCM_VAUDP15_MASK_SFT (0x1 << 11) + +/* MT6358_AUDDEC_ANA_CON8 */ +#define RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP15_SFT 0 +#define RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP15_MASK 0xf +#define RG_AUDTRIMBUF_INPUTMUXSEL_VAUDP15_MASK_SFT (0xf << 0) +#define RG_AUDTRIMBUF_GAINSEL_VAUDP15_SFT 4 +#define RG_AUDTRIMBUF_GAINSEL_VAUDP15_MASK 0x3 +#define RG_AUDTRIMBUF_GAINSEL_VAUDP15_MASK_SFT (0x3 << 4) +#define RG_AUDTRIMBUF_EN_VAUDP15_SFT 6 +#define RG_AUDTRIMBUF_EN_VAUDP15_MASK 0x1 +#define RG_AUDTRIMBUF_EN_VAUDP15_MASK_SFT (0x1 << 6) +#define RG_AUDHPSPKDET_INPUTMUXSEL_VAUDP15_SFT 8 +#define RG_AUDHPSPKDET_INPUTMUXSEL_VAUDP15_MASK 0x3 +#define RG_AUDHPSPKDET_INPUTMUXSEL_VAUDP15_MASK_SFT (0x3 << 8) +#define RG_AUDHPSPKDET_OUTPUTMUXSEL_VAUDP15_SFT 10 +#define RG_AUDHPSPKDET_OUTPUTMUXSEL_VAUDP15_MASK 0x3 +#define RG_AUDHPSPKDET_OUTPUTMUXSEL_VAUDP15_MASK_SFT (0x3 << 10) +#define RG_AUDHPSPKDET_EN_VAUDP15_SFT 12 +#define RG_AUDHPSPKDET_EN_VAUDP15_MASK 0x1 +#define RG_AUDHPSPKDET_EN_VAUDP15_MASK_SFT (0x1 << 12) + +/* MT6358_AUDDEC_ANA_CON9 */ +#define RG_ABIDEC_RSVD0_VA28_SFT 0 +#define RG_ABIDEC_RSVD0_VA28_MASK 0xff +#define RG_ABIDEC_RSVD0_VA28_MASK_SFT (0xff << 0) +#define RG_ABIDEC_RSVD0_VAUDP15_SFT 8 +#define RG_ABIDEC_RSVD0_VAUDP15_MASK 0xff +#define RG_ABIDEC_RSVD0_VAUDP15_MASK_SFT (0xff << 8) + +/* MT6358_AUDDEC_ANA_CON10 */ +#define RG_ABIDEC_RSVD1_VAUDP15_SFT 0 +#define RG_ABIDEC_RSVD1_VAUDP15_MASK 0xff +#define RG_ABIDEC_RSVD1_VAUDP15_MASK_SFT (0xff << 0) +#define RG_ABIDEC_RSVD2_VAUDP15_SFT 8 +#define RG_ABIDEC_RSVD2_VAUDP15_MASK 0xff +#define RG_ABIDEC_RSVD2_VAUDP15_MASK_SFT (0xff << 8) + +/* MT6358_AUDDEC_ANA_CON11 */ +#define RG_AUDZCDMUXSEL_VAUDP15_SFT 0 +#define RG_AUDZCDMUXSEL_VAUDP15_MASK 0x7 +#define RG_AUDZCDMUXSEL_VAUDP15_MASK_SFT (0x7 << 0) +#define RG_AUDZCDCLKSEL_VAUDP15_SFT 3 +#define RG_AUDZCDCLKSEL_VAUDP15_MASK 0x1 +#define RG_AUDZCDCLKSEL_VAUDP15_MASK_SFT (0x1 << 3) +#define RG_AUDBIASADJ_0_VAUDP15_SFT 7 +#define RG_AUDBIASADJ_0_VAUDP15_MASK 0x1ff +#define RG_AUDBIASADJ_0_VAUDP15_MASK_SFT (0x1ff << 7) + +/* MT6358_AUDDEC_ANA_CON12 */ +#define RG_AUDBIASADJ_1_VAUDP15_SFT 0 +#define RG_AUDBIASADJ_1_VAUDP15_MASK 0xff +#define RG_AUDBIASADJ_1_VAUDP15_MASK_SFT (0xff << 0) +#define RG_AUDIBIASPWRDN_VAUDP15_SFT 8 +#define RG_AUDIBIASPWRDN_VAUDP15_MASK 0x1 +#define RG_AUDIBIASPWRDN_VAUDP15_MASK_SFT (0x1 << 8) + +/* MT6358_AUDDEC_ANA_CON13 */ +#define RG_RSTB_DECODER_VA28_SFT 0 +#define RG_RSTB_DECODER_VA28_MASK 0x1 +#define RG_RSTB_DECODER_VA28_MASK_SFT (0x1 << 0) +#define RG_SEL_DECODER_96K_VA28_SFT 1 +#define RG_SEL_DECODER_96K_VA28_MASK 0x1 +#define RG_SEL_DECODER_96K_VA28_MASK_SFT (0x1 << 1) +#define RG_SEL_DELAY_VCORE_SFT 2 +#define RG_SEL_DELAY_VCORE_MASK 0x1 +#define RG_SEL_DELAY_VCORE_MASK_SFT (0x1 << 2) +#define RG_AUDGLB_PWRDN_VA28_SFT 4 +#define RG_AUDGLB_PWRDN_VA28_MASK 0x1 +#define RG_AUDGLB_PWRDN_VA28_MASK_SFT (0x1 << 4) +#define RG_RSTB_ENCODER_VA28_SFT 5 +#define RG_RSTB_ENCODER_VA28_MASK 0x1 +#define RG_RSTB_ENCODER_VA28_MASK_SFT (0x1 << 5) +#define RG_SEL_ENCODER_96K_VA28_SFT 6 +#define RG_SEL_ENCODER_96K_VA28_MASK 0x1 +#define RG_SEL_ENCODER_96K_VA28_MASK_SFT (0x1 << 6) + +/* MT6358_AUDDEC_ANA_CON14 */ +#define RG_HCLDO_EN_VA18_SFT 0 +#define RG_HCLDO_EN_VA18_MASK 0x1 +#define RG_HCLDO_EN_VA18_MASK_SFT (0x1 << 0) +#define RG_HCLDO_PDDIS_EN_VA18_SFT 1 +#define RG_HCLDO_PDDIS_EN_VA18_MASK 0x1 +#define RG_HCLDO_PDDIS_EN_VA18_MASK_SFT (0x1 << 1) +#define RG_HCLDO_REMOTE_SENSE_VA18_SFT 2 +#define RG_HCLDO_REMOTE_SENSE_VA18_MASK 0x1 +#define RG_HCLDO_REMOTE_SENSE_VA18_MASK_SFT (0x1 << 2) +#define RG_LCLDO_EN_VA18_SFT 4 +#define RG_LCLDO_EN_VA18_MASK 0x1 +#define RG_LCLDO_EN_VA18_MASK_SFT (0x1 << 4) +#define RG_LCLDO_PDDIS_EN_VA18_SFT 5 +#define RG_LCLDO_PDDIS_EN_VA18_MASK 0x1 +#define RG_LCLDO_PDDIS_EN_VA18_MASK_SFT (0x1 << 5) +#define RG_LCLDO_REMOTE_SENSE_VA18_SFT 6 +#define RG_LCLDO_REMOTE_SENSE_VA18_MASK 0x1 +#define RG_LCLDO_REMOTE_SENSE_VA18_MASK_SFT (0x1 << 6) +#define RG_LCLDO_ENC_EN_VA28_SFT 8 +#define RG_LCLDO_ENC_EN_VA28_MASK 0x1 +#define RG_LCLDO_ENC_EN_VA28_MASK_SFT (0x1 << 8) +#define RG_LCLDO_ENC_PDDIS_EN_VA28_SFT 9 +#define RG_LCLDO_ENC_PDDIS_EN_VA28_MASK 0x1 +#define RG_LCLDO_ENC_PDDIS_EN_VA28_MASK_SFT (0x1 << 9) +#define RG_LCLDO_ENC_REMOTE_SENSE_VA28_SFT 10 +#define RG_LCLDO_ENC_REMOTE_SENSE_VA28_MASK 0x1 +#define RG_LCLDO_ENC_REMOTE_SENSE_VA28_MASK_SFT (0x1 << 10) +#define RG_VA33REFGEN_EN_VA18_SFT 12 +#define RG_VA33REFGEN_EN_VA18_MASK 0x1 +#define RG_VA33REFGEN_EN_VA18_MASK_SFT (0x1 << 12) +#define RG_VA28REFGEN_EN_VA28_SFT 13 +#define RG_VA28REFGEN_EN_VA28_MASK 0x1 +#define RG_VA28REFGEN_EN_VA28_MASK_SFT (0x1 << 13) +#define RG_HCLDO_VOSEL_VA18_SFT 14 +#define RG_HCLDO_VOSEL_VA18_MASK 0x1 +#define RG_HCLDO_VOSEL_VA18_MASK_SFT (0x1 << 14) +#define RG_LCLDO_VOSEL_VA18_SFT 15 +#define RG_LCLDO_VOSEL_VA18_MASK 0x1 +#define RG_LCLDO_VOSEL_VA18_MASK_SFT (0x1 << 15) + +/* MT6358_AUDDEC_ANA_CON15 */ +#define RG_NVREG_EN_VAUDP15_SFT 0 +#define RG_NVREG_EN_VAUDP15_MASK 0x1 +#define RG_NVREG_EN_VAUDP15_MASK_SFT (0x1 << 0) +#define RG_NVREG_PULL0V_VAUDP15_SFT 1 +#define RG_NVREG_PULL0V_VAUDP15_MASK 0x1 +#define RG_NVREG_PULL0V_VAUDP15_MASK_SFT (0x1 << 1) +#define RG_AUDPMU_RSD0_VAUDP15_SFT 4 +#define RG_AUDPMU_RSD0_VAUDP15_MASK 0xf +#define RG_AUDPMU_RSD0_VAUDP15_MASK_SFT (0xf << 4) +#define RG_AUDPMU_RSD0_VA18_SFT 8 +#define RG_AUDPMU_RSD0_VA18_MASK 0xf +#define RG_AUDPMU_RSD0_VA18_MASK_SFT (0xf << 8) +#define RG_AUDPMU_RSD0_VA28_SFT 12 +#define RG_AUDPMU_RSD0_VA28_MASK 0xf +#define RG_AUDPMU_RSD0_VA28_MASK_SFT (0xf << 12) + +/* MT6358_ZCD_CON0 */ +#define RG_AUDZCDENABLE_SFT 0 +#define RG_AUDZCDENABLE_MASK 0x1 +#define RG_AUDZCDENABLE_MASK_SFT (0x1 << 0) +#define RG_AUDZCDGAINSTEPTIME_SFT 1 +#define RG_AUDZCDGAINSTEPTIME_MASK 0x7 +#define RG_AUDZCDGAINSTEPTIME_MASK_SFT (0x7 << 1) +#define RG_AUDZCDGAINSTEPSIZE_SFT 4 +#define RG_AUDZCDGAINSTEPSIZE_MASK 0x3 +#define RG_AUDZCDGAINSTEPSIZE_MASK_SFT (0x3 << 4) +#define RG_AUDZCDTIMEOUTMODESEL_SFT 6 +#define RG_AUDZCDTIMEOUTMODESEL_MASK 0x1 +#define RG_AUDZCDTIMEOUTMODESEL_MASK_SFT (0x1 << 6) + +/* MT6358_ZCD_CON1 */ +#define RG_AUDLOLGAIN_SFT 0 +#define RG_AUDLOLGAIN_MASK 0x1f +#define RG_AUDLOLGAIN_MASK_SFT (0x1f << 0) +#define RG_AUDLORGAIN_SFT 7 +#define RG_AUDLORGAIN_MASK 0x1f +#define RG_AUDLORGAIN_MASK_SFT (0x1f << 7) + +/* MT6358_ZCD_CON2 */ +#define RG_AUDHPLGAIN_SFT 0 +#define RG_AUDHPLGAIN_MASK 0x1f +#define RG_AUDHPLGAIN_MASK_SFT (0x1f << 0) +#define RG_AUDHPRGAIN_SFT 7 +#define RG_AUDHPRGAIN_MASK 0x1f +#define RG_AUDHPRGAIN_MASK_SFT (0x1f << 7) + +/* MT6358_ZCD_CON3 */ +#define RG_AUDHSGAIN_SFT 0 +#define RG_AUDHSGAIN_MASK 0x1f +#define RG_AUDHSGAIN_MASK_SFT (0x1f << 0) + +/* MT6358_ZCD_CON4 */ +#define RG_AUDIVLGAIN_SFT 0 +#define RG_AUDIVLGAIN_MASK 0x7 +#define RG_AUDIVLGAIN_MASK_SFT (0x7 << 0) +#define RG_AUDIVRGAIN_SFT 8 +#define RG_AUDIVRGAIN_MASK 0x7 +#define RG_AUDIVRGAIN_MASK_SFT (0x7 << 8) + +/* MT6358_ZCD_CON5 */ +#define RG_AUDINTGAIN1_SFT 0 +#define RG_AUDINTGAIN1_MASK 0x3f +#define RG_AUDINTGAIN1_MASK_SFT (0x3f << 0) +#define RG_AUDINTGAIN2_SFT 8 +#define RG_AUDINTGAIN2_MASK 0x3f +#define RG_AUDINTGAIN2_MASK_SFT (0x3f << 8) + +/* audio register */ +#define MT6358_DRV_CON3 0x3c +#define MT6358_GPIO_DIR0 0x88 + +#define MT6358_GPIO_MODE2 0xd8 /* mosi */ +#define MT6358_GPIO_MODE2_SET 0xda +#define MT6358_GPIO_MODE2_CLR 0xdc + +#define MT6358_GPIO_MODE3 0xde /* miso */ +#define MT6358_GPIO_MODE3_SET 0xe0 +#define MT6358_GPIO_MODE3_CLR 0xe2 + +#define MT6358_TOP_CKPDN_CON0 0x10c +#define MT6358_TOP_CKPDN_CON0_SET 0x10e +#define MT6358_TOP_CKPDN_CON0_CLR 0x110 + +#define MT6358_TOP_CKHWEN_CON0 0x12a +#define MT6358_TOP_CKHWEN_CON0_SET 0x12c +#define MT6358_TOP_CKHWEN_CON0_CLR 0x12e + +#define MT6358_OTP_CON0 0x38a +#define MT6358_OTP_CON8 0x39a +#define MT6358_OTP_CON11 0x3a0 +#define MT6358_OTP_CON12 0x3a2 +#define MT6358_OTP_CON13 0x3a4 + +#define MT6358_DCXO_CW13 0x7aa +#define MT6358_DCXO_CW14 0x7ac + +#define MT6358_AUXADC_CON10 0x11a0 + +/* audio register */ +#define MT6358_AUD_TOP_ID 0x2200 +#define MT6358_AUD_TOP_REV0 0x2202 +#define MT6358_AUD_TOP_DBI 0x2204 +#define MT6358_AUD_TOP_DXI 0x2206 +#define MT6358_AUD_TOP_CKPDN_TPM0 0x2208 +#define MT6358_AUD_TOP_CKPDN_TPM1 0x220a +#define MT6358_AUD_TOP_CKPDN_CON0 0x220c +#define MT6358_AUD_TOP_CKPDN_CON0_SET 0x220e +#define MT6358_AUD_TOP_CKPDN_CON0_CLR 0x2210 +#define MT6358_AUD_TOP_CKSEL_CON0 0x2212 +#define MT6358_AUD_TOP_CKSEL_CON0_SET 0x2214 +#define MT6358_AUD_TOP_CKSEL_CON0_CLR 0x2216 +#define MT6358_AUD_TOP_CKTST_CON0 0x2218 +#define MT6358_AUD_TOP_CLK_HWEN_CON0 0x221a +#define MT6358_AUD_TOP_CLK_HWEN_CON0_SET 0x221c +#define MT6358_AUD_TOP_CLK_HWEN_CON0_CLR 0x221e +#define MT6358_AUD_TOP_RST_CON0 0x2220 +#define MT6358_AUD_TOP_RST_CON0_SET 0x2222 +#define MT6358_AUD_TOP_RST_CON0_CLR 0x2224 +#define MT6358_AUD_TOP_RST_BANK_CON0 0x2226 +#define MT6358_AUD_TOP_INT_CON0 0x2228 +#define MT6358_AUD_TOP_INT_CON0_SET 0x222a +#define MT6358_AUD_TOP_INT_CON0_CLR 0x222c +#define MT6358_AUD_TOP_INT_MASK_CON0 0x222e +#define MT6358_AUD_TOP_INT_MASK_CON0_SET 0x2230 +#define MT6358_AUD_TOP_INT_MASK_CON0_CLR 0x2232 +#define MT6358_AUD_TOP_INT_STATUS0 0x2234 +#define MT6358_AUD_TOP_INT_RAW_STATUS0 0x2236 +#define MT6358_AUD_TOP_INT_MISC_CON0 0x2238 +#define MT6358_AUDNCP_CLKDIV_CON0 0x223a +#define MT6358_AUDNCP_CLKDIV_CON1 0x223c +#define MT6358_AUDNCP_CLKDIV_CON2 0x223e +#define MT6358_AUDNCP_CLKDIV_CON3 0x2240 +#define MT6358_AUDNCP_CLKDIV_CON4 0x2242 +#define MT6358_AUD_TOP_MON_CON0 0x2244 +#define MT6358_AUDIO_DIG_DSN_ID 0x2280 +#define MT6358_AUDIO_DIG_DSN_REV0 0x2282 +#define MT6358_AUDIO_DIG_DSN_DBI 0x2284 +#define MT6358_AUDIO_DIG_DSN_DXI 0x2286 +#define MT6358_AFE_UL_DL_CON0 0x2288 +#define MT6358_AFE_DL_SRC2_CON0_L 0x228a +#define MT6358_AFE_UL_SRC_CON0_H 0x228c +#define MT6358_AFE_UL_SRC_CON0_L 0x228e +#define MT6358_AFE_TOP_CON0 0x2290 +#define MT6358_AUDIO_TOP_CON0 0x2292 +#define MT6358_AFE_MON_DEBUG0 0x2294 +#define MT6358_AFUNC_AUD_CON0 0x2296 +#define MT6358_AFUNC_AUD_CON1 0x2298 +#define MT6358_AFUNC_AUD_CON2 0x229a +#define MT6358_AFUNC_AUD_CON3 0x229c +#define MT6358_AFUNC_AUD_CON4 0x229e +#define MT6358_AFUNC_AUD_CON5 0x22a0 +#define MT6358_AFUNC_AUD_CON6 0x22a2 +#define MT6358_AFUNC_AUD_MON0 0x22a4 +#define MT6358_AUDRC_TUNE_MON0 0x22a6 +#define MT6358_AFE_ADDA_MTKAIF_FIFO_CFG0 0x22a8 +#define MT6358_AFE_ADDA_MTKAIF_FIFO_LOG_MON1 0x22aa +#define MT6358_AFE_ADDA_MTKAIF_MON0 0x22ac +#define MT6358_AFE_ADDA_MTKAIF_MON1 0x22ae +#define MT6358_AFE_ADDA_MTKAIF_MON2 0x22b0 +#define MT6358_AFE_ADDA_MTKAIF_MON3 0x22b2 +#define MT6358_AFE_ADDA_MTKAIF_CFG0 0x22b4 +#define MT6358_AFE_ADDA_MTKAIF_RX_CFG0 0x22b6 +#define MT6358_AFE_ADDA_MTKAIF_RX_CFG1 0x22b8 +#define MT6358_AFE_ADDA_MTKAIF_RX_CFG2 0x22ba +#define MT6358_AFE_ADDA_MTKAIF_RX_CFG3 0x22bc +#define MT6358_AFE_ADDA_MTKAIF_TX_CFG1 0x22be +#define MT6358_AFE_SGEN_CFG0 0x22c0 +#define MT6358_AFE_SGEN_CFG1 0x22c2 +#define MT6358_AFE_ADC_ASYNC_FIFO_CFG 0x22c4 +#define MT6358_AFE_DCCLK_CFG0 0x22c6 +#define MT6358_AFE_DCCLK_CFG1 0x22c8 +#define MT6358_AUDIO_DIG_CFG 0x22ca +#define MT6358_AFE_AUD_PAD_TOP 0x22cc +#define MT6358_AFE_AUD_PAD_TOP_MON 0x22ce +#define MT6358_AFE_AUD_PAD_TOP_MON1 0x22d0 +#define MT6358_AFE_DL_NLE_CFG 0x22d2 +#define MT6358_AFE_DL_NLE_MON 0x22d4 +#define MT6358_AFE_CG_EN_MON 0x22d6 +#define MT6358_AUDIO_DIG_2ND_DSN_ID 0x2300 +#define MT6358_AUDIO_DIG_2ND_DSN_REV0 0x2302 +#define MT6358_AUDIO_DIG_2ND_DSN_DBI 0x2304 +#define MT6358_AUDIO_DIG_2ND_DSN_DXI 0x2306 +#define MT6358_AFE_PMIC_NEWIF_CFG3 0x2308 +#define MT6358_AFE_VOW_TOP 0x230a +#define MT6358_AFE_VOW_CFG0 0x230c +#define MT6358_AFE_VOW_CFG1 0x230e +#define MT6358_AFE_VOW_CFG2 0x2310 +#define MT6358_AFE_VOW_CFG3 0x2312 +#define MT6358_AFE_VOW_CFG4 0x2314 +#define MT6358_AFE_VOW_CFG5 0x2316 +#define MT6358_AFE_VOW_CFG6 0x2318 +#define MT6358_AFE_VOW_MON0 0x231a +#define MT6358_AFE_VOW_MON1 0x231c +#define MT6358_AFE_VOW_MON2 0x231e +#define MT6358_AFE_VOW_MON3 0x2320 +#define MT6358_AFE_VOW_MON4 0x2322 +#define MT6358_AFE_VOW_MON5 0x2324 +#define MT6358_AFE_VOW_SN_INI_CFG 0x2326 +#define MT6358_AFE_VOW_TGEN_CFG0 0x2328 +#define MT6358_AFE_VOW_POSDIV_CFG0 0x232a +#define MT6358_AFE_VOW_HPF_CFG0 0x232c +#define MT6358_AFE_VOW_PERIODIC_CFG0 0x232e +#define MT6358_AFE_VOW_PERIODIC_CFG1 0x2330 +#define MT6358_AFE_VOW_PERIODIC_CFG2 0x2332 +#define MT6358_AFE_VOW_PERIODIC_CFG3 0x2334 +#define MT6358_AFE_VOW_PERIODIC_CFG4 0x2336 +#define MT6358_AFE_VOW_PERIODIC_CFG5 0x2338 +#define MT6358_AFE_VOW_PERIODIC_CFG6 0x233a +#define MT6358_AFE_VOW_PERIODIC_CFG7 0x233c +#define MT6358_AFE_VOW_PERIODIC_CFG8 0x233e +#define MT6358_AFE_VOW_PERIODIC_CFG9 0x2340 +#define MT6358_AFE_VOW_PERIODIC_CFG10 0x2342 +#define MT6358_AFE_VOW_PERIODIC_CFG11 0x2344 +#define MT6358_AFE_VOW_PERIODIC_CFG12 0x2346 +#define MT6358_AFE_VOW_PERIODIC_CFG13 0x2348 +#define MT6358_AFE_VOW_PERIODIC_CFG14 0x234a +#define MT6358_AFE_VOW_PERIODIC_CFG15 0x234c +#define MT6358_AFE_VOW_PERIODIC_CFG16 0x234e +#define MT6358_AFE_VOW_PERIODIC_CFG17 0x2350 +#define MT6358_AFE_VOW_PERIODIC_CFG18 0x2352 +#define MT6358_AFE_VOW_PERIODIC_CFG19 0x2354 +#define MT6358_AFE_VOW_PERIODIC_CFG20 0x2356 +#define MT6358_AFE_VOW_PERIODIC_CFG21 0x2358 +#define MT6358_AFE_VOW_PERIODIC_CFG22 0x235a +#define MT6358_AFE_VOW_PERIODIC_CFG23 0x235c +#define MT6358_AFE_VOW_PERIODIC_MON0 0x235e +#define MT6358_AFE_VOW_PERIODIC_MON1 0x2360 +#define MT6358_AUDENC_DSN_ID 0x2380 +#define MT6358_AUDENC_DSN_REV0 0x2382 +#define MT6358_AUDENC_DSN_DBI 0x2384 +#define MT6358_AUDENC_DSN_FPI 0x2386 +#define MT6358_AUDENC_ANA_CON0 0x2388 +#define MT6358_AUDENC_ANA_CON1 0x238a +#define MT6358_AUDENC_ANA_CON2 0x238c +#define MT6358_AUDENC_ANA_CON3 0x238e +#define MT6358_AUDENC_ANA_CON4 0x2390 +#define MT6358_AUDENC_ANA_CON5 0x2392 +#define MT6358_AUDENC_ANA_CON6 0x2394 +#define MT6358_AUDENC_ANA_CON7 0x2396 +#define MT6358_AUDENC_ANA_CON8 0x2398 +#define MT6358_AUDENC_ANA_CON9 0x239a +#define MT6358_AUDENC_ANA_CON10 0x239c +#define MT6358_AUDENC_ANA_CON11 0x239e +#define MT6358_AUDENC_ANA_CON12 0x23a0 +#define MT6358_AUDDEC_DSN_ID 0x2400 +#define MT6358_AUDDEC_DSN_REV0 0x2402 +#define MT6358_AUDDEC_DSN_DBI 0x2404 +#define MT6358_AUDDEC_DSN_FPI 0x2406 +#define MT6358_AUDDEC_ANA_CON0 0x2408 +#define MT6358_AUDDEC_ANA_CON1 0x240a +#define MT6358_AUDDEC_ANA_CON2 0x240c +#define MT6358_AUDDEC_ANA_CON3 0x240e +#define MT6358_AUDDEC_ANA_CON4 0x2410 +#define MT6358_AUDDEC_ANA_CON5 0x2412 +#define MT6358_AUDDEC_ANA_CON6 0x2414 +#define MT6358_AUDDEC_ANA_CON7 0x2416 +#define MT6358_AUDDEC_ANA_CON8 0x2418 +#define MT6358_AUDDEC_ANA_CON9 0x241a +#define MT6358_AUDDEC_ANA_CON10 0x241c +#define MT6358_AUDDEC_ANA_CON11 0x241e +#define MT6358_AUDDEC_ANA_CON12 0x2420 +#define MT6358_AUDDEC_ANA_CON13 0x2422 +#define MT6358_AUDDEC_ANA_CON14 0x2424 +#define MT6358_AUDDEC_ANA_CON15 0x2426 +#define MT6358_AUDDEC_ELR_NUM 0x2428 +#define MT6358_AUDDEC_ELR_0 0x242a +#define MT6358_AUDZCD_DSN_ID 0x2480 +#define MT6358_AUDZCD_DSN_REV0 0x2482 +#define MT6358_AUDZCD_DSN_DBI 0x2484 +#define MT6358_AUDZCD_DSN_FPI 0x2486 +#define MT6358_ZCD_CON0 0x2488 +#define MT6358_ZCD_CON1 0x248a +#define MT6358_ZCD_CON2 0x248c +#define MT6358_ZCD_CON3 0x248e +#define MT6358_ZCD_CON4 0x2490 +#define MT6358_ZCD_CON5 0x2492 +#define MT6358_ACCDET_CON13 0x2522 + +#define MT6358_MAX_REGISTER MT6358_ZCD_CON5 + +enum { + MT6358_MTKAIF_PROTOCOL_1 = 0, + MT6358_MTKAIF_PROTOCOL_2, + MT6358_MTKAIF_PROTOCOL_2_CLK_P2, +}; + +/* set only during init */ +int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, + int mtkaif_protocol); +int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt); +int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt); +int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, + int phase_1, int phase_2); +#endif /* __MT6358_H__ */ -- cgit v1.2.3-58-ga151 From 7ca80f232e810b758ba72daef8f189c34a20bd32 Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Tue, 22 Jan 2019 14:39:11 +0800 Subject: ASoC: mediatek: mt6358: add codec document Signed-off-by: Shunli Wang Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/mt6358.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mt6358.txt diff --git a/Documentation/devicetree/bindings/sound/mt6358.txt b/Documentation/devicetree/bindings/sound/mt6358.txt new file mode 100644 index 000000000000..5465730013a1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt6358.txt @@ -0,0 +1,18 @@ +Mediatek MT6358 Audio Codec + +The communication between MT6358 and SoC is through Mediatek PMIC wrapper. +For more detail, please visit Mediatek PMIC wrapper documentation. + +Must be a child node of PMIC wrapper. + +Required properties: + +- compatible : "mediatek,mt6358-sound". +- Avdd-supply : power source of AVDD + +Example: + +mt6358_snd { + compatible = "mediatek,mt6358-sound"; + Avdd-supply = <&mt6358_vaud28_reg>; +}; -- cgit v1.2.3-58-ga151 From f1adceaf01f0446e69c15b32f24ce98e3c3623f1 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 25 Jan 2019 12:19:34 +0100 Subject: x86/kvm/hyper-v: recommend using eVMCS only when it is enabled We shouldn't probably be suggesting using Enlightened VMCS when it's not enabled (not supported from guest's point of view). Hyper-V on KVM seems to be fine either way but let's be consistent. Fixes: 2bc39970e932 ("x86/kvm/hyper-v: Introduce KVM_GET_SUPPORTED_HV_CPUID") Reviewed-by: Liran Alon Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 4840f5b3c88f..4730fcaa70cf 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1850,7 +1850,8 @@ int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, ent->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED; ent->eax |= HV_X64_CLUSTER_IPI_RECOMMENDED; ent->eax |= HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED; - ent->eax |= HV_X64_ENLIGHTENED_VMCS_RECOMMENDED; + if (evmcs_ver) + ent->eax |= HV_X64_ENLIGHTENED_VMCS_RECOMMENDED; /* * Default number of spinlock retry attempts, matches -- cgit v1.2.3-58-ga151 From 1ed199a41c70ad7bfaee8b14f78e791fcf43b278 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 23 Jan 2019 09:22:39 -0800 Subject: KVM: x86: Fix PV IPIs for 32-bit KVM host The recognition of the KVM_HC_SEND_IPI hypercall was unintentionally wrapped in "#ifdef CONFIG_X86_64", causing 32-bit KVM hosts to reject any and all PV IPI requests despite advertising the feature. This results in all KVM paravirtualized guests hanging during SMP boot due to IPIs never being delivered. Fixes: 4180bf1b655a ("KVM: X86: Implement "send IPI" hypercall") Cc: stable@vger.kernel.org Cc: Wanpeng Li Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f14bb806aeed..d21dcad397e4 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -7092,10 +7092,10 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) case KVM_HC_CLOCK_PAIRING: ret = kvm_pv_clock_pairing(vcpu, a0, a1); break; +#endif case KVM_HC_SEND_IPI: ret = kvm_pv_send_ipi(vcpu->kvm, a0, a1, a2, a3, op_64_bit); break; -#endif default: ret = -KVM_ENOSYS; break; -- cgit v1.2.3-58-ga151 From de81c2f912ef57917bdc6d63b410c534c3e07982 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 23 Jan 2019 09:22:40 -0800 Subject: KVM: x86: WARN_ONCE if sending a PV IPI returns a fatal error KVM hypercalls return a negative value error code in case of a fatal error, e.g. when the hypercall isn't supported or was made with invalid parameters. WARN_ONCE on fatal errors when sending PV IPIs as any such error all but guarantees an SMP system will hang due to a missing IPI. Fixes: aaffcfd1e82d ("KVM: X86: Implement PV IPIs in linux guest") Cc: stable@vger.kernel.org Cc: Wanpeng Li Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kernel/kvm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index ba4bfb7f6a36..5c93a65ee1e5 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -457,6 +457,7 @@ static void __send_ipi_mask(const struct cpumask *mask, int vector) #else u64 ipi_bitmap = 0; #endif + long ret; if (cpumask_empty(mask)) return; @@ -482,8 +483,9 @@ static void __send_ipi_mask(const struct cpumask *mask, int vector) } else if (apic_id < min + KVM_IPI_CLUSTER_SIZE) { max = apic_id < max ? max : apic_id; } else { - kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap, + ret = kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap, (unsigned long)(ipi_bitmap >> BITS_PER_LONG), min, icr); + WARN_ONCE(ret < 0, "KVM: failed to send PV IPI: %ld", ret); min = max = apic_id; ipi_bitmap = 0; } @@ -491,8 +493,9 @@ static void __send_ipi_mask(const struct cpumask *mask, int vector) } if (ipi_bitmap) { - kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap, + ret = kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap, (unsigned long)(ipi_bitmap >> BITS_PER_LONG), min, icr); + WARN_ONCE(ret < 0, "KVM: failed to send PV IPI: %ld", ret); } local_irq_restore(flags); -- cgit v1.2.3-58-ga151 From 37ef0c4414c9743ba7f1af4392f0a27a99649f2a Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Tue, 22 Jan 2019 10:24:19 +0000 Subject: svm: Add warning message for AVIC IPI invalid target Print warning message when IPI target ID is invalid due to one of the following reasons: * In logical mode: cluster > max_cluster (64) * In physical mode: target > max_physical (512) * Address is not present in the physical or logical ID tables Signed-off-by: Suravee Suthikulpanit Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index a157ca5b6869..2aff835a65ed 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -4526,6 +4526,8 @@ static int avic_incomplete_ipi_interception(struct vcpu_svm *svm) break; } case AVIC_IPI_FAILURE_INVALID_TARGET: + WARN_ONCE(1, "Invalid IPI target: index=%u, vcpu=%d, icr=%#0x:%#0x\n", + index, svm->vcpu.vcpu_id, icrh, icrl); break; case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE: WARN_ONCE(1, "Invalid backing page\n"); -- cgit v1.2.3-58-ga151 From bb218fbcfaaa3b115d4cd7a43c0ca164f3a96e57 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Tue, 22 Jan 2019 10:25:13 +0000 Subject: svm: Fix AVIC incomplete IPI emulation In case of incomplete IPI with invalid interrupt type, the current SVM driver does not properly emulate the IPI, and fails to boot FreeBSD guests with multiple vcpus when enabling AVIC. Fix this by update APIC ICR high/low registers, which also emulate sending the IPI. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 2aff835a65ed..8a0c9a1f6ac8 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -4504,25 +4504,14 @@ static int avic_incomplete_ipi_interception(struct vcpu_svm *svm) kvm_lapic_reg_write(apic, APIC_ICR, icrl); break; case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING: { - int i; - struct kvm_vcpu *vcpu; - struct kvm *kvm = svm->vcpu.kvm; struct kvm_lapic *apic = svm->vcpu.arch.apic; /* - * At this point, we expect that the AVIC HW has already - * set the appropriate IRR bits on the valid target - * vcpus. So, we just need to kick the appropriate vcpu. + * Update ICR high and low, then emulate sending IPI, + * which is handled when writing APIC_ICR. */ - kvm_for_each_vcpu(i, vcpu, kvm) { - bool m = kvm_apic_match_dest(vcpu, apic, - icrl & KVM_APIC_SHORT_MASK, - GET_APIC_DEST_FIELD(icrh), - icrl & KVM_APIC_DEST_MASK); - - if (m && !avic_vcpu_is_running(vcpu)) - kvm_vcpu_wake_up(vcpu); - } + kvm_lapic_reg_write(apic, APIC_ICR2, icrh); + kvm_lapic_reg_write(apic, APIC_ICR, icrl); break; } case AVIC_IPI_FAILURE_INVALID_TARGET: -- cgit v1.2.3-58-ga151 From 619ad846fc3452adaf71ca246c5aa711e2055398 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 7 Jan 2019 19:44:51 +0100 Subject: KVM: nSVM: clear events pending from svm_complete_interrupts() when exiting to L1 kvm-unit-tests' eventinj "NMI failing on IDT" test results in NMI being delivered to the host (L1) when it's running nested. The problem seems to be: svm_complete_interrupts() raises 'nmi_injected' flag but later we decide to reflect EXIT_NPF to L1. The flag remains pending and we do NMI injection upon entry so it got delivered to L1 instead of L2. It seems that VMX code solves the same issue in prepare_vmcs12(), this was introduced with code refactoring in commit 5f3d5799974b ("KVM: nVMX: Rework event injection and recovery"). Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 8a0c9a1f6ac8..9caf1252c64a 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -3414,6 +3414,14 @@ static int nested_svm_vmexit(struct vcpu_svm *svm) kvm_mmu_reset_context(&svm->vcpu); kvm_mmu_load(&svm->vcpu); + /* + * Drop what we picked up for L2 via svm_complete_interrupts() so it + * doesn't end up in L1. + */ + svm->vcpu.arch.nmi_injected = false; + kvm_clear_exception_queue(&svm->vcpu); + kvm_clear_interrupt_queue(&svm->vcpu); + return 0; } -- cgit v1.2.3-58-ga151 From 8997f657001d1ac5042d368a936987c87251c5ec Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Mon, 21 Jan 2019 15:27:05 +0800 Subject: kvm: vmx: fix some -Wmissing-prototypes warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We get some warnings when building kernel with W=1: arch/x86/kvm/vmx/vmx.c:426:5: warning: no previous prototype for ‘kvm_fill_hv_flush_list_func’ [-Wmissing-prototypes] arch/x86/kvm/vmx/nested.c:58:6: warning: no previous prototype for ‘init_vmcs_shadow_fields’ [-Wmissing-prototypes] Make them static to fix this. Signed-off-by: Yi Wang Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 2 +- arch/x86/kvm/vmx/vmx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index ce8153923854..8ff20523661b 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -55,7 +55,7 @@ static u16 shadow_read_write_fields[] = { static int max_shadow_read_write_fields = ARRAY_SIZE(shadow_read_write_fields); -void init_vmcs_shadow_fields(void) +static void init_vmcs_shadow_fields(void) { int i, j; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 0762fcab8fc9..8be2abbdf63f 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -423,7 +423,7 @@ static void check_ept_pointer_match(struct kvm *kvm) to_kvm_vmx(kvm)->ept_pointers_match = EPT_POINTERS_MATCH; } -int kvm_fill_hv_flush_list_func(struct hv_guest_mapping_flush_list *flush, +static int kvm_fill_hv_flush_list_func(struct hv_guest_mapping_flush_list *flush, void *data) { struct kvm_tlb_range *range = data; -- cgit v1.2.3-58-ga151 From 94a980c39c8e3f8abaff5d3b5bbcd4ccf1c02c4f Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Wed, 16 Jan 2019 09:41:15 -0800 Subject: kvm: selftests: Fix region overlap check in kvm_util Fix a call to userspace_mem_region_find to conform to its spec of taking an inclusive, inclusive range. It was previously being called with an inclusive, exclusive range. Also remove a redundant region bounds check in vm_userspace_mem_region_add. Region overlap checking is already performed by the call to userspace_mem_region_find. Tested: Compiled tools/testing/selftests/kvm with -static Ran all resulting test binaries on an Intel Haswell test machine All tests passed Signed-off-by: Ben Gardon Reviewed-by: Jim Mattson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/kvm_util.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 23022e9d32eb..b52cfdefecbf 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -571,7 +571,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, * already exist. */ region = (struct userspace_mem_region *) userspace_mem_region_find( - vm, guest_paddr, guest_paddr + npages * vm->page_size); + vm, guest_paddr, (guest_paddr + npages * vm->page_size) - 1); if (region != NULL) TEST_ASSERT(false, "overlapping userspace_mem_region already " "exists\n" @@ -587,15 +587,10 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, region = region->next) { if (region->region.slot == slot) break; - if ((guest_paddr <= (region->region.guest_phys_addr - + region->region.memory_size)) - && ((guest_paddr + npages * vm->page_size) - >= region->region.guest_phys_addr)) - break; } if (region != NULL) TEST_ASSERT(false, "A mem region with the requested slot " - "or overlapping physical memory range already exists.\n" + "already exists.\n" " requested slot: %u paddr: 0x%lx npages: 0x%lx\n" " existing slot: %u paddr: 0x%lx size: 0x%lx", slot, guest_paddr, npages, -- cgit v1.2.3-58-ga151 From 5ad6ece869d46c834976ce383ef200f9116881f8 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Jan 2019 17:10:53 -0800 Subject: KVM: VMX: Move vmx_vcpu_run()'s VM-Enter asm blob to a helper function ...along with the function's STACK_FRAME_NON_STANDARD tag. Moving the asm blob results in a significantly smaller amount of code that is marked with STACK_FRAME_NON_STANDARD, which makes it far less likely that gcc will split the function and trigger a spurious objtool warning. As a bonus, removing STACK_FRAME_NON_STANDARD from vmx_vcpu_run() allows the bulk of code to be properly checked by objtool. Because %rbp is not loaded via VMCS fields, vmx_vcpu_run() must manually save/restore the host's RBP and load the guest's RBP prior to calling vmx_vmenter(). Modifying %rbp triggers objtool's stack validation code, and so vmx_vcpu_run() is tagged with STACK_FRAME_NON_STANDARD since it's impossible to avoid modifying %rbp. Unfortunately, vmx_vcpu_run() is also a gigantic function that gcc will split into separate functions, e.g. so that pieces of the function can be inlined. Splitting the function means that the compiled Elf file will contain one or more vmx_vcpu_run.part.* functions in addition to a vmx_vcpu_run function. Depending on where the function is split, objtool may warn about a "call without frame pointer save/setup" in vmx_vcpu_run.part.* since objtool's stack validation looks for exact names when whitelisting functions tagged with STACK_FRAME_NON_STANDARD. Up until recently, the undesirable function splitting was effectively blocked because vmx_vcpu_run() was tagged with __noclone. At the time, __noclone had an unintended side effect that put vmx_vcpu_run() into a separate optimization unit, which in turn prevented gcc from inlining the function (or any of its own function calls) and thus eliminated gcc's motivation to split the function. Removing the __noclone attribute allowed gcc to optimize vmx_vcpu_run(), exposing the objtool warning. Kudos to Qian Cai for root causing that the fnsplit optimization is what caused objtool to complain. Fixes: 453eafbe65f7 ("KVM: VMX: Move VM-Enter + VM-Exit handling to non-inline sub-routines") Tested-by: Qian Cai Cc: Josh Poimboeuf Reported-by: kbuild test robot Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 139 ++++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 66 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 8be2abbdf63f..99c898523c5e 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6362,72 +6362,9 @@ static void vmx_update_hv_timer(struct kvm_vcpu *vcpu) vmx->loaded_vmcs->hv_timer_armed = false; } -static void vmx_vcpu_run(struct kvm_vcpu *vcpu) +static void __vmx_vcpu_run(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx) { - struct vcpu_vmx *vmx = to_vmx(vcpu); - unsigned long cr3, cr4, evmcs_rsp; - - /* Record the guest's net vcpu time for enforced NMI injections. */ - if (unlikely(!enable_vnmi && - vmx->loaded_vmcs->soft_vnmi_blocked)) - vmx->loaded_vmcs->entry_time = ktime_get(); - - /* Don't enter VMX if guest state is invalid, let the exit handler - start emulation until we arrive back to a valid state */ - if (vmx->emulation_required) - return; - - if (vmx->ple_window_dirty) { - vmx->ple_window_dirty = false; - vmcs_write32(PLE_WINDOW, vmx->ple_window); - } - - if (vmx->nested.need_vmcs12_sync) - nested_sync_from_vmcs12(vcpu); - - if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty)) - vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]); - if (test_bit(VCPU_REGS_RIP, (unsigned long *)&vcpu->arch.regs_dirty)) - vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]); - - cr3 = __get_current_cr3_fast(); - if (unlikely(cr3 != vmx->loaded_vmcs->host_state.cr3)) { - vmcs_writel(HOST_CR3, cr3); - vmx->loaded_vmcs->host_state.cr3 = cr3; - } - - cr4 = cr4_read_shadow(); - if (unlikely(cr4 != vmx->loaded_vmcs->host_state.cr4)) { - vmcs_writel(HOST_CR4, cr4); - vmx->loaded_vmcs->host_state.cr4 = cr4; - } - - /* When single-stepping over STI and MOV SS, we must clear the - * corresponding interruptibility bits in the guest state. Otherwise - * vmentry fails as it then expects bit 14 (BS) in pending debug - * exceptions being set, but that's not correct for the guest debugging - * case. */ - if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) - vmx_set_interrupt_shadow(vcpu, 0); - - if (static_cpu_has(X86_FEATURE_PKU) && - kvm_read_cr4_bits(vcpu, X86_CR4_PKE) && - vcpu->arch.pkru != vmx->host_pkru) - __write_pkru(vcpu->arch.pkru); - - pt_guest_enter(vmx); - - atomic_switch_perf_msrs(vmx); - - vmx_update_hv_timer(vcpu); - - /* - * If this vCPU has touched SPEC_CTRL, restore the guest's value if - * it's non-zero. Since vmentry is serialising on affected CPUs, there - * is no need to worry about the conditional branch over the wrmsr - * being speculatively taken. - */ - x86_spec_ctrl_set_guest(vmx->spec_ctrl, 0); + unsigned long evmcs_rsp; vmx->__launched = vmx->loaded_vmcs->launched; @@ -6567,6 +6504,77 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu) , "eax", "ebx", "edi" #endif ); +} +STACK_FRAME_NON_STANDARD(__vmx_vcpu_run); + +static void vmx_vcpu_run(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned long cr3, cr4; + + /* Record the guest's net vcpu time for enforced NMI injections. */ + if (unlikely(!enable_vnmi && + vmx->loaded_vmcs->soft_vnmi_blocked)) + vmx->loaded_vmcs->entry_time = ktime_get(); + + /* Don't enter VMX if guest state is invalid, let the exit handler + start emulation until we arrive back to a valid state */ + if (vmx->emulation_required) + return; + + if (vmx->ple_window_dirty) { + vmx->ple_window_dirty = false; + vmcs_write32(PLE_WINDOW, vmx->ple_window); + } + + if (vmx->nested.need_vmcs12_sync) + nested_sync_from_vmcs12(vcpu); + + if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty)) + vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]); + if (test_bit(VCPU_REGS_RIP, (unsigned long *)&vcpu->arch.regs_dirty)) + vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]); + + cr3 = __get_current_cr3_fast(); + if (unlikely(cr3 != vmx->loaded_vmcs->host_state.cr3)) { + vmcs_writel(HOST_CR3, cr3); + vmx->loaded_vmcs->host_state.cr3 = cr3; + } + + cr4 = cr4_read_shadow(); + if (unlikely(cr4 != vmx->loaded_vmcs->host_state.cr4)) { + vmcs_writel(HOST_CR4, cr4); + vmx->loaded_vmcs->host_state.cr4 = cr4; + } + + /* When single-stepping over STI and MOV SS, we must clear the + * corresponding interruptibility bits in the guest state. Otherwise + * vmentry fails as it then expects bit 14 (BS) in pending debug + * exceptions being set, but that's not correct for the guest debugging + * case. */ + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) + vmx_set_interrupt_shadow(vcpu, 0); + + if (static_cpu_has(X86_FEATURE_PKU) && + kvm_read_cr4_bits(vcpu, X86_CR4_PKE) && + vcpu->arch.pkru != vmx->host_pkru) + __write_pkru(vcpu->arch.pkru); + + pt_guest_enter(vmx); + + atomic_switch_perf_msrs(vmx); + + vmx_update_hv_timer(vcpu); + + /* + * If this vCPU has touched SPEC_CTRL, restore the guest's value if + * it's non-zero. Since vmentry is serialising on affected CPUs, there + * is no need to worry about the conditional branch over the wrmsr + * being speculatively taken. + */ + x86_spec_ctrl_set_guest(vmx->spec_ctrl, 0); + + __vmx_vcpu_run(vcpu, vmx); /* * We do not use IBRS in the kernel. If this vCPU has used the @@ -6648,7 +6656,6 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu) vmx_recover_nmi_blocking(vmx); vmx_complete_interrupts(vmx); } -STACK_FRAME_NON_STANDARD(vmx_vcpu_run); static struct kvm *vmx_vm_alloc(void) { -- cgit v1.2.3-58-ga151 From 3a2f5773baab34a9943be4c77e1ff2ac79d16c75 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 17 Jan 2019 18:12:09 +0100 Subject: x86/kvm/hyper-v: nested_enable_evmcs() sets vmcs_version incorrectly Commit e2e871ab2f02 ("x86/kvm/hyper-v: Introduce nested_get_evmcs_version() helper") broke EVMCS enablement: to set vmcs_version we now call nested_get_evmcs_version() but this function checks enlightened_vmcs_enabled flag which is not yet set so we end up returning zero. Fix the issue by re-arranging things in nested_enable_evmcs(). Fixes: e2e871ab2f02 ("x86/kvm/hyper-v: Introduce nested_get_evmcs_version() helper") Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/evmcs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/vmx/evmcs.c b/arch/x86/kvm/vmx/evmcs.c index 95bc2247478d..5466c6d85cf3 100644 --- a/arch/x86/kvm/vmx/evmcs.c +++ b/arch/x86/kvm/vmx/evmcs.c @@ -332,16 +332,17 @@ int nested_enable_evmcs(struct kvm_vcpu *vcpu, uint16_t *vmcs_version) { struct vcpu_vmx *vmx = to_vmx(vcpu); + bool evmcs_already_enabled = vmx->nested.enlightened_vmcs_enabled; + + vmx->nested.enlightened_vmcs_enabled = true; if (vmcs_version) *vmcs_version = nested_get_evmcs_version(vcpu); /* We don't support disabling the feature for simplicity. */ - if (vmx->nested.enlightened_vmcs_enabled) + if (evmcs_already_enabled) return 0; - vmx->nested.enlightened_vmcs_enabled = true; - vmx->nested.msrs.pinbased_ctls_high &= ~EVMCS1_UNSUPPORTED_PINCTRL; vmx->nested.msrs.entry_ctls_high &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL; vmx->nested.msrs.exit_ctls_high &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL; -- cgit v1.2.3-58-ga151 From 35b531a1e7fc30ac8c62e5ac1794eb1460da614e Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 17 Jan 2019 18:12:10 +0100 Subject: KVM: selftests: check returned evmcs version range Check that KVM_CAP_HYPERV_ENLIGHTENED_VMCS returns correct version range. Signed-off-by: Vitaly Kuznetsov Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/x86_64/evmcs_test.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c index ea3c73e8f4f6..c49c2a28b0eb 100644 --- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -103,6 +103,12 @@ int main(int argc, char *argv[]) vcpu_ioctl(vm, VCPU_ID, KVM_ENABLE_CAP, &enable_evmcs_cap); + /* KVM should return supported EVMCS version range */ + TEST_ASSERT(((evmcs_ver >> 8) >= (evmcs_ver & 0xff)) && + (evmcs_ver & 0xff) > 0, + "Incorrect EVMCS version range: %x:%x\n", + evmcs_ver & 0xff, evmcs_ver >> 8); + run = vcpu_state(vm, VCPU_ID); vcpu_regs_get(vm, VCPU_ID, ®s1); -- cgit v1.2.3-58-ga151 From 5cd5548ff439b916cf72448109994394c2bf4b3c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 25 Jan 2019 16:32:46 +0900 Subject: KVM: x86: fix TRACE_INCLUDE_PATH and remove -I. header search paths The header search path -I. in kernel Makefiles is very suspicious; it allows the compiler to search for headers in the top of $(srctree), where obviously no header file exists. The reason of having -I. here is to make the incorrectly set TRACE_INCLUDE_PATH working. As the comment block in include/trace/define_trace.h says, TRACE_INCLUDE_PATH should be a relative path to the define_trace.h Fix the TRACE_INCLUDE_PATH, and remove the iffy include paths. Signed-off-by: Masahiro Yamada Signed-off-by: Paolo Bonzini --- arch/x86/kvm/Makefile | 4 ---- arch/x86/kvm/trace.h | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index 69b3a7c30013..31ecf7a76d5a 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -2,10 +2,6 @@ ccflags-y += -Iarch/x86/kvm -CFLAGS_x86.o := -I. -CFLAGS_svm.o := -I. -CFLAGS_vmx.o := -I. - KVM := ../../../virt/kvm kvm-y += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o \ diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index 705f40ae2532..6432d08c7de7 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -1465,7 +1465,7 @@ TRACE_EVENT(kvm_hv_send_ipi_ex, #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH arch/x86/kvm +#define TRACE_INCLUDE_PATH ../../arch/x86/kvm #undef TRACE_INCLUDE_FILE #define TRACE_INCLUDE_FILE trace -- cgit v1.2.3-58-ga151 From b2869f28e1476cd705bb28c58fd01b0bd661bb99 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 25 Jan 2019 12:23:17 -0600 Subject: KVM: x86: Mark expected switch fall-throughs In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warnings: arch/x86/kvm/lapic.c:1037:27: warning: this statement may fall through [-Wimplicit-fallthrough=] arch/x86/kvm/lapic.c:1876:3: warning: this statement may fall through [-Wimplicit-fallthrough=] arch/x86/kvm/hyperv.c:1637:6: warning: this statement may fall through [-Wimplicit-fallthrough=] arch/x86/kvm/svm.c:4396:6: warning: this statement may fall through [-Wimplicit-fallthrough=] arch/x86/kvm/mmu.c:4372:36: warning: this statement may fall through [-Wimplicit-fallthrough=] arch/x86/kvm/x86.c:3835:6: warning: this statement may fall through [-Wimplicit-fallthrough=] arch/x86/kvm/x86.c:7938:23: warning: this statement may fall through [-Wimplicit-fallthrough=] arch/x86/kvm/vmx/vmx.c:2015:6: warning: this statement may fall through [-Wimplicit-fallthrough=] arch/x86/kvm/vmx/vmx.c:1773:6: warning: this statement may fall through [-Wimplicit-fallthrough=] Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enabling -Wimplicit-fallthrough. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 2 +- arch/x86/kvm/lapic.c | 2 ++ arch/x86/kvm/mmu.c | 1 + arch/x86/kvm/svm.c | 2 +- arch/x86/kvm/vmx/vmx.c | 4 ++-- arch/x86/kvm/x86.c | 3 +++ 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 4730fcaa70cf..89d20ed1d2e8 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1636,7 +1636,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) ret = kvm_hvcall_signal_event(vcpu, fast, ingpa); if (ret != HV_STATUS_INVALID_PORT_ID) break; - /* maybe userspace knows this conn_id: fall through */ + /* fall through - maybe userspace knows this conn_id. */ case HVCALL_POST_MESSAGE: /* don't bother userspace if it has no way to handle it */ if (unlikely(rep || !vcpu_to_synic(vcpu)->active)) { diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 9f089e2e09d0..4b6c2da7265c 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1035,6 +1035,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, switch (delivery_mode) { case APIC_DM_LOWEST: vcpu->arch.apic_arb_prio++; + /* fall through */ case APIC_DM_FIXED: if (unlikely(trig_mode && !level)) break; @@ -1874,6 +1875,7 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_LVT0: apic_manage_nmi_watchdog(apic, val); + /* fall through */ case APIC_LVTTHMR: case APIC_LVTPC: case APIC_LVT1: diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index ce770b446238..da9c42349b1f 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -4371,6 +4371,7 @@ __reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, rsvd_bits(maxphyaddr, 51); rsvd_check->rsvd_bits_mask[1][4] = rsvd_check->rsvd_bits_mask[0][4]; + /* fall through */ case PT64_ROOT_4LEVEL: rsvd_check->rsvd_bits_mask[0][3] = exb_bit_rsvd | nonleaf_bit8_rsvd | rsvd_bits(7, 7) | diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 9caf1252c64a..f13a3a24d360 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -4403,7 +4403,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) case MSR_IA32_APICBASE: if (kvm_vcpu_apicv_active(vcpu)) avic_update_vapic_bar(to_svm(vcpu), data); - /* Follow through */ + /* Fall through */ default: return kvm_set_msr_common(vcpu, msr); } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 99c898523c5e..4341175339f3 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1773,7 +1773,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (!msr_info->host_initiated && !guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP)) return 1; - /* Otherwise falls through */ + /* Else, falls through */ default: msr = find_msr_entry(vmx, msr_info->index); if (msr) { @@ -2014,7 +2014,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) /* Check reserved bit, higher 32 bits should be zero */ if ((data >> 32) != 0) return 1; - /* Otherwise falls through */ + /* Else, falls through */ default: msr = find_msr_entry(vmx, msr_index); if (msr) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d21dcad397e4..3d27206f6c01 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3834,6 +3834,8 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, case KVM_CAP_HYPERV_SYNIC2: if (cap->args[0]) return -EINVAL; + /* fall through */ + case KVM_CAP_HYPERV_SYNIC: if (!irqchip_in_kernel(vcpu->kvm)) return -EINVAL; @@ -7936,6 +7938,7 @@ static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu) vcpu->arch.pv.pv_unhalted = false; vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; + /* fall through */ case KVM_MP_STATE_RUNNABLE: vcpu->arch.apf.halted = false; break; -- cgit v1.2.3-58-ga151 From abfd04f738c2625f63e04c8fc7cadb3b7a70d580 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 25 Jan 2019 15:32:28 -0800 Subject: qed: Revert error handling changes. This is new code and not bug fixes. This reverts all changes added by merge commit 8fb18be93efd7292d6ee403b9f61af1008239639 Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed.h | 5 +- drivers/net/ethernet/qlogic/qed/qed_dev.c | 158 ++++++------- drivers/net/ethernet/qlogic/qed/qed_dev_api.h | 12 - drivers/net/ethernet/qlogic/qed/qed_hsi.h | 2 +- drivers/net/ethernet/qlogic/qed/qed_hw.c | 11 - drivers/net/ethernet/qlogic/qed/qed_int.c | 126 +++++------ drivers/net/ethernet/qlogic/qed/qed_int.h | 3 - drivers/net/ethernet/qlogic/qed/qed_main.c | 30 --- drivers/net/ethernet/qlogic/qed/qed_mcp.c | 115 ---------- drivers/net/ethernet/qlogic/qed/qed_mcp.h | 42 ---- drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 2 - drivers/net/ethernet/qlogic/qed/qed_spq.c | 22 -- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 9 +- drivers/net/ethernet/qlogic/qede/qede.h | 3 - drivers/net/ethernet/qlogic/qede/qede_main.c | 300 +++++-------------------- drivers/net/ethernet/qlogic/qede/qede_rdma.c | 64 ++---- include/linux/qed/qed_if.h | 20 -- include/linux/qed/qede_rdma.h | 21 +- 18 files changed, 202 insertions(+), 743 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h index 3b0955d34716..24a90163775e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed.h +++ b/drivers/net/ethernet/qlogic/qed/qed.h @@ -554,6 +554,7 @@ struct qed_hwfn { u8 dp_level; char name[NAME_SIZE]; + bool first_on_engine; bool hw_init_done; u8 num_funcs_on_engine; @@ -804,9 +805,6 @@ struct qed_dev { u32 mcp_nvm_resp; - /* Recovery */ - bool recov_in_prog; - /* Linux specific here */ struct qede_dev *edev; struct pci_dev *pdev; @@ -946,7 +944,6 @@ void qed_link_update(struct qed_hwfn *hwfn, struct qed_ptt *ptt); u32 qed_unzip_data(struct qed_hwfn *p_hwfn, u32 input_len, u8 *input_buf, u32 max_size, u8 *unzip_buf); -void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn); void qed_get_protocol_stats(struct qed_dev *cdev, enum qed_mcp_protocol_type type, union qed_mcp_protocol_stats *stats); diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index b17003d9066c..8f6551421945 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1959,6 +1959,11 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, (p_hwfn->hw_info.personality == QED_PCI_FCOE) ? 1 : 0); STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0); + /* Cleanup chip from previous driver if such remains exist */ + rc = qed_final_cleanup(p_hwfn, p_ptt, rel_pf_id, false); + if (rc) + return rc; + /* Sanity check before the PF init sequence that uses DMAE */ rc = qed_dmae_sanity(p_hwfn, p_ptt, "pf_phase"); if (rc) @@ -2002,15 +2007,17 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn, return rc; } -int qed_pglueb_set_pfid_enable(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, bool b_enable) +static int qed_change_pci_hwfn(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt, + u8 enable) { - u32 delay_idx = 0, val, set_val = b_enable ? 1 : 0; + u32 delay_idx = 0, val, set_val = enable ? 1 : 0; - /* Configure the PF's internal FID_enable for master transactions */ - qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val); + /* Change PF in PXP */ + qed_wr(p_hwfn, p_ptt, + PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val); - /* Wait until value is set - try for 1 second every 50us */ + /* wait until value is set - try for 1 second every 50us */ for (delay_idx = 0; delay_idx < 20000; delay_idx++) { val = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER); @@ -2064,19 +2071,13 @@ static int qed_vf_start(struct qed_hwfn *p_hwfn, return 0; } -static void qed_pglueb_clear_err(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) -{ - qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR, - BIT(p_hwfn->abs_pf_id)); -} - int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) { struct qed_load_req_params load_req_params; u32 load_code, resp, param, drv_mb_param; bool b_default_mtu = true; struct qed_hwfn *p_hwfn; - int rc = 0, i; + int rc = 0, mfw_rc, i; u16 ether_type; if ((p_params->int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) { @@ -2091,7 +2092,7 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) } for_each_hwfn(cdev, i) { - p_hwfn = &cdev->hwfns[i]; + struct qed_hwfn *p_hwfn = &cdev->hwfns[i]; /* If management didn't provide a default, set one of our own */ if (!p_hwfn->hw_info.mtu) { @@ -2104,6 +2105,9 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) continue; } + /* Enable DMAE in PXP */ + rc = qed_change_pci_hwfn(p_hwfn, p_hwfn->p_main_ptt, true); + rc = qed_calc_hw_mode(p_hwfn); if (rc) return rc; @@ -2140,43 +2144,12 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) "Load request was sent. Load code: 0x%x\n", load_code); - /* Only relevant for recovery: - * Clear the indication after LOAD_REQ is responded by the MFW. - */ - cdev->recov_in_prog = false; - qed_mcp_set_capabilities(p_hwfn, p_hwfn->p_main_ptt); qed_reset_mb_shadow(p_hwfn, p_hwfn->p_main_ptt); - /* Clean up chip from previous driver if such remains exist. - * This is not needed when the PF is the first one on the - * engine, since afterwards we are going to init the FW. - */ - if (load_code != FW_MSG_CODE_DRV_LOAD_ENGINE) { - rc = qed_final_cleanup(p_hwfn, p_hwfn->p_main_ptt, - p_hwfn->rel_pf_id, false); - if (rc) { - DP_NOTICE(p_hwfn, "Final cleanup failed\n"); - goto load_err; - } - } - - /* Log and clear previous pglue_b errors if such exist */ - qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_main_ptt); - - /* Enable the PF's internal FID_enable in the PXP */ - rc = qed_pglueb_set_pfid_enable(p_hwfn, p_hwfn->p_main_ptt, - true); - if (rc) - goto load_err; - - /* Clear the pglue_b was_error indication. - * In E4 it must be done after the BME and the internal - * FID_enable for the PF are set, since VDMs may cause the - * indication to be set again. - */ - qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt); + p_hwfn->first_on_engine = (load_code == + FW_MSG_CODE_DRV_LOAD_ENGINE); switch (load_code) { case FW_MSG_CODE_DRV_LOAD_ENGINE: @@ -2207,29 +2180,39 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) break; } - if (rc) { + if (rc) DP_NOTICE(p_hwfn, "init phase failed for loadcode 0x%x (rc %d)\n", - load_code, rc); - goto load_err; - } + load_code, rc); - rc = qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt); + /* ACK mfw regardless of success or failure of initialization */ + mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, + DRV_MSG_CODE_LOAD_DONE, + 0, &load_code, ¶m); if (rc) return rc; + if (mfw_rc) { + DP_NOTICE(p_hwfn, "Failed sending LOAD_DONE command\n"); + return mfw_rc; + } + + /* Check if there is a DID mismatch between nvm-cfg/efuse */ + if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) + DP_NOTICE(p_hwfn, + "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); /* send DCBX attention request command */ DP_VERBOSE(p_hwfn, QED_MSG_DCB, "sending phony dcbx set command to trigger DCBx attention handling\n"); - rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, - DRV_MSG_CODE_SET_DCBX, - 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT, - &resp, ¶m); - if (rc) { + mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt, + DRV_MSG_CODE_SET_DCBX, + 1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT, + &load_code, ¶m); + if (mfw_rc) { DP_NOTICE(p_hwfn, "Failed to send DCBX attention request\n"); - return rc; + return mfw_rc; } p_hwfn->hw_init_done = true; @@ -2278,12 +2261,6 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) } return 0; - -load_err: - /* The MFW load lock should be released also when initialization fails. - */ - qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt); - return rc; } #define QED_HW_STOP_RETRY_LIMIT (10) @@ -2296,9 +2273,6 @@ static void qed_hw_timers_stop(struct qed_dev *cdev, qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0); qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0); - if (cdev->recov_in_prog) - return; - for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) { if ((!qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_CONN)) && @@ -2361,14 +2335,12 @@ int qed_hw_stop(struct qed_dev *cdev) p_hwfn->hw_init_done = false; /* Send unload command to MCP */ - if (!cdev->recov_in_prog) { - rc = qed_mcp_unload_req(p_hwfn, p_ptt); - if (rc) { - DP_NOTICE(p_hwfn, - "Failed sending a UNLOAD_REQ command. rc = %d.\n", - rc); - rc2 = -EINVAL; - } + rc = qed_mcp_unload_req(p_hwfn, p_ptt); + if (rc) { + DP_NOTICE(p_hwfn, + "Failed sending a UNLOAD_REQ command. rc = %d.\n", + rc); + rc2 = -EINVAL; } qed_slowpath_irq_sync(p_hwfn); @@ -2410,31 +2382,27 @@ int qed_hw_stop(struct qed_dev *cdev) qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_DB_ENABLE, 0); qed_wr(p_hwfn, p_ptt, QM_REG_PF_EN, 0); - if (!cdev->recov_in_prog) { - rc = qed_mcp_unload_done(p_hwfn, p_ptt); - if (rc) { - DP_NOTICE(p_hwfn, - "Failed sending a UNLOAD_DONE command. rc = %d.\n", - rc); - rc2 = -EINVAL; - } + qed_mcp_unload_done(p_hwfn, p_ptt); + if (rc) { + DP_NOTICE(p_hwfn, + "Failed sending a UNLOAD_DONE command. rc = %d.\n", + rc); + rc2 = -EINVAL; } } - if (IS_PF(cdev) && !cdev->recov_in_prog) { + if (IS_PF(cdev)) { p_hwfn = QED_LEADING_HWFN(cdev); p_ptt = QED_LEADING_HWFN(cdev)->p_main_ptt; - /* Clear the PF's internal FID_enable in the PXP. - * In CMT this should only be done for first hw-function, and - * only after all transactions have stopped for all active - * hw-functions. + /* Disable DMAE in PXP - in CMT, this should only be done for + * first hw-function, and only after all transactions have + * stopped for all active hw-functions. */ - rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); + rc = qed_change_pci_hwfn(p_hwfn, p_ptt, false); if (rc) { DP_NOTICE(p_hwfn, - "qed_pglueb_set_pfid_enable() failed. rc = %d.\n", - rc); + "qed_change_pci_hwfn failed. rc = %d.\n", rc); rc2 = -EINVAL; } } @@ -2534,8 +2502,9 @@ static void qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn) PGLUE_B_REG_PGL_ADDR_94_F0_BB, 0); } - /* Clean previous pglue_b errors if such exist */ - qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt); + /* Clean Previous errors if such exist */ + qed_wr(p_hwfn, p_hwfn->p_main_ptt, + PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR, 1 << p_hwfn->abs_pf_id); /* enable internal target-read */ qed_wr(p_hwfn, p_hwfn->p_main_ptt, @@ -3471,7 +3440,6 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn, void __iomem *p_doorbells, enum qed_pci_personality personality) { - struct qed_dev *cdev = p_hwfn->cdev; int rc = 0; /* Split PCI bars evenly between hwfns */ @@ -3524,7 +3492,7 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn, /* Sending a mailbox to the MFW should be done after qed_get_hw_info() * is called as it sets the ports number in an engine. */ - if (IS_LEAD_HWFN(p_hwfn) && !cdev->recov_in_prog) { + if (IS_LEAD_HWFN(p_hwfn)) { rc = qed_mcp_initiate_pf_flr(p_hwfn, p_hwfn->p_main_ptt); if (rc) DP_NOTICE(p_hwfn, "Failed to initiate PF FLR\n"); diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h index e4b4e3b78e8a..acccd85170aa 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h +++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h @@ -472,18 +472,6 @@ int qed_get_queue_coalesce(struct qed_hwfn *p_hwfn, u16 *coal, void *handle); int qed_set_queue_coalesce(u16 rx_coal, u16 tx_coal, void *p_handle); -/** - * @brief qed_pglueb_set_pfid_enable - Enable or disable PCI BUS MASTER - * - * @param p_hwfn - * @param p_ptt - * @param b_enable - true/false - * - * @return int - */ -int qed_pglueb_set_pfid_enable(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, bool b_enable); - /** * @brief db_recovery_add - add doorbell information to the doorbell * recovery mechanism. diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h index 417121e74ee9..b13cfb449d8f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h @@ -12827,7 +12827,7 @@ enum MFW_DRV_MSG_TYPE { MFW_DRV_MSG_LLDP_DATA_UPDATED, MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED, MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED, - MFW_DRV_MSG_ERROR_RECOVERY, + MFW_DRV_MSG_RESERVED4, MFW_DRV_MSG_BW_UPDATE, MFW_DRV_MSG_S_TAG_UPDATE, MFW_DRV_MSG_GET_LAN_STATS, diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c index 72ec1c6bdf70..70504dcf4087 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hw.c +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c @@ -703,17 +703,6 @@ static int qed_dmae_execute_command(struct qed_hwfn *p_hwfn, int qed_status = 0; u32 offset = 0; - if (p_hwfn->cdev->recov_in_prog) { - DP_VERBOSE(p_hwfn, - NETIF_MSG_HW, - "Recovery is in progress. Avoid DMAE transaction [{src: addr 0x%llx, type %d}, {dst: addr 0x%llx, type %d}, size %d].\n", - src_addr, src_type, dst_addr, dst_type, - size_in_dwords); - - /* Let the flow complete w/o any error handling */ - return 0; - } - qed_dmae_opcode(p_hwfn, (src_type == QED_DMAE_ADDRESS_GRC), (dst_type == QED_DMAE_ADDRESS_GRC), diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index e23980e301b6..92340919d852 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -255,114 +255,112 @@ out: #define PGLUE_ATTENTION_ICPL_VALID (1 << 23) #define PGLUE_ATTENTION_ZLR_VALID (1 << 25) #define PGLUE_ATTENTION_ILT_VALID (1 << 23) - -int qed_pglueb_rbc_attn_handler(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt) +static int qed_pglub_rbc_attn_cb(struct qed_hwfn *p_hwfn) { u32 tmp; - tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_DETAILS2); + tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + PGLUE_B_REG_TX_ERR_WR_DETAILS2); if (tmp & PGLUE_ATTENTION_VALID) { u32 addr_lo, addr_hi, details; - addr_lo = qed_rd(p_hwfn, p_ptt, + addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_TX_ERR_WR_ADD_31_0); - addr_hi = qed_rd(p_hwfn, p_ptt, + addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_TX_ERR_WR_ADD_63_32); - details = qed_rd(p_hwfn, p_ptt, + details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_TX_ERR_WR_DETAILS); - DP_NOTICE(p_hwfn, - "Illegal write by chip to [%08x:%08x] blocked.\n" - "Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n" - "Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n", - addr_hi, addr_lo, details, - (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID), - (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID), - GET_FIELD(details, - PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0, - tmp, - GET_FIELD(tmp, - PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 : 0, - GET_FIELD(tmp, - PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0, - GET_FIELD(tmp, - PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 : 0); + DP_INFO(p_hwfn, + "Illegal write by chip to [%08x:%08x] blocked.\n" + "Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n" + "Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n", + addr_hi, addr_lo, details, + (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID), + (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID), + GET_FIELD(details, + PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0, + tmp, + GET_FIELD(tmp, + PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 : 0, + GET_FIELD(tmp, + PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0, + GET_FIELD(tmp, + PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 : 0); } - tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_RD_DETAILS2); + tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + PGLUE_B_REG_TX_ERR_RD_DETAILS2); if (tmp & PGLUE_ATTENTION_RD_VALID) { u32 addr_lo, addr_hi, details; - addr_lo = qed_rd(p_hwfn, p_ptt, + addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_TX_ERR_RD_ADD_31_0); - addr_hi = qed_rd(p_hwfn, p_ptt, + addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_TX_ERR_RD_ADD_63_32); - details = qed_rd(p_hwfn, p_ptt, + details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_TX_ERR_RD_DETAILS); - DP_NOTICE(p_hwfn, - "Illegal read by chip from [%08x:%08x] blocked.\n" - "Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n" - "Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n", - addr_hi, addr_lo, details, - (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID), - (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID), - GET_FIELD(details, - PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0, - tmp, - GET_FIELD(tmp, - PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 : 0, - GET_FIELD(tmp, - PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0, - GET_FIELD(tmp, - PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 : 0); + DP_INFO(p_hwfn, + "Illegal read by chip from [%08x:%08x] blocked.\n" + " Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n" + " Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n", + addr_hi, addr_lo, details, + (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID), + (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID), + GET_FIELD(details, + PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0, + tmp, + GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 + : 0, + GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0, + GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 + : 0); } - tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_TX_ERR_WR_DETAILS_ICPL); + tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + PGLUE_B_REG_TX_ERR_WR_DETAILS_ICPL); if (tmp & PGLUE_ATTENTION_ICPL_VALID) - DP_NOTICE(p_hwfn, "ICPL error - %08x\n", tmp); + DP_INFO(p_hwfn, "ICPL error - %08x\n", tmp); - tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_MASTER_ZLR_ERR_DETAILS); + tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + PGLUE_B_REG_MASTER_ZLR_ERR_DETAILS); if (tmp & PGLUE_ATTENTION_ZLR_VALID) { u32 addr_hi, addr_lo; - addr_lo = qed_rd(p_hwfn, p_ptt, + addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_MASTER_ZLR_ERR_ADD_31_0); - addr_hi = qed_rd(p_hwfn, p_ptt, + addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_MASTER_ZLR_ERR_ADD_63_32); - DP_NOTICE(p_hwfn, "ZLR error - %08x [Address %08x:%08x]\n", - tmp, addr_hi, addr_lo); + DP_INFO(p_hwfn, "ZLR eror - %08x [Address %08x:%08x]\n", + tmp, addr_hi, addr_lo); } - tmp = qed_rd(p_hwfn, p_ptt, PGLUE_B_REG_VF_ILT_ERR_DETAILS2); + tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, + PGLUE_B_REG_VF_ILT_ERR_DETAILS2); if (tmp & PGLUE_ATTENTION_ILT_VALID) { u32 addr_hi, addr_lo, details; - addr_lo = qed_rd(p_hwfn, p_ptt, + addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_VF_ILT_ERR_ADD_31_0); - addr_hi = qed_rd(p_hwfn, p_ptt, + addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_VF_ILT_ERR_ADD_63_32); - details = qed_rd(p_hwfn, p_ptt, + details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, PGLUE_B_REG_VF_ILT_ERR_DETAILS); - DP_NOTICE(p_hwfn, - "ILT error - Details %08x Details2 %08x [Address %08x:%08x]\n", - details, tmp, addr_hi, addr_lo); + DP_INFO(p_hwfn, + "ILT error - Details %08x Details2 %08x [Address %08x:%08x]\n", + details, tmp, addr_hi, addr_lo); } /* Clear the indications */ - qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_LATCHED_ERRORS_CLR, BIT(2)); + qed_wr(p_hwfn, p_hwfn->p_dpc_ptt, + PGLUE_B_REG_LATCHED_ERRORS_CLR, (1 << 2)); return 0; } -static int qed_pglueb_rbc_attn_cb(struct qed_hwfn *p_hwfn) -{ - return qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_dpc_ptt); -} - #define QED_DORQ_ATTENTION_REASON_MASK (0xfffff) #define QED_DORQ_ATTENTION_OPAQUE_MASK (0xffff) #define QED_DORQ_ATTENTION_OPAQUE_SHIFT (0x0) @@ -542,7 +540,7 @@ static struct aeu_invert_reg aeu_descs[NUM_ATTN_REGS] = { {"PGLUE misc_flr", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID}, {"PGLUE B RBC", ATTENTION_PAR_INT, - qed_pglueb_rbc_attn_cb, BLOCK_PGLUE_B}, + qed_pglub_rbc_attn_cb, BLOCK_PGLUE_B}, {"PGLUE misc_mctp", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID}, {"Flash event", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID}, diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index 1f356ed4f761..d81a62ebd524 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -431,7 +431,4 @@ int qed_int_set_timer_res(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, #define QED_MAPPING_MEMORY_SIZE(dev) (NUM_OF_SBS(dev)) -int qed_pglueb_rbc_attn_handler(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt); - #endif diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index b47352643fb5..6adf5bda9811 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -359,8 +359,6 @@ static struct qed_dev *qed_probe(struct pci_dev *pdev, qed_init_dp(cdev, params->dp_module, params->dp_level); - cdev->recov_in_prog = params->recov_in_prog; - rc = qed_init_pci(cdev, pdev); if (rc) { DP_ERR(cdev, "init pci failed\n"); @@ -2205,15 +2203,6 @@ static int qed_nvm_get_image(struct qed_dev *cdev, enum qed_nvm_images type, return qed_mcp_get_nvm_image(hwfn, type, buf, len); } -void qed_schedule_recovery_handler(struct qed_hwfn *p_hwfn) -{ - struct qed_common_cb_ops *ops = p_hwfn->cdev->protocol_ops.common; - void *cookie = p_hwfn->cdev->ops_cookie; - - if (ops && ops->schedule_recovery_handler) - ops->schedule_recovery_handler(cookie); -} - static int qed_set_coalesce(struct qed_dev *cdev, u16 rx_coal, u16 tx_coal, void *handle) { @@ -2237,23 +2226,6 @@ static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode) return status; } -static int qed_recovery_process(struct qed_dev *cdev) -{ - struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); - struct qed_ptt *p_ptt; - int rc = 0; - - p_ptt = qed_ptt_acquire(p_hwfn); - if (!p_ptt) - return -EAGAIN; - - rc = qed_start_recovery_process(p_hwfn, p_ptt); - - qed_ptt_release(p_hwfn, p_ptt); - - return rc; -} - static int qed_update_wol(struct qed_dev *cdev, bool enabled) { struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); @@ -2408,8 +2380,6 @@ const struct qed_common_ops qed_common_ops_pass = { .nvm_get_image = &qed_nvm_get_image, .set_coalesce = &qed_set_coalesce, .set_led = &qed_set_led, - .recovery_process = &qed_recovery_process, - .recovery_prolog = &qed_recovery_prolog, .update_drv_state = &qed_update_drv_state, .update_mac = &qed_update_mac, .update_mtu = &qed_update_mtu, diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index bb8541847aa5..e7f18e34ff0d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -1070,27 +1070,6 @@ int qed_mcp_load_req(struct qed_hwfn *p_hwfn, return 0; } -int qed_mcp_load_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) -{ - u32 resp = 0, param = 0; - int rc; - - rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_LOAD_DONE, 0, &resp, - ¶m); - if (rc) { - DP_NOTICE(p_hwfn, - "Failed to send a LOAD_DONE command, rc = %d\n", rc); - return rc; - } - - /* Check if there is a DID mismatch between nvm-cfg/efuse */ - if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) - DP_NOTICE(p_hwfn, - "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); - - return 0; -} - int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_mcp_mb_params mb_params; @@ -1549,60 +1528,6 @@ int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) return 0; } -u32 qed_get_process_kill_counter(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt) -{ - u32 path_offsize_addr, path_offsize, path_addr, proc_kill_cnt; - - if (IS_VF(p_hwfn->cdev)) - return -EINVAL; - - path_offsize_addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, - PUBLIC_PATH); - path_offsize = qed_rd(p_hwfn, p_ptt, path_offsize_addr); - path_addr = SECTION_ADDR(path_offsize, QED_PATH_ID(p_hwfn)); - - proc_kill_cnt = qed_rd(p_hwfn, p_ptt, - path_addr + - offsetof(struct public_path, process_kill)) & - PROCESS_KILL_COUNTER_MASK; - - return proc_kill_cnt; -} - -static void qed_mcp_handle_process_kill(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt) -{ - struct qed_dev *cdev = p_hwfn->cdev; - u32 proc_kill_cnt; - - /* Prevent possible attentions/interrupts during the recovery handling - * and till its load phase, during which they will be re-enabled. - */ - qed_int_igu_disable_int(p_hwfn, p_ptt); - - DP_NOTICE(p_hwfn, "Received a process kill indication\n"); - - /* The following operations should be done once, and thus in CMT mode - * are carried out by only the first HW function. - */ - if (p_hwfn != QED_LEADING_HWFN(cdev)) - return; - - if (cdev->recov_in_prog) { - DP_NOTICE(p_hwfn, - "Ignoring the indication since a recovery process is already in progress\n"); - return; - } - - cdev->recov_in_prog = true; - - proc_kill_cnt = qed_get_process_kill_counter(p_hwfn, p_ptt); - DP_NOTICE(p_hwfn, "Process kill counter: %d\n", proc_kill_cnt); - - qed_schedule_recovery_handler(p_hwfn); -} - static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, enum MFW_DRV_MSG_TYPE type) @@ -1833,9 +1758,6 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); break; - case MFW_DRV_MSG_ERROR_RECOVERY: - qed_mcp_handle_process_kill(p_hwfn, p_ptt); - break; case MFW_DRV_MSG_GET_LAN_STATS: case MFW_DRV_MSG_GET_FCOE_STATS: case MFW_DRV_MSG_GET_ISCSI_STATS: @@ -2381,43 +2303,6 @@ int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, return 0; } -int qed_start_recovery_process(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) -{ - struct qed_dev *cdev = p_hwfn->cdev; - - if (cdev->recov_in_prog) { - DP_NOTICE(p_hwfn, - "Avoid triggering a recovery since such a process is already in progress\n"); - return -EAGAIN; - } - - DP_NOTICE(p_hwfn, "Triggering a recovery process\n"); - qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_GENERAL_ATTN_35, 0x1); - - return 0; -} - -#define QED_RECOVERY_PROLOG_SLEEP_MS 100 - -int qed_recovery_prolog(struct qed_dev *cdev) -{ - struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); - struct qed_ptt *p_ptt = p_hwfn->p_main_ptt; - int rc; - - /* Allow ongoing PCIe transactions to complete */ - msleep(QED_RECOVERY_PROLOG_SLEEP_MS); - - /* Clear the PF's internal FID_enable in the PXP */ - rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); - if (rc) - DP_NOTICE(p_hwfn, - "qed_pglueb_set_pfid_enable() failed. rc = %d.\n", - rc); - - return rc; -} - static int qed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, u8 vf_id, u8 num) diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index 6e1d72a669ae..eddf67798d6f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -440,38 +440,6 @@ qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_mcp_drv_version *p_ver); -/** - * @brief Read the MFW process kill counter - * - * @param p_hwfn - * @param p_ptt - * - * @return u32 - */ -u32 qed_get_process_kill_counter(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt); - -/** - * @brief Trigger a recovery process - * - * @param p_hwfn - * @param p_ptt - * - * @return int - */ -int qed_start_recovery_process(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); - -/** - * @brief A recovery handler must call this function as its first step. - * It is assumed that the handler is not run from an interrupt context. - * - * @param cdev - * @param p_ptt - * - * @return int - */ -int qed_recovery_prolog(struct qed_dev *cdev); - /** * @brief Notify MFW about the change in base device properties * @@ -832,16 +800,6 @@ int qed_mcp_load_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_load_req_params *p_params); -/** - * @brief Sends a LOAD_DONE message to the MFW - * - * @param p_hwfn - * @param p_ptt - * - * @return int - 0 - Operation was successful. - */ -int qed_mcp_load_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt); - /** * @brief Sends a UNLOAD_REQ message to the MFW * diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 5ce825ca5f24..8939ed6e08b7 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -518,8 +518,6 @@ 0x180824UL #define MISC_REG_AEU_GENERAL_ATTN_0 \ 0x008400UL -#define MISC_REG_AEU_GENERAL_ATTN_35 \ - 0x00848cUL #define CAU_REG_SB_ADDR_MEMORY \ 0x1c8000UL #define CAU_REG_SB_VAR_MEMORY \ diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c index 3e0f7c46bb1b..eb88bbc6b193 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c @@ -790,17 +790,6 @@ static int qed_spq_pend_post(struct qed_hwfn *p_hwfn) SPQ_HIGH_PRI_RESERVE_DEFAULT); } -static void qed_spq_recov_set_ret_code(struct qed_spq_entry *p_ent, - u8 *fw_return_code) -{ - if (!fw_return_code) - return; - - if (p_ent->elem.hdr.protocol_id == PROTOCOLID_ROCE || - p_ent->elem.hdr.protocol_id == PROTOCOLID_IWARP) - *fw_return_code = RDMA_RETURN_OK; -} - /* Avoid overriding of SPQ entries when getting out-of-order completions, by * marking the completions in a bitmap and increasing the chain consumer only * for the first successive completed entries. @@ -836,17 +825,6 @@ int qed_spq_post(struct qed_hwfn *p_hwfn, return -EINVAL; } - if (p_hwfn->cdev->recov_in_prog) { - DP_VERBOSE(p_hwfn, - QED_MSG_SPQ, - "Recovery is in progress. Skip spq post [cmd %02x protocol %02x]\n", - p_ent->elem.hdr.cmd_id, p_ent->elem.hdr.protocol_id); - - /* Let the flow complete w/o any error handling */ - qed_spq_recov_set_ret_code(p_ent, fw_return_code); - return 0; - } - /* Complete the entry */ rc = qed_spq_fill_entry(p_hwfn, p_ent); diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index 71e28be58102..ca6290fa0f30 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -4447,13 +4447,6 @@ int qed_sriov_disable(struct qed_dev *cdev, bool pci_enabled) if (cdev->p_iov_info && cdev->p_iov_info->num_vfs && pci_enabled) pci_disable_sriov(cdev->pdev); - if (cdev->recov_in_prog) { - DP_VERBOSE(cdev, - QED_MSG_IOV, - "Skip SRIOV disable operations in the device since a recovery is in progress\n"); - goto out; - } - for_each_hwfn(cdev, i) { struct qed_hwfn *hwfn = &cdev->hwfns[i]; struct qed_ptt *ptt = qed_ptt_acquire(hwfn); @@ -4493,7 +4486,7 @@ int qed_sriov_disable(struct qed_dev *cdev, bool pci_enabled) qed_ptt_release(hwfn, ptt); } -out: + qed_iov_set_vfs_to_disable(cdev, false); return 0; diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 843416404aeb..613249d1e967 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h @@ -162,7 +162,6 @@ struct qede_rdma_dev { struct list_head entry; struct list_head rdma_event_list; struct workqueue_struct *rdma_wq; - bool exp_recovery; }; struct qede_ptp; @@ -265,7 +264,6 @@ struct qede_dev { enum QEDE_STATE { QEDE_STATE_CLOSED, QEDE_STATE_OPEN, - QEDE_STATE_RECOVERY, }; #define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo)) @@ -464,7 +462,6 @@ struct qede_fastpath { #define QEDE_CSUM_UNNECESSARY BIT(1) #define QEDE_TUNN_CSUM_UNNECESSARY BIT(2) -#define QEDE_SP_RECOVERY 0 #define QEDE_SP_RX_MODE 1 #ifdef CONFIG_RFS_ACCEL diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index de955f2b2980..5a74fcbdbc2b 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -133,12 +133,23 @@ static int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void qede_remove(struct pci_dev *pdev); static void qede_shutdown(struct pci_dev *pdev); static void qede_link_update(void *dev, struct qed_link_output *link); -static void qede_schedule_recovery_handler(void *dev); -static void qede_recovery_handler(struct qede_dev *edev); static void qede_get_eth_tlv_data(void *edev, void *data); static void qede_get_generic_tlv_data(void *edev, struct qed_generic_tlvs *data); +/* The qede lock is used to protect driver state change and driver flows that + * are not reentrant. + */ +void __qede_lock(struct qede_dev *edev) +{ + mutex_lock(&edev->qede_lock); +} + +void __qede_unlock(struct qede_dev *edev) +{ + mutex_unlock(&edev->qede_lock); +} + #ifdef CONFIG_QED_SRIOV static int qede_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan, u8 qos, __be16 vlan_proto) @@ -220,7 +231,6 @@ static struct qed_eth_cb_ops qede_ll_ops = { .arfs_filter_op = qede_arfs_filter_op, #endif .link_update = qede_link_update, - .schedule_recovery_handler = qede_schedule_recovery_handler, .get_generic_tlv_data = qede_get_generic_tlv_data, .get_protocol_tlv_data = qede_get_eth_tlv_data, }, @@ -940,57 +950,11 @@ err: return -ENOMEM; } -/* The qede lock is used to protect driver state change and driver flows that - * are not reentrant. - */ -void __qede_lock(struct qede_dev *edev) -{ - mutex_lock(&edev->qede_lock); -} - -void __qede_unlock(struct qede_dev *edev) -{ - mutex_unlock(&edev->qede_lock); -} - -/* This version of the lock should be used when acquiring the RTNL lock is also - * needed in addition to the internal qede lock. - */ -void qede_lock(struct qede_dev *edev) -{ - rtnl_lock(); - __qede_lock(edev); -} - -void qede_unlock(struct qede_dev *edev) -{ - __qede_unlock(edev); - rtnl_unlock(); -} - static void qede_sp_task(struct work_struct *work) { struct qede_dev *edev = container_of(work, struct qede_dev, sp_task.work); - /* The locking scheme depends on the specific flag: - * In case of QEDE_SP_RECOVERY, acquiring the RTNL lock is required to - * ensure that ongoing flows are ended and new ones are not started. - * In other cases - only the internal qede lock should be acquired. - */ - - if (test_and_clear_bit(QEDE_SP_RECOVERY, &edev->sp_flags)) { -#ifdef CONFIG_QED_SRIOV - /* SRIOV must be disabled outside the lock to avoid a deadlock. - * The recovery of the active VFs is currently not supported. - */ - qede_sriov_configure(edev->pdev, 0); -#endif - qede_lock(edev); - qede_recovery_handler(edev); - qede_unlock(edev); - } - __qede_lock(edev); if (test_and_clear_bit(QEDE_SP_RX_MODE, &edev->sp_flags)) @@ -1067,13 +1031,8 @@ static void qede_log_probe(struct qede_dev *edev) enum qede_probe_mode { QEDE_PROBE_NORMAL, - QEDE_PROBE_RECOVERY, }; -#define QEDE_RDMA_PROBE_MODE(mode) \ - ((mode) == QEDE_PROBE_NORMAL ? QEDE_RDMA_PROBE_NORMAL \ - : QEDE_RDMA_PROBE_RECOVERY) - static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, bool is_vf, enum qede_probe_mode mode) { @@ -1092,7 +1051,6 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, probe_params.dp_module = dp_module; probe_params.dp_level = dp_level; probe_params.is_vf = is_vf; - probe_params.recov_in_prog = (mode == QEDE_PROBE_RECOVERY); cdev = qed_ops->common->probe(pdev, &probe_params); if (!cdev) { rc = -ENODEV; @@ -1120,20 +1078,11 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, if (rc) goto err2; - if (mode != QEDE_PROBE_RECOVERY) { - edev = qede_alloc_etherdev(cdev, pdev, &dev_info, dp_module, - dp_level); - if (!edev) { - rc = -ENOMEM; - goto err2; - } - } else { - struct net_device *ndev = pci_get_drvdata(pdev); - - edev = netdev_priv(ndev); - edev->cdev = cdev; - memset(&edev->stats, 0, sizeof(edev->stats)); - memcpy(&edev->dev_info, &dev_info, sizeof(dev_info)); + edev = qede_alloc_etherdev(cdev, pdev, &dev_info, dp_module, + dp_level); + if (!edev) { + rc = -ENOMEM; + goto err2; } if (is_vf) @@ -1141,31 +1090,28 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, qede_init_ndev(edev); - rc = qede_rdma_dev_add(edev, QEDE_RDMA_PROBE_MODE(mode)); + rc = qede_rdma_dev_add(edev); if (rc) goto err3; - if (mode != QEDE_PROBE_RECOVERY) { - /* Prepare the lock prior to the registration of the netdev, - * as once it's registered we might reach flows requiring it - * [it's even possible to reach a flow needing it directly - * from there, although it's unlikely]. - */ - INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task); - mutex_init(&edev->qede_lock); - - rc = register_netdev(edev->ndev); - if (rc) { - DP_NOTICE(edev, "Cannot register net-device\n"); - goto err4; - } + /* Prepare the lock prior to the registration of the netdev, + * as once it's registered we might reach flows requiring it + * [it's even possible to reach a flow needing it directly + * from there, although it's unlikely]. + */ + INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task); + mutex_init(&edev->qede_lock); + rc = register_netdev(edev->ndev); + if (rc) { + DP_NOTICE(edev, "Cannot register net-device\n"); + goto err4; } edev->ops->common->set_name(cdev, edev->ndev->name); /* PTP not supported on VFs */ if (!is_vf) - qede_ptp_enable(edev, (mode == QEDE_PROBE_NORMAL)); + qede_ptp_enable(edev, true); edev->ops->register_ops(cdev, &qede_ll_ops, edev); @@ -1180,7 +1126,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, return 0; err4: - qede_rdma_dev_remove(edev, QEDE_RDMA_PROBE_MODE(mode)); + qede_rdma_dev_remove(edev); err3: free_netdev(edev->ndev); err2: @@ -1216,13 +1162,8 @@ static int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id) enum qede_remove_mode { QEDE_REMOVE_NORMAL, - QEDE_REMOVE_RECOVERY, }; -#define QEDE_RDMA_REMOVE_MODE(mode) \ - ((mode) == QEDE_REMOVE_NORMAL ? QEDE_RDMA_REMOVE_NORMAL \ - : QEDE_RDMA_REMOVE_RECOVERY) - static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) { struct net_device *ndev = pci_get_drvdata(pdev); @@ -1231,19 +1172,15 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) DP_INFO(edev, "Starting qede_remove\n"); - qede_rdma_dev_remove(edev, QEDE_RDMA_REMOVE_MODE(mode)); - - if (mode != QEDE_REMOVE_RECOVERY) { - unregister_netdev(ndev); + qede_rdma_dev_remove(edev); + unregister_netdev(ndev); + cancel_delayed_work_sync(&edev->sp_task); - cancel_delayed_work_sync(&edev->sp_task); + qede_ptp_disable(edev); - edev->ops->common->set_power_state(cdev, PCI_D0); + edev->ops->common->set_power_state(cdev, PCI_D0); - pci_set_drvdata(pdev, NULL); - } - - qede_ptp_disable(edev); + pci_set_drvdata(pdev, NULL); /* Use global ops since we've freed edev */ qed_ops->common->slowpath_stop(cdev); @@ -1257,8 +1194,7 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) * [e.g., QED register callbacks] won't break anything when * accessing the netdevice. */ - if (mode != QEDE_REMOVE_RECOVERY) - free_netdev(ndev); + free_netdev(ndev); dev_info(&pdev->dev, "Ending qede_remove successfully\n"); } @@ -1603,58 +1539,6 @@ static int qede_alloc_mem_load(struct qede_dev *edev) return 0; } -static void qede_empty_tx_queue(struct qede_dev *edev, - struct qede_tx_queue *txq) -{ - unsigned int pkts_compl = 0, bytes_compl = 0; - struct netdev_queue *netdev_txq; - int rc, len = 0; - - netdev_txq = netdev_get_tx_queue(edev->ndev, txq->ndev_txq_id); - - while (qed_chain_get_cons_idx(&txq->tx_pbl) != - qed_chain_get_prod_idx(&txq->tx_pbl)) { - DP_VERBOSE(edev, NETIF_MSG_IFDOWN, - "Freeing a packet on tx queue[%d]: chain_cons 0x%x, chain_prod 0x%x\n", - txq->index, qed_chain_get_cons_idx(&txq->tx_pbl), - qed_chain_get_prod_idx(&txq->tx_pbl)); - - rc = qede_free_tx_pkt(edev, txq, &len); - if (rc) { - DP_NOTICE(edev, - "Failed to free a packet on tx queue[%d]: chain_cons 0x%x, chain_prod 0x%x\n", - txq->index, - qed_chain_get_cons_idx(&txq->tx_pbl), - qed_chain_get_prod_idx(&txq->tx_pbl)); - break; - } - - bytes_compl += len; - pkts_compl++; - txq->sw_tx_cons++; - } - - netdev_tx_completed_queue(netdev_txq, pkts_compl, bytes_compl); -} - -static void qede_empty_tx_queues(struct qede_dev *edev) -{ - int i; - - for_each_queue(i) - if (edev->fp_array[i].type & QEDE_FASTPATH_TX) { - int cos; - - for_each_cos_in_txq(edev, cos) { - struct qede_fastpath *fp; - - fp = &edev->fp_array[i]; - qede_empty_tx_queue(edev, - &fp->txq[cos]); - } - } -} - /* This function inits fp content and resets the SB, RXQ and TXQ structures */ static void qede_init_fp(struct qede_dev *edev) { @@ -2169,7 +2053,6 @@ out: enum qede_unload_mode { QEDE_UNLOAD_NORMAL, - QEDE_UNLOAD_RECOVERY, }; static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, @@ -2185,8 +2068,7 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, clear_bit(QEDE_FLAGS_LINK_REQUESTED, &edev->flags); - if (mode != QEDE_UNLOAD_RECOVERY) - edev->state = QEDE_STATE_CLOSED; + edev->state = QEDE_STATE_CLOSED; qede_rdma_dev_event_close(edev); @@ -2194,21 +2076,18 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, netif_tx_disable(edev->ndev); netif_carrier_off(edev->ndev); - if (mode != QEDE_UNLOAD_RECOVERY) { - /* Reset the link */ - memset(&link_params, 0, sizeof(link_params)); - link_params.link_up = false; - edev->ops->common->set_link(edev->cdev, &link_params); - - rc = qede_stop_queues(edev); - if (rc) { - qede_sync_free_irqs(edev); - goto out; - } - - DP_INFO(edev, "Stopped Queues\n"); + /* Reset the link */ + memset(&link_params, 0, sizeof(link_params)); + link_params.link_up = false; + edev->ops->common->set_link(edev->cdev, &link_params); + rc = qede_stop_queues(edev); + if (rc) { + qede_sync_free_irqs(edev); + goto out; } + DP_INFO(edev, "Stopped Queues\n"); + qede_vlan_mark_nonconfigured(edev); edev->ops->fastpath_stop(edev->cdev); @@ -2223,26 +2102,18 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, qede_napi_disable_remove(edev); - if (mode == QEDE_UNLOAD_RECOVERY) - qede_empty_tx_queues(edev); - qede_free_mem_load(edev); qede_free_fp_array(edev); out: if (!is_locked) __qede_unlock(edev); - - if (mode != QEDE_UNLOAD_RECOVERY) - DP_NOTICE(edev, "Link is down\n"); - DP_INFO(edev, "Ending qede unload\n"); } enum qede_load_mode { QEDE_LOAD_NORMAL, QEDE_LOAD_RELOAD, - QEDE_LOAD_RECOVERY, }; static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, @@ -2422,77 +2293,6 @@ static void qede_link_update(void *dev, struct qed_link_output *link) } } -static void qede_schedule_recovery_handler(void *dev) -{ - struct qede_dev *edev = dev; - - if (edev->state == QEDE_STATE_RECOVERY) { - DP_NOTICE(edev, - "Avoid scheduling a recovery handling since already in recovery state\n"); - return; - } - - set_bit(QEDE_SP_RECOVERY, &edev->sp_flags); - schedule_delayed_work(&edev->sp_task, 0); - - DP_INFO(edev, "Scheduled a recovery handler\n"); -} - -static void qede_recovery_failed(struct qede_dev *edev) -{ - netdev_err(edev->ndev, "Recovery handling has failed. Power cycle is needed.\n"); - - netif_device_detach(edev->ndev); - - if (edev->cdev) - edev->ops->common->set_power_state(edev->cdev, PCI_D3hot); -} - -static void qede_recovery_handler(struct qede_dev *edev) -{ - u32 curr_state = edev->state; - int rc; - - DP_NOTICE(edev, "Starting a recovery process\n"); - - /* No need to acquire first the qede_lock since is done by qede_sp_task - * before calling this function. - */ - edev->state = QEDE_STATE_RECOVERY; - - edev->ops->common->recovery_prolog(edev->cdev); - - if (curr_state == QEDE_STATE_OPEN) - qede_unload(edev, QEDE_UNLOAD_RECOVERY, true); - - __qede_remove(edev->pdev, QEDE_REMOVE_RECOVERY); - - rc = __qede_probe(edev->pdev, edev->dp_module, edev->dp_level, - IS_VF(edev), QEDE_PROBE_RECOVERY); - if (rc) { - edev->cdev = NULL; - goto err; - } - - if (curr_state == QEDE_STATE_OPEN) { - rc = qede_load(edev, QEDE_LOAD_RECOVERY, true); - if (rc) - goto err; - - qede_config_rx_mode(edev->ndev); - udp_tunnel_get_rx_info(edev->ndev); - } - - edev->state = curr_state; - - DP_NOTICE(edev, "Recovery handling is done\n"); - - return; - -err: - qede_recovery_failed(edev); -} - static bool qede_is_txq_full(struct qede_dev *edev, struct qede_tx_queue *txq) { struct netdev_queue *netdev_txq; diff --git a/drivers/net/ethernet/qlogic/qede/qede_rdma.c b/drivers/net/ethernet/qlogic/qede/qede_rdma.c index 9668e5e47d5f..1900bf7e67d1 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_rdma.c +++ b/drivers/net/ethernet/qlogic/qede/qede_rdma.c @@ -50,8 +50,6 @@ static void _qede_rdma_dev_add(struct qede_dev *edev) if (!qedr_drv) return; - /* Leftovers from previous error recovery */ - edev->rdma_info.exp_recovery = false; edev->rdma_info.qedr_dev = qedr_drv->add(edev->cdev, edev->pdev, edev->ndev); } @@ -89,26 +87,21 @@ static void qede_rdma_destroy_wq(struct qede_dev *edev) destroy_workqueue(edev->rdma_info.rdma_wq); } -int qede_rdma_dev_add(struct qede_dev *edev, enum qede_rdma_probe_mode mode) +int qede_rdma_dev_add(struct qede_dev *edev) { - int rc; + int rc = 0; - if (!qede_rdma_supported(edev)) - return 0; - - /* Cannot start qedr while recovering since it wasn't fully stopped */ - if (mode == QEDE_RDMA_PROBE_RECOVERY) - return 0; - - rc = qede_rdma_create_wq(edev); - if (rc) - return rc; + if (qede_rdma_supported(edev)) { + rc = qede_rdma_create_wq(edev); + if (rc) + return rc; - INIT_LIST_HEAD(&edev->rdma_info.entry); - mutex_lock(&qedr_dev_list_lock); - list_add_tail(&edev->rdma_info.entry, &qedr_dev_list); - _qede_rdma_dev_add(edev); - mutex_unlock(&qedr_dev_list_lock); + INIT_LIST_HEAD(&edev->rdma_info.entry); + mutex_lock(&qedr_dev_list_lock); + list_add_tail(&edev->rdma_info.entry, &qedr_dev_list); + _qede_rdma_dev_add(edev); + mutex_unlock(&qedr_dev_list_lock); + } return rc; } @@ -117,31 +110,19 @@ static void _qede_rdma_dev_remove(struct qede_dev *edev) { if (qedr_drv && qedr_drv->remove && edev->rdma_info.qedr_dev) qedr_drv->remove(edev->rdma_info.qedr_dev); + edev->rdma_info.qedr_dev = NULL; } -void qede_rdma_dev_remove(struct qede_dev *edev, - enum qede_rdma_remove_mode mode) +void qede_rdma_dev_remove(struct qede_dev *edev) { if (!qede_rdma_supported(edev)) return; - /* Cannot remove qedr while recovering since it wasn't fully stopped */ - if (mode == QEDE_RDMA_REMOVE_NORMAL) { - qede_rdma_destroy_wq(edev); - mutex_lock(&qedr_dev_list_lock); - if (!edev->rdma_info.exp_recovery) - _qede_rdma_dev_remove(edev); - edev->rdma_info.qedr_dev = NULL; - list_del(&edev->rdma_info.entry); - mutex_unlock(&qedr_dev_list_lock); - } else { - if (!edev->rdma_info.exp_recovery) { - mutex_lock(&qedr_dev_list_lock); - _qede_rdma_dev_remove(edev); - mutex_unlock(&qedr_dev_list_lock); - } - edev->rdma_info.exp_recovery = true; - } + qede_rdma_destroy_wq(edev); + mutex_lock(&qedr_dev_list_lock); + _qede_rdma_dev_remove(edev); + list_del(&edev->rdma_info.entry); + mutex_unlock(&qedr_dev_list_lock); } static void _qede_rdma_dev_open(struct qede_dev *edev) @@ -223,8 +204,7 @@ void qede_rdma_unregister_driver(struct qedr_driver *drv) mutex_lock(&qedr_dev_list_lock); list_for_each_entry(edev, &qedr_dev_list, rdma_info.entry) { - /* If device has experienced recovery it was already removed */ - if (edev->rdma_info.qedr_dev && !edev->rdma_info.exp_recovery) + if (edev->rdma_info.qedr_dev) _qede_rdma_dev_remove(edev); } qedr_drv = NULL; @@ -304,10 +284,6 @@ static void qede_rdma_add_event(struct qede_dev *edev, { struct qede_rdma_event_work *event_node; - /* If a recovery was experienced avoid adding the event */ - if (edev->rdma_info.exp_recovery) - return; - if (!edev->rdma_info.qedr_dev) return; diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h index c2a1b7dbe4eb..91c536a01b56 100644 --- a/include/linux/qed/qed_if.h +++ b/include/linux/qed/qed_if.h @@ -764,7 +764,6 @@ struct qed_probe_params { u32 dp_module; u8 dp_level; bool is_vf; - bool recov_in_prog; }; #define QED_DRV_VER_STR_SIZE 12 @@ -811,7 +810,6 @@ struct qed_common_cb_ops { void (*arfs_filter_op)(void *dev, void *fltr, u8 fw_rc); void (*link_update)(void *dev, struct qed_link_output *link); - void (*schedule_recovery_handler)(void *dev); void (*dcbx_aen)(void *dev, struct qed_dcbx_get *get, u32 mib_type); void (*get_generic_tlv_data)(void *dev, struct qed_generic_tlvs *data); void (*get_protocol_tlv_data)(void *dev, void *data); @@ -1059,24 +1057,6 @@ struct qed_common_ops { int (*db_recovery_del)(struct qed_dev *cdev, void __iomem *db_addr, void *db_data); -/** - * @brief recovery_process - Trigger a recovery process - * - * @param cdev - * - * @return 0 on success, error otherwise. - */ - int (*recovery_process)(struct qed_dev *cdev); - -/** - * @brief recovery_prolog - Execute the prolog operations of a recovery process - * - * @param cdev - * - * @return 0 on success, error otherwise. - */ - int (*recovery_prolog)(struct qed_dev *cdev); - /** * @brief update_drv_state - API to inform the change in the driver state. * diff --git a/include/linux/qed/qede_rdma.h b/include/linux/qed/qede_rdma.h index e29d7199c10e..9904617a9730 100644 --- a/include/linux/qed/qede_rdma.h +++ b/include/linux/qed/qede_rdma.h @@ -55,16 +55,6 @@ struct qede_rdma_event_work { enum qede_rdma_event event; }; -enum qede_rdma_probe_mode { - QEDE_RDMA_PROBE_NORMAL, - QEDE_RDMA_PROBE_RECOVERY, -}; - -enum qede_rdma_remove_mode { - QEDE_RDMA_REMOVE_NORMAL, - QEDE_RDMA_REMOVE_RECOVERY, -}; - struct qedr_driver { unsigned char name[32]; @@ -84,24 +74,21 @@ void qede_rdma_unregister_driver(struct qedr_driver *drv); bool qede_rdma_supported(struct qede_dev *dev); #if IS_ENABLED(CONFIG_QED_RDMA) -int qede_rdma_dev_add(struct qede_dev *dev, enum qede_rdma_probe_mode mode); +int qede_rdma_dev_add(struct qede_dev *dev); void qede_rdma_dev_event_open(struct qede_dev *dev); void qede_rdma_dev_event_close(struct qede_dev *dev); -void qede_rdma_dev_remove(struct qede_dev *dev, - enum qede_rdma_remove_mode mode); +void qede_rdma_dev_remove(struct qede_dev *dev); void qede_rdma_event_changeaddr(struct qede_dev *edr); #else -static inline int qede_rdma_dev_add(struct qede_dev *dev, - enum qede_rdma_probe_mode mode) +static inline int qede_rdma_dev_add(struct qede_dev *dev) { return 0; } static inline void qede_rdma_dev_event_open(struct qede_dev *dev) {} static inline void qede_rdma_dev_event_close(struct qede_dev *dev) {} -static inline void qede_rdma_dev_remove(struct qede_dev *dev, - enum qede_rdma_remove_mode mode) {} +static inline void qede_rdma_dev_remove(struct qede_dev *dev) {} static inline void qede_rdma_event_changeaddr(struct qede_dev *edr) {} #endif #endif -- cgit v1.2.3-58-ga151 From 947b7ac135b16aa60f9141ff72bd494eda0edb5e Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sun, 27 Jan 2019 06:35:28 -0700 Subject: Revert "block: cover another queue enter recursion via BIO_QUEUE_ENTERED" We can't touch a bio after ->make_request_fn(), for all we know it could already have been completed by the time this function returns. This reverts commit 698cef173983b086977e633e46476e0f925ca01e. Reported-by: syzbot+4df6ca820108fd248943@syzkaller.appspotmail.com Signed-off-by: Jens Axboe --- block/blk-core.c | 11 ----------- block/blk-merge.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 1ccec27d20c3..3c5f61ceeb67 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1083,18 +1083,7 @@ blk_qc_t generic_make_request(struct bio *bio) /* Create a fresh bio_list for all subordinate requests */ bio_list_on_stack[1] = bio_list_on_stack[0]; bio_list_init(&bio_list_on_stack[0]); - - /* - * Since we're recursing into make_request here, ensure - * that we mark this bio as already having entered the queue. - * If not, and the queue is going away, we can get stuck - * forever on waiting for the queue reference to drop. But - * that will never happen, as we're already holding a - * reference to it. - */ - bio_set_flag(bio, BIO_QUEUE_ENTERED); ret = q->make_request_fn(q, bio); - bio_clear_flag(bio, BIO_QUEUE_ENTERED); /* sort new bios into those for a lower level * and those for the same level diff --git a/block/blk-merge.c b/block/blk-merge.c index d79a22f111d1..71e9ac03f621 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -272,6 +272,16 @@ void blk_queue_split(struct request_queue *q, struct bio **bio) /* there isn't chance to merge the splitted bio */ split->bi_opf |= REQ_NOMERGE; + /* + * Since we're recursing into make_request here, ensure + * that we mark this bio as already having entered the queue. + * If not, and the queue is going away, we can get stuck + * forever on waiting for the queue reference to drop. But + * that will never happen, as we're already holding a + * reference to it. + */ + bio_set_flag(*bio, BIO_QUEUE_ENTERED); + bio_chain(split, *bio); trace_block_split(q, split, (*bio)->bi_iter.bi_sector); generic_make_request(*bio); -- cgit v1.2.3-58-ga151 From f17b5f06cb92ef2250513a1e154c47b78df07d40 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 27 Jan 2019 15:18:05 -0800 Subject: Linux 5.0-rc4 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f5b1d0d168e0..141653226f3c 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 5 PATCHLEVEL = 0 SUBLEVEL = 0 -EXTRAVERSION = -rc3 +EXTRAVERSION = -rc4 NAME = Shy Crocodile # *DOCUMENTATION* -- cgit v1.2.3-58-ga151 From 141474c6ac7f279824780453d3f9c75d6193dc85 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Jan 2019 11:24:34 +0900 Subject: ASoC: Fixup build error for mt6358 This patch fixup build error for commit 6a8d4198ca8 ("ASoC: mediatek: mt6358: add codec driver") Fixes: commit 6a8d4198ca8 ("ASoC: mediatek: mt6358: add codec driver") Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 55fd58015c2d..83ef965cbff1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1344,7 +1344,7 @@ config SND_SOC_MT6358 tristate "MediaTek MT6358 Codec" help Enable support for the platform which uses MT6358 as - external codec device. + external codec device. config SND_SOC_NAU8540 tristate "Nuvoton Technology Corporation NAU85L40 CODEC" -- cgit v1.2.3-58-ga151 From 720734a0b66f9ca42ec6663a48702b16e49552ee Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Jan 2019 10:40:24 +0900 Subject: ASoC: soc-core: use for_each_link_codecs() for dai_link codecs V2 We can use for_each_link_codecs() without waiting for_each_rtd_codec_dai() on soc_bind_dai_link(). Let's use for_each macro. Fixes: 50acc7e49 ("ASoC: core: Fix multi-CODEC setups") Fixes: 10dff9b0d ("ASoC: soc-core: use for_each_link_codecs() for dai_link codecs") Signed-off-by: Kuninori Morimoto Tested-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8a58fa86675a..93efab486736 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,13 +905,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ - /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dais[i] = snd_soc_find_dai(&codecs[i]); + for_each_link_codecs(dai_link, i, codecs) { + codec_dais[i] = snd_soc_find_dai(codecs); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", - codecs[i].dai_name); + codecs->dai_name); goto _err_defer; } snd_soc_rtdcom_add(rtd, codec_dais[i]->component); -- cgit v1.2.3-58-ga151 From ccc8d6c7b6d2f521a4b10c7f6d027f46c7a686bf Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 26 Jan 2019 15:17:01 +0200 Subject: ASoC: pcm512x: Implement the set_bclk_ratio interface Some boards, such as the HiFiBerry DAC+ Pro, use a pair of external oscillators, to generate 44.1 or 48kHz multiples and are forced to resort to hacks [1] in order to support 24-bit data without ending up with fractional dividers. This patch allows the machine driver to use 32-bit frames for 24-bit data to avoid such issues. Although the datasheet (p. 15) seems to suggest that only a handful of ratios are supported, it's not very explicit about it, so we allow the full range of values supported by the underlying register in the callback, to avoid needlessly rejecting potentially usable configurations. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-December/143442.html Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 4cc24a5d5c31..ce8c5dbd2164 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -55,6 +55,7 @@ struct pcm512x_priv { unsigned long overclock_dsp; int mute; struct mutex mutex; + unsigned int bclk_ratio; }; /* @@ -915,10 +916,15 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, int fssp; int gpio; - lrclk_div = snd_soc_params_to_frame_size(params); - if (lrclk_div == 0) { - dev_err(dev, "No LRCLK?\n"); - return -EINVAL; + if (pcm512x->bclk_ratio > 0) { + lrclk_div = pcm512x->bclk_ratio; + } else { + lrclk_div = snd_soc_params_to_frame_size(params); + + if (lrclk_div == 0) { + dev_err(dev, "No LRCLK?\n"); + return -EINVAL; + } } if (!pcm512x->pll_out) { @@ -1383,6 +1389,19 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int pcm512x_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_component *component = dai->component; + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + if (ratio > 256) + return -EINVAL; + + pcm512x->bclk_ratio = ratio; + + return 0; +} + static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_component *component = dai->component; @@ -1435,6 +1454,7 @@ static const struct snd_soc_dai_ops pcm512x_dai_ops = { .hw_params = pcm512x_hw_params, .set_fmt = pcm512x_set_fmt, .digital_mute = pcm512x_digital_mute, + .set_bclk_ratio = pcm512x_set_bclk_ratio, }; static struct snd_soc_dai_driver pcm512x_dai = { -- cgit v1.2.3-58-ga151 From 51b033c2608147efe3a5368bfa64837e772d8c55 Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 26 Jan 2019 15:23:45 +0200 Subject: ASoC: pcm512x: Fix clocking calculations when not using the PLL The rationale behind the current calculation is somewhat obscure [1] and can yield slightly wrong dividers in certain cases, which the machine drivers for some boards (like the HiFiBerry DAC+ Pro) seemingly try to circumvent, by updating the rate fraction so as to suit this calculation. The updated calculation should correctly yield the smallest bit clock rate that would fit the frame. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2019-January/144219.html Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown --- sound/soc/codecs/pcm512x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index ce8c5dbd2164..ae3bd533eadb 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -929,8 +929,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, if (!pcm512x->pll_out) { sck_rate = clk_get_rate(pcm512x->sclk); - bclk_div = params->rate_den * 64 / lrclk_div; - bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div); + bclk_rate = params_rate(params) * lrclk_div; + bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate); mck_rate = sck_rate; } else { -- cgit v1.2.3-58-ga151 From 5e484ec1758b95e6420787fc17f0e8c5e152c264 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:16:17 -0600 Subject: ASoC: soc-acpi: add static inline fallbacks when CONFIG_ACPI=n Fix compilation issues reported by 0day-Kbuild with sparc64 w/ SOF. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 266e64e3c24c..6cbbeed9cdd0 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -22,20 +22,37 @@ struct snd_soc_acpi_package_context { #define SND_ACPI_I2C_ID_LEN (4 + ACPI_ID_LEN + 3 + 1) #if IS_ENABLED(CONFIG_ACPI) +/* acpi match */ +struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); + bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx); + +/* check all codecs */ +struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); + #else +/* acpi match */ +static inline struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) +{ + return NULL; +} + static inline bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx) { return false; } -#endif -/* acpi match */ -struct snd_soc_acpi_mach * -snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); +/* check all codecs */ +static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) +{ + return NULL; +} +#endif /** * snd_soc_acpi_mach_params: interface for machine driver configuration @@ -105,7 +122,4 @@ struct snd_soc_acpi_codecs { u8 codecs[SND_SOC_ACPI_MAX_CODECS][ACPI_ID_LEN]; }; -/* check all codecs */ -struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); - #endif -- cgit v1.2.3-58-ga151 From e20bfeb0b7d808bc05e7c4cb1f492cd31d837da0 Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Fri, 25 Jan 2019 10:45:37 -0800 Subject: ASoC: rt5651: Variable "ret" in function rt5651_i2c_probe() could be uninitialized In function rt5651_i2c_probe(), local variable "ret" could be uninitialized if function regmap_read() returns -EINVAL. However, this value is used in if statement. This is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 75994297c896..29b2d60076b0 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2181,6 +2181,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, { struct rt5651_priv *rt5651; int ret; + int err; rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651), GFP_KERNEL); @@ -2197,7 +2198,10 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, return ret; } - regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + err = regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + if (err) + return err; + if (ret != RT5651_DEVICE_ID_VALUE) { dev_err(&i2c->dev, "Device with ID register %#x is not rt5651\n", ret); -- cgit v1.2.3-58-ga151 From cb50358b83846e4dcb37137c431327c4dd68561b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:55 -0600 Subject: ASoC: add helper to change platform name for all dailinks To reuse the same machine drivers with Atom/SST, Skylake and SOF, we need to change the default platform_name (or platforms->name in the "modern" representation). So far, this override was done with an automatic override, which was broken by a set of changes for DT platforms related to deferred probe handling. This automatic override is actually not really needed, the machine driver can already receive the platform name as a platform_data parameter. This is used e.g. for HDaudio support where we have different PCI aliases used for different platforms. We can reuse the same mechanism and modify the machine drivers to override the dailinks prior to registrating the card. This will require additional work for SOF, but with this helper it'll be just two lines of additional code per machine driver which is reused, not the end of the world. This helper can be simplified when all drivers have transitioned to the "modern" representation of dailinks. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 3089257ead95..95689680336b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1580,6 +1580,37 @@ struct snd_soc_dai *snd_soc_card_get_codec_dai(struct snd_soc_card *card, return NULL; } +static inline +int snd_soc_fixup_dai_links_platform_name(struct snd_soc_card *card, + const char *platform_name) +{ + struct snd_soc_dai_link *dai_link; + const char *name; + int i; + + if (!platform_name) /* nothing to do */ + return 0; + + /* set platform name for each dailink */ + for_each_card_prelinks(card, i, dai_link) { + name = devm_kstrdup(card->dev, platform_name, GFP_KERNEL); + if (!name) + return -ENOMEM; + + if (dai_link->platforms) + /* only single platform is supported for now */ + dai_link->platforms->name = name; + else + /* + * legacy mode, this case will be removed when all + * derivers are switched to modern style dai_link. + */ + dai_link->platform_name = name; + } + + return 0; +} + #ifdef CONFIG_DEBUG_FS extern struct dentry *snd_soc_debugfs_root; #endif -- cgit v1.2.3-58-ga151 From e87055d732e34d8f5fa95da686958b30a03da5b4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:56 -0600 Subject: ASoC: Intel: haswell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/haswell.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index a4022983a7ce..971226d42042 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "../common/sst-dsp.h" @@ -189,8 +190,22 @@ static struct snd_soc_card haswell_rt5640 = { static int haswell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + haswell_rt5640.dev = &pdev->dev; + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640); } -- cgit v1.2.3-58-ga151 From 2d067b2807f9d3381a37acef1b2f43682a868c7a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:57 -0600 Subject: ASoC: Intel: broadwell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/broadwell.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 99f2a0156ae8..b86c746d9b7a 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -267,7 +268,22 @@ static struct snd_soc_card broadwell_rt286 = { static int broadwell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + broadwell_rt286.dev = &pdev->dev; + + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); } -- cgit v1.2.3-58-ga151 From 7e40ddcf974a970e750420f88365174cfd207b24 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:58 -0600 Subject: ASoC: Intel: bdw-rt5677: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bdw-rt5677.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index efcfd906c856..1844c88ea4e2 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -339,6 +340,9 @@ static struct snd_soc_card bdw_rt5677_card = { static int bdw_rt5677_probe(struct platform_device *pdev) { struct bdw_rt5677_priv *bdw_rt5677; + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; bdw_rt5677_card.dev = &pdev->dev; @@ -350,6 +354,16 @@ static int bdw_rt5677_probe(struct platform_device *pdev) return -ENOMEM; } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5677_card, + platform_name); + if (ret) + return ret; + snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); -- cgit v1.2.3-58-ga151 From bd7661b761bc7f585aad4fc6e5b62d684bdad75b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:59 -0600 Subject: ASoC: Intel: bytcr_rt5640: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a79466c8fb29..940eb27158da 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1153,6 +1153,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int ret_val = 0; int dai_index = 0; @@ -1317,6 +1318,14 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); byt_rt5640_card.long_name = byt_rt5640_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5640_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) { -- cgit v1.2.3-58-ga151 From 0b2c2093fc3a1f89f2ef15d945c0439ce7b9dd9d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:00 -0600 Subject: ASoC: Intel: bytcr_rt5651: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5651.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e6945d11c8ab..c3b7732929cc 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -922,6 +922,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct device *codec_dev; const char *i2c_name = NULL; const char *hp_swapped; @@ -1137,6 +1138,14 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], hp_swapped); byt_rt5651_card.long_name = byt_rt5651_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5651_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); if (ret_val) { -- cgit v1.2.3-58-ga151 From 686338c12a2bd2d27f8444901fb9ce1a4c0c0b58 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:01 -0600 Subject: ASoC: Intel: bytcht_da7213: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_da7213.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 2179dedb28ad..b8e884803777 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -225,6 +225,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int dai_index = 0; int ret_val = 0; @@ -250,6 +251,13 @@ static int bytcht_da7213_probe(struct platform_device *pdev) dailink[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, -- cgit v1.2.3-58-ga151 From e4bc6b1195f64d345646709c4a65edf1fc4d3228 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:02 -0600 Subject: ASoC: Intel: bytcht_es8316: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 1364e4e601d8..d2a7e6ba11ae 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -441,6 +441,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; struct device *codec_dev; int dai_index = 0; @@ -469,6 +470,14 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card, + platform_name); + if (ret) + return ret; + /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { -- cgit v1.2.3-58-ga151 From 7e7e24d7c7ff0e85956288915aaa7e682e2ccd55 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:03 -0600 Subject: ASoC: Intel: cht_bsw_max98090_ti: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 08a5152e635a..3263b0495853 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "../../codecs/max98090.h" #include "../atom/sst-atom-controls.h" @@ -420,6 +421,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; const char *mclk_name; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int quirks = 0; dmi_id = dmi_first_match(cht_max98090_quirk_table); @@ -442,6 +445,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) dev_dbg(dev, "Unable to add GPIO mapping table\n"); } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); -- cgit v1.2.3-58-ga151 From 4506db8043341f2351e03d45c0e96c8e1a141dfa Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:04 -0600 Subject: ASoC: Intel: cht_bsw_nau8824: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_nau8824.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 30c46977d53c..02c2fa239331 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "../atom/sst-atom-controls.h" @@ -246,6 +247,8 @@ static struct snd_soc_card snd_soc_card_cht = { static int snd_cht_mc_probe(struct platform_device *pdev) { struct cht_mc_private *drv; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int ret_val; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -253,6 +256,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return -ENOMEM; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); -- cgit v1.2.3-58-ga151 From 3a934e7c75b446a104bdea3dd676d7199db9a7bd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:05 -0600 Subject: ASoC: Intel: cht_bsw_rt5645: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 250a356a0cbf..cbc2d458483f 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -530,6 +530,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) { struct snd_soc_card *card = snd_soc_cards[0].soc_card; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct cht_mc_private *drv; const char *i2c_name = NULL; bool found = false; @@ -663,6 +664,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) cht_rt5645_cpu_dai_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, -- cgit v1.2.3-58-ga151 From f403906da05cdea38c222ef472fdc4df29ece47f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:06 -0600 Subject: ASoC: Intel: cht_bsw_rt5672: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 9de64f447e7b..f1c1f9dd5353 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -400,6 +400,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + const char *platform_name; const char *i2c_name; int i; @@ -426,6 +427,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, -- cgit v1.2.3-58-ga151 From 7ebf2528eacae2a9c1edff575c3c58b75095ce08 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:07 -0600 Subject: ASoC: Intel: bxt_da7219_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6f052fc8d1e2..c00925f9da73 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "../../codecs/hdac_hdmi.h" #include "../../codecs/da7219.h" #include "../../codecs/da7219-aad.h" @@ -584,6 +585,9 @@ static struct snd_soc_card broxton_audio_card = { static int broxton_audio_probe(struct platform_device *pdev) { struct bxt_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -594,6 +598,15 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broxton_audio_card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } -- cgit v1.2.3-58-ga151 From fbe2c2736e295bf866110c9278504c42498318c5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:08 -0600 Subject: ASoC: Intel: bxt_rt298: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_rt298.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 27308337ab12..e91057f83d20 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "../../codecs/hdac_hdmi.h" @@ -576,6 +577,9 @@ static int broxton_audio_probe(struct platform_device *pdev) struct bxt_rt286_private *ctx; struct snd_soc_card *card = (struct snd_soc_card *)pdev->id_entry->driver_data; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; int i; for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) { @@ -602,6 +606,15 @@ static int broxton_audio_probe(struct platform_device *pdev) card->dev = &pdev->dev; snd_soc_card_set_drvdata(card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, card); } -- cgit v1.2.3-58-ga151 From 5b14aa718f5993b0ecee3bbd61557468ac2420bf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:09 -0600 Subject: ASoC: Intel: glk_rt5682_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index f6597c216fa8..d17126f7757c 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "../skylake/skl.h" #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" @@ -571,6 +572,10 @@ static struct snd_soc_card glk_audio_card_rt5682_m98357a = { static int geminilake_audio_probe(struct platform_device *pdev) { struct glk_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + struct snd_soc_card *card; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -578,11 +583,19 @@ static int geminilake_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - glk_audio_card_rt5682_m98357a.dev = &pdev->dev; - snd_soc_card_set_drvdata(&glk_audio_card_rt5682_m98357a, ctx); + card = &glk_audio_card_rt5682_m98357a; + card->dev = &pdev->dev; + snd_soc_card_set_drvdata(card, ctx); + + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret) + return ret; - return devm_snd_soc_register_card(&pdev->dev, - &glk_audio_card_rt5682_m98357a); + return devm_snd_soc_register_card(&pdev->dev, card); } static const struct platform_device_id glk_board_ids[] = { -- cgit v1.2.3-58-ga151 From 262ff68fce8fe388bfa60efc95e394cf0a149563 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:46 +0000 Subject: ASoC: dt-bindings: update wcd9335 bindings. This patch updates wcd9335 bindings with recommended properties. Signed-off-by: Srinivas Kandagatla Reviewed-by: Rob Herring Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,wcd9335.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt index 1d8d49e30af7..5d6ea66a863f 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt +++ b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt @@ -34,12 +34,12 @@ Required properties with SLIMbus Interface: Definition: Interrupt names of WCD INTR1 and INTR2 Should be: "intr1", "intr2" -- reset-gpio: +- reset-gpios: Usage: required Value type: Definition: Reset gpio line -- qcom,ifd: +- slim-ifc-dev: Usage: required Value type: Definition: SLIM interface device @@ -104,13 +104,13 @@ Required properties with SLIMbus Interface: Value type: Definition: Must be 1 -codec@1{ +audio-codec@1{ compatible = "slim217,1a0"; reg = <1 0>; interrupts = <&msmgpio 54 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "intr2" - reset-gpio = <&msmgpio 64 0>; - qcom,ifd = <&wc9335_ifd>; + reset-gpios = <&msmgpio 64 0>; + slim-ifc-dev = <&wc9335_ifd>; clock-names = "mclk", "native"; clocks = <&rpmcc RPM_SMD_DIV_CLK1>, <&rpmcc RPM_SMD_BB_CLK1>; -- cgit v1.2.3-58-ga151 From 20aedafdf4926e7a957f8b302a18c8fb75c7e332 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:47 +0000 Subject: ASoC: wcd9335: add support to wcd9335 codec Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC, It supports both I2S/I2C and SLIMbus audio interfaces. On slimbus interface it supports two data lanes; 16 Tx ports and 8 Rx ports. It has Seven DACs and nine dedicated interpolators, Seven (six audio ADCs, and one VBAT ADC), Multibutton headset control (MBHC), Active noise cancellation and Sidetone paths and processing. This patchset adds very basic support for playback and capture via the 9 interpolators and ADC respectively. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 9 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wcd9335.c | 1483 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd9335.h | 640 +++++++++++++++++++ 4 files changed, 2134 insertions(+) create mode 100644 sound/soc/codecs/wcd9335.c create mode 100644 sound/soc/codecs/wcd9335.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 83ef965cbff1..9b904f81863d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -188,6 +188,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TWL6040 if TWL6040_CORE select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C + select SND_SOC_WCD9335 if SLIMBUS select SND_SOC_WL1273 if MFD_WL1273_CORE select SND_SOC_WM0010 if SPI_MASTER select SND_SOC_WM1250_EV1 if I2C @@ -1114,6 +1115,14 @@ config SND_SOC_UDA1380 tristate depends on I2C +config SND_SOC_WCD9335 + tristate "WCD9335 Codec" + select REGMAP_SLIMBUS + help + The WCD9335 is a standalone Hi-Fi audio CODEC IC, supports + Qualcomm Technologies, Inc. (QTI) multimedia solutions, + including the MSM8996, MSM8976, and MSM8956 chipsets. + config SND_SOC_WL1273 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 457f9ff5a2d4..342d057cd7fc 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -201,6 +201,7 @@ snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o +snd-soc-wcd9335-objs := wcd9335.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o @@ -469,6 +470,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o +obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c new file mode 100644 index 000000000000..d6b690af7f09 --- /dev/null +++ b/sound/soc/codecs/wcd9335.c @@ -0,0 +1,1483 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +// Copyright (c) 2017-2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wcd9335.h" + +#define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +/* Fractional Rates */ +#define WCD9335_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100) +#define WCD9335_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +/* slave port water mark level + * (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes) + */ +#define SLAVE_PORT_WATER_MARK_6BYTES 0 +#define SLAVE_PORT_WATER_MARK_9BYTES 1 +#define SLAVE_PORT_WATER_MARK_12BYTES 2 +#define SLAVE_PORT_WATER_MARK_15BYTES 3 +#define SLAVE_PORT_WATER_MARK_SHIFT 1 +#define SLAVE_PORT_ENABLE 1 +#define SLAVE_PORT_DISABLE 0 +#define WCD9335_SLIM_WATER_MARK_VAL \ + ((SLAVE_PORT_WATER_MARK_12BYTES << SLAVE_PORT_WATER_MARK_SHIFT) | \ + (SLAVE_PORT_ENABLE)) + +#define WCD9335_SLIM_NUM_PORT_REG 3 +#define WCD9335_SLIM_PGD_PORT_INT_TX_EN0 (WCD9335_SLIM_PGD_PORT_INT_EN0 + 2) + +#define WCD9335_MCLK_CLK_12P288MHZ 12288000 +#define WCD9335_MCLK_CLK_9P6MHZ 9600000 + +#define WCD9335_SLIM_CLOSE_TIMEOUT 1000 +#define WCD9335_SLIM_IRQ_OVERFLOW (1 << 0) +#define WCD9335_SLIM_IRQ_UNDERFLOW (1 << 1) +#define WCD9335_SLIM_IRQ_PORT_CLOSED (1 << 2) + +#define WCD9335_NUM_INTERPOLATORS 9 +#define WCD9335_RX_START 16 +#define WCD9335_SLIM_CH_START 128 + +#define WCD9335_SLIM_RX_CH(p) \ + {.port = p + WCD9335_RX_START, .shift = p,} + +/* vout step value */ +#define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) + +enum { + WCD9335_RX0 = 0, + WCD9335_RX1, + WCD9335_RX2, + WCD9335_RX3, + WCD9335_RX4, + WCD9335_RX5, + WCD9335_RX6, + WCD9335_RX7, + WCD9335_RX8, + WCD9335_RX9, + WCD9335_RX10, + WCD9335_RX11, + WCD9335_RX12, + WCD9335_RX_MAX, +}; + +enum { + SIDO_SOURCE_INTERNAL = 0, + SIDO_SOURCE_RCO_BG, +}; + +enum wcd9335_sido_voltage { + SIDO_VOLTAGE_SVS_MV = 950, + SIDO_VOLTAGE_NOMINAL_MV = 1100, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + AIF2_PB, + AIF2_CAP, + AIF3_PB, + AIF3_CAP, + AIF4_PB, + NUM_CODEC_DAIS, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, + INTn_2_INP_SEL_RX6, + INTn_2_INP_SEL_RX7, + INTn_2_INP_SEL_PROXIMITY, +}; + +enum { + INTn_1_MIX_INP_SEL_ZERO = 0, + INTn_1_MIX_INP_SEL_DEC0, + INTn_1_MIX_INP_SEL_DEC1, + INTn_1_MIX_INP_SEL_IIR0, + INTn_1_MIX_INP_SEL_IIR1, + INTn_1_MIX_INP_SEL_RX0, + INTn_1_MIX_INP_SEL_RX1, + INTn_1_MIX_INP_SEL_RX2, + INTn_1_MIX_INP_SEL_RX3, + INTn_1_MIX_INP_SEL_RX4, + INTn_1_MIX_INP_SEL_RX5, + INTn_1_MIX_INP_SEL_RX6, + INTn_1_MIX_INP_SEL_RX7, + +}; + +enum wcd_clock_type { + WCD_CLK_OFF, + WCD_CLK_RCO, + WCD_CLK_MCLK, +}; + +struct wcd9335_slim_ch { + u32 ch_num; + u16 port; + u16 shift; + struct list_head list; +}; + +struct wcd_slim_codec_dai_data { + struct list_head slim_ch_list; + struct slim_stream_config sconfig; + struct slim_stream_runtime *sruntime; +}; + +struct wcd9335_codec { + struct device *dev; + struct clk *mclk; + struct clk *native_clk; + u32 mclk_rate; + u8 version; + + struct slim_device *slim; + struct slim_device *slim_ifc_dev; + struct regmap *regmap; + struct regmap *if_regmap; + struct regmap_irq_chip_data *irq_data; + + struct wcd9335_slim_ch rx_chs[WCD9335_RX_MAX]; + u32 num_rx_port; + + int sido_input_src; + enum wcd9335_sido_voltage sido_voltage; + + struct wcd_slim_codec_dai_data dai[NUM_CODEC_DAIS]; + struct snd_soc_component *component; + + int master_bias_users; + int clk_mclk_users; + int clk_rco_users; + int sido_ccl_cnt; + enum wcd_clock_type clk_type; + + u32 hph_mode; + int intr1; + int reset_gpio; + struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; +}; + +struct wcd9335_irq { + int irq; + irqreturn_t (*handler)(int irq, void *data); + char *name; +}; + +static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = { + WCD9335_SLIM_RX_CH(0), /* 16 */ + WCD9335_SLIM_RX_CH(1), /* 17 */ + WCD9335_SLIM_RX_CH(2), + WCD9335_SLIM_RX_CH(3), + WCD9335_SLIM_RX_CH(4), + WCD9335_SLIM_RX_CH(5), + WCD9335_SLIM_RX_CH(6), + WCD9335_SLIM_RX_CH(7), + WCD9335_SLIM_RX_CH(8), + WCD9335_SLIM_RX_CH(9), + WCD9335_SLIM_RX_CH(10), + WCD9335_SLIM_RX_CH(11), + WCD9335_SLIM_RX_CH(12), +}; + +struct interp_sample_rate { + int rate; + int rate_val; +}; + +static struct interp_sample_rate int_mix_rate_val[] = { + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ +}; + +static struct interp_sample_rate int_prim_rate_val[] = { + {8000, 0x0}, /* 8K */ + {16000, 0x1}, /* 16K */ + {24000, -EINVAL},/* 24K */ + {32000, 0x3}, /* 32K */ + {48000, 0x4}, /* 48K */ + {96000, 0x5}, /* 96K */ + {192000, 0x6}, /* 192K */ + {384000, 0x7}, /* 384K */ + {44100, 0x8}, /* 44.1K */ +}; + +struct wcd9335_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init[] = { + /* Rbuckfly/R_EAR(32) */ + {WCD9335_CDC_CLSH_K2_MSB, 0x0F, 0x00}, + {WCD9335_CDC_CLSH_K2_LSB, 0xFF, 0x60}, + {WCD9335_CPE_SS_DMIC_CFG, 0x80, 0x00}, + {WCD9335_CDC_BOOST0_BOOST_CTL, 0x70, 0x50}, + {WCD9335_CDC_BOOST1_BOOST_CTL, 0x70, 0x50}, + {WCD9335_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08}, + {WCD9335_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08}, + {WCD9335_ANA_LO_1_2, 0x3C, 0X3C}, + {WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x70, 0x00}, + {WCD9335_DIFF_LO_COM_PA_FREQ, 0x70, 0x40}, + {WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03}, + {WCD9335_CDC_TOP_TOP_CFG1, 0x02, 0x02}, + {WCD9335_CDC_TOP_TOP_CFG1, 0x01, 0x01}, + {WCD9335_EAR_CMBUFF, 0x08, 0x00}, + {WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01}, + {WCD9335_CDC_RX0_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX1_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX2_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX3_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX4_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX5_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX6_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX7_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX8_RX_PATH_CFG0, 0x01, 0x01}, + {WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD9335_VBADC_IBIAS_FE, 0x0C, 0x08}, + {WCD9335_RCO_CTRL_2, 0x0F, 0x08}, + {WCD9335_RX_BIAS_FLYB_MID_RST, 0xF0, 0x10}, + {WCD9335_FLYBACK_CTRL_1, 0x20, 0x20}, + {WCD9335_HPH_OCP_CTL, 0xFF, 0x5A}, + {WCD9335_HPH_L_TEST, 0x01, 0x01}, + {WCD9335_HPH_R_TEST, 0x01, 0x01}, + {WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12}, + {WCD9335_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08}, + {WCD9335_CDC_COMPANDER7_CTL7, 0x1E, 0x18}, + {WCD9335_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12}, + {WCD9335_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08}, + {WCD9335_CDC_COMPANDER8_CTL7, 0x1E, 0x18}, + {WCD9335_CDC_TX0_TX_PATH_SEC7, 0xFF, 0x45}, + {WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08}, + {WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02}, +}; + +static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, + int rate_val, + u32 rate) +{ + struct snd_soc_component *component = dai->component; + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + struct wcd9335_slim_ch *ch; + int val, j; + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) { + for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) { + val = snd_soc_component_read32(component, + WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(j)) & + WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + + if (val == (ch->shift + INTn_2_INP_SEL_RX0)) + snd_soc_component_update_bits(component, + WCD9335_CDC_RX_PATH_MIX_CTL(j), + WCD9335_CDC_MIX_PCM_RATE_MASK, + rate_val); + } + } + + return 0; +} + +static int wcd9335_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_val, + u32 rate) +{ + struct snd_soc_component *comp = dai->component; + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + struct wcd9335_slim_ch *ch; + u8 cfg0, cfg1, inp0_sel, inp1_sel, inp2_sel; + int inp, j; + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) { + inp = ch->shift + INTn_1_MIX_INP_SEL_RX0; + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the slim rx port + * is connected + */ + for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) { + cfg0 = snd_soc_component_read32(comp, + WCD9335_CDC_RX_INP_MUX_RX_INT_CFG0(j)); + cfg1 = snd_soc_component_read32(comp, + WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(j)); + + inp0_sel = cfg0 & + WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + inp1_sel = (cfg0 >> 4) & + WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + inp2_sel = (cfg1 >> 4) & + WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK; + + if ((inp0_sel == inp) || (inp1_sel == inp) || + (inp2_sel == inp)) { + /* rate is in Hz */ + if ((j == 0) && (rate == 44100)) + dev_info(wcd->dev, + "Cannot set 44.1KHz on INT0\n"); + else + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX_PATH_CTL(j), + WCD9335_CDC_MIX_PCM_RATE_MASK, + rate_val); + } + } + } + + return 0; +} + +static int wcd9335_set_interpolator_rate(struct snd_soc_dai *dai, u32 rate) +{ + int i; + + /* set mixing path rate */ + for (i = 0; i < ARRAY_SIZE(int_mix_rate_val); i++) { + if (rate == int_mix_rate_val[i].rate) { + wcd9335_set_mix_interpolator_rate(dai, + int_mix_rate_val[i].rate_val, rate); + break; + } + } + + /* set primary path sample rate */ + for (i = 0; i < ARRAY_SIZE(int_prim_rate_val); i++) { + if (rate == int_prim_rate_val[i].rate) { + wcd9335_set_prim_interpolator_rate(dai, + int_prim_rate_val[i].rate_val, rate); + break; + } + } + + return 0; +} + +static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd, + struct wcd_slim_codec_dai_data *dai_data, + int direction) +{ + struct list_head *slim_ch_list = &dai_data->slim_ch_list; + struct slim_stream_config *cfg = &dai_data->sconfig; + struct wcd9335_slim_ch *ch; + u16 payload = 0; + int ret, i; + + cfg->ch_count = 0; + cfg->direction = direction; + cfg->port_mask = 0; + + /* Configure slave interface device */ + list_for_each_entry(ch, slim_ch_list, list) { + cfg->ch_count++; + payload |= 1 << ch->shift; + cfg->port_mask |= BIT(ch->port); + } + + cfg->chs = kcalloc(cfg->ch_count, sizeof(unsigned int), GFP_KERNEL); + if (!cfg->chs) + return -ENOMEM; + + i = 0; + list_for_each_entry(ch, slim_ch_list, list) { + cfg->chs[i++] = ch->ch_num; + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + /* write to interface device */ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_RX_PORT_MULTI_CHNL_0(ch->port), + payload); + + if (ret < 0) + goto err; + + /* configure the slave port for water mark and enable*/ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_RX_PORT_CFG(ch->port), + WCD9335_SLIM_WATER_MARK_VAL); + if (ret < 0) + goto err; + } + } + + dai_data->sruntime = slim_stream_allocate(wcd->slim, "WCD9335-SLIM"); + + return 0; + +err: + dev_err(wcd->dev, "Error Setting slim hw params\n"); + kfree(cfg->chs); + cfg->chs = NULL; + + return ret; +} + +static int wcd9335_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wcd9335_codec *wcd; + int ret; + + wcd = snd_soc_component_get_drvdata(dai->component); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = wcd9335_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err(wcd->dev, "cannot set sample rate: %u\n", + params_rate(params)); + return ret; + } + switch (params_width(params)) { + case 16 ... 24: + wcd->dai[dai->id].sconfig.bps = params_width(params); + break; + default: + dev_err(wcd->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + } + break; + default: + dev_err(wcd->dev, "Invalid stream type %d\n", + substream->stream); + return -EINVAL; + }; + + wcd->dai[dai->id].sconfig.rate = params_rate(params); + wcd9335_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream); + + return 0; +} + +static int wcd9335_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct wcd_slim_codec_dai_data *dai_data; + struct wcd9335_codec *wcd; + struct slim_stream_config *cfg; + + wcd = snd_soc_component_get_drvdata(dai->component); + + dai_data = &wcd->dai[dai->id]; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + cfg = &dai_data->sconfig; + slim_stream_prepare(dai_data->sruntime, cfg); + slim_stream_enable(dai_data->sruntime); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + slim_stream_unprepare(dai_data->sruntime); + slim_stream_disable(dai_data->sruntime); + break; + default: + break; + } + + return 0; +} + +static int wcd9335_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct wcd9335_codec *wcd; + int i; + + wcd = snd_soc_component_get_drvdata(dai->component); + + if (!tx_slot || !rx_slot) { + dev_err(wcd->dev, "Invalid tx_slot=%p, rx_slot=%p\n", + tx_slot, rx_slot); + return -EINVAL; + } + + if (wcd->rx_chs) { + wcd->num_rx_port = rx_num; + for (i = 0; i < rx_num; i++) { + wcd->rx_chs[i].ch_num = rx_slot[i]; + INIT_LIST_HEAD(&wcd->rx_chs[i].list); + } + } + + return 0; +} + +static int wcd9335_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct wcd9335_slim_ch *ch; + struct wcd9335_codec *wcd; + int i = 0; + + wcd = snd_soc_component_get_drvdata(dai->component); + + switch (dai->id) { + case AIF1_PB: + case AIF2_PB: + case AIF3_PB: + case AIF4_PB: + if (!rx_slot || !rx_num) { + dev_err(wcd->dev, "Invalid rx_slot %p or rx_num %p\n", + rx_slot, rx_num); + return -EINVAL; + } + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) + rx_slot[i++] = ch->ch_num; + + *rx_num = i; + break; + default: + dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id); + break; + } + + return 0; +} + +static struct snd_soc_dai_ops wcd9335_dai_ops = { + .hw_params = wcd9335_hw_params, + .trigger = wcd9335_trigger, + .set_channel_map = wcd9335_set_channel_map, + .get_channel_map = wcd9335_get_channel_map, +}; + +static struct snd_soc_dai_driver wcd9335_slim_dais[] = { + [0] = { + .name = "wcd9335_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, + [1] = { + .name = "wcd9335_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = WCD9335_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd9335_dai_ops, + }, + [2] = { + .name = "wcd9335_rx2", + .id = AIF2_PB, + .playback = { + .stream_name = "AIF2 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, + [3] = { + .name = "wcd9335_tx2", + .id = AIF2_CAP, + .capture = { + .stream_name = "AIF2 Capture", + .rates = WCD9335_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd9335_dai_ops, + }, + [4] = { + .name = "wcd9335_rx3", + .id = AIF3_PB, + .playback = { + .stream_name = "AIF3 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, + [5] = { + .name = "wcd9335_tx3", + .id = AIF3_CAP, + .capture = { + .stream_name = "AIF3 Capture", + .rates = WCD9335_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd9335_dai_ops, + }, + [6] = { + .name = "wcd9335_rx4", + .id = AIF4_PB, + .playback = { + .stream_name = "AIF4 Playback", + .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK, + .formats = WCD9335_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd9335_dai_ops, + }, +}; + +static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) +{ + struct wcd9335_codec *wcd = data; + unsigned long status = 0; + int i, j, port_id; + unsigned int val, int_val = 0; + irqreturn_t ret = IRQ_NONE; + bool tx; + unsigned short reg = 0; + + for (i = WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0; + i <= WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) { + regmap_read(wcd->if_regmap, i, &val); + status |= ((u32)val << (8 * j)); + } + + for_each_set_bit(j, &status, 32) { + tx = (j >= 16 ? true : false); + port_id = (tx ? j - 16 : j); + regmap_read(wcd->if_regmap, + WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val); + if (val) { + if (!tx) + reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + + (port_id / 8); + else + reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + regmap_read( + wcd->if_regmap, reg, &int_val); + /* + * Ignore interrupts for ports for which the + * interrupts are not specifically enabled. + */ + if (!(int_val & (1 << (port_id % 8)))) + continue; + } + + if (val & WCD9335_SLIM_IRQ_OVERFLOW) + dev_err_ratelimited(wcd->dev, + "%s: overflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + + if (val & WCD9335_SLIM_IRQ_UNDERFLOW) + dev_err_ratelimited(wcd->dev, + "%s: underflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + + if ((val & WCD9335_SLIM_IRQ_OVERFLOW) || + (val & WCD9335_SLIM_IRQ_UNDERFLOW)) { + if (!tx) + reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + + (port_id / 8); + else + reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + regmap_read( + wcd->if_regmap, reg, &int_val); + if (int_val & (1 << (port_id % 8))) { + int_val = int_val ^ (1 << (port_id % 8)); + regmap_write(wcd->if_regmap, + reg, int_val); + } + } + + regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0 + (j / 8), + BIT(j % 8)); + ret = IRQ_HANDLED; + } + + return ret; +} + +static struct wcd9335_irq wcd9335_irqs[] = { + { + .irq = WCD9335_IRQ_SLIMBUS, + .handler = wcd9335_slimbus_irq, + .name = "SLIM Slave", + }, +}; + +static int wcd9335_setup_irqs(struct wcd9335_codec *wcd) +{ + int irq, ret, i; + + for (i = 0; i < ARRAY_SIZE(wcd9335_irqs); i++) { + irq = regmap_irq_get_virq(wcd->irq_data, wcd9335_irqs[i].irq); + if (irq < 0) { + dev_err(wcd->dev, "Failed to get %s\n", + wcd9335_irqs[i].name); + return irq; + } + + ret = devm_request_threaded_irq(wcd->dev, irq, NULL, + wcd9335_irqs[i].handler, + IRQF_TRIGGER_RISING, + wcd9335_irqs[i].name, wcd); + if (ret) { + dev_err(wcd->dev, "Failed to request %s\n", + wcd9335_irqs[i].name); + return ret; + } + } + + /* enable interrupts on all slave ports */ + for (i = 0; i < WCD9335_SLIM_NUM_PORT_REG; i++) + regmap_write(wcd->if_regmap, WCD9335_SLIM_PGD_PORT_INT_EN0 + i, + 0xFF); + + return ret; +} + +static void wcd9335_cdc_sido_ccl_enable(struct wcd9335_codec *wcd, + bool ccl_flag) +{ + struct snd_soc_component *comp = wcd->component; + + if (ccl_flag) { + if (++wcd->sido_ccl_cnt == 1) + snd_soc_component_write(comp, WCD9335_SIDO_SIDO_CCL_10, + WCD9335_SIDO_SIDO_CCL_DEF_VALUE); + } else { + if (wcd->sido_ccl_cnt == 0) { + dev_err(wcd->dev, "sido_ccl already disabled\n"); + return; + } + if (--wcd->sido_ccl_cnt == 0) + snd_soc_component_write(comp, WCD9335_SIDO_SIDO_CCL_10, + WCD9335_SIDO_SIDO_CCL_10_ICHARG_PWR_SEL_C320FF); + } +} + +static int wcd9335_enable_master_bias(struct wcd9335_codec *wcd) +{ + wcd->master_bias_users++; + if (wcd->master_bias_users == 1) { + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_EN_MASK, + WCD9335_ANA_BIAS_ENABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_EN_MASK, + WCD9335_ANA_BIAS_PRECHRG_ENABLE); + /* + * 1ms delay is required after pre-charge is enabled + * as per HW requirement + */ + usleep_range(1000, 1100); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_EN_MASK, + WCD9335_ANA_BIAS_PRECHRG_DISABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL); + } + + return 0; +} + +static int wcd9335_enable_mclk(struct wcd9335_codec *wcd) +{ + /* Enable mclk requires master bias to be enabled first */ + if (wcd->master_bias_users <= 0) + return -EINVAL; + + if (((wcd->clk_mclk_users == 0) && (wcd->clk_type == WCD_CLK_MCLK)) || + ((wcd->clk_mclk_users > 0) && (wcd->clk_type != WCD_CLK_MCLK))) { + dev_err(wcd->dev, "Error enabling MCLK, clk_type: %d\n", + wcd->clk_type); + return -EINVAL; + } + + if (++wcd->clk_mclk_users == 1) { + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK, + WCD9335_ANA_CLK_EXT_CLKBUF_ENABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_SRC_MASK, + WCD9335_ANA_CLK_MCLK_SRC_EXTERNAL); + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_EN_MASK, + WCD9335_ANA_CLK_MCLK_ENABLE); + regmap_update_bits(wcd->regmap, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_EN_MASK, + WCD9335_CDC_CLK_RST_CTRL_FS_CNT_ENABLE); + regmap_update_bits(wcd->regmap, + WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL, + WCD9335_CDC_CLK_RST_CTRL_MCLK_EN_MASK, + WCD9335_CDC_CLK_RST_CTRL_MCLK_ENABLE); + /* + * 10us sleep is required after clock is enabled + * as per HW requirement + */ + usleep_range(10, 15); + } + + wcd->clk_type = WCD_CLK_MCLK; + + return 0; +} + +static int wcd9335_disable_mclk(struct wcd9335_codec *wcd) +{ + if (wcd->clk_mclk_users <= 0) + return -EINVAL; + + if (--wcd->clk_mclk_users == 0) { + if (wcd->clk_rco_users > 0) { + /* MCLK to RCO switch */ + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_SRC_MASK, + WCD9335_ANA_CLK_MCLK_SRC_RCO); + wcd->clk_type = WCD_CLK_RCO; + } else { + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_MCLK_EN_MASK, + WCD9335_ANA_CLK_MCLK_DISABLE); + wcd->clk_type = WCD_CLK_OFF; + } + + regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP, + WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK, + WCD9335_ANA_CLK_EXT_CLKBUF_DISABLE); + } + + return 0; +} + +static int wcd9335_disable_master_bias(struct wcd9335_codec *wcd) +{ + if (wcd->master_bias_users <= 0) + return -EINVAL; + + wcd->master_bias_users--; + if (wcd->master_bias_users == 0) { + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_EN_MASK, + WCD9335_ANA_BIAS_DISABLE); + regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE, + WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL); + } + return 0; +} + +static int wcd9335_cdc_req_mclk_enable(struct wcd9335_codec *wcd, + bool enable) +{ + int ret = 0; + + if (enable) { + wcd9335_cdc_sido_ccl_enable(wcd, true); + ret = clk_prepare_enable(wcd->mclk); + if (ret) { + dev_err(wcd->dev, "%s: ext clk enable failed\n", + __func__); + goto err; + } + /* get BG */ + wcd9335_enable_master_bias(wcd); + /* get MCLK */ + wcd9335_enable_mclk(wcd); + + } else { + /* put MCLK */ + wcd9335_disable_mclk(wcd); + /* put BG */ + wcd9335_disable_master_bias(wcd); + clk_disable_unprepare(wcd->mclk); + wcd9335_cdc_sido_ccl_enable(wcd, false); + } +err: + return ret; +} + +static void wcd9335_codec_apply_sido_voltage(struct wcd9335_codec *wcd, + enum wcd9335_sido_voltage req_mv) +{ + struct snd_soc_component *comp = wcd->component; + int vout_d_val; + + if (req_mv == wcd->sido_voltage) + return; + + /* compute the vout_d step value */ + vout_d_val = WCD9335_CALCULATE_VOUT_D(req_mv) & + WCD9335_ANA_BUCK_VOUT_MASK; + snd_soc_component_write(comp, WCD9335_ANA_BUCK_VOUT_D, vout_d_val); + snd_soc_component_update_bits(comp, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_RAMP_START_MASK, + WCD9335_ANA_BUCK_CTL_RAMP_START_ENABLE); + + /* 1 msec sleep required after SIDO Vout_D voltage change */ + usleep_range(1000, 1100); + wcd->sido_voltage = req_mv; + snd_soc_component_update_bits(comp, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_RAMP_START_MASK, + WCD9335_ANA_BUCK_CTL_RAMP_START_DISABLE); +} + +static int wcd9335_codec_update_sido_voltage(struct wcd9335_codec *wcd, + enum wcd9335_sido_voltage req_mv) +{ + int ret = 0; + + /* enable mclk before setting SIDO voltage */ + ret = wcd9335_cdc_req_mclk_enable(wcd, true); + if (ret) { + dev_err(wcd->dev, "Ext clk enable failed\n"); + goto err; + } + + wcd9335_codec_apply_sido_voltage(wcd, req_mv); + wcd9335_cdc_req_mclk_enable(wcd, false); + +err: + return ret; +} + +static int _wcd9335_codec_enable_mclk(struct snd_soc_component *component, + int enable) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int ret; + + if (enable) { + ret = wcd9335_cdc_req_mclk_enable(wcd, true); + if (ret) + return ret; + + wcd9335_codec_apply_sido_voltage(wcd, + SIDO_VOLTAGE_NOMINAL_MV); + } else { + wcd9335_codec_update_sido_voltage(wcd, + wcd->sido_voltage); + wcd9335_cdc_req_mclk_enable(wcd, false); + } + + return 0; +} + +static void wcd9335_enable_sido_buck(struct snd_soc_component *component) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + snd_soc_component_update_bits(component, WCD9335_ANA_RCO, + WCD9335_ANA_RCO_BG_EN_MASK, + WCD9335_ANA_RCO_BG_ENABLE); + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_MASK, + WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_EXT); + /* 100us sleep needed after IREF settings */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, + WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_MASK, + WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT); + /* 100us sleep needed after VREF settings */ + usleep_range(100, 110); + wcd->sido_input_src = SIDO_SOURCE_RCO_BG; +} + +static int wcd9335_enable_efuse_sensing(struct snd_soc_component *comp) +{ + _wcd9335_codec_enable_mclk(comp, true); + snd_soc_component_update_bits(comp, + WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, + WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK, + WCD9335_CHIP_TIER_CTRL_EFUSE_ENABLE); + /* + * 5ms sleep required after enabling efuse control + * before checking the status. + */ + usleep_range(5000, 5500); + + if (!(snd_soc_component_read32(comp, + WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS) & + WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK)) + WARN(1, "%s: Efuse sense is not complete\n", __func__); + + wcd9335_enable_sido_buck(comp); + _wcd9335_codec_enable_mclk(comp, false); + + return 0; +} + +static void wcd9335_codec_init(struct snd_soc_component *component) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int i; + + /* ungate MCLK and set clk rate */ + regmap_update_bits(wcd->regmap, WCD9335_CODEC_RPM_CLK_GATE, + WCD9335_CODEC_RPM_CLK_GATE_MCLK_GATE_MASK, 0); + + regmap_update_bits(wcd->regmap, WCD9335_CODEC_RPM_CLK_MCLK_CFG, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ); + + for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init); i++) + snd_soc_component_update_bits(component, + wcd9335_codec_reg_init[i].reg, + wcd9335_codec_reg_init[i].mask, + wcd9335_codec_reg_init[i].val); + + wcd9335_enable_efuse_sensing(component); +} + +static int wcd9335_codec_probe(struct snd_soc_component *component) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int i; + + snd_soc_component_init_regmap(component, wcd->regmap); + wcd->component = component; + + wcd9335_codec_init(component); + + for (i = 0; i < NUM_CODEC_DAIS; i++) + INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list); + + return wcd9335_setup_irqs(wcd); +} + +static void wcd9335_codec_remove(struct snd_soc_component *comp) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + free_irq(regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS), wcd); +} + +static int wcd9335_codec_set_sysclk(struct snd_soc_component *comp, + int clk_id, int source, + unsigned int freq, int dir) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + wcd->mclk_rate = freq; + + if (wcd->mclk_rate == WCD9335_MCLK_CLK_12P288MHZ) + snd_soc_component_update_bits(comp, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ); + else if (wcd->mclk_rate == WCD9335_MCLK_CLK_9P6MHZ) + snd_soc_component_update_bits(comp, + WCD9335_CODEC_RPM_CLK_MCLK_CFG, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK, + WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ); + + return clk_set_rate(wcd->mclk, freq); +} + +static const struct snd_soc_component_driver wcd9335_component_drv = { + .probe = wcd9335_codec_probe, + .remove = wcd9335_codec_remove, + .set_sysclk = wcd9335_codec_set_sysclk, +}; + +static int wcd9335_probe(struct wcd9335_codec *wcd) +{ + struct device *dev = wcd->dev; + + memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs)); + + wcd->sido_input_src = SIDO_SOURCE_INTERNAL; + wcd->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV; + + return devm_snd_soc_register_component(dev, &wcd9335_component_drv, + wcd9335_slim_dais, + ARRAY_SIZE(wcd9335_slim_dais)); +} + +static const struct regmap_range_cfg wcd9335_ranges[] = { + { + .name = "WCD9335", + .range_min = 0x0, + .range_max = WCD9335_MAX_REGISTER, + .selector_reg = WCD9335_REG(0x0, 0), + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0x0, + .window_len = 0x1000, + }, +}; + +static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD9335_INTR_PIN1_STATUS0...WCD9335_INTR_PIN2_CLEAR3: + case WCD9335_ANA_MBHC_RESULT_3: + case WCD9335_ANA_MBHC_RESULT_2: + case WCD9335_ANA_MBHC_RESULT_1: + case WCD9335_ANA_MBHC_MECH: + case WCD9335_ANA_MBHC_ELECT: + case WCD9335_ANA_MBHC_ZDET: + case WCD9335_ANA_MICB2: + case WCD9335_ANA_RCO: + case WCD9335_ANA_BIAS: + return true; + default: + return false; + } +} + +static struct regmap_config wcd9335_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = WCD9335_MAX_REGISTER, + .can_multi_write = true, + .ranges = wcd9335_ranges, + .num_ranges = ARRAY_SIZE(wcd9335_ranges), + .volatile_reg = wcd9335_is_volatile_register, +}; + +static const struct regmap_range_cfg wcd9335_ifc_ranges[] = { + { + .name = "WCD9335-IFC-DEV", + .range_min = 0x0, + .range_max = WCD9335_REG(0, 0x7ff), + .selector_reg = WCD9335_REG(0, 0x0), + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0x0, + .window_len = 0x1000, + }, +}; + +static struct regmap_config wcd9335_ifc_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .can_multi_write = true, + .max_register = WCD9335_REG(0, 0x7FF), + .ranges = wcd9335_ifc_ranges, + .num_ranges = ARRAY_SIZE(wcd9335_ifc_ranges), +}; + +static const struct regmap_irq wcd9335_codec_irqs[] = { + /* INTR_REG 0 */ + [WCD9335_IRQ_SLIMBUS] = { + .reg_offset = 0, + .mask = BIT(0), + .type = { + .type_reg_offset = 0, + .types_supported = IRQ_TYPE_EDGE_BOTH, + .type_reg_mask = BIT(0), + }, + }, +}; + +static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = { + .name = "wcd9335_pin1_irq", + .status_base = WCD9335_INTR_PIN1_STATUS0, + .mask_base = WCD9335_INTR_PIN1_MASK0, + .ack_base = WCD9335_INTR_PIN1_CLEAR0, + .type_base = WCD9335_INTR_LEVEL0, + .num_type_reg = 4, + .num_regs = 4, + .irqs = wcd9335_codec_irqs, + .num_irqs = ARRAY_SIZE(wcd9335_codec_irqs), +}; + +static int wcd9335_parse_dt(struct wcd9335_codec *wcd) +{ + struct device *dev = wcd->dev; + struct device_node *np = dev->of_node; + int ret; + + wcd->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); + if (wcd->reset_gpio < 0) { + dev_err(dev, "Reset GPIO missing from DT\n"); + return wcd->reset_gpio; + } + + wcd->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(wcd->mclk)) { + dev_err(dev, "mclk not found\n"); + return PTR_ERR(wcd->mclk); + } + + wcd->native_clk = devm_clk_get(dev, "slimbus"); + if (IS_ERR(wcd->native_clk)) { + dev_err(dev, "slimbus clock not found\n"); + return PTR_ERR(wcd->native_clk); + } + + wcd->supplies[0].supply = "vdd-buck"; + wcd->supplies[1].supply = "vdd-buck-sido"; + wcd->supplies[2].supply = "vdd-tx"; + wcd->supplies[3].supply = "vdd-rx"; + wcd->supplies[4].supply = "vdd-io"; + + ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, wcd->supplies); + if (ret) { + dev_err(dev, "Failed to get supplies: err = %d\n", ret); + return ret; + } + + return 0; +} + +static int wcd9335_power_on_reset(struct wcd9335_codec *wcd) +{ + struct device *dev = wcd->dev; + int ret; + + ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, wcd->supplies); + if (ret) { + dev_err(dev, "Failed to get supplies: err = %d\n", ret); + return ret; + } + + /* + * For WCD9335, it takes about 600us for the Vout_A and + * Vout_D to be ready after BUCK_SIDO is powered up. + * SYS_RST_N shouldn't be pulled high during this time + * Toggle the reset line to make sure the reset pulse is + * correctly applied + */ + usleep_range(600, 650); + + gpio_direction_output(wcd->reset_gpio, 0); + msleep(20); + gpio_set_value(wcd->reset_gpio, 1); + msleep(20); + + return 0; +} + +static int wcd9335_bring_up(struct wcd9335_codec *wcd) +{ + struct regmap *rm = wcd->regmap; + int val, byte0; + + regmap_read(rm, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val); + regmap_read(rm, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0); + + if ((val < 0) || (byte0 < 0)) { + dev_err(wcd->dev, "WCD9335 CODEC version detection fail!\n"); + return -EINVAL; + } + + if (byte0 == 0x1) { + dev_info(wcd->dev, "WCD9335 CODEC version is v2.0\n"); + wcd->version = WCD9335_VERSION_2_0; + regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x01); + regmap_write(rm, WCD9335_SIDO_SIDO_TEST_2, 0x00); + regmap_write(rm, WCD9335_SIDO_SIDO_CCL_8, 0x6F); + regmap_write(rm, WCD9335_BIAS_VBG_FINE_ADJ, 0x65); + regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5); + regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7); + regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3); + regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL, 0x3); + } else { + dev_err(wcd->dev, "WCD9335 CODEC version not supported\n"); + return -EINVAL; + } + + return 0; +} + +static int wcd9335_irq_init(struct wcd9335_codec *wcd) +{ + int ret; + + /* + * INTR1 consists of all possible interrupt sources Ear OCP, + * HPH OCP, MBHC, MAD, VBAT, and SVA + * INTR2 is a subset of first interrupt sources MAD, VBAT, and SVA + */ + wcd->intr1 = of_irq_get_byname(wcd->dev->of_node, "intr1"); + if (wcd->intr1 < 0) { + if (wcd->intr1 != -EPROBE_DEFER) + dev_err(wcd->dev, "Unable to configure IRQ\n"); + + return wcd->intr1; + } + + ret = devm_regmap_add_irq_chip(wcd->dev, wcd->regmap, wcd->intr1, + IRQF_TRIGGER_HIGH, 0, + &wcd9335_regmap_irq1_chip, &wcd->irq_data); + if (ret) + dev_err(wcd->dev, "Failed to register IRQ chip: %d\n", ret); + + return ret; +} + +static int wcd9335_slim_probe(struct slim_device *slim) +{ + struct device *dev = &slim->dev; + struct wcd9335_codec *wcd; + int ret; + + wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); + if (!wcd) + return -ENOMEM; + + wcd->dev = dev; + ret = wcd9335_parse_dt(wcd); + if (ret) { + dev_err(dev, "Error parsing DT: %d\n", ret); + return ret; + } + + ret = wcd9335_power_on_reset(wcd); + if (ret) + return ret; + + dev_set_drvdata(dev, wcd); + + return 0; +} + +static int wcd9335_slim_status(struct slim_device *sdev, + enum slim_device_status status) +{ + struct device *dev = &sdev->dev; + struct device_node *ifc_dev_np; + struct wcd9335_codec *wcd; + int ret; + + wcd = dev_get_drvdata(dev); + + ifc_dev_np = of_parse_phandle(dev->of_node, "slim-ifc-dev", 0); + if (!ifc_dev_np) { + dev_err(dev, "No Interface device found\n"); + return -EINVAL; + } + + wcd->slim = sdev; + wcd->slim_ifc_dev = of_slim_get_device(sdev->ctrl, ifc_dev_np); + if (!wcd->slim_ifc_dev) { + dev_err(dev, "Unable to get SLIM Interface device\n"); + return -EINVAL; + } + + slim_get_logical_addr(wcd->slim_ifc_dev); + + wcd->regmap = regmap_init_slimbus(sdev, &wcd9335_regmap_config); + if (IS_ERR(wcd->regmap)) { + dev_err(dev, "Failed to allocate slim register map\n"); + return PTR_ERR(wcd->regmap); + } + + wcd->if_regmap = regmap_init_slimbus(wcd->slim_ifc_dev, + &wcd9335_ifc_regmap_config); + if (IS_ERR(wcd->if_regmap)) { + dev_err(dev, "Failed to allocate ifc register map\n"); + return PTR_ERR(wcd->if_regmap); + } + + ret = wcd9335_bring_up(wcd); + if (ret) { + dev_err(dev, "Failed to bringup WCD9335\n"); + return ret; + } + + ret = wcd9335_irq_init(wcd); + if (ret) + return ret; + + wcd9335_probe(wcd); + + return ret; +} + +static const struct slim_device_id wcd9335_slim_id[] = { + {SLIM_MANF_ID_QCOM, SLIM_PROD_CODE_WCD9335, 0x1, 0x0}, + {} +}; +MODULE_DEVICE_TABLE(slim, wcd9335_slim_id); + +static struct slim_driver wcd9335_slim_driver = { + .driver = { + .name = "wcd9335-slim", + }, + .probe = wcd9335_slim_probe, + .device_status = wcd9335_slim_status, + .id_table = wcd9335_slim_id, +}; + +module_slim_driver(wcd9335_slim_driver); +MODULE_DESCRIPTION("WCD9335 slim driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("slim:217:1a0:*"); diff --git a/sound/soc/codecs/wcd9335.h b/sound/soc/codecs/wcd9335.h new file mode 100644 index 000000000000..4d9be2496c30 --- /dev/null +++ b/sound/soc/codecs/wcd9335.h @@ -0,0 +1,640 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __WCD9335_H__ +#define __WCD9335_H__ + +/* + * WCD9335 register base can change according to the mode it works in + * in slimbus mode the reg base starts from 0x800 + * in i2s/i2c mode the reg base is 0x0 + */ +#define WCD9335_REG(pg, r) ((pg << 12) | (r) | 0x800) +#define WCD9335_REG_OFFSET(r) (r & 0xFF) +#define WCD9335_PAGE_OFFSET(r) ((r >> 12) & 0xFF) + +/* Page-0 Registers */ +#define WCD9335_PAGE0_PAGE_REGISTER WCD9335_REG(0x00, 0x000) +#define WCD9335_CODEC_RPM_CLK_GATE WCD9335_REG(0x00, 0x002) +#define WCD9335_CODEC_RPM_CLK_GATE_MCLK_GATE_MASK GENMASK(1, 0) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG WCD9335_REG(0x00, 0x003) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ BIT(0) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ BIT(0) +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK GENMASK(1, 0) +#define WCD9335_CODEC_RPM_RST_CTL WCD9335_REG(0x00, 0x009) +#define WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL WCD9335_REG(0x00, 0x011) +#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0 WCD9335_REG(0x00, 0x021) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_CTL WCD9335_REG(0x00, 0x025) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_SSTATE_MASK GENMASK(4, 1) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK BIT(0) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_ENABLE BIT(0) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0 WCD9335_REG(0x00, 0x029) +#define WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS WCD9335_REG(0x00, 0x039) +#define WCD9335_INTR_CFG WCD9335_REG(0x00, 0x081) +#define WCD9335_INTR_CLR_COMMIT WCD9335_REG(0x00, 0x082) +#define WCD9335_INTR_PIN1_MASK0 WCD9335_REG(0x00, 0x089) +#define WCD9335_INTR_PIN1_MASK1 WCD9335_REG(0x00, 0x08a) +#define WCD9335_INTR_PIN1_MASK2 WCD9335_REG(0x00, 0x08b) +#define WCD9335_INTR_PIN1_MASK3 WCD9335_REG(0x00, 0x08c) +#define WCD9335_INTR_PIN1_STATUS0 WCD9335_REG(0x00, 0x091) +#define WCD9335_INTR_PIN1_STATUS1 WCD9335_REG(0x00, 0x092) +#define WCD9335_INTR_PIN1_STATUS2 WCD9335_REG(0x00, 0x093) +#define WCD9335_INTR_PIN1_STATUS3 WCD9335_REG(0x00, 0x094) +#define WCD9335_INTR_PIN1_CLEAR0 WCD9335_REG(0x00, 0x099) +#define WCD9335_INTR_PIN1_CLEAR1 WCD9335_REG(0x00, 0x09a) +#define WCD9335_INTR_PIN1_CLEAR2 WCD9335_REG(0x00, 0x09b) +#define WCD9335_INTR_PIN1_CLEAR3 WCD9335_REG(0x00, 0x09c) +#define WCD9335_INTR_PIN2_MASK0 WCD9335_REG(0x00, 0x0a1) +#define WCD9335_INTR_PIN2_MASK1 WCD9335_REG(0x00, 0x0a2) +#define WCD9335_INTR_PIN2_MASK2 WCD9335_REG(0x00, 0x0a3) +#define WCD9335_INTR_PIN2_MASK3 WCD9335_REG(0x00, 0x0a4) +#define WCD9335_INTR_PIN2_STATUS0 WCD9335_REG(0x00, 0x0a9) +#define WCD9335_INTR_PIN2_STATUS1 WCD9335_REG(0x00, 0x0aa) +#define WCD9335_INTR_PIN2_STATUS2 WCD9335_REG(0x00, 0x0ab) +#define WCD9335_INTR_PIN2_STATUS3 WCD9335_REG(0x00, 0x0ac) +#define WCD9335_INTR_PIN2_CLEAR0 WCD9335_REG(0x00, 0x0b1) +#define WCD9335_INTR_PIN2_CLEAR1 WCD9335_REG(0x00, 0x0b2) +#define WCD9335_INTR_PIN2_CLEAR2 WCD9335_REG(0x00, 0x0b3) +#define WCD9335_INTR_PIN2_CLEAR3 WCD9335_REG(0x00, 0x0b4) +#define WCD9335_INTR_LEVEL0 WCD9335_REG(0x00, 0x0e1) +#define WCD9335_INTR_LEVEL1 WCD9335_REG(0x00, 0x0e2) +#define WCD9335_INTR_LEVEL2 WCD9335_REG(0x00, 0x0e3) +#define WCD9335_INTR_LEVEL3 WCD9335_REG(0x00, 0x0e4) + +/* Page-1 Registers */ +#define WCD9335_CPE_FLL_USER_CTL_0 WCD9335_REG(0x01, 0x001) +#define WCD9335_CPE_FLL_USER_CTL_1 WCD9335_REG(0x01, 0x002) +#define WCD9335_CPE_FLL_USER_CTL_2 WCD9335_REG(0x01, 0x003) +#define WCD9335_CPE_FLL_USER_CTL_3 WCD9335_REG(0x01, 0x004) +#define WCD9335_CPE_FLL_USER_CTL_4 WCD9335_REG(0x01, 0x005) +#define WCD9335_CPE_FLL_USER_CTL_5 WCD9335_REG(0x01, 0x006) +#define WCD9335_CPE_FLL_USER_CTL_6 WCD9335_REG(0x01, 0x007) +#define WCD9335_CPE_FLL_USER_CTL_7 WCD9335_REG(0x01, 0x008) +#define WCD9335_CPE_FLL_USER_CTL_8 WCD9335_REG(0x01, 0x009) +#define WCD9335_CPE_FLL_USER_CTL_9 WCD9335_REG(0x01, 0x00a) +#define WCD9335_CPE_FLL_L_VAL_CTL_0 WCD9335_REG(0x01, 0x00b) +#define WCD9335_CPE_FLL_L_VAL_CTL_1 WCD9335_REG(0x01, 0x00c) +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_0 WCD9335_REG(0x01, 0x00d) +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_1 WCD9335_REG(0x01, 0x00e) +#define WCD9335_CPE_FLL_CONFIG_CTL_0 WCD9335_REG(0x01, 0x00f) +#define WCD9335_CPE_FLL_CONFIG_CTL_1 WCD9335_REG(0x01, 0x010) +#define WCD9335_CPE_FLL_CONFIG_CTL_2 WCD9335_REG(0x01, 0x011) +#define WCD9335_CPE_FLL_CONFIG_CTL_3 WCD9335_REG(0x01, 0x012) +#define WCD9335_CPE_FLL_CONFIG_CTL_4 WCD9335_REG(0x01, 0x013) +#define WCD9335_CPE_FLL_TEST_CTL_0 WCD9335_REG(0x01, 0x014) +#define WCD9335_CPE_FLL_TEST_CTL_1 WCD9335_REG(0x01, 0x015) +#define WCD9335_CPE_FLL_TEST_CTL_2 WCD9335_REG(0x01, 0x016) +#define WCD9335_CPE_FLL_TEST_CTL_3 WCD9335_REG(0x01, 0x017) +#define WCD9335_CPE_FLL_TEST_CTL_4 WCD9335_REG(0x01, 0x018) +#define WCD9335_CPE_FLL_TEST_CTL_5 WCD9335_REG(0x01, 0x019) +#define WCD9335_CPE_FLL_TEST_CTL_6 WCD9335_REG(0x01, 0x01a) +#define WCD9335_CPE_FLL_TEST_CTL_7 WCD9335_REG(0x01, 0x01b) +#define WCD9335_CPE_FLL_FREQ_CTL_0 WCD9335_REG(0x01, 0x01c) +#define WCD9335_CPE_FLL_FREQ_CTL_1 WCD9335_REG(0x01, 0x01d) +#define WCD9335_CPE_FLL_FREQ_CTL_2 WCD9335_REG(0x01, 0x01e) +#define WCD9335_CPE_FLL_FREQ_CTL_3 WCD9335_REG(0x01, 0x01f) +#define WCD9335_CPE_FLL_SSC_CTL_0 WCD9335_REG(0x01, 0x020) +#define WCD9335_CPE_FLL_SSC_CTL_1 WCD9335_REG(0x01, 0x021) +#define WCD9335_CPE_FLL_SSC_CTL_2 WCD9335_REG(0x01, 0x022) +#define WCD9335_CPE_FLL_SSC_CTL_3 WCD9335_REG(0x01, 0x023) +#define WCD9335_CPE_FLL_FLL_MODE WCD9335_REG(0x01, 0x024) +#define WCD9335_CPE_FLL_STATUS_0 WCD9335_REG(0x01, 0x025) +#define WCD9335_CPE_FLL_STATUS_1 WCD9335_REG(0x01, 0x026) +#define WCD9335_CPE_FLL_STATUS_2 WCD9335_REG(0x01, 0x027) +#define WCD9335_CPE_FLL_STATUS_3 WCD9335_REG(0x01, 0x028) +#define WCD9335_I2S_FLL_USER_CTL_0 WCD9335_REG(0x01, 0x041) +#define WCD9335_I2S_FLL_USER_CTL_1 WCD9335_REG(0x01, 0x042) +#define WCD9335_I2S_FLL_USER_CTL_2 WCD9335_REG(0x01, 0x043) +#define WCD9335_I2S_FLL_USER_CTL_3 WCD9335_REG(0x01, 0x044) +#define WCD9335_I2S_FLL_USER_CTL_4 WCD9335_REG(0x01, 0x045) +#define WCD9335_I2S_FLL_USER_CTL_5 WCD9335_REG(0x01, 0x046) +#define WCD9335_I2S_FLL_USER_CTL_6 WCD9335_REG(0x01, 0x047) +#define WCD9335_I2S_FLL_USER_CTL_7 WCD9335_REG(0x01, 0x048) +#define WCD9335_I2S_FLL_USER_CTL_8 WCD9335_REG(0x01, 0x049) +#define WCD9335_I2S_FLL_USER_CTL_9 WCD9335_REG(0x01, 0x04a) +#define WCD9335_I2S_FLL_L_VAL_CTL_0 WCD9335_REG(0x01, 0x04b) +#define WCD9335_I2S_FLL_L_VAL_CTL_1 WCD9335_REG(0x01, 0x04c) +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_0 WCD9335_REG(0x01, 0x04d) +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_1 WCD9335_REG(0x01, 0x04e) +#define WCD9335_I2S_FLL_CONFIG_CTL_0 WCD9335_REG(0x01, 0x04f) +#define WCD9335_I2S_FLL_CONFIG_CTL_1 WCD9335_REG(0x01, 0x050) +#define WCD9335_I2S_FLL_CONFIG_CTL_2 WCD9335_REG(0x01, 0x051) +#define WCD9335_I2S_FLL_CONFIG_CTL_3 WCD9335_REG(0x01, 0x052) +#define WCD9335_I2S_FLL_CONFIG_CTL_4 WCD9335_REG(0x01, 0x053) +#define WCD9335_I2S_FLL_TEST_CTL_0 WCD9335_REG(0x01, 0x054) +#define WCD9335_I2S_FLL_TEST_CTL_1 WCD9335_REG(0x01, 0x055) +#define WCD9335_I2S_FLL_TEST_CTL_2 WCD9335_REG(0x01, 0x056) +#define WCD9335_I2S_FLL_TEST_CTL_3 WCD9335_REG(0x01, 0x057) +#define WCD9335_I2S_FLL_TEST_CTL_4 WCD9335_REG(0x01, 0x058) +#define WCD9335_I2S_FLL_TEST_CTL_5 WCD9335_REG(0x01, 0x059) +#define WCD9335_I2S_FLL_TEST_CTL_6 WCD9335_REG(0x01, 0x05a) +#define WCD9335_I2S_FLL_TEST_CTL_7 WCD9335_REG(0x01, 0x05b) +#define WCD9335_I2S_FLL_FREQ_CTL_0 WCD9335_REG(0x01, 0x05c) +#define WCD9335_I2S_FLL_FREQ_CTL_1 WCD9335_REG(0x01, 0x05d) +#define WCD9335_I2S_FLL_FREQ_CTL_2 WCD9335_REG(0x01, 0x05e) +#define WCD9335_I2S_FLL_FREQ_CTL_3 WCD9335_REG(0x01, 0x05f) +#define WCD9335_I2S_FLL_SSC_CTL_0 WCD9335_REG(0x01, 0x060) +#define WCD9335_I2S_FLL_SSC_CTL_1 WCD9335_REG(0x01, 0x061) +#define WCD9335_I2S_FLL_SSC_CTL_2 WCD9335_REG(0x01, 0x062) +#define WCD9335_I2S_FLL_SSC_CTL_3 WCD9335_REG(0x01, 0x063) +#define WCD9335_I2S_FLL_FLL_MODE WCD9335_REG(0x01, 0x064) +#define WCD9335_I2S_FLL_STATUS_0 WCD9335_REG(0x01, 0x065) +#define WCD9335_I2S_FLL_STATUS_1 WCD9335_REG(0x01, 0x066) +#define WCD9335_I2S_FLL_STATUS_2 WCD9335_REG(0x01, 0x067) +#define WCD9335_I2S_FLL_STATUS_3 WCD9335_REG(0x01, 0x068) +#define WCD9335_SB_FLL_USER_CTL_0 WCD9335_REG(0x01, 0x081) +#define WCD9335_SB_FLL_USER_CTL_1 WCD9335_REG(0x01, 0x082) +#define WCD9335_SB_FLL_USER_CTL_2 WCD9335_REG(0x01, 0x083) +#define WCD9335_SB_FLL_USER_CTL_3 WCD9335_REG(0x01, 0x084) +#define WCD9335_SB_FLL_USER_CTL_4 WCD9335_REG(0x01, 0x085) +#define WCD9335_SB_FLL_USER_CTL_5 WCD9335_REG(0x01, 0x086) +#define WCD9335_SB_FLL_USER_CTL_6 WCD9335_REG(0x01, 0x087) +#define WCD9335_SB_FLL_USER_CTL_7 WCD9335_REG(0x01, 0x088) +#define WCD9335_SB_FLL_USER_CTL_8 WCD9335_REG(0x01, 0x089) +#define WCD9335_SB_FLL_USER_CTL_9 WCD9335_REG(0x01, 0x08a) +#define WCD9335_SB_FLL_L_VAL_CTL_0 WCD9335_REG(0x01, 0x08b) +#define WCD9335_SB_FLL_L_VAL_CTL_1 WCD9335_REG(0x01, 0x08c) +#define WCD9335_SB_FLL_DSM_FRAC_CTL_0 WCD9335_REG(0x01, 0x08d) +#define WCD9335_SB_FLL_DSM_FRAC_CTL_1 WCD9335_REG(0x01, 0x08e) +#define WCD9335_SB_FLL_CONFIG_CTL_0 WCD9335_REG(0x01, 0x08f) +#define WCD9335_SB_FLL_CONFIG_CTL_1 WCD9335_REG(0x01, 0x090) +#define WCD9335_SB_FLL_CONFIG_CTL_2 WCD9335_REG(0x01, 0x091) +#define WCD9335_SB_FLL_CONFIG_CTL_3 WCD9335_REG(0x01, 0x092) +#define WCD9335_SB_FLL_CONFIG_CTL_4 WCD9335_REG(0x01, 0x093) +#define WCD9335_SB_FLL_TEST_CTL_0 WCD9335_REG(0x01, 0x094) +#define WCD9335_SB_FLL_TEST_CTL_1 WCD9335_REG(0x01, 0x095) +#define WCD9335_SB_FLL_TEST_CTL_2 WCD9335_REG(0x01, 0x096) +#define WCD9335_SB_FLL_TEST_CTL_3 WCD9335_REG(0x01, 0x097) +#define WCD9335_SB_FLL_TEST_CTL_4 WCD9335_REG(0x01, 0x098) +#define WCD9335_SB_FLL_TEST_CTL_5 WCD9335_REG(0x01, 0x099) +#define WCD9335_SB_FLL_TEST_CTL_6 WCD9335_REG(0x01, 0x09a) +#define WCD9335_SB_FLL_TEST_CTL_7 WCD9335_REG(0x01, 0x09b) +#define WCD9335_SB_FLL_FREQ_CTL_0 WCD9335_REG(0x01, 0x09c) +#define WCD9335_SB_FLL_FREQ_CTL_1 WCD9335_REG(0x01, 0x09d) +#define WCD9335_SB_FLL_FREQ_CTL_2 WCD9335_REG(0x01, 0x09e) +#define WCD9335_SB_FLL_FREQ_CTL_3 WCD9335_REG(0x01, 0x09f) +#define WCD9335_SB_FLL_SSC_CTL_0 WCD9335_REG(0x01, 0x0a0) +#define WCD9335_SB_FLL_SSC_CTL_1 WCD9335_REG(0x01, 0x0a1) +#define WCD9335_SB_FLL_SSC_CTL_2 WCD9335_REG(0x01, 0x0a2) +#define WCD9335_SB_FLL_SSC_CTL_3 WCD9335_REG(0x01, 0x0a3) +#define WCD9335_SB_FLL_FLL_MODE WCD9335_REG(0x01, 0x0a4) +#define WCD9335_SB_FLL_STATUS_0 WCD9335_REG(0x01, 0x0a5) +#define WCD9335_SB_FLL_STATUS_1 WCD9335_REG(0x01, 0x0a6) +#define WCD9335_SB_FLL_STATUS_2 WCD9335_REG(0x01, 0x0a7) +#define WCD9335_SB_FLL_STATUS_3 WCD9335_REG(0x01, 0x0a8) + +/* Page-2 Registers */ +#define WCD9335_PAGE2_PAGE_REGISTER WCD9335_REG(0x02, 0x000) +#define WCD9335_CPE_SS_DMIC0_CTL WCD9335_REG(0x02, 0x063) +#define WCD9335_CPE_SS_DMIC1_CTL WCD9335_REG(0x02, 0x064) +#define WCD9335_CPE_SS_DMIC2_CTL WCD9335_REG(0x02, 0x065) +#define WCD9335_CPE_SS_DMIC_CFG WCD9335_REG(0x02, 0x066) +#define WCD9335_SOC_MAD_AUDIO_CTL_2 WCD9335_REG(0x02, 0x084) + +/* Page-6 Registers */ +#define WCD9335_PAGE6_PAGE_REGISTER WCD9335_REG(0x06, 0x000) +#define WCD9335_ANA_BIAS WCD9335_REG(0x06, 0x001) +#define WCD9335_ANA_BIAS_EN_MASK BIT(7) +#define WCD9335_ANA_BIAS_ENABLE BIT(7) +#define WCD9335_ANA_BIAS_DISABLE 0 +#define WCD9335_ANA_BIAS_PRECHRG_EN_MASK BIT(6) +#define WCD9335_ANA_BIAS_PRECHRG_ENABLE BIT(6) +#define WCD9335_ANA_BIAS_PRECHRG_DISABLE 0 +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE BIT(5) +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_AUTO BIT(5) +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL 0 +#define WCD9335_ANA_CLK_TOP WCD9335_REG(0x06, 0x002) +#define WCD9335_ANA_CLK_MCLK_EN_MASK BIT(2) +#define WCD9335_ANA_CLK_MCLK_ENABLE BIT(2) +#define WCD9335_ANA_CLK_MCLK_DISABLE 0 +#define WCD9335_ANA_CLK_MCLK_SRC_MASK BIT(3) +#define WCD9335_ANA_CLK_MCLK_SRC_RCO BIT(3) +#define WCD9335_ANA_CLK_MCLK_SRC_EXTERNAL 0 +#define WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK BIT(7) +#define WCD9335_ANA_CLK_EXT_CLKBUF_ENABLE BIT(7) +#define WCD9335_ANA_CLK_EXT_CLKBUF_DISABLE 0 +#define WCD9335_ANA_RCO WCD9335_REG(0x06, 0x003) +#define WCD9335_ANA_RCO_BG_EN_MASK BIT(7) +#define WCD9335_ANA_RCO_BG_ENABLE BIT(7) +#define WCD9335_ANA_BUCK_VOUT_D WCD9335_REG(0x06, 0x005) +#define WCD9335_ANA_BUCK_VOUT_MASK GENMASK(7, 0) +#define WCD9335_ANA_BUCK_CTL WCD9335_REG(0x06, 0x006) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_MASK BIT(1) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_EXT BIT(1) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_INT 0 +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_MASK BIT(2) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT BIT(2) +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_INT 0 +#define WCD9335_ANA_BUCK_CTL_RAMP_START_MASK BIT(7) +#define WCD9335_ANA_BUCK_CTL_RAMP_START_ENABLE BIT(7) +#define WCD9335_ANA_BUCK_CTL_RAMP_START_DISABLE 0 +#define WCD9335_ANA_RX_SUPPLIES WCD9335_REG(0x06, 0x008) +#define WCD9335_ANA_RX_BIAS_ENABLE_MASK BIT(0) +#define WCD9335_ANA_RX_BIAS_ENABLE BIT(0) +#define WCD9335_ANA_RX_BIAS_DISABLE 0 +#define WCD9335_ANA_HPH WCD9335_REG(0x06, 0x009) +#define WCD9335_ANA_EAR WCD9335_REG(0x06, 0x00a) +#define WCD9335_ANA_LO_1_2 WCD9335_REG(0x06, 0x00b) +#define WCD9335_ANA_LO_3_4 WCD9335_REG(0x06, 0x00c) +#define WCD9335_ANA_AMIC1 WCD9335_REG(0x06, 0x00e) +#define WCD9335_ANA_AMIC2 WCD9335_REG(0x06, 0x00f) +#define WCD9335_ANA_AMIC3 WCD9335_REG(0x06, 0x010) +#define WCD9335_ANA_AMIC4 WCD9335_REG(0x06, 0x011) +#define WCD9335_ANA_AMIC5 WCD9335_REG(0x06, 0x012) +#define WCD9335_ANA_AMIC6 WCD9335_REG(0x06, 0x013) +#define WCD9335_ANA_MBHC_MECH WCD9335_REG(0x06, 0x014) +#define WCD9335_MBHC_L_DET_EN_MASK BIT(7) +#define WCD9335_MBHC_L_DET_EN BIT(7) +#define WCD9335_MBHC_GND_DET_EN_MASK BIT(6) +#define WCD9335_MBHC_MECH_DETECT_TYPE_MASK BIT(5) +#define WCD9335_MBHC_MECH_DETECT_TYPE_SHIFT 5 +#define WCD9335_MBHC_HPHL_PLUG_TYPE_MASK BIT(4) +#define WCD9335_MBHC_HPHL_PLUG_TYPE_NO BIT(4) +#define WCD9335_MBHC_GND_PLUG_TYPE_MASK BIT(3) +#define WCD9335_MBHC_GND_PLUG_TYPE_NO BIT(3) +#define WCD9335_MBHC_HSL_PULLUP_COMP_EN BIT(2) +#define WCD9335_MBHC_HPHL_100K_TO_GND_EN BIT(0) + +#define WCD9335_ANA_MBHC_ELECT WCD9335_REG(0x06, 0x015) +#define WCD9335_ANA_MBHC_BD_ISRC_CTL_MASK GENMASK(6, 4) +#define WCD9335_ANA_MBHC_BD_ISRC_100UA GENMASK(5, 4) +#define WCD9335_ANA_MBHC_BD_ISRC_OFF 0 +#define WCD9335_ANA_MBHC_BIAS_EN_MASK BIT(0) +#define WCD9335_ANA_MBHC_BIAS_EN BIT(0) +#define WCD9335_ANA_MBHC_ZDET WCD9335_REG(0x06, 0x016) +#define WCD9335_ANA_MBHC_RESULT_1 WCD9335_REG(0x06, 0x017) +#define WCD9335_ANA_MBHC_RESULT_2 WCD9335_REG(0x06, 0x018) +#define WCD9335_ANA_MBHC_RESULT_3 WCD9335_REG(0x06, 0x019) +#define WCD9335_MBHC_BTN_RESULT_MASK GENMASK(2, 0) +#define WCD9335_ANA_MBHC_BTN0 WCD9335_REG(0x06, 0x01a) +#define WCD9335_ANA_MBHC_BTN1 WCD9335_REG(0x06, 0x01b) +#define WCD9335_ANA_MBHC_BTN2 WCD9335_REG(0x06, 0x01c) +#define WCD9335_ANA_MBHC_BTN3 WCD9335_REG(0x06, 0x01d) +#define WCD9335_ANA_MBHC_BTN4 WCD9335_REG(0x06, 0x01e) +#define WCD9335_ANA_MBHC_BTN5 WCD9335_REG(0x06, 0x01f) +#define WCD9335_ANA_MBHC_BTN6 WCD9335_REG(0x06, 0x020) +#define WCD9335_ANA_MBHC_BTN7 WCD9335_REG(0x06, 0x021) +#define WCD9335_ANA_MICB1 WCD9335_REG(0x06, 0x022) +#define WCD9335_ANA_MICB2 WCD9335_REG(0x06, 0x023) +#define WCD9335_ANA_MICB2_ENABLE BIT(6) +#define WCD9335_ANA_MICB2_RAMP WCD9335_REG(0x06, 0x024) +#define WCD9335_ANA_MICB3 WCD9335_REG(0x06, 0x025) +#define WCD9335_ANA_MICB4 WCD9335_REG(0x06, 0x026) +#define WCD9335_ANA_VBADC WCD9335_REG(0x06, 0x027) +#define WCD9335_BIAS_VBG_FINE_ADJ WCD9335_REG(0x06, 0x029) +#define WCD9335_RCO_CTRL_2 WCD9335_REG(0x06, 0x02f) +#define WCD9335_SIDO_SIDO_CCL_2 WCD9335_REG(0x06, 0x042) +#define WCD9335_SIDO_SIDO_CCL_4 WCD9335_REG(0x06, 0x044) +#define WCD9335_SIDO_SIDO_CCL_8 WCD9335_REG(0x06, 0x048) +#define WCD9335_SIDO_SIDO_CCL_10 WCD9335_REG(0x06, 0x04a) +#define WCD9335_SIDO_SIDO_CCL_10_ICHARG_PWR_SEL_C320FF 0x2 +/* Comparator 1 and 2 Bias current at 1P0UA with start pulse width of C320FF */ +#define WCD9335_SIDO_SIDO_CCL_DEF_VALUE 0x6e +#define WCD9335_SIDO_SIDO_TEST_2 WCD9335_REG(0x06, 0x055) +#define WCD9335_MBHC_CTL_1 WCD9335_REG(0x06, 0x056) +#define WCD9335_MBHC_BTN_DBNC_MASK GENMASK(1, 0) +#define WCD9335_MBHC_BTN_DBNC_T_16_MS 0x2 +#define WCD9335_MBHC_CTL_RCO_EN_MASK BIT(7) +#define WCD9335_MBHC_CTL_RCO_EN BIT(7) + +#define WCD9335_MBHC_CTL_2 WCD9335_REG(0x06, 0x057) +#define WCD9335_MBHC_HS_VREF_CTL_MASK GENMASK(1, 0) +#define WCD9335_MBHC_HS_VREF_1P5_V 0x1 +#define WCD9335_MBHC_PLUG_DETECT_CTL WCD9335_REG(0x06, 0x058) +#define WCD9335_MBHC_HSDET_PULLUP_CTL_MASK GENMASK(7, 6) +#define WCD9335_MBHC_HSDET_PULLUP_CTL_SHIFT 6 +#define WCD9335_MBHC_HSDET_PULLUP_CTL_1_2P0_UA 0x80 +#define WCD9335_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS 0x6 + +#define WCD9335_MBHC_ZDET_RAMP_CTL WCD9335_REG(0x06, 0x05a) +#define WCD9335_VBADC_IBIAS_FE WCD9335_REG(0x06, 0x05e) +#define WCD9335_FLYBACK_CTRL_1 WCD9335_REG(0x06, 0x0b1) +#define WCD9335_RX_BIAS_HPH_PA WCD9335_REG(0x06, 0x0bb) +#define WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK GENMASK(3, 0) +#define WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2 WCD9335_REG(0x06, 0x0bc) +#define WCD9335_RX_BIAS_HPH_RDAC_LDO WCD9335_REG(0x06, 0x0bd) +#define WCD9335_RX_BIAS_FLYB_BUFF WCD9335_REG(0x06, 0x0c7) +#define WCD9335_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0) +#define WCD9335_RX_BIAS_FLYB_I_0P0_UA 0 +#define WCD9335_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) +#define WCD9335_RX_BIAS_FLYB_MID_RST WCD9335_REG(0x06, 0x0c8) +#define WCD9335_HPH_CNP_WG_CTL WCD9335_REG(0x06, 0x0cc) +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK GENMASK(2, 0) +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500 0x2 +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000 0x3 +#define WCD9335_HPH_OCP_CTL WCD9335_REG(0x06, 0x0ce) +#define WCD9335_HPH_AUTO_CHOP WCD9335_REG(0x06, 0x0cf) +#define WCD9335_HPH_AUTO_CHOP_MASK BIT(5) +#define WCD9335_HPH_AUTO_CHOP_FORCE_ENABLE BIT(5) +#define WCD9335_HPH_AUTO_CHOP_ENABLE_BY_CMPDR_GAIN 0 +#define WCD9335_HPH_PA_CTL1 WCD9335_REG(0x06, 0x0d1) +#define WCD9335_HPH_PA_GM3_IB_SCALE_MASK GENMASK(3, 1) +#define WCD9335_HPH_PA_CTL2 WCD9335_REG(0x06, 0x0d2) +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK BIT(2) +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_ENABLE BIT(2) +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_DISABLE 0 +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK BIT(3) +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE BIT(3) +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE 0 +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK BIT(5) +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENABLE BIT(5) +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_DISABLE 0 +#define WCD9335_HPH_L_EN WCD9335_REG(0x06, 0x0d3) +#define WCD9335_HPH_CONST_SEL_L_MASK GENMASK(7, 6) +#define WCD9335_HPH_CONST_SEL_L_BYPASS 0 +#define WCD9335_HPH_CONST_SEL_L_LP_PATH 0x40 +#define WCD9335_HPH_CONST_SEL_L_HQ_PATH 0x80 +#define WCD9335_HPH_PA_GAIN_MASK GENMASK(4, 0) +#define WCD9335_HPH_GAIN_SRC_SEL_MASK BIT(5) +#define WCD9335_HPH_GAIN_SRC_SEL_COMPANDER 0 +#define WCD9335_HPH_GAIN_SRC_SEL_REGISTER BIT(5) +#define WCD9335_HPH_L_TEST WCD9335_REG(0x06, 0x0d4) +#define WCD9335_HPH_R_EN WCD9335_REG(0x06, 0x0d6) +#define WCD9335_HPH_R_TEST WCD9335_REG(0x06, 0x0d7) +#define WCD9335_HPH_R_ATEST WCD9335_REG(0x06, 0x0d8) +#define WCD9335_HPH_RDAC_LDO_CTL WCD9335_REG(0x06, 0x0db) +#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_MASK GENMASK(2, 0) +#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_V_N1P60 0x1 +#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_MASK GENMASK(6, 4) +#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_V_N1P60 0x10 +#define WCD9335_HPH_REFBUFF_LP_CTL WCD9335_REG(0x06, 0x0de) +#define WCD9335_HPH_L_DAC_CTL WCD9335_REG(0x06, 0x0df) +#define WCD9335_HPH_DAC_LDO_POWERMODE_MASK BIT(0) +#define WCD9335_HPH_DAC_LDO_POWERMODE_LOWPOWER 0 +#define WCD9335_HPH_DAC_LDO_POWERMODE_UHQA BIT(0) +#define WCD9335_HPH_DAC_LDO_UHQA_OV_MASK BIT(1) +#define WCD9335_HPH_DAC_LDO_UHQA_OV_ENABLE BIT(1) +#define WCD9335_HPH_DAC_LDO_UHQA_OV_DISABLE 0 + +#define WCD9335_EAR_CMBUFF WCD9335_REG(0x06, 0x0e2) +#define WCD9335_DIFF_LO_LO2_COMPANDER WCD9335_REG(0x06, 0x0ea) +#define WCD9335_DIFF_LO_LO1_COMPANDER WCD9335_REG(0x06, 0x0eb) +#define WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ WCD9335_REG(0x06, 0x0f1) +#define WCD9335_DIFF_LO_COM_PA_FREQ WCD9335_REG(0x06, 0x0f2) +#define WCD9335_SE_LO_LO3_GAIN WCD9335_REG(0x06, 0x0f8) +#define WCD9335_SE_LO_LO3_CTRL WCD9335_REG(0x06, 0x0f9) +#define WCD9335_SE_LO_LO4_GAIN WCD9335_REG(0x06, 0x0fa) + +/* Page-10 Registers */ +#define WCD9335_CDC_TX0_TX_PATH_CTL WCD9335_REG(0x0a, 0x031) +#define WCD9335_CDC_TX_PATH_CTL_PCM_RATE_MASK GENMASK(3, 0) +#define WCD9335_CDC_TX_PATH_CTL(dec) WCD9335_REG(0xa, (0x31 + dec * 0x10)) +#define WCD9335_CDC_TX0_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x032) +#define WCD9335_CDC_TX_ADC_AMIC_DMIC_SEL_MASK BIT(7) +#define WCD9335_CDC_TX_ADC_DMIC_SEL BIT(7) +#define WCD9335_CDC_TX_ADC_AMIC_SEL 0 +#define WCD9335_CDC_TX0_TX_VOL_CTL WCD9335_REG(0x0a, 0x034) +#define WCD9335_CDC_TX0_TX_PATH_SEC2 WCD9335_REG(0x0a, 0x039) +#define WCD9335_CDC_TX0_TX_PATH_SEC7 WCD9335_REG(0x0a, 0x03e) +#define WCD9335_CDC_TX1_TX_PATH_CTL WCD9335_REG(0x0a, 0x041) +#define WCD9335_CDC_TX1_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x042) +#define WCD9335_CDC_TX2_TX_PATH_CTL WCD9335_REG(0x0a, 0x051) +#define WCD9335_CDC_TX2_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x052) +#define WCD9335_CDC_TX2_TX_VOL_CTL WCD9335_REG(0x0a, 0x054) +#define WCD9335_CDC_TX3_TX_PATH_CTL WCD9335_REG(0x0a, 0x061) +#define WCD9335_CDC_TX3_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x062) +#define WCD9335_CDC_TX3_TX_VOL_CTL WCD9335_REG(0x0a, 0x064) +#define WCD9335_CDC_TX4_TX_PATH_CTL WCD9335_REG(0x0a, 0x071) +#define WCD9335_CDC_TX4_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x072) +#define WCD9335_CDC_TX4_TX_VOL_CTL WCD9335_REG(0x0a, 0x074) +#define WCD9335_CDC_TX5_TX_PATH_CTL WCD9335_REG(0x0a, 0x081) +#define WCD9335_CDC_TX5_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x082) +#define WCD9335_CDC_TX5_TX_VOL_CTL WCD9335_REG(0x0a, 0x084) +#define WCD9335_CDC_TX6_TX_PATH_CTL WCD9335_REG(0x0a, 0x091) +#define WCD9335_CDC_TX6_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x092) +#define WCD9335_CDC_TX6_TX_VOL_CTL WCD9335_REG(0x0a, 0x094) +#define WCD9335_CDC_TX7_TX_PATH_CTL WCD9335_REG(0x0a, 0x0a1) +#define WCD9335_CDC_TX7_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x0a2) +#define WCD9335_CDC_TX7_TX_VOL_CTL WCD9335_REG(0x0a, 0x0a4) +#define WCD9335_CDC_TX8_TX_PATH_CTL WCD9335_REG(0x0a, 0x0b1) +#define WCD9335_CDC_TX8_TX_PATH_CFG0 WCD9335_REG(0x0a, 0x0b2) +#define WCD9335_CDC_TX8_TX_VOL_CTL WCD9335_REG(0x0a, 0x0b4) +#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0c3) +#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0c7) +#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0cb) +#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0 WCD9335_REG(0x0a, 0x0cf) + +/* Page-11 Registers */ +#define WCD9335_PAGE11_PAGE_REGISTER WCD9335_REG(0x0b, 0x000) +#define WCD9335_CDC_COMPANDER1_CTL0 WCD9335_REG(0x0b, 0x001) +#define WCD9335_CDC_COMPANDER1_CTL(c) WCD9335_REG(0x0b, (0x001 + c * 0x8)) +#define WCD9335_CDC_COMPANDER_CLK_EN_MASK BIT(0) +#define WCD9335_CDC_COMPANDER_CLK_ENABLE BIT(0) +#define WCD9335_CDC_COMPANDER_CLK_DISABLE 0 +#define WCD9335_CDC_COMPANDER_SOFT_RST_MASK BIT(1) +#define WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE BIT(1) +#define WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE 0 +#define WCD9335_CDC_COMPANDER_HALT_MASK BIT(2) +#define WCD9335_CDC_COMPANDER_HALT BIT(2) +#define WCD9335_CDC_COMPANDER_NOHALT 0 +#define WCD9335_CDC_COMPANDER7_CTL3 WCD9335_REG(0x0b, 0x034) +#define WCD9335_CDC_COMPANDER7_CTL7 WCD9335_REG(0x0b, 0x038) +#define WCD9335_CDC_COMPANDER8_CTL3 WCD9335_REG(0x0b, 0x03c) +#define WCD9335_CDC_COMPANDER8_CTL7 WCD9335_REG(0x0b, 0x040) +#define WCD9335_CDC_RX0_RX_PATH_CTL WCD9335_REG(0x0b, 0x041) +#define WCD9335_CDC_RX_PGA_MUTE_EN_MASK BIT(4) +#define WCD9335_CDC_RX_PGA_MUTE_ENABLE BIT(4) +#define WCD9335_CDC_RX_PGA_MUTE_DISABLE 0 +#define WCD9335_CDC_RX_CLK_EN_MASK BIT(5) +#define WCD9335_CDC_RX_CLK_ENABLE BIT(5) +#define WCD9335_CDC_RX_CLK_DISABLE 0 +#define WCD9335_CDC_RX_RESET_MASK BIT(6) +#define WCD9335_CDC_RX_RESET_ENABLE BIT(6) +#define WCD9335_CDC_RX_RESET_DISABLE 0 +#define WCD9335_CDC_RX_PATH_CTL(rx) WCD9335_REG(0x0b, (0x041 + rx * 0x14)) +#define WCD9335_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x042) +#define WCD9335_CDC_RX0_RX_PATH_CFG1 WCD9335_REG(0x0b, 0x043) +#define WCD9335_CDC_RX0_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x044) +#define WCD9335_CDC_RX0_RX_VOL_CTL WCD9335_REG(0x0b, 0x045) +#define WCD9335_CDC_RX0_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x046) +#define WCD9335_CDC_MIX_PCM_RATE_MASK GENMASK(3, 0) +#define WCD9335_CDC_RX_PATH_MIX_CTL(rx) WCD9335_REG(0x0b, (0x46 + rx * 0x14)) +#define WCD9335_CDC_RX0_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x047) +#define WCD9335_CDC_RX0_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x048) +#define WCD9335_CDC_RX0_RX_PATH_SEC0 WCD9335_REG(0x0b, 0x049) +#define WCD9335_CDC_RX0_RX_PATH_SEC7 WCD9335_REG(0x0b, 0x050) +#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC0 WCD9335_REG(0x0b, 0x051) +#define WCD9335_CDC_RX1_RX_PATH_CTL WCD9335_REG(0x0b, 0x055) +#define WCD9335_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x056) +#define WCD9335_CDC_RX1_RX_PATH_CFG(c) WCD9335_REG(0x0b, (0x056 + c * 0x14)) +#define WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK BIT(1) +#define WCD9335_CDC_RX_PATH_CFG_CMP_ENABLE BIT(1) +#define WCD9335_CDC_RX_PATH_CFG_CMP_DISABLE 0 +#define WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK BIT(2) +#define WCD9335_CDC_RX_PATH_CFG_HD2_ENABLE BIT(2) +#define WCD9335_CDC_RX_PATH_CFG_HD2_DISABLE 0 +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN_MASK BIT(3) +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN BIT(3) +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_DISABLE 0 +#define WCD9335_CDC_RX1_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x058) +#define WCD9335_CDC_RX1_RX_VOL_CTL WCD9335_REG(0x0b, 0x059) +#define WCD9335_CDC_RX1_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x05a) +#define WCD9335_CDC_RX1_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x05b) +#define WCD9335_CDC_RX1_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x05c) +#define WCD9335_CDC_RX1_RX_PATH_SEC0 WCD9335_REG(0x0b, 0x05d) +#define WCD9335_CDC_RX1_RX_PATH_SEC3 WCD9335_REG(0x0b, 0x060) +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK GENMASK(1, 0) +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_2 0x1 +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_1 0 +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK GENMASK(5, 2) +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P2500 0x10 +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000 0 +#define WCD9335_CDC_RX2_RX_PATH_CTL WCD9335_REG(0x0b, 0x069) +#define WCD9335_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x06a) +#define WCD9335_CDC_RX2_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x06c) +#define WCD9335_CDC_RX2_RX_VOL_CTL WCD9335_REG(0x0b, 0x06d) +#define WCD9335_CDC_RX2_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x06e) +#define WCD9335_CDC_RX2_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x06f) +#define WCD9335_CDC_RX2_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x070) +#define WCD9335_CDC_RX2_RX_PATH_SEC0 WCD9335_REG(0x0b, 0x071) +#define WCD9335_CDC_RX_PATH_DEM_INP_SEL_MASK GENMASK(1, 0) +#define WCD9335_CDC_RX2_RX_PATH_SEC3 WCD9335_REG(0x0b, 0x074) +#define WCD9335_CDC_RX3_RX_PATH_CTL WCD9335_REG(0x0b, 0x07d) +#define WCD9335_CDC_RX3_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x07e) +#define WCD9335_CDC_RX3_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x080) +#define WCD9335_CDC_RX3_RX_VOL_CTL WCD9335_REG(0x0b, 0x081) +#define WCD9335_CDC_RX3_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x082) +#define WCD9335_CDC_RX3_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x083) +#define WCD9335_CDC_RX3_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x084) +#define WCD9335_CDC_RX4_RX_PATH_CTL WCD9335_REG(0x0b, 0x091) +#define WCD9335_CDC_RX4_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x092) +#define WCD9335_CDC_RX4_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x094) +#define WCD9335_CDC_RX4_RX_VOL_CTL WCD9335_REG(0x0b, 0x095) +#define WCD9335_CDC_RX4_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x096) +#define WCD9335_CDC_RX4_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x097) +#define WCD9335_CDC_RX4_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x098) +#define WCD9335_CDC_RX5_RX_PATH_CTL WCD9335_REG(0x0b, 0x0a5) +#define WCD9335_CDC_RX5_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0a6) +#define WCD9335_CDC_RX5_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0a8) +#define WCD9335_CDC_RX5_RX_VOL_CTL WCD9335_REG(0x0b, 0x0a9) +#define WCD9335_CDC_RX5_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0aa) +#define WCD9335_CDC_RX5_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0ab) +#define WCD9335_CDC_RX5_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0ac) +#define WCD9335_CDC_RX6_RX_PATH_CTL WCD9335_REG(0x0b, 0x0b9) +#define WCD9335_CDC_RX6_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0ba) +#define WCD9335_CDC_RX6_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0bc) +#define WCD9335_CDC_RX6_RX_VOL_CTL WCD9335_REG(0x0b, 0x0bd) +#define WCD9335_CDC_RX6_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0be) +#define WCD9335_CDC_RX6_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0bf) +#define WCD9335_CDC_RX6_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0c0) +#define WCD9335_CDC_RX7_RX_PATH_CTL WCD9335_REG(0x0b, 0x0cd) +#define WCD9335_CDC_RX7_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0ce) +#define WCD9335_CDC_RX7_RX_PATH_CFG1 WCD9335_REG(0x0b, 0x0cf) +#define WCD9335_CDC_RX7_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0d0) +#define WCD9335_CDC_RX7_RX_VOL_CTL WCD9335_REG(0x0b, 0x0d1) +#define WCD9335_CDC_RX7_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0d2) +#define WCD9335_CDC_RX7_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0d3) +#define WCD9335_CDC_RX7_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0d4) +#define WCD9335_CDC_RX8_RX_PATH_CTL WCD9335_REG(0x0b, 0x0e1) +#define WCD9335_CDC_RX8_RX_PATH_CFG0 WCD9335_REG(0x0b, 0x0e2) +#define WCD9335_CDC_RX8_RX_PATH_CFG1 WCD9335_REG(0x0b, 0x0e3) +#define WCD9335_CDC_RX8_RX_PATH_CFG2 WCD9335_REG(0x0b, 0x0e4) +#define WCD9335_CDC_RX8_RX_VOL_CTL WCD9335_REG(0x0b, 0x0e5) +#define WCD9335_CDC_RX8_RX_PATH_MIX_CTL WCD9335_REG(0x0b, 0x0e6) +#define WCD9335_CDC_RX8_RX_PATH_MIX_CFG WCD9335_REG(0x0b, 0x0e7) +#define WCD9335_CDC_RX8_RX_VOL_MIX_CTL WCD9335_REG(0x0b, 0x0e8) + +/* Page-12 Registers */ +#define WCD9335_PAGE12_PAGE_REGISTER WCD9335_REG(0x0c, 0x000) +#define WCD9335_CDC_CLSH_K2_MSB WCD9335_REG(0x0c, 0x00a) +#define WCD9335_CDC_CLSH_K2_LSB WCD9335_REG(0x0c, 0x00b) +#define WCD9335_CDC_BOOST0_BOOST_CTL WCD9335_REG(0x0c, 0x01a) +#define WCD9335_CDC_BOOST0_BOOST_CFG1 WCD9335_REG(0x0c, 0x01b) +#define WCD9335_CDC_BOOST0_BOOST_CFG2 WCD9335_REG(0x0c, 0x01c) +#define WCD9335_CDC_BOOST1_BOOST_CTL WCD9335_REG(0x0c, 0x022) +#define WCD9335_CDC_BOOST1_BOOST_CFG1 WCD9335_REG(0x0c, 0x023) +#define WCD9335_CDC_BOOST1_BOOST_CFG2 WCD9335_REG(0x0c, 0x024) + +/* Page-13 Registers */ +#define WCD9335_PAGE13_PAGE_REGISTER WCD9335_REG(0x0d, 0x000) +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0 WCD9335_REG(0x0d, 0x001) +#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG0(i) WCD9335_REG(0xd, (0x1 + i * 0x2)) +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1 WCD9335_REG(0xd, 0x002) +#define WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK GENMASK(3, 0) +#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(i) WCD9335_REG(0xd, (0x2 + i * 0x2)) + +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0 WCD9335_REG(0x0d, 0x003) +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1 WCD9335_REG(0x0d, 0x004) +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0 WCD9335_REG(0x0d, 0x005) +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1 WCD9335_REG(0x0d, 0x006) +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0 WCD9335_REG(0x0d, 0x007) +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1 WCD9335_REG(0x0d, 0x008) +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0 WCD9335_REG(0x0d, 0x009) +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1 WCD9335_REG(0x0d, 0x00a) +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0 WCD9335_REG(0x0d, 0x00b) +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1 WCD9335_REG(0x0d, 0x00c) +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0 WCD9335_REG(0x0d, 0x00d) +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1 WCD9335_REG(0x0d, 0x00e) +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0 WCD9335_REG(0x0d, 0x00f) +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1 WCD9335_REG(0x0d, 0x010) +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0 WCD9335_REG(0x0d, 0x011) +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1 WCD9335_REG(0x0d, 0x012) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 WCD9335_REG(0x0d, 0x01d) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 WCD9335_REG(0x0d, 0x01e) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0 WCD9335_REG(0x0d, 0x01f) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1 WCD9335_REG(0x0d, 0x020) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0 WCD9335_REG(0x0d, 0x021) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1 WCD9335_REG(0x0d, 0x022) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0 WCD9335_REG(0x0d, 0x023) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1 WCD9335_REG(0x0d, 0x024) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 WCD9335_REG(0x0d, 0x025) +#define WCD9335_CDC_TX_INP_MUX_SEL_AMIC 0x1 +#define WCD9335_CDC_TX_INP_MUX_SEL_DMIC 0 +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0 WCD9335_REG(0x0d, 0x026) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0 WCD9335_REG(0x0d, 0x027) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0 WCD9335_REG(0x0d, 0x028) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0 WCD9335_REG(0x0d, 0x029) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0 WCD9335_REG(0x0d, 0x02b) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0 WCD9335_REG(0x0d, 0x02c) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0 WCD9335_REG(0x0d, 0x02d) +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0 WCD9335_REG(0x0d, 0x02e) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0 WCD9335_REG(0x0d, 0x03a) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1 WCD9335_REG(0x0d, 0x03b) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2 WCD9335_REG(0x0d, 0x03c) +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3 WCD9335_REG(0x0d, 0x03d) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0x0d, 0x041) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_ENABLE BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_DISABLE 0 +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL WCD9335_REG(0x0d, 0x042) +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_EN_MASK BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_ENABLE BIT(0) +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_DISABLE 0 +#define WCD9335_CDC_TOP_TOP_CFG1 WCD9335_REG(0x0d, 0x082) +#define WCD9335_MAX_REGISTER WCD9335_REG(0x80, 0x0FF) + +/* SLIMBUS Slave Registers */ +#define WCD9335_SLIM_PGD_PORT_INT_EN0 WCD9335_REG(0, 0x30) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0 WCD9335_REG(0, 0x34) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_1 WCD9335_REG(0, 0x35) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_0 WCD9335_REG(0, 0x36) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1 WCD9335_REG(0, 0x37) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0 WCD9335_REG(0, 0x38) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_1 WCD9335_REG(0, 0x39) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_0 WCD9335_REG(0, 0x3A) +#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_1 WCD9335_REG(0, 0x3B) +#define WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 WCD9335_REG(0, 0x60) +#define WCD9335_SLIM_PGD_PORT_INT_TX_SOURCE0 WCD9335_REG(0, 0x70) +#define WCD9335_SLIM_PGD_RX_PORT_CFG(p) WCD9335_REG(0, (0x30 + p)) +#define WCD9335_SLIM_PGD_PORT_CFG(p) WCD9335_REG(0, (0x40 + p)) +#define WCD9335_SLIM_PGD_TX_PORT_CFG(p) WCD9335_REG(0, (0x50 + p)) +#define WCD9335_SLIM_PGD_PORT_INT_SRC(p) WCD9335_REG(0, (0x60 + p)) +#define WCD9335_SLIM_PGD_PORT_INT_STATUS(p) WCD9335_REG(0, (0x80 + p)) +#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x100 + 4 * p)) +/* ports range from 10-16 */ +#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_1(p) WCD9335_REG(0, (0x101 + 4 * p)) +#define WCD9335_SLIM_PGD_RX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x140 + 4 * p)) + +#define WCD9335_IRQ_SLIMBUS 0 +#define WCD9335_IRQ_MBHC_SW_DET 8 +#define WCD9335_IRQ_MBHC_ELECT_INS_REM_DET 9 +#define WCD9335_IRQ_MBHC_BUTTON_PRESS_DET 10 +#define WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET 11 +#define WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET 12 + +#define SLIM_MANF_ID_QCOM 0x217 +#define SLIM_PROD_CODE_WCD9335 0x1a0 + +#define WCD9335_VERSION_2_0 2 +#define WCD9335_MAX_SUPPLY 5 + +#endif /* __WCD9335_H__ */ -- cgit v1.2.3-58-ga151 From cc2e324d39b26d62599d056f5cb905a025b909a3 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:48 +0000 Subject: ASoC: wcd9335: add CLASS-H Controller support CLASS-H controller/Amplifier is common accorss Qualcomm WCD codec series. This patchset adds basic CLASS-H controller apis for WCD codecs after wcd9335 to use. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/Makefile | 2 +- sound/soc/codecs/wcd-clsh-v2.c | 576 +++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd-clsh-v2.h | 49 ++++ sound/soc/codecs/wcd9335.c | 10 + 4 files changed, 636 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/wcd-clsh-v2.c create mode 100644 sound/soc/codecs/wcd-clsh-v2.h diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 342d057cd7fc..4cf29e3dbff6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -201,7 +201,7 @@ snd-soc-twl4030-objs := twl4030.o snd-soc-twl6040-objs := twl6040.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o -snd-soc-wcd9335-objs := wcd9335.o +snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c new file mode 100644 index 000000000000..1bd70c5a7b63 --- /dev/null +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +// Copyright (c) 2017-2018, Linaro Limited + +#include +#include +#include +#include +#include "wcd9335.h" +#include "wcd-clsh-v2.h" + +struct wcd_clsh_ctrl { + int state; + int mode; + int flyback_users; + int buck_users; + int clsh_users; + int codec_version; + struct snd_soc_component *comp; +}; + +/* Class-H registers for codecs from and above WCD9335 */ +#define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0xB, 0x42) +#define WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK BIT(6) +#define WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE BIT(6) +#define WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE 0 +#define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0xB, 0x56) +#define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0xB, 0x6A) +#define WCD9XXX_A_CDC_CLSH_K1_MSB WCD9335_REG(0xC, 0x08) +#define WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK GENMASK(3, 0) +#define WCD9XXX_A_CDC_CLSH_K1_LSB WCD9335_REG(0xC, 0x09) +#define WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK GENMASK(7, 0) +#define WCD9XXX_A_ANA_RX_SUPPLIES WCD9335_REG(0x6, 0x08) +#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK BIT(1) +#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H 0 +#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB BIT(1) +#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK BIT(2) +#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA BIT(2) +#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT 0 +#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK BIT(3) +#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA BIT(3) +#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT 0 +#define WCD9XXX_A_ANA_RX_VNEG_EN_MASK BIT(6) +#define WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT 6 +#define WCD9XXX_A_ANA_RX_VNEG_ENABLE BIT(6) +#define WCD9XXX_A_ANA_RX_VNEG_DISABLE 0 +#define WCD9XXX_A_ANA_RX_VPOS_EN_MASK BIT(7) +#define WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT 7 +#define WCD9XXX_A_ANA_RX_VPOS_ENABLE BIT(7) +#define WCD9XXX_A_ANA_RX_VPOS_DISABLE 0 +#define WCD9XXX_A_ANA_HPH WCD9335_REG(0x6, 0x09) +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK GENMASK(3, 2) +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA 0x08 +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP 0x04 +#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL 0x0 +#define WCD9XXX_A_CDC_CLSH_CRC WCD9335_REG(0xC, 0x01) +#define WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK BIT(0) +#define WCD9XXX_A_CDC_CLSH_CRC_CLK_ENABLE BIT(0) +#define WCD9XXX_A_CDC_CLSH_CRC_CLK_DISABLE 0 +#define WCD9XXX_FLYBACK_EN WCD9335_REG(0x6, 0xA4) +#define WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK GENMASK(6, 5) +#define WCD9XXX_FLYBACK_EN_DELAY_26P25_US 0x40 +#define WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK BIT(4) +#define WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY BIT(4) +#define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0 +#define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7) +#define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) +#define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(0, 3) +#define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3) +#define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3) +#define WCD9XXX_HPH_CONST_SEL_BYPASS 0 +#define WCD9XXX_HPH_CONST_SEL_LP_PATH 0x40 +#define WCD9XXX_HPH_CONST_SEL_HQ_PATH 0x80 +#define WCD9XXX_HPH_R_EN WCD9335_REG(0x6, 0xD6) +#define WCD9XXX_HPH_REFBUFF_UHQA_CTL WCD9335_REG(0x6, 0xDD) +#define WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK GENMASK(2, 0) +#define WCD9XXX_CLASSH_CTRL_VCL_2 WCD9335_REG(0x6, 0x9B) +#define WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK GENMASK(5, 4) +#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM 0x20 +#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM 0x0 +#define WCD9XXX_CDC_RX1_RX_PATH_CTL WCD9335_REG(0xB, 0x55) +#define WCD9XXX_CDC_RX2_RX_PATH_CTL WCD9335_REG(0xB, 0x69) +#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0xD, 0x41) +#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0) +#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK BIT(1) +#define WCD9XXX_CLASSH_CTRL_CCL_1 WCD9335_REG(0x6, 0x9C) +#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK GENMASK(7, 4) +#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50 +#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30 + +#define CLSH_REQ_ENABLE true +#define CLSH_REQ_DISABLE false +#define WCD_USLEEP_RANGE 50 + +enum { + DAC_GAIN_0DB = 0, + DAC_GAIN_0P2DB, + DAC_GAIN_0P4DB, + DAC_GAIN_0P6DB, + DAC_GAIN_0P8DB, + DAC_GAIN_M0P2DB, + DAC_GAIN_M0P4DB, + DAC_GAIN_M0P6DB, +}; + +static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl, + bool enable) +{ + struct snd_soc_component *comp = ctrl->comp; + + if ((enable && ++ctrl->clsh_users == 1) || + (!enable && --ctrl->clsh_users == 0)) + snd_soc_component_update_bits(comp, WCD9XXX_A_CDC_CLSH_CRC, + WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK, + enable); + if (ctrl->clsh_users < 0) + ctrl->clsh_users = 0; +} + +static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp) +{ + return snd_soc_component_read32(comp, WCD9XXX_A_CDC_CLSH_CRC) & + WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK; +} + +static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, + int mode) +{ + /* set to HIFI */ + if (mode == CLS_H_HIFI) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA); + else + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT); +} + +static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp, + int mode) +{ + /* set to HIFI */ + if (mode == CLS_H_HIFI) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA); + else + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, + WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT); +} + +static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + struct snd_soc_component *comp = ctrl->comp; + + /* enable/disable buck */ + if ((enable && (++ctrl->buck_users == 1)) || + (!enable && (--ctrl->buck_users == 0))) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VPOS_EN_MASK, + enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT); + /* + * 500us sleep is required after buck enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); +} + +static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + struct snd_soc_component *comp = ctrl->comp; + + /* enable/disable flyback */ + if ((enable && (++ctrl->flyback_users == 1)) || + (!enable && (--ctrl->flyback_users == 0))) { + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_VNEG_EN_MASK, + enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT); + /* 100usec delay is needed as per HW requirement */ + usleep_range(100, 110); + } + /* + * 500us sleep is required after flyback enable/disable + * as per HW requirement + */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); +} + +static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + int val = 0; + + switch (mode) { + case CLS_H_NORMAL: + case CLS_AB: + val = WCD9XXX_HPH_CONST_SEL_BYPASS; + break; + case CLS_H_HIFI: + val = WCD9XXX_HPH_CONST_SEL_HQ_PATH; + break; + case CLS_H_LP: + val = WCD9XXX_HPH_CONST_SEL_LP_PATH; + break; + }; + + snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN, + WCD9XXX_HPH_CONST_SEL_L_MASK, + val); + + snd_soc_component_update_bits(comp, WCD9XXX_HPH_R_EN, + WCD9XXX_HPH_CONST_SEL_L_MASK, + val); +} + +static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, + int mode) +{ + int val = 0, gain = 0, res_val; + int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + + res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM; + switch (mode) { + case CLS_H_NORMAL: + res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM; + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; + gain = DAC_GAIN_0DB; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + break; + case CLS_AB: + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; + gain = DAC_GAIN_0DB; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + break; + case CLS_H_HIFI: + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA; + gain = DAC_GAIN_M0P2DB; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; + break; + case CLS_H_LP: + val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP; + ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA; + break; + }; + + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH, + WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val); + snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2, + WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK, + res_val); + if (mode != CLS_H_LP) + snd_soc_component_update_bits(comp, + WCD9XXX_HPH_REFBUFF_UHQA_CTL, + WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK, + gain); + snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1, + WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK, + ipeak); +} + +static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp, + int mode) +{ + + snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, + WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A); + snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, + WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A); + /* Sleep needed to avoid click and pop as per HW requirement */ + usleep_range(100, 110); +} + +static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp, + int mode) +{ + if (mode == CLS_AB) + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB); + else + snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, + WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H); +} + +static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode != CLS_AB) { + dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n", + __func__, mode); + return; + } + + if (is_enable) { + wcd_clsh_set_buck_regulator_mode(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + } else { + wcd_clsh_buck_ctrl(ctrl, mode, false); + wcd_clsh_flyback_ctrl(ctrl, mode, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB) { + wcd_enable_clsh_block(ctrl, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_MSB, + WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, + 0x00); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_LSB, + WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, + 0xC0); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } + wcd_clsh_set_buck_regulator_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_set_gain_path(ctrl, mode); + } else { + wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + + if (mode != CLS_AB) { + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + wcd_enable_clsh_block(ctrl, false); + } + /* buck and flyback set to default mode and disable */ + wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n", + __func__); + return; + } + + if (is_enable) { + if (mode != CLS_AB) { + wcd_enable_clsh_block(ctrl, true); + /* + * These K1 values depend on the Headphone Impedance + * For now it is assumed to be 16 ohm + */ + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_MSB, + WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, + 0x00); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_CLSH_K1_LSB, + WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, + 0xC0); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + } + wcd_clsh_set_buck_regulator_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_set_gain_path(ctrl, mode); + } else { + wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + + if (mode != CLS_AB) { + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + wcd_enable_clsh_block(ctrl, false); + } + /* set buck and flyback to Default Mode */ + wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); + } +} + +static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (mode != CLS_H_NORMAL) { + dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n", + __func__, mode); + return; + } + + if (is_enable) { + wcd_enable_clsh_block(ctrl, true); + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); + wcd_clsh_set_buck_mode(comp, mode); + wcd_clsh_set_flyback_mode(comp, mode); + wcd_clsh_flyback_ctrl(ctrl, mode, true); + wcd_clsh_set_flyback_current(comp, mode); + wcd_clsh_buck_ctrl(ctrl, mode, true); + } else { + snd_soc_component_update_bits(comp, + WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, + WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, + WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); + wcd_enable_clsh_block(ctrl, false); + wcd_clsh_buck_ctrl(ctrl, mode, false); + wcd_clsh_flyback_ctrl(ctrl, mode, false); + wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); + wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); + } +} + +static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + switch (req_state) { + case WCD_CLSH_STATE_EAR: + wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPHL: + wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_HPHR: + wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); + break; + break; + case WCD_CLSH_STATE_LO: + wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); + break; + default: + break; + } + + return 0; +} + +/* + * Function: wcd_clsh_is_state_valid + * Params: state + * Description: + * Provides information on valid states of Class H configuration + */ +static bool wcd_clsh_is_state_valid(int state) +{ + switch (state) { + case WCD_CLSH_STATE_IDLE: + case WCD_CLSH_STATE_EAR: + case WCD_CLSH_STATE_HPHL: + case WCD_CLSH_STATE_HPHR: + case WCD_CLSH_STATE_LO: + return true; + default: + return false; + }; +} + +/* + * Function: wcd_clsh_fsm + * Params: ctrl, req_state, req_type, clsh_event + * Description: + * This function handles PRE DAC and POST DAC conditions of different devices + * and updates class H configuration of different combination of devices + * based on validity of their states. ctrl will contain current + * class h state information + */ +int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + enum wcd_clsh_event clsh_event, + int nstate, + enum wcd_clsh_mode mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (nstate == ctrl->state) + return 0; + + if (!wcd_clsh_is_state_valid(nstate)) { + dev_err(comp->dev, "Class-H not a valid new state:\n"); + return -EINVAL; + } + + switch (clsh_event) { + case WCD_CLSH_EVENT_PRE_DAC: + _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode); + break; + case WCD_CLSH_EVENT_POST_PA: + _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode); + break; + }; + + ctrl->state = nstate; + ctrl->mode = mode; + + return 0; +} + +int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl) +{ + return ctrl->state; +} + +struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, + int version) +{ + struct wcd_clsh_ctrl *ctrl; + + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return ERR_PTR(-ENOMEM); + + ctrl->state = WCD_CLSH_STATE_IDLE; + ctrl->comp = comp; + + return ctrl; +} + +void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl) +{ + kfree(ctrl); +} diff --git a/sound/soc/codecs/wcd-clsh-v2.h b/sound/soc/codecs/wcd-clsh-v2.h new file mode 100644 index 000000000000..a902f9893467 --- /dev/null +++ b/sound/soc/codecs/wcd-clsh-v2.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _WCD_CLSH_V2_H_ +#define _WCD_CLSH_V2_H_ +#include + +enum wcd_clsh_event { + WCD_CLSH_EVENT_PRE_DAC = 1, + WCD_CLSH_EVENT_POST_PA, +}; + +/* + * Basic states for Class H state machine. + * represented as a bit mask within a u8 data type + * bit 0: EAR mode + * bit 1: HPH Left mode + * bit 2: HPH Right mode + * bit 3: Lineout mode + */ +#define WCD_CLSH_STATE_IDLE 0 +#define WCD_CLSH_STATE_EAR BIT(0) +#define WCD_CLSH_STATE_HPHL BIT(1) +#define WCD_CLSH_STATE_HPHR BIT(2) +#define WCD_CLSH_STATE_LO BIT(3) +#define WCD_CLSH_STATE_MAX 4 +#define NUM_CLSH_STATES_V2 BIT(WCD_CLSH_STATE_MAX) + +enum wcd_clsh_mode { + CLS_H_NORMAL = 0, /* Class-H Default */ + CLS_H_HIFI, /* Class-H HiFi */ + CLS_H_LP, /* Class-H Low Power */ + CLS_AB, /* Class-AB */ + CLS_H_LOHIFI, /* LoHIFI */ + CLS_NONE, /* None of the above modes */ +}; + +struct wcd_clsh_ctrl; + +extern struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc( + struct snd_soc_component *component, + int version); +extern void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl); +extern int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl); +extern int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, + enum wcd_clsh_event event, + int state, + enum wcd_clsh_mode mode); + +#endif /* _WCD_CLSH_V2_H_ */ diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index d6b690af7f09..3fdf4d8f310f 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -22,6 +22,7 @@ #include #include #include "wcd9335.h" +#include "wcd-clsh-v2.h" #define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ @@ -181,6 +182,7 @@ struct wcd9335_codec { int sido_ccl_cnt; enum wcd_clock_type clk_type; + struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; int intr1; int reset_gpio; @@ -1109,6 +1111,13 @@ static int wcd9335_codec_probe(struct snd_soc_component *component) int i; snd_soc_component_init_regmap(component, wcd->regmap); + /* Class-H Init*/ + wcd->clsh_ctrl = wcd_clsh_ctrl_alloc(component, wcd->version); + if (IS_ERR(wcd->clsh_ctrl)) + return PTR_ERR(wcd->clsh_ctrl); + + /* Default HPH Mode to Class-H HiFi */ + wcd->hph_mode = CLS_H_HIFI; wcd->component = component; wcd9335_codec_init(component); @@ -1123,6 +1132,7 @@ static void wcd9335_codec_remove(struct snd_soc_component *comp) { struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + wcd_clsh_ctrl_free(wcd->clsh_ctrl); free_irq(regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS), wcd); } -- cgit v1.2.3-58-ga151 From 8c4f021d806ac52902856d7cbd148a4b24a88f59 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:49 +0000 Subject: ASoC: wcd9335: add basic controls This patch adds basic controls found in wcd9335 codec. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 325 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 3fdf4d8f310f..66d634764d28 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -105,6 +105,18 @@ enum { NUM_CODEC_DAIS, }; +enum { + COMPANDER_1, /* HPH_L */ + COMPANDER_2, /* HPH_R */ + COMPANDER_3, /* LO1_DIFF */ + COMPANDER_4, /* LO2_DIFF */ + COMPANDER_5, /* LO3_SE */ + COMPANDER_6, /* LO4_SE */ + COMPANDER_7, /* SWR SPK CH1 */ + COMPANDER_8, /* SWR SPK CH2 */ + COMPANDER_MAX, +}; + enum { INTn_2_INP_SEL_ZERO = 0, INTn_2_INP_SEL_RX0, @@ -184,6 +196,8 @@ struct wcd9335_codec { struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; + int comp_enabled[COMPANDER_MAX]; + int intr1; int reset_gpio; struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; @@ -301,6 +315,111 @@ static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init[] = { {WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02}, }; +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static const char * const rx_cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ", + "CF_NEG_3DB_0P48HZ" +}; + +static const char * const rx_hph_mode_mux_text[] = { + "Class H Invalid", "Class-H Hi-Fi", "Class-H Low Power", "Class-AB", + "Class-H Hi-Fi Low Power" +}; + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); +static const DECLARE_TLV_DB_SCALE(ear_pa_gain, 0, 150, 0); + +static const struct soc_enum cf_dec0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX0_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX1_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX2_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX3_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX4_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX5_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX6_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX7_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_dec8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX8_TX_PATH_CFG0, 5, 3, cf_text); + +static const struct soc_enum cf_int0_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int1_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int2_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int3_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int4_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int5_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int5_2_enum, WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int6_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int6_2_enum, WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int7_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum cf_int8_1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CFG2, 0, 4, rx_cf_text); + +static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, int rate_val, u32 rate) @@ -697,6 +816,210 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = { }, }; +static int wcd9335_get_compander(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + int comp = ((struct soc_mixer_control *)kc->private_value)->shift; + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + ucontrol->value.integer.value[0] = wcd->comp_enabled[comp]; + return 0; +} + +static int wcd9335_set_compander(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int comp = ((struct soc_mixer_control *) kc->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + int sel; + + wcd->comp_enabled[comp] = value; + sel = value ? WCD9335_HPH_GAIN_SRC_SEL_COMPANDER : + WCD9335_HPH_GAIN_SRC_SEL_REGISTER; + + /* Any specific register configuration for compander */ + switch (comp) { + case COMPANDER_1: + /* Set Gain Source Select based on compander enable/disable */ + snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_2: + snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_5: + snd_soc_component_update_bits(component, WCD9335_SE_LO_LO3_GAIN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + case COMPANDER_6: + snd_soc_component_update_bits(component, WCD9335_SE_LO_LO4_GAIN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, sel); + break; + default: + break; + }; + + return 0; +} + +static int wcd9335_rx_hph_mode_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + + ucontrol->value.enumerated.item[0] = wcd->hph_mode; + + return 0; +} + +static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + u32 mode_val; + + mode_val = ucontrol->value.enumerated.item[0]; + + if (mode_val == 0) { + dev_err(wcd->dev, "Invalid HPH Mode, default to ClSH HiFi\n"); + mode_val = CLS_H_HIFI; + } + wcd->hph_mode = mode_val; + + return 0; +} + +static const struct snd_kcontrol_new wcd9335_snd_controls[] = { + /* -84dB min - 40dB max */ + SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume", + WCD9335_CDC_RX0_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume", + WCD9335_CDC_RX1_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume", + WCD9335_CDC_RX2_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume", + WCD9335_CDC_RX3_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume", + WCD9335_CDC_RX4_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume", + WCD9335_CDC_RX5_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume", + WCD9335_CDC_RX6_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume", + WCD9335_CDC_RX7_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume", + WCD9335_CDC_RX8_RX_VOL_MIX_CTL, + 0, -84, 40, digital_gain), + SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum), + SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum), + SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum), + SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum), + SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum), + SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum), + SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum), + SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum), + SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum), + SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum), + SOC_ENUM("RX INT5_1 HPF cut off", cf_int5_1_enum), + SOC_ENUM("RX INT5_2 HPF cut off", cf_int5_2_enum), + SOC_ENUM("RX INT6_1 HPF cut off", cf_int6_1_enum), + SOC_ENUM("RX INT6_2 HPF cut off", cf_int6_2_enum), + SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum), + SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum), + SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum), + SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum), + SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP5 Switch", SND_SOC_NOPM, COMPANDER_5, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP6 Switch", SND_SOC_NOPM, COMPANDER_6, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0, + wcd9335_get_compander, wcd9335_set_compander), + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd9335_rx_hph_mode_get, wcd9335_rx_hph_mode_put), + + /* Gain Controls */ + SOC_SINGLE_TLV("EAR PA Volume", WCD9335_ANA_EAR, 4, 4, 1, + ear_pa_gain), + SOC_SINGLE_TLV("HPHL Volume", WCD9335_HPH_L_EN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD9335_HPH_R_EN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("LINEOUT1 Volume", WCD9335_DIFF_LO_LO1_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT2 Volume", WCD9335_DIFF_LO_LO2_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT3 Volume", WCD9335_SE_LO_LO3_GAIN, 0, 20, 1, + line_gain), + SOC_SINGLE_TLV("LINEOUT4 Volume", WCD9335_SE_LO_LO4_GAIN, 0, 20, 1, + line_gain), + + SOC_SINGLE_TLV("ADC1 Volume", WCD9335_ANA_AMIC1, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD9335_ANA_AMIC2, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD9335_ANA_AMIC3, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD9335_ANA_AMIC4, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC5 Volume", WCD9335_ANA_AMIC5, 0, 20, 0, + analog_gain), + SOC_SINGLE_TLV("ADC6 Volume", WCD9335_ANA_AMIC6, 0, 20, 0, + analog_gain), + + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + SOC_ENUM("TX5 HPF cut off", cf_dec5_enum), + SOC_ENUM("TX6 HPF cut off", cf_dec6_enum), + SOC_ENUM("TX7 HPF cut off", cf_dec7_enum), + SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), +}; + static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) { struct wcd9335_codec *wcd = data; @@ -1162,6 +1485,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .probe = wcd9335_codec_probe, .remove = wcd9335_codec_remove, .set_sysclk = wcd9335_codec_set_sysclk, + .controls = wcd9335_snd_controls, + .num_controls = ARRAY_SIZE(wcd9335_snd_controls), }; static int wcd9335_probe(struct wcd9335_codec *wcd) -- cgit v1.2.3-58-ga151 From 354461486f66e4311d9412c53205d773aac85b78 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:50 +0000 Subject: ASoC: wcd9335: add playback dapm widgets This patch adds required dapm widgets for playback. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 1795 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1795 insertions(+) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 66d634764d28..aa430cf27b19 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -147,6 +147,18 @@ enum { }; +enum { + INTERP_EAR = 0, + INTERP_HPHL, + INTERP_HPHR, + INTERP_LO1, + INTERP_LO2, + INTERP_LO3, + INTERP_LO4, + INTERP_SPKR1, + INTERP_SPKR2, +}; + enum wcd_clock_type { WCD_CLK_OFF, WCD_CLK_RCO, @@ -196,11 +208,19 @@ struct wcd9335_codec { struct wcd_clsh_ctrl *clsh_ctrl; u32 hph_mode; + int prim_int_users[WCD9335_NUM_INTERPOLATORS]; + int comp_enabled[COMPANDER_MAX]; int intr1; int reset_gpio; struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; + + unsigned int rx_port_value; + int hph_l_gain; + int hph_r_gain; + u32 rx_bias_count; + }; struct wcd9335_irq { @@ -325,11 +345,70 @@ static const char * const rx_cf_text[] = { "CF_NEG_3DB_0P48HZ" }; +static const char * const rx_int0_7_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7", "PROXIMITY" +}; + +static const char * const rx_int_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7" +}; + +static const char * const rx_prim_mix_text[] = { + "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2", + "RX3", "RX4", "RX5", "RX6", "RX7" +}; + +static const char * const rx_int_dem_inp_mux_text[] = { + "NORMAL_DSM_OUT", "CLSH_DSM_OUT", +}; + +static const char * const rx_int0_interp_mux_text[] = { + "ZERO", "RX INT0 MIX2", +}; + +static const char * const rx_int1_interp_mux_text[] = { + "ZERO", "RX INT1 MIX2", +}; + +static const char * const rx_int2_interp_mux_text[] = { + "ZERO", "RX INT2 MIX2", +}; + +static const char * const rx_int3_interp_mux_text[] = { + "ZERO", "RX INT3 MIX2", +}; + +static const char * const rx_int4_interp_mux_text[] = { + "ZERO", "RX INT4 MIX2", +}; + +static const char * const rx_int5_interp_mux_text[] = { + "ZERO", "RX INT5 MIX2", +}; + +static const char * const rx_int6_interp_mux_text[] = { + "ZERO", "RX INT6 MIX2", +}; + +static const char * const rx_int7_interp_mux_text[] = { + "ZERO", "RX INT7 MIX2", +}; + +static const char * const rx_int8_interp_mux_text[] = { + "ZERO", "RX INT8 SEC MIX" +}; + static const char * const rx_hph_mode_mux_text[] = { "Class H Invalid", "Class-H Hi-Fi", "Class-H Low Power", "Class-AB", "Class-H Hi-Fi Low Power" }; +static const char *const slim_rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB", +}; + static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -420,6 +499,455 @@ static const struct soc_enum rx_hph_mode_mux_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text); +static const struct soc_enum slim_rx_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text); + +static const struct soc_enum rx_int0_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, 10, + rx_int0_7_mix_mux_text); + +static const struct soc_enum rx_int1_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int2_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int3_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int4_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int5_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int6_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int7_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, 10, + rx_int0_7_mix_mux_text); + +static const struct soc_enum rx_int8_2_mux_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, 9, + rx_int_mix_mux_text); + +static const struct soc_enum rx_int0_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int1_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int2_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int3_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int4_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int5_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int6_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int7_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int8_1_mix_inp2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, 13, + rx_prim_mix_text); + +static const struct soc_enum rx_int0_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int1_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int2_dem_inp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_SEC0, 0, + ARRAY_SIZE(rx_int_dem_inp_mux_text), + rx_int_dem_inp_mux_text); + +static const struct soc_enum rx_int0_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CTL, 5, 2, + rx_int0_interp_mux_text); + +static const struct soc_enum rx_int1_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CTL, 5, 2, + rx_int1_interp_mux_text); + +static const struct soc_enum rx_int2_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CTL, 5, 2, + rx_int2_interp_mux_text); + +static const struct soc_enum rx_int3_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CTL, 5, 2, + rx_int3_interp_mux_text); + +static const struct soc_enum rx_int4_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CTL, 5, 2, + rx_int4_interp_mux_text); + +static const struct soc_enum rx_int5_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CTL, 5, 2, + rx_int5_interp_mux_text); + +static const struct soc_enum rx_int6_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CTL, 5, 2, + rx_int6_interp_mux_text); + +static const struct soc_enum rx_int7_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CTL, 5, 2, + rx_int7_interp_mux_text); + +static const struct soc_enum rx_int8_interp_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2, + rx_int8_interp_mux_text); + +static const struct snd_kcontrol_new rx_int0_2_mux = + SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int1_2_mux = + SOC_DAPM_ENUM("RX INT1_2 MUX Mux", rx_int1_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int2_2_mux = + SOC_DAPM_ENUM("RX INT2_2 MUX Mux", rx_int2_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int3_2_mux = + SOC_DAPM_ENUM("RX INT3_2 MUX Mux", rx_int3_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int4_2_mux = + SOC_DAPM_ENUM("RX INT4_2 MUX Mux", rx_int4_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int5_2_mux = + SOC_DAPM_ENUM("RX INT5_2 MUX Mux", rx_int5_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int6_2_mux = + SOC_DAPM_ENUM("RX INT6_2 MUX Mux", rx_int6_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int7_2_mux = + SOC_DAPM_ENUM("RX INT7_2 MUX Mux", rx_int7_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int8_2_mux = + SOC_DAPM_ENUM("RX INT8_2 MUX Mux", rx_int8_2_mux_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP0 Mux", rx_int0_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP1 Mux", rx_int0_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT0_1 MIX1 INP2 Mux", rx_int0_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP0 Mux", rx_int1_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP1 Mux", rx_int1_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT1_1 MIX1 INP2 Mux", rx_int1_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP0 Mux", rx_int2_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP1 Mux", rx_int2_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT2_1 MIX1 INP2 Mux", rx_int2_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP0 Mux", rx_int3_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP1 Mux", rx_int3_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int3_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT3_1 MIX1 INP2 Mux", rx_int3_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP0 Mux", rx_int4_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP1 Mux", rx_int4_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int4_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT4_1 MIX1 INP2 Mux", rx_int4_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP0 Mux", rx_int5_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP1 Mux", rx_int5_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int5_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT5_1 MIX1 INP2 Mux", rx_int5_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP0 Mux", rx_int6_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP1 Mux", rx_int6_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int6_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT6_1 MIX1 INP2 Mux", rx_int6_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP0 Mux", rx_int7_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP1 Mux", rx_int7_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int7_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT7_1 MIX1 INP2 Mux", rx_int7_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp0_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP0 Mux", rx_int8_1_mix_inp0_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp1_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP1 Mux", rx_int8_1_mix_inp1_chain_enum); + +static const struct snd_kcontrol_new rx_int8_1_mix_inp2_mux = + SOC_DAPM_ENUM("RX INT8_1 MIX1 INP2 Mux", rx_int8_1_mix_inp2_chain_enum); + +static const struct snd_kcontrol_new rx_int0_interp_mux = + SOC_DAPM_ENUM("RX INT0 INTERP Mux", rx_int0_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int1_interp_mux = + SOC_DAPM_ENUM("RX INT1 INTERP Mux", rx_int1_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int2_interp_mux = + SOC_DAPM_ENUM("RX INT2 INTERP Mux", rx_int2_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int3_interp_mux = + SOC_DAPM_ENUM("RX INT3 INTERP Mux", rx_int3_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int4_interp_mux = + SOC_DAPM_ENUM("RX INT4 INTERP Mux", rx_int4_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int5_interp_mux = + SOC_DAPM_ENUM("RX INT5 INTERP Mux", rx_int5_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int6_interp_mux = + SOC_DAPM_ENUM("RX INT6 INTERP Mux", rx_int6_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int7_interp_mux = + SOC_DAPM_ENUM("RX INT7 INTERP Mux", rx_int7_interp_mux_enum); + +static const struct snd_kcontrol_new rx_int8_interp_mux = + SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum); + +static int slim_rx_mux_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev); + + ucontrol->value.enumerated.item[0] = wcd->rx_port_value; + + return 0; +} + +static int slim_rx_mux_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(w->dapm->dev); + struct soc_enum *e = (struct soc_enum *)kc->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 port_id = w->shift; + + wcd->rx_port_value = ucontrol->value.enumerated.item[0]; + + switch (wcd->rx_port_value) { + case 0: + list_del_init(&wcd->rx_chs[port_id].list); + break; + case 1: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF1_PB].slim_ch_list); + break; + case 2: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF2_PB].slim_ch_list); + break; + case 3: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF3_PB].slim_ch_list); + break; + case 4: + list_add_tail(&wcd->rx_chs[port_id].list, + &wcd->dai[AIF4_PB].slim_ch_list); + break; + default: + dev_err(wcd->dev, "Unknown AIF %d\n", wcd->rx_port_value); + goto err; + } + + snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value, + e, update); + + return 0; +err: + return -EINVAL; +} + +static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = { + SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), + SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum, + slim_rx_mux_get, slim_rx_mux_put), +}; + +static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kc->private_value; + struct snd_soc_component *component; + int reg, val; + + component = snd_soc_dapm_kcontrol_component(kc); + val = ucontrol->value.enumerated.item[0]; + + if (e->reg == WCD9335_CDC_RX0_RX_PATH_SEC0) + reg = WCD9335_CDC_RX0_RX_PATH_CFG0; + else if (e->reg == WCD9335_CDC_RX1_RX_PATH_SEC0) + reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + else if (e->reg == WCD9335_CDC_RX2_RX_PATH_SEC0) + reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + else + return -EINVAL; + + /* Set Look Ahead Delay */ + snd_soc_component_update_bits(component, reg, + WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN_MASK, + val ? WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN : 0); + /* Set DEM INP Select */ + return snd_soc_dapm_put_enum_double(kc, ucontrol); +} + +static const struct snd_kcontrol_new rx_int0_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT0 DEM MUX Mux", rx_int0_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + wcd9335_int_dem_inp_mux_put); + +static const struct snd_kcontrol_new rx_int1_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT1 DEM MUX Mux", rx_int1_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + wcd9335_int_dem_inp_mux_put); + +static const struct snd_kcontrol_new rx_int2_dem_inp_mux = + SOC_DAPM_ENUM_EXT("RX INT2 DEM MUX Mux", rx_int2_dem_inp_mux_enum, + snd_soc_dapm_get_enum_double, + wcd9335_int_dem_inp_mux_put); + static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, int rate_val, u32 rate) @@ -1020,6 +1548,986 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = { SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), }; +static void wcd9335_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai, + struct snd_soc_component *component) +{ + int port_num = 0; + unsigned short reg = 0; + unsigned int val = 0; + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + struct wcd9335_slim_ch *ch; + + list_for_each_entry(ch, &dai->slim_ch_list, list) { + if (ch->port >= WCD9335_RX_START) { + port_num = ch->port - WCD9335_RX_START; + reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + (port_num / 8); + } else { + port_num = ch->port; + reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8); + } + + regmap_read(wcd->if_regmap, reg, &val); + if (!(val & BIT(port_num % 8))) + regmap_write(wcd->if_regmap, reg, + val | BIT(port_num % 8)); + } +} + +static int wcd9335_codec_enable_slim(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp); + struct wcd_slim_codec_dai_data *dai = &wcd->dai[w->shift]; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + wcd9335_codec_enable_int_port(dai, comp); + break; + case SND_SOC_DAPM_POST_PMD: + kfree(dai->sconfig.chs); + + break; + } + + return ret; +} + +static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + int offset_val = 0; + int val = 0; + + switch (w->reg) { + case WCD9335_CDC_RX0_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX0_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX1_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX1_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX2_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX2_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX3_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX3_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX4_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX4_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX5_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX5_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX6_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX6_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX7_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX7_RX_VOL_MIX_CTL; + break; + case WCD9335_CDC_RX8_RX_PATH_MIX_CTL: + gain_reg = WCD9335_CDC_RX8_RX_VOL_MIX_CTL; + break; + default: + dev_err(comp->dev, "%s: No gain register avail for %s\n", + __func__, w->name); + return 0; + }; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = snd_soc_component_read32(comp, gain_reg); + val += offset_val; + snd_soc_component_write(comp, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + break; + }; + + return 0; +} + +static u16 wcd9335_interp_get_primary_reg(u16 reg, u16 *ind) +{ + u16 prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL; + + switch (reg) { + case WCD9335_CDC_RX0_RX_PATH_CTL: + case WCD9335_CDC_RX0_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL; + *ind = 0; + break; + case WCD9335_CDC_RX1_RX_PATH_CTL: + case WCD9335_CDC_RX1_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX1_RX_PATH_CTL; + *ind = 1; + break; + case WCD9335_CDC_RX2_RX_PATH_CTL: + case WCD9335_CDC_RX2_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX2_RX_PATH_CTL; + *ind = 2; + break; + case WCD9335_CDC_RX3_RX_PATH_CTL: + case WCD9335_CDC_RX3_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX3_RX_PATH_CTL; + *ind = 3; + break; + case WCD9335_CDC_RX4_RX_PATH_CTL: + case WCD9335_CDC_RX4_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX4_RX_PATH_CTL; + *ind = 4; + break; + case WCD9335_CDC_RX5_RX_PATH_CTL: + case WCD9335_CDC_RX5_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX5_RX_PATH_CTL; + *ind = 5; + break; + case WCD9335_CDC_RX6_RX_PATH_CTL: + case WCD9335_CDC_RX6_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX6_RX_PATH_CTL; + *ind = 6; + break; + case WCD9335_CDC_RX7_RX_PATH_CTL: + case WCD9335_CDC_RX7_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX7_RX_PATH_CTL; + *ind = 7; + break; + case WCD9335_CDC_RX8_RX_PATH_CTL: + case WCD9335_CDC_RX8_RX_PATH_MIX_CTL: + prim_int_reg = WCD9335_CDC_RX8_RX_PATH_CTL; + *ind = 8; + break; + }; + + return prim_int_reg; +} + +static void wcd9335_codec_hd2_control(struct snd_soc_component *component, + u16 prim_int_reg, int event) +{ + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + + if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX1_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX1_RX_PATH_CFG0; + } + if (prim_int_reg == WCD9335_CDC_RX2_RX_PATH_CTL) { + hd2_scale_reg = WCD9335_CDC_RX2_RX_PATH_SEC3; + hd2_enable_reg = WCD9335_CDC_RX2_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P2500); + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_2); + snd_soc_component_update_bits(component, hd2_enable_reg, + WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_HD2_ENABLE); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, hd2_enable_reg, + WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_HD2_DISABLE); + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_1); + snd_soc_component_update_bits(component, hd2_scale_reg, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK, + WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000); + } +} + +static int wcd9335_codec_enable_prim_interpolator( + struct snd_soc_component *comp, + u16 reg, int event) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + u16 ind = 0; + int prim_int_reg = wcd9335_interp_get_primary_reg(reg, &ind); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd->prim_int_users[ind]++; + if (wcd->prim_int_users[ind] == 1) { + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_ENABLE); + wcd9335_codec_hd2_control(comp, prim_int_reg, event); + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_CLK_EN_MASK, + WCD9335_CDC_RX_CLK_ENABLE); + } + + if ((reg != prim_int_reg) && + ((snd_soc_component_read32(comp, prim_int_reg)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK)) + snd_soc_component_update_bits(comp, reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_ENABLE); + break; + case SND_SOC_DAPM_POST_PMD: + wcd->prim_int_users[ind]--; + if (wcd->prim_int_users[ind] == 0) { + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_CLK_EN_MASK, + WCD9335_CDC_RX_CLK_DISABLE); + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_RESET_MASK, + WCD9335_CDC_RX_RESET_ENABLE); + snd_soc_component_update_bits(comp, prim_int_reg, + WCD9335_CDC_RX_RESET_MASK, + WCD9335_CDC_RX_RESET_DISABLE); + wcd9335_codec_hd2_control(comp, prim_int_reg, event); + } + break; + }; + + return 0; +} + +static int wcd9335_config_compander(struct snd_soc_component *component, + int interp_n, int event) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + int comp; + u16 comp_ctl0_reg, rx_path_cfg0_reg; + + /* EAR does not have compander */ + if (!interp_n) + return 0; + + comp = interp_n - 1; + if (!wcd->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = WCD9335_CDC_COMPANDER1_CTL(comp); + rx_path_cfg0_reg = WCD9335_CDC_RX1_RX_PATH_CFG(comp); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_CLK_EN_MASK, + WCD9335_CDC_COMPANDER_CLK_ENABLE); + /* Reset comander */ + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE); + /* Enables DRE in this path */ + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_CMP_ENABLE); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_HALT_MASK, + WCD9335_CDC_COMPANDER_HALT); + snd_soc_component_update_bits(component, rx_path_cfg0_reg, + WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK, + WCD9335_CDC_RX_PATH_CFG_CMP_DISABLE); + + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_SOFT_RST_MASK, + WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_CLK_EN_MASK, + WCD9335_CDC_COMPANDER_CLK_DISABLE); + snd_soc_component_update_bits(component, comp_ctl0_reg, + WCD9335_CDC_COMPANDER_HALT_MASK, + WCD9335_CDC_COMPANDER_NOHALT); + } + + return 0; +} + +static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + u16 gain_reg; + u16 reg; + int val; + int offset_val = 0; + + if (!(strcmp(w->name, "RX INT0 INTERP"))) { + reg = WCD9335_CDC_RX0_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX0_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT1 INTERP"))) { + reg = WCD9335_CDC_RX1_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX1_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT2 INTERP"))) { + reg = WCD9335_CDC_RX2_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX2_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT3 INTERP"))) { + reg = WCD9335_CDC_RX3_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX3_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT4 INTERP"))) { + reg = WCD9335_CDC_RX4_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX4_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT5 INTERP"))) { + reg = WCD9335_CDC_RX5_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX5_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT6 INTERP"))) { + reg = WCD9335_CDC_RX6_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX6_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT7 INTERP"))) { + reg = WCD9335_CDC_RX7_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX7_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT8 INTERP"))) { + reg = WCD9335_CDC_RX8_RX_PATH_CTL; + gain_reg = WCD9335_CDC_RX8_RX_VOL_CTL; + } else { + dev_err(comp->dev, "%s: Interpolator reg not found\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reset if needed */ + wcd9335_codec_enable_prim_interpolator(comp, reg, event); + break; + case SND_SOC_DAPM_POST_PMU: + wcd9335_config_compander(comp, w->shift, event); + val = snd_soc_component_read32(comp, gain_reg); + val += offset_val; + snd_soc_component_write(comp, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + wcd9335_config_compander(comp, w->shift, event); + wcd9335_codec_enable_prim_interpolator(comp, reg, event); + break; + }; + + return 0; +} + +static void wcd9335_codec_hph_mode_gain_opt(struct snd_soc_component *component, + u8 gain) +{ + struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); + u8 hph_l_en, hph_r_en; + u8 l_val, r_val; + u8 hph_pa_status; + bool is_hphl_pa, is_hphr_pa; + + hph_pa_status = snd_soc_component_read32(component, WCD9335_ANA_HPH); + is_hphl_pa = hph_pa_status >> 7; + is_hphr_pa = (hph_pa_status & 0x40) >> 6; + + hph_l_en = snd_soc_component_read32(component, WCD9335_HPH_L_EN); + hph_r_en = snd_soc_component_read32(component, WCD9335_HPH_R_EN); + + l_val = (hph_l_en & 0xC0) | 0x20 | gain; + r_val = (hph_r_en & 0xC0) | 0x20 | gain; + + /* + * Set HPH_L & HPH_R gain source selection to REGISTER + * for better click and pop only if corresponding PAs are + * not enabled. Also cache the values of the HPHL/R + * PA gains to be applied after PAs are enabled + */ + if ((l_val != hph_l_en) && !is_hphl_pa) { + snd_soc_component_write(component, WCD9335_HPH_L_EN, l_val); + wcd->hph_l_gain = hph_l_en & 0x1F; + } + + if ((r_val != hph_r_en) && !is_hphr_pa) { + snd_soc_component_write(component, WCD9335_HPH_R_EN, r_val); + wcd->hph_r_gain = hph_r_en & 0x1F; + } +} + +static void wcd9335_codec_hph_lohifi_config(struct snd_soc_component *comp, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(comp, WCD9335_RX_BIAS_HPH_PA, + WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK, + 0x06); + snd_soc_component_update_bits(comp, + WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, + 0xF0, 0x40); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + 0x0C); + wcd9335_codec_hph_mode_gain_opt(comp, 0x11); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500); + snd_soc_component_write(comp, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, + 0x8A); + snd_soc_component_update_bits(comp, WCD9335_RX_BIAS_HPH_PA, + WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK, + 0x0A); + } +} + +static void wcd9335_codec_hph_lp_config(struct snd_soc_component *comp, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + 0x0C); + wcd9335_codec_hph_mode_gain_opt(comp, 0x10); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK, + WCD9335_HPH_PA_CTL2_HPH_PSRR_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_RDAC_LDO_CTL, + WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_MASK, + WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_V_N1P60); + snd_soc_component_update_bits(comp, WCD9335_HPH_RDAC_LDO_CTL, + WCD9335_HPH_RDAC_1P65_LD_OUTCTL_MASK, + WCD9335_HPH_RDAC_1P65_LD_OUTCTL_V_N1P60); + snd_soc_component_update_bits(comp, + WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x0F, 0x01); + snd_soc_component_update_bits(comp, + WCD9335_RX_BIAS_HPH_RDAC_LDO, 0xF0, 0x10); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_write(comp, WCD9335_RX_BIAS_HPH_RDAC_LDO, + 0x88); + snd_soc_component_write(comp, WCD9335_HPH_RDAC_LDO_CTL, + 0x33); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK, + WCD9335_HPH_PA_CTL2_HPH_PSRR_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK, + WCD9335_HPH_PA_CTL2_FORCE_PSRREH_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500); + snd_soc_component_update_bits(comp, WCD9335_HPH_R_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_HQ_PATH); + snd_soc_component_update_bits(comp, WCD9335_HPH_L_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_HQ_PATH); + } +} + +static void wcd9335_codec_hph_hifi_config(struct snd_soc_component *comp, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + 0x0C); + wcd9335_codec_hph_mode_gain_opt(comp, 0x11); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK, + WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE); + snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK, + WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500); + } +} + +static void wcd9335_codec_hph_mode_config(struct snd_soc_component *component, + int event, int mode) +{ + switch (mode) { + case CLS_H_LP: + wcd9335_codec_hph_lp_config(component, event); + break; + case CLS_H_LOHIFI: + wcd9335_codec_hph_lohifi_config(component, event); + break; + case CLS_H_HIFI: + wcd9335_codec_hph_hifi_config(component, event); + break; + } +} + +static int wcd9335_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + u8 dem_inp; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32(comp, + WCD9335_CDC_RX1_RX_PATH_SEC0) & 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(comp->dev, "Incorrect DEM Input\n"); + return -EINVAL; + } + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + break; + case SND_SOC_DAPM_POST_PMU: + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_PRE_PMD: + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + + if (!(wcd_clsh_ctrl_get_state(wcd->clsh_ctrl) & + WCD_CLSH_STATE_HPHR)) + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + }; + + return ret; +} + +static int wcd9335_codec_lineout_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_LO, CLS_AB); + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_LO, CLS_AB); + break; + } + + return 0; +} + +static int wcd9335_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, CLS_H_NORMAL); + + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, CLS_H_NORMAL); + break; + }; + + return ret; +} + +static void wcd9335_codec_hph_post_pa_config(struct wcd9335_codec *wcd, + int mode, int event) +{ + u8 scale_val = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + switch (mode) { + case CLS_H_HIFI: + scale_val = 0x3; + break; + case CLS_H_LOHIFI: + scale_val = 0x1; + break; + } + break; + case SND_SOC_DAPM_PRE_PMD: + scale_val = 0x6; + break; + } + + if (scale_val) + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_PA_CTL1, + WCD9335_HPH_PA_GM3_IB_SCALE_MASK, + scale_val << 1); + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (wcd->comp_enabled[COMPANDER_1] || + wcd->comp_enabled[COMPANDER_2]) { + /* GAIN Source Selection */ + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_L_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, + WCD9335_HPH_GAIN_SRC_SEL_COMPANDER); + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_R_EN, + WCD9335_HPH_GAIN_SRC_SEL_MASK, + WCD9335_HPH_GAIN_SRC_SEL_COMPANDER); + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_AUTO_CHOP, + WCD9335_HPH_AUTO_CHOP_MASK, + WCD9335_HPH_AUTO_CHOP_FORCE_ENABLE); + } + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_L_EN, + WCD9335_HPH_PA_GAIN_MASK, + wcd->hph_l_gain); + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_R_EN, + WCD9335_HPH_PA_GAIN_MASK, + wcd->hph_r_gain); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) + snd_soc_component_update_bits(wcd->component, + WCD9335_HPH_AUTO_CHOP, + WCD9335_HPH_AUTO_CHOP_MASK, + WCD9335_HPH_AUTO_CHOP_ENABLE_BY_CMPDR_GAIN); +} + +static int wcd9335_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + u8 dem_inp; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + + /* Read DEM INP Select */ + dem_inp = snd_soc_component_read32(comp, + WCD9335_CDC_RX2_RX_PATH_SEC0) & + WCD9335_CDC_RX_PATH_DEM_INP_SEL_MASK; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(comp->dev, "DEM Input not set correctly, hph_mode: %d\n", + hph_mode); + return -EINVAL; + } + + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + + if (!(wcd_clsh_ctrl_get_state(wcd->clsh_ctrl) & + WCD_CLSH_STATE_HPHL)) + wcd9335_codec_hph_mode_config(comp, event, hph_mode); + + wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + }; + + return ret; +} + +static int wcd9335_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(7000, 7100); + + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX1_RX_PATH_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + break; + case SND_SOC_DAPM_PRE_PMD: + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + break; + }; + + return ret; +} + +static int wcd9335_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + int vol_reg = 0, mix_vol_reg = 0; + int ret = 0; + + if (w->reg == WCD9335_ANA_LO_1_2) { + if (w->shift == 7) { + vol_reg = WCD9335_CDC_RX3_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX3_RX_PATH_MIX_CTL; + } else if (w->shift == 6) { + vol_reg = WCD9335_CDC_RX4_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX4_RX_PATH_MIX_CTL; + } + } else if (w->reg == WCD9335_ANA_LO_3_4) { + if (w->shift == 7) { + vol_reg = WCD9335_CDC_RX5_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX5_RX_PATH_MIX_CTL; + } else if (w->shift == 6) { + vol_reg = WCD9335_CDC_RX6_RX_PATH_CTL; + mix_vol_reg = WCD9335_CDC_RX6_RX_PATH_MIX_CTL; + } + } else { + dev_err(comp->dev, "Error enabling lineout PA\n"); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(comp, vol_reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, mix_vol_reg)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, mix_vol_reg, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + break; + }; + + return ret; +} + +static void wcd9335_codec_init_flyback(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_BYPASS); + snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, + WCD9335_HPH_CONST_SEL_L_MASK, + WCD9335_HPH_CONST_SEL_L_BYPASS); + snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, + WCD9335_RX_BIAS_FLYB_VPOS_5_UA_MASK, + WCD9335_RX_BIAS_FLYB_I_0P0_UA); + snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, + WCD9335_RX_BIAS_FLYB_VNEG_5_UA_MASK, + WCD9335_RX_BIAS_FLYB_I_0P0_UA); +} + +static int wcd9335_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd->rx_bias_count++; + if (wcd->rx_bias_count == 1) { + wcd9335_codec_init_flyback(comp); + snd_soc_component_update_bits(comp, + WCD9335_ANA_RX_SUPPLIES, + WCD9335_ANA_RX_BIAS_ENABLE_MASK, + WCD9335_ANA_RX_BIAS_ENABLE); + } + break; + case SND_SOC_DAPM_POST_PMD: + wcd->rx_bias_count--; + if (!wcd->rx_bias_count) + snd_soc_component_update_bits(comp, + WCD9335_ANA_RX_SUPPLIES, + WCD9335_ANA_RX_BIAS_ENABLE_MASK, + WCD9335_ANA_RX_BIAS_DISABLE); + break; + }; + + return 0; +} + +static int wcd9335_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev); + int hph_mode = wcd->hph_mode; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(7000, 7100); + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX2_RX_PATH_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + + break; + + case SND_SOC_DAPM_PRE_PMD: + wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + break; + }; + + return ret; +} + +static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX0_RX_PATH_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_component_read32(comp, + WCD9335_CDC_RX0_RX_PATH_MIX_CTL)) & + WCD9335_CDC_RX_PGA_MUTE_EN_MASK) + snd_soc_component_update_bits(comp, + WCD9335_CDC_RX0_RX_PATH_MIX_CTL, + WCD9335_CDC_RX_PGA_MUTE_EN_MASK, + WCD9335_CDC_RX_PGA_MUTE_DISABLE); + break; + case SND_SOC_DAPM_POST_PMD: + /* 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + + break; + }; + + return ret; +} + static irqreturn_t wcd9335_slimbus_irq(int irq, void *data) { struct wcd9335_codec *wcd = data; @@ -1362,6 +2870,291 @@ static int _wcd9335_codec_enable_mclk(struct snd_soc_component *component, return 0; } +static int wcd9335_codec_enable_mclk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return _wcd9335_codec_enable_mclk(comp, true); + case SND_SOC_DAPM_POST_PMD: + return _wcd9335_codec_enable_mclk(comp, false); + } + + return 0; +} + +static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = { + /* TODO SPK1 & SPK2 OUT*/ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + SND_SOC_DAPM_OUTPUT("LINEOUT1"), + SND_SOC_DAPM_OUTPUT("LINEOUT2"), + SND_SOC_DAPM_OUTPUT("LINEOUT3"), + SND_SOC_DAPM_OUTPUT("LINEOUT4"), + SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM, + AIF1_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM, + AIF2_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM, + AIF3_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM, + AIF4_PB, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("SLIM RX0 MUX", SND_SOC_NOPM, WCD9335_RX0, 0, + &slim_rx_mux[WCD9335_RX0]), + SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, WCD9335_RX1, 0, + &slim_rx_mux[WCD9335_RX1]), + SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, WCD9335_RX2, 0, + &slim_rx_mux[WCD9335_RX2]), + SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, WCD9335_RX3, 0, + &slim_rx_mux[WCD9335_RX3]), + SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, WCD9335_RX4, 0, + &slim_rx_mux[WCD9335_RX4]), + SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, WCD9335_RX5, 0, + &slim_rx_mux[WCD9335_RX5]), + SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, WCD9335_RX6, 0, + &slim_rx_mux[WCD9335_RX6]), + SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, WCD9335_RX7, 0, + &slim_rx_mux[WCD9335_RX7]), + SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", WCD9335_CDC_RX0_RX_PATH_MIX_CTL, + 5, 0, &rx_int0_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + 5, 0, &rx_int1_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + 5, 0, &rx_int2_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", WCD9335_CDC_RX3_RX_PATH_MIX_CTL, + 5, 0, &rx_int3_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", WCD9335_CDC_RX4_RX_PATH_MIX_CTL, + 5, 0, &rx_int4_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT5_2 MUX", WCD9335_CDC_RX5_RX_PATH_MIX_CTL, + 5, 0, &rx_int5_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT6_2 MUX", WCD9335_CDC_RX6_RX_PATH_MIX_CTL, + 5, 0, &rx_int6_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", WCD9335_CDC_RX7_RX_PATH_MIX_CTL, + 5, 0, &rx_int7_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", WCD9335_CDC_RX8_RX_PATH_MIX_CTL, + 5, 0, &rx_int8_2_mux, wcd9335_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int0_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int1_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int2_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int3_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int4_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int5_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int6_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp2_mux), + SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp0_mux), + SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp1_mux), + SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp2_mux), + + SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT5 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT6 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int0_dem_inp_mux), + SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int1_dem_inp_mux), + SND_SOC_DAPM_MUX("RX INT2 DEM MUX", SND_SOC_NOPM, 0, 0, + &rx_int2_dem_inp_mux), + + SND_SOC_DAPM_MUX_E("RX INT0 INTERP", SND_SOC_NOPM, + INTERP_EAR, 0, &rx_int0_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1 INTERP", SND_SOC_NOPM, + INTERP_HPHL, 0, &rx_int1_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2 INTERP", SND_SOC_NOPM, + INTERP_HPHR, 0, &rx_int2_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT3 INTERP", SND_SOC_NOPM, + INTERP_LO1, 0, &rx_int3_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT4 INTERP", SND_SOC_NOPM, + INTERP_LO2, 0, &rx_int4_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT5 INTERP", SND_SOC_NOPM, + INTERP_LO3, 0, &rx_int5_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT6 INTERP", SND_SOC_NOPM, + INTERP_LO4, 0, &rx_int6_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7 INTERP", SND_SOC_NOPM, + INTERP_SPKR1, 0, &rx_int7_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8 INTERP", SND_SOC_NOPM, + INTERP_SPKR2, 0, &rx_int8_interp_mux, + wcd9335_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, WCD9335_ANA_HPH, + 5, 0, wcd9335_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, WCD9335_ANA_HPH, + 4, 0, wcd9335_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT5 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT6 DAC", NULL, SND_SOC_NOPM, + 0, 0, wcd9335_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0, + wcd9335_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PA", WCD9335_ANA_HPH, 6, 0, NULL, 0, + wcd9335_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("EAR PA", WCD9335_ANA_EAR, 7, 0, NULL, 0, + wcd9335_codec_enable_ear_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD9335_ANA_LO_1_2, 7, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD9335_ANA_LO_1_2, 6, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT3 PA", WCD9335_ANA_LO_3_4, 7, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT4 PA", WCD9335_ANA_LO_3_4, 6, 0, NULL, 0, + wcd9335_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_mclk, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + +}; + static void wcd9335_enable_sido_buck(struct snd_soc_component *component) { struct wcd9335_codec *wcd = dev_get_drvdata(component->dev); @@ -1487,6 +3280,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .set_sysclk = wcd9335_codec_set_sysclk, .controls = wcd9335_snd_controls, .num_controls = ARRAY_SIZE(wcd9335_snd_controls), + .dapm_widgets = wcd9335_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets), }; static int wcd9335_probe(struct wcd9335_codec *wcd) -- cgit v1.2.3-58-ga151 From 6ccc25f6696cb603ead89b797825d305c7b27798 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:51 +0000 Subject: ASoC: wcd9335: add capture dapm widgets This patch adds required dapm widgets for capture path. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 1448 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1447 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index aa430cf27b19..887352398f70 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -60,10 +60,43 @@ #define WCD9335_NUM_INTERPOLATORS 9 #define WCD9335_RX_START 16 #define WCD9335_SLIM_CH_START 128 +#define WCD9335_MAX_MICBIAS 4 +#define WCD9335_MAX_VALID_ADC_MUX 13 +#define WCD9335_INVALID_ADC_MUX 9 + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 +#define WCD9335_DMIC_CLK_DIV_2 0x0 +#define WCD9335_DMIC_CLK_DIV_3 0x1 +#define WCD9335_DMIC_CLK_DIV_4 0x2 +#define WCD9335_DMIC_CLK_DIV_6 0x3 +#define WCD9335_DMIC_CLK_DIV_8 0x4 +#define WCD9335_DMIC_CLK_DIV_16 0x5 +#define WCD9335_DMIC_CLK_DRIVE_DEFAULT 0x02 +#define WCD9335_AMIC_PWR_LEVEL_LP 0 +#define WCD9335_AMIC_PWR_LEVEL_DEFAULT 1 +#define WCD9335_AMIC_PWR_LEVEL_HP 2 +#define WCD9335_AMIC_PWR_LVL_MASK 0x60 +#define WCD9335_AMIC_PWR_LVL_SHIFT 0x5 + +#define WCD9335_DEC_PWR_LVL_MASK 0x06 +#define WCD9335_DEC_PWR_LVL_LP 0x02 +#define WCD9335_DEC_PWR_LVL_HP 0x04 +#define WCD9335_DEC_PWR_LVL_DF 0x00 + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 #define WCD9335_SLIM_RX_CH(p) \ {.port = p + WCD9335_RX_START, .shift = p,} +#define WCD9335_SLIM_TX_CH(p) \ + {.port = p, .shift = p,} + /* vout step value */ #define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) @@ -84,6 +117,26 @@ enum { WCD9335_RX_MAX, }; +enum { + WCD9335_TX0 = 0, + WCD9335_TX1, + WCD9335_TX2, + WCD9335_TX3, + WCD9335_TX4, + WCD9335_TX5, + WCD9335_TX6, + WCD9335_TX7, + WCD9335_TX8, + WCD9335_TX9, + WCD9335_TX10, + WCD9335_TX11, + WCD9335_TX12, + WCD9335_TX13, + WCD9335_TX14, + WCD9335_TX15, + WCD9335_TX_MAX, +}; + enum { SIDO_SOURCE_INTERNAL = 0, SIDO_SOURCE_RCO_BG, @@ -165,6 +218,20 @@ enum wcd_clock_type { WCD_CLK_MCLK, }; +enum { + MIC_BIAS_1 = 1, + MIC_BIAS_2, + MIC_BIAS_3, + MIC_BIAS_4 +}; + +enum { + MICB_PULLUP_ENABLE, + MICB_PULLUP_DISABLE, + MICB_ENABLE, + MICB_DISABLE, +}; + struct wcd9335_slim_ch { u32 ch_num; u16 port; @@ -192,7 +259,9 @@ struct wcd9335_codec { struct regmap_irq_chip_data *irq_data; struct wcd9335_slim_ch rx_chs[WCD9335_RX_MAX]; + struct wcd9335_slim_ch tx_chs[WCD9335_TX_MAX]; u32 num_rx_port; + u32 num_tx_port; int sido_input_src; enum wcd9335_sido_voltage sido_voltage; @@ -217,10 +286,22 @@ struct wcd9335_codec { struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY]; unsigned int rx_port_value; + unsigned int tx_port_value; int hph_l_gain; int hph_r_gain; u32 rx_bias_count; + /*TX*/ + int micb_ref[WCD9335_MAX_MICBIAS]; + int pullup_ref[WCD9335_MAX_MICBIAS]; + + int dmic_0_1_clk_cnt; + int dmic_2_3_clk_cnt; + int dmic_4_5_clk_cnt; + int dmic_sample_rate; + int mad_dmic_sample_rate; + + int native_clk_users; }; struct wcd9335_irq { @@ -229,6 +310,25 @@ struct wcd9335_irq { char *name; }; +static const struct wcd9335_slim_ch wcd9335_tx_chs[WCD9335_TX_MAX] = { + WCD9335_SLIM_TX_CH(0), + WCD9335_SLIM_TX_CH(1), + WCD9335_SLIM_TX_CH(2), + WCD9335_SLIM_TX_CH(3), + WCD9335_SLIM_TX_CH(4), + WCD9335_SLIM_TX_CH(5), + WCD9335_SLIM_TX_CH(6), + WCD9335_SLIM_TX_CH(7), + WCD9335_SLIM_TX_CH(8), + WCD9335_SLIM_TX_CH(9), + WCD9335_SLIM_TX_CH(10), + WCD9335_SLIM_TX_CH(11), + WCD9335_SLIM_TX_CH(12), + WCD9335_SLIM_TX_CH(13), + WCD9335_SLIM_TX_CH(14), + WCD9335_SLIM_TX_CH(15), +}; + static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = { WCD9335_SLIM_RX_CH(0), /* 16 */ WCD9335_SLIM_RX_CH(1), /* 17 */ @@ -409,6 +509,59 @@ static const char *const slim_rx_mux_text[] = { "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB", }; +static const char * const adc_mux_text[] = { + "DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2" +}; + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", + "SMIC0", "SMIC1", "SMIC2", "SMIC3" +}; + +static const char * const dmic_mux_alt_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", +}; + +static const char * const amic_mux_text[] = { + "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6" +}; + +static const char * const sb_tx0_mux_text[] = { + "ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192" +}; + +static const char * const sb_tx1_mux_text[] = { + "ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192" +}; + +static const char * const sb_tx2_mux_text[] = { + "ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192" +}; + +static const char * const sb_tx3_mux_text[] = { + "ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192" +}; + +static const char * const sb_tx4_mux_text[] = { + "ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192" +}; + +static const char * const sb_tx5_mux_text[] = { + "ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192" +}; + +static const char * const sb_tx6_mux_text[] = { + "ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192" +}; + +static const char * const sb_tx7_mux_text[] = { + "ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192" +}; + +static const char * const sb_tx8_mux_text[] = { + "ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192" +}; + static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -697,6 +850,150 @@ static const struct soc_enum rx_int8_interp_mux_enum = SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2, rx_int8_interp_mux_text); +static const struct soc_enum tx_adc_mux0_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux1_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux2_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux3_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux4_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux5_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux6_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux7_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_adc_mux8_chain_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 6, 4, + adc_mux_text); + +static const struct soc_enum tx_dmic_mux0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3, 11, + dmic_mux_text); + +static const struct soc_enum tx_dmic_mux4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_dmic_mux8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3, 7, + dmic_mux_alt_text); + +static const struct soc_enum tx_amic_mux0_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux1_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux2_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux3_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux4_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux5_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux6_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux7_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum tx_amic_mux8_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0, 7, + amic_mux_text); + +static const struct soc_enum sb_tx0_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0, 4, + sb_tx0_mux_text); + +static const struct soc_enum sb_tx1_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 2, 4, + sb_tx1_mux_text); + +static const struct soc_enum sb_tx2_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 4, 4, + sb_tx2_mux_text); + +static const struct soc_enum sb_tx3_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 6, 4, + sb_tx3_mux_text); + +static const struct soc_enum sb_tx4_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 0, 4, + sb_tx4_mux_text); + +static const struct soc_enum sb_tx5_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 2, 4, + sb_tx5_mux_text); + +static const struct soc_enum sb_tx6_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 4, 4, + sb_tx6_mux_text); + +static const struct soc_enum sb_tx7_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 6, 4, + sb_tx7_mux_text); + +static const struct soc_enum sb_tx8_mux_enum = + SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 0, 4, + sb_tx8_mux_text); + static const struct snd_kcontrol_new rx_int0_2_mux = SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum); @@ -832,6 +1129,87 @@ static const struct snd_kcontrol_new rx_int7_interp_mux = static const struct snd_kcontrol_new rx_int8_interp_mux = SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum); +static const struct snd_kcontrol_new tx_dmic_mux0 = + SOC_DAPM_ENUM("DMIC MUX0 Mux", tx_dmic_mux0_enum); + +static const struct snd_kcontrol_new tx_dmic_mux1 = + SOC_DAPM_ENUM("DMIC MUX1 Mux", tx_dmic_mux1_enum); + +static const struct snd_kcontrol_new tx_dmic_mux2 = + SOC_DAPM_ENUM("DMIC MUX2 Mux", tx_dmic_mux2_enum); + +static const struct snd_kcontrol_new tx_dmic_mux3 = + SOC_DAPM_ENUM("DMIC MUX3 Mux", tx_dmic_mux3_enum); + +static const struct snd_kcontrol_new tx_dmic_mux4 = + SOC_DAPM_ENUM("DMIC MUX4 Mux", tx_dmic_mux4_enum); + +static const struct snd_kcontrol_new tx_dmic_mux5 = + SOC_DAPM_ENUM("DMIC MUX5 Mux", tx_dmic_mux5_enum); + +static const struct snd_kcontrol_new tx_dmic_mux6 = + SOC_DAPM_ENUM("DMIC MUX6 Mux", tx_dmic_mux6_enum); + +static const struct snd_kcontrol_new tx_dmic_mux7 = + SOC_DAPM_ENUM("DMIC MUX7 Mux", tx_dmic_mux7_enum); + +static const struct snd_kcontrol_new tx_dmic_mux8 = + SOC_DAPM_ENUM("DMIC MUX8 Mux", tx_dmic_mux8_enum); + +static const struct snd_kcontrol_new tx_amic_mux0 = + SOC_DAPM_ENUM("AMIC MUX0 Mux", tx_amic_mux0_enum); + +static const struct snd_kcontrol_new tx_amic_mux1 = + SOC_DAPM_ENUM("AMIC MUX1 Mux", tx_amic_mux1_enum); + +static const struct snd_kcontrol_new tx_amic_mux2 = + SOC_DAPM_ENUM("AMIC MUX2 Mux", tx_amic_mux2_enum); + +static const struct snd_kcontrol_new tx_amic_mux3 = + SOC_DAPM_ENUM("AMIC MUX3 Mux", tx_amic_mux3_enum); + +static const struct snd_kcontrol_new tx_amic_mux4 = + SOC_DAPM_ENUM("AMIC MUX4 Mux", tx_amic_mux4_enum); + +static const struct snd_kcontrol_new tx_amic_mux5 = + SOC_DAPM_ENUM("AMIC MUX5 Mux", tx_amic_mux5_enum); + +static const struct snd_kcontrol_new tx_amic_mux6 = + SOC_DAPM_ENUM("AMIC MUX6 Mux", tx_amic_mux6_enum); + +static const struct snd_kcontrol_new tx_amic_mux7 = + SOC_DAPM_ENUM("AMIC MUX7 Mux", tx_amic_mux7_enum); + +static const struct snd_kcontrol_new tx_amic_mux8 = + SOC_DAPM_ENUM("AMIC MUX8 Mux", tx_amic_mux8_enum); + +static const struct snd_kcontrol_new sb_tx0_mux = + SOC_DAPM_ENUM("SLIM TX0 MUX Mux", sb_tx0_mux_enum); + +static const struct snd_kcontrol_new sb_tx1_mux = + SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum); + +static const struct snd_kcontrol_new sb_tx2_mux = + SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum); + +static const struct snd_kcontrol_new sb_tx3_mux = + SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum); + +static const struct snd_kcontrol_new sb_tx4_mux = + SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum); + +static const struct snd_kcontrol_new sb_tx5_mux = + SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum); + +static const struct snd_kcontrol_new sb_tx6_mux = + SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum); + +static const struct snd_kcontrol_new sb_tx7_mux = + SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum); + +static const struct snd_kcontrol_new sb_tx8_mux = + SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum); + static int slim_rx_mux_get(struct snd_kcontrol *kc, struct snd_ctl_elem_value *ucontrol) { @@ -887,6 +1265,55 @@ err: return -EINVAL; } +static int slim_tx_mixer_get(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev); + + ucontrol->value.integer.value[0] = wcd->tx_port_value; + + return 0; +} + +static int slim_tx_mixer_put(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc); + struct wcd9335_codec *wcd = dev_get_drvdata(widget->dapm->dev); + struct snd_soc_dapm_update *update = NULL; + struct soc_mixer_control *mixer = + (struct soc_mixer_control *)kc->private_value; + int enable = ucontrol->value.integer.value[0]; + int dai_id = widget->shift; + int port_id = mixer->shift; + + switch (dai_id) { + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + /* only add to the list if value not set */ + if (enable && !(wcd->tx_port_value & BIT(port_id))) { + wcd->tx_port_value |= BIT(port_id); + list_add_tail(&wcd->tx_chs[port_id].list, + &wcd->dai[dai_id].slim_ch_list); + } else if (!enable && (wcd->tx_port_value & BIT(port_id))) { + wcd->tx_port_value &= ~BIT(port_id); + list_del_init(&wcd->tx_chs[port_id].list); + } + break; + default: + dev_err(wcd->dev, "Unknown AIF %d\n", dai_id); + return -EINVAL; + } + + snd_soc_dapm_mixer_update_power(widget->dapm, kc, enable, update); + + return 0; +} + static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = { SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum, slim_rx_mux_get, slim_rx_mux_put), @@ -906,6 +1333,136 @@ static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = { slim_rx_mux_get, slim_rx_mux_put), }; +static const struct snd_kcontrol_new aif1_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD9335_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD9335_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD9335_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD9335_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif2_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD9335_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD9335_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD9335_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD9335_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif3_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static int wcd9335_put_dec_enum(struct snd_kcontrol *kc, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); + struct soc_enum *e = (struct soc_enum *)kc->private_value; + unsigned int val, reg, sel; + + val = ucontrol->value.enumerated.item[0]; + + switch (e->reg) { + case WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1: + reg = WCD9335_CDC_TX0_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1: + reg = WCD9335_CDC_TX1_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1: + reg = WCD9335_CDC_TX2_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1: + reg = WCD9335_CDC_TX3_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0: + reg = WCD9335_CDC_TX4_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0: + reg = WCD9335_CDC_TX5_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0: + reg = WCD9335_CDC_TX6_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0: + reg = WCD9335_CDC_TX7_TX_PATH_CFG0; + break; + case WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0: + reg = WCD9335_CDC_TX8_TX_PATH_CFG0; + break; + default: + return -EINVAL; + } + + /* AMIC: 0, DMIC: 1 */ + sel = val ? WCD9335_CDC_TX_ADC_AMIC_SEL : WCD9335_CDC_TX_ADC_DMIC_SEL; + snd_soc_component_update_bits(component, reg, + WCD9335_CDC_TX_ADC_AMIC_DMIC_SEL_MASK, + sel); + + return snd_soc_dapm_put_enum_double(kc, ucontrol); +} + static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kc, struct snd_ctl_elem_value *ucontrol) { @@ -948,6 +1505,51 @@ static const struct snd_kcontrol_new rx_int2_dem_inp_mux = snd_soc_dapm_get_enum_double, wcd9335_int_dem_inp_mux_put); +static const struct snd_kcontrol_new tx_adc_mux0 = + SOC_DAPM_ENUM_EXT("ADC MUX0 Mux", tx_adc_mux0_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux1 = + SOC_DAPM_ENUM_EXT("ADC MUX1 Mux", tx_adc_mux1_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux2 = + SOC_DAPM_ENUM_EXT("ADC MUX2 Mux", tx_adc_mux2_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux3 = + SOC_DAPM_ENUM_EXT("ADC MUX3 Mux", tx_adc_mux3_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux4 = + SOC_DAPM_ENUM_EXT("ADC MUX4 Mux", tx_adc_mux4_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux5 = + SOC_DAPM_ENUM_EXT("ADC MUX5 Mux", tx_adc_mux5_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux6 = + SOC_DAPM_ENUM_EXT("ADC MUX6 Mux", tx_adc_mux6_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux7 = + SOC_DAPM_ENUM_EXT("ADC MUX7 Mux", tx_adc_mux7_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + +static const struct snd_kcontrol_new tx_adc_mux8 = + SOC_DAPM_ENUM_EXT("ADC MUX8 Mux", tx_adc_mux8_chain_enum, + snd_soc_dapm_get_enum_double, + wcd9335_put_dec_enum); + static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai, int rate_val, u32 rate) @@ -1090,6 +1692,27 @@ static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd, WCD9335_SLIM_WATER_MARK_VAL); if (ret < 0) goto err; + } else { + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_0(ch->port), + payload & 0x00FF); + if (ret < 0) + goto err; + + /* ports 8,9 */ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_1(ch->port), + (payload & 0xFF00)>>8); + if (ret < 0) + goto err; + + /* configure the slave port for water mark and enable*/ + ret = regmap_write(wcd->if_regmap, + WCD9335_SLIM_PGD_TX_PORT_CFG(ch->port), + WCD9335_SLIM_WATER_MARK_VAL); + + if (ret < 0) + goto err; } } @@ -1105,12 +1728,91 @@ err: return ret; } +static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai, + u8 rate_val, u32 rate) +{ + struct snd_soc_component *comp = dai->component; + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp); + u8 shift = 0, shift_val = 0, tx_mux_sel; + struct wcd9335_slim_ch *ch; + int tx_port, tx_port_reg; + int decimator = -1; + + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) { + tx_port = ch->port; + if ((tx_port == 12) || (tx_port >= 14)) { + dev_err(wcd->dev, "Invalid SLIM TX%u port DAI ID:%d\n", + tx_port, dai->id); + return -EINVAL; + } + /* Find the SB TX MUX input - which decimator is connected */ + if (tx_port < 4) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0; + shift = (tx_port << 1); + shift_val = 0x03; + } else if ((tx_port >= 4) && (tx_port < 8)) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1; + shift = ((tx_port - 4) << 1); + shift_val = 0x03; + } else if ((tx_port >= 8) && (tx_port < 11)) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2; + shift = ((tx_port - 8) << 1); + shift_val = 0x03; + } else if (tx_port == 11) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 0; + shift_val = 0x0F; + } else if (tx_port == 13) { + tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 4; + shift_val = 0x03; + } else { + return -EINVAL; + } + + tx_mux_sel = snd_soc_component_read32(comp, tx_port_reg) & + (shift_val << shift); + + tx_mux_sel = tx_mux_sel >> shift; + if (tx_port <= 8) { + if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3)) + decimator = tx_port; + } else if (tx_port <= 10) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = ((tx_port == 9) ? 7 : 6); + } else if (tx_port == 11) { + if ((tx_mux_sel >= 1) && (tx_mux_sel < 7)) + decimator = tx_mux_sel - 1; + } else if (tx_port == 13) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = 5; + } + + if (decimator >= 0) { + snd_soc_component_update_bits(comp, + WCD9335_CDC_TX_PATH_CTL(decimator), + WCD9335_CDC_TX_PATH_CTL_PCM_RATE_MASK, + rate_val); + } else if ((tx_port <= 8) && (tx_mux_sel == 0x01)) { + /* Check if the TX Mux input is RX MIX TXn */ + dev_err(wcd->dev, "RX_MIX_TX%u going to SLIM TX%u\n", + tx_port, tx_port); + } else { + dev_err(wcd->dev, "ERROR: Invalid decimator: %d\n", + decimator); + return -EINVAL; + } + } + + return 0; +} + static int wcd9335_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct wcd9335_codec *wcd; - int ret; + int ret, tx_fs_rate = 0; wcd = snd_soc_component_get_drvdata(dai->component); @@ -1132,6 +1834,53 @@ static int wcd9335_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } break; + + case SNDRV_PCM_STREAM_CAPTURE: + switch (params_rate(params)) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + case 384000: + tx_fs_rate = 7; + break; + default: + dev_err(wcd->dev, "%s: Invalid TX sample rate: %d\n", + __func__, params_rate(params)); + return -EINVAL; + + }; + + ret = wcd9335_set_decimator_rate(dai, tx_fs_rate, + params_rate(params)); + if (ret < 0) { + dev_err(wcd->dev, "Cannot set TX Decimator rate\n"); + return ret; + } + switch (params_width(params)) { + case 16 ... 32: + wcd->dai[dai->id].sconfig.bps = params_width(params); + break; + default: + dev_err(wcd->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + }; + break; default: dev_err(wcd->dev, "Invalid stream type %d\n", substream->stream); @@ -1199,6 +1948,14 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai, } } + if (wcd->tx_chs) { + wcd->num_tx_port = tx_num; + for (i = 0; i < tx_num; i++) { + wcd->tx_chs[i].ch_num = tx_slot[i]; + INIT_LIST_HEAD(&wcd->tx_chs[i].list); + } + } + return 0; } @@ -1228,6 +1985,19 @@ static int wcd9335_get_channel_map(struct snd_soc_dai *dai, *rx_num = i; break; + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + if (!tx_slot || !tx_num) { + dev_err(wcd->dev, "Invalid tx_slot %p or tx_num %p\n", + tx_slot, tx_num); + return -EINVAL; + } + list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) + tx_slot[i++] = ch->ch_num; + + *tx_num = i; + break; default: dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id); break; @@ -1548,6 +2318,496 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = { SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), }; +static int wcd9335_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(component); + int micb_index = micb_num - 1; + u16 micb_reg; + + if ((micb_index < 0) || (micb_index > WCD9335_MAX_MICBIAS - 1)) { + dev_err(wcd->dev, "Invalid micbias index, micb_ind:%d\n", + micb_index); + return -EINVAL; + } + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD9335_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD9335_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD9335_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD9335_ANA_MICB4; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + + switch (req) { + case MICB_PULLUP_ENABLE: + wcd->pullup_ref[micb_index]++; + if ((wcd->pullup_ref[micb_index] == 1) && + (wcd->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + break; + case MICB_PULLUP_DISABLE: + wcd->pullup_ref[micb_index]--; + if ((wcd->pullup_ref[micb_index] == 0) && + (wcd->micb_ref[micb_index] == 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + break; + case MICB_ENABLE: + wcd->micb_ref[micb_index]++; + if (wcd->micb_ref[micb_index] == 1) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x40); + break; + case MICB_DISABLE: + wcd->micb_ref[micb_index]--; + if ((wcd->micb_ref[micb_index] == 0) && + (wcd->pullup_ref[micb_index] > 0)) + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x80); + else if ((wcd->micb_ref[micb_index] == 0) && + (wcd->pullup_ref[micb_index] == 0)) { + snd_soc_component_update_bits(component, micb_reg, + 0xC0, 0x00); + } + break; + }; + + return 0; +} + +static int __wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + int micb_num; + + if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) + micb_num = MIC_BIAS_4; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* + * MIC BIAS can also be requested by MBHC, + * so use ref count to handle micbias pullup + * and enable requests + */ + wcd9335_micbias_control(comp, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* wait for cnp time */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd9335_micbias_control(comp, micb_num, MICB_DISABLE, true); + break; + }; + + return 0; +} + +static int wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + return __wcd9335_codec_enable_micbias(w, event); +} + +static void wcd9335_codec_set_tx_hold(struct snd_soc_component *comp, + u16 amic_reg, bool set) +{ + u8 mask = 0x20; + u8 val; + + if (amic_reg == WCD9335_ANA_AMIC1 || amic_reg == WCD9335_ANA_AMIC3 || + amic_reg == WCD9335_ANA_AMIC5) + mask = 0x40; + + val = set ? mask : 0x00; + + switch (amic_reg) { + case WCD9335_ANA_AMIC1: + case WCD9335_ANA_AMIC2: + snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC2, mask, + val); + break; + case WCD9335_ANA_AMIC3: + case WCD9335_ANA_AMIC4: + snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC4, mask, + val); + break; + case WCD9335_ANA_AMIC5: + case WCD9335_ANA_AMIC6: + snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC6, mask, + val); + break; + default: + dev_err(comp->dev, "%s: invalid amic: %d\n", + __func__, amic_reg); + break; + } +} + +static int wcd9335_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd9335_codec_set_tx_hold(comp, w->reg, true); + break; + default: + break; + } + + return 0; +} + +static int wcd9335_codec_find_amic_input(struct snd_soc_component *comp, + int adc_mux_n) +{ + int mux_sel, reg, mreg; + + if (adc_mux_n < 0 || adc_mux_n > WCD9335_MAX_VALID_ADC_MUX || + adc_mux_n == WCD9335_INVALID_ADC_MUX) + return 0; + + /* Check whether adc mux input is AMIC or DMIC */ + if (adc_mux_n < 4) { + reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + 2 * adc_mux_n; + mreg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + 2 * adc_mux_n; + mux_sel = snd_soc_component_read32(comp, reg) & 0x3; + } else { + reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + adc_mux_n - 4; + mreg = reg; + mux_sel = snd_soc_component_read32(comp, reg) >> 6; + } + + if (mux_sel != WCD9335_CDC_TX_INP_MUX_SEL_AMIC) + return 0; + + return snd_soc_component_read32(comp, mreg) & 0x07; +} + +static u16 wcd9335_codec_get_amic_pwlvl_reg(struct snd_soc_component *comp, + int amic) +{ + u16 pwr_level_reg = 0; + + switch (amic) { + case 1: + case 2: + pwr_level_reg = WCD9335_ANA_AMIC1; + break; + + case 3: + case 4: + pwr_level_reg = WCD9335_ANA_AMIC3; + break; + + case 5: + case 6: + pwr_level_reg = WCD9335_ANA_AMIC5; + break; + default: + dev_err(comp->dev, "invalid amic: %d\n", amic); + break; + } + + return pwr_level_reg; +} + +static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + unsigned int decimator; + char *dec_adc_mux_name = NULL; + char *widget_name = NULL; + char *wname; + int ret = 0, amic_n; + u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg; + u16 tx_gain_ctl_reg; + char *dec; + u8 hpf_coff_freq; + + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) + return -ENOMEM; + + wname = widget_name; + dec_adc_mux_name = strsep(&widget_name, " "); + if (!dec_adc_mux_name) { + dev_err(comp->dev, "%s: Invalid decimator = %s\n", + __func__, w->name); + ret = -EINVAL; + goto out; + } + dec_adc_mux_name = widget_name; + + dec = strpbrk(dec_adc_mux_name, "012345678"); + if (!dec) { + dev_err(comp->dev, "%s: decimator index not found\n", + __func__); + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(dec, 10, &decimator); + if (ret < 0) { + dev_err(comp->dev, "%s: Invalid decimator = %s\n", + __func__, wname); + ret = -EINVAL; + goto out; + } + + tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator; + hpf_gate_reg = WCD9335_CDC_TX0_TX_PATH_SEC2 + 16 * decimator; + dec_cfg_reg = WCD9335_CDC_TX0_TX_PATH_CFG0 + 16 * decimator; + tx_gain_ctl_reg = WCD9335_CDC_TX0_TX_VOL_CTL + 16 * decimator; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + amic_n = wcd9335_codec_find_amic_input(comp, decimator); + if (amic_n) + pwr_level_reg = wcd9335_codec_get_amic_pwlvl_reg(comp, + amic_n); + + if (pwr_level_reg) { + switch ((snd_soc_component_read32(comp, pwr_level_reg) & + WCD9335_AMIC_PWR_LVL_MASK) >> + WCD9335_AMIC_PWR_LVL_SHIFT) { + case WCD9335_AMIC_PWR_LEVEL_LP: + snd_soc_component_update_bits(comp, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_LP); + break; + + case WCD9335_AMIC_PWR_LEVEL_HP: + snd_soc_component_update_bits(comp, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_HP); + break; + case WCD9335_AMIC_PWR_LEVEL_DEFAULT: + default: + snd_soc_component_update_bits(comp, dec_cfg_reg, + WCD9335_DEC_PWR_LVL_MASK, + WCD9335_DEC_PWR_LVL_DF); + break; + } + } + hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + + if (hpf_coff_freq != CF_MIN_3DB_150HZ) + snd_soc_component_update_bits(comp, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + /* Enable TX PGA Mute */ + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, + 0x10, 0x10); + /* Enable APC */ + snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x08); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_update_bits(comp, hpf_gate_reg, 0x01, 0x00); + + if (decimator == 0) { + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x83); + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0xA3); + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x83); + snd_soc_component_write(comp, + WCD9335_MBHC_ZDET_RAMP_CTL, 0x03); + } + + snd_soc_component_update_bits(comp, hpf_gate_reg, + 0x01, 0x01); + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, + 0x10, 0x00); + snd_soc_component_write(comp, tx_gain_ctl_reg, + snd_soc_component_read32(comp, tx_gain_ctl_reg)); + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x10); + snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x00); + if (hpf_coff_freq != CF_MIN_3DB_150HZ) { + snd_soc_component_update_bits(comp, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_coff_freq << 5); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00); + break; + }; +out: + kfree(wname); + return ret; +} + +static u8 wcd9335_get_dmic_clk_val(struct snd_soc_component *component, + u32 mclk_rate, u32 dmic_clk_rate) +{ + u32 div_factor; + u8 dmic_ctl_val; + + dev_err(component->dev, + "%s: mclk_rate = %d, dmic_sample_rate = %d\n", + __func__, mclk_rate, dmic_clk_rate); + + /* Default value to return in case of error */ + if (mclk_rate == WCD9335_MCLK_CLK_9P6MHZ) + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; + else + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; + + if (dmic_clk_rate == 0) { + dev_err(component->dev, + "%s: dmic_sample_rate cannot be 0\n", + __func__); + goto done; + } + + div_factor = mclk_rate / dmic_clk_rate; + switch (div_factor) { + case 2: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2; + break; + case 3: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3; + break; + case 4: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4; + break; + case 6: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6; + break; + case 8: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8; + break; + case 16: + dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16; + break; + default: + dev_err(component->dev, + "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n", + __func__, div_factor, mclk_rate, dmic_clk_rate); + break; + } + +done: + return dmic_ctl_val; +} + +static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kc, int event) +{ + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); + struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg; + s32 *dmic_clk_cnt; + u8 dmic_rate_val, dmic_rate_shift = 1; + unsigned int dmic; + int ret; + char *wname; + + wname = strpbrk(w->name, "012345"); + if (!wname) { + dev_err(comp->dev, "%s: widget not found\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(wname, 10, &dmic); + if (ret < 0) { + dev_err(comp->dev, "%s: Invalid DMIC line on the codec\n", + __func__); + return -EINVAL; + } + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(wcd->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC0_CTL; + break; + case 2: + case 3: + dmic_clk_cnt = &(wcd->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC1_CTL; + break; + case 4: + case 5: + dmic_clk_cnt = &(wcd->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD9335_CPE_SS_DMIC2_CTL; + break; + default: + dev_err(comp->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + }; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + dmic_rate_val = + wcd9335_get_dmic_clk_val(comp, + wcd->mclk_rate, + wcd->dmic_sample_rate); + + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_component_update_bits(comp, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + snd_soc_component_update_bits(comp, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } + + break; + case SND_SOC_DAPM_POST_PMD: + dmic_rate_val = + wcd9335_get_dmic_clk_val(comp, + wcd->mclk_rate, + wcd->mad_dmic_sample_rate); + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_component_update_bits(comp, dmic_clk_reg, + dmic_clk_en, 0); + snd_soc_component_update_bits(comp, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + } + break; + }; + + return 0; +} + static void wcd9335_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai, struct snd_soc_component *component) { @@ -3153,6 +4413,191 @@ static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = { wcd9335_codec_enable_mclk, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* TX */ + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + SND_SOC_DAPM_INPUT("AMIC6"), + + SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM, + AIF1_CAP, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM, + AIF2_CAP, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM, + AIF3_CAP, 0, wcd9335_codec_enable_slim, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD9335_ANA_AMIC1, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD9335_ANA_AMIC2, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD9335_ANA_AMIC3, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD9335_ANA_AMIC4, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC5", NULL, WCD9335_ANA_AMIC5, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC6", NULL, WCD9335_ANA_AMIC6, 7, 0, + wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + + /* Digital Mic Inputs */ + SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0, + wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("DMIC MUX0", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux0), + SND_SOC_DAPM_MUX("DMIC MUX1", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux1), + SND_SOC_DAPM_MUX("DMIC MUX2", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux2), + SND_SOC_DAPM_MUX("DMIC MUX3", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux3), + SND_SOC_DAPM_MUX("DMIC MUX4", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux4), + SND_SOC_DAPM_MUX("DMIC MUX5", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux5), + SND_SOC_DAPM_MUX("DMIC MUX6", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux6), + SND_SOC_DAPM_MUX("DMIC MUX7", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux7), + SND_SOC_DAPM_MUX("DMIC MUX8", SND_SOC_NOPM, 0, 0, + &tx_dmic_mux8), + + SND_SOC_DAPM_MUX("AMIC MUX0", SND_SOC_NOPM, 0, 0, + &tx_amic_mux0), + SND_SOC_DAPM_MUX("AMIC MUX1", SND_SOC_NOPM, 0, 0, + &tx_amic_mux1), + SND_SOC_DAPM_MUX("AMIC MUX2", SND_SOC_NOPM, 0, 0, + &tx_amic_mux2), + SND_SOC_DAPM_MUX("AMIC MUX3", SND_SOC_NOPM, 0, 0, + &tx_amic_mux3), + SND_SOC_DAPM_MUX("AMIC MUX4", SND_SOC_NOPM, 0, 0, + &tx_amic_mux4), + SND_SOC_DAPM_MUX("AMIC MUX5", SND_SOC_NOPM, 0, 0, + &tx_amic_mux5), + SND_SOC_DAPM_MUX("AMIC MUX6", SND_SOC_NOPM, 0, 0, + &tx_amic_mux6), + SND_SOC_DAPM_MUX("AMIC MUX7", SND_SOC_NOPM, 0, 0, + &tx_amic_mux7), + SND_SOC_DAPM_MUX("AMIC MUX8", SND_SOC_NOPM, 0, 0, + &tx_amic_mux8), + + SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0, + aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)), + + SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0, + aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)), + + SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0, + aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)), + + SND_SOC_DAPM_MUX("SLIM TX0 MUX", SND_SOC_NOPM, WCD9335_TX0, 0, + &sb_tx0_mux), + SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, WCD9335_TX1, 0, + &sb_tx1_mux), + SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, WCD9335_TX2, 0, + &sb_tx2_mux), + SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, WCD9335_TX3, 0, + &sb_tx3_mux), + SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, WCD9335_TX4, 0, + &sb_tx4_mux), + SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, WCD9335_TX5, 0, + &sb_tx5_mux), + SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, WCD9335_TX6, 0, + &sb_tx6_mux), + SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, WCD9335_TX7, 0, + &sb_tx7_mux), + SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, WCD9335_TX8, 0, + &sb_tx8_mux), + + SND_SOC_DAPM_MUX_E("ADC MUX0", WCD9335_CDC_TX0_TX_PATH_CTL, 5, 0, + &tx_adc_mux0, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX1", WCD9335_CDC_TX1_TX_PATH_CTL, 5, 0, + &tx_adc_mux1, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX2", WCD9335_CDC_TX2_TX_PATH_CTL, 5, 0, + &tx_adc_mux2, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX3", WCD9335_CDC_TX3_TX_PATH_CTL, 5, 0, + &tx_adc_mux3, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX4", WCD9335_CDC_TX4_TX_PATH_CTL, 5, 0, + &tx_adc_mux4, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX5", WCD9335_CDC_TX5_TX_PATH_CTL, 5, 0, + &tx_adc_mux5, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX6", WCD9335_CDC_TX6_TX_PATH_CTL, 5, 0, + &tx_adc_mux6, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX7", WCD9335_CDC_TX7_TX_PATH_CTL, 5, 0, + &tx_adc_mux7, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX8", WCD9335_CDC_TX8_TX_PATH_CTL, 5, 0, + &tx_adc_mux8, wcd9335_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), }; static void wcd9335_enable_sido_buck(struct snd_soc_component *component) @@ -3289,6 +4734,7 @@ static int wcd9335_probe(struct wcd9335_codec *wcd) struct device *dev = wcd->dev; memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs)); + memcpy(wcd->tx_chs, wcd9335_tx_chs, sizeof(wcd9335_tx_chs)); wcd->sido_input_src = SIDO_SOURCE_INTERNAL; wcd->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV; -- cgit v1.2.3-58-ga151 From 93f97ff1911a34e2a4662f16b6266b2c309f918b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:52 +0000 Subject: ASoC: wcd9335: add audio routings This patch adds audio routing for both playback and capture. Signed-off-by: Srinivas Kandagatla Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 189 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 887352398f70..3878187bb512 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -100,6 +100,67 @@ /* vout step value */ #define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) +#define WCD9335_INTERPOLATOR_PATH(id) \ + {"RX INT" #id "_1 MIX1 INP0", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_1 MIX1 INP0", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_1 MIX1 INP1", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_1 MIX1 INP2", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_2 MUX", "RX0", "SLIM RX0"}, \ + {"RX INT" #id "_2 MUX", "RX1", "SLIM RX1"}, \ + {"RX INT" #id "_2 MUX", "RX2", "SLIM RX2"}, \ + {"RX INT" #id "_2 MUX", "RX3", "SLIM RX3"}, \ + {"RX INT" #id "_2 MUX", "RX4", "SLIM RX4"}, \ + {"RX INT" #id "_2 MUX", "RX5", "SLIM RX5"}, \ + {"RX INT" #id "_2 MUX", "RX6", "SLIM RX6"}, \ + {"RX INT" #id "_2 MUX", "RX7", "SLIM RX7"}, \ + {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP0"}, \ + {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP1"}, \ + {"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP2"}, \ + {"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_2 MUX"}, \ + {"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_1 MIX1"}, \ + {"RX INT" #id " MIX2", NULL, "RX INT" #id " SEC MIX"}, \ + {"RX INT" #id " INTERP", NULL, "RX INT" #id " MIX2"} + +#define WCD9335_ADC_MUX_PATH(id) \ + {"AIF1_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \ + {"AIF2_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \ + {"AIF3_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \ + {"SLIM TX" #id " MUX", "DEC" #id, "ADC MUX" #id}, \ + {"ADC MUX" #id, "DMIC", "DMIC MUX" #id}, \ + {"ADC MUX" #id, "AMIC", "AMIC MUX" #id}, \ + {"DMIC MUX" #id, "DMIC0", "DMIC0"}, \ + {"DMIC MUX" #id, "DMIC1", "DMIC1"}, \ + {"DMIC MUX" #id, "DMIC2", "DMIC2"}, \ + {"DMIC MUX" #id, "DMIC3", "DMIC3"}, \ + {"DMIC MUX" #id, "DMIC4", "DMIC4"}, \ + {"DMIC MUX" #id, "DMIC5", "DMIC5"}, \ + {"AMIC MUX" #id, "ADC1", "ADC1"}, \ + {"AMIC MUX" #id, "ADC2", "ADC2"}, \ + {"AMIC MUX" #id, "ADC3", "ADC3"}, \ + {"AMIC MUX" #id, "ADC4", "ADC4"}, \ + {"AMIC MUX" #id, "ADC5", "ADC5"}, \ + {"AMIC MUX" #id, "ADC6", "ADC6"} + enum { WCD9335_RX0 = 0, WCD9335_RX1, @@ -2318,6 +2379,132 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = { SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), }; +static const struct snd_soc_dapm_route wcd9335_audio_map[] = { + {"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"}, + + {"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"}, + + {"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"}, + + {"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"}, + + {"SLIM RX0", NULL, "SLIM RX0 MUX"}, + {"SLIM RX1", NULL, "SLIM RX1 MUX"}, + {"SLIM RX2", NULL, "SLIM RX2 MUX"}, + {"SLIM RX3", NULL, "SLIM RX3 MUX"}, + {"SLIM RX4", NULL, "SLIM RX4 MUX"}, + {"SLIM RX5", NULL, "SLIM RX5 MUX"}, + {"SLIM RX6", NULL, "SLIM RX6 MUX"}, + {"SLIM RX7", NULL, "SLIM RX7 MUX"}, + + WCD9335_INTERPOLATOR_PATH(0), + WCD9335_INTERPOLATOR_PATH(1), + WCD9335_INTERPOLATOR_PATH(2), + WCD9335_INTERPOLATOR_PATH(3), + WCD9335_INTERPOLATOR_PATH(4), + WCD9335_INTERPOLATOR_PATH(5), + WCD9335_INTERPOLATOR_PATH(6), + WCD9335_INTERPOLATOR_PATH(7), + WCD9335_INTERPOLATOR_PATH(8), + + /* EAR PA */ + {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 INTERP"}, + {"RX INT0 DAC", NULL, "RX INT0 DEM MUX"}, + {"RX INT0 DAC", NULL, "RX_BIAS"}, + {"EAR PA", NULL, "RX INT0 DAC"}, + {"EAR", NULL, "EAR PA"}, + + /* HPHL */ + {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 INTERP"}, + {"RX INT1 DAC", NULL, "RX INT1 DEM MUX"}, + {"RX INT1 DAC", NULL, "RX_BIAS"}, + {"HPHL PA", NULL, "RX INT1 DAC"}, + {"HPHL", NULL, "HPHL PA"}, + + /* HPHR */ + {"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 INTERP"}, + {"RX INT2 DAC", NULL, "RX INT2 DEM MUX"}, + {"RX INT2 DAC", NULL, "RX_BIAS"}, + {"HPHR PA", NULL, "RX INT2 DAC"}, + {"HPHR", NULL, "HPHR PA"}, + + /* LINEOUT1 */ + {"RX INT3 DAC", NULL, "RX INT3 INTERP"}, + {"RX INT3 DAC", NULL, "RX_BIAS"}, + {"LINEOUT1 PA", NULL, "RX INT3 DAC"}, + {"LINEOUT1", NULL, "LINEOUT1 PA"}, + + /* LINEOUT2 */ + {"RX INT4 DAC", NULL, "RX INT4 INTERP"}, + {"RX INT4 DAC", NULL, "RX_BIAS"}, + {"LINEOUT2 PA", NULL, "RX INT4 DAC"}, + {"LINEOUT2", NULL, "LINEOUT2 PA"}, + + /* LINEOUT3 */ + {"RX INT5 DAC", NULL, "RX INT5 INTERP"}, + {"RX INT5 DAC", NULL, "RX_BIAS"}, + {"LINEOUT3 PA", NULL, "RX INT5 DAC"}, + {"LINEOUT3", NULL, "LINEOUT3 PA"}, + + /* LINEOUT4 */ + {"RX INT6 DAC", NULL, "RX INT6 INTERP"}, + {"RX INT6 DAC", NULL, "RX_BIAS"}, + {"LINEOUT4 PA", NULL, "RX INT6 DAC"}, + {"LINEOUT4", NULL, "LINEOUT4 PA"}, + + /* SLIMBUS Connections */ + {"AIF1 CAP", NULL, "AIF1_CAP Mixer"}, + {"AIF2 CAP", NULL, "AIF2_CAP Mixer"}, + {"AIF3 CAP", NULL, "AIF3_CAP Mixer"}, + + /* ADC Mux */ + WCD9335_ADC_MUX_PATH(0), + WCD9335_ADC_MUX_PATH(1), + WCD9335_ADC_MUX_PATH(2), + WCD9335_ADC_MUX_PATH(3), + WCD9335_ADC_MUX_PATH(4), + WCD9335_ADC_MUX_PATH(5), + WCD9335_ADC_MUX_PATH(6), + WCD9335_ADC_MUX_PATH(7), + WCD9335_ADC_MUX_PATH(8), + + /* ADC Connections */ + {"ADC1", NULL, "AMIC1"}, + {"ADC2", NULL, "AMIC2"}, + {"ADC3", NULL, "AMIC3"}, + {"ADC4", NULL, "AMIC4"}, + {"ADC5", NULL, "AMIC5"}, + {"ADC6", NULL, "AMIC6"}, +}; + static int wcd9335_micbias_control(struct snd_soc_component *component, int micb_num, int req, bool is_dapm) { @@ -4727,6 +4914,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = { .num_controls = ARRAY_SIZE(wcd9335_snd_controls), .dapm_widgets = wcd9335_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets), + .dapm_routes = wcd9335_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd9335_audio_map), }; static int wcd9335_probe(struct wcd9335_codec *wcd) -- cgit v1.2.3-58-ga151 From 9f11d233d98aa7570210fbfd6cc6e11f5df8906d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 28 Jan 2019 14:27:53 +0000 Subject: ASoC: apq8096: add slim support Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/qcom/apq8096.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index fb45f396ab4a..94363fd6846a 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -9,6 +9,10 @@ #include #include "common.h" +#define SLIM_MAX_TX_PORTS 16 +#define SLIM_MAX_RX_PORTS 16 +#define WCD9335_DEFAULT_MCLK_RATE 9600000 + static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -23,14 +27,79 @@ static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static int msm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + int ret = 0; + + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret != 0 && ret != -ENOTSUPP) { + pr_err("failed to get codec chan map, err:%d\n", ret); + goto end; + } else if (ret == -ENOTSUPP) { + return 0; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, + rx_ch_cnt, rx_ch); + else + ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt, tx_ch, + 0, NULL); + if (ret != 0 && ret != -ENOTSUPP) + pr_err("Failed to set cpu chan map, err:%d\n", ret); + else if (ret == -ENOTSUPP) + ret = 0; +end: + return ret; +} + +static struct snd_soc_ops apq8096_ops = { + .hw_params = msm_snd_hw_params, +}; + +static int apq8096_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + /* + * Codec SLIMBUS configuration + * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13 + * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13 + * TX14, TX15, TX16 + */ + unsigned int rx_ch[SLIM_MAX_RX_PORTS] = {144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156}; + unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143}; + + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + + snd_soc_dai_set_sysclk(codec_dai, 0, WCD9335_DEFAULT_MCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); + + return 0; +} + static void apq8096_add_be_ops(struct snd_soc_card *card) { struct snd_soc_dai_link *link; int i; for_each_card_prelinks(card, i, link) { - if (link->no_pcm == 1) + if (link->no_pcm == 1) { link->be_hw_params_fixup = apq8096_be_hw_params_fixup; + link->init = apq8096_init; + link->ops = &apq8096_ops; + } } } -- cgit v1.2.3-58-ga151 From a8233b6c1972e1959cf84a021aeb61ddcd23cc26 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 29 Jan 2019 12:02:29 +0000 Subject: ASoC: wcd9335: Fix missing slimbus dependency Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 9b904f81863d..d47d321bfb96 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1117,6 +1117,7 @@ config SND_SOC_UDA1380 config SND_SOC_WCD9335 tristate "WCD9335 Codec" + depends on SLIMBUS select REGMAP_SLIMBUS help The WCD9335 is a standalone Hi-Fi audio CODEC IC, supports -- cgit v1.2.3-58-ga151 From 494a3503d684b6fc497623bc01e3e16f8def0499 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Sat, 19 Jan 2019 19:33:31 +0800 Subject: ASoC: Documentation: Add google, cros-ec-codec Add documentation for Chrome EC codec driver. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown --- .../bindings/sound/google,cros-ec-codec.txt | 26 ++++++++++++++++++++++ MAINTAINERS | 7 ++++++ 2 files changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt diff --git a/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt new file mode 100644 index 000000000000..1084f7f22eea --- /dev/null +++ b/Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt @@ -0,0 +1,26 @@ +* Audio codec controlled by ChromeOS EC + +Google's ChromeOS EC codec is a digital mic codec provided by the +Embedded Controller (EC) and is controlled via a host-command interface. + +An EC codec node should only be found as a sub-node of the EC node (see +Documentation/devicetree/bindings/mfd/cros-ec.txt). + +Required properties: +- compatible: Must contain "google,cros-ec-codec" +- #sound-dai-cells: Should be 1. The cell specifies number of DAIs. +- max-dmic-gain: A number for maximum gain in dB on digital microphone. + +Example: + +cros-ec@0 { + compatible = "google,cros-ec-spi"; + + ... + + cros_ec_codec: ec-codec { + compatible = "google,cros-ec-codec"; + #sound-dai-cells = <1>; + max-dmic-gain = <43>; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index 9f64f8d3740e..3bcc5465e460 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3687,6 +3687,13 @@ N: cros_ec N: cros-ec F: drivers/power/supply/cros_usbpd-charger.c +CHROMEOS EC CODEC DRIVER +M: Cheng-Yi Chiang +S: Maintained +R: Enric Balletbo i Serra +R: Guenter Roeck +F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt + CIRRUS LOGIC AUDIO CODEC DRIVERS M: Brian Austin M: Paul Handrigan -- cgit v1.2.3-58-ga151 From b291f42a37187cbd78ff59a34f2751164baad8bf Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Sat, 19 Jan 2019 19:33:33 +0800 Subject: ASoC: cros_ec_codec: Add codec driver for Cros EC Add a codec driver to control ChromeOS EC codec. Use EC Host command to enable/disable I2S recording and control other configurations. Signed-off-by: Cheng-Yi Chiang Reviewed-by: Enric Balletbo i Serra Signed-off-by: Mark Brown --- MAINTAINERS | 1 + sound/soc/codecs/Kconfig | 8 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cros_ec_codec.c | 441 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 452 insertions(+) create mode 100644 sound/soc/codecs/cros_ec_codec.c diff --git a/MAINTAINERS b/MAINTAINERS index 3bcc5465e460..9d846fb07442 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3693,6 +3693,7 @@ S: Maintained R: Enric Balletbo i Serra R: Guenter Roeck F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt +F: sound/soc/codecs/cros_ec_codec.* CIRRUS LOGIC AUDIO CODEC DRIVERS M: Brian Austin diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d47d321bfb96..a15710c8a95f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -50,6 +50,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_BT_SCO select SND_SOC_BD28623 select SND_SOC_CQ0093VC + select SND_SOC_CROS_EC_CODEC if MFD_CROS_EC select SND_SOC_CS35L32 if I2C select SND_SOC_CS35L33 if I2C select SND_SOC_CS35L34 if I2C @@ -459,6 +460,13 @@ config SND_SOC_CPCAP config SND_SOC_CQ0093VC tristate +config SND_SOC_CROS_EC_CODEC + tristate "codec driver for ChromeOS EC" + depends on MFD_CROS_EC + help + If you say yes here you will get support for the + ChromeOS Embedded Controller's Audio Codec. + config SND_SOC_CS35L32 tristate "Cirrus Logic CS35L32 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4cf29e3dbff6..3d7a59761c08 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -42,6 +42,7 @@ snd-soc-bd28623-objs := bd28623.o snd-soc-bt-sco-objs := bt-sco.o snd-soc-cpcap-objs := cpcap.o snd-soc-cq93vc-objs := cq93vc.o +snd-soc-cros-ec-codec-objs := cros_ec_codec.o snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o @@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CPCAP) += snd-soc-cpcap.o +obj-$(CONFIG_SND_SOC_CROS_EC_CODEC) += snd-soc-cros-ec-codec.o obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c new file mode 100644 index 000000000000..b14100b6a939 --- /dev/null +++ b/sound/soc/codecs/cros_ec_codec.c @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for ChromeOS Embedded Controller codec. + * + * This driver uses the cros-ec interface to communicate with the ChromeOS + * EC for audio function. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "cros-ec-codec" + +/** + * struct cros_ec_codec_data - ChromeOS EC codec driver data. + * @dev: Device structure used in sysfs. + * @ec_device: cros_ec_device structure to talk to the physical device. + * @component: Pointer to the component. + * @max_dmic_gain: Maximum gain in dB supported by EC codec. + */ +struct cros_ec_codec_data { + struct device *dev; + struct cros_ec_device *ec_device; + struct snd_soc_component *component; + unsigned int max_dmic_gain; +}; + +static const DECLARE_TLV_DB_SCALE(ec_mic_gain_tlv, 0, 100, 0); + +static int ec_command_get_gain(struct snd_soc_component *component, + struct ec_param_codec_i2s *param, + struct ec_response_codec_gain *resp) +{ + struct cros_ec_codec_data *codec_data = + snd_soc_component_get_drvdata(component); + struct cros_ec_device *ec_device = codec_data->ec_device; + u8 buffer[sizeof(struct cros_ec_command) + + max(sizeof(struct ec_param_codec_i2s), + sizeof(struct ec_response_codec_gain))]; + struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; + int ret; + + msg->version = 0; + msg->command = EC_CMD_CODEC_I2S; + msg->outsize = sizeof(struct ec_param_codec_i2s); + msg->insize = sizeof(struct ec_response_codec_gain); + + memcpy(msg->data, param, msg->outsize); + + ret = cros_ec_cmd_xfer_status(ec_device, msg); + if (ret > 0) + memcpy(resp, msg->data, msg->insize); + + return ret; +} + +/* + * Wrapper for EC command without response. + */ +static int ec_command_no_resp(struct snd_soc_component *component, + struct ec_param_codec_i2s *param) +{ + struct cros_ec_codec_data *codec_data = + snd_soc_component_get_drvdata(component); + struct cros_ec_device *ec_device = codec_data->ec_device; + u8 buffer[sizeof(struct cros_ec_command) + + sizeof(struct ec_param_codec_i2s)]; + struct cros_ec_command *msg = (struct cros_ec_command *)&buffer; + + msg->version = 0; + msg->command = EC_CMD_CODEC_I2S; + msg->outsize = sizeof(struct ec_param_codec_i2s); + msg->insize = 0; + + memcpy(msg->data, param, msg->outsize); + + return cros_ec_cmd_xfer_status(ec_device, msg); +} + +static int set_i2s_config(struct snd_soc_component *component, + enum ec_i2s_config i2s_config) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set I2S format to %u\n", __func__, + i2s_config); + + param.cmd = EC_CODEC_I2S_SET_CONFIG; + param.i2s_config = i2s_config; + + return ec_command_no_resp(component, ¶m); +} + +static int cros_ec_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + enum ec_i2s_config i2s_config; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + i2s_config = EC_DAI_FMT_I2S; + break; + + case SND_SOC_DAIFMT_RIGHT_J: + i2s_config = EC_DAI_FMT_RIGHT_J; + break; + + case SND_SOC_DAIFMT_LEFT_J: + i2s_config = EC_DAI_FMT_LEFT_J; + break; + + case SND_SOC_DAIFMT_DSP_A: + i2s_config = EC_DAI_FMT_PCM_A; + break; + + case SND_SOC_DAIFMT_DSP_B: + i2s_config = EC_DAI_FMT_PCM_B; + break; + + default: + return -EINVAL; + } + + return set_i2s_config(component, i2s_config); +} + +static int set_i2s_sample_depth(struct snd_soc_component *component, + enum ec_sample_depth_value depth) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set depth to %u\n", __func__, depth); + + param.cmd = EC_CODEC_SET_SAMPLE_DEPTH; + param.depth = depth; + + return ec_command_no_resp(component, ¶m); +} + +static int set_i2s_bclk(struct snd_soc_component *component, uint32_t bclk) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set i2s bclk to %u\n", __func__, bclk); + + param.cmd = EC_CODEC_I2S_SET_BCLK; + param.bclk = bclk; + + return ec_command_no_resp(component, ¶m); +} + +static int cros_ec_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + unsigned int rate, bclk; + int ret; + + rate = params_rate(params); + if (rate != 48000) + return -EINVAL; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + ret = set_i2s_sample_depth(component, EC_CODEC_SAMPLE_DEPTH_16); + break; + case SNDRV_PCM_FORMAT_S24_LE: + ret = set_i2s_sample_depth(component, EC_CODEC_SAMPLE_DEPTH_24); + break; + default: + return -EINVAL; + } + if (ret < 0) + return ret; + + bclk = snd_soc_params_to_bclk(params); + return set_i2s_bclk(component, bclk); +} + +static const struct snd_soc_dai_ops cros_ec_i2s_dai_ops = { + .hw_params = cros_ec_i2s_hw_params, + .set_fmt = cros_ec_i2s_set_dai_fmt, +}; + +struct snd_soc_dai_driver cros_ec_dai[] = { + { + .name = "cros_ec_codec I2S", + .id = 0, + .capture = { + .stream_name = "I2S Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, + .ops = &cros_ec_i2s_dai_ops, + } +}; + +static int get_ec_mic_gain(struct snd_soc_component *component, + u8 *left, u8 *right) +{ + struct ec_param_codec_i2s param; + struct ec_response_codec_gain resp; + int ret; + + param.cmd = EC_CODEC_GET_GAIN; + + ret = ec_command_get_gain(component, ¶m, &resp); + if (ret < 0) + return ret; + + *left = resp.left; + *right = resp.right; + + return 0; +} + +static int mic_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + u8 left, right; + int ret; + + ret = get_ec_mic_gain(component, &left, &right); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = left; + ucontrol->value.integer.value[1] = right; + + return 0; +} + +static int set_ec_mic_gain(struct snd_soc_component *component, + u8 left, u8 right) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set mic gain to %u, %u\n", + __func__, left, right); + + param.cmd = EC_CODEC_SET_GAIN; + param.gain.left = left; + param.gain.right = right; + + return ec_command_no_resp(component, ¶m); +} + +static int mic_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct cros_ec_codec_data *codec_data = + snd_soc_component_get_drvdata(component); + int left = ucontrol->value.integer.value[0]; + int right = ucontrol->value.integer.value[1]; + unsigned int max_dmic_gain = codec_data->max_dmic_gain; + + if (left > max_dmic_gain || right > max_dmic_gain) + return -EINVAL; + + return set_ec_mic_gain(component, (u8)left, (u8)right); +} + +static struct snd_kcontrol_new mic_gain_control = + SOC_DOUBLE_EXT_TLV("EC Mic Gain", SND_SOC_NOPM, SND_SOC_NOPM, 0, 0, 0, + mic_gain_get, mic_gain_put, ec_mic_gain_tlv); + +static int enable_i2s(struct snd_soc_component *component, int enable) +{ + struct ec_param_codec_i2s param; + + dev_dbg(component->dev, "%s set i2s to %u\n", __func__, enable); + + param.cmd = EC_CODEC_I2S_ENABLE; + param.i2s_enable = enable; + + return ec_command_no_resp(component, ¶m); +} + +static int cros_ec_i2s_enable_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + dev_dbg(component->dev, + "%s got SND_SOC_DAPM_PRE_PMU event\n", __func__); + return enable_i2s(component, 1); + + case SND_SOC_DAPM_PRE_PMD: + dev_dbg(component->dev, + "%s got SND_SOC_DAPM_PRE_PMD event\n", __func__); + return enable_i2s(component, 0); + } + + return 0; +} + +/* + * The goal of this DAPM route is to turn on/off I2S using EC + * host command when capture stream is started/stopped. + */ +static const struct snd_soc_dapm_widget cros_ec_codec_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMIC"), + + /* + * Control EC to enable/disable I2S. + */ + SND_SOC_DAPM_SUPPLY("I2S Enable", SND_SOC_NOPM, + 0, 0, cros_ec_i2s_enable_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_AIF_OUT("I2STX", "I2S Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route cros_ec_codec_dapm_routes[] = { + { "I2STX", NULL, "DMIC" }, + { "I2STX", NULL, "I2S Enable" }, +}; + +/* + * Read maximum gain from device property and set it to mixer control. + */ +static int cros_ec_set_gain_range(struct device *dev) +{ + struct soc_mixer_control *control; + struct cros_ec_codec_data *codec_data = dev_get_drvdata(dev); + int rc; + + rc = device_property_read_u32(dev, "max-dmic-gain", + &codec_data->max_dmic_gain); + if (rc) + return rc; + + control = (struct soc_mixer_control *) + mic_gain_control.private_value; + control->max = codec_data->max_dmic_gain; + control->platform_max = codec_data->max_dmic_gain; + + return 0; +} + +static int cros_ec_codec_probe(struct snd_soc_component *component) +{ + int rc; + + struct cros_ec_codec_data *codec_data = + snd_soc_component_get_drvdata(component); + + rc = cros_ec_set_gain_range(codec_data->dev); + if (rc) + return rc; + + return snd_soc_add_component_controls(component, &mic_gain_control, 1); +} + +static const struct snd_soc_component_driver cros_ec_component_driver = { + .probe = cros_ec_codec_probe, + .dapm_widgets = cros_ec_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cros_ec_codec_dapm_widgets), + .dapm_routes = cros_ec_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cros_ec_codec_dapm_routes), +}; + +/* + * Platform device and platform driver fro cros-ec-codec. + */ +static int cros_ec_codec_platform_probe(struct platform_device *pd) +{ + struct device *dev = &pd->dev; + struct cros_ec_device *ec_device = dev_get_drvdata(pd->dev.parent); + struct cros_ec_codec_data *codec_data; + + codec_data = devm_kzalloc(dev, sizeof(struct cros_ec_codec_data), + GFP_KERNEL); + if (!codec_data) + return -ENOMEM; + + codec_data->dev = dev; + codec_data->ec_device = ec_device; + + platform_set_drvdata(pd, codec_data); + + return snd_soc_register_component(dev, &cros_ec_component_driver, + cros_ec_dai, ARRAY_SIZE(cros_ec_dai)); +} + +#ifdef CONFIG_OF +static const struct of_device_id cros_ec_codec_of_match[] = { + { .compatible = "google,cros-ec-codec" }, + {}, +}; +MODULE_DEVICE_TABLE(of, cros_ec_codec_of_match); +#endif + +static struct platform_driver cros_ec_codec_platform_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(cros_ec_codec_of_match), + }, + .probe = cros_ec_codec_platform_probe, +}; + +module_platform_driver(cros_ec_codec_platform_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ChromeOS EC codec driver"); +MODULE_AUTHOR("Cheng-Yi Chiang "); +MODULE_ALIAS("platform:" DRV_NAME); -- cgit v1.2.3-58-ga151 From 53b6d0adffb0505db5332589e78da1c66f7e626a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 29 Jan 2019 09:42:20 -0600 Subject: ASoC: Intel: cht_bsw_rt5672: remove useless test For some reason we test if the machine is passed as a parameter before fixing up the codec name. This is unnecessary, generates false positives in static analysis tools and done only in this machine driver, remove and adjust indentation. Reported-by: Colin Ian King Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index f1c1f9dd5353..3d5a2b3a06f0 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -411,18 +411,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) strcpy(drv->codec_name, RT5672_I2C_DEFAULT); /* fixup codec name based on HID */ - if (mach) { - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { - snprintf(drv->codec_name, sizeof(drv->codec_name), - "i2c-%s", i2c_name); - for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { - if (!strcmp(cht_dailink[i].codec_name, - RT5672_I2C_DEFAULT)) { - cht_dailink[i].codec_name = - drv->codec_name; - break; - } + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); + if (i2c_name) { + snprintf(drv->codec_name, sizeof(drv->codec_name), + "i2c-%s", i2c_name); + for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { + if (!strcmp(cht_dailink[i].codec_name, + RT5672_I2C_DEFAULT)) { + cht_dailink[i].codec_name = drv->codec_name; + break; } } } -- cgit v1.2.3-58-ga151 From 33ae6ae2111c3118d8d15eba331b6ba5932825c9 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 25 Jan 2019 14:06:42 -0600 Subject: ASoC: topology: Reduce number of dereferences when accessing dobj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have passed dobj, there is no reason to access it through containing structs. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 045ef136903d..b02c41614f96 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -382,10 +382,10 @@ static void remove_mixer(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - if (sm->dobj.control.kcontrol->tlv.p) - p = sm->dobj.control.kcontrol->tlv.p; - snd_ctl_remove(card, sm->dobj.control.kcontrol); - list_del(&sm->dobj.list); + if (dobj->control.kcontrol->tlv.p) + p = dobj->control.kcontrol->tlv.p; + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sm); kfree(p); } @@ -404,12 +404,12 @@ static void remove_enum(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, se->dobj.control.kcontrol); - list_del(&se->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) - kfree(se->dobj.control.dtexts[i]); + kfree(dobj->control.dtexts[i]); kfree(se); } @@ -427,8 +427,8 @@ static void remove_bytes(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, sb->dobj.control.kcontrol); - list_del(&sb->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sb); } @@ -464,9 +464,9 @@ static void remove_widget(struct snd_soc_component *comp, snd_ctl_remove(card, kcontrol); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) - kfree(se->dobj.control.dtexts[j]); + kfree(dobj->control.dtexts[j]); kfree(se); kfree(w->kcontrol_news[i].name); -- cgit v1.2.3-58-ga151 From a46e8393d128d4e5f722b47f708a0d5de91e0176 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 25 Jan 2019 14:06:43 -0600 Subject: ASoC: topology: Remove widgets from dobj list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when we unload and reload machine driver few times we end with corrupted list and try to cleanup no longer existing objects. Fix this by removing dobj from the list. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b02c41614f96..abc2d804d5bf 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -493,6 +493,8 @@ static void remove_widget(struct snd_soc_component *comp, free_news: kfree(w->kcontrol_news); + list_del(&dobj->list); + /* widget w is freed by soc-dapm.c */ } -- cgit v1.2.3-58-ga151 From 34db6a3e91d8f6f6fefbbd9ad7e1efc6f8d440e0 Mon Sep 17 00:00:00 2001 From: Amadeusz Sławiński Date: Fri, 25 Jan 2019 14:06:44 -0600 Subject: ASoC: topology: Fix memory leak from soc_tplg_denum_create_texts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dtexts is two dimensional array, so we also need to free it after freeing its fields. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index abc2d804d5bf..71bc5b8a9bd3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -410,6 +410,7 @@ static void remove_enum(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) kfree(dobj->control.dtexts[i]); + kfree(dobj->control.dtexts); kfree(se); } @@ -467,6 +468,7 @@ static void remove_widget(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) kfree(dobj->control.dtexts[j]); + kfree(dobj->control.dtexts); kfree(se); kfree(w->kcontrol_news[i].name); @@ -1361,6 +1363,7 @@ err_se: kfree(se->dobj.control.dvalues); for (j = 0; j < ec->items; j++) kfree(se->dobj.control.dtexts[j]); + kfree(se->dobj.control.dtexts); kfree(se); kfree(kc[i].name); -- cgit v1.2.3-58-ga151 From 7620fe9161cec2722db880affe03f5e9e2bb93d5 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 25 Jan 2019 14:06:45 -0600 Subject: ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create template.sname and template.name are only freed when an error occur. They should be freed in the success return case, too. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 71bc5b8a9bd3..2cb0a05e2368 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1583,6 +1583,9 @@ widget: if (ret < 0) goto ready_err; + kfree(template.sname); + kfree(template.name); + return 0; ready_err: -- cgit v1.2.3-58-ga151 From 5c30f43f0625a792c30e465f21dbeb1bb4dfc40b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 25 Jan 2019 14:06:46 -0600 Subject: ASoC: topology: add SND_SOC_DOBJ_GRAPH type for dapm routes Add a new dobj type SND_SOC_DOBJ_GRAPH for dapm routes and add snd_soc_dobj member to struct snd_soc_dapm_route. This enables device drivers to save driver specific data pertaining to dapm routes and also be able to clean up the data when the driver module is unloaded. Also, reorder the snd_soc_dobj_type types to align with matching topology header types. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 ++ include/sound/soc-topology.h | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index bd8163f151cb..46f2ba3ffcb7 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -540,6 +540,8 @@ struct snd_soc_dapm_route { /* Note: currently only supported for links where source is a supply */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); + + struct snd_soc_dobj dobj; }; /* dapm audio path between two widgets */ diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index fa4b8413d2e2..8c43cfc240fa 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -38,12 +38,13 @@ struct snd_soc_dapm_route; enum snd_soc_dobj_type { SND_SOC_DOBJ_NONE = 0, /* object is not dynamic */ SND_SOC_DOBJ_MIXER, - SND_SOC_DOBJ_ENUM, SND_SOC_DOBJ_BYTES, - SND_SOC_DOBJ_PCM, + SND_SOC_DOBJ_ENUM, + SND_SOC_DOBJ_GRAPH, + SND_SOC_DOBJ_WIDGET, SND_SOC_DOBJ_DAI_LINK, + SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, - SND_SOC_DOBJ_WIDGET, }; /* dynamic control object */ -- cgit v1.2.3-58-ga151 From 7df04ea7a31eaa75bdad2905f07cc097b15558ee Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 25 Jan 2019 14:06:47 -0600 Subject: ASoC: topology: modify dapm route loading routine and add dapm route unloading struct snd_soc_dapm_route has been modified to be a dynamic object so that it can be used to save driver specific data while parsing topology and clean up driver-specific data during driver unloading. This patch makes the following changes to accomplish the above: 1. Set the dobj member of snd_soc_dapm_route during the SOC_TPLG_PASS_GRAPH pass of topology parsing. 2. Add the remove_route() routine that will be called while removing all dynamic objects from the component driver. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 102 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 2cb0a05e2368..23d421370e6c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -433,6 +433,23 @@ static void remove_bytes(struct snd_soc_component *comp, kfree(sb); } +/* remove a route */ +static void remove_route(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + struct snd_soc_dapm_route *route = + container_of(dobj, struct snd_soc_dapm_route, dobj); + + if (pass != SOC_TPLG_PASS_GRAPH) + return; + + if (dobj->ops && dobj->ops->dapm_route_unload) + dobj->ops->dapm_route_unload(comp, dobj); + + list_del(&dobj->list); + kfree(route); +} + /* remove a widget and it's kcontrols - routes must be removed first */ static void remove_widget(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) @@ -1119,9 +1136,10 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; - struct snd_soc_dapm_route route; struct snd_soc_tplg_dapm_graph_elem *elem; - int count = hdr->count, i; + struct snd_soc_dapm_route **routes; + int count = hdr->count, i, j; + int ret = 0; if (tplg->pass != SOC_TPLG_PASS_GRAPH) { tplg->pos += hdr->size + hdr->payload_size; @@ -1140,36 +1158,85 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count, hdr->index); + /* allocate memory for pointer to array of dapm routes */ + routes = kcalloc(count, sizeof(struct snd_soc_dapm_route *), + GFP_KERNEL); + if (!routes) + return -ENOMEM; + + /* + * allocate memory for each dapm route in the array. + * This needs to be done individually so that + * each route can be freed when it is removed in remove_route(). + */ + for (i = 0; i < count; i++) { + routes[i] = kzalloc(sizeof(*routes[i]), GFP_KERNEL); + if (!routes[i]) { + /* free previously allocated memory */ + for (j = 0; j < i; j++) + kfree(routes[j]); + + kfree(routes); + return -ENOMEM; + } + } + for (i = 0; i < count; i++) { elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem); /* validate routes */ if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } + + routes[i]->source = elem->source; + routes[i]->sink = elem->sink; - route.source = elem->source; - route.sink = elem->sink; - route.connected = NULL; /* set to NULL atm for tplg users */ + /* set to NULL atm for tplg users */ + routes[i]->connected = NULL; if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0) - route.control = NULL; + routes[i]->control = NULL; else - route.control = elem->control; + routes[i]->control = elem->control; + + /* add route dobj to dobj_list */ + routes[i]->dobj.type = SND_SOC_DOBJ_GRAPH; + routes[i]->dobj.ops = tplg->ops; + routes[i]->dobj.index = tplg->index; + list_add(&routes[i]->dobj.list, &tplg->comp->dobj_list); - soc_tplg_add_route(tplg, &route); + soc_tplg_add_route(tplg, routes[i]); /* add route, but keep going if some fail */ - snd_soc_dapm_add_routes(dapm, &route, 1); + snd_soc_dapm_add_routes(dapm, routes[i], 1); } - return 0; + /* free memory allocated for all dapm routes in case of error */ + if (ret < 0) + for (i = 0; i < count ; i++) + kfree(routes[i]); + + /* + * free pointer to array of dapm routes as this is no longer needed. + * The memory allocated for each dapm route will be freed + * when it is removed in remove_route(). + */ + kfree(routes); + + return ret; } static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( @@ -2570,6 +2637,9 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_BYTES: remove_bytes(comp, dobj, pass); break; + case SND_SOC_DOBJ_GRAPH: + remove_route(comp, dobj, pass); + break; case SND_SOC_DOBJ_WIDGET: remove_widget(comp, dobj, pass); break; -- cgit v1.2.3-58-ga151 From 27e27e6555d3a1dd3c906796af6d8e7eb538857f Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 29 Jan 2019 16:04:44 +0800 Subject: dt-bindings: ASoC: Add Spreadtrum DMA platform documentation Add documentation for Spreadtrum DMA platform driver. Signed-off-by: Baolin Wang Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sprd-pcm.txt | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/sprd-pcm.txt diff --git a/Documentation/devicetree/bindings/sound/sprd-pcm.txt b/Documentation/devicetree/bindings/sound/sprd-pcm.txt new file mode 100644 index 000000000000..4b23e84b2e57 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sprd-pcm.txt @@ -0,0 +1,23 @@ +* Spreadtrum DMA platfrom bindings + +Required properties: +- compatible: Should be "sprd,pcm-platform". +- dmas: Specify the list of DMA controller phandle and DMA request line ordered pairs. +- dma-names: Identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. + +Example: + + audio_platform:platform@0 { + compatible = "sprd,pcm-platform"; + dmas = <&agcp_dma 1 1>, <&agcp_dma 2 2>, + <&agcp_dma 3 3>, <&agcp_dma 4 4>, + <&agcp_dma 5 5>, <&agcp_dma 6 6>, + <&agcp_dma 7 7>, <&agcp_dma 8 8>, + <&agcp_dma 9 9>, <&agcp_dma 10 10>; + dma-names = "normal_p_l", "normal_p_r", + "normal_c_l", "normal_c_r", + "voice_c", "fast_p", + "loop_c", "loop_p", + "voip_c", "voip_p"; + }; -- cgit v1.2.3-58-ga151 From 42fea318e1d19c0214ed4336d19f512c5d78cc3b Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Tue, 29 Jan 2019 16:04:45 +0800 Subject: ASoC: sprd: Add Spreadtrum audio DMA platfrom driver The Spreadtrum DMA engine uses the link-list mode to support audio playback or capture, thus this patch adds audio DMA platform support for CPU DAI to trigger DMA link-list transfer. Signed-off-by: Baolin Wang Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/sprd/Kconfig | 6 + sound/soc/sprd/Makefile | 4 + sound/soc/sprd/sprd-pcm-dma.c | 562 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/sprd/sprd-pcm-dma.h | 15 ++ 6 files changed, 589 insertions(+) create mode 100644 sound/soc/sprd/Kconfig create mode 100644 sound/soc/sprd/Makefile create mode 100644 sound/soc/sprd/sprd-pcm-dma.c create mode 100644 sound/soc/sprd/sprd-pcm-dma.h diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 6592a422a047..aa35940f5c50 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -64,6 +64,7 @@ source "sound/soc/samsung/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/sirf/Kconfig" source "sound/soc/spear/Kconfig" +source "sound/soc/sprd/Kconfig" source "sound/soc/sti/Kconfig" source "sound/soc/stm/Kconfig" source "sound/soc/sunxi/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 48c48c1c893c..974fb9821e17 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_SND_SOC) += samsung/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += sirf/ obj-$(CONFIG_SND_SOC) += spear/ +obj-$(CONFIG_SND_SOC) += sprd/ obj-$(CONFIG_SND_SOC) += sti/ obj-$(CONFIG_SND_SOC) += stm/ obj-$(CONFIG_SND_SOC) += sunxi/ diff --git a/sound/soc/sprd/Kconfig b/sound/soc/sprd/Kconfig new file mode 100644 index 000000000000..43ece7daf0e9 --- /dev/null +++ b/sound/soc/sprd/Kconfig @@ -0,0 +1,6 @@ +config SND_SOC_SPRD + tristate "SoC Audio for the Spreadtrum SoC chips" + depends on ARCH_SPRD || COMPILE_TEST + help + Say Y or M if you want to add support for codecs attached to + the Spreadtrum SoCs' Audio interfaces. diff --git a/sound/soc/sprd/Makefile b/sound/soc/sprd/Makefile new file mode 100644 index 000000000000..47620e57a9f2 --- /dev/null +++ b/sound/soc/sprd/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +# Spreadtrum Audio Support + +obj-$(CONFIG_SND_SOC_SPRD) += sprd-pcm-dma.o diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c new file mode 100644 index 000000000000..cbb27c4abeba --- /dev/null +++ b/sound/soc/sprd/sprd-pcm-dma.c @@ -0,0 +1,562 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2019 Spreadtrum Communications Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sprd-pcm-dma.h" + +#define DRV_NAME "sprd_pcm_dma" +#define SPRD_PCM_DMA_LINKLIST_SIZE 64 +#define SPRD_PCM_DMA_BRUST_LEN 640 + +struct sprd_pcm_dma_data { + struct dma_chan *chan; + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + dma_addr_t phys; + void *virt; + int pre_pointer; +}; + +struct sprd_pcm_dma_private { + struct snd_pcm_substream *substream; + struct sprd_pcm_dma_params *params; + struct sprd_pcm_dma_data data[SPRD_PCM_CHANNEL_MAX]; + int hw_chan; + int dma_addr_offset; +}; + +static const struct snd_pcm_hardware sprd_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + .period_bytes_min = 1, + .period_bytes_max = 64 * 1024, + .periods_min = 1, + .periods_max = PAGE_SIZE / SPRD_PCM_DMA_LINKLIST_SIZE, + .buffer_bytes_max = 64 * 1024, +}; + +static int sprd_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; + struct sprd_pcm_dma_private *dma_private; + int hw_chan = SPRD_PCM_CHANNEL_MAX; + int size, ret, i; + + snd_soc_set_runtime_hwparams(substream, &sprd_pcm_hardware); + + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + SPRD_PCM_DMA_BRUST_LEN); + if (ret < 0) + return ret; + + ret = snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + SPRD_PCM_DMA_BRUST_LEN); + if (ret < 0) + return ret; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + dma_private = devm_kzalloc(dev, sizeof(*dma_private), GFP_KERNEL); + if (!dma_private) + return -ENOMEM; + + size = runtime->hw.periods_max * SPRD_PCM_DMA_LINKLIST_SIZE; + + for (i = 0; i < hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + data->virt = dmam_alloc_coherent(dev, size, &data->phys, + GFP_KERNEL); + if (!data->virt) { + ret = -ENOMEM; + goto error; + } + } + + dma_private->hw_chan = hw_chan; + runtime->private_data = dma_private; + dma_private->substream = substream; + + return 0; + +error: + for (i = 0; i < hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->virt) + dmam_free_coherent(dev, size, data->virt, data->phys); + } + + devm_kfree(dev, dma_private); + return ret; +} + +static int sprd_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; + int size = runtime->hw.periods_max * SPRD_PCM_DMA_LINKLIST_SIZE; + int i; + + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + dmam_free_coherent(dev, size, data->virt, data->phys); + } + + devm_kfree(dev, dma_private); + + return 0; +} + +static void sprd_pcm_dma_complete(void *data) +{ + struct sprd_pcm_dma_private *dma_private = data; + struct snd_pcm_substream *substream = dma_private->substream; + + snd_pcm_period_elapsed(substream); +} + +static void sprd_pcm_release_dma_channel(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + int i; + + for (i = 0; i < SPRD_PCM_CHANNEL_MAX; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->chan) { + dma_release_channel(data->chan); + data->chan = NULL; + } + } +} + +static int sprd_pcm_request_dma_channel(struct snd_pcm_substream *substream, + int channels) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; + struct sprd_pcm_dma_params *dma_params = dma_private->params; + int i; + + if (channels > SPRD_PCM_CHANNEL_MAX) { + dev_err(dev, "invalid dma channel number:%d\n", channels); + return -EINVAL; + } + + for (i = 0; i < channels; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + data->chan = dma_request_slave_channel(dev, + dma_params->chan_name[i]); + if (!data->chan) { + dev_err(dev, "failed to request dma channel:%s\n", + dma_params->chan_name[i]); + sprd_pcm_release_dma_channel(substream); + return -ENODEV; + } + } + + return 0; +} + +static int sprd_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct sprd_pcm_dma_params *dma_params; + size_t totsize = params_buffer_bytes(params); + size_t period = params_period_bytes(params); + int channels = params_channels(params); + int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + struct scatterlist *sg; + unsigned long flags; + int ret, i, j, sg_num; + + dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + if (!dma_params) { + dev_warn(component->dev, "no dma parameters setting\n"); + dma_private->params = NULL; + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = totsize; + return 0; + } + + if (!dma_private->params) { + dma_private->params = dma_params; + ret = sprd_pcm_request_dma_channel(substream, channels); + if (ret) + return ret; + } + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + runtime->dma_bytes = totsize; + sg_num = totsize / period; + dma_private->dma_addr_offset = totsize / channels; + + sg = devm_kcalloc(component->dev, sg_num, sizeof(*sg), GFP_KERNEL); + if (!sg) { + ret = -ENOMEM; + goto sg_err; + } + + for (i = 0; i < channels; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + struct dma_chan *chan = data->chan; + struct dma_slave_config config = { }; + struct sprd_dma_linklist link = { }; + enum dma_transfer_direction dir; + struct scatterlist *sgt = sg; + + config.src_maxburst = dma_params->fragment_len[i]; + config.src_addr_width = dma_params->datawidth[i]; + config.dst_addr_width = dma_params->datawidth[i]; + if (is_playback) { + config.src_addr = runtime->dma_addr + + i * dma_private->dma_addr_offset; + config.dst_addr = dma_params->dev_phys[i]; + dir = DMA_MEM_TO_DEV; + } else { + config.src_addr = dma_params->dev_phys[i]; + config.dst_addr = runtime->dma_addr + + i * dma_private->dma_addr_offset; + dir = DMA_DEV_TO_MEM; + } + + sg_init_table(sgt, sg_num); + for (j = 0; j < sg_num; j++, sgt++) { + u32 sg_len = period / channels; + + sg_dma_len(sgt) = sg_len; + sg_dma_address(sgt) = runtime->dma_addr + + i * dma_private->dma_addr_offset + sg_len * j; + } + + /* + * Configure the link-list address for the DMA engine link-list + * mode. + */ + link.virt_addr = (unsigned long)data->virt; + link.phy_addr = data->phys; + + ret = dmaengine_slave_config(chan, &config); + if (ret) { + dev_err(component->dev, + "failed to set slave configuration: %d\n", ret); + goto config_err; + } + + /* + * We configure the DMA request mode, interrupt mode, channel + * mode and channel trigger mode by the flags. + */ + flags = SPRD_DMA_FLAGS(SPRD_DMA_CHN_MODE_NONE, SPRD_DMA_NO_TRG, + SPRD_DMA_FRAG_REQ, SPRD_DMA_TRANS_INT); + data->desc = chan->device->device_prep_slave_sg(chan, sg, + sg_num, dir, + flags, &link); + if (!data->desc) { + dev_err(component->dev, "failed to prepare slave sg\n"); + ret = -ENOMEM; + goto config_err; + } + + if (!runtime->no_period_wakeup) { + data->desc->callback = sprd_pcm_dma_complete; + data->desc->callback_param = dma_private; + } + } + + devm_kfree(component->dev, sg); + + return 0; + +config_err: + devm_kfree(component->dev, sg); +sg_err: + sprd_pcm_release_dma_channel(substream); + return ret; +} + +static int sprd_pcm_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_set_runtime_buffer(substream, NULL); + sprd_pcm_release_dma_channel(substream); + + return 0; +} + +static int sprd_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct sprd_pcm_dma_private *dma_private = + substream->runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + int ret = 0, i; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (!data->desc) + continue; + + data->cookie = dmaengine_submit(data->desc); + ret = dma_submit_error(data->cookie); + if (ret) { + dev_err(component->dev, + "failed to submit dma request: %d\n", + ret); + return ret; + } + + dma_async_issue_pending(data->chan); + } + + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->chan) + dmaengine_resume(data->chan); + } + + break; + case SNDRV_PCM_TRIGGER_STOP: + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->chan) + dmaengine_terminate_async(data->chan); + } + + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (data->chan) + dmaengine_pause(data->chan); + } + + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t sprd_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sprd_pcm_dma_private *dma_private = runtime->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + int pointer[SPRD_PCM_CHANNEL_MAX]; + int bytes_of_pointer = 0, sel_max = 0, i; + snd_pcm_uframes_t x; + struct dma_tx_state state; + enum dma_status status; + + for (i = 0; i < dma_private->hw_chan; i++) { + struct sprd_pcm_dma_data *data = &dma_private->data[i]; + + if (!data->chan) + continue; + + status = dmaengine_tx_status(data->chan, data->cookie, &state); + if (status == DMA_ERROR) { + dev_err(component->dev, + "failed to get dma channel %d status\n", i); + return 0; + } + + /* + * We just get current transfer address from the DMA engine, so + * we need convert to current pointer. + */ + pointer[i] = state.residue - runtime->dma_addr - + i * dma_private->dma_addr_offset; + + if (i == 0) { + bytes_of_pointer = pointer[i]; + sel_max = pointer[i] < data->pre_pointer ? 1 : 0; + } else { + sel_max ^= pointer[i] < data->pre_pointer ? 1 : 0; + + if (sel_max) + bytes_of_pointer = + max(pointer[i], pointer[i - 1]) << 1; + else + bytes_of_pointer = + min(pointer[i], pointer[i - 1]) << 1; + } + + data->pre_pointer = pointer[i]; + } + + x = bytes_to_frames(runtime, bytes_of_pointer); + if (x == runtime->buffer_size) + x = 0; + + return x; +} + +static int sprd_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + return remap_pfn_range(vma, vma->vm_start, + runtime->dma_addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +static struct snd_pcm_ops sprd_pcm_ops = { + .open = sprd_pcm_open, + .close = sprd_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = sprd_pcm_hw_params, + .hw_free = sprd_pcm_hw_free, + .trigger = sprd_pcm_trigger, + .pointer = sprd_pcm_pointer, + .mmap = sprd_pcm_mmap, +}; + +static int sprd_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + struct snd_pcm_substream *substream; + int ret; + + ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (substream) { + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, + sprd_pcm_hardware.buffer_bytes_max, + &substream->dma_buffer); + if (ret) { + dev_err(card->dev, + "can't alloc playback dma buffer: %d\n", ret); + return ret; + } + } + + substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (substream) { + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, + sprd_pcm_hardware.buffer_bytes_max, + &substream->dma_buffer); + if (ret) { + dev_err(card->dev, + "can't alloc capture dma buffer: %d\n", ret); + snd_dma_free_pages(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); + return ret; + } + } + + return 0; +} + +static void sprd_pcm_free(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + int i; + + for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { + substream = pcm->streams[i].substream; + if (substream) { + snd_dma_free_pages(&substream->dma_buffer); + substream->dma_buffer.area = NULL; + substream->dma_buffer.addr = 0; + } + } +} + +static const struct snd_soc_component_driver sprd_soc_component = { + .name = DRV_NAME, + .ops = &sprd_pcm_ops, + .pcm_new = sprd_pcm_new, + .pcm_free = sprd_pcm_free, +}; + +static int sprd_soc_platform_probe(struct platform_device *pdev) +{ + int ret; + + ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component, + NULL, 0); + if (ret) + dev_err(&pdev->dev, "could not register platform:%d\n", ret); + + return ret; +} + +static const struct of_device_id sprd_pcm_of_match[] = { + { .compatible = "sprd,pcm-platform", }, + { }, +}; +MODULE_DEVICE_TABLE(of, sprd_pcm_of_match); + +static struct platform_driver sprd_pcm_driver = { + .driver = { + .name = "sprd-pcm-audio", + .of_match_table = sprd_pcm_of_match, + }, + + .probe = sprd_soc_platform_probe, +}; + +module_platform_driver(sprd_pcm_driver); + +MODULE_DESCRIPTION("Spreadtrum ASoC PCM DMA"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sprd-audio"); diff --git a/sound/soc/sprd/sprd-pcm-dma.h b/sound/soc/sprd/sprd-pcm-dma.h new file mode 100644 index 000000000000..d85a34f1461d --- /dev/null +++ b/sound/soc/sprd/sprd-pcm-dma.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifndef __SPRD_PCM_DMA_H +#define __SPRD_PCM_DMA_H + +#define SPRD_PCM_CHANNEL_MAX 2 + +struct sprd_pcm_dma_params { + dma_addr_t dev_phys[SPRD_PCM_CHANNEL_MAX]; + u32 datawidth[SPRD_PCM_CHANNEL_MAX]; + u32 fragment_len[SPRD_PCM_CHANNEL_MAX]; + const char *chan_name[SPRD_PCM_CHANNEL_MAX]; +}; + +#endif /* __SPRD_PCM_DMA_H */ -- cgit v1.2.3-58-ga151 From 7aea8a9d71d54f449f49e20324df06341cc18395 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Feb 2019 16:49:30 +0900 Subject: ASoC: rsnd: fixup MIX kctrl registration Renesas sound device has many IPs and many situations. If platform/board uses MIXer, situation will be more complex. To avoid duplicate DVC kctrl registration when MIXer was used, it had original flags. But it was issue when sound card was re-binded, because no one can't cleanup this flags then. To solve this issue, commit 9c698e8481a15237a ("ASoC: rsnd: tidyup registering method for rsnd_kctrl_new()") checks registered card->controls, because if card was re-binded, these were cleanuped automatically. This patch could solve re-binding issue. But, it start to avoid MIX kctrl. To solve these issues, we need below. To avoid card re-binding issue: check registered card->controls To avoid duplicate DVC registration: check registered rsnd_kctrl_cfg To allow multiple MIX registration: check registered rsnd_kctrl_cfg This patch do it. Fixes: 9c698e8481a15237a ("ASoC: rsnd: tidyup registering method for rsnd_kctrl_new()") Reported-by: Jiada Wang Signed-off-by: Kuninori Morimoto Tested-By: Jiada Wang Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 59e250cc2e9d..e819e965e1db 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1526,14 +1526,14 @@ int rsnd_kctrl_new(struct rsnd_mod *mod, int ret; /* - * 1) Avoid duplicate register (ex. MIXer case) - * 2) re-register if card was rebinded + * 1) Avoid duplicate register for DVC with MIX case + * 2) Allow duplicate register for MIX + * 3) re-register if card was rebinded */ list_for_each_entry(kctrl, &card->controls, list) { struct rsnd_kctrl_cfg *c = kctrl->private_data; - if (strcmp(kctrl->id.name, name) == 0 && - c->mod == mod) + if (c == cfg) return 0; } -- cgit v1.2.3-58-ga151 From f497c88b195eaee8733a304f2a1dc27fb319c9c3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Feb 2019 16:46:27 +0900 Subject: ASoC: rsnd: synchronize connection check for simple-card/audio-graph Current rsnd driver has below function to check connection rsnd_parse_connect_simple() rsnd_parse_connect_graph() But these have different parameters. This patch synchronize these for cleanup. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 59e250cc2e9d..2a48d8a6cc76 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1032,16 +1032,13 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { }; static void rsnd_parse_connect_simple(struct rsnd_priv *priv, - struct device_node *dai_np, - int dai_i, int is_play) + struct rsnd_dai_stream *io, + struct device_node *dai_np) { struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); - struct rsnd_dai_stream *io = is_play ? - &rdai->playback : - &rdai->capture; struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); struct device_node *np; + int is_play = rsnd_io_is_play(io); int i, j; if (!ssiu_np) @@ -1292,8 +1289,10 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) for_each_child_of_node(dai_node, dai_np) { __rsnd_dai_probe(priv, dai_np, dai_i); if (rsnd_is_gen3(priv)) { - rsnd_parse_connect_simple(priv, dai_np, dai_i, 1); - rsnd_parse_connect_simple(priv, dai_np, dai_i, 0); + struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); + rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); } dai_i++; } -- cgit v1.2.3-58-ga151 From 2264cf2e5db99cdff995592bf80ab6dea567ea91 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Feb 2019 16:47:25 +0900 Subject: ASoC: rsnd: fixup TDM Split mode check for CTU Renesas sound card need to judge that whether it is using "TDM Split mode". To judge it and for other purpose, it has rsnd_parse_connect_simple() and rsnd_parse_connect_graph(), but these are using different judgement policy for TDM Split mode. It is pointless and confusable. This patch add new rsnd_parse_tdm_split_mode() and use common judgement policy for simple-card/audio-graph. Without this patch, CTU will be judged as TDM Split mode on audio-graph card. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 2a48d8a6cc76..2c2c60a3f276 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1031,7 +1031,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .prepare = rsnd_soc_dai_prepare, }; -static void rsnd_parse_connect_simple(struct rsnd_priv *priv, +static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *dai_np) { @@ -1044,9 +1044,6 @@ static void rsnd_parse_connect_simple(struct rsnd_priv *priv, if (!ssiu_np) return; - if (!rsnd_io_to_mod_ssi(io)) - return; - /* * This driver assumes that it is TDM Split mode * if it includes ssiu node @@ -1071,12 +1068,21 @@ static void rsnd_parse_connect_simple(struct rsnd_priv *priv, } } +static void rsnd_parse_connect_simple(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + struct device_node *dai_np) +{ + if (!rsnd_io_to_mod_ssi(io)) + return; + + rsnd_parse_tdm_split_mode(priv, io, dai_np); +} + static void rsnd_parse_connect_graph(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *endpoint) { struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *remote_port = of_graph_get_remote_port(endpoint); struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint); if (!rsnd_io_to_mod_ssi(io)) @@ -1094,14 +1100,7 @@ static void rsnd_parse_connect_graph(struct rsnd_priv *priv, dev_dbg(dev, "%s connected to HDMI1\n", io->name); } - /* - * This driver assumes that it is TDM Split mode - * if remote node has multi endpoint - */ - if (of_get_child_count(remote_port) > 1) { - rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); - dev_dbg(dev, "%s is part of TDM Split\n", io->name); - } + rsnd_parse_tdm_split_mode(priv, io, endpoint); } void rsnd_parse_connect_common(struct rsnd_dai *rdai, -- cgit v1.2.3-58-ga151 From 909d74e39fe18e145a15ba3638f764e7ac3382c1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 31 Jan 2019 13:30:19 +0000 Subject: ASoC: arizona: Add channel numbers to AIFs Set the channel number on each AIF widget to allow unused channels not to be powered up across AIFs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 52 +++++++++++++++--------------- sound/soc/codecs/wm5102.c | 64 ++++++++++++++++++------------------- sound/soc/codecs/wm5110.c | 80 +++++++++++++++++++++++----------------------- sound/soc/codecs/wm8997.c | 60 +++++++++++++++++----------------- sound/soc/codecs/wm8998.c | 60 +++++++++++++++++----------------- 5 files changed, 158 insertions(+), 158 deletions(-) diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 45e50fe3bf25..b16832a6a9af 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -500,72 +500,72 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 6, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 7, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 6, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 7, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 2, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 3, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 4, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 5, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 2, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 3, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 4, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 5, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 1, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 1, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 7e817e1877c2..4466e195b66d 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1214,105 +1214,105 @@ SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 6, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 7, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 6, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 7, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 1, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 1, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 1, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 2, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 3, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 4, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 5, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 6, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 7, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 1, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 2, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 3, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 4, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 5, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 6, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 7, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX8_ENA_SHIFT, 0), diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index b0789a03d699..b25877fa529d 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1348,122 +1348,122 @@ SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 6, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 7, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 6, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 7, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 2, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 3, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 4, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 5, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 2, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 3, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 4, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 5, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 1, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 2, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 3, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 4, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 5, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 6, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 7, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 1, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 2, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 3, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 4, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 5, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 6, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 7, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 1, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 1, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index df5b36b8fc5a..33e3dc1a1367 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -516,95 +516,95 @@ SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 6, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 7, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 6, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 7, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 1, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 2, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 3, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 4, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 5, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 6, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 7, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX8_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 1, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 2, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 3, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 4, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 5, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX6_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 6, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX7_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 7, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX8_ENA_SHIFT, 0), diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 409bed30a4e4..125fc32ad92a 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -626,96 +626,96 @@ SND_SOC_DAPM_MUX("AEC2 Loopback", ARIZONA_DAC_AEC_CONTROL_2, SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 1, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 2, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 3, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 4, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 5, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 1, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 2, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 3, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 4, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 5, ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 1, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 2, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 3, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 4, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 5, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 1, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 2, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 3, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 4, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 5, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 1, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 2, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0, +SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 3, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, ARIZONA_SLIMRX4_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 1, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX2_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 2, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX3_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 3, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX4_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 4, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX5_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0, +SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 5, ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE, ARIZONA_SLIMTX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 1, ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), -SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 1, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, -- cgit v1.2.3-58-ga151 From 425da20a98e0ab6ba6b37ff00ab50519d7dd7740 Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang Date: Wed, 30 Jan 2019 14:47:11 +0800 Subject: ASoC: mediatek: add documents for btcvsd driver document for btcvsd driver Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mtk-btcvsd-snd.txt | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt diff --git a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt b/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt new file mode 100644 index 000000000000..679e44839b48 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt @@ -0,0 +1,24 @@ +Mediatek ALSA BT SCO CVSD/MSBC Driver + +Required properties: +- compatible = "mediatek,mtk-btcvsd-snd"; +- reg: register location and size of PKV and SRAM_BANK2 +- interrupts: should contain BTSCO interrupt +- mediatek,infracfg: the phandles of INFRASYS +- mediatek,offset: Array contains of register offset and mask + infra_misc_offset, + infra_conn_bt_cvsd_mask, + cvsd_mcu_read_offset, + cvsd_mcu_write_offset, + cvsd_packet_indicator_offset + +Example: + + mtk-btcvsd-snd@18000000 { + compatible = "mediatek,mtk-btcvsd-snd"; + reg=<0 0x18000000 0 0x1000>, + <0 0x18080000 0 0x8000>; + interrupts = ; + mediatek,infracfg = <&infrasys>; + mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>; + }; -- cgit v1.2.3-58-ga151 From 4bd8597dc36c376a2bb1ef2c72984615bdeb68de Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang Date: Wed, 30 Jan 2019 14:47:10 +0800 Subject: ASoC: mediatek: add btcvsd driver The driver function for transferring/receiving BT encoded data to/from BT firmware. Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 9 + sound/soc/mediatek/common/Makefile | 2 + sound/soc/mediatek/common/mtk-btcvsd.c | 1364 ++++++++++++++++++++++++++++++++ 3 files changed, 1375 insertions(+) create mode 100644 sound/soc/mediatek/common/mtk-btcvsd.c diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 8bb360ee7234..b35410e4020e 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -115,3 +115,12 @@ config SND_SOC_MT8183 that can be used with other codecs. Select Y if you have such device. If unsure select "N". + +config SND_SOC_MTK_BTCVSD + tristate "ALSA BT SCO CVSD/MSBC Driver" + help + This is for software BTCVSD. This enable + the function for transferring/receiving + BT encoded data to/from BT firmware. + Select Y if you have such device. + If unsure select "N". diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile index cdadabc5fd16..9ab90433a8d7 100644 --- a/sound/soc/mediatek/common/Makefile +++ b/sound/soc/mediatek/common/Makefile @@ -2,3 +2,5 @@ # platform driver snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o + +obj-$(CONFIG_SND_SOC_MTK_BTCVSD) += mtk-btcvsd.o \ No newline at end of file diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c new file mode 100644 index 000000000000..349a9120a0dd --- /dev/null +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -0,0 +1,1364 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Mediatek ALSA BT SCO CVSD/MSBC Driver +// +// Copyright (c) 2019 MediaTek Inc. +// Author: KaiChieh Chuang + +#include +#include +#include +#include + +#include + +#define BTCVSD_SND_NAME "mtk-btcvsd-snd" + +#define BT_CVSD_TX_NREADY BIT(21) +#define BT_CVSD_RX_READY BIT(22) +#define BT_CVSD_TX_UNDERFLOW BIT(23) +#define BT_CVSD_RX_OVERFLOW BIT(24) +#define BT_CVSD_INTERRUPT BIT(31) + +#define BT_CVSD_CLEAR \ + (BT_CVSD_TX_NREADY | BT_CVSD_RX_READY | BT_CVSD_TX_UNDERFLOW |\ + BT_CVSD_RX_OVERFLOW | BT_CVSD_INTERRUPT) + +/* TX */ +#define SCO_TX_ENCODE_SIZE (60) +/* 18 = 6 * 180 / SCO_TX_ENCODE_SIZE */ +#define SCO_TX_PACKER_BUF_NUM (18) + +/* RX */ +#define SCO_RX_PLC_SIZE (30) +#define SCO_RX_PACKER_BUF_NUM (64) +#define SCO_RX_PACKET_MASK (0x3F) + +#define SCO_CVSD_PACKET_VALID_SIZE 2 + +#define SCO_PACKET_120 120 +#define SCO_PACKET_180 180 + +#define BTCVSD_RX_PACKET_SIZE (SCO_RX_PLC_SIZE + SCO_CVSD_PACKET_VALID_SIZE) +#define BTCVSD_TX_PACKET_SIZE (SCO_TX_ENCODE_SIZE) + +#define BTCVSD_RX_BUF_SIZE (BTCVSD_RX_PACKET_SIZE * SCO_RX_PACKER_BUF_NUM) +#define BTCVSD_TX_BUF_SIZE (BTCVSD_TX_PACKET_SIZE * SCO_TX_PACKER_BUF_NUM) + +enum bt_sco_state { + BT_SCO_STATE_IDLE, + BT_SCO_STATE_RUNNING, + BT_SCO_STATE_ENDING, +}; + +enum bt_sco_direct { + BT_SCO_DIRECT_BT2ARM, + BT_SCO_DIRECT_ARM2BT, +}; + +enum bt_sco_packet_len { + BT_SCO_CVSD_30 = 0, + BT_SCO_CVSD_60, + BT_SCO_CVSD_90, + BT_SCO_CVSD_120, + BT_SCO_CVSD_10, + BT_SCO_CVSD_20, + BT_SCO_CVSD_MAX, +}; + +enum BT_SCO_BAND { + BT_SCO_NB, + BT_SCO_WB, +}; + +struct mtk_btcvsd_snd_hw_info { + unsigned int num_valid_addr; + unsigned long bt_sram_addr[20]; + unsigned int packet_length; + unsigned int packet_num; +}; + +struct mtk_btcvsd_snd_stream { + struct snd_pcm_substream *substream; + int stream; + + enum bt_sco_state state; + + unsigned int packet_size; + unsigned int buf_size; + u8 temp_packet_buf[SCO_PACKET_180]; + + int packet_w; + int packet_r; + snd_pcm_uframes_t prev_frame; + int prev_packet_idx; + + unsigned int xrun:1; + unsigned int timeout:1; + unsigned int mute:1; + unsigned int trigger_start:1; + unsigned int wait_flag:1; + unsigned int rw_cnt; + + unsigned long long time_stamp; + unsigned long long buf_data_equivalent_time; + + struct mtk_btcvsd_snd_hw_info buffer_info; +}; + +struct mtk_btcvsd_snd { + struct device *dev; + int irq_id; + + struct regmap *infra; + void __iomem *bt_pkv_base; + void __iomem *bt_sram_bank2_base; + + unsigned int infra_misc_offset; + unsigned int conn_bt_cvsd_mask; + unsigned int cvsd_mcu_read_offset; + unsigned int cvsd_mcu_write_offset; + unsigned int cvsd_packet_indicator; + + u32 *bt_reg_pkt_r; + u32 *bt_reg_pkt_w; + u32 *bt_reg_ctl; + + unsigned int irq_disabled:1; + + spinlock_t tx_lock; /* spinlock for bt tx stream control */ + spinlock_t rx_lock; /* spinlock for bt rx stream control */ + wait_queue_head_t tx_wait; + wait_queue_head_t rx_wait; + + struct mtk_btcvsd_snd_stream *tx; + struct mtk_btcvsd_snd_stream *rx; + u8 tx_packet_buf[BTCVSD_TX_BUF_SIZE]; + u8 rx_packet_buf[BTCVSD_RX_BUF_SIZE]; + + enum BT_SCO_BAND band; +}; + +struct mtk_btcvsd_snd_time_buffer_info { + unsigned long long data_count_equi_time; + unsigned long long time_stamp_us; +}; + +static const unsigned int btsco_packet_valid_mask[BT_SCO_CVSD_MAX][6] = { + {0x1, 0x1 << 1, 0x1 << 2, 0x1 << 3, 0x1 << 4, 0x1 << 5}, + {0x1, 0x1, 0x2, 0x2, 0x4, 0x4}, + {0x1, 0x1, 0x1, 0x2, 0x2, 0x2}, + {0x1, 0x1, 0x1, 0x1, 0x0, 0x0}, + {0x7, 0x7 << 3, 0x7 << 6, 0x7 << 9, 0x7 << 12, 0x7 << 15}, + {0x3, 0x3 << 1, 0x3 << 3, 0x3 << 4, 0x3 << 6, 0x3 << 7}, +}; + +static const unsigned int btsco_packet_info[BT_SCO_CVSD_MAX][4] = { + {30, 6, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, + {60, 3, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, + {90, 2, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, + {120, 1, SCO_PACKET_120 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_120 / SCO_RX_PLC_SIZE}, + {10, 18, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, + {20, 9, SCO_PACKET_180 / SCO_TX_ENCODE_SIZE, + SCO_PACKET_180 / SCO_RX_PLC_SIZE}, +}; + +static const u8 table_msbc_silence[SCO_PACKET_180] = { + 0x01, 0x38, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, + 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, + 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, + 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, + 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00, + 0x01, 0xc8, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, + 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, + 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, + 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, + 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00, + 0x01, 0xf8, 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, + 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, + 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6, 0xdd, + 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, + 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c, 0x00 +}; + +static void mtk_btcvsd_snd_irq_enable(struct mtk_btcvsd_snd *bt) +{ + regmap_update_bits(bt->infra, bt->infra_misc_offset, + bt->conn_bt_cvsd_mask, bt->conn_bt_cvsd_mask); +} + +static void mtk_btcvsd_snd_irq_disable(struct mtk_btcvsd_snd *bt) +{ + regmap_update_bits(bt->infra, bt->infra_misc_offset, + bt->conn_bt_cvsd_mask, 0); +} + +static void mtk_btcvsd_snd_set_state(struct mtk_btcvsd_snd *bt, + struct mtk_btcvsd_snd_stream *bt_stream, + int state) +{ + dev_dbg(bt->dev, "%s(), stream %d, state %d, tx->state %d, rx->state %d, irq_disabled %d\n", + __func__, + bt_stream->stream, state, + bt->tx->state, bt->rx->state, bt->irq_disabled); + + bt_stream->state = state; + + if (bt->tx->state == BT_SCO_STATE_IDLE && + bt->rx->state == BT_SCO_STATE_IDLE) { + if (!bt->irq_disabled) { + disable_irq(bt->irq_id); + mtk_btcvsd_snd_irq_disable(bt); + bt->irq_disabled = 1; + } + } else { + if (bt->irq_disabled) { + enable_irq(bt->irq_id); + mtk_btcvsd_snd_irq_enable(bt); + bt->irq_disabled = 0; + } + } +} + +static int mtk_btcvsd_snd_tx_init(struct mtk_btcvsd_snd *bt) +{ + memset(bt->tx, 0, sizeof(*bt->tx)); + memset(bt->tx_packet_buf, 0, sizeof(bt->tx_packet_buf)); + + bt->tx->packet_size = BTCVSD_TX_PACKET_SIZE; + bt->tx->buf_size = BTCVSD_TX_BUF_SIZE; + bt->tx->timeout = 0; + bt->tx->rw_cnt = 0; + bt->tx->stream = SNDRV_PCM_STREAM_PLAYBACK; + return 0; +} + +static int mtk_btcvsd_snd_rx_init(struct mtk_btcvsd_snd *bt) +{ + memset(bt->rx, 0, sizeof(*bt->rx)); + memset(bt->rx_packet_buf, 0, sizeof(bt->rx_packet_buf)); + + bt->rx->packet_size = BTCVSD_RX_PACKET_SIZE; + bt->rx->buf_size = BTCVSD_RX_BUF_SIZE; + bt->rx->timeout = 0; + bt->rx->rw_cnt = 0; + bt->tx->stream = SNDRV_PCM_STREAM_CAPTURE; + return 0; +} + +static void get_tx_time_stamp(struct mtk_btcvsd_snd *bt, + struct mtk_btcvsd_snd_time_buffer_info *ts) +{ + ts->time_stamp_us = bt->tx->time_stamp; + ts->data_count_equi_time = bt->tx->buf_data_equivalent_time; +} + +static void get_rx_time_stamp(struct mtk_btcvsd_snd *bt, + struct mtk_btcvsd_snd_time_buffer_info *ts) +{ + ts->time_stamp_us = bt->rx->time_stamp; + ts->data_count_equi_time = bt->rx->buf_data_equivalent_time; +} + +static int btcvsd_bytes_to_frame(struct snd_pcm_substream *substream, + int bytes) +{ + int count = bytes; + struct snd_pcm_runtime *runtime = substream->runtime; + + if (runtime->format == SNDRV_PCM_FORMAT_S32_LE || + runtime->format == SNDRV_PCM_FORMAT_U32_LE) + count = count >> 2; + else + count = count >> 1; + + count = count / runtime->channels; + return count; +} + +static void mtk_btcvsd_snd_data_transfer(enum bt_sco_direct dir, + u8 *src, u8 *dst, + unsigned int blk_size, + unsigned int blk_num) +{ + unsigned int i, j; + + if (blk_size == 60 || blk_size == 120 || blk_size == 20) { + u32 *src_32 = (u32 *)src; + u32 *dst_32 = (u32 *)dst; + + for (i = 0; i < (blk_size * blk_num / 4); i++) + *dst_32++ = *src_32++; + } else { + u16 *src_16 = (u16 *)src; + u16 *dst_16 = (u16 *)dst; + + for (j = 0; j < blk_num; j++) { + for (i = 0; i < (blk_size / 2); i++) + *dst_16++ = *src_16++; + + if (dir == BT_SCO_DIRECT_BT2ARM) + src_16++; + else + dst_16++; + } + } +} + +/* write encoded mute data to bt sram */ +static int btcvsd_tx_clean_buffer(struct mtk_btcvsd_snd *bt) +{ + unsigned int i; + unsigned int num_valid_addr; + unsigned long flags; + enum BT_SCO_BAND band = bt->band; + + /* prepare encoded mute data */ + if (band == BT_SCO_NB) + memset(bt->tx->temp_packet_buf, 170, SCO_PACKET_180); + else + memcpy(bt->tx->temp_packet_buf, + table_msbc_silence, SCO_PACKET_180); + + /* write mute data to bt tx sram buffer */ + spin_lock_irqsave(&bt->tx_lock, flags); + num_valid_addr = bt->tx->buffer_info.num_valid_addr; + + dev_info(bt->dev, "%s(), band %d, num_valid_addr %u\n", + __func__, band, num_valid_addr); + + for (i = 0; i < num_valid_addr; i++) { + void *dst; + + dev_info(bt->dev, "%s(), clean addr 0x%lx\n", __func__, + bt->tx->buffer_info.bt_sram_addr[i]); + + dst = (void *)bt->tx->buffer_info.bt_sram_addr[i]; + + mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_ARM2BT, + bt->tx->temp_packet_buf, dst, + bt->tx->buffer_info.packet_length, + bt->tx->buffer_info.packet_num); + } + spin_unlock_irqrestore(&bt->tx_lock, flags); + + return 0; +} + +static int mtk_btcvsd_read_from_bt(struct mtk_btcvsd_snd *bt, + enum bt_sco_packet_len packet_type, + unsigned int packet_length, + unsigned int packet_num, + unsigned int blk_size, + unsigned int control) +{ + unsigned int i; + int pv; + u8 *src; + unsigned int packet_buf_ofs; + unsigned long flags; + unsigned long connsys_addr_rx, ap_addr_rx; + + connsys_addr_rx = *bt->bt_reg_pkt_r; + ap_addr_rx = (unsigned long)bt->bt_sram_bank2_base + + (connsys_addr_rx & 0xFFFF); + + if (connsys_addr_rx == 0xdeadfeed) { + /* bt return 0xdeadfeed if read register during bt sleep */ + dev_warn(bt->dev, "%s(), connsys_addr_rx == 0xdeadfeed", + __func__); + return -EIO; + } + + src = (u8 *)ap_addr_rx; + + mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_BT2ARM, src, + bt->rx->temp_packet_buf, packet_length, + packet_num); + + spin_lock_irqsave(&bt->rx_lock, flags); + for (i = 0; i < blk_size; i++) { + packet_buf_ofs = (bt->rx->packet_w & SCO_RX_PACKET_MASK) * + bt->rx->packet_size; + memcpy(bt->rx_packet_buf + packet_buf_ofs, + bt->rx->temp_packet_buf + (SCO_RX_PLC_SIZE * i), + SCO_RX_PLC_SIZE); + if ((control & btsco_packet_valid_mask[packet_type][i]) == + btsco_packet_valid_mask[packet_type][i]) + pv = 1; + else + pv = 0; + + packet_buf_ofs += SCO_RX_PLC_SIZE; + memcpy(bt->rx_packet_buf + packet_buf_ofs, (void *)&pv, + SCO_CVSD_PACKET_VALID_SIZE); + bt->rx->packet_w++; + } + spin_unlock_irqrestore(&bt->rx_lock, flags); + return 0; +} + +int mtk_btcvsd_write_to_bt(struct mtk_btcvsd_snd *bt, + enum bt_sco_packet_len packet_type, + unsigned int packet_length, + unsigned int packet_num, + unsigned int blk_size) +{ + unsigned int i; + unsigned long flags; + u8 *dst; + unsigned long connsys_addr_tx, ap_addr_tx; + bool new_ap_addr_tx = true; + + connsys_addr_tx = *bt->bt_reg_pkt_w; + ap_addr_tx = (unsigned long)bt->bt_sram_bank2_base + + (connsys_addr_tx & 0xFFFF); + + if (connsys_addr_tx == 0xdeadfeed) { + /* bt return 0xdeadfeed if read register during bt sleep */ + dev_warn(bt->dev, "%s(), connsys_addr_tx == 0xdeadfeed\n", + __func__); + return -EIO; + } + + spin_lock_irqsave(&bt->tx_lock, flags); + for (i = 0; i < blk_size; i++) { + memcpy(bt->tx->temp_packet_buf + (bt->tx->packet_size * i), + (bt->tx_packet_buf + + (bt->tx->packet_r % SCO_TX_PACKER_BUF_NUM) * + bt->tx->packet_size), + bt->tx->packet_size); + + bt->tx->packet_r++; + } + spin_unlock_irqrestore(&bt->tx_lock, flags); + + dst = (u8 *)ap_addr_tx; + + if (!bt->tx->mute) { + mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_ARM2BT, + bt->tx->temp_packet_buf, dst, + packet_length, packet_num); + } + + /* store bt tx buffer sram info */ + bt->tx->buffer_info.packet_length = packet_length; + bt->tx->buffer_info.packet_num = packet_num; + for (i = 0; i < bt->tx->buffer_info.num_valid_addr; i++) { + if (bt->tx->buffer_info.bt_sram_addr[i] == ap_addr_tx) { + new_ap_addr_tx = false; + break; + } + } + if (new_ap_addr_tx) { + unsigned int next_idx; + + spin_lock_irqsave(&bt->tx_lock, flags); + bt->tx->buffer_info.num_valid_addr++; + next_idx = bt->tx->buffer_info.num_valid_addr - 1; + bt->tx->buffer_info.bt_sram_addr[next_idx] = ap_addr_tx; + spin_unlock_irqrestore(&bt->tx_lock, flags); + dev_info(bt->dev, "%s(), new ap_addr_tx = 0x%lx, num_valid_addr %d\n", + __func__, ap_addr_tx, + bt->tx->buffer_info.num_valid_addr); + } + + if (bt->tx->mute) + btcvsd_tx_clean_buffer(bt); + + return 0; +} + +static irqreturn_t mtk_btcvsd_snd_irq_handler(int irq_id, void *dev) +{ + struct mtk_btcvsd_snd *bt = dev; + unsigned int packet_type, packet_num, packet_length; + unsigned int buf_cnt_tx, buf_cnt_rx, control; + + if (bt->rx->state != BT_SCO_STATE_RUNNING && + bt->rx->state != BT_SCO_STATE_ENDING && + bt->tx->state != BT_SCO_STATE_RUNNING && + bt->tx->state != BT_SCO_STATE_ENDING) { + dev_warn(bt->dev, "%s(), in idle state: rx->state: %d, tx->state: %d\n", + __func__, bt->rx->state, bt->tx->state); + goto irq_handler_exit; + } + + control = *bt->bt_reg_ctl; + packet_type = (control >> 18) & 0x7; + + if (((control >> 31) & 1) == 0) { + dev_warn(bt->dev, "%s(), ((control >> 31) & 1) == 0, control 0x%x\n", + __func__, control); + goto irq_handler_exit; + } + + if (packet_type >= BT_SCO_CVSD_MAX) { + dev_warn(bt->dev, "%s(), invalid packet_type %u, exit\n", + __func__, packet_type); + goto irq_handler_exit; + } + + packet_length = btsco_packet_info[packet_type][0]; + packet_num = btsco_packet_info[packet_type][1]; + buf_cnt_tx = btsco_packet_info[packet_type][2]; + buf_cnt_rx = btsco_packet_info[packet_type][3]; + + if (bt->rx->state == BT_SCO_STATE_RUNNING || + bt->rx->state == BT_SCO_STATE_ENDING) { + if (bt->rx->xrun) { + if (bt->rx->packet_w - bt->rx->packet_r <= + SCO_RX_PACKER_BUF_NUM - 2 * buf_cnt_rx) { + /* + * free space is larger then + * twice interrupt rx data size + */ + bt->rx->xrun = 0; + dev_warn(bt->dev, "%s(), rx->xrun 0!\n", + __func__); + } + } + + if (!bt->rx->xrun && + (bt->rx->packet_w - bt->rx->packet_r <= + SCO_RX_PACKER_BUF_NUM - buf_cnt_rx)) { + mtk_btcvsd_read_from_bt(bt, + packet_type, + packet_length, + packet_num, + buf_cnt_rx, + control); + bt->rx->rw_cnt++; + } else { + bt->rx->xrun = 1; + dev_warn(bt->dev, "%s(), rx->xrun 1\n", __func__); + } + } + + /* tx */ + bt->tx->timeout = 0; + if ((bt->tx->state == BT_SCO_STATE_RUNNING || + bt->tx->state == BT_SCO_STATE_ENDING) && + bt->tx->trigger_start) { + if (bt->tx->xrun) { + /* prepared data is larger then twice + * interrupt tx data size + */ + if (bt->tx->packet_w - bt->tx->packet_r >= + 2 * buf_cnt_tx) { + bt->tx->xrun = 0; + dev_warn(bt->dev, "%s(), tx->xrun 0\n", + __func__); + } + } + + if ((!bt->tx->xrun && + (bt->tx->packet_w - bt->tx->packet_r >= buf_cnt_tx)) || + bt->tx->state == BT_SCO_STATE_ENDING) { + mtk_btcvsd_write_to_bt(bt, + packet_type, + packet_length, + packet_num, + buf_cnt_tx); + bt->tx->rw_cnt++; + } else { + bt->tx->xrun = 1; + dev_warn(bt->dev, "%s(), tx->xrun 1\n", __func__); + } + } + + *bt->bt_reg_ctl &= ~BT_CVSD_CLEAR; + + if (bt->rx->state == BT_SCO_STATE_RUNNING || + bt->rx->state == BT_SCO_STATE_ENDING) { + bt->rx->wait_flag = 1; + wake_up_interruptible(&bt->rx_wait); + snd_pcm_period_elapsed(bt->rx->substream); + } + if (bt->tx->state == BT_SCO_STATE_RUNNING || + bt->tx->state == BT_SCO_STATE_ENDING) { + bt->tx->wait_flag = 1; + wake_up_interruptible(&bt->tx_wait); + snd_pcm_period_elapsed(bt->tx->substream); + } + + return IRQ_HANDLED; +irq_handler_exit: + *bt->bt_reg_ctl &= ~BT_CVSD_CLEAR; + return IRQ_HANDLED; +} + +static int wait_for_bt_irq(struct mtk_btcvsd_snd *bt, + struct mtk_btcvsd_snd_stream *bt_stream) +{ + unsigned long long t1, t2; + /* one interrupt period = 22.5ms */ + unsigned long long timeout_limit = 22500000; + int max_timeout_trial = 2; + int ret; + + bt_stream->wait_flag = 0; + + while (max_timeout_trial && !bt_stream->wait_flag) { + t1 = sched_clock(); + if (bt_stream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = wait_event_interruptible_timeout(bt->tx_wait, + bt_stream->wait_flag, + nsecs_to_jiffies(timeout_limit)); + } else { + ret = wait_event_interruptible_timeout(bt->rx_wait, + bt_stream->wait_flag, + nsecs_to_jiffies(timeout_limit)); + } + + t2 = sched_clock(); + t2 = t2 - t1; /* in ns (10^9) */ + + if (t2 > timeout_limit) { + dev_warn(bt->dev, "%s(), stream %d, timeout %llu, limit %llu, ret %d, flag %d\n", + __func__, bt_stream->stream, + t2, timeout_limit, ret, + bt_stream->wait_flag); + } + + if (ret < 0) { + /* + * error, -ERESTARTSYS if it was interrupted by + * a signal + */ + dev_warn(bt->dev, "%s(), stream %d, error, trial left %d\n", + __func__, + bt_stream->stream, max_timeout_trial); + + bt_stream->timeout = 1; + return ret; + } else if (ret == 0) { + /* conidtion is false after timeout */ + max_timeout_trial--; + dev_warn(bt->dev, "%s(), stream %d, error, timeout, condition is false, trial left %d\n", + __func__, + bt_stream->stream, max_timeout_trial); + + if (max_timeout_trial <= 0) { + bt_stream->timeout = 1; + return -ETIME; + } + } + } + + return 0; +} + +ssize_t mtk_btcvsd_snd_read(struct mtk_btcvsd_snd *bt, + char __user *buf, + size_t count) +{ + ssize_t read_size = 0, read_count = 0, cur_read_idx, cont; + unsigned int cur_buf_ofs = 0; + unsigned long avail; + unsigned long flags; + unsigned int packet_size = bt->rx->packet_size; + + while (count) { + spin_lock_irqsave(&bt->rx_lock, flags); + /* available data in RX packet buffer */ + avail = (bt->rx->packet_w - bt->rx->packet_r) * packet_size; + + cur_read_idx = (bt->rx->packet_r & SCO_RX_PACKET_MASK) * + packet_size; + spin_unlock_irqrestore(&bt->rx_lock, flags); + + if (!avail) { + int ret = wait_for_bt_irq(bt, bt->rx); + + if (ret) + return read_count; + + continue; + } + + /* count must be multiple of packet_size */ + if (count % packet_size != 0 || + avail % packet_size != 0) { + dev_warn(bt->dev, "%s(), count %zu or d %lu is not multiple of packet_size %dd\n", + __func__, count, avail, packet_size); + + count -= count % packet_size; + avail -= avail % packet_size; + } + + if (count > avail) + read_size = avail; + else + read_size = count; + + /* calculate continue space */ + cont = bt->rx->buf_size - cur_read_idx; + if (read_size > cont) + read_size = cont; + + if (copy_to_user(buf + cur_buf_ofs, + bt->rx_packet_buf + cur_read_idx, + read_size)) { + dev_warn(bt->dev, "%s(), copy_to_user fail\n", + __func__); + return -EFAULT; + } + + spin_lock_irqsave(&bt->rx_lock, flags); + bt->rx->packet_r += read_size / packet_size; + spin_unlock_irqrestore(&bt->rx_lock, flags); + + read_count += read_size; + cur_buf_ofs += read_size; + count -= read_size; + } + + /* + * save current timestamp & buffer time in times_tamp and + * buf_data_equivalent_time + */ + bt->rx->time_stamp = sched_clock(); + bt->rx->buf_data_equivalent_time = + (unsigned long long)(bt->rx->packet_w - bt->rx->packet_r) * + SCO_RX_PLC_SIZE * 16 * 1000 / 2 / 64; + bt->rx->buf_data_equivalent_time += read_count * SCO_RX_PLC_SIZE * + 16 * 1000 / packet_size / 2 / 64; + /* return equivalent time(us) to data count */ + bt->rx->buf_data_equivalent_time *= 1000; + + return read_count; +} + +ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, + char __user *buf, + size_t count) +{ + int written_size = count, avail = 0, cur_write_idx, write_size, cont; + unsigned int cur_buf_ofs = 0; + unsigned long flags; + unsigned int packet_size = bt->tx->packet_size; + + /* + * save current timestamp & buffer time in time_stamp and + * buf_data_equivalent_time + */ + bt->tx->time_stamp = sched_clock(); + bt->tx->buf_data_equivalent_time = + (unsigned long long)(bt->tx->packet_w - bt->tx->packet_r) * + packet_size * 16 * 1000 / 2 / 64; + + /* return equivalent time(us) to data count */ + bt->tx->buf_data_equivalent_time *= 1000; + + while (count) { + spin_lock_irqsave(&bt->tx_lock, flags); + /* free space of TX packet buffer */ + avail = bt->tx->buf_size - + (bt->tx->packet_w - bt->tx->packet_r) * packet_size; + + cur_write_idx = (bt->tx->packet_w % SCO_TX_PACKER_BUF_NUM) * + packet_size; + spin_unlock_irqrestore(&bt->tx_lock, flags); + + if (!avail) { + int ret = wait_for_bt_irq(bt, bt->rx); + + if (ret) + return written_size; + + continue; + } + + /* count must be multiple of bt->tx->packet_size */ + if (count % packet_size != 0 || + avail % packet_size != 0) { + dev_warn(bt->dev, "%s(), count %zu or avail %d is not multiple of packet_size %d\n", + __func__, count, avail, packet_size); + count -= count % packet_size; + avail -= avail % packet_size; + } + + if (count > avail) + write_size = avail; + else + write_size = count; + + /* calculate continue space */ + cont = bt->tx->buf_size - cur_write_idx; + if (write_size > cont) + write_size = cont; + + if (copy_from_user(bt->tx_packet_buf + + cur_write_idx, + buf + cur_buf_ofs, + write_size)) { + dev_warn(bt->dev, "%s(), copy_from_user fail\n", + __func__); + return -EFAULT; + } + + spin_lock_irqsave(&bt->tx_lock, flags); + bt->tx->packet_w += write_size / packet_size; + spin_unlock_irqrestore(&bt->tx_lock, flags); + cur_buf_ofs += write_size; + count -= write_size; + } + + return written_size; +} + +static struct mtk_btcvsd_snd_stream *get_bt_stream + (struct mtk_btcvsd_snd *bt, struct snd_pcm_substream *substream) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return bt->tx; + else + return bt->rx; +} + +/* pcm ops */ +static const struct snd_pcm_hardware mtk_btcvsd_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_RESUME), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .buffer_bytes_max = 24 * 1024, + .period_bytes_max = 24 * 1024, + .periods_min = 2, + .periods_max = 16, + .fifo_size = 0, +}; + +static int mtk_pcm_btcvsd_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + int ret; + + dev_dbg(bt->dev, "%s(), stream %d, substream %p\n", + __func__, substream->stream, substream); + + snd_soc_set_runtime_hwparams(substream, &mtk_btcvsd_hardware); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = mtk_btcvsd_snd_tx_init(bt); + bt->tx->substream = substream; + } else { + ret = mtk_btcvsd_snd_rx_init(bt); + bt->rx->substream = substream; + } + + return ret; +} + +static int mtk_pcm_btcvsd_close(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream); + + dev_dbg(bt->dev, "%s(), stream %d\n", __func__, substream->stream); + + mtk_btcvsd_snd_set_state(bt, bt_stream, BT_SCO_STATE_IDLE); + bt_stream->substream = NULL; + return 0; +} + +static int mtk_pcm_btcvsd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + params_buffer_bytes(hw_params) % bt->tx->packet_size != 0) { + dev_warn(bt->dev, "%s(), error, buffer size %d not valid\n", + __func__, + params_buffer_bytes(hw_params)); + return -EINVAL; + } + + substream->runtime->dma_bytes = params_buffer_bytes(hw_params); + return 0; +} + +static int mtk_pcm_btcvsd_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + btcvsd_tx_clean_buffer(bt); + + return 0; +} + +static int mtk_pcm_btcvsd_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream); + + dev_dbg(bt->dev, "%s(), stream %d\n", __func__, substream->stream); + + mtk_btcvsd_snd_set_state(bt, bt_stream, BT_SCO_STATE_RUNNING); + return 0; +} + +static int mtk_pcm_btcvsd_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + struct mtk_btcvsd_snd_stream *bt_stream = get_bt_stream(bt, substream); + int stream = substream->stream; + int hw_packet_ptr; + + dev_dbg(bt->dev, "%s(), stream %d, cmd %d\n", + __func__, substream->stream, cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + hw_packet_ptr = stream == SNDRV_PCM_STREAM_PLAYBACK ? + bt_stream->packet_r : bt_stream->packet_w; + bt_stream->prev_packet_idx = hw_packet_ptr; + bt_stream->prev_frame = 0; + bt_stream->trigger_start = 1; + return 0; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + bt_stream->trigger_start = 0; + mtk_btcvsd_snd_set_state(bt, bt_stream, BT_SCO_STATE_ENDING); + return 0; + default: + return -EINVAL; + } +} + +static snd_pcm_uframes_t mtk_pcm_btcvsd_pointer + (struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + struct mtk_btcvsd_snd_stream *bt_stream; + snd_pcm_uframes_t frame = 0; + int byte = 0; + int hw_packet_ptr; + int packet_diff; + spinlock_t *lock; /* spinlock for bt stream control */ + unsigned long flags; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + lock = &bt->tx_lock; + bt_stream = bt->tx; + } else { + lock = &bt->rx_lock; + bt_stream = bt->rx; + } + + spin_lock_irqsave(lock, flags); + hw_packet_ptr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + bt->tx->packet_r : bt->rx->packet_w; + + /* get packet diff from last time */ + if (hw_packet_ptr >= bt_stream->prev_packet_idx) { + packet_diff = hw_packet_ptr - bt_stream->prev_packet_idx; + } else { + /* integer overflow */ + packet_diff = (INT_MAX - bt_stream->prev_packet_idx) + + (hw_packet_ptr - INT_MIN) + 1; + } + bt_stream->prev_packet_idx = hw_packet_ptr; + + /* increased bytes */ + byte = packet_diff * bt_stream->packet_size; + + frame = btcvsd_bytes_to_frame(substream, byte); + frame += bt_stream->prev_frame; + frame %= substream->runtime->buffer_size; + + bt_stream->prev_frame = frame; + + spin_unlock_irqrestore(lock, flags); + + return frame; +} + +static int mtk_pcm_btcvsd_copy(struct snd_pcm_substream *substream, + int channel, unsigned long pos, + void __user *buf, unsigned long count) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, BTCVSD_SND_NAME); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(component); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + mtk_btcvsd_snd_write(bt, buf, count); + else + mtk_btcvsd_snd_read(bt, buf, count); + + return 0; +} + +static struct snd_pcm_ops mtk_btcvsd_ops = { + .open = mtk_pcm_btcvsd_open, + .close = mtk_pcm_btcvsd_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = mtk_pcm_btcvsd_hw_params, + .hw_free = mtk_pcm_btcvsd_hw_free, + .prepare = mtk_pcm_btcvsd_prepare, + .trigger = mtk_pcm_btcvsd_trigger, + .pointer = mtk_pcm_btcvsd_pointer, + .copy_user = mtk_pcm_btcvsd_copy, +}; + +/* kcontrol */ +static const char *const btsco_band_str[] = {"NB", "WB"}; + +static const struct soc_enum btcvsd_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(btsco_band_str), btsco_band_str), +}; + +static int btcvsd_band_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + ucontrol->value.integer.value[0] = bt->band; + return 0; +} + +static int btcvsd_band_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + + if (ucontrol->value.enumerated.item[0] >= e->items) + return -EINVAL; + + bt->band = ucontrol->value.integer.value[0]; + dev_dbg(bt->dev, "%s(), band %d\n", __func__, bt->band); + return 0; +} + +static int btcvsd_tx_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->tx) { + ucontrol->value.integer.value[0] = 0; + return 0; + } + + ucontrol->value.integer.value[0] = bt->tx->mute; + return 0; +} + +static int btcvsd_tx_mute_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->tx) + return 0; + + bt->tx->mute = ucontrol->value.integer.value[0]; + return 0; +} + +static int btcvsd_rx_irq_received_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->rx) + return 0; + + ucontrol->value.integer.value[0] = bt->rx->rw_cnt ? 1 : 0; + return 0; +} + +static int btcvsd_rx_timeout_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->rx) + return 0; + + ucontrol->value.integer.value[0] = bt->rx->timeout; + bt->rx->timeout = 0; + return 0; +} + +static int btcvsd_rx_timestamp_get(struct snd_kcontrol *kcontrol, + unsigned int __user *data, unsigned int size) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + int ret = 0; + struct mtk_btcvsd_snd_time_buffer_info time_buffer_info_rx; + + if (size > sizeof(struct mtk_btcvsd_snd_time_buffer_info)) + return -EINVAL; + + get_rx_time_stamp(bt, &time_buffer_info_rx); + + dev_dbg(bt->dev, "%s(), time_stamp_us %llu, data_count_equi_time %llu", + __func__, + time_buffer_info_rx.time_stamp_us, + time_buffer_info_rx.data_count_equi_time); + + if (copy_to_user(data, &time_buffer_info_rx, + sizeof(struct mtk_btcvsd_snd_time_buffer_info))) { + dev_warn(bt->dev, "%s(), copy_to_user fail", __func__); + ret = -EFAULT; + } + + return ret; +} + +static int btcvsd_tx_irq_received_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + if (!bt->tx) + return 0; + + ucontrol->value.integer.value[0] = bt->tx->rw_cnt ? 1 : 0; + return 0; +} + +static int btcvsd_tx_timeout_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + + ucontrol->value.integer.value[0] = bt->tx->timeout; + return 0; +} + +static int btcvsd_tx_timestamp_get(struct snd_kcontrol *kcontrol, + unsigned int __user *data, unsigned int size) +{ + struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); + struct mtk_btcvsd_snd *bt = snd_soc_component_get_drvdata(cmpnt); + int ret = 0; + struct mtk_btcvsd_snd_time_buffer_info time_buffer_info_tx; + + if (size > sizeof(struct mtk_btcvsd_snd_time_buffer_info)) + return -EINVAL; + + get_tx_time_stamp(bt, &time_buffer_info_tx); + + dev_dbg(bt->dev, "%s(), time_stamp_us %llu, data_count_equi_time %llu", + __func__, + time_buffer_info_tx.time_stamp_us, + time_buffer_info_tx.data_count_equi_time); + + if (copy_to_user(data, &time_buffer_info_tx, + sizeof(struct mtk_btcvsd_snd_time_buffer_info))) { + dev_warn(bt->dev, "%s(), copy_to_user fail", __func__); + ret = -EFAULT; + } + + return ret; +} + +static const struct snd_kcontrol_new mtk_btcvsd_snd_controls[] = { + SOC_ENUM_EXT("BTCVSD Band", btcvsd_enum[0], + btcvsd_band_get, btcvsd_band_set), + SOC_SINGLE_BOOL_EXT("BTCVSD Tx Mute Switch", 0, + btcvsd_tx_mute_get, btcvsd_tx_mute_set), + SOC_SINGLE_BOOL_EXT("BTCVSD Tx Irq Received Switch", 0, + btcvsd_tx_irq_received_get, NULL), + SOC_SINGLE_BOOL_EXT("BTCVSD Tx Timeout Switch", 0, + btcvsd_tx_timeout_get, NULL), + SOC_SINGLE_BOOL_EXT("BTCVSD Rx Irq Received Switch", 0, + btcvsd_rx_irq_received_get, NULL), + SOC_SINGLE_BOOL_EXT("BTCVSD Rx Timeout Switch", 0, + btcvsd_rx_timeout_get, NULL), + SND_SOC_BYTES_TLV("BTCVSD Rx Timestamp", + sizeof(struct mtk_btcvsd_snd_time_buffer_info), + btcvsd_rx_timestamp_get, NULL), + SND_SOC_BYTES_TLV("BTCVSD Tx Timestamp", + sizeof(struct mtk_btcvsd_snd_time_buffer_info), + btcvsd_tx_timestamp_get, NULL), +}; + +static int mtk_btcvsd_snd_component_probe(struct snd_soc_component *component) +{ + return snd_soc_add_component_controls(component, + mtk_btcvsd_snd_controls, + ARRAY_SIZE(mtk_btcvsd_snd_controls)); +} + +static const struct snd_soc_component_driver mtk_btcvsd_snd_platform = { + .name = BTCVSD_SND_NAME, + .ops = &mtk_btcvsd_ops, + .probe = mtk_btcvsd_snd_component_probe, +}; + +static int mtk_btcvsd_snd_probe(struct platform_device *pdev) +{ + int ret = 0; + int irq_id; + u32 offset[5] = {0, 0, 0, 0, 0}; + struct mtk_btcvsd_snd *btcvsd; + struct device *dev = &pdev->dev; + + /* init btcvsd private data */ + btcvsd = devm_kzalloc(dev, sizeof(*btcvsd), GFP_KERNEL); + if (!btcvsd) + return -ENOMEM; + platform_set_drvdata(pdev, btcvsd); + btcvsd->dev = dev; + + /* init tx/rx */ + btcvsd->rx = devm_kzalloc(btcvsd->dev, sizeof(*btcvsd->rx), GFP_KERNEL); + if (!btcvsd->rx) + return -ENOMEM; + + btcvsd->tx = devm_kzalloc(btcvsd->dev, sizeof(*btcvsd->tx), GFP_KERNEL); + if (!btcvsd->tx) + return -ENOMEM; + + spin_lock_init(&btcvsd->tx_lock); + spin_lock_init(&btcvsd->rx_lock); + + init_waitqueue_head(&btcvsd->tx_wait); + init_waitqueue_head(&btcvsd->rx_wait); + + mtk_btcvsd_snd_tx_init(btcvsd); + mtk_btcvsd_snd_rx_init(btcvsd); + + /* irq */ + irq_id = platform_get_irq(pdev, 0); + if (irq_id <= 0) { + dev_err(dev, "%s no irq found\n", dev->of_node->name); + return irq_id < 0 ? irq_id : -ENXIO; + } + + ret = devm_request_irq(dev, irq_id, mtk_btcvsd_snd_irq_handler, + IRQF_TRIGGER_LOW, "BTCVSD_ISR_Handle", + (void *)btcvsd); + if (ret) { + dev_err(dev, "could not request_irq for BTCVSD_ISR_Handle\n"); + return ret; + } + + btcvsd->irq_id = irq_id; + + /* iomap */ + btcvsd->bt_pkv_base = of_iomap(dev->of_node, 0); + if (!btcvsd->bt_pkv_base) { + dev_err(dev, "iomap bt_pkv_base fail\n"); + return -EIO; + } + + btcvsd->bt_sram_bank2_base = of_iomap(dev->of_node, 1); + if (!btcvsd->bt_sram_bank2_base) { + dev_err(dev, "iomap bt_sram_bank2_base fail\n"); + return -EIO; + } + + btcvsd->infra = syscon_regmap_lookup_by_phandle(dev->of_node, + "mediatek,infracfg"); + if (IS_ERR(btcvsd->infra)) { + dev_err(dev, "cannot find infra controller: %ld\n", + PTR_ERR(btcvsd->infra)); + return PTR_ERR(btcvsd->infra); + } + + /* get offset */ + ret = of_property_read_u32_array(dev->of_node, "mediatek,offset", + offset, + ARRAY_SIZE(offset)); + if (ret) { + dev_warn(dev, "%s(), get offest fail, ret %d\n", __func__, ret); + return ret; + } + btcvsd->infra_misc_offset = offset[0]; + btcvsd->conn_bt_cvsd_mask = offset[1]; + btcvsd->cvsd_mcu_read_offset = offset[2]; + btcvsd->cvsd_mcu_write_offset = offset[3]; + btcvsd->cvsd_packet_indicator = offset[4]; + + btcvsd->bt_reg_pkt_r = btcvsd->bt_pkv_base + + btcvsd->cvsd_mcu_read_offset; + btcvsd->bt_reg_pkt_w = btcvsd->bt_pkv_base + + btcvsd->cvsd_mcu_write_offset; + btcvsd->bt_reg_ctl = btcvsd->bt_pkv_base + + btcvsd->cvsd_packet_indicator; + + /* init state */ + mtk_btcvsd_snd_set_state(btcvsd, btcvsd->tx, BT_SCO_STATE_IDLE); + mtk_btcvsd_snd_set_state(btcvsd, btcvsd->rx, BT_SCO_STATE_IDLE); + + return devm_snd_soc_register_component(dev, &mtk_btcvsd_snd_platform, + NULL, 0); +} + +static int mtk_btcvsd_snd_remove(struct platform_device *pdev) +{ + struct mtk_btcvsd_snd *btcvsd = dev_get_drvdata(&pdev->dev); + + iounmap(btcvsd->bt_pkv_base); + iounmap(btcvsd->bt_sram_bank2_base); + return 0; +} + +static const struct of_device_id mtk_btcvsd_snd_dt_match[] = { + { .compatible = "mediatek,mtk-btcvsd-snd", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mtk_btcvsd_snd_dt_match); + +static struct platform_driver mtk_btcvsd_snd_driver = { + .driver = { + .name = "mtk-btcvsd-snd", + .of_match_table = mtk_btcvsd_snd_dt_match, + }, + .probe = mtk_btcvsd_snd_probe, + .remove = mtk_btcvsd_snd_remove, +}; + +module_platform_driver(mtk_btcvsd_snd_driver); + +MODULE_DESCRIPTION("Mediatek ALSA BT SCO CVSD/MSBC Driver"); +MODULE_AUTHOR("KaiChieh Chuang "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-58-ga151 From 199ed3e81c49a621ce6fcb630ab9f30d92db6718 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:05:12 -0600 Subject: ASoC: dapm: fix use-after-free issue with dailink sname Commit 7620fe9161ce ("ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create") fixed a memory leak issue, but additional tests and KASAN reports show a use-after-free in soc-dapm. The widgets are created with a kmemdup operating on a template. The "name" string is also duplicated, but the "sname" string is not. As a result, when the template is freed after widget creation, its sname string is still used. Fix by explicitly duplicating the "sname" string, and freeing it when required. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2c4c13419539..e71cd5b660ad 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -295,7 +295,22 @@ EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); static inline struct snd_soc_dapm_widget *dapm_cnew_widget( const struct snd_soc_dapm_widget *_widget) { - return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + struct snd_soc_dapm_widget *w; + + w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + if (!w) + return NULL; + + /* + * w->name is duplicated in caller, but w->sname isn't. + * Duplicate it here if defined + */ + if (_widget->sname) { + w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); + if (!w->sname) + return NULL; + } + return w; } struct dapm_kcontrol_data { @@ -2412,6 +2427,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) kfree(w->kcontrols); kfree_const(w->name); + kfree_const(w->sname); kfree(w); } @@ -3469,6 +3485,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, else w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { + kfree_const(w->sname); kfree(w); return ERR_PTR(-ENOMEM); } -- cgit v1.2.3-58-ga151 From 52abe6cc1866ac3d54612f5d80563e6608c0ddfc Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 1 Feb 2019 11:05:13 -0600 Subject: ASoC: topology: fix oops/use-after-free case with dai driver rmmod/modprobe tests expose a kernel oops when accessing the dai driver pointer. This comes from the topology design which operates in multiple passes. Each object removal happens at a specific iteration, and the code checks for the iteration (order) number after the memory containing the order was freed. Fix this be clearing a reference to the dai driver and check its validity to avoid dereferences. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- sound/soc/soc-topology.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ea16c2b199ce..50617db05c46 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -956,7 +956,7 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (!dai || !dai->probed || + if (!dai || !dai->probed || !dai->driver || dai->driver->remove_order != order) return; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 045ef136903d..fc79ec6927e3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -502,6 +502,7 @@ static void remove_dai(struct snd_soc_component *comp, { struct snd_soc_dai_driver *dai_drv = container_of(dobj, struct snd_soc_dai_driver, dobj); + struct snd_soc_dai *dai; if (pass != SOC_TPLG_PASS_PCM_DAI) return; @@ -509,6 +510,10 @@ static void remove_dai(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->dai_unload) dobj->ops->dai_unload(comp, dobj); + list_for_each_entry(dai, &comp->dai_list, list) + if (dai->driver == dai_drv) + dai->driver = NULL; + kfree(dai_drv->name); list_del(&dobj->list); kfree(dai_drv); -- cgit v1.2.3-58-ga151 From 078a85f2806f0ffd11289009462a6a390f9adb5c Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 31 Jan 2019 13:30:18 +0000 Subject: ASoC: dapm: Only power up active channels from a DAI Currently all widgets attached to a DAI link will be powered up when the DAI is active, however this may include routes that are not actually in use if there are unused channels available on the DAI. The macros for creating AIF widgets already include an entry for slot, it is proposed to change that to channel. The effective difference here being respresenting the logical channel index rather than the physical slot index. The CODECs currently using the slot entry on the DAPM_AIF macros are using it in a manner consistent with this, the CODECs not using it just have the field set to zero. A variable is added to snd_soc_dapm_widget to represent this channel index and then for each AIF widget attached to a DAI this is compared against the number of channels on the stream. Enabling the links for those which will be in use. This has the nice property that the CODECs which haven't used the slot/channel entry in the macro will function exactly as before due to all the AIF widgets having a channel of zero and a stream by definition having at least one channel. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 22 +++++++++----- sound/soc/soc-dapm.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 4 +++ 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 46f2ba3ffcb7..79b4ddfb8e9e 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -214,21 +214,21 @@ struct device; .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} /* stream domain */ -#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \ +#define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } -#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } +#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } -#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \ +#define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } -#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } +#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ @@ -407,6 +407,10 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); @@ -627,6 +631,8 @@ struct snd_soc_dapm_widget { int endpoints[2]; struct clk *clk; + + int channel; }; struct snd_soc_dapm_update { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e71cd5b660ad..36d964a52874 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2541,6 +2541,78 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) } EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); +static int dapm_update_dai_chan(struct snd_soc_dapm_path *p, + struct snd_soc_dapm_widget *w, + int channels) +{ + switch (w->id) { + case snd_soc_dapm_aif_out: + case snd_soc_dapm_aif_in: + break; + default: + return 0; + } + + dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n", + w->channel < channels ? "Connecting" : "Disconnecting", + p->source->name, p->sink->name); + + if (w->channel < channels) + soc_dapm_connect_path(p, true, "dai update"); + else + soc_dapm_connect_path(p, false, "dai update"); + + return 0; +} + +static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int dir = substream->stream; + int channels = params_channels(params); + struct snd_soc_dapm_path *p; + struct snd_soc_dapm_widget *w; + int ret; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + w = dai->playback_widget; + else + w = dai->capture_widget; + + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, + dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + + snd_soc_dapm_widget_for_each_sink_path(w, p) { + ret = dapm_update_dai_chan(p, p->sink, channels); + if (ret < 0) + return ret; + } + + snd_soc_dapm_widget_for_each_source_path(w, p) { + ret = dapm_update_dai_chan(p, p->source, channels); + if (ret < 0) + return ret; + } + + return 0; +} + +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int ret; + + mutex_lock_nested(&rtd->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + ret = dapm_update_dai_unlocked(substream, params, dai); + mutex_unlock(&rtd->card->dapm_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai); + /* * dapm_update_widget_flags() - Re-compute widget sink and source flags * @w: The widget for which to update the flags @@ -3706,6 +3778,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = soc_dai_hw_params(&substream, params, source); if (ret < 0) goto out; + + dapm_update_dai_unlocked(&substream, params, source); } substream.stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -3726,6 +3800,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = soc_dai_hw_params(&substream, params, sink); if (ret < 0) goto out; + + dapm_update_dai_unlocked(&substream, params, sink); } break; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 03f36e534050..a5b40e82dea4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -969,6 +969,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, codec_dai->channels = params_channels(&codec_params); codec_dai->sample_bits = snd_pcm_format_physical_width( params_format(&codec_params)); + + snd_soc_dapm_update_dai(substream, &codec_params, codec_dai); } ret = soc_dai_hw_params(substream, params, cpu_dai); @@ -998,6 +1000,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, cpu_dai->sample_bits = snd_pcm_format_physical_width(params_format(params)); + snd_soc_dapm_update_dai(substream, params, cpu_dai); + ret = soc_pcm_params_symmetry(substream, params); if (ret) goto component_err; -- cgit v1.2.3-58-ga151 From 411db2ab7df35804422e4b26c5849b3868e6a038 Mon Sep 17 00:00:00 2001 From: Zhiwei Jiang Date: Thu, 31 Jan 2019 19:30:05 +0800 Subject: ASoC: dapm: Add warnings for widget overwrite when adding route Currently, in some complex cases, more than one widgets have same name and registed from differnt dapm context, and route add from another context too. When snd_soc_dapm_add_route, the previous registered widget will overwritten by the latest same name widget, will cause unexpect error. For Asoc framework we cant avoid this situation and we cant decide which widget that wanted with route. At least we can give users a notice. Signed-off-by: Zhiwei Jiang Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 36d964a52874..5b74dffc9c11 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2829,6 +2829,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, char prefixed_sink[80]; char prefixed_source[80]; const char *prefix; + unsigned int sink_ref = 0; + unsigned int source_ref = 0; int ret; prefix = soc_dapm_prefix(dapm); @@ -2862,6 +2864,11 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (wsource) break; } + sink_ref++; + if (sink_ref > 1) + dev_warn(dapm->dev, + "ASoC: sink widget %s overwritten\n", + w->name); continue; } if (!wsource && !(strcmp(w->name, source))) { @@ -2871,6 +2878,11 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (wsink) break; } + source_ref++; + if (source_ref > 1) + dev_warn(dapm->dev, + "ASoC: source widget %s overwritten\n", + w->name); } } /* use widget from another DAPM context if not found from this */ -- cgit v1.2.3-58-ga151 From 11907e9d3533648615db08140e3045b829d2c141 Mon Sep 17 00:00:00 2001 From: wen yang Date: Sat, 2 Feb 2019 14:53:16 +0000 Subject: ASoC: fsl-asoc-card: fix object reference leaks in fsl_asoc_card_probe The of_find_device_by_node() takes a reference to the underlying device structure, we should release that reference. Signed-off-by: Wen Yang Cc: Timur Tabi Cc: Nicolin Chen Cc: Xiubo Li Cc: Fabio Estevam Cc: Liam Girdwood Cc: Mark Brown Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: alsa-devel@alsa-project.org Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 81f2fe2c6d23..60f87a0d99f4 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -689,6 +689,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) asrc_fail: of_node_put(asrc_np); of_node_put(codec_np); + put_device(&cpu_pdev->dev); fail: of_node_put(cpu_np); -- cgit v1.2.3-58-ga151 From 78a24e10cd94420f1b4e2dc5923ae7109e2aaba1 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Tue, 29 Jan 2019 13:47:09 -0800 Subject: ASoC: soc-core: clear platform pointers on error Originally snd_soc_init_platform was not cleaning up its pointers, this was fixed to always reallocate dynamic memory but created a memory leak when snd_soc_init_platform was called multiple times during the same probe attempt and also threw away any changes made to the struct between calls. In order to avoid reallocating memory that is still valid, the behaviour will be changed to clear the dynamically set pointers on a probe error and a unregister event and snd_soc_init_platform will go back to its original behaviour of only allocating null pointers so it will stop throwing away valid changes. Signed-off-by: Curtis Malainey Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 93efab486736..8c63d32ab2fe 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1048,7 +1048,7 @@ static int snd_soc_init_platform(struct snd_soc_card *card, * soc.h :: struct snd_soc_dai_link */ /* convert Legacy platform link */ - if (!platform || dai_link->legacy_platform) { + if (!platform) { platform = devm_kzalloc(card->dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); @@ -1071,6 +1071,24 @@ static int snd_soc_init_platform(struct snd_soc_card *card, return 0; } +static void soc_cleanup_platform(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + /* + * FIXME + * + * this function should be removed with snd_soc_init_platform + */ + + for_each_card_prelinks(card, i, link) { + if (link->legacy_platform) { + link->legacy_platform = 0; + link->platforms = NULL; + } + } +} + static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -2015,6 +2033,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove and free each DAI */ soc_remove_dai_links(card); soc_remove_pcm_runtimes(card); + soc_cleanup_platform(card); /* remove auxiliary devices */ soc_remove_aux_devices(card); -- cgit v1.2.3-58-ga151 From adfebb51e1750c5df9e5d42f505b73c5542a879d Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 1 Feb 2019 11:07:40 -0600 Subject: ASoC: topology: unload physical dai link in remove soc_tplg_link_config() will find the physical dai link and call soc_tplg_dai_link_load() to load the BE dai link. Currently remove_link() is only used to remove the FE dai link which is created by the topology. The BE dai link cannot however be unloaded in snd_soc_tplg_component _remove(), which is problematic if anything needs to be released or reinitialized. This patch aligns the definitions of dynamic types with the existing UAPI and adds a new remove_backend_link() routine to unload the the BE dai link when snd_soc_tplg_component_remove() is invoked. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 1 + sound/soc/soc-topology.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 8c43cfc240fa..5223896de26f 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -45,6 +45,7 @@ enum snd_soc_dobj_type { SND_SOC_DOBJ_DAI_LINK, SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, + SND_SOC_DOBJ_BACKEND_LINK, }; /* dynamic control object */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 23d421370e6c..246d2a2d43c8 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -557,6 +557,25 @@ static void remove_link(struct snd_soc_component *comp, kfree(link); } +/* unload dai link */ +static void remove_backend_link(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + if (pass != SOC_TPLG_PASS_LINK) + return; + + if (dobj->ops && dobj->ops->link_unload) + dobj->ops->link_unload(comp, dobj); + + /* + * We don't free the link here as what remove_link() do since BE + * links are not allocated by topology. + * We however need to reset the dobj type to its initial values + */ + dobj->type = SND_SOC_DOBJ_NONE; + list_del(&dobj->list); +} + /* bind a kcontrol to it's IO handlers */ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, struct snd_kcontrol_new *k, @@ -2163,6 +2182,12 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, return ret; } + /* for unloading it in snd_soc_tplg_component_remove */ + link->dobj.index = tplg->index; + link->dobj.ops = tplg->ops; + link->dobj.type = SND_SOC_DOBJ_BACKEND_LINK; + list_add(&link->dobj.list, &tplg->comp->dobj_list); + return 0; } @@ -2649,6 +2674,13 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_DAI_LINK: remove_link(comp, dobj, pass); break; + case SND_SOC_DOBJ_BACKEND_LINK: + /* + * call link_unload ops if extra + * deinitialization is needed. + */ + remove_backend_link(comp, dobj, pass); + break; default: dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", dobj->type); -- cgit v1.2.3-58-ga151 From 766cc4965a3a2a8a62e70e9d98e1d946a71368d5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 4 Feb 2019 15:31:05 +0000 Subject: ASoC: mediatek: btcvsd: fix spelling mistake "offest" -> "offset" There is a spelling mistake in a dev_warn message. Fix this. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-btcvsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index 349a9120a0dd..e408c1b270ab 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -1309,7 +1309,7 @@ static int mtk_btcvsd_snd_probe(struct platform_device *pdev) offset, ARRAY_SIZE(offset)); if (ret) { - dev_warn(dev, "%s(), get offest fail, ret %d\n", __func__, ret); + dev_warn(dev, "%s(), get offset fail, ret %d\n", __func__, ret); return ret; } btcvsd->infra_misc_offset = offset[0]; -- cgit v1.2.3-58-ga151 From 0f747bb273790f49be4660521d86d7cebd1bbe1e Mon Sep 17 00:00:00 2001 From: Clément Péron Date: Mon, 4 Feb 2019 16:35:38 +0100 Subject: ASoC: ak4118: fix missing header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver use the gpio consumer interface. Add the header as it's needed. Signed-off-by: Clément Péron Signed-off-by: Mark Brown --- sound/soc/codecs/ak4118.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/ak4118.c b/sound/soc/codecs/ak4118.c index 238ab29f2bf4..ce419e8cf890 100644 --- a/sound/soc/codecs/ak4118.c +++ b/sound/soc/codecs/ak4118.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include -- cgit v1.2.3-58-ga151 From cf17a5ffd27234371d10748bf1c716ef172877f3 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 6 Feb 2019 11:13:59 +0000 Subject: ASoC: dapm: Check for NULL widget in dapm_update_dai_unlocked DAIs linked to the dummy will not have an associated playback/capture widget, so we need to skip the update in that case. Fixes: 078a85f2806f ("ASoC: dapm: Only power up active channels from a DAI") Reported-by: Krzysztof Kozlowski Signed-off-by: Charles Keepax Tested-by: Sylwester Nawrocki Tested-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5b74dffc9c11..111a23a9708a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2580,6 +2580,9 @@ static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, else w = dai->capture_widget; + if (!w) + return 0; + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); -- cgit v1.2.3-58-ga151 From 37768e3917405e82611af8e693ccac1a20df38b5 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 6 Feb 2019 16:29:47 +0100 Subject: ASoC: ssm2602: Fix ADC powerup sequencing According to the ssm2603 data sheet (control register sequencing), the digital core should be activated only after all necessary bits in the power register are enabled, and a delay determined by the decoupling capacitor on the VMID pin has passed. If the digital core is activated too early, or even before the ADC is powered up, audible artifacts appear at the beginning of the recorded signal. The digital core is also needed for playback, so when recording starts it may already be enabled. This means we cannot get the power sequence correct when we want to be able to start recording after playback. As a workaround put the MIC mute switch into the DAPM routes. This way we can keep the recording disabled until the MIC Bias has settled and thus get rid of audible artifacts. Signed-off-by: Philipp Zabel m.felsch@pengutronix.de: adapt commit message m.felsch@pengutronix.de: drop of configuration as mentioned by Mark: https://patchwork.kernel.org/patch/10407449/ Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 501a4e73b185..6f79cb0fbc63 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -26,6 +26,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include @@ -111,7 +112,6 @@ SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1, SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0), SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0), -SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1), }; /* Output Mixer */ @@ -121,10 +121,31 @@ SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0), SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0), }; +static const struct snd_kcontrol_new mic_ctl = + SOC_DAPM_SINGLE("Switch", SSM2602_APANA, 1, 1, 1); + /* Input mux */ static const struct snd_kcontrol_new ssm2602_input_mux_controls = SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]); +static int ssm2602_mic_switch_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + /* + * According to the ssm2603 data sheet (control register sequencing), + * the digital core should be activated only after all necessary bits + * in the power register are enabled, and a delay determined by the + * decoupling capacitor on the VMID pin has passed. If the digital core + * is activated too early, or even before the ADC is powered up, audible + * artifacts appear at the beginning and end of the recorded signal. + * + * In practice, audible artifacts disappear well over 500 ms. + */ + msleep(500); + + return 0; +} + static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1), SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1), @@ -146,6 +167,9 @@ SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1, SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls), SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1), +SND_SOC_DAPM_SWITCH_E("Mic Switch", SSM2602_APANA, 1, 1, &mic_ctl, + ssm2602_mic_switch_event, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_OUTPUT("LHPOUT"), SND_SOC_DAPM_OUTPUT("RHPOUT"), SND_SOC_DAPM_INPUT("MICIN"), @@ -178,9 +202,11 @@ static const struct snd_soc_dapm_route ssm2602_routes[] = { {"LHPOUT", NULL, "Output Mixer"}, {"Input Mux", "Line", "Line Input"}, - {"Input Mux", "Mic", "Mic Bias"}, + {"Input Mux", "Mic", "Mic Switch"}, {"ADC", NULL, "Input Mux"}, + {"Mic Switch", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "MICIN"}, }; -- cgit v1.2.3-58-ga151 From d22b4117538d42f3dcf7e28210f07f968e46222e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 5 Feb 2019 12:09:27 +0300 Subject: ASoC: wcd9335: remove some unnecessary NULL checks These are arrays, not pointers, and they can't be NULL. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 3878187bb512..981f88a5f615 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -2001,20 +2001,16 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai, return -EINVAL; } - if (wcd->rx_chs) { - wcd->num_rx_port = rx_num; - for (i = 0; i < rx_num; i++) { - wcd->rx_chs[i].ch_num = rx_slot[i]; - INIT_LIST_HEAD(&wcd->rx_chs[i].list); - } + wcd->num_rx_port = rx_num; + for (i = 0; i < rx_num; i++) { + wcd->rx_chs[i].ch_num = rx_slot[i]; + INIT_LIST_HEAD(&wcd->rx_chs[i].list); } - if (wcd->tx_chs) { - wcd->num_tx_port = tx_num; - for (i = 0; i < tx_num; i++) { - wcd->tx_chs[i].ch_num = tx_slot[i]; - INIT_LIST_HEAD(&wcd->tx_chs[i].list); - } + wcd->num_tx_port = tx_num; + for (i = 0; i < tx_num; i++) { + wcd->tx_chs[i].ch_num = tx_slot[i]; + INIT_LIST_HEAD(&wcd->tx_chs[i].list); } return 0; -- cgit v1.2.3-58-ga151 From 52cadf1fdbe87a3a3eee11d9cc4873796903c934 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2019 11:18:12 +0000 Subject: ASoC: compress: Clarify the intent of current compressed ops handling For callbacks configuring the state of the components (trigger, set_params, ack and set_metadata) simplify the code a little and make intention clearer by aborting as soon as an error is encountered. The operation has already failed and there is nothing to be gained from processing the callbacks on additional components. The operations currently abort after the callbacks, so this simply shortens the error path. For callbacks returning information from the driver (copy, get_metadata, pointer, get_codec_caps, get_caps and get_params) only look for the first callback provided, currently the code will call every callback only returning the information provided by the last. Since we can only return one set of data, it makes no sense to request the data from every component. Again this just makes the currently supported feature set a little more clear. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 106 +++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 58 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 699397a09167..fc8742383b23 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -353,7 +353,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -364,12 +364,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); @@ -394,7 +392,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; - int ret = 0, __ret, stream; + int ret, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || cmd == SND_COMPR_TRIGGER_DRAIN) { @@ -406,9 +404,10 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, + cmd); + if (ret < 0) + return ret; } return ret; } @@ -433,12 +432,10 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; @@ -472,7 +469,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -496,12 +493,10 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_params) continue; - __ret = component->driver->compr_ops->set_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + goto err; } - if (ret < 0) - goto err; if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); @@ -522,7 +517,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, cancel_delayed_work_sync(&rtd->delayed_work); - return ret; + return 0; err: mutex_unlock(&rtd->pcm_mutex); @@ -538,7 +533,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; - int ret = 0, __ret, stream; + int ret, stream; if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -578,12 +573,10 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_params) continue; - __ret = component->driver->compr_ops->set_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { ret = fe->dai_link->compr_ops->set_params(cstream); @@ -607,7 +600,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -624,9 +617,8 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_params) continue; - __ret = component->driver->compr_ops->get_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_params(cstream, params); + break; } err: @@ -640,7 +632,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -651,9 +643,8 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_caps) continue; - __ret = component->driver->compr_ops->get_caps(cstream, caps); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_caps(cstream, caps); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -666,7 +657,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -677,9 +668,9 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_codec_caps) continue; - __ret = component->driver->compr_ops->get_codec_caps(cstream, codec); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_codec_caps(cstream, + codec); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -692,7 +683,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -709,9 +700,9 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) !component->driver->compr_ops->ack) continue; - __ret = component->driver->compr_ops->ack(cstream, bytes); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->ack(cstream, bytes); + if (ret < 0) + goto err; } err: @@ -725,7 +716,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -740,9 +731,8 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, !component->driver->compr_ops->pointer) continue; - __ret = component->driver->compr_ops->pointer(cstream, tstamp); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->pointer(cstream, tstamp); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -781,7 +771,7 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) { ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai); @@ -796,12 +786,13 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_metadata) continue; - __ret = component->driver->compr_ops->set_metadata(cstream, metadata); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_metadata(cstream, + metadata); + if (ret < 0) + return ret; } - return ret; + return 0; } static int soc_compr_get_metadata(struct snd_compr_stream *cstream, @@ -811,7 +802,7 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) { ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai); @@ -826,12 +817,11 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_metadata) continue; - __ret = component->driver->compr_ops->get_metadata(cstream, metadata); - if (__ret < 0) - ret = __ret; + return component->driver->compr_ops->get_metadata(cstream, + metadata); } - return ret; + return 0; } /* ASoC Compress operations */ -- cgit v1.2.3-58-ga151 From 4ef0ecb80e348f1888b0c7ebfa8f7c1ec3ed9006 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2019 11:18:13 +0000 Subject: ASoC: compress: Add helper functions for component trigger/set_params The trigger and set_params callbacks are called from 3 and 2 separate loops respectively, tidy up the code a little by factoring these out into helper functions. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 117 ++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 63 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index fc8742383b23..03d5b9ccd3fc 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -345,17 +345,13 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) return 0; } -static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +static int soc_compr_components_trigger(struct snd_compr_stream *cstream, + int cmd) { - struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0; - - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + int ret; for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -366,9 +362,25 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) ret = component->driver->compr_ops->trigger(cstream, cmd); if (ret < 0) - goto out; + return ret; } + return 0; +} + +static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret; + + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + + ret = soc_compr_components_trigger(cstream, cmd); + if (ret < 0) + goto out; + if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); @@ -389,28 +401,12 @@ out: static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) { struct snd_soc_pcm_runtime *fe = cstream->private_data; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || - cmd == SND_COMPR_TRIGGER_DRAIN) { - - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->trigger) - continue; - - ret = component->driver->compr_ops->trigger(cstream, - cmd); - if (ret < 0) - return ret; - } - return ret; - } + cmd == SND_COMPR_TRIGGER_DRAIN) + return soc_compr_components_trigger(cstream, cmd); if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -425,17 +421,9 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) goto out; } - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->trigger) - continue; - - ret = component->driver->compr_ops->trigger(cstream, cmd); - if (ret < 0) - goto out; - } + ret = soc_compr_components_trigger(cstream, cmd); + if (ret < 0) + goto out; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; @@ -462,12 +450,33 @@ out: return ret; } -static int soc_compr_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params) +static int soc_compr_components_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; + int ret; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->compr_ops || + !component->driver->compr_ops->set_params) + continue; + + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + return ret; + } + + return 0; +} + +static int soc_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; @@ -486,17 +495,9 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, goto err; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->set_params) - continue; - - ret = component->driver->compr_ops->set_params(cstream, params); - if (ret < 0) - goto err; - } + ret = soc_compr_components_set_params(cstream, params); + if (ret < 0) + goto err; if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); @@ -530,8 +531,6 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[cstream->direction].substream; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret, stream; @@ -566,17 +565,9 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, goto out; } - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->set_params) - continue; - - ret = component->driver->compr_ops->set_params(cstream, params); - if (ret < 0) - goto out; - } + ret = soc_compr_components_set_params(cstream, params); + if (ret < 0) + goto out; if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { ret = fe->dai_link->compr_ops->set_params(cstream); -- cgit v1.2.3-58-ga151 From 47306401835a095843df8d87a51848f7e5e5099e Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Wed, 6 Feb 2019 18:00:03 +0100 Subject: ASoC: ssm2602: switch to SPDX identifier Drop old license header and switch to SPDX-License-Identifier. Signed-off-by: Marco Felsch Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 6f79cb0fbc63..464a4d7873bb 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -1,30 +1,15 @@ -/* - * File: sound/soc/codecs/ssm2602.c - * Author: Cliff Cai - * - * Created: Tue June 06 2008 - * Description: Driver for ssm2602 sound chip - * - * Modified: - * Copyright 2008 Analog Devices Inc. - * - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see the file COPYING, or write - * to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// File: sound/soc/codecs/ssm2602.c +// Author: Cliff Cai +// +// Created: Tue June 06 2008 +// Description: Driver for ssm2602 sound chip +// +// Modified: +// Copyright 2008 Analog Devices Inc. +// +// Bugs: Enter bugs at http://blackfin.uclinux.org/ #include #include -- cgit v1.2.3-58-ga151 From c16e12010060c6c7a31f08b4a99513064cb53b7d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 10:22:27 -0600 Subject: ASoC: dapm: fix out-of-bounds accesses to DAPM lookup tables KASAN reports and additional traces point to out-of-bounds accesses to the dapm_up_seq and dapm_down_seq lookup tables. The indices used are larger than the array definition. Fix by adding missing entries for the new widget types in these two lookup tables, and align them with PGA values. Also the sequences for the following widgets were not defined. Since their values defaulted to zero, assign them explicitly snd_soc_dapm_input snd_soc_dapm_output snd_soc_dapm_vmid snd_soc_dapm_siggen snd_soc_dapm_sink Fixes: 8a70b4544ef4 ('ASoC: dapm: Add new widget type for constructing DAPM graphs on DSPs.'). Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2c4c13419539..20bad755888b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -70,12 +70,16 @@ static int dapm_up_seq[] = { [snd_soc_dapm_clock_supply] = 1, [snd_soc_dapm_supply] = 2, [snd_soc_dapm_micbias] = 3, + [snd_soc_dapm_vmid] = 3, [snd_soc_dapm_dai_link] = 2, [snd_soc_dapm_dai_in] = 4, [snd_soc_dapm_dai_out] = 4, [snd_soc_dapm_aif_in] = 4, [snd_soc_dapm_aif_out] = 4, [snd_soc_dapm_mic] = 5, + [snd_soc_dapm_siggen] = 5, + [snd_soc_dapm_input] = 5, + [snd_soc_dapm_output] = 5, [snd_soc_dapm_mux] = 6, [snd_soc_dapm_demux] = 6, [snd_soc_dapm_dac] = 7, @@ -83,11 +87,19 @@ static int dapm_up_seq[] = { [snd_soc_dapm_mixer] = 8, [snd_soc_dapm_mixer_named_ctl] = 8, [snd_soc_dapm_pga] = 9, + [snd_soc_dapm_buffer] = 9, + [snd_soc_dapm_scheduler] = 9, + [snd_soc_dapm_effect] = 9, + [snd_soc_dapm_src] = 9, + [snd_soc_dapm_asrc] = 9, + [snd_soc_dapm_encoder] = 9, + [snd_soc_dapm_decoder] = 9, [snd_soc_dapm_adc] = 10, [snd_soc_dapm_out_drv] = 11, [snd_soc_dapm_hp] = 11, [snd_soc_dapm_spk] = 11, [snd_soc_dapm_line] = 11, + [snd_soc_dapm_sink] = 11, [snd_soc_dapm_kcontrol] = 12, [snd_soc_dapm_post] = 13, }; @@ -100,13 +112,25 @@ static int dapm_down_seq[] = { [snd_soc_dapm_spk] = 3, [snd_soc_dapm_line] = 3, [snd_soc_dapm_out_drv] = 3, + [snd_soc_dapm_sink] = 3, [snd_soc_dapm_pga] = 4, + [snd_soc_dapm_buffer] = 4, + [snd_soc_dapm_scheduler] = 4, + [snd_soc_dapm_effect] = 4, + [snd_soc_dapm_src] = 4, + [snd_soc_dapm_asrc] = 4, + [snd_soc_dapm_encoder] = 4, + [snd_soc_dapm_decoder] = 4, [snd_soc_dapm_switch] = 5, [snd_soc_dapm_mixer_named_ctl] = 5, [snd_soc_dapm_mixer] = 5, [snd_soc_dapm_dac] = 6, [snd_soc_dapm_mic] = 7, + [snd_soc_dapm_siggen] = 7, + [snd_soc_dapm_input] = 7, + [snd_soc_dapm_output] = 7, [snd_soc_dapm_micbias] = 8, + [snd_soc_dapm_vmid] = 8, [snd_soc_dapm_mux] = 9, [snd_soc_dapm_demux] = 9, [snd_soc_dapm_aif_in] = 10, -- cgit v1.2.3-58-ga151 From f13d4b5f85e1c436c9bf21205509266b5a81a320 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 10:22:28 -0600 Subject: ASoC: dapm: harden use of lookup tables To detect potential errors, let's add: a) build-time warnings when the table size isn't aligned with the enum list b) run-time warnings when the values are not initialized. This requires an increase by one of all values to avoid the default 0. Suggested-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 3 + sound/soc/soc-dapm.c | 158 ++++++++++++++++++++++++----------------------- 2 files changed, 85 insertions(+), 76 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 79b4ddfb8e9e..c00a0b8ade08 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -523,6 +523,9 @@ enum snd_soc_dapm_type { snd_soc_dapm_asrc, /* DSP/CODEC ASRC component */ snd_soc_dapm_encoder, /* FW/SW audio encoder component */ snd_soc_dapm_decoder, /* FW/SW audio decoder component */ + + /* Don't edit below this line */ + SND_SOC_DAPM_TYPE_COUNT }; enum snd_soc_dapm_subclass { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 40e7190f533a..d31d295b540f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -64,85 +64,85 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { - [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_regulator_supply] = 1, - [snd_soc_dapm_pinctrl] = 1, - [snd_soc_dapm_clock_supply] = 1, - [snd_soc_dapm_supply] = 2, - [snd_soc_dapm_micbias] = 3, - [snd_soc_dapm_vmid] = 3, - [snd_soc_dapm_dai_link] = 2, - [snd_soc_dapm_dai_in] = 4, - [snd_soc_dapm_dai_out] = 4, - [snd_soc_dapm_aif_in] = 4, - [snd_soc_dapm_aif_out] = 4, - [snd_soc_dapm_mic] = 5, - [snd_soc_dapm_siggen] = 5, - [snd_soc_dapm_input] = 5, - [snd_soc_dapm_output] = 5, - [snd_soc_dapm_mux] = 6, - [snd_soc_dapm_demux] = 6, - [snd_soc_dapm_dac] = 7, - [snd_soc_dapm_switch] = 8, - [snd_soc_dapm_mixer] = 8, - [snd_soc_dapm_mixer_named_ctl] = 8, - [snd_soc_dapm_pga] = 9, - [snd_soc_dapm_buffer] = 9, - [snd_soc_dapm_scheduler] = 9, - [snd_soc_dapm_effect] = 9, - [snd_soc_dapm_src] = 9, - [snd_soc_dapm_asrc] = 9, - [snd_soc_dapm_encoder] = 9, - [snd_soc_dapm_decoder] = 9, - [snd_soc_dapm_adc] = 10, - [snd_soc_dapm_out_drv] = 11, - [snd_soc_dapm_hp] = 11, - [snd_soc_dapm_spk] = 11, - [snd_soc_dapm_line] = 11, - [snd_soc_dapm_sink] = 11, - [snd_soc_dapm_kcontrol] = 12, - [snd_soc_dapm_post] = 13, + [snd_soc_dapm_pre] = 1, + [snd_soc_dapm_regulator_supply] = 2, + [snd_soc_dapm_pinctrl] = 2, + [snd_soc_dapm_clock_supply] = 2, + [snd_soc_dapm_supply] = 3, + [snd_soc_dapm_micbias] = 4, + [snd_soc_dapm_vmid] = 4, + [snd_soc_dapm_dai_link] = 3, + [snd_soc_dapm_dai_in] = 5, + [snd_soc_dapm_dai_out] = 5, + [snd_soc_dapm_aif_in] = 5, + [snd_soc_dapm_aif_out] = 5, + [snd_soc_dapm_mic] = 6, + [snd_soc_dapm_siggen] = 6, + [snd_soc_dapm_input] = 6, + [snd_soc_dapm_output] = 6, + [snd_soc_dapm_mux] = 7, + [snd_soc_dapm_demux] = 7, + [snd_soc_dapm_dac] = 8, + [snd_soc_dapm_switch] = 9, + [snd_soc_dapm_mixer] = 9, + [snd_soc_dapm_mixer_named_ctl] = 9, + [snd_soc_dapm_pga] = 10, + [snd_soc_dapm_buffer] = 10, + [snd_soc_dapm_scheduler] = 10, + [snd_soc_dapm_effect] = 10, + [snd_soc_dapm_src] = 10, + [snd_soc_dapm_asrc] = 10, + [snd_soc_dapm_encoder] = 10, + [snd_soc_dapm_decoder] = 10, + [snd_soc_dapm_adc] = 11, + [snd_soc_dapm_out_drv] = 12, + [snd_soc_dapm_hp] = 12, + [snd_soc_dapm_spk] = 12, + [snd_soc_dapm_line] = 12, + [snd_soc_dapm_sink] = 12, + [snd_soc_dapm_kcontrol] = 13, + [snd_soc_dapm_post] = 14, }; static int dapm_down_seq[] = { - [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_kcontrol] = 1, - [snd_soc_dapm_adc] = 2, - [snd_soc_dapm_hp] = 3, - [snd_soc_dapm_spk] = 3, - [snd_soc_dapm_line] = 3, - [snd_soc_dapm_out_drv] = 3, - [snd_soc_dapm_sink] = 3, - [snd_soc_dapm_pga] = 4, - [snd_soc_dapm_buffer] = 4, - [snd_soc_dapm_scheduler] = 4, - [snd_soc_dapm_effect] = 4, - [snd_soc_dapm_src] = 4, - [snd_soc_dapm_asrc] = 4, - [snd_soc_dapm_encoder] = 4, - [snd_soc_dapm_decoder] = 4, - [snd_soc_dapm_switch] = 5, - [snd_soc_dapm_mixer_named_ctl] = 5, - [snd_soc_dapm_mixer] = 5, - [snd_soc_dapm_dac] = 6, - [snd_soc_dapm_mic] = 7, - [snd_soc_dapm_siggen] = 7, - [snd_soc_dapm_input] = 7, - [snd_soc_dapm_output] = 7, - [snd_soc_dapm_micbias] = 8, - [snd_soc_dapm_vmid] = 8, - [snd_soc_dapm_mux] = 9, - [snd_soc_dapm_demux] = 9, - [snd_soc_dapm_aif_in] = 10, - [snd_soc_dapm_aif_out] = 10, - [snd_soc_dapm_dai_in] = 10, - [snd_soc_dapm_dai_out] = 10, - [snd_soc_dapm_dai_link] = 11, - [snd_soc_dapm_supply] = 12, - [snd_soc_dapm_clock_supply] = 13, - [snd_soc_dapm_pinctrl] = 13, - [snd_soc_dapm_regulator_supply] = 13, - [snd_soc_dapm_post] = 14, + [snd_soc_dapm_pre] = 1, + [snd_soc_dapm_kcontrol] = 2, + [snd_soc_dapm_adc] = 3, + [snd_soc_dapm_hp] = 4, + [snd_soc_dapm_spk] = 4, + [snd_soc_dapm_line] = 4, + [snd_soc_dapm_out_drv] = 4, + [snd_soc_dapm_sink] = 4, + [snd_soc_dapm_pga] = 5, + [snd_soc_dapm_buffer] = 5, + [snd_soc_dapm_scheduler] = 5, + [snd_soc_dapm_effect] = 5, + [snd_soc_dapm_src] = 5, + [snd_soc_dapm_asrc] = 5, + [snd_soc_dapm_encoder] = 5, + [snd_soc_dapm_decoder] = 5, + [snd_soc_dapm_switch] = 6, + [snd_soc_dapm_mixer_named_ctl] = 6, + [snd_soc_dapm_mixer] = 6, + [snd_soc_dapm_dac] = 7, + [snd_soc_dapm_mic] = 8, + [snd_soc_dapm_siggen] = 8, + [snd_soc_dapm_input] = 8, + [snd_soc_dapm_output] = 8, + [snd_soc_dapm_micbias] = 9, + [snd_soc_dapm_vmid] = 9, + [snd_soc_dapm_mux] = 10, + [snd_soc_dapm_demux] = 10, + [snd_soc_dapm_aif_in] = 11, + [snd_soc_dapm_aif_out] = 11, + [snd_soc_dapm_dai_in] = 11, + [snd_soc_dapm_dai_out] = 11, + [snd_soc_dapm_dai_link] = 12, + [snd_soc_dapm_supply] = 13, + [snd_soc_dapm_clock_supply] = 14, + [snd_soc_dapm_pinctrl] = 14, + [snd_soc_dapm_regulator_supply] = 14, + [snd_soc_dapm_post] = 15, }; static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) @@ -1425,11 +1425,17 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, { int *sort; + BUILD_BUG_ON(ARRAY_SIZE(dapm_up_seq) != SND_SOC_DAPM_TYPE_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(dapm_down_seq) != SND_SOC_DAPM_TYPE_COUNT); + if (power_up) sort = dapm_up_seq; else sort = dapm_down_seq; + WARN_ONCE(sort[a->id] == 0, "offset a->id %d not initialized\n", a->id); + WARN_ONCE(sort[b->id] == 0, "offset b->id %d not initialized\n", b->id); + if (sort[a->id] != sort[b->id]) return sort[a->id] - sort[b->id]; if (a->subseq != b->subseq) { -- cgit v1.2.3-58-ga151 From e9d97b05a80f27d5ba7379b108db19b0d93cf267 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 5 Feb 2019 00:11:08 -0300 Subject: ASoC: codecs: Add jz4725b-codec driver Add jz4725b-codec driver to support the internal CODEC found in the JZ4725B SoC from Ingenic. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 12 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/jz4725b.c | 599 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 613 insertions(+) create mode 100644 sound/soc/codecs/jz4725b.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a15710c8a95f..fec894c725d3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -90,6 +90,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_INNO_RK3036 select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC + select SND_SOC_JZ4725B_CODEC select SND_SOC_LM4857 if I2C select SND_SOC_LM49453 if I2C select SND_SOC_MAX98088 if I2C @@ -581,6 +582,17 @@ config SND_SOC_JZ4740_CODEC select REGMAP_MMIO tristate +config SND_SOC_JZ4725B_CODEC + depends on MIPS || COMPILE_TEST + select REGMAP + tristate "Ingenic JZ4725B internal CODEC" + help + Enable support for the internal CODEC found in the JZ4725B SoC + from Ingenic. + + This driver can also be built as a module. If so, the module + will be called snd-soc-jz4725b-codec. + config SND_SOC_L3 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3d7a59761c08..b07dfb5fa700 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -86,6 +86,7 @@ snd-soc-ics43432-objs := ics43432.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o +snd-soc-jz4725b-codec-objs := jz4725b.o snd-soc-l3-objs := l3.o snd-soc-lm4857-objs := lm4857.o snd-soc-lm49453-objs := lm49453.o @@ -357,6 +358,7 @@ obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o +obj-$(CONFIG_SND_SOC_JZ4725B_CODEC) += snd-soc-jz4725b-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c new file mode 100644 index 000000000000..e3dba92f30bd --- /dev/null +++ b/sound/soc/codecs/jz4725b.c @@ -0,0 +1,599 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * JZ4725B CODEC driver + * + * Copyright (C) 2019, Paul Cercueil + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define ICDC_RGADW_OFFSET 0x00 +#define ICDC_RGDATA_OFFSET 0x04 + +/* ICDC internal register access control register(RGADW) */ +#define ICDC_RGADW_RGWR BIT(16) + +#define ICDC_RGADW_RGADDR_OFFSET 8 +#define ICDC_RGADW_RGADDR_MASK GENMASK(14, ICDC_RGADW_RGADDR_OFFSET) + +#define ICDC_RGADW_RGDIN_OFFSET 0 +#define ICDC_RGADW_RGDIN_MASK GENMASK(7, ICDC_RGADW_RGDIN_OFFSET) + +/* ICDC internal register data output register (RGDATA)*/ +#define ICDC_RGDATA_IRQ BIT(8) + +#define ICDC_RGDATA_RGDOUT_OFFSET 0 +#define ICDC_RGDATA_RGDOUT_MASK GENMASK(7, ICDC_RGDATA_RGDOUT_OFFSET) + +/* JZ internal register space */ +enum { + JZ4725B_CODEC_REG_AICR, + JZ4725B_CODEC_REG_CR1, + JZ4725B_CODEC_REG_CR2, + JZ4725B_CODEC_REG_CCR1, + JZ4725B_CODEC_REG_CCR2, + JZ4725B_CODEC_REG_PMR1, + JZ4725B_CODEC_REG_PMR2, + JZ4725B_CODEC_REG_CRR, + JZ4725B_CODEC_REG_ICR, + JZ4725B_CODEC_REG_IFR, + JZ4725B_CODEC_REG_CGR1, + JZ4725B_CODEC_REG_CGR2, + JZ4725B_CODEC_REG_CGR3, + JZ4725B_CODEC_REG_CGR4, + JZ4725B_CODEC_REG_CGR5, + JZ4725B_CODEC_REG_CGR6, + JZ4725B_CODEC_REG_CGR7, + JZ4725B_CODEC_REG_CGR8, + JZ4725B_CODEC_REG_CGR9, + JZ4725B_CODEC_REG_CGR10, + JZ4725B_CODEC_REG_TR1, + JZ4725B_CODEC_REG_TR2, + JZ4725B_CODEC_REG_CR3, + JZ4725B_CODEC_REG_AGC1, + JZ4725B_CODEC_REG_AGC2, + JZ4725B_CODEC_REG_AGC3, + JZ4725B_CODEC_REG_AGC4, + JZ4725B_CODEC_REG_AGC5, +}; + +#define REG_AICR_CONFIG1_OFFSET 0 +#define REG_AICR_CONFIG1_MASK (0xf << REG_AICR_CONFIG1_OFFSET) + +#define REG_CR1_SB_MICBIAS_OFFSET 7 +#define REG_CR1_MONO_OFFSET 6 +#define REG_CR1_DAC_MUTE_OFFSET 5 +#define REG_CR1_HP_DIS_OFFSET 4 +#define REG_CR1_DACSEL_OFFSET 3 +#define REG_CR1_BYPASS_OFFSET 2 + +#define REG_CR2_DAC_DEEMP_OFFSET 7 +#define REG_CR2_DAC_ADWL_OFFSET 5 +#define REG_CR2_DAC_ADWL_MASK (0x3 << REG_CR2_DAC_ADWL_OFFSET) +#define REG_CR2_ADC_ADWL_OFFSET 3 +#define REG_CR2_ADC_ADWL_MASK (0x3 << REG_CR2_ADC_ADWL_OFFSET) +#define REG_CR2_ADC_HPF_OFFSET 2 + +#define REG_CR3_SB_MIC1_OFFSET 7 +#define REG_CR3_SB_MIC2_OFFSET 6 +#define REG_CR3_SIDETONE1_OFFSET 5 +#define REG_CR3_SIDETONE2_OFFSET 4 +#define REG_CR3_MICDIFF_OFFSET 3 +#define REG_CR3_MICSTEREO_OFFSET 2 +#define REG_CR3_INSEL_OFFSET 0 +#define REG_CR3_INSEL_MASK (0x3 << REG_CR3_INSEL_OFFSET) + +#define REG_CCR1_CONFIG4_OFFSET 0 +#define REG_CCR1_CONFIG4_MASK (0xf << REG_CCR1_CONFIG4_OFFSET) + +#define REG_CCR2_DFREQ_OFFSET 4 +#define REG_CCR2_DFREQ_MASK (0xf << REG_CCR2_DFREQ_OFFSET) +#define REG_CCR2_AFREQ_OFFSET 0 +#define REG_CCR2_AFREQ_MASK (0xf << REG_CCR2_AFREQ_OFFSET) + +#define REG_PMR1_SB_DAC_OFFSET 7 +#define REG_PMR1_SB_OUT_OFFSET 6 +#define REG_PMR1_SB_MIX_OFFSET 5 +#define REG_PMR1_SB_ADC_OFFSET 4 +#define REG_PMR1_SB_LIN_OFFSET 3 +#define REG_PMR1_SB_IND_OFFSET 0 + +#define REG_PMR2_LRGI_OFFSET 7 +#define REG_PMR2_RLGI_OFFSET 6 +#define REG_PMR2_LRGOD_OFFSET 5 +#define REG_PMR2_RLGOD_OFFSET 4 +#define REG_PMR2_GIM_OFFSET 3 +#define REG_PMR2_SB_MC_OFFSET 2 +#define REG_PMR2_SB_OFFSET 1 +#define REG_PMR2_SB_SLEEP_OFFSET 0 + +#define REG_IFR_RAMP_UP_DONE_OFFSET 3 +#define REG_IFR_RAMP_DOWN_DONE_OFFSET 2 + +#define REG_CGR1_GODL_OFFSET 4 +#define REG_CGR1_GODL_MASK (0xf << REG_CGR1_GODL_OFFSET) +#define REG_CGR1_GODR_OFFSET 0 +#define REG_CGR1_GODR_MASK (0xf << REG_CGR1_GODR_OFFSET) + +#define REG_CGR2_GO1R_OFFSET 0 +#define REG_CGR2_GO1R_MASK (0x1f << REG_CGR2_GO1R_OFFSET) + +#define REG_CGR3_GO1L_OFFSET 0 +#define REG_CGR3_GO1L_MASK (0x1f << REG_CGR3_GO1L_OFFSET) + +struct jz_icdc { + struct regmap *regmap; + void __iomem *base; + struct clk *clk; +}; + +static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_dac_tlv, -2250, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_line_tlv, -1500, 600); + +static const struct snd_kcontrol_new jz4725b_codec_controls[] = { + SOC_DOUBLE_TLV("Master Playback Volume", + JZ4725B_CODEC_REG_CGR1, + REG_CGR1_GODL_OFFSET, + REG_CGR1_GODR_OFFSET, + 0xf, 1, jz4725b_dac_tlv), + SOC_DOUBLE_R_TLV("Master Capture Volume", + JZ4725B_CODEC_REG_CGR3, + JZ4725B_CODEC_REG_CGR2, + REG_CGR2_GO1R_OFFSET, + 0x1f, 1, jz4725b_line_tlv), + + SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1, + REG_CR1_DAC_MUTE_OFFSET, 1, 1), + + SOC_SINGLE("Deemphatize Filter Playback Switch", + JZ4725B_CODEC_REG_CR2, + REG_CR2_DAC_DEEMP_OFFSET, 1, 0), + + SOC_SINGLE("High-Pass Filter Capture Switch", + JZ4725B_CODEC_REG_CR2, + REG_CR2_ADC_HPF_OFFSET, 1, 0), +}; + +static const char * const jz4725b_codec_adc_src_texts[] = { + "Mic 1", "Mic 2", "Line In", "Mixer", +}; +static const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, }; +static const SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum, + JZ4725B_CODEC_REG_CR3, + REG_CR3_INSEL_OFFSET, + REG_CR3_INSEL_MASK, + jz4725b_codec_adc_src_texts, + jz4725b_codec_adc_src_values); +static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl = + SOC_DAPM_ENUM("Route", jz4725b_codec_adc_src_enum); + +static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = { + SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1, + REG_CR1_BYPASS_OFFSET, 1, 0), +}; + +static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm); + struct jz_icdc *icdc = snd_soc_component_get_drvdata(codec); + struct regmap *map = icdc->regmap; + unsigned int val; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR, + BIT(REG_IFR_RAMP_UP_DONE_OFFSET), 0); + case SND_SOC_DAPM_POST_PMU: + return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR, + val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET), + 100000, 500000); + case SND_SOC_DAPM_PRE_PMD: + return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR, + BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), 0); + case SND_SOC_DAPM_POST_PMD: + return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR, + val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), + 100000, 500000); + default: + return -EINVAL; + } +} + +static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = { + /* DAC */ + SND_SOC_DAPM_DAC("DAC", "Playback", + JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_DAC_OFFSET, 1), + + /* ADC */ + SND_SOC_DAPM_ADC("ADC", "Capture", + JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_ADC_OFFSET, 1), + + SND_SOC_DAPM_MUX("ADC Source", SND_SOC_NOPM, 0, 0, + &jz4725b_codec_adc_src_ctrl), + + /* Mixer */ + SND_SOC_DAPM_MIXER("Mixer", JZ4725B_CODEC_REG_PMR1, + REG_PMR1_SB_MIX_OFFSET, 1, + jz4725b_codec_mixer_controls, + ARRAY_SIZE(jz4725b_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("DAC to Mixer", JZ4725B_CODEC_REG_CR1, + REG_CR1_DACSEL_OFFSET, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("Line In", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("HP Out", JZ4725B_CODEC_REG_CR1, + REG_CR1_HP_DIS_OFFSET, 1, NULL, 0), + + SND_SOC_DAPM_MIXER("Mic 1", JZ4725B_CODEC_REG_CR3, + REG_CR3_SB_MIC1_OFFSET, 1, NULL, 0), + SND_SOC_DAPM_MIXER("Mic 2", JZ4725B_CODEC_REG_CR3, + REG_CR3_SB_MIC2_OFFSET, 1, NULL, 0), + + SND_SOC_DAPM_MIXER_E("Out Stage", JZ4725B_CODEC_REG_PMR1, + REG_PMR1_SB_OUT_OFFSET, 1, NULL, 0, + jz4725b_out_stage_enable, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("Mixer to ADC", JZ4725B_CODEC_REG_PMR1, + REG_PMR1_SB_IND_OFFSET, 1, NULL, 0), + + SND_SOC_DAPM_SUPPLY("Mic Bias", JZ4725B_CODEC_REG_CR1, + REG_CR1_SB_MICBIAS_OFFSET, 1, NULL, 0), + + /* Pins */ + SND_SOC_DAPM_INPUT("MIC1P"), + SND_SOC_DAPM_INPUT("MIC1N"), + SND_SOC_DAPM_INPUT("MIC2P"), + SND_SOC_DAPM_INPUT("MIC2N"), + + SND_SOC_DAPM_INPUT("LLINEIN"), + SND_SOC_DAPM_INPUT("RLINEIN"), + + SND_SOC_DAPM_OUTPUT("LHPOUT"), + SND_SOC_DAPM_OUTPUT("RHPOUT"), +}; + +static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = { + {"Mic 1", NULL, "MIC1P"}, + {"Mic 1", NULL, "MIC1N"}, + {"Mic 2", NULL, "MIC2P"}, + {"Mic 2", NULL, "MIC2N"}, + + {"Line In", NULL, "LLINEIN"}, + {"Line In", NULL, "RLINEIN"}, + + {"Mixer", "Line In Bypass", "Line In"}, + {"DAC to Mixer", NULL, "DAC"}, + {"Mixer", NULL, "DAC to Mixer"}, + + {"Mixer to ADC", NULL, "Mixer"}, + {"ADC Source", "Mixer", "Mixer to ADC"}, + {"ADC Source", "Line In", "Line In"}, + {"ADC Source", "Mic 1", "Mic 1"}, + {"ADC Source", "Mic 2", "Mic 2"}, + {"ADC", NULL, "ADC Source"}, + + {"Out Stage", NULL, "Mixer"}, + {"HP Out", NULL, "Out Stage"}, + {"LHPOUT", NULL, "HP Out"}, + {"RHPOUT", NULL, "HP Out"}, +}; + +static int jz4725b_codec_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct jz_icdc *icdc = snd_soc_component_get_drvdata(component); + struct regmap *map = icdc->regmap; + + switch (level) { + case SND_SOC_BIAS_ON: + regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_SLEEP_OFFSET), 0); + break; + case SND_SOC_BIAS_PREPARE: + /* Enable sound hardware */ + regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_OFFSET), 0); + msleep(224); + break; + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_SLEEP_OFFSET), + BIT(REG_PMR2_SB_SLEEP_OFFSET)); + break; + case SND_SOC_BIAS_OFF: + regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2, + BIT(REG_PMR2_SB_OFFSET), + BIT(REG_PMR2_SB_OFFSET)); + break; + } + + return 0; +} + +static int jz4725b_codec_dev_probe(struct snd_soc_component *component) +{ + struct jz_icdc *icdc = snd_soc_component_get_drvdata(component); + struct regmap *map = icdc->regmap; + + clk_prepare_enable(icdc->clk); + + /* Write CONFIGn (n=1 to 8) bits. + * The value 0x0f is specified in the datasheet as a requirement. + */ + regmap_write(map, JZ4725B_CODEC_REG_AICR, + 0xf << REG_AICR_CONFIG1_OFFSET); + regmap_write(map, JZ4725B_CODEC_REG_CCR1, + 0x0 << REG_CCR1_CONFIG4_OFFSET); + + return 0; +} + +static void jz4725b_codec_dev_remove(struct snd_soc_component *component) +{ + struct jz_icdc *icdc = snd_soc_component_get_drvdata(component); + + clk_disable_unprepare(icdc->clk); +} + +static const struct snd_soc_component_driver jz4725b_codec = { + .probe = jz4725b_codec_dev_probe, + .remove = jz4725b_codec_dev_remove, + .set_bias_level = jz4725b_codec_set_bias_level, + .controls = jz4725b_codec_controls, + .num_controls = ARRAY_SIZE(jz4725b_codec_controls), + .dapm_widgets = jz4725b_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(jz4725b_codec_dapm_widgets), + .dapm_routes = jz4725b_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(jz4725b_codec_dapm_routes), + .suspend_bias_off = 1, + .use_pmdown_time = 1, +}; + +static const unsigned int jz4725b_codec_sample_rates[] = { + 96000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, + 11025, 9600, 8000, +}; + +static int jz4725b_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct jz_icdc *icdc = snd_soc_component_get_drvdata(dai->component); + unsigned int rate, bit_width; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + bit_width = 0; + break; + case SNDRV_PCM_FORMAT_S18_3LE: + bit_width = 1; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + bit_width = 2; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + bit_width = 3; + break; + default: + return -EINVAL; + } + + for (rate = 0; rate < ARRAY_SIZE(jz4725b_codec_sample_rates); rate++) { + if (jz4725b_codec_sample_rates[rate] == params_rate(params)) + break; + } + + if (rate == ARRAY_SIZE(jz4725b_codec_sample_rates)) + return -EINVAL; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(icdc->regmap, + JZ4725B_CODEC_REG_CR2, + REG_CR2_DAC_ADWL_MASK, + bit_width << REG_CR2_DAC_ADWL_OFFSET); + + regmap_update_bits(icdc->regmap, + JZ4725B_CODEC_REG_CCR2, + REG_CCR2_DFREQ_MASK, + rate << REG_CCR2_DFREQ_OFFSET); + } else { + regmap_update_bits(icdc->regmap, + JZ4725B_CODEC_REG_CR2, + REG_CR2_ADC_ADWL_MASK, + bit_width << REG_CR2_ADC_ADWL_OFFSET); + + regmap_update_bits(icdc->regmap, + JZ4725B_CODEC_REG_CCR2, + REG_CCR2_AFREQ_MASK, + rate << REG_CCR2_AFREQ_OFFSET); + } + + return 0; +} + +static const struct snd_soc_dai_ops jz4725b_codec_dai_ops = { + .hw_params = jz4725b_codec_hw_params, +}; + +#define JZ_ICDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE) + +static struct snd_soc_dai_driver jz4725b_codec_dai = { + .name = "jz4725b-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = JZ_ICDC_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = JZ_ICDC_FORMATS, + }, + .ops = &jz4725b_codec_dai_ops, +}; + +static bool jz4725b_codec_volatile(struct device *dev, unsigned int reg) +{ + return reg == JZ4725B_CODEC_REG_IFR; +} + +static bool jz4725b_codec_can_access_reg(struct device *dev, unsigned int reg) +{ + return (reg != JZ4725B_CODEC_REG_TR1) && (reg != JZ4725B_CODEC_REG_TR2); +} + +static int jz4725b_codec_io_wait(struct jz_icdc *icdc) +{ + u32 reg; + + return readl_poll_timeout(icdc->base + ICDC_RGADW_OFFSET, reg, + !(reg & ICDC_RGADW_RGWR), 1000, 10000); +} + +static int jz4725b_codec_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct jz_icdc *icdc = context; + unsigned int i; + u32 tmp; + int ret; + + ret = jz4725b_codec_io_wait(icdc); + if (ret) + return ret; + + tmp = readl(icdc->base + ICDC_RGADW_OFFSET); + tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK) + | (reg << ICDC_RGADW_RGADDR_OFFSET); + writel(tmp, icdc->base + ICDC_RGADW_OFFSET); + + /* wait 6+ cycles */ + for (i = 0; i < 6; i++) + *val = readl(icdc->base + ICDC_RGDATA_OFFSET) & + ICDC_RGDATA_RGDOUT_MASK; + + return 0; +} + +static int jz4725b_codec_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct jz_icdc *icdc = context; + int ret; + + ret = jz4725b_codec_io_wait(icdc); + if (ret) + return ret; + + writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val, + icdc->base + ICDC_RGADW_OFFSET); + + ret = jz4725b_codec_io_wait(icdc); + if (ret) + return ret; + + return 0; +} + +static const u8 jz4725b_codec_reg_defaults[] = { + 0x0c, 0xaa, 0x78, 0x00, 0x00, 0xff, 0x03, 0x51, + 0x3f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xc0, 0x34, + 0x07, 0x44, 0x1f, 0x00, +}; + +static const struct regmap_config jz4725b_codec_regmap_config = { + .reg_bits = 7, + .val_bits = 8, + + .max_register = JZ4725B_CODEC_REG_AGC5, + .volatile_reg = jz4725b_codec_volatile, + .readable_reg = jz4725b_codec_can_access_reg, + .writeable_reg = jz4725b_codec_can_access_reg, + + .reg_read = jz4725b_codec_reg_read, + .reg_write = jz4725b_codec_reg_write, + + .reg_defaults_raw = jz4725b_codec_reg_defaults, + .num_reg_defaults_raw = ARRAY_SIZE(jz4725b_codec_reg_defaults), + .cache_type = REGCACHE_FLAT, +}; + +static int jz4725b_codec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct jz_icdc *icdc; + struct resource *mem; + int ret; + + icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL); + if (!icdc) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + icdc->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(icdc->base)) + return PTR_ERR(icdc->base); + + icdc->regmap = devm_regmap_init(dev, NULL, icdc, + &jz4725b_codec_regmap_config); + if (IS_ERR(icdc->regmap)) + return PTR_ERR(icdc->regmap); + + icdc->clk = devm_clk_get(&pdev->dev, "aic"); + if (IS_ERR(icdc->clk)) + return PTR_ERR(icdc->clk); + + platform_set_drvdata(pdev, icdc); + + ret = devm_snd_soc_register_component(dev, &jz4725b_codec, + &jz4725b_codec_dai, 1); + if (ret) + dev_err(dev, "Failed to register codec\n"); + + return ret; +} + +#ifdef CONFIG_OF +static const struct of_device_id jz4725b_codec_of_matches[] = { + { .compatible = "ingenic,jz4725b-codec", }, + { } +}; +MODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches); +#endif + +static struct platform_driver jz4725b_codec_driver = { + .probe = jz4725b_codec_probe, + .driver = { + .name = "jz4725b-codec", + .of_match_table = of_match_ptr(jz4725b_codec_of_matches), + }, +}; +module_platform_driver(jz4725b_codec_driver); + +MODULE_DESCRIPTION("JZ4725B SoC internal codec driver"); +MODULE_AUTHOR("Paul Cercueil "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-58-ga151 From afb86626509205b009d636dcc098066ccf3954c6 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 5 Feb 2019 05:33:25 +0800 Subject: ASoC: wcd9335: fix semicolon.cocci warnings sound/soc/codecs/wcd-clsh-v2.c:545:2-3: Unneeded semicolon sound/soc/codecs/wcd-clsh-v2.c:211:2-3: Unneeded semicolon sound/soc/codecs/wcd-clsh-v2.c:250:2-3: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Fixes: cc2e324d39b2 ("ASoC: wcd9335: add CLASS-H Controller support") CC: Srinivas Kandagatla Signed-off-by: kbuild test robot Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-clsh-v2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c index 1bd70c5a7b63..c397d713f01a 100644 --- a/sound/soc/codecs/wcd-clsh-v2.c +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -208,7 +208,7 @@ static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) case CLS_H_LP: val = WCD9XXX_HPH_CONST_SEL_LP_PATH; break; - }; + } snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN, WCD9XXX_HPH_CONST_SEL_L_MASK, @@ -247,7 +247,7 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP; ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA; break; - }; + } snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH, WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val); @@ -542,7 +542,7 @@ int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, case WCD_CLSH_EVENT_POST_PA: _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode); break; - }; + } ctrl->state = nstate; ctrl->mode = mode; -- cgit v1.2.3-58-ga151 From 6c3e6302364aa5d152e0f5f81d550fdbc7bb8d38 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 7 Feb 2019 09:26:42 +0000 Subject: ASoC: codecs: jz4725b: fix spelling mistake "Deemphatize" -> "Deemphasize" There is a spelling mistake in the SOC_SINGLE control name. Fix this. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/codecs/jz4725b.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index e3dba92f30bd..24b1b23b99c9 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -161,7 +161,7 @@ static const struct snd_kcontrol_new jz4725b_codec_controls[] = { SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1, REG_CR1_DAC_MUTE_OFFSET, 1, 1), - SOC_SINGLE("Deemphatize Filter Playback Switch", + SOC_SINGLE("Deemphasize Filter Playback Switch", JZ4725B_CODEC_REG_CR2, REG_CR2_DAC_DEEMP_OFFSET, 1, 0), -- cgit v1.2.3-58-ga151 From 63bd84890fc41f280809a9bce7326529d044e2f9 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:37 +0100 Subject: ASoC: sun4i-codec: Add MIC2 Pre-Amplifier, Mic2 input Add MIC2 Pre-Amplifier, Mic2 input for Allwinner A10 and Allwinner A20. Previously, there only the Mic1 input and MIC1 Pre-Amplifier was exposed. This exposes the Mic2 input and MIC2 Pre-Amplifier. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 9a3cb7704810..7b965bc50042 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -64,6 +64,7 @@ #define SUN4I_CODEC_DAC_ACTL_DACAENR (31) #define SUN4I_CODEC_DAC_ACTL_DACAENL (30) #define SUN4I_CODEC_DAC_ACTL_MIXEN (29) +#define SUN4I_CODEC_DAC_ACTL_MICG (20) #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15) #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS (14) #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS (13) @@ -673,6 +674,8 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); +static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150, + 0); static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, @@ -741,6 +744,8 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { /* Mic Pre-Amplifiers */ SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0), + SND_SOC_DAPM_PGA("MIC2 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_PREG2EN, 0, NULL, 0), /* Power Amplifier */ SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL, @@ -751,6 +756,7 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { &sun4i_codec_pa_mute), SND_SOC_DAPM_INPUT("Mic1"), + SND_SOC_DAPM_INPUT("Mic2"), SND_SOC_DAPM_OUTPUT("HP Right"), SND_SOC_DAPM_OUTPUT("HP Left"), @@ -790,6 +796,12 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { { "Right ADC", NULL, "MIC1 Pre-Amplifier" }, { "MIC1 Pre-Amplifier", NULL, "Mic1"}, { "Mic1", NULL, "VMIC" }, + + /* Mic2 Routes */ + { "Left ADC", NULL, "MIC2 Pre-Amplifier" }, + { "Right ADC", NULL, "MIC2 Pre-Amplifier" }, + { "MIC2 Pre-Amplifier", NULL, "Mic2"}, + { "Mic2", NULL, "VMIC" }, }; static const struct snd_soc_component_driver sun4i_codec_codec = { -- cgit v1.2.3-58-ga151 From b5a656030c7435f37deb5d38b1593fba624b8d6d Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:38 +0100 Subject: ASoC: sun4i-codec: Add Mic Playback Volume Add a control "Mic Playback Volume" that allows the user to control the MIC gain stage (common for Mic1 and Mic2) leading to the output mixer. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 7b965bc50042..060a40b45ab0 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -681,6 +681,9 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, + sun4i_codec_micin_loopback_gain_scale), }; static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = { -- cgit v1.2.3-58-ga151 From b71a7eb56c958ffb8c90cef74f3dff6f87e6b554 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:39 +0100 Subject: ASoC: sun4i-codec: Add sun7i_codec_controls, sun7i_codec_codec Introduce sun7i_codec_controls because some of the controls are different on Allwinner A20 compared to Allwinner A10. Also introduce sun7i_codec_codec in order to use sun7i_codec_controls and make sun7i_codec_quirks use sun7i_codec_codec. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 060a40b45ab0..52453c46b409 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -686,6 +686,15 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { sun4i_codec_micin_loopback_gain_scale), }; +static const struct snd_kcontrol_new sun7i_codec_controls[] = { + SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, + sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, + sun4i_codec_micin_loopback_gain_scale), +}; + static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = { SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS, 1, 0), @@ -820,6 +829,19 @@ static const struct snd_soc_component_driver sun4i_codec_codec = { .non_legacy_dai_naming = 1, }; +static const struct snd_soc_component_driver sun7i_codec_codec = { + .controls = sun7i_codec_controls, + .num_controls = ARRAY_SIZE(sun7i_codec_controls), + .dapm_widgets = sun4i_codec_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets), + .dapm_routes = sun4i_codec_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + /*** sun6i Codec ***/ /* mixer controls */ @@ -1500,7 +1522,7 @@ static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = { static const struct sun4i_codec_quirks sun7i_codec_quirks = { .regmap_config = &sun7i_codec_regmap_config, - .codec = &sun4i_codec_codec, + .codec = &sun7i_codec_codec, .create_card = sun4i_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, -- cgit v1.2.3-58-ga151 From b329c78eb0c80bf17e877edde6d42c0793f19024 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:40 +0100 Subject: ASoC: sun4i-codec: Add Mic1 Boost Volume, Mic2 Boost Volume Add Mic1 Boost Volume and Mic2 Boost Volume for Allwinner A10 and for Allwinner A20. Those controls are in different registers per chip model, so put the Allwinner A10 controls and the Allwinner A20 controls into the newly split sun4i_codec_controls and sun7i_codec_controls, respectively. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 52453c46b409..9d509ede22c7 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -95,6 +95,8 @@ #define SUN4I_CODEC_ADC_ACTL_PREG1EN (29) #define SUN4I_CODEC_ADC_ACTL_PREG2EN (28) #define SUN4I_CODEC_ADC_ACTL_VMICEN (27) +#define SUN4I_CODEC_ADC_ACTL_PREG1 (25) +#define SUN4I_CODEC_ADC_ACTL_PREG2 (23) #define SUN4I_CODEC_ADC_ACTL_VADCG (20) #define SUN4I_CODEC_ADC_ACTL_ADCIS (17) #define SUN4I_CODEC_ADC_ACTL_PA_EN (4) @@ -111,6 +113,9 @@ /* Microphone controls (sun7i only) */ #define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c) +#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1 (29) +#define SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2 (26) + /* * sun6i specific registers * @@ -676,6 +681,12 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150, 0); +static DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(3500, 300, 0)); +static DECLARE_TLV_DB_RANGE(sun7i_codec_micin_preamp_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0)); static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, @@ -684,6 +695,12 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, sun4i_codec_micin_loopback_gain_scale), + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_PREG1, 3, 0, + sun4i_codec_micin_preamp_gain_scale), + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_PREG2, 3, 0, + sun4i_codec_micin_preamp_gain_scale), }; static const struct snd_kcontrol_new sun7i_codec_controls[] = { @@ -693,6 +710,12 @@ static const struct snd_kcontrol_new sun7i_codec_controls[] = { SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, sun4i_codec_micin_loopback_gain_scale), + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL, + SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG1, 7, 0, + sun7i_codec_micin_preamp_gain_scale), + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN7I_CODEC_AC_MIC_PHONE_CAL, + SUN7I_CODEC_AC_MIC_PHONE_CAL_PREG2, 7, 0, + sun7i_codec_micin_preamp_gain_scale), }; static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = { -- cgit v1.2.3-58-ga151 From 0bbb8e83cfe02d670380798ae1876668f8bbd00c Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:41 +0100 Subject: ASoC: sun4i-codec: Merge sun4i_codec_left_mixer_controls and sun4i_codec_right_mixer_controls into sun4i_codec_mixer_controls Since it's now possible to have a DAPM mixer control with multiple channels, use it to cut down the total number of controls. Keep "Left Mixer Left DAC Playback Switch" and "Right Mixer Right DAC Playback Switch" name & layout the same as before for compatibility. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 9d509ede22c7..279a7880d623 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -718,15 +718,15 @@ static const struct snd_kcontrol_new sun7i_codec_controls[] = { sun7i_codec_micin_preamp_gain_scale), }; -static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, - SUN4I_CODEC_DAC_ACTL_LDACLMIXS, 1, 0), -}; - -static const struct snd_kcontrol_new sun4i_codec_right_mixer_controls[] = { - SOC_DAPM_SINGLE("Right DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, - SUN4I_CODEC_DAC_ACTL_RDACRMIXS, 1, 0), - SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, +static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Mixer Left DAC Playback Switch", + SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACLMIXS, + 1, 0), + SOC_DAPM_SINGLE("Right Mixer Right DAC Playback Switch", + SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_RDACRMIXS, + 1, 0), + SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch", + SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0), }; @@ -762,11 +762,11 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { /* Mixers */ SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, - sun4i_codec_left_mixer_controls, - ARRAY_SIZE(sun4i_codec_left_mixer_controls)), + sun4i_codec_mixer_controls, + ARRAY_SIZE(sun4i_codec_mixer_controls)), SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, - sun4i_codec_right_mixer_controls, - ARRAY_SIZE(sun4i_codec_right_mixer_controls)), + sun4i_codec_mixer_controls, + ARRAY_SIZE(sun4i_codec_mixer_controls)), /* Global Mixer Enable */ SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL, @@ -808,12 +808,12 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { /* Right Mixer Routes */ { "Right Mixer", NULL, "Mixer Enable" }, - { "Right Mixer", "Left DAC Playback Switch", "Left DAC" }, - { "Right Mixer", "Right DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" }, + { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" }, /* Left Mixer Routes */ { "Left Mixer", NULL, "Mixer Enable" }, - { "Left Mixer", "Left DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" }, /* Power Amplifier Routes */ { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" }, -- cgit v1.2.3-58-ga151 From 44a1f4e8cfcc5492c4e33b983987506719714786 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:42 +0100 Subject: ASoC: sun4i-codec: Add Mic1 Playback Switch, Mic2 Playback Switch Add Mic1 Playback Switch and Mic2 Playback Switch for Allwinner A10 and Allwinner A20. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 279a7880d623..87bb16e59da7 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -68,6 +68,10 @@ #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15) #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS (14) #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS (13) +#define SUN4I_CODEC_DAC_ACTL_MIC1LS (12) +#define SUN4I_CODEC_DAC_ACTL_MIC1RS (11) +#define SUN4I_CODEC_DAC_ACTL_MIC2LS (10) +#define SUN4I_CODEC_DAC_ACTL_MIC2RS (9) #define SUN4I_CODEC_DAC_ACTL_DACPAS (8) #define SUN4I_CODEC_DAC_ACTL_MIXPAS (7) #define SUN4I_CODEC_DAC_ACTL_PA_MUTE (6) @@ -728,6 +732,12 @@ static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = { SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0), + SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_MIC1LS, + SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0), + SOC_DAPM_DOUBLE("Mic2 Playback Switch", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_MIC2LS, + SUN4I_CODEC_DAC_ACTL_MIC2RS, 1, 0), }; static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = { @@ -810,10 +820,14 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { { "Right Mixer", NULL, "Mixer Enable" }, { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" }, { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, + { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, /* Left Mixer Routes */ { "Left Mixer", NULL, "Mixer Enable" }, { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, + { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, /* Power Amplifier Routes */ { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" }, -- cgit v1.2.3-58-ga151 From 50d164194879ade8dbb1a473232fed0e77d8bfd1 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:43 +0100 Subject: ASoC: sun4i-codec: Add FM Playback Volume, FM Left, FM Right, FM Playback Switch Add FM Playback Volume for Allwinner A10 and Allwinner A20. Add FM Left, FM Right, FM Playback Switch for Allwinner A10 and Allwinner A20. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 87bb16e59da7..2ec7a43975f6 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -64,7 +64,10 @@ #define SUN4I_CODEC_DAC_ACTL_DACAENR (31) #define SUN4I_CODEC_DAC_ACTL_DACAENL (30) #define SUN4I_CODEC_DAC_ACTL_MIXEN (29) +#define SUN4I_CODEC_DAC_ACTL_FMG (23) #define SUN4I_CODEC_DAC_ACTL_MICG (20) +#define SUN4I_CODEC_DAC_ACTL_LFMS (17) +#define SUN4I_CODEC_DAC_ACTL_RFMS (16) #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15) #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS (14) #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS (13) @@ -683,6 +686,8 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); +static DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150, + 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150, 0); static DECLARE_TLV_DB_RANGE(sun4i_codec_micin_preamp_gain_scale, @@ -696,6 +701,9 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, + sun4i_codec_fmin_loopback_gain_scale), SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, sun4i_codec_micin_loopback_gain_scale), @@ -711,6 +719,9 @@ static const struct snd_kcontrol_new sun7i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, + sun4i_codec_fmin_loopback_gain_scale), SOC_SINGLE_TLV("Mic Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MICG, 7, 0, sun4i_codec_micin_loopback_gain_scale), @@ -732,6 +743,9 @@ static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = { SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0), + SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_LFMS, + SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0), SOC_DAPM_DOUBLE("Mic1 Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MIC1LS, SUN4I_CODEC_DAC_ACTL_MIC1RS, 1, 0), @@ -800,6 +814,8 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0, &sun4i_codec_pa_mute), + SND_SOC_DAPM_INPUT("FM Right"), + SND_SOC_DAPM_INPUT("FM Left"), SND_SOC_DAPM_INPUT("Mic1"), SND_SOC_DAPM_INPUT("Mic2"), @@ -820,12 +836,14 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { { "Right Mixer", NULL, "Mixer Enable" }, { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" }, { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "FM Playback Switch", "FM Right" }, { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, /* Left Mixer Routes */ { "Left Mixer", NULL, "Mixer Enable" }, { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "FM Playback Switch", "FM Left" }, { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, -- cgit v1.2.3-58-ga151 From 67690c286de6afa0dc954b19a9878e3623153cb7 Mon Sep 17 00:00:00 2001 From: Danny Milosavljevic Date: Wed, 30 Jan 2019 11:39:44 +0100 Subject: ASoC: sun4i-codec: Add Line Playback Volume, Line Boost Volume, Line Right, Line Left, Line Playback Switch Add Line Playback Volume for Allwinner A10 and Allwinner A20. Add Line Boost Volume for Allwinner A10 and Allwinner A20. Add Line Right, Line Left, Line Playback Switch for Allwinner A10 and Allwinner A20. Signed-off-by: Danny Milosavljevic Reviewed-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 2ec7a43975f6..15d08e343b47 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -64,8 +64,11 @@ #define SUN4I_CODEC_DAC_ACTL_DACAENR (31) #define SUN4I_CODEC_DAC_ACTL_DACAENL (30) #define SUN4I_CODEC_DAC_ACTL_MIXEN (29) +#define SUN4I_CODEC_DAC_ACTL_LNG (26) #define SUN4I_CODEC_DAC_ACTL_FMG (23) #define SUN4I_CODEC_DAC_ACTL_MICG (20) +#define SUN4I_CODEC_DAC_ACTL_LLNS (19) +#define SUN4I_CODEC_DAC_ACTL_RLNS (18) #define SUN4I_CODEC_DAC_ACTL_LFMS (17) #define SUN4I_CODEC_DAC_ACTL_RFMS (16) #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS (15) @@ -106,6 +109,7 @@ #define SUN4I_CODEC_ADC_ACTL_PREG2 (23) #define SUN4I_CODEC_ADC_ACTL_VADCG (20) #define SUN4I_CODEC_ADC_ACTL_ADCIS (17) +#define SUN4I_CODEC_ADC_ACTL_LNPREG (13) #define SUN4I_CODEC_ADC_ACTL_PA_EN (4) #define SUN4I_CODEC_ADC_ACTL_DDE (3) #define SUN4I_CODEC_ADC_DEBUG (0x2c) @@ -686,6 +690,10 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute = SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1); +static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_loopback_gain_scale, -150, 150, + 0); +static DECLARE_TLV_DB_SCALE(sun4i_codec_linein_preamp_gain_scale, -1200, 300, + 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_fmin_loopback_gain_scale, -450, 150, 0); static DECLARE_TLV_DB_SCALE(sun4i_codec_micin_loopback_gain_scale, -450, 150, @@ -701,6 +709,12 @@ static const struct snd_kcontrol_new sun4i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_LNG, 1, 0, + sun4i_codec_linein_loopback_gain_scale), + SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0, + sun4i_codec_linein_preamp_gain_scale), SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, sun4i_codec_fmin_loopback_gain_scale), @@ -719,6 +733,12 @@ static const struct snd_kcontrol_new sun7i_codec_controls[] = { SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0, sun4i_codec_pa_volume_scale), + SOC_SINGLE_TLV("Line Playback Volume", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_LNG, 1, 0, + sun4i_codec_linein_loopback_gain_scale), + SOC_SINGLE_TLV("Line Boost Volume", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_LNPREG, 7, 0, + sun4i_codec_linein_preamp_gain_scale), SOC_SINGLE_TLV("FM Playback Volume", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_FMG, 3, 0, sun4i_codec_fmin_loopback_gain_scale), @@ -743,6 +763,9 @@ static const struct snd_kcontrol_new sun4i_codec_mixer_controls[] = { SOC_DAPM_SINGLE("Right Mixer Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0), + SOC_DAPM_DOUBLE("Line Playback Switch", SUN4I_CODEC_DAC_ACTL, + SUN4I_CODEC_DAC_ACTL_LLNS, + SUN4I_CODEC_DAC_ACTL_RLNS, 1, 0), SOC_DAPM_DOUBLE("FM Playback Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_LFMS, SUN4I_CODEC_DAC_ACTL_RFMS, 1, 0), @@ -814,6 +837,8 @@ static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0, &sun4i_codec_pa_mute), + SND_SOC_DAPM_INPUT("Line Right"), + SND_SOC_DAPM_INPUT("Line Left"), SND_SOC_DAPM_INPUT("FM Right"), SND_SOC_DAPM_INPUT("FM Left"), SND_SOC_DAPM_INPUT("Mic1"), @@ -836,6 +861,7 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { { "Right Mixer", NULL, "Mixer Enable" }, { "Right Mixer", "Right Mixer Left DAC Playback Switch", "Left DAC" }, { "Right Mixer", "Right Mixer Right DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "Line Playback Switch", "Line Right" }, { "Right Mixer", "FM Playback Switch", "FM Right" }, { "Right Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, { "Right Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, @@ -843,6 +869,7 @@ static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { /* Left Mixer Routes */ { "Left Mixer", NULL, "Mixer Enable" }, { "Left Mixer", "Left Mixer Left DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "Line Playback Switch", "Line Left" }, { "Left Mixer", "FM Playback Switch", "FM Left" }, { "Left Mixer", "Mic1 Playback Switch", "MIC1 Pre-Amplifier" }, { "Left Mixer", "Mic2 Playback Switch", "MIC2 Pre-Amplifier" }, -- cgit v1.2.3-58-ga151 From 7c536bade37f11833ea358fbb84aca045b157fa4 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:38 -0300 Subject: dt-bindings: sound: Document jz4740-codec bindings Add documentation about how to probe the jz4740-codec driver from devicetree. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- .../bindings/sound/ingenic,jz4740-codec.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ingenic,jz4740-codec.txt diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4740-codec.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4740-codec.txt new file mode 100644 index 000000000000..1ffcade87e7b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ingenic,jz4740-codec.txt @@ -0,0 +1,20 @@ +Ingenic JZ4740 codec controller + +Required properties: +- compatible : "ingenic,jz4740-codec" +- reg : codec registers location and length +- clocks : phandle to the AIC clock. +- clock-names: must be set to "aic". +- #sound-dai-cells: Must be set to 0. + +Example: + +codec: audio-codec@10020080 { + compatible = "ingenic,jz4740-codec"; + reg = <0x10020080 0x8>; + + #sound-dai-cells = <0>; + + clocks = <&cgu JZ4740_CLK_AIC>; + clock-names = "aic"; +}; -- cgit v1.2.3-58-ga151 From f58f2b0a9f6ecfd76cb08fe1c4894ab009a30c66 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:39 -0300 Subject: dt-bindings: sound: Document jz4725b-codec bindings Add documentation about how to probe the jz4725b-codec driver from devicetree. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- .../bindings/sound/ingenic,jz4725b-codec.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ingenic,jz4725b-codec.txt diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4725b-codec.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4725b-codec.txt new file mode 100644 index 000000000000..05adc0d47b13 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ingenic,jz4725b-codec.txt @@ -0,0 +1,20 @@ +Ingenic JZ4725B codec controller + +Required properties: +- compatible : "ingenic,jz4725b-codec" +- reg : codec registers location and length +- clocks : phandle to the AIC clock. +- clock-names: must be set to "aic". +- #sound-dai-cells: Must be set to 0. + +Example: + +codec: audio-codec@100200a4 { + compatible = "ingenic,jz4725b-codec"; + reg = <0x100200a4 0x8>; + + #sound-dai-cells = <0>; + + clocks = <&cgu JZ4725B_CLK_AIC>; + clock-names = "aic"; +}; -- cgit v1.2.3-58-ga151 From 06a334ae98d15c3e32ae4ef8ce18a241a12f3dff Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:40 -0300 Subject: ASoC: codecs: jz4740: Use SPDX license notifier Add license information as a standard SPDX license notifier instead of custom text. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/jz4740.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 9395b583432c..9b3e1227a971 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -1,15 +1,8 @@ -/* - * Copyright (C) 2009-2010, Lars-Peter Clausen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ +// SPDX-License-Identifier: GPL-2.0 +// +// JZ4740 CODEC driver +// +// Copyright (C) 2009-2010, Lars-Peter Clausen #include #include -- cgit v1.2.3-58-ga151 From 030a79e97730976f54299634fa3bbb7a99e32b71 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:41 -0300 Subject: ASoC: codecs: jz4740: Add support for devicetree Add support for probing the driver from devicetree. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/jz4740.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index 9b3e1227a971..974e17fa1911 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c @@ -346,10 +346,19 @@ static int jz4740_codec_probe(struct platform_device *pdev) return ret; } +#ifdef CONFIG_OF +static const struct of_device_id jz4740_codec_of_matches[] = { + { .compatible = "ingenic,jz4740-codec", }, + { } +}; +MODULE_DEVICE_TABLE(of, jz4740_codec_of_matches); +#endif + static struct platform_driver jz4740_codec_driver = { .probe = jz4740_codec_probe, .driver = { .name = "jz4740-codec", + .of_match_table = of_match_ptr(jz4740_codec_of_matches), }, }; -- cgit v1.2.3-58-ga151 From edcd3ed182f804ebec71b063bab32c424ddd8b6a Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:42 -0300 Subject: ASoC: codecs: Kconfig: Show knob, and depend on MIPS || COMPILE_TEST Show the knob to enable or disable the jz4740-codec driver, add a proper description, and add a dependency on MIPS || COMPILE_TEST, as this driver is only useful on MIPS. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index fec894c725d3..e6ce18c21b98 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -579,8 +579,15 @@ config SND_SOC_CX20442 depends on TTY config SND_SOC_JZ4740_CODEC + depends on MIPS || COMPILE_TEST select REGMAP_MMIO - tristate + tristate "Ingenic JZ4740 internal CODEC" + help + Enable support for the internal CODEC found in the JZ4740 SoC + from Ingenic. + + This driver can also be built as a module. If so, the module + will be called snd-soc-jz4740-codec. config SND_SOC_JZ4725B_CODEC depends on MIPS || COMPILE_TEST -- cgit v1.2.3-58-ga151 From a50e32694fbcdbf55875095258b9398e2eabd71f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 7 Feb 2019 10:31:43 -0300 Subject: ASoC: codecs: jz4725b: Use C++ style comments in header Change the header comment to use C++ style, so that it looks more consistent with the rest of ASoC. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown --- sound/soc/codecs/jz4725b.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/jz4725b.c b/sound/soc/codecs/jz4725b.c index 24b1b23b99c9..103ccbc5d55c 100644 --- a/sound/soc/codecs/jz4725b.c +++ b/sound/soc/codecs/jz4725b.c @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 -/* - * JZ4725B CODEC driver - * - * Copyright (C) 2019, Paul Cercueil - */ +// +// JZ4725B CODEC driver +// +// Copyright (C) 2019, Paul Cercueil #include #include -- cgit v1.2.3-58-ga151