From fdc0074c5fc8c7adb8186cbb123fe2082d9bd05f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 9 Feb 2015 18:23:20 +0800 Subject: [PATCH 001/567] ARM: sunxi: Have ARCH_SUNXI select RESET_CONTROLLER for clock driver usage As the sunxi usb clocks all contain a reset controller, it is not possible to build the sunxi clock driver without RESET_CONTROLLER enabled. Doing so results in an undefined symbol error: drivers/built-in.o: In function `sunxi_gates_clk_setup': linux/drivers/clk/sunxi/clk-sunxi.c:1071: undefined reference to `reset_controller_register' This is possible if building a minimal kernel without PHY_SUN4I_USB. The dependency issue is made visible at compile time instead of link time by the new A80 mmc clocks, which also use a reset control itself. This patch makes ARCH_SUNXI select ARCH_HAS_RESET_CONTROLLER and RESET_CONTROLLER. Fixes: 559482d1f950 ARM: sunxi: Split the various SoCs support in Kconfig Cc: # 3.16+ Reported-by: Lourens Rozema Acked-by: Arnd Bergmann Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/mach-sunxi/Kconfig | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index a77604fbaf25..81502b90dd91 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -1,10 +1,12 @@ menuconfig ARCH_SUNXI bool "Allwinner SoCs" if ARCH_MULTI_V7 select ARCH_REQUIRE_GPIOLIB + select ARCH_HAS_RESET_CONTROLLER select CLKSRC_MMIO select GENERIC_IRQ_CHIP select PINCTRL select SUN4I_TIMER + select RESET_CONTROLLER if ARCH_SUNXI @@ -20,10 +22,8 @@ config MACH_SUN5I config MACH_SUN6I bool "Allwinner A31 (sun6i) SoCs support" default ARCH_SUNXI - select ARCH_HAS_RESET_CONTROLLER select ARM_GIC select MFD_SUN6I_PRCM - select RESET_CONTROLLER select SUN5I_HSTIMER config MACH_SUN7I @@ -37,16 +37,12 @@ config MACH_SUN7I config MACH_SUN8I bool "Allwinner A23 (sun8i) SoCs support" default ARCH_SUNXI - select ARCH_HAS_RESET_CONTROLLER select ARM_GIC select MFD_SUN6I_PRCM - select RESET_CONTROLLER config MACH_SUN9I bool "Allwinner (sun9i) SoCs support" default ARCH_SUNXI - select ARCH_HAS_RESET_CONTROLLER select ARM_GIC - select RESET_CONTROLLER endif From 5c0c75d33d45a8dc7a2af815834812d41f5361e8 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sat, 31 Jan 2015 14:49:38 +0900 Subject: [PATCH 002/567] ARM: pxa: Fix typo in zeus.c This patch fix a typo in struct platform_device can_regulator_device. Signed-off-by: Masanari Iida Acked-by: Daniel Mack Signed-off-by: Robert Jarzmik --- arch/arm/mach-pxa/zeus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index 205f9bf3821e..ac2ae5c71ab4 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -412,7 +412,7 @@ static struct fixed_voltage_config can_regulator_pdata = { }; static struct platform_device can_regulator_device = { - .name = "reg-fixed-volage", + .name = "reg-fixed-voltage", .id = 0, .dev = { .platform_data = &can_regulator_pdata, From d6cf30ca716b347587b35923eda400ad2d9e8832 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 14 Feb 2015 22:41:56 +0100 Subject: [PATCH 003/567] ARM: pxa: fix pxa interrupts handling in DT The commit "ARM: pxa: arbitrarily set first interrupt number" changed the first pxa interrupt to 16. As a consequence, device-tree builds got broken, because : - pxa_mask_irq() and pxa_unmask_irq() are using IRQ_BIT() - IRQ_BIT(x) calculates the interrupts as : x - PXA_IRQ(0) Before the commit, the first interrupt shift, PXA_IRQ(0) was 0, therefore IRQ_BIT(x) was x. After the change, it is necessary that the same shift of 16 is applied between the virtual interrupt number and the hardware irq number. This situation comes from the common irq_chip shared between legacy platform builds and device-tree builds. Fix the broken interrupts in DT case by adding this shift in the DT case too. As a consequence of the IRQ_BIT() is removed alltogether from interrupts handling, even in the platform data types of platforms : - a legacy irq domain is used - the irq_chip handles hardware interrupts - the virtual to hardware interrupt conversion is fully handled by irq domain mechanics Signed-off-by: Robert Jarzmik --- arch/arm/Kconfig | 1 + arch/arm/mach-pxa/irq.c | 111 +++++++++++++++++----------------------- 2 files changed, 49 insertions(+), 63 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9f1f09a2bc9b..cf4c0c99aa25 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -619,6 +619,7 @@ config ARCH_PXA select GENERIC_CLOCKEVENTS select GPIO_PXA select HAVE_IDE + select IRQ_DOMAIN select MULTI_IRQ_HANDLER select PLAT_PXA select SPARSE_IRQ diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 0eecd83c624e..89a7c06570d3 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -11,6 +11,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include #include #include #include @@ -40,7 +41,6 @@ #define ICHP_VAL_IRQ (1 << 31) #define ICHP_IRQ(i) (((i) >> 16) & 0x7fff) #define IPR_VALID (1 << 31) -#define IRQ_BIT(n) (((n) - PXA_IRQ(0)) & 0x1f) #define MAX_INTERNAL_IRQS 128 @@ -51,6 +51,7 @@ static void __iomem *pxa_irq_base; static int pxa_internal_irq_nr; static bool cpu_has_ipr; +static struct irq_domain *pxa_irq_domain; static inline void __iomem *irq_base(int i) { @@ -66,18 +67,20 @@ static inline void __iomem *irq_base(int i) void pxa_mask_irq(struct irq_data *d) { void __iomem *base = irq_data_get_irq_chip_data(d); + irq_hw_number_t irq = irqd_to_hwirq(d); uint32_t icmr = __raw_readl(base + ICMR); - icmr &= ~(1 << IRQ_BIT(d->irq)); + icmr &= ~BIT(irq & 0x1f); __raw_writel(icmr, base + ICMR); } void pxa_unmask_irq(struct irq_data *d) { void __iomem *base = irq_data_get_irq_chip_data(d); + irq_hw_number_t irq = irqd_to_hwirq(d); uint32_t icmr = __raw_readl(base + ICMR); - icmr |= 1 << IRQ_BIT(d->irq); + icmr |= BIT(irq & 0x1f); __raw_writel(icmr, base + ICMR); } @@ -118,40 +121,63 @@ asmlinkage void __exception_irq_entry ichp_handle_irq(struct pt_regs *regs) } while (1); } -void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int)) +static int pxa_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) { - int irq, i, n; + void __iomem *base = irq_base(hw / 32); - BUG_ON(irq_nr > MAX_INTERNAL_IRQS); + /* initialize interrupt priority */ + if (cpu_has_ipr) + __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw)); + + irq_set_chip_and_handler(virq, &pxa_internal_irq_chip, + handle_level_irq); + irq_set_chip_data(virq, base); + set_irq_flags(virq, IRQF_VALID); + + return 0; +} + +static struct irq_domain_ops pxa_irq_ops = { + .map = pxa_irq_map, + .xlate = irq_domain_xlate_onecell, +}; + +static __init void +pxa_init_irq_common(struct device_node *node, int irq_nr, + int (*fn)(struct irq_data *, unsigned int)) +{ + int n; pxa_internal_irq_nr = irq_nr; - cpu_has_ipr = !cpu_is_pxa25x(); - pxa_irq_base = io_p2v(0x40d00000); + pxa_irq_domain = irq_domain_add_legacy(node, irq_nr, + PXA_IRQ(0), 0, + &pxa_irq_ops, NULL); + if (!pxa_irq_domain) + panic("Unable to add PXA IRQ domain\n"); + irq_set_default_host(pxa_irq_domain); for (n = 0; n < irq_nr; n += 32) { void __iomem *base = irq_base(n >> 5); __raw_writel(0, base + ICMR); /* disable all IRQs */ __raw_writel(0, base + ICLR); /* all IRQs are IRQ, not FIQ */ - for (i = n; (i < (n + 32)) && (i < irq_nr); i++) { - /* initialize interrupt priority */ - if (cpu_has_ipr) - __raw_writel(i | IPR_VALID, pxa_irq_base + IPR(i)); - - irq = PXA_IRQ(i); - irq_set_chip_and_handler(irq, &pxa_internal_irq_chip, - handle_level_irq); - irq_set_chip_data(irq, base); - set_irq_flags(irq, IRQF_VALID); - } } - /* only unmasked interrupts kick us out of idle */ __raw_writel(1, irq_base(0) + ICCR); pxa_internal_irq_chip.irq_set_wake = fn; } +void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int)) +{ + BUG_ON(irq_nr > MAX_INTERNAL_IRQS); + + pxa_irq_base = io_p2v(0x40d00000); + cpu_has_ipr = !cpu_is_pxa25x(); + pxa_init_irq_common(NULL, irq_nr, fn); +} + #ifdef CONFIG_PM static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32]; static unsigned long saved_ipr[MAX_INTERNAL_IRQS]; @@ -203,30 +229,6 @@ struct syscore_ops pxa_irq_syscore_ops = { }; #ifdef CONFIG_OF -static struct irq_domain *pxa_irq_domain; - -static int pxa_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - void __iomem *base = irq_base(hw / 32); - - /* initialize interrupt priority */ - if (cpu_has_ipr) - __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw)); - - irq_set_chip_and_handler(hw, &pxa_internal_irq_chip, - handle_level_irq); - irq_set_chip_data(hw, base); - set_irq_flags(hw, IRQF_VALID); - - return 0; -} - -static struct irq_domain_ops pxa_irq_ops = { - .map = pxa_irq_map, - .xlate = irq_domain_xlate_onecell, -}; - static const struct of_device_id intc_ids[] __initconst = { { .compatible = "marvell,pxa-intc", }, {} @@ -236,7 +238,7 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int)) { struct device_node *node; struct resource res; - int n, ret; + int ret; node = of_find_matching_node(NULL, intc_ids); if (!node) { @@ -267,23 +269,6 @@ void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int)) return; } - pxa_irq_domain = irq_domain_add_legacy(node, pxa_internal_irq_nr, 0, 0, - &pxa_irq_ops, NULL); - if (!pxa_irq_domain) - panic("Unable to add PXA IRQ domain\n"); - - irq_set_default_host(pxa_irq_domain); - - for (n = 0; n < pxa_internal_irq_nr; n += 32) { - void __iomem *base = irq_base(n >> 5); - - __raw_writel(0, base + ICMR); /* disable all IRQs */ - __raw_writel(0, base + ICLR); /* all IRQs are IRQ, not FIQ */ - } - - /* only unmasked interrupts kick us out of idle */ - __raw_writel(1, irq_base(0) + ICCR); - - pxa_internal_irq_chip.irq_set_wake = fn; + pxa_init_irq_common(node, pxa_internal_irq_nr, fn); } #endif /* CONFIG_OF */ From 7d70e15480c0450d2bfafaad338a32e884fc215e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 4 Mar 2015 10:37:43 -0500 Subject: [PATCH 004/567] writeback: add missing INITIAL_JIFFIES init in global_update_bandwidth() global_update_bandwidth() uses static variable update_time as the timestamp for the last update but forgets to initialize it to INITIALIZE_JIFFIES. This means that global_dirty_limit will be 5 mins into the future on 32bit and some large amount jiffies into the past on 64bit. This isn't critical as the only effect is that global_dirty_limit won't be updated for the first 5 mins after booting on 32bit machines, especially given the auxiliary nature of global_dirty_limit's role - protecting against global dirty threshold's sudden dips; however, it does lead to unintended suboptimal behavior. Fix it. Fixes: c42843f2f0bb ("writeback: introduce smoothed global dirty limit") Signed-off-by: Tejun Heo Acked-by: Jan Kara Cc: Wu Fengguang Cc: Jens Axboe Cc: stable@vger.kernel.org Signed-off-by: Jens Axboe --- mm/page-writeback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 45e187b2d971..b4fd980a93eb 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -922,7 +922,7 @@ static void global_update_bandwidth(unsigned long thresh, unsigned long now) { static DEFINE_SPINLOCK(dirty_lock); - static unsigned long update_time; + static unsigned long update_time = INITIAL_JIFFIES; /* * check locklessly first to optimize away locking for the most time From ff6b8090e26ef7649ef0cc6b42389141ef48b0cf Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 27 Jan 2015 18:08:22 +0530 Subject: [PATCH 005/567] nbd: fix possible memory leak we have already allocated memory for nbd_dev, but we were not releasing that memory and just returning the error value. Signed-off-by: Sudip Mukherjee Acked-by: Paul Clements Cc: Signed-off-by: Markus Pargmann --- drivers/block/nbd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 4bc2a5cb9935..a98c41f72c63 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -803,10 +803,6 @@ static int __init nbd_init(void) return -EINVAL; } - nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL); - if (!nbd_dev) - return -ENOMEM; - part_shift = 0; if (max_part > 0) { part_shift = fls(max_part); @@ -828,6 +824,10 @@ static int __init nbd_init(void) if (nbds_max > 1UL << (MINORBITS - part_shift)) return -EINVAL; + nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL); + if (!nbd_dev) + return -ENOMEM; + for (i = 0; i < nbds_max; i++) { struct gendisk *disk = alloc_disk(1 << part_shift); if (!disk) From 32c006a99799f6f3c759b77ba761c3a5981e34eb Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Thu, 12 Feb 2015 14:52:49 +0800 Subject: [PATCH 006/567] gpio: mpc8xxx: remove __initdata annotation for mpc8xxx_gpio_ids[] Since commit 98686d9a52ee ("gpio: mpc8xxx: Convert to platform device interface"), we get the following section mismatch warning. Remove the __initdata annotation to fix it. WARNING: vmlinux.o(.data+0xbc28): Section mismatch in reference from the variable mpc8xxx_plat_driver to the variable .init.data:mpc8xxx_gpio_ids The variable mpc8xxx_plat_driver references the variable __initdata mpc8xxx_gpio_ids If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console Signed-off-by: Kevin Hao Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index a6952ba343a8..a65b75161aa4 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -334,7 +334,7 @@ static struct irq_domain_ops mpc8xxx_gpio_irq_ops = { .xlate = irq_domain_xlate_twocell, }; -static struct of_device_id mpc8xxx_gpio_ids[] __initdata = { +static struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc8349-gpio", }, { .compatible = "fsl,mpc8572-gpio", }, { .compatible = "fsl,mpc8610-gpio", }, From 12cb89e37a0c25fae7a0f1d2e4985558db9d0b13 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Fri, 6 Mar 2015 17:26:17 +0200 Subject: [PATCH 007/567] spi: qup: Fix cs-num DT property parsing num-cs is 32 bit property, don't read just upper 16 bits. Fixes: 4a8573abe965 (spi: qup: Remove chip select function) Signed-off-by: Ivan T. Ivanov Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-qup.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index ff9cdbdb6672..2b2c359f5a50 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -498,7 +498,7 @@ static int spi_qup_probe(struct platform_device *pdev) struct resource *res; struct device *dev; void __iomem *base; - u32 max_freq, iomode; + u32 max_freq, iomode, num_cs; int ret, irq, size; dev = &pdev->dev; @@ -550,10 +550,11 @@ static int spi_qup_probe(struct platform_device *pdev) } /* use num-cs unless not present or out of range */ - if (of_property_read_u16(dev->of_node, "num-cs", - &master->num_chipselect) || - (master->num_chipselect > SPI_NUM_CHIPSELECTS)) + if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) || + num_cs > SPI_NUM_CHIPSELECTS) master->num_chipselect = SPI_NUM_CHIPSELECTS; + else + master->num_chipselect = num_cs; master->bus_num = pdev->id; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; From 854d2f241d71f6ca08ccde30e6c7c2e403363e52 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 6 Mar 2015 14:42:01 +0200 Subject: [PATCH 008/567] spi: dw-mid: clear BUSY flag fist and test other one The logic of DMA completion is broken now since test_and_clear_bit() never returns the other bit is set. It means condition are always false and we have spi_finalize_current_transfer() called per each DMA completion which is wrong. The patch fixes logic by clearing BUSY bit first and then check for the other one. Fixes: 30c8eb52cc4a (spi: dw-mid: split rx and tx callbacks when DMA) Signed-off-by: Andy Shevchenko Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-dw-mid.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index 3ce39d10fafb..4f8c798e0633 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -108,7 +108,8 @@ static void dw_spi_dma_tx_done(void *arg) { struct dw_spi *dws = arg; - if (test_and_clear_bit(TX_BUSY, &dws->dma_chan_busy) & BIT(RX_BUSY)) + clear_bit(TX_BUSY, &dws->dma_chan_busy); + if (test_bit(RX_BUSY, &dws->dma_chan_busy)) return; dw_spi_xfer_done(dws); } @@ -156,7 +157,8 @@ static void dw_spi_dma_rx_done(void *arg) { struct dw_spi *dws = arg; - if (test_and_clear_bit(RX_BUSY, &dws->dma_chan_busy) & BIT(TX_BUSY)) + clear_bit(RX_BUSY, &dws->dma_chan_busy); + if (test_bit(TX_BUSY, &dws->dma_chan_busy)) return; dw_spi_xfer_done(dws); } From 70dddeee8945a0e62525a278ae7b91778f82f765 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Mon, 2 Mar 2015 21:03:05 +0200 Subject: [PATCH 009/567] iio: fix drivers that check buffer->scan_mask If the in-kernel push interface is used we may have a different masks on the device buffer and the kernel buffer and in this case the device should generate data for the reunion of the buffers, which is available at indio_dev->active_scan_mask. Compiled tested only except for bmc150-accel which was tested at runtime with the hardware. Signed-off-by: Octavian Purdila Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 2 +- drivers/iio/accel/bmc150-accel.c | 2 +- drivers/iio/accel/kxcjk-1013.c | 2 +- drivers/iio/adc/at91_adc.c | 5 ++--- drivers/iio/adc/ti_am335x_adc.c | 3 +-- drivers/iio/gyro/bmg160.c | 2 +- drivers/iio/imu/kmx61.c | 2 +- drivers/iio/proximity/sx9500.c | 2 +- 8 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 1096da327130..75c6d2103e07 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -659,7 +659,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) mutex_lock(&data->mutex); - for_each_set_bit(bit, indio_dev->buffer->scan_mask, + for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { ret = bma180_get_data_reg(data, bit); if (ret < 0) { diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 066d0c04072c..7d1383de3e85 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -986,7 +986,7 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p) int bit, ret, i = 0; mutex_lock(&data->mutex); - for_each_set_bit(bit, indio_dev->buffer->scan_mask, + for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { ret = i2c_smbus_read_word_data(data->client, BMC150_ACCEL_AXIS_TO_REG(bit)); diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 567de269cc00..1a6379525fa4 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -956,7 +956,7 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p) mutex_lock(&data->mutex); - for_each_set_bit(bit, indio_dev->buffer->scan_mask, + for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { ret = kxcjk1013_get_acc_reg(data, bit); if (ret < 0) { diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index ff61ae55dd3f..8a0eb4a04fb5 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -544,7 +544,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) { struct iio_dev *idev = iio_trigger_get_drvdata(trig); struct at91_adc_state *st = iio_priv(idev); - struct iio_buffer *buffer = idev->buffer; struct at91_adc_reg_desc *reg = st->registers; u32 status = at91_adc_readl(st, reg->trigger_register); int value; @@ -564,7 +563,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) at91_adc_writel(st, reg->trigger_register, status | value); - for_each_set_bit(bit, buffer->scan_mask, + for_each_set_bit(bit, idev->active_scan_mask, st->num_channels) { struct iio_chan_spec const *chan = idev->channels + bit; at91_adc_writel(st, AT91_ADC_CHER, @@ -579,7 +578,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) at91_adc_writel(st, reg->trigger_register, status & ~value); - for_each_set_bit(bit, buffer->scan_mask, + for_each_set_bit(bit, idev->active_scan_mask, st->num_channels) { struct iio_chan_spec const *chan = idev->channels + bit; at91_adc_writel(st, AT91_ADC_CHDR, diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 2e5cc4409f78..a0e7161f040c 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -188,12 +188,11 @@ static int tiadc_buffer_preenable(struct iio_dev *indio_dev) static int tiadc_buffer_postenable(struct iio_dev *indio_dev) { struct tiadc_device *adc_dev = iio_priv(indio_dev); - struct iio_buffer *buffer = indio_dev->buffer; unsigned int enb = 0; u8 bit; tiadc_step_config(indio_dev); - for_each_set_bit(bit, buffer->scan_mask, adc_dev->channels) + for_each_set_bit(bit, indio_dev->active_scan_mask, adc_dev->channels) enb |= (get_adc_step_bit(adc_dev, bit) << 1); adc_dev->buffer_en_ch_steps = enb; diff --git a/drivers/iio/gyro/bmg160.c b/drivers/iio/gyro/bmg160.c index 60451b328242..ccf3ea7e1afa 100644 --- a/drivers/iio/gyro/bmg160.c +++ b/drivers/iio/gyro/bmg160.c @@ -822,7 +822,7 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p) int bit, ret, i = 0; mutex_lock(&data->mutex); - for_each_set_bit(bit, indio_dev->buffer->scan_mask, + for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { ret = i2c_smbus_read_word_data(data->client, BMG160_AXIS_TO_REG(bit)); diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 5cc3692acf37..b3a36376c719 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1227,7 +1227,7 @@ static irqreturn_t kmx61_trigger_handler(int irq, void *p) base = KMX61_MAG_XOUT_L; mutex_lock(&data->lock); - for_each_set_bit(bit, indio_dev->buffer->scan_mask, + for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { ret = kmx61_read_measurement(data, base, bit); if (ret < 0) { diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 74dff4e4a11a..89fca3a70750 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -494,7 +494,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private) mutex_lock(&data->mutex); - for_each_set_bit(bit, indio_dev->buffer->scan_mask, + for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { ret = sx9500_read_proximity(data, &indio_dev->channels[bit], &val); From a3a0a5992e47869232cffcb02b7d32fe5204ac7c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 10 Mar 2015 22:42:50 +0200 Subject: [PATCH 010/567] iwlwifi: dvm: drop VO packets when mac80211 tells us to mac80211 now informs the driver when to drop the packets upon flush(). This will happen before disconnecting, or before we shut down the interface. We can now rely on this to drop all the packets including the VO queues. When mac80211 sets drop to false, wait for all the queues to be empty. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 47e64e8b9517..cceb026e0793 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1114,16 +1114,17 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) | BIT(IWL_DEFAULT_CMD_QUEUE_NUM)); - if (vif) - scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]); - - IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues); - if (iwlagn_txfifo_flush(priv, scd_queues)) { - IWL_ERR(priv, "flush request fail\n"); - goto done; + if (drop) { + IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", + scd_queues); + if (iwlagn_txfifo_flush(priv, scd_queues)) { + IWL_ERR(priv, "flush request fail\n"); + goto done; + } } + IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n"); - iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff); + iwl_trans_wait_tx_queue_empty(priv->trans, scd_queues); done: mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); From 060b4460c47143440e77e6721f68ef756674d207 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 10 Mar 2015 10:47:57 +0100 Subject: [PATCH 011/567] iwlwifi: mvm: disconnect if CSA time event fails scheduling If this situation ever happens, the mac80211 state machine gets confused because it never clears csa_active. There was a separate bug that lead to this happening with a working connection, but it isn't very robust to try to keep the connection up in this case. When removing the time event the CSA essentially procedure stops, so the safest thing to do is to disconnect in this case. Signed-off-by: Johannes Berg Reviewed-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/time-event.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index f8d6f306dd76..4b81c0bf63b0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -197,6 +197,8 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, struct iwl_time_event_notif *notif) { if (!le32_to_cpu(notif->status)) { + if (te_data->vif->type == NL80211_IFTYPE_STATION) + ieee80211_connection_loss(te_data->vif); IWL_DEBUG_TE(mvm, "CSA time event failed to start\n"); iwl_mvm_te_clear_data(mvm, te_data); return; From 3c2d24a9147e4c041ce94be2d166afe89225ff93 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 23 Feb 2015 02:40:07 +0200 Subject: [PATCH 012/567] iwlwifi: fix max_ht_ampdu_exponent for older devices The commit below didn't update the max_ht_ampdu_exponent for the devices listed in iwl-[1-6]000.c which, in result, became 0 instead of 8K. This reduced the size of the Rx AMPDU from 64K to 8K which had an impact in the Rx throughput. One user reported that because of this, his downstream throughput droppped by a half. CC: [3.19] Fixes: c064ddf318aa ("iwlwifi: change max HT and VHT A-MPDU exponent") Reported-and-tested-by: Valentin Manea Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-1000.c | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-2000.c | 13 +++++++++---- drivers/net/wireless/iwlwifi/iwl-5000.c | 6 ++++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 18 ++++++++++++------ 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index c3817fae16c0..06f6cc08f451 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -95,7 +95,8 @@ static const struct iwl_eeprom_params iwl1000_eeprom_params = { .nvm_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .base_params = &iwl1000_base_params, \ .eeprom_params = &iwl1000_eeprom_params, \ - .led_mode = IWL_LED_BLINK + .led_mode = IWL_LED_BLINK, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl1000_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN", @@ -121,7 +122,8 @@ const struct iwl_cfg iwl1000_bg_cfg = { .base_params = &iwl1000_base_params, \ .eeprom_params = &iwl1000_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ - .rx_with_siso_diversity = true + .rx_with_siso_diversity = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl100_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 100 BGN", diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 21e5d0843a62..890b95f497d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -123,7 +123,9 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = { .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .base_params = &iwl2000_base_params, \ .eeprom_params = &iwl20x0_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + const struct iwl_cfg iwl2000_2bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 2200 BGN", @@ -149,7 +151,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = { .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .base_params = &iwl2030_base_params, \ .eeprom_params = &iwl20x0_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl2030_2bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", @@ -170,7 +173,8 @@ const struct iwl_cfg iwl2030_2bgn_cfg = { .base_params = &iwl2000_base_params, \ .eeprom_params = &iwl20x0_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ - .rx_with_siso_diversity = true + .rx_with_siso_diversity = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl105_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 105 BGN", @@ -197,7 +201,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = { .base_params = &iwl2030_base_params, \ .eeprom_params = &iwl20x0_eeprom_params, \ .led_mode = IWL_LED_RF_STATE, \ - .rx_with_siso_diversity = true + .rx_with_siso_diversity = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl135_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N 135 BGN", diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 332bbede39e5..724194e23414 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -93,7 +93,8 @@ static const struct iwl_eeprom_params iwl5000_eeprom_params = { .nvm_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ .base_params = &iwl5000_base_params, \ .eeprom_params = &iwl5000_eeprom_params, \ - .led_mode = IWL_LED_BLINK + .led_mode = IWL_LED_BLINK, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl5300_agn_cfg = { .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", @@ -158,7 +159,8 @@ const struct iwl_cfg iwl5350_agn_cfg = { .base_params = &iwl5000_base_params, \ .eeprom_params = &iwl5000_eeprom_params, \ .led_mode = IWL_LED_BLINK, \ - .internal_wimax_coex = true + .internal_wimax_coex = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl5150_agn_cfg = { .name = "Intel(R) WiMAX/WiFi Link 5150 AGN", diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 8f2c3c8c6b84..21b2630763dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -145,7 +145,8 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = { .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .base_params = &iwl6000_g2_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl6005_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN", @@ -199,7 +200,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = { .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ .base_params = &iwl6000_g2_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl6030_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN", @@ -235,7 +237,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = { .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ .base_params = &iwl6000_g2_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_RF_STATE + .led_mode = IWL_LED_RF_STATE, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl6035_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", @@ -290,7 +293,8 @@ const struct iwl_cfg iwl130_bg_cfg = { .nvm_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ .base_params = &iwl6000_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ - .led_mode = IWL_LED_BLINK + .led_mode = IWL_LED_BLINK, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl6000i_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN", @@ -322,7 +326,8 @@ const struct iwl_cfg iwl6000i_2bg_cfg = { .base_params = &iwl6050_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ .led_mode = IWL_LED_BLINK, \ - .internal_wimax_coex = true + .internal_wimax_coex = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl6050_2agn_cfg = { .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN", @@ -347,7 +352,8 @@ const struct iwl_cfg iwl6050_2abg_cfg = { .base_params = &iwl6050_base_params, \ .eeprom_params = &iwl6000_eeprom_params, \ .led_mode = IWL_LED_BLINK, \ - .internal_wimax_coex = true + .internal_wimax_coex = true, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K const struct iwl_cfg iwl6150_bgn_cfg = { .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN", From dcaf9f5ecb6f395152609bdc40660d9b593dca63 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 4 Mar 2014 19:54:12 +0200 Subject: [PATCH 013/567] iwlwifi: mvm: add MCC update FW API The new API sets an MCC (mobile country code) to FW and receives a channel structure to be used as a basis for an updated regulatory domain. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-debug.h | 2 + drivers/net/wireless/iwlwifi/mvm/fw-api.h | 48 +++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 9 +++ drivers/net/wireless/iwlwifi/mvm/nvm.c | 84 +++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + 5 files changed, 144 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index 684254553558..9bb36d79c2bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -157,6 +157,7 @@ do { \ /* 0x0000F000 - 0x00001000 */ #define IWL_DL_ASSOC 0x00001000 #define IWL_DL_DROP 0x00002000 +#define IWL_DL_LAR 0x00004000 #define IWL_DL_COEX 0x00008000 /* 0x000F0000 - 0x00010000 */ #define IWL_DL_FW 0x00010000 @@ -219,5 +220,6 @@ do { \ #define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a) #define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a) #define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a) +#define IWL_DEBUG_LAR(p, f, a...) IWL_DEBUG(p, IWL_DL_LAR, f, ## a) #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index d95b47213731..85afede5c7c4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -212,6 +212,9 @@ enum { REPLY_RX_MPDU_CMD = 0xc1, BA_NOTIF = 0xc5, + /* Location Aware Regulatory */ + MCC_UPDATE_CMD = 0xc8, + MARKER_CMD = 0xcb, /* BT Coex */ @@ -1674,4 +1677,49 @@ struct iwl_shared_mem_cfg { __le32 page_buff_size; } __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */ +/*********************************** + * Location Aware Regulatory (LAR) API - MCC updates + ***********************************/ + +/** + * struct iwl_mcc_update_cmd - Request the device to update geographic + * regulatory profile according to the given MCC (Mobile Country Code). + * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. + * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the + * MCC in the cmd response will be the relevant MCC in the NVM. + * @mcc: given mobile country code + * @reserved: reserved for alignment + */ +struct iwl_mcc_update_cmd { + __le16 mcc; + __le16 reserved; +} __packed; /* LAR_UPDATE_MCC_CMD_API_S */ + +/** + * iwl_mcc_update_resp - response to MCC_UPDATE_CMD. + * Contains the new channel control profile map, if changed, and the new MCC + * (mobile country code). + * The new MCC may be different than what was requested in MCC_UPDATE_CMD. + * @status: 0 for success, 1 no change in channel profile, 2 invalid input. + * @mcc: the new applied MCC + * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 + * channels, depending on platform) + * @channels: channel control data map, DWORD for each channel. Only the first + * 16bits are used. + */ +struct iwl_mcc_update_resp { + __le32 status; + __le16 mcc; + __le16 reserved; + __le32 n_channels; + __le32 channels[0]; +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */ + +enum iwl_mcc_update_status { + MCC_RESP_NEW_CHAN_PROFILE, + MCC_RESP_SAME_CHAN_PROFILE, + MCC_RESP_INVALID, + MCC_RESP_NVM_DISABLED, +}; + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index e10172d69eaa..a0aa3b1dc7a5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -910,6 +910,11 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); } +static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) +{ + return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_LAR_SUPPORT; +} + static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) { return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG; @@ -1389,6 +1394,10 @@ void iwl_mvm_tt_exit(struct iwl_mvm *mvm); void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); int iwl_mvm_get_temp(struct iwl_mvm *mvm); +/* Location Aware Regulatory */ +struct iwl_mcc_update_resp * +iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2); + /* smart fifo */ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool added_vif); diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 5383429d96c1..96107b80e130 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -570,3 +570,87 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) return 0; } + +struct iwl_mcc_update_resp * +iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2) +{ + struct iwl_mcc_update_cmd mcc_update_cmd = { + .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), + }; + struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL; + struct iwl_rx_packet *pkt; + struct iwl_host_cmd cmd = { + .id = MCC_UPDATE_CMD, + .flags = CMD_WANT_SKB, + .data = { &mcc_update_cmd }, + }; + + int ret; + u32 status; + int resp_len, n_channels; + u16 mcc; + + if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) + return ERR_PTR(-EOPNOTSUPP); + + cmd.len[0] = sizeof(struct iwl_mcc_update_cmd); + + IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c'\n", + alpha2[0], alpha2[1]); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) + return ERR_PTR(ret); + + pkt = cmd.resp_pkt; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERR(mvm, "Bad return from MCC_UPDATE_COMMAND (0x%08X)\n", + pkt->hdr.flags); + ret = -EIO; + goto exit; + } + + /* Extract MCC response */ + mcc_resp = (void *)pkt->data; + status = le32_to_cpu(mcc_resp->status); + + if (status == MCC_RESP_INVALID) { + IWL_ERR(mvm, + "FW ERROR: MCC update with invalid parameter '%c%c'\n", + alpha2[0], alpha2[1]); + ret = -EINVAL; + goto exit; + } else if (status == MCC_RESP_NVM_DISABLED) { + ret = 0; + /* resp_cp will be NULL */ + goto exit; + } + + mcc = le16_to_cpu(mcc_resp->mcc); + + /* W/A for a FW/NVM issue - returns 0x00 for the world domain */ + if (mcc == 0) { + mcc = 0x3030; /* "00" - world */ + mcc_resp->mcc = cpu_to_le16(mcc); + } + + n_channels = __le32_to_cpu(mcc_resp->n_channels); + IWL_DEBUG_LAR(mvm, + "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n", + status, mcc, mcc >> 8, mcc & 0xff, + !!(status == MCC_RESP_SAME_CHAN_PROFILE), n_channels); + + resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32); + resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); + if (!resp_cp) { + ret = -ENOMEM; + goto exit; + } + + ret = 0; +exit: + iwl_free_resp(&cmd); + if (ret) + return ERR_PTR(ret); + return resp_cp; +} diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index fe40922a6b0d..72b8e19004c4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -358,6 +358,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(TDLS_CHANNEL_SWITCH_CMD), CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION), CMD(TDLS_CONFIG_CMD), + CMD(MCC_UPDATE_CMD), }; #undef CMD From 90d4f7db6c5d8af1f4eab7bc714ec0ee130f9f00 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 4 Mar 2014 19:58:46 +0200 Subject: [PATCH 014/567] iwlwifi: mvm: init country code on init/recovery During init queue a regulatory update to retrieve the default regulatory settings from FW. If we're during recovery, only replay the current country code to FW, if it exists. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw.c | 4 +++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/nvm.c | 37 ++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index a81da4cde643..c03bde093927 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -739,6 +739,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; + ret = iwl_mvm_init_mcc(mvm); + if (ret) + goto error; + if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { ret = iwl_mvm_config_scan(mvm); if (ret) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index a0aa3b1dc7a5..b31f43c7cf80 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1397,6 +1397,7 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm); /* Location Aware Regulatory */ struct iwl_mcc_update_resp * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2); +int iwl_mvm_init_mcc(struct iwl_mvm *mvm); /* smart fifo */ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 96107b80e130..26c5d94d3717 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -63,6 +63,7 @@ * *****************************************************************************/ #include +#include #include "iwl-trans.h" #include "iwl-csr.h" #include "mvm.h" @@ -654,3 +655,39 @@ exit: return ERR_PTR(ret); return resp_cp; } + +int iwl_mvm_init_mcc(struct iwl_mvm *mvm) +{ + if (!iwl_mvm_is_lar_supported(mvm)) + return 0; + + /* + * During HW restart, only replay the last set MCC to FW. Otherwise, + * queue an update to cfg80211 to retrieve the default alpha2 from FW. + */ + if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + /* This should only be called during vif up and hold RTNL */ + const struct ieee80211_regdomain *r = + rtnl_dereference(mvm->hw->wiphy->regd); + + if (r) { + struct iwl_mcc_update_resp *resp; + + resp = iwl_mvm_update_mcc(mvm, r->alpha2); + if (IS_ERR_OR_NULL(resp)) + return -EIO; + + kfree(resp); + } + + return 0; + } + + /* + * Driver regulatory hint for initial update - use the special + * unknown-country "99" code. This will also clear the "custom reg" + * flag and allow regdomain changes. It will happen after init since + * RTNL is required. + */ + return regulatory_hint(mvm->hw->wiphy, "99"); +} From af45a9003f1f14af24804f7747f14238e8d51163 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 5 Mar 2014 12:19:10 +0200 Subject: [PATCH 015/567] iwlwifi: create regdomain from mcc_update_cmd response Parse the NVM channel data and create a regulatory domain with a rule for every 20Mhz channel. Use the AUTO_BW flag so the regulatory core can unify single-channel rules into ranges. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 153 +++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | 14 ++ 2 files changed, 167 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index c74f1a4edf23..d8d9a97ff14c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -643,3 +643,156 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, return data; } IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); + +static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan, + int ch_idx, u16 nvm_flags) +{ + u32 flags = NL80211_RRF_NO_HT40; + + if (ch_idx < NUM_2GHZ_CHANNELS && + (nvm_flags & NVM_CHANNEL_40MHZ)) { + if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) + flags &= ~NL80211_RRF_NO_HT40PLUS; + if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) + flags &= ~NL80211_RRF_NO_HT40MINUS; + } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT && + (nvm_flags & NVM_CHANNEL_40MHZ)) { + if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) + flags &= ~NL80211_RRF_NO_HT40PLUS; + else + flags &= ~NL80211_RRF_NO_HT40MINUS; + } + + if (!(nvm_flags & NVM_CHANNEL_80MHZ)) + flags |= NL80211_RRF_NO_80MHZ; + if (!(nvm_flags & NVM_CHANNEL_160MHZ)) + flags |= NL80211_RRF_NO_160MHZ; + + if (!(nvm_flags & NVM_CHANNEL_IBSS)) + flags |= NL80211_RRF_NO_IR; + + if (!(nvm_flags & NVM_CHANNEL_ACTIVE)) + flags |= NL80211_RRF_NO_IR; + + if (nvm_flags & NVM_CHANNEL_RADAR) + flags |= NL80211_RRF_DFS; + + if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY) + flags |= NL80211_RRF_NO_OUTDOOR; + + /* Set the GO concurrent flag only in case that NO_IR is set. + * Otherwise it is meaningless + */ + if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) && + (flags & NL80211_RRF_NO_IR)) + flags |= NL80211_RRF_GO_CONCURRENT; + + return flags; +} + +struct ieee80211_regdomain * +iwl_parse_nvm_mcc_info(struct device *dev, int num_of_ch, __le32 *channels, + u16 fw_mcc) +{ + int ch_idx; + u16 ch_flags, prev_ch_flags = 0; + const u8 *nvm_chan = iwl_nvm_channels; /* TODO: 8000 series differs */ + struct ieee80211_regdomain *regd; + int size_of_regd; + struct ieee80211_reg_rule *rule; + enum ieee80211_band band; + int center_freq, prev_center_freq = 0; + int valid_rules = 0; + bool new_rule; + + if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) + return ERR_PTR(-EINVAL); + + IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n", + num_of_ch); + + /* build a regdomain rule for every valid channel */ + size_of_regd = + sizeof(struct ieee80211_regdomain) + + num_of_ch * sizeof(struct ieee80211_reg_rule); + + regd = kzalloc(size_of_regd, GFP_KERNEL); + if (!regd) + return ERR_PTR(-ENOMEM); + + for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { + ch_flags = (u16)__le32_to_cpup(channels + ch_idx); + band = (ch_idx < NUM_2GHZ_CHANNELS) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; + center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx], + band); + new_rule = false; + + if (!(ch_flags & NVM_CHANNEL_VALID)) { + IWL_DEBUG_DEV(dev, IWL_DL_LAR, + "Ch. %d Flags %x [%sGHz] - No traffic\n", + nvm_chan[ch_idx], + ch_flags, + (ch_idx >= NUM_2GHZ_CHANNELS) ? + "5.2" : "2.4"); + continue; + } + + /* we can't continue the same rule */ + if (ch_idx == 0 || prev_ch_flags != ch_flags || + center_freq - prev_center_freq > 20) { + valid_rules++; + new_rule = true; + } + + rule = ®d->reg_rules[valid_rules - 1]; + + if (new_rule) + rule->freq_range.start_freq_khz = + MHZ_TO_KHZ(center_freq - 10); + + rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10); + + /* this doesn't matter - not used by FW */ + rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); + rule->power_rule.max_eirp = DBM_TO_MBM(20); + + rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, + ch_flags); + + /* rely on auto-calculation to merge BW of contiguous chans */ + rule->flags |= NL80211_RRF_AUTO_BW; + rule->freq_range.max_bandwidth_khz = 0; + + prev_ch_flags = ch_flags; + prev_center_freq = center_freq; + + IWL_DEBUG_DEV(dev, IWL_DL_LAR, + "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n", + center_freq, + band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4", + CHECK_AND_PRINT_I(VALID), + CHECK_AND_PRINT_I(IBSS), + CHECK_AND_PRINT_I(ACTIVE), + CHECK_AND_PRINT_I(RADAR), + CHECK_AND_PRINT_I(WIDE), + CHECK_AND_PRINT_I(40MHZ), + CHECK_AND_PRINT_I(80MHZ), + CHECK_AND_PRINT_I(160MHZ), + CHECK_AND_PRINT_I(INDOOR_ONLY), + CHECK_AND_PRINT_I(GO_CONCURRENT), + ch_flags, + ((ch_flags & NVM_CHANNEL_IBSS) && + !(ch_flags & NVM_CHANNEL_RADAR)) + ? "" : "not "); + } + + regd->n_reg_rules = valid_rules; + + /* set alpha2 from FW. */ + regd->alpha2[0] = fw_mcc >> 8; + regd->alpha2[1] = fw_mcc & 0xff; + + return regd; +} +IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info); diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index c9c45a39d212..fa493ce01aad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h @@ -62,6 +62,7 @@ #ifndef __iwl_nvm_parse_h__ #define __iwl_nvm_parse_h__ +#include #include "iwl-eeprom-parse.h" /** @@ -78,4 +79,17 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, u8 tx_chains, u8 rx_chains); +/** + * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW + * + * This function parses the regulatory channel data received as a + * MCC_UPDATE_CMD command. It returns a newly allocation regulatory domain, + * to be fed into the regulatory core. An ERR_PTR is returned on error. + * If not given to the regulatory core, the user is responsible for freeing + * the regdomain returned here with kfree. + */ +struct ieee80211_regdomain * +iwl_parse_nvm_mcc_info(struct device *dev, int num_of_ch, __le32 *channels, + u16 fw_mcc); + #endif /* __iwl_nvm_parse_h__ */ From 770ceda6158b00cd872e0c6713f4f65320c5ff8d Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 23 Mar 2014 16:18:40 +0200 Subject: [PATCH 016/567] iwlwifi: mvm: consider LAR support during NVM parse Register to cfg80211 with all channels enabled when LAR is supported. Appropriate channels will later be disabled when a specific regulatory domain is defined. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 110 +++++++++++-------- drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | 3 +- drivers/net/wireless/iwlwifi/mvm/nvm.c | 3 +- 3 files changed, 67 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index d8d9a97ff14c..a49666f529f0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -201,9 +201,53 @@ enum iwl_nvm_channel_flags { #define CHECK_AND_PRINT_I(x) \ ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "") +static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, + u16 nvm_flags) +{ + u32 flags = IEEE80211_CHAN_NO_HT40; + + if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) { + if (ch_num <= LAST_2GHZ_HT_PLUS) + flags &= ~IEEE80211_CHAN_NO_HT40PLUS; + if (ch_num >= FIRST_2GHZ_HT_MINUS) + flags &= ~IEEE80211_CHAN_NO_HT40MINUS; + } else if (ch_num <= LAST_5GHZ_HT && (nvm_flags & NVM_CHANNEL_40MHZ)) { + if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) + flags &= ~IEEE80211_CHAN_NO_HT40PLUS; + else + flags &= ~IEEE80211_CHAN_NO_HT40MINUS; + } + if (!(nvm_flags & NVM_CHANNEL_80MHZ)) + flags |= IEEE80211_CHAN_NO_80MHZ; + if (!(nvm_flags & NVM_CHANNEL_160MHZ)) + flags |= IEEE80211_CHAN_NO_160MHZ; + + if (!(nvm_flags & NVM_CHANNEL_IBSS)) + flags |= IEEE80211_CHAN_NO_IR; + + if (!(nvm_flags & NVM_CHANNEL_ACTIVE)) + flags |= IEEE80211_CHAN_NO_IR; + + if (nvm_flags & NVM_CHANNEL_RADAR) + flags |= IEEE80211_CHAN_RADAR; + + if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY) + flags |= IEEE80211_CHAN_INDOOR_ONLY; + + /* Set the GO concurrent flag only in case that NO_IR is set. + * Otherwise it is meaningless + */ + if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) && + (flags & IEEE80211_CHAN_NO_IR)) + flags |= IEEE80211_CHAN_GO_CONCURRENT; + + return flags; +} + static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, - const __le16 * const nvm_ch_flags) + const __le16 * const nvm_ch_flags, + bool lar_supported) { int ch_idx; int n_channels = 0; @@ -230,7 +274,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, !data->sku_cap_band_52GHz_enable) ch_flags &= ~NVM_CHANNEL_VALID; - if (!(ch_flags & NVM_CHANNEL_VALID)) { + if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) { IWL_DEBUG_EEPROM(dev, "Ch. %d Flags %x [%sGHz] - No traffic\n", nvm_chan[ch_idx], @@ -250,45 +294,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, ieee80211_channel_to_frequency( channel->hw_value, channel->band); - /* TODO: Need to be dependent to the NVM */ - channel->flags = IEEE80211_CHAN_NO_HT40; - if (ch_idx < num_2ghz_channels && - (ch_flags & NVM_CHANNEL_40MHZ)) { - if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) - channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; - if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) - channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; - } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT && - (ch_flags & NVM_CHANNEL_40MHZ)) { - if ((ch_idx - num_2ghz_channels) % 2 == 0) - channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; - else - channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; - } - if (!(ch_flags & NVM_CHANNEL_80MHZ)) - channel->flags |= IEEE80211_CHAN_NO_80MHZ; - if (!(ch_flags & NVM_CHANNEL_160MHZ)) - channel->flags |= IEEE80211_CHAN_NO_160MHZ; - - if (!(ch_flags & NVM_CHANNEL_IBSS)) - channel->flags |= IEEE80211_CHAN_NO_IR; - - if (!(ch_flags & NVM_CHANNEL_ACTIVE)) - channel->flags |= IEEE80211_CHAN_NO_IR; - - if (ch_flags & NVM_CHANNEL_RADAR) - channel->flags |= IEEE80211_CHAN_RADAR; - - if (ch_flags & NVM_CHANNEL_INDOOR_ONLY) - channel->flags |= IEEE80211_CHAN_INDOOR_ONLY; - - /* Set the GO concurrent flag only in case that NO_IR is set. - * Otherwise it is meaningless - */ - if ((ch_flags & NVM_CHANNEL_GO_CONCURRENT) && - (channel->flags & IEEE80211_CHAN_NO_IR)) - channel->flags |= IEEE80211_CHAN_GO_CONCURRENT; - /* Initialize regulatory-based run-time data */ /* @@ -297,6 +302,15 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, */ channel->max_power = IWL_DEFAULT_MAX_TX_POWER; is_5ghz = channel->band == IEEE80211_BAND_5GHZ; + + /* don't put limitations in case we're using LAR */ + if (!lar_supported) + channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx], + ch_idx, is_5ghz, + ch_flags); + else + channel->flags = 0; + IWL_DEBUG_EEPROM(dev, "Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", channel->hw_value, @@ -371,7 +385,7 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *ch_section, bool enable_vht, - u8 tx_chains, u8 rx_chains) + u8 tx_chains, u8 rx_chains, bool lar_supported) { int n_channels; int n_used = 0; @@ -380,11 +394,12 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, if (cfg->device_family != IWL_DEVICE_FAMILY_8000) n_channels = iwl_init_channel_map( dev, cfg, data, - &ch_section[NVM_CHANNELS]); + &ch_section[NVM_CHANNELS], lar_supported); else n_channels = iwl_init_channel_map( dev, cfg, data, - &ch_section[NVM_CHANNELS_FAMILY_8000]); + &ch_section[NVM_CHANNELS_FAMILY_8000], + lar_supported); sband = &data->bands[IEEE80211_BAND_2GHZ]; sband->band = IEEE80211_BAND_2GHZ; @@ -571,7 +586,8 @@ struct iwl_nvm_data * iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, - const __le16 *mac_override, u8 tx_chains, u8 rx_chains) + const __le16 *mac_override, u8 tx_chains, u8 rx_chains, + bool lar_supported) { struct iwl_nvm_data *data; u32 sku; @@ -627,7 +643,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, - rx_chains); + rx_chains, lar_supported); } else { /* MAC address in family 8000 */ iwl_set_hw_address_family_8000(dev, cfg, data, mac_override, @@ -635,7 +651,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, iwl_init_sbands(dev, cfg, data, regulatory, sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, - rx_chains); + rx_chains, lar_supported); } data->calib_version = 255; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index fa493ce01aad..c2fa930a9892 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h @@ -77,7 +77,8 @@ struct iwl_nvm_data * iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, - const __le16 *mac_override, u8 tx_chains, u8 rx_chains); + const __le16 *mac_override, u8 tx_chains, u8 rx_chains, + bool lar_supported); /** * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 26c5d94d3717..907e231f2c5c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -302,7 +302,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, regulatory, mac_override, mvm->fw->valid_tx_ant, - mvm->fw->valid_rx_ant); + mvm->fw->valid_rx_ant, + iwl_mvm_is_lar_supported(mvm)); } #define MAX_NVM_FILE_LEN 16384 From bdf2fae8376bbf1bdb0baa4c3616e81731214dfb Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Thu, 30 Oct 2014 15:12:39 +0200 Subject: [PATCH 017/567] iwlwifi: ignore IBSS flag as regulatory NO-IR indication According to updated regulatory guidelines, the ACTIVE bit in the NVM also allows ibss activity on the channel. The IBSS NVM bit is not updated when LAR is active and is deprecated. Using this bit for NO-IR incorrectly causes all 5Ghz channels to be marked as passive. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index a49666f529f0..99476bd6663a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -684,9 +684,6 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan, if (!(nvm_flags & NVM_CHANNEL_160MHZ)) flags |= NL80211_RRF_NO_160MHZ; - if (!(nvm_flags & NVM_CHANNEL_IBSS)) - flags |= NL80211_RRF_NO_IR; - if (!(nvm_flags & NVM_CHANNEL_ACTIVE)) flags |= NL80211_RRF_NO_IR; @@ -784,11 +781,10 @@ iwl_parse_nvm_mcc_info(struct device *dev, int num_of_ch, __le32 *channels, prev_center_freq = center_freq; IWL_DEBUG_DEV(dev, IWL_DL_LAR, - "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n", + "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n", center_freq, band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4", CHECK_AND_PRINT_I(VALID), - CHECK_AND_PRINT_I(IBSS), CHECK_AND_PRINT_I(ACTIVE), CHECK_AND_PRINT_I(RADAR), CHECK_AND_PRINT_I(WIDE), @@ -798,7 +794,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, int num_of_ch, __le32 *channels, CHECK_AND_PRINT_I(INDOOR_ONLY), CHECK_AND_PRINT_I(GO_CONCURRENT), ch_flags, - ((ch_flags & NVM_CHANNEL_IBSS) && + ((ch_flags & NVM_CHANNEL_ACTIVE) && !(ch_flags & NVM_CHANNEL_RADAR)) ? "" : "not "); } From a76f3bfe016dbda161f9d31cc5cbdd9238d13488 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Mon, 26 May 2014 18:11:37 +0300 Subject: [PATCH 018/567] iwlwifi: don't declare support for 5ghz if not supported Remove a useless debug print about unsupported channels. Also add a comment about the LAR special case where channels might become valid later. Signed-off-by: Eliad Peller Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 99476bd6663a..88703778dbb2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -272,9 +272,14 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, if (ch_idx >= num_2ghz_channels && !data->sku_cap_band_52GHz_enable) - ch_flags &= ~NVM_CHANNEL_VALID; + continue; if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) { + /* + * Channels might become valid later if lar is + * supported, hence we still want to add them to + * the list of supported channels to cfg80211. + */ IWL_DEBUG_EEPROM(dev, "Ch. %d Flags %x [%sGHz] - No traffic\n", nvm_chan[ch_idx], From 88931cc92872151d53f86720c848e469574ce7f0 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 5 Mar 2014 12:26:15 +0200 Subject: [PATCH 019/567] iwlwifi: mvm: LAR: Add chub mcc change notify command Chub (Communication Hub, CommsHUB) is a HW component that connects to the cellular and connectivity cores that gets updates of mcc changes, and then notifies the FW directly of any mcc change. The ucode notifies the driver (via this command) that it should ask for an mcc update, and the driver sends the ucode the update mcc command to set the updated regulatory info. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 20 ++++++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 56 +++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 7 +++ drivers/net/wireless/iwlwifi/mvm/nvm.c | 26 +++++++++- drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + 5 files changed, 109 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 85afede5c7c4..c4b59ecb3606 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -214,6 +214,7 @@ enum { /* Location Aware Regulatory */ MCC_UPDATE_CMD = 0xc8, + MCC_CHUB_UPDATE_CMD = 0xc9, MARKER_CMD = 0xcb, @@ -1715,6 +1716,25 @@ struct iwl_mcc_update_resp { __le32 channels[0]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */ +/** + * struct iwl_mcc_chub_notif - chub notifies of mcc change + * (MCC_CHUB_UPDATE_CMD = 0xc9) + * The Chub (Communication Hub, CommsHUB) is a HW component that connects to + * the cellular and connectivity cores that gets updates of the mcc, and + * notifies the ucode directly of any mcc change. + * The ucode requests the driver to request the device to update geographic + * regulatory profile according to the given MCC (Mobile Country Code). + * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. + * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the + * MCC in the cmd response will be the relevant MCC in the NVM. + * @mcc: given mobile country code + * @reserved: reserved for alignment + */ +struct iwl_mcc_chub_notif { + u16 mcc; + u16 reserved1; +} __packed; /* LAR_MCC_NOTIFY_S */ + enum iwl_mcc_update_status { MCC_RESP_NEW_CHAN_PROFILE, MCC_RESP_SAME_CHAN_PROFILE, diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 204255423d99..0da8787aa25b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -86,6 +86,7 @@ #include "iwl-fw-error-dump.h" #include "iwl-prph.h" #include "iwl-csr.h" +#include "iwl-nvm-parse.h" static const struct ieee80211_iface_limit iwl_mvm_limits[] = { { @@ -301,6 +302,49 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) } } +struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, + const char *alpha2) +{ + struct ieee80211_regdomain *regd = NULL; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mcc_update_resp *resp; + + IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2); + + mutex_lock(&mvm->mutex); + + /* change "99" to "ZZ" for the FW */ + if (alpha2[0] == '9' && alpha2[1] == '9') + alpha2 = "ZZ"; + + resp = iwl_mvm_update_mcc(mvm, alpha2); + if (IS_ERR_OR_NULL(resp)) { + IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n", + PTR_RET(resp)); + goto out_unlock; + } + + regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, + __le32_to_cpu(resp->n_channels), + resp->channels, + __le16_to_cpu(resp->mcc)); + kfree(resp); + if (IS_ERR_OR_NULL(regd)) { + IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n", + PTR_RET(resp)); + goto out_unlock; + } + + IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x)\n", + regd->alpha2, regd->alpha2[0], regd->alpha2[1]); + mvm->lar_regdom_set = true; + +out_unlock: + mutex_unlock(&mvm->mutex); + return regd; +} + int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) { struct ieee80211_hw *hw = mvm->hw; @@ -2245,6 +2289,12 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); + if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) { + IWL_ERR(mvm, "scan while LAR regdomain is not set\n"); + ret = -EBUSY; + goto out; + } + if (mvm->scan_status != IWL_MVM_SCAN_NONE) { ret = -EBUSY; goto out; @@ -2583,6 +2633,12 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); + if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) { + IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n"); + ret = -EBUSY; + goto out; + } + if (!vif->bss_conf.idle) { ret = -EBUSY; goto out; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index b31f43c7cf80..df5a2286b409 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -810,6 +810,8 @@ struct iwl_mvm { /* system time of last beacon (for AP/GO interface) */ u32 ap_last_beacon_gp2; + bool lar_regdom_set; + u8 low_latency_agg_frame_limit; /* TDLS channel switch data */ @@ -1398,6 +1400,11 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm); struct iwl_mcc_update_resp * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2); int iwl_mvm_init_mcc(struct iwl_mvm *mvm); +int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd); +struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, + const char *alpha2); /* smart fifo */ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 907e231f2c5c..b88b4cd07a22 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -689,6 +689,30 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) * unknown-country "99" code. This will also clear the "custom reg" * flag and allow regdomain changes. It will happen after init since * RTNL is required. + * Disallow scans that might crash the FW while the LAR regdomain + * is not set. */ - return regulatory_hint(mvm->hw->wiphy, "99"); + mvm->lar_regdom_set = false; + return 0; +} + +int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb, + struct iwl_device_cmd *cmd) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_mcc_chub_notif *notif = (void *)pkt->data; + char mcc[3]; + + if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) + return -EOPNOTSUPP; + + mcc[0] = notif->mcc >> 8; + mcc[1] = notif->mcc & 0xff; + mcc[2] = '\0'; + + IWL_DEBUG_LAR(mvm, + "RX: received chub update mcc command (mcc 0x%x '%s')\n", + notif->mcc, mcc); + return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 72b8e19004c4..1072f45720d6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -234,6 +234,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { iwl_mvm_rx_ant_coupling_notif, true), RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), + RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, false), RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false), From 162ee3c9a81556316e22305e455166e470fbb2b2 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Tue, 10 Jun 2014 11:25:35 +0300 Subject: [PATCH 020/567] iwlwifi: nvm: init correct nvm channel list for 8000 devices Otherwise the regulatory data will mistakenly contain only 7000 series channels. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 7 ++++--- drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | 4 ++-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 88703778dbb2..5959329e83c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -709,12 +709,13 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan, } struct ieee80211_regdomain * -iwl_parse_nvm_mcc_info(struct device *dev, int num_of_ch, __le32 *channels, - u16 fw_mcc) +iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, + int num_of_ch, __le32 *channels, u16 fw_mcc) { int ch_idx; u16 ch_flags, prev_ch_flags = 0; - const u8 *nvm_chan = iwl_nvm_channels; /* TODO: 8000 series differs */ + const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? + iwl_nvm_channels_family_8000 : iwl_nvm_channels; struct ieee80211_regdomain *regd; int size_of_regd; struct ieee80211_reg_rule *rule; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index c2fa930a9892..1b3990d15dc1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h @@ -90,7 +90,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, * the regdomain returned here with kfree. */ struct ieee80211_regdomain * -iwl_parse_nvm_mcc_info(struct device *dev, int num_of_ch, __le32 *channels, - u16 fw_mcc); +iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, + int num_of_ch, __le32 *channels, u16 fw_mcc); #endif /* __iwl_nvm_parse_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 0da8787aa25b..5dc3a9492d9a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -325,7 +325,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, goto out_unlock; } - regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, + regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg, __le32_to_cpu(resp->n_channels), resp->channels, __le16_to_cpu(resp->mcc)); From b281c93d23cdc3e44fcd3f36548689add4c06543 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Thu, 26 Jun 2014 11:10:57 +0300 Subject: [PATCH 021/567] iwlwifi: change last 5ghz channel to 165 & add support for 8000 family Fix the last 5ghz channel to 165 instead of 161 Add support for 8000 family, until channel 181. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 24 ++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 5959329e83c9..727e8a428903 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -146,7 +146,8 @@ static const u8 iwl_nvm_channels_family_8000[] = { #define NUM_2GHZ_CHANNELS_FAMILY_8000 14 #define FIRST_2GHZ_HT_MINUS 5 #define LAST_2GHZ_HT_PLUS 9 -#define LAST_5GHZ_HT 161 +#define LAST_5GHZ_HT 165 +#define LAST_5GHZ_HT_FAMILY_8000 181 /* rate data (static) */ static struct ieee80211_rate iwl_cfg80211_rates[] = { @@ -202,16 +203,20 @@ enum iwl_nvm_channel_flags { ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "") static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, - u16 nvm_flags) + u16 nvm_flags, const struct iwl_cfg *cfg) { u32 flags = IEEE80211_CHAN_NO_HT40; + u32 last_5ghz_ht = LAST_5GHZ_HT; + + if (cfg->device_family == IWL_DEVICE_FAMILY_8000) + last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000; if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) { if (ch_num <= LAST_2GHZ_HT_PLUS) flags &= ~IEEE80211_CHAN_NO_HT40PLUS; if (ch_num >= FIRST_2GHZ_HT_MINUS) flags &= ~IEEE80211_CHAN_NO_HT40MINUS; - } else if (ch_num <= LAST_5GHZ_HT && (nvm_flags & NVM_CHANNEL_40MHZ)) { + } else if (ch_num <= last_5ghz_ht && (nvm_flags & NVM_CHANNEL_40MHZ)) { if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) flags &= ~IEEE80211_CHAN_NO_HT40PLUS; else @@ -312,7 +317,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, if (!lar_supported) channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx], ch_idx, is_5ghz, - ch_flags); + ch_flags, cfg); else channel->flags = 0; @@ -666,9 +671,14 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan, - int ch_idx, u16 nvm_flags) + int ch_idx, u16 nvm_flags, + const struct iwl_cfg *cfg) { u32 flags = NL80211_RRF_NO_HT40; + u32 last_5ghz_ht = LAST_5GHZ_HT; + + if (cfg->device_family == IWL_DEVICE_FAMILY_8000) + last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000; if (ch_idx < NUM_2GHZ_CHANNELS && (nvm_flags & NVM_CHANNEL_40MHZ)) { @@ -676,7 +686,7 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan, flags &= ~NL80211_RRF_NO_HT40PLUS; if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) flags &= ~NL80211_RRF_NO_HT40MINUS; - } else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT && + } else if (nvm_chan[ch_idx] <= last_5ghz_ht && (nvm_flags & NVM_CHANNEL_40MHZ)) { if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) flags &= ~NL80211_RRF_NO_HT40PLUS; @@ -777,7 +787,7 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, rule->power_rule.max_eirp = DBM_TO_MBM(20); rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, - ch_flags); + ch_flags, cfg); /* rely on auto-calculation to merge BW of contiguous chans */ rule->flags |= NL80211_RRF_AUTO_BW; From 02a50495dec111c68d82ecf3ac1e00224e880790 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 7 Sep 2014 17:45:11 +0300 Subject: [PATCH 022/567] iwlwifi: use IWL_DEFAULT_MAX_TX_POWER for max_eirp max_eirp affects the txpower configured to the power, so use the max tx power (22) instead of some other value. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 727e8a428903..83ba307f0618 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -784,7 +784,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, /* this doesn't matter - not used by FW */ rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); - rule->power_rule.max_eirp = DBM_TO_MBM(20); + rule->power_rule.max_eirp = + DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER); rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, ch_flags, cfg); From d0d151973626eec3b8651311bdec209ba9050869 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Thu, 31 Jul 2014 09:16:25 +0300 Subject: [PATCH 023/567] iwlwifi: iwlmvm: LAR: disable LAR support due to NVM vs TLV conflict If LAR is supported in TLV, but the NVM does not enable it, then disable LAR support and ignore the TLV's bit that enabled LAR. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h | 1 + drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 15 ++++++++++++--- drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 12 +++++++++++- drivers/net/wireless/iwlwifi/mvm/nvm.c | 17 ++++++++++++++++- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h index f0548b8a64b0..5234a0bf11e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h @@ -94,6 +94,7 @@ struct iwl_nvm_data { u32 nvm_version; s8 max_tx_pwr_half_dbm; + bool lar_enabled; struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; struct ieee80211_channel channels[]; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 83ba307f0618..88ee84cbd7d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -105,6 +105,8 @@ enum family_8000_nvm_offsets { /* NVM REGULATORY -Section offset (in words) definitions */ NVM_CHANNELS_FAMILY_8000 = 0, + NVM_LAR_OFFSET_FAMILY_8000 = 0x4C7, + NVM_LAR_ENABLED_FAMILY_8000 = 0x7, /* NVM calibration section offset (in words) definitions */ NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8, @@ -597,11 +599,12 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, u8 tx_chains, u8 rx_chains, - bool lar_supported) + bool lar_fw_supported) { struct iwl_nvm_data *data; u32 sku; u32 radio_cfg; + u16 lar_config; if (cfg->device_family != IWL_DEVICE_FAMILY_8000) data = kzalloc(sizeof(*data) + @@ -653,15 +656,21 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, - rx_chains, lar_supported); + rx_chains, lar_fw_supported); } else { + lar_config = le16_to_cpup(regulatory + + NVM_LAR_OFFSET_FAMILY_8000); + data->lar_enabled = !!(lar_config & + NVM_LAR_ENABLED_FAMILY_8000); + /* MAC address in family 8000 */ iwl_set_hw_address_family_8000(dev, cfg, data, mac_override, nvm_hw); iwl_init_sbands(dev, cfg, data, regulatory, sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, - rx_chains, lar_supported); + rx_chains, lar_fw_supported && + data->lar_enabled); } data->calib_version = 255; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index 1b3990d15dc1..c950c142ba0f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h @@ -78,7 +78,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, u8 tx_chains, u8 rx_chains, - bool lar_supported); + bool lar_fw_supported); /** * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index df5a2286b409..a196c7859086 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -914,7 +914,17 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) { - return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_LAR_SUPPORT; + bool nvm_lar = mvm->nvm_data->lar_enabled; + bool tlv_lar = mvm->fw->ucode_capa.capa[0] & + IWL_UCODE_TLV_CAPA_LAR_SUPPORT; + /* + * Enable LAR only if it is supported by the FW (TLV) && + * enabled in the NVM + */ + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) + return nvm_lar && tlv_lar; + else + return tlv_lar; } static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index b88b4cd07a22..1c699c9aaad3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -303,7 +303,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) regulatory, mac_override, mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, - iwl_mvm_is_lar_supported(mvm)); + mvm->fw->ucode_capa.capa[0] & + IWL_UCODE_TLV_CAPA_LAR_SUPPORT); } #define MAX_NVM_FILE_LEN 16384 @@ -659,6 +660,20 @@ exit: int iwl_mvm_init_mcc(struct iwl_mvm *mvm) { + bool tlv_lar; + bool nvm_lar; + + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + tlv_lar = mvm->fw->ucode_capa.capa[0] & + IWL_UCODE_TLV_CAPA_LAR_SUPPORT; + nvm_lar = mvm->nvm_data->lar_enabled; + if (tlv_lar != nvm_lar) + IWL_INFO(mvm, + "Conflict between TLV & NVM regarding enabling LAR (TLV = %s NVM =%s)\n", + tlv_lar ? "enabled" : "disabled", + nvm_lar ? "enabled" : "disabled"); + } + if (!iwl_mvm_is_lar_supported(mvm)) return 0; From 2926f9589b6cbcb6f0b2d02e9102e1842a9c8fc1 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 23 Oct 2014 16:29:10 +0300 Subject: [PATCH 024/567] iwlwifi: disable 11ac if 11n is disabled 11ac depends on 11n, so disable it if 11n is disabled. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 88ee84cbd7d5..bca4582f4e73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -396,7 +396,7 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, - const __le16 *ch_section, bool enable_vht, + const __le16 *ch_section, u8 tx_chains, u8 rx_chains, bool lar_supported) { int n_channels; @@ -430,7 +430,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, IEEE80211_BAND_5GHZ); iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ, tx_chains, rx_chains); - if (enable_vht) + if (data->sku_cap_11ac_enable) iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap, tx_chains, rx_chains); @@ -632,9 +632,10 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; - data->sku_cap_11ac_enable = sku & NVM_SKU_CAP_11AC_ENABLE; if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) data->sku_cap_11n_enable = false; + data->sku_cap_11ac_enable = data->sku_cap_11n_enable && + (sku & NVM_SKU_CAP_11AC_ENABLE); data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); @@ -655,8 +656,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, iwl_set_hw_address(cfg, data, nvm_hw); iwl_init_sbands(dev, cfg, data, nvm_sw, - sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, - rx_chains, lar_fw_supported); + tx_chains, rx_chains, lar_fw_supported); } else { lar_config = le16_to_cpup(regulatory + NVM_LAR_OFFSET_FAMILY_8000); @@ -668,9 +668,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, nvm_hw); iwl_init_sbands(dev, cfg, data, regulatory, - sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains, - rx_chains, lar_fw_supported && - data->lar_enabled); + tx_chains, rx_chains, + lar_fw_supported && data->lar_enabled); } data->calib_version = 255; From ce5000710bd80b87917875897d74167a0a07b342 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Mon, 1 Dec 2014 17:53:53 +0200 Subject: [PATCH 025/567] iwlwifi: mvm: support new PHY_SKU nvm section for family 8000 B0 Starting from family 8000 B0 step the radio_cfg parameters and the get_sku parameters moved from SW section to PHY_SKU section. Signed-off-by: Eran Harary Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 49 +++++++++++++++----- drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | 5 +- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 3 +- drivers/net/wireless/iwlwifi/mvm/nvm.c | 20 ++++++-- 4 files changed, 60 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index bca4582f4e73..d9423eda6ad9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -103,6 +103,11 @@ enum family_8000_nvm_offsets { SKU_FAMILY_8000 = 4, N_HW_ADDRS_FAMILY_8000 = 5, + /* NVM PHY-SKU-Section offset (in words) for B0 */ + RADIO_CFG_FAMILY_8000_B0 = 0, + SKU_FAMILY_8000_B0 = 2, + N_HW_ADDRS_FAMILY_8000_B0 = 3, + /* NVM REGULATORY -Section offset (in words) definitions */ NVM_CHANNELS_FAMILY_8000 = 0, NVM_LAR_OFFSET_FAMILY_8000 = 0x4C7, @@ -150,6 +155,7 @@ static const u8 iwl_nvm_channels_family_8000[] = { #define LAST_2GHZ_HT_PLUS 9 #define LAST_5GHZ_HT 165 #define LAST_5GHZ_HT_FAMILY_8000 181 +#define N_HW_ADDR_MASK 0xF /* rate data (static) */ static struct ieee80211_rate iwl_cfg80211_rates[] = { @@ -440,10 +446,15 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, } static int iwl_get_sku(const struct iwl_cfg *cfg, - const __le16 *nvm_sw) + const __le16 *nvm_sw, const __le16 *phy_sku, + bool is_family_8000_a_step) { if (cfg->device_family != IWL_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + SKU); + + if (!is_family_8000_a_step) + return le32_to_cpup((__le32 *)(phy_sku + + SKU_FAMILY_8000_B0)); else return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000)); } @@ -459,23 +470,36 @@ static int iwl_get_nvm_version(const struct iwl_cfg *cfg, } static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, - const __le16 *nvm_sw) + const __le16 *nvm_sw, const __le16 *phy_sku, + bool is_family_8000_a_step) { if (cfg->device_family != IWL_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + RADIO_CFG); + + if (!is_family_8000_a_step) + return le32_to_cpup((__le32 *)(phy_sku + + RADIO_CFG_FAMILY_8000_B0)); else return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000)); + } -#define N_HW_ADDRS_MASK_FAMILY_8000 0xF static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, - const __le16 *nvm_sw) + const __le16 *nvm_sw, bool is_family_8000_a_step) { + int n_hw_addr; + if (cfg->device_family != IWL_DEVICE_FAMILY_8000) return le16_to_cpup(nvm_sw + N_HW_ADDRS); + + if (!is_family_8000_a_step) + n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + + N_HW_ADDRS_FAMILY_8000_B0)); else - return le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)) - & N_HW_ADDRS_MASK_FAMILY_8000; + n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + + N_HW_ADDRS_FAMILY_8000)); + + return n_hw_addr & N_HW_ADDR_MASK; } static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, @@ -598,8 +622,9 @@ struct iwl_nvm_data * iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, - const __le16 *mac_override, u8 tx_chains, u8 rx_chains, - bool lar_fw_supported) + const __le16 *mac_override, const __le16 *phy_sku, + u8 tx_chains, u8 rx_chains, + bool lar_fw_supported, bool is_family_8000_a_step) { struct iwl_nvm_data *data; u32 sku; @@ -621,14 +646,15 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw); - radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw); + radio_cfg = + iwl_get_radio_cfg(cfg, nvm_sw, phy_sku, is_family_8000_a_step); iwl_set_radio_cfg(cfg, data, radio_cfg); if (data->valid_tx_ant) tx_chains &= data->valid_tx_ant; if (data->valid_rx_ant) rx_chains &= data->valid_rx_ant; - sku = iwl_get_sku(cfg, nvm_sw); + sku = iwl_get_sku(cfg, nvm_sw, phy_sku, is_family_8000_a_step); data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; @@ -637,7 +663,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, data->sku_cap_11ac_enable = data->sku_cap_11n_enable && (sku & NVM_SKU_CAP_11AC_ENABLE); - data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); + data->n_hw_addrs = + iwl_get_n_hw_addrs(cfg, nvm_sw, is_family_8000_a_step); if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { /* Checking for required sections */ diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index c950c142ba0f..18c3ff2c5593 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h @@ -77,8 +77,9 @@ struct iwl_nvm_data * iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, - const __le16 *mac_override, u8 tx_chains, u8 rx_chains, - bool lar_fw_supported); + const __le16 *mac_override, const __le16 *phy_sku, + u8 tx_chains, u8 rx_chains, + bool lar_fw_supported, bool is_family_8000_a_step); /** * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index c4b59ecb3606..f514fae017d1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -366,7 +366,8 @@ enum { NVM_SECTION_TYPE_CALIBRATION = 4, NVM_SECTION_TYPE_PRODUCTION = 5, NVM_SECTION_TYPE_MAC_OVERRIDE = 11, - NVM_MAX_NUM_SECTIONS = 12, + NVM_SECTION_TYPE_PHY_SKU = 12, + NVM_MAX_NUM_SECTIONS = 13, }; /** diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 1c699c9aaad3..eb40c89624d3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -263,7 +263,8 @@ static struct iwl_nvm_data * iwl_parse_nvm_sections(struct iwl_mvm *mvm) { struct iwl_nvm_section *sections = mvm->nvm_sections; - const __le16 *hw, *sw, *calib, *regulatory, *mac_override; + const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; + bool is_family_8000_a_step = false; /* Checking for required sections */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { @@ -287,6 +288,17 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) "Can't parse mac_address, empty sections\n"); return NULL; } + + if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) + is_family_8000_a_step = true; + + /* PHY_SKU section is mandatory in B0 */ + if (!is_family_8000_a_step && + !mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) { + IWL_ERR(mvm, + "Can't parse phy_sku in B0, empty sections\n"); + return NULL; + } } if (WARN_ON(!mvm->cfg)) @@ -298,13 +310,15 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; mac_override = (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data; + phy_sku = (const __le16 *)sections[NVM_SECTION_TYPE_PHY_SKU].data; return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, - regulatory, mac_override, + regulatory, mac_override, phy_sku, mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, mvm->fw->ucode_capa.capa[0] & - IWL_UCODE_TLV_CAPA_LAR_SUPPORT); + IWL_UCODE_TLV_CAPA_LAR_SUPPORT, + is_family_8000_a_step); } #define MAX_NVM_FILE_LEN 16384 From 5711cac489d06cc9c3cdcd513c810b7148beb49d Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 28 Dec 2014 09:23:16 +0200 Subject: [PATCH 026/567] iwlwifi: allow disabling LAR via module param This module parameter is useful for debugging NVM and LAR related issues. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-modparams.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 ++++ drivers/net/wireless/iwlwifi/mvm/nvm.c | 13 +++++++------ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 141331d41abf..f1d73d5e6eff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1546,6 +1546,10 @@ module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable, bool, S_IRUGO); MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)"); +module_param_named(lar_disable, iwlwifi_mod_params.lar_disable, + bool, S_IRUGO); +MODULE_PARM_DESC(lar_disable, "disable LAR functionality (default: N)"); + module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, bool, S_IRUGO | S_IWUSR); #ifdef CONFIG_IWLWIFI_UAPSD diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index e8eabd21ccfe..ac2b90df8413 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -103,6 +103,7 @@ enum iwl_disable_11n { * @debug_level: levels are IWL_DL_* * @ant_coupling: antenna coupling in dB, default = 0 * @d0i3_disable: disable d0i3, default = 1, + * @lar_disable: disable LAR (regulatory), default = 0 * @fw_monitor: allow to use firmware monitor */ struct iwl_mod_params { @@ -121,6 +122,7 @@ struct iwl_mod_params { char *nvm_file; bool uapsd_disable; bool d0i3_disable; + bool lar_disable; bool fw_monitor; }; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index a196c7859086..207c3a847ed4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -917,6 +917,10 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) bool nvm_lar = mvm->nvm_data->lar_enabled; bool tlv_lar = mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_LAR_SUPPORT; + + if (iwlwifi_mod_params.lar_disable) + return false; + /* * Enable LAR only if it is supported by the FW (TLV) && * enabled in the NVM diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index eb40c89624d3..5a16e0d79352 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -264,7 +264,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) { struct iwl_nvm_section *sections = mvm->nvm_sections; const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; - bool is_family_8000_a_step = false; + bool is_family_8000_a_step = false, lar_enabled; /* Checking for required sections */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { @@ -312,13 +312,14 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) (const __le16 *)sections[NVM_SECTION_TYPE_MAC_OVERRIDE].data; phy_sku = (const __le16 *)sections[NVM_SECTION_TYPE_PHY_SKU].data; + lar_enabled = !iwlwifi_mod_params.lar_disable && + (mvm->fw->ucode_capa.capa[0] & + IWL_UCODE_TLV_CAPA_LAR_SUPPORT); + return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, regulatory, mac_override, phy_sku, - mvm->fw->valid_tx_ant, - mvm->fw->valid_rx_ant, - mvm->fw->ucode_capa.capa[0] & - IWL_UCODE_TLV_CAPA_LAR_SUPPORT, - is_family_8000_a_step); + mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, + lar_enabled, is_family_8000_a_step); } #define MAX_NVM_FILE_LEN 16384 From 8ba2d7a1dd5defd7a9cbc400004cc112fc9ff3b5 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Sun, 8 Feb 2015 11:41:43 +0200 Subject: [PATCH 027/567] iwlwifi: mvm: take the MAC address from HW registers For some configurations, the driver should get the MAC address from the hardware registers and not from the regular locations. Since the parsing of the MAC address is the same regardless of its source, continue the regular code path (parsing) after we read the registers. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 + drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 57 ++----- drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | 3 +- drivers/net/wireless/iwlwifi/iwl-prph.h | 8 + drivers/net/wireless/iwlwifi/mvm/fw-api.h | 150 +++++++++++-------- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 73 +++++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 14 +- drivers/net/wireless/iwlwifi/mvm/nvm.c | 79 +++++----- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- 9 files changed, 223 insertions(+), 165 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 5ea381861d5d..81c2f4875d30 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -244,6 +244,7 @@ enum iwl_ucode_tlv_flag { * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. + * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, * regardless of the band or the number of the probes. FW will calculate @@ -261,6 +262,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), + IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9), IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10), IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), IWL_UCODE_TLV_API_SCD_CFG = BIT(15), diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index d9423eda6ad9..54e447b9978c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -542,7 +542,8 @@ static void iwl_set_hw_address_family_8000(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *mac_override, - const __le16 *nvm_hw) + const __le16 *nvm_hw, + u32 mac_addr0, u32 mac_addr1) { const u8 *hw_addr; @@ -566,48 +567,17 @@ static void iwl_set_hw_address_family_8000(struct device *dev, } if (nvm_hw) { - /* read the MAC address from OTP */ - if (!dev_is_pci(dev) || (data->nvm_version < 0xE08)) { - /* read the mac address from the WFPM location */ - hw_addr = (const u8 *)(nvm_hw + - HW_ADDR0_WFPM_FAMILY_8000); - data->hw_addr[0] = hw_addr[3]; - data->hw_addr[1] = hw_addr[2]; - data->hw_addr[2] = hw_addr[1]; - data->hw_addr[3] = hw_addr[0]; + /* read the MAC address from HW resisters */ + hw_addr = (const u8 *)&mac_addr0; + data->hw_addr[0] = hw_addr[3]; + data->hw_addr[1] = hw_addr[2]; + data->hw_addr[2] = hw_addr[1]; + data->hw_addr[3] = hw_addr[0]; - hw_addr = (const u8 *)(nvm_hw + - HW_ADDR1_WFPM_FAMILY_8000); - data->hw_addr[4] = hw_addr[1]; - data->hw_addr[5] = hw_addr[0]; - } else if ((data->nvm_version >= 0xE08) && - (data->nvm_version < 0xE0B)) { - /* read "reverse order" from the PCIe location */ - hw_addr = (const u8 *)(nvm_hw + - HW_ADDR0_PCIE_FAMILY_8000); - data->hw_addr[5] = hw_addr[2]; - data->hw_addr[4] = hw_addr[1]; - data->hw_addr[3] = hw_addr[0]; + hw_addr = (const u8 *)&mac_addr1; + data->hw_addr[4] = hw_addr[1]; + data->hw_addr[5] = hw_addr[0]; - hw_addr = (const u8 *)(nvm_hw + - HW_ADDR1_PCIE_FAMILY_8000); - data->hw_addr[2] = hw_addr[3]; - data->hw_addr[1] = hw_addr[2]; - data->hw_addr[0] = hw_addr[1]; - } else { - /* read from the PCIe location */ - hw_addr = (const u8 *)(nvm_hw + - HW_ADDR0_PCIE_FAMILY_8000); - data->hw_addr[5] = hw_addr[0]; - data->hw_addr[4] = hw_addr[1]; - data->hw_addr[3] = hw_addr[2]; - - hw_addr = (const u8 *)(nvm_hw + - HW_ADDR1_PCIE_FAMILY_8000); - data->hw_addr[2] = hw_addr[1]; - data->hw_addr[1] = hw_addr[2]; - data->hw_addr[0] = hw_addr[3]; - } if (!is_valid_ether_addr(data->hw_addr)) IWL_ERR_DEV(dev, "mac address from hw section is not valid\n"); @@ -624,7 +594,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, u8 tx_chains, u8 rx_chains, - bool lar_fw_supported, bool is_family_8000_a_step) + bool lar_fw_supported, bool is_family_8000_a_step, + u32 mac_addr0, u32 mac_addr1) { struct iwl_nvm_data *data; u32 sku; @@ -692,7 +663,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, /* MAC address in family 8000 */ iwl_set_hw_address_family_8000(dev, cfg, data, mac_override, - nvm_hw); + nvm_hw, mac_addr0, mac_addr1); iwl_init_sbands(dev, cfg, data, regulatory, tx_chains, rx_chains, diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index 18c3ff2c5593..c995d2cee3f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h @@ -79,7 +79,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, u8 tx_chains, u8 rx_chains, - bool lar_fw_supported, bool is_family_8000_a_step); + bool lar_fw_supported, bool is_family_8000_a_step, + u32 mac_addr0, u32 mac_addr1); /** * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 6095088b88d9..383af2749d9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -371,6 +371,14 @@ enum secure_load_status_reg { #define DBGC_IN_SAMPLE (0xa03c00) +/* enable the ID buf for read */ +#define WFPM_PS_CTL_CLR 0xA0300C +#define WFMP_MAC_ADDR_0 0xA03080 +#define WFMP_MAC_ADDR_1 0xA03084 +#define LMPM_PMG_EN 0xA01CEC +#define RADIO_REG_SYS_MANUAL_DFT_0 0xAD4078 +#define RFIC_REG_RD 0xAD0470 + /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 enum { diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index f514fae017d1..7e4936585544 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -1478,6 +1478,92 @@ struct iwl_sf_cfg_cmd { __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; } __packed; /* SF_CFG_API_S_VER_2 */ +/*********************************** + * Location Aware Regulatory (LAR) API - MCC updates + ***********************************/ + +/** + * struct iwl_mcc_update_cmd - Request the device to update geographic + * regulatory profile according to the given MCC (Mobile Country Code). + * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. + * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the + * MCC in the cmd response will be the relevant MCC in the NVM. + * @mcc: given mobile country code + * @source_id: the source from where we got the MCC, see iwl_mcc_source + * @reserved: reserved for alignment + */ +struct iwl_mcc_update_cmd { + __le16 mcc; + u8 source_id; + u8 reserved; +} __packed; /* LAR_UPDATE_MCC_CMD_API_S */ + +/** + * iwl_mcc_update_resp - response to MCC_UPDATE_CMD. + * Contains the new channel control profile map, if changed, and the new MCC + * (mobile country code). + * The new MCC may be different than what was requested in MCC_UPDATE_CMD. + * @status: 0 for success, 1 no change in channel profile, 2 invalid input. + * @mcc: the new applied MCC + * @cap: capabilities for all channels which matches the MCC + * @source_id: the MCC source, see iwl_mcc_source + * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 + * channels, depending on platform) + * @channels: channel control data map, DWORD for each channel. Only the first + * 16bits are used. + */ +struct iwl_mcc_update_resp { + __le32 status; + __le16 mcc; + u8 cap; + u8 source_id; + __le32 n_channels; + __le32 channels[0]; +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */ + +/** + * struct iwl_mcc_chub_notif - chub notifies of mcc change + * (MCC_CHUB_UPDATE_CMD = 0xc9) + * The Chub (Communication Hub, CommsHUB) is a HW component that connects to + * the cellular and connectivity cores that gets updates of the mcc, and + * notifies the ucode directly of any mcc change. + * The ucode requests the driver to request the device to update geographic + * regulatory profile according to the given MCC (Mobile Country Code). + * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. + * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the + * MCC in the cmd response will be the relevant MCC in the NVM. + * @mcc: given mobile country code + * @source_id: identity of the change originator, see iwl_mcc_source + * @reserved1: reserved for alignment + */ +struct iwl_mcc_chub_notif { + u16 mcc; + u8 source_id; + u8 reserved1; +} __packed; /* LAR_MCC_NOTIFY_S */ + +enum iwl_mcc_update_status { + MCC_RESP_NEW_CHAN_PROFILE, + MCC_RESP_SAME_CHAN_PROFILE, + MCC_RESP_INVALID, + MCC_RESP_NVM_DISABLED, + MCC_RESP_ILLEGAL, + MCC_RESP_LOW_PRIORITY, +}; + +enum iwl_mcc_source { + MCC_SOURCE_OLD_FW = 0, + MCC_SOURCE_ME = 1, + MCC_SOURCE_BIOS = 2, + MCC_SOURCE_3G_LTE_HOST = 3, + MCC_SOURCE_3G_LTE_DEVICE = 4, + MCC_SOURCE_WIFI = 5, + MCC_SOURCE_RESERVED = 6, + MCC_SOURCE_DEFAULT = 7, + MCC_SOURCE_UNINITIALIZED = 8, + MCC_SOURCE_GET_CURRENT = 0x10 +}; + /* DTS measurements */ enum iwl_dts_measurement_flags { @@ -1679,68 +1765,4 @@ struct iwl_shared_mem_cfg { __le32 page_buff_size; } __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */ -/*********************************** - * Location Aware Regulatory (LAR) API - MCC updates - ***********************************/ - -/** - * struct iwl_mcc_update_cmd - Request the device to update geographic - * regulatory profile according to the given MCC (Mobile Country Code). - * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. - * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the - * MCC in the cmd response will be the relevant MCC in the NVM. - * @mcc: given mobile country code - * @reserved: reserved for alignment - */ -struct iwl_mcc_update_cmd { - __le16 mcc; - __le16 reserved; -} __packed; /* LAR_UPDATE_MCC_CMD_API_S */ - -/** - * iwl_mcc_update_resp - response to MCC_UPDATE_CMD. - * Contains the new channel control profile map, if changed, and the new MCC - * (mobile country code). - * The new MCC may be different than what was requested in MCC_UPDATE_CMD. - * @status: 0 for success, 1 no change in channel profile, 2 invalid input. - * @mcc: the new applied MCC - * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 - * channels, depending on platform) - * @channels: channel control data map, DWORD for each channel. Only the first - * 16bits are used. - */ -struct iwl_mcc_update_resp { - __le32 status; - __le16 mcc; - __le16 reserved; - __le32 n_channels; - __le32 channels[0]; -} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S */ - -/** - * struct iwl_mcc_chub_notif - chub notifies of mcc change - * (MCC_CHUB_UPDATE_CMD = 0xc9) - * The Chub (Communication Hub, CommsHUB) is a HW component that connects to - * the cellular and connectivity cores that gets updates of the mcc, and - * notifies the ucode directly of any mcc change. - * The ucode requests the driver to request the device to update geographic - * regulatory profile according to the given MCC (Mobile Country Code). - * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. - * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the - * MCC in the cmd response will be the relevant MCC in the NVM. - * @mcc: given mobile country code - * @reserved: reserved for alignment - */ -struct iwl_mcc_chub_notif { - u16 mcc; - u16 reserved1; -} __packed; /* LAR_MCC_NOTIFY_S */ - -enum iwl_mcc_update_status { - MCC_RESP_NEW_CHAN_PROFILE, - MCC_RESP_SAME_CHAN_PROFILE, - MCC_RESP_INVALID, - MCC_RESP_NVM_DISABLED, -}; - #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 5dc3a9492d9a..303a7a0c6498 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -303,7 +303,8 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) } struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, - const char *alpha2) + const char *alpha2, + enum iwl_mcc_source src_id) { struct ieee80211_regdomain *regd = NULL; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); @@ -312,39 +313,75 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2); - mutex_lock(&mvm->mutex); + lockdep_assert_held(&mvm->mutex); - /* change "99" to "ZZ" for the FW */ - if (alpha2[0] == '9' && alpha2[1] == '9') - alpha2 = "ZZ"; - - resp = iwl_mvm_update_mcc(mvm, alpha2); + resp = iwl_mvm_update_mcc(mvm, alpha2, src_id); if (IS_ERR_OR_NULL(resp)) { IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n", PTR_RET(resp)); - goto out_unlock; + goto out; } regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg, __le32_to_cpu(resp->n_channels), resp->channels, __le16_to_cpu(resp->mcc)); + /* Store the return source id */ + src_id = resp->source_id; kfree(resp); if (IS_ERR_OR_NULL(regd)) { IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n", - PTR_RET(resp)); - goto out_unlock; + PTR_RET(regd)); + goto out; } - IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x)\n", - regd->alpha2, regd->alpha2[0], regd->alpha2[1]); + IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x) src=%d\n", + regd->alpha2, regd->alpha2[0], regd->alpha2[1], src_id); mvm->lar_regdom_set = true; + mvm->mcc_src = src_id; -out_unlock: - mutex_unlock(&mvm->mutex); +out: return regd; } +struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm) +{ + return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ", + iwl_mvm_is_wifi_mcc_supported(mvm) ? + MCC_SOURCE_GET_CURRENT : + MCC_SOURCE_OLD_FW); +} + +int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) +{ + enum iwl_mcc_source used_src; + struct ieee80211_regdomain *regd; + const struct ieee80211_regdomain *r = + rtnl_dereference(mvm->hw->wiphy->regd); + + if (!r) + return 0; + + /* save the last source in case we overwrite it below */ + used_src = mvm->mcc_src; + if (iwl_mvm_is_wifi_mcc_supported(mvm)) { + /* Notify the firmware we support wifi location updates */ + regd = iwl_mvm_get_current_regdomain(mvm); + if (!IS_ERR_OR_NULL(regd)) + kfree(regd); + } + + /* Now set our last stored MCC and source */ + regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src); + if (IS_ERR_OR_NULL(regd)) + return -EIO; + + regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); + kfree(regd); + + return 0; +} + int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) { struct ieee80211_hw *hw = mvm->hw; @@ -400,8 +437,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; - hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | - REGULATORY_DISABLE_BEACON_HINTS; + hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR; + if (iwl_mvm_is_lar_supported(mvm)) + hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; + else + hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | + REGULATORY_DISABLE_BEACON_HINTS; if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 207c3a847ed4..5d5be372593a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -811,6 +811,7 @@ struct iwl_mvm { u32 ap_last_beacon_gp2; bool lar_regdom_set; + enum iwl_mcc_source mcc_src; u8 low_latency_agg_frame_limit; @@ -931,6 +932,11 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) return tlv_lar; } +static inline bool iwl_mvm_is_wifi_mcc_supported(struct iwl_mvm *mvm) +{ + return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WIFI_MCC_UPDATE; +} + static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm) { return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG; @@ -1412,13 +1418,17 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm); /* Location Aware Regulatory */ struct iwl_mcc_update_resp * -iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2); +iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, + enum iwl_mcc_source src_id); int iwl_mvm_init_mcc(struct iwl_mvm *mvm); int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, - const char *alpha2); + const char *alpha2, + enum iwl_mcc_source src_id); +struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm); +int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm); /* smart fifo */ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 5a16e0d79352..41189e5e98df 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -70,6 +70,7 @@ #include "iwl-eeprom-parse.h" #include "iwl-eeprom-read.h" #include "iwl-nvm-parse.h" +#include "iwl-prph.h" /* Default NVM size to read */ #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) @@ -265,6 +266,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) struct iwl_nvm_section *sections = mvm->nvm_sections; const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; bool is_family_8000_a_step = false, lar_enabled; + u32 mac_addr0, mac_addr1; /* Checking for required sections */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { @@ -304,6 +306,10 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) if (WARN_ON(!mvm->cfg)) return NULL; + /* read the mac address from WFMP registers */ + mac_addr0 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_0); + mac_addr1 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_1); + hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; @@ -319,7 +325,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, regulatory, mac_override, phy_sku, mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, - lar_enabled, is_family_8000_a_step); + lar_enabled, is_family_8000_a_step, + mac_addr0, mac_addr1); } #define MAX_NVM_FILE_LEN 16384 @@ -590,10 +597,12 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) } struct iwl_mcc_update_resp * -iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2) +iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, + enum iwl_mcc_source src_id) { struct iwl_mcc_update_cmd mcc_update_cmd = { .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), + .source_id = (u8)src_id, }; struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL; struct iwl_rx_packet *pkt; @@ -613,8 +622,8 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2) cmd.len[0] = sizeof(struct iwl_mcc_update_cmd); - IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c'\n", - alpha2[0], alpha2[1]); + IWL_DEBUG_LAR(mvm, "send MCC update to FW with '%c%c' src = %d\n", + alpha2[0], alpha2[1], src_id); ret = iwl_mvm_send_cmd(mvm, &cmd); if (ret) @@ -632,18 +641,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2) mcc_resp = (void *)pkt->data; status = le32_to_cpu(mcc_resp->status); - if (status == MCC_RESP_INVALID) { - IWL_ERR(mvm, - "FW ERROR: MCC update with invalid parameter '%c%c'\n", - alpha2[0], alpha2[1]); - ret = -EINVAL; - goto exit; - } else if (status == MCC_RESP_NVM_DISABLED) { - ret = 0; - /* resp_cp will be NULL */ - goto exit; - } - mcc = le16_to_cpu(mcc_resp->mcc); /* W/A for a FW/NVM issue - returns 0x00 for the world domain */ @@ -677,6 +674,8 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) { bool tlv_lar; bool nvm_lar; + int retval; + struct ieee80211_regdomain *regd; if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) { tlv_lar = mvm->fw->ucode_capa.capa[0] & @@ -698,32 +697,24 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) */ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { /* This should only be called during vif up and hold RTNL */ - const struct ieee80211_regdomain *r = - rtnl_dereference(mvm->hw->wiphy->regd); - - if (r) { - struct iwl_mcc_update_resp *resp; - - resp = iwl_mvm_update_mcc(mvm, r->alpha2); - if (IS_ERR_OR_NULL(resp)) - return -EIO; - - kfree(resp); - } - - return 0; + return iwl_mvm_init_fw_regd(mvm); } /* - * Driver regulatory hint for initial update - use the special - * unknown-country "99" code. This will also clear the "custom reg" - * flag and allow regdomain changes. It will happen after init since - * RTNL is required. + * Driver regulatory hint for initial update, this also informs the + * firmware we support wifi location updates. * Disallow scans that might crash the FW while the LAR regdomain * is not set. */ mvm->lar_regdom_set = false; - return 0; + + regd = iwl_mvm_get_current_regdomain(mvm); + if (IS_ERR_OR_NULL(regd)) + return -EIO; + + retval = regulatory_set_wiphy_regd_sync_rtnl(mvm->hw->wiphy, regd); + kfree(regd); + return retval; } int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, @@ -732,17 +723,29 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mcc_chub_notif *notif = (void *)pkt->data; + enum iwl_mcc_source src; char mcc[3]; + struct ieee80211_regdomain *regd; + + lockdep_assert_held(&mvm->mutex); if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) - return -EOPNOTSUPP; + return 0; mcc[0] = notif->mcc >> 8; mcc[1] = notif->mcc & 0xff; mcc[2] = '\0'; + src = notif->source_id; IWL_DEBUG_LAR(mvm, - "RX: received chub update mcc command (mcc 0x%x '%s')\n", - notif->mcc, mcc); + "RX: received chub update mcc cmd (mcc '%s' src %d)\n", + mcc, src); + regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src); + if (IS_ERR_OR_NULL(regd)) + return 0; + + regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); + kfree(regd); + return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 1072f45720d6..c1de23cc07fd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -234,7 +234,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { iwl_mvm_rx_ant_coupling_notif, true), RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), - RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, false), + RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, true), RX_HANDLER(EOSP_NOTIFICATION, iwl_mvm_rx_eosp_notif, false), From 7f0344c218a6110cbdb7d0974984838e35a24b30 Mon Sep 17 00:00:00 2001 From: Jonathan Doron Date: Thu, 27 Nov 2014 16:57:55 +0200 Subject: [PATCH 028/567] iwlwifi: mvm: support LAR updates from BIOS When booting the card, check for a dedicated regulatory ACPI entry. If such exists, read it and give the information to FW with the appropriate source. Signed-off-by: Jonathan Doron Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/nvm.c | 103 +++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 41189e5e98df..d08ea695685f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -64,6 +64,8 @@ *****************************************************************************/ #include #include +#include +#include #include "iwl-trans.h" #include "iwl-csr.h" #include "mvm.h" @@ -670,12 +672,104 @@ exit: return resp_cp; } +#ifdef CONFIG_ACPI +#define WRD_METHOD "WRDD" +#define WRDD_WIFI (0x07) +#define WRDD_WIGIG (0x10) + +static u32 iwl_mvm_wrdd_get_mcc(struct iwl_mvm *mvm, union acpi_object *wrdd) +{ + union acpi_object *mcc_pkg, *domain_type, *mcc_value; + u32 i; + + if (wrdd->type != ACPI_TYPE_PACKAGE || + wrdd->package.count < 2 || + wrdd->package.elements[0].type != ACPI_TYPE_INTEGER || + wrdd->package.elements[0].integer.value != 0) { + IWL_DEBUG_LAR(mvm, "Unsupported wrdd structure\n"); + return 0; + } + + for (i = 1 ; i < wrdd->package.count ; ++i) { + mcc_pkg = &wrdd->package.elements[i]; + + if (mcc_pkg->type != ACPI_TYPE_PACKAGE || + mcc_pkg->package.count < 2 || + mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER || + mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { + mcc_pkg = NULL; + continue; + } + + domain_type = &mcc_pkg->package.elements[0]; + if (domain_type->integer.value == WRDD_WIFI) + break; + + mcc_pkg = NULL; + } + + if (mcc_pkg) { + mcc_value = &mcc_pkg->package.elements[1]; + return mcc_value->integer.value; + } + + return 0; +} + +static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc) +{ + acpi_handle root_handle; + acpi_handle handle; + struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + u32 mcc_val; + struct pci_dev *pdev = to_pci_dev(mvm->dev); + + root_handle = ACPI_HANDLE(&pdev->dev); + if (!root_handle) { + IWL_DEBUG_LAR(mvm, + "Could not retrieve root port ACPI handle\n"); + return -ENOENT; + } + + /* Get the method's handle */ + status = acpi_get_handle(root_handle, (acpi_string)WRD_METHOD, &handle); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_LAR(mvm, "WRD method not found\n"); + return -ENOENT; + } + + /* Call WRDD with no arguments */ + status = acpi_evaluate_object(handle, NULL, NULL, &wrdd); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_LAR(mvm, "WRDC invocation failed (0x%x)\n", status); + return -ENOENT; + } + + mcc_val = iwl_mvm_wrdd_get_mcc(mvm, wrdd.pointer); + kfree(wrdd.pointer); + if (!mcc_val) + return -ENOENT; + + mcc[0] = (mcc_val >> 8) & 0xff; + mcc[1] = mcc_val & 0xff; + mcc[2] = '\0'; + return 0; +} +#else /* CONFIG_ACPI */ +static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc) +{ + return -ENOENT; +} +#endif + int iwl_mvm_init_mcc(struct iwl_mvm *mvm) { bool tlv_lar; bool nvm_lar; int retval; struct ieee80211_regdomain *regd; + char mcc[3]; if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) { tlv_lar = mvm->fw->ucode_capa.capa[0] & @@ -712,6 +806,15 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) if (IS_ERR_OR_NULL(regd)) return -EIO; + if (iwl_mvm_is_wifi_mcc_supported(mvm) && + !iwl_mvm_get_bios_mcc(mvm, mcc)) { + kfree(regd); + regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, + MCC_SOURCE_BIOS); + if (IS_ERR_OR_NULL(regd)) + return -EIO; + } + retval = regulatory_set_wiphy_regd_sync_rtnl(mvm->hw->wiphy, regd); kfree(regd); return retval; From 47c8b154a7d080626dfd148397782a49d5212a88 Mon Sep 17 00:00:00 2001 From: Jonathan Doron Date: Thu, 27 Nov 2014 16:55:25 +0200 Subject: [PATCH 029/567] iwlwifi: mvm: set LAR MCC on D3/D0 transitions When moving to the D3 FW give it the valid MCC from the D0 FW. When returning from D3 to D0, query the D3 FW for the latest MCC, as it might have changed internally. This MCC will be replayed to the D0 FW when it boots. Signed-off-by: Jonathan Doron Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 9 ++++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 2 +- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 33 +++++++++++++++++---- drivers/net/wireless/iwlwifi/mvm/mvm.h | 7 +++-- drivers/net/wireless/iwlwifi/mvm/nvm.c | 8 ++--- drivers/net/wireless/iwlwifi/mvm/ops.c | 4 +++ 6 files changed, 51 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 9bdfa95d6ce7..486fd4c259c3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -694,6 +694,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (ret) IWL_ERR(mvm, "Failed to send quota: %d\n", ret); + if (iwl_mvm_is_lar_supported(mvm) && iwl_mvm_init_fw_regd(mvm)) + IWL_ERR(mvm, "Failed to initialize D3 LAR information\n"); + return 0; } @@ -1874,6 +1877,12 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) /* query SRAM first in case we want event logging */ iwl_mvm_read_d3_sram(mvm); + /* + * Query the current location and source from the D3 firmware so we + * can play it back when we re-intiailize the D0 firmware + */ + iwl_mvm_update_changed_regdom(mvm); + if (mvm->net_detect) { iwl_mvm_query_netdetect_reasons(mvm, vif); /* has unlocked the mutex, so skip that */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 7e4936585544..d89b0dd9e728 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -1503,7 +1503,7 @@ struct iwl_mcc_update_cmd { * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. - * @status: 0 for success, 1 no change in channel profile, 2 invalid input. + * @status: see &enum iwl_mcc_update_status * @mcc: the new applied MCC * @cap: capabilities for all channels which matches the MCC * @source_id: the MCC source, see iwl_mcc_source diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 303a7a0c6498..74847244c833 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -304,7 +304,8 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, const char *alpha2, - enum iwl_mcc_source src_id) + enum iwl_mcc_source src_id, + bool *changed) { struct ieee80211_regdomain *regd = NULL; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); @@ -322,6 +323,9 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, goto out; } + if (changed) + *changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE); + regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg, __le32_to_cpu(resp->n_channels), resp->channels, @@ -344,12 +348,31 @@ out: return regd; } -struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm) +void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm) +{ + bool changed; + struct ieee80211_regdomain *regd; + + if (!iwl_mvm_is_lar_supported(mvm)) + return; + + regd = iwl_mvm_get_current_regdomain(mvm, &changed); + if (!IS_ERR_OR_NULL(regd)) { + /* only update the regulatory core if changed */ + if (changed) + regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); + + kfree(regd); + } +} + +struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm, + bool *changed) { return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ", iwl_mvm_is_wifi_mcc_supported(mvm) ? MCC_SOURCE_GET_CURRENT : - MCC_SOURCE_OLD_FW); + MCC_SOURCE_OLD_FW, changed); } int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) @@ -366,13 +389,13 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) used_src = mvm->mcc_src; if (iwl_mvm_is_wifi_mcc_supported(mvm)) { /* Notify the firmware we support wifi location updates */ - regd = iwl_mvm_get_current_regdomain(mvm); + regd = iwl_mvm_get_current_regdomain(mvm, NULL); if (!IS_ERR_OR_NULL(regd)) kfree(regd); } /* Now set our last stored MCC and source */ - regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src); + regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src, NULL); if (IS_ERR_OR_NULL(regd)) return -EIO; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 5d5be372593a..9a8868e31ddf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1426,9 +1426,12 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, struct iwl_device_cmd *cmd); struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, const char *alpha2, - enum iwl_mcc_source src_id); -struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm); + enum iwl_mcc_source src_id, + bool *changed); +struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm, + bool *changed); int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm); +void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm); /* smart fifo */ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index d08ea695685f..123e0a16aea8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -655,7 +655,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, IWL_DEBUG_LAR(mvm, "MCC response status: 0x%x. new MCC: 0x%x ('%c%c') change: %d n_chans: %d\n", status, mcc, mcc >> 8, mcc & 0xff, - !!(status == MCC_RESP_SAME_CHAN_PROFILE), n_channels); + !!(status == MCC_RESP_NEW_CHAN_PROFILE), n_channels); resp_len = sizeof(*mcc_resp) + n_channels * sizeof(__le32); resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); @@ -802,7 +802,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) */ mvm->lar_regdom_set = false; - regd = iwl_mvm_get_current_regdomain(mvm); + regd = iwl_mvm_get_current_regdomain(mvm, NULL); if (IS_ERR_OR_NULL(regd)) return -EIO; @@ -810,7 +810,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) !iwl_mvm_get_bios_mcc(mvm, mcc)) { kfree(regd); regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, - MCC_SOURCE_BIOS); + MCC_SOURCE_BIOS, NULL); if (IS_ERR_OR_NULL(regd)) return -EIO; } @@ -843,7 +843,7 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, IWL_DEBUG_LAR(mvm, "RX: received chub update mcc cmd (mcc '%s' src %d)\n", mcc, src); - regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src); + regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, NULL); if (IS_ERR_OR_NULL(regd)) return 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index c1de23cc07fd..7b555f6cc580 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -1272,6 +1272,10 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) iwl_free_resp(&get_status_cmd); out: iwl_mvm_d0i3_enable_tx(mvm, qos_seq); + + /* the FW might have updated the regdomain */ + iwl_mvm_update_changed_regdom(mvm); + iwl_mvm_unref(mvm, IWL_MVM_REF_EXIT_WORK); mutex_unlock(&mvm->mutex); } From 560ba3e6f4ca31ff884fb238a16032e0e9c5814a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 1 Mar 2015 10:46:58 +0200 Subject: [PATCH 030/567] iwlwifi: bump API to 13 for devices that use iwlmvm This new firmware will come out soon. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 8 ++++---- drivers/net/wireless/iwlwifi/iwl-8000.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 0597a9cfd2f6..36e786f0387b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -69,12 +69,12 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX 12 -#define IWL3160_UCODE_API_MAX 12 +#define IWL7260_UCODE_API_MAX 13 +#define IWL3160_UCODE_API_MAX 13 /* Oldest version we won't warn about */ -#define IWL7260_UCODE_API_OK 10 -#define IWL3160_UCODE_API_OK 10 +#define IWL7260_UCODE_API_OK 12 +#define IWL3160_UCODE_API_OK 12 /* Lowest firmware API version supported */ #define IWL7260_UCODE_API_MIN 10 diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index d8dfa6da6307..9c396a42aec8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -69,10 +69,10 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 12 +#define IWL8000_UCODE_API_MAX 13 /* Oldest version we won't warn about */ -#define IWL8000_UCODE_API_OK 10 +#define IWL8000_UCODE_API_OK 12 /* Lowest firmware API version supported */ #define IWL8000_UCODE_API_MIN 10 From 767d6f9d43b4ebe97cc5dc7b7b2cdb5e57b82288 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 26 Feb 2015 16:39:36 +0200 Subject: [PATCH 031/567] iwlwifi: mvm: remove IWL_UCODE_TLV_API_DISABLE_STA_TX All the supported firwmares have this new API. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 -- drivers/net/wireless/iwlwifi/mvm/sta.c | 3 --- 2 files changed, 5 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 81c2f4875d30..489bda4ec231 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -240,7 +240,6 @@ enum iwl_ucode_tlv_flag { /** * enum iwl_ucode_tlv_api - ucode api * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex - * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. @@ -259,7 +258,6 @@ enum iwl_ucode_tlv_flag { */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), - IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9), diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 5c23cddaaae3..325cbbb61c0e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1681,9 +1681,6 @@ void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, }; int ret; - if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_DISABLE_STA_TX)) - return; - ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd); if (ret) IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret); From 0ec850dc194586398242d3fa590720f737b5f088 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 26 Feb 2015 16:40:56 +0200 Subject: [PATCH 032/567] iwlwifi: mvm: remove IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF All the supported firmwares support this API. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 -- drivers/net/wireless/iwlwifi/mvm/sf.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 489bda4ec231..e5fd19d8fc30 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -240,7 +240,6 @@ enum iwl_ucode_tlv_flag { /** * enum iwl_ucode_tlv_api - ucode api * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex - * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif. * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time * longer than the passive one, which is essential for fragmented scan. * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. @@ -258,7 +257,6 @@ enum iwl_ucode_tlv_flag { */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), - IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7), IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9), IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10), diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index 7eb78e2c240a..4b9f6c6fb614 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -179,8 +179,7 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, struct ieee80211_sta *sta; int ret = 0; - if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF && - mvm->cfg->disable_dummy_notification) + if (mvm->cfg->disable_dummy_notification) sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); /* From 70e90992e7c5dc4092869827665485a09ca777ea Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 26 Feb 2015 16:54:24 +0200 Subject: [PATCH 033/567] iwlwifi: mvm: BT Coex - disable RRC by default Enable this feature only if the firmware advertises support for it. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index e5fd19d8fc30..291a3382aa3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -290,6 +290,7 @@ enum iwl_ucode_tlv_api { * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running + * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC */ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), @@ -306,6 +307,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18), IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = BIT(22), IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = BIT(28), + IWL_UCODE_TLV_CAPA_BT_COEX_RRC = BIT(30), }; /* The default calibrate table size if not specified by firmware file */ diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 9717ee61928c..593bed7adad7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -633,7 +633,7 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm) if (IWL_MVM_BT_COEX_TTC) bt_cmd->flags |= cpu_to_le32(BT_COEX_TTC); - if (IWL_MVM_BT_COEX_RRC) + if (iwl_mvm_bt_is_rrc_supported(mvm)) bt_cmd->flags |= cpu_to_le32(BT_COEX_RRC); if (mvm->cfg->bt_shared_single_ant) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 9a8868e31ddf..4d44cf07475a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -948,6 +948,12 @@ static inline bool iwl_mvm_bt_is_plcr_supported(struct iwl_mvm *mvm) IWL_MVM_BT_COEX_CORUNNING; } +static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm) +{ + return (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BT_COEX_RRC) && + IWL_MVM_BT_COEX_RRC; +} + extern const u8 iwl_mvm_ac_to_tx_fifo[]; struct iwl_rate_info { From 7754ae79e218bfd7782655fdebc8966c8a858358 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 26 Feb 2015 15:14:35 +0200 Subject: [PATCH 034/567] iwlwifi: mvm: always update the quota after association When we associate we always need to update the quotas. This fixes a bug for cases in which quotas weren't udapted after association. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 20 ++++++++++---------- drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/iwlwifi/mvm/quota.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/utils.c | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 74847244c833..7eab892de29b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1298,7 +1298,7 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); iwl_mvm_d0i3_enable_tx(mvm, NULL); - ret = iwl_mvm_update_quotas(mvm, NULL); + ret = iwl_mvm_update_quotas(mvm, false, NULL); if (ret) IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", ret); @@ -1977,7 +1977,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, sizeof(mvmvif->beacon_stats)); /* add quota for this interface */ - ret = iwl_mvm_update_quotas(mvm, NULL); + ret = iwl_mvm_update_quotas(mvm, true, NULL); if (ret) { IWL_ERR(mvm, "failed to update quotas\n"); return; @@ -2029,7 +2029,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; /* remove quota for this interface */ - ret = iwl_mvm_update_quotas(mvm, NULL); + ret = iwl_mvm_update_quotas(mvm, false, NULL); if (ret) IWL_ERR(mvm, "failed to update quotas\n"); @@ -2148,7 +2148,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, /* power updated needs to be done before quotas */ iwl_mvm_power_update_mac(mvm); - ret = iwl_mvm_update_quotas(mvm, NULL); + ret = iwl_mvm_update_quotas(mvm, false, NULL); if (ret) goto out_quota_failed; @@ -2214,7 +2214,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, if (vif->p2p && mvm->p2p_device_vif) iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); - iwl_mvm_update_quotas(mvm, NULL); + iwl_mvm_update_quotas(mvm, false, NULL); iwl_mvm_send_rm_bcast_sta(mvm, vif); iwl_mvm_binding_remove_vif(mvm, vif); @@ -3247,14 +3247,14 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, */ if (vif->type == NL80211_IFTYPE_MONITOR) { mvmvif->monitor_active = true; - ret = iwl_mvm_update_quotas(mvm, NULL); + ret = iwl_mvm_update_quotas(mvm, false, NULL); if (ret) goto out_remove_binding; } /* Handle binding during CSA */ if (vif->type == NL80211_IFTYPE_AP) { - iwl_mvm_update_quotas(mvm, NULL); + iwl_mvm_update_quotas(mvm, false, NULL); iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); } @@ -3278,7 +3278,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA); - iwl_mvm_update_quotas(mvm, NULL); + iwl_mvm_update_quotas(mvm, false, NULL); } goto out; @@ -3351,7 +3351,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, break; } - iwl_mvm_update_quotas(mvm, disabled_vif); + iwl_mvm_update_quotas(mvm, false, disabled_vif); iwl_mvm_binding_remove_vif(mvm, vif); out: @@ -3543,7 +3543,7 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, mvm->noa_duration = noa_duration; mvm->noa_vif = vif; - return iwl_mvm_update_quotas(mvm, NULL); + return iwl_mvm_update_quotas(mvm, false, NULL); case IWL_MVM_TM_CMD_SET_BEACON_FILTER: /* must be associated client vif - ignore authorized */ if (!vif || vif->type != NL80211_IFTYPE_STATION || diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 4d44cf07475a..52135a4fd8d3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1139,7 +1139,7 @@ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); /* Quota management */ -int iwl_mvm_update_quotas(struct iwl_mvm *mvm, +int iwl_mvm_update_quotas(struct iwl_mvm *mvm, bool force_upload, struct ieee80211_vif *disabled_vif); /* Scanning */ diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index dbb2594390e9..509a66d05245 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -172,6 +172,7 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm, } int iwl_mvm_update_quotas(struct iwl_mvm *mvm, + bool force_update, struct ieee80211_vif *disabled_vif) { struct iwl_time_quota_cmd cmd = {}; @@ -309,7 +310,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, "zero quota on binding %d\n", i); } - if (!send) { + if (!send && !force_update) { /* don't send a practically unchanged command, the firmware has * to re-initialize a lot of state and that can have an adverse * impact on it diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 2b9de63951e6..435faee0a28e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -857,7 +857,7 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmvif->low_latency = value; - res = iwl_mvm_update_quotas(mvm, NULL); + res = iwl_mvm_update_quotas(mvm, false, NULL); if (res) return res; From 7a42baa621538eb73b261828027b1faa25e341e6 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Wed, 25 Feb 2015 14:24:51 +0200 Subject: [PATCH 035/567] iwlwifi: mvm: support family 8000 B2/C steps In-order to recognize newer step of the device, the driver must read the chip_version_id from the AUX bus MISC address space. This will determine what firmware file will be loaded. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 9 ++++++ drivers/net/wireless/iwlwifi/pcie/trans.c | 37 ++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 383af2749d9a..aa6fb584a5a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -378,6 +378,15 @@ enum secure_load_status_reg { #define LMPM_PMG_EN 0xA01CEC #define RADIO_REG_SYS_MANUAL_DFT_0 0xAD4078 #define RFIC_REG_RD 0xAD0470 +#define WFPM_CTRL_REG 0xA03030 +enum { + ENABLE_WFPM = BIT(31), +}; + +#define AUX_MISC_REG 0xA200B0 +enum { + HW_STEP_LOCATION_BITS = 24, +}; /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index f31a94160771..4c16333b21f7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2423,10 +2423,45 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, * "dash" value). To keep hw_rev backwards compatible - we'll store it * in the old format. */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { + unsigned long flags; + int ret; + trans->hw_rev = (trans->hw_rev & 0xfff0) | (CSR_HW_REV_STEP(trans->hw_rev << 2) << 2); + /* + * in-order to recognize C step driver should read chip version + * id located at the AUX bus MISC address space. + */ + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + udelay(2); + + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, + 25000); + if (ret < 0) { + IWL_DEBUG_INFO(trans, "Failed to wake up the nic\n"); + goto out_pci_disable_msi; + } + + if (iwl_trans_grab_nic_access(trans, false, &flags)) { + u32 hw_step; + + hw_step = __iwl_read_prph(trans, WFPM_CTRL_REG); + hw_step |= ENABLE_WFPM; + __iwl_write_prph(trans, WFPM_CTRL_REG, hw_step); + hw_step = __iwl_read_prph(trans, AUX_MISC_REG); + hw_step = (hw_step >> HW_STEP_LOCATION_BITS) & 0xF; + if (hw_step == 0x3) + trans->hw_rev = (trans->hw_rev & 0xFFFFFFF3) | + (SILICON_C_STEP << 2); + iwl_trans_release_nic_access(trans, &flags); + } + } + trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; snprintf(trans->hw_id_str, sizeof(trans->hw_id_str), "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device); From 36277234da673293a6afe60ac19a79d20bce9ae5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 25 Feb 2015 15:49:39 +0200 Subject: [PATCH 036/567] iwlwifi: pcie: speed up the Tx DMA stop flow We don't need to acquire MAC access for each access, it makes much more sense to keep the MAC access. This speeds up the Tx DMA stop flow significantly. Moreover, if one channel can't be stopped, stop the others but don't poll for them to avoid being stuck there for a long time. This solves a situation in which we were stuck in that flow for way too long with a spinlock held which led to a kernel panic. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/tx.c | 51 +++++++++++++++++--------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index af0bce736358..26e6dd0e9f05 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -725,33 +725,50 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) iwl_pcie_tx_start(trans, 0); } +static void iwl_pcie_tx_stop_fh(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long flags; + int ch, ret; + u32 mask = 0; + + spin_lock(&trans_pcie->irq_lock); + + if (!iwl_trans_grab_nic_access(trans, false, &flags)) + goto out; + + /* Stop each Tx DMA channel */ + for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { + iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); + mask |= FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch); + } + + /* Wait for DMA channels to be idle */ + ret = iwl_poll_bit(trans, FH_TSSR_TX_STATUS_REG, mask, mask, 5000); + if (ret < 0) + IWL_ERR(trans, + "Failing on timeout while stopping DMA channel %d [0x%08x]\n", + ch, iwl_read32(trans, FH_TSSR_TX_STATUS_REG)); + + iwl_trans_release_nic_access(trans, &flags); + +out: + spin_unlock(&trans_pcie->irq_lock); +} + /* * iwl_pcie_tx_stop - Stop all Tx DMA channels */ int iwl_pcie_tx_stop(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int ch, txq_id, ret; + int txq_id; /* Turn off all Tx DMA fifos */ - spin_lock(&trans_pcie->irq_lock); - iwl_scd_deactivate_fifos(trans); - /* Stop each Tx DMA channel, and wait for it to be idle */ - for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { - iwl_write_direct32(trans, - FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); - ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000); - if (ret < 0) - IWL_ERR(trans, - "Failing on timeout while stopping DMA channel %d [0x%08x]\n", - ch, - iwl_read_direct32(trans, - FH_TSSR_TX_STATUS_REG)); - } - spin_unlock(&trans_pcie->irq_lock); + /* Turn off all Tx DMA channels */ + iwl_pcie_tx_stop_fh(trans); /* * This function can be called before the op_mode disabled the From 6a65bd534e5844d42d432eb41ee04e2a242bfc60 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 25 Feb 2015 16:06:46 +0200 Subject: [PATCH 037/567] iwlwifi: pcie: include more registers in the prph dump This adds BT Coex data to the prph register list. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 4c16333b21f7..421ef6b5fae2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1961,24 +1961,25 @@ static const struct { { .start = 0x00a01c7c, .end = 0x00a01c7c }, { .start = 0x00a01c28, .end = 0x00a01c54 }, { .start = 0x00a01c5c, .end = 0x00a01c5c }, - { .start = 0x00a01c84, .end = 0x00a01c84 }, + { .start = 0x00a01c60, .end = 0x00a01cdc }, { .start = 0x00a01ce0, .end = 0x00a01d0c }, { .start = 0x00a01d18, .end = 0x00a01d20 }, { .start = 0x00a01d2c, .end = 0x00a01d30 }, { .start = 0x00a01d40, .end = 0x00a01d5c }, { .start = 0x00a01d80, .end = 0x00a01d80 }, - { .start = 0x00a01d98, .end = 0x00a01d98 }, + { .start = 0x00a01d98, .end = 0x00a01d9c }, + { .start = 0x00a01da8, .end = 0x00a01da8 }, + { .start = 0x00a01db8, .end = 0x00a01df4 }, { .start = 0x00a01dc0, .end = 0x00a01dfc }, { .start = 0x00a01e00, .end = 0x00a01e2c }, { .start = 0x00a01e40, .end = 0x00a01e60 }, + { .start = 0x00a01e68, .end = 0x00a01e6c }, + { .start = 0x00a01e74, .end = 0x00a01e74 }, { .start = 0x00a01e84, .end = 0x00a01e90 }, { .start = 0x00a01e9c, .end = 0x00a01ec4 }, - { .start = 0x00a01ed0, .end = 0x00a01ed0 }, - { .start = 0x00a01f00, .end = 0x00a01f14 }, - { .start = 0x00a01f44, .end = 0x00a01f58 }, - { .start = 0x00a01f80, .end = 0x00a01fa8 }, - { .start = 0x00a01fb0, .end = 0x00a01fbc }, - { .start = 0x00a01ff8, .end = 0x00a01ffc }, + { .start = 0x00a01ed0, .end = 0x00a01ee0 }, + { .start = 0x00a01f00, .end = 0x00a01f1c }, + { .start = 0x00a01f44, .end = 0x00a01ffc }, { .start = 0x00a02000, .end = 0x00a02048 }, { .start = 0x00a02068, .end = 0x00a020f0 }, { .start = 0x00a02100, .end = 0x00a02118 }, From e70fe7eb9dec9c7b7c570a489f198b93b5ca609b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 1 Mar 2015 17:18:00 +0200 Subject: [PATCH 038/567] iwlwifi: fix smatch warning: warn: inconsistent indenting While at it, fix a few checkpatch issues. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/rs.c | 7 ++++--- drivers/net/wireless/iwlwifi/dvm/tx.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-drv.c | 18 +++++++++--------- drivers/net/wireless/iwlwifi/mvm/rs.c | 18 +++++++++--------- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 32b78a66536d..3bd7c86e90d9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -3153,12 +3153,13 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff+desc, "lq type %s\n", (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); if (is_Ht(tbl->lq_type)) { - desc += sprintf(buff+desc, " %s", + desc += sprintf(buff + desc, " %s", (is_siso(tbl->lq_type)) ? "SISO" : ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); - desc += sprintf(buff+desc, " %s", + desc += sprintf(buff + desc, " %s", (tbl->is_ht40) ? "40MHz" : "20MHz"); - desc += sprintf(buff+desc, " %s %s %s\n", (tbl->is_SGI) ? "SGI" : "", + desc += sprintf(buff + desc, " %s %s %s\n", + (tbl->is_SGI) ? "SGI" : "", (lq_sta->is_green) ? "GF enabled" : "", (lq_sta->is_agg) ? "AGG on" : ""); } diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 1e40a12de077..275df12a6045 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -189,9 +189,9 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, rate_flags |= RATE_MCS_CCK_MSK; /* Set up antennas */ - if (priv->lib->bt_params && - priv->lib->bt_params->advanced_bt_coexist && - priv->bt_full_concurrent) { + if (priv->lib->bt_params && + priv->lib->bt_params->advanced_bt_coexist && + priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, first_antenna(priv->nvm_data->valid_tx_ant)); diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index f1d73d5e6eff..66ca000f0da1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1014,34 +1014,34 @@ static int validate_sec_sizes(struct iwl_drv *drv, /* Verify that uCode images will fit in card's SRAM. */ if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_INST) > - cfg->max_inst_size) { + cfg->max_inst_size) { IWL_ERR(drv, "uCode instr len %Zd too large to fit in\n", get_sec_size(pieces, IWL_UCODE_REGULAR, - IWL_UCODE_SECTION_INST)); + IWL_UCODE_SECTION_INST)); return -1; } if (get_sec_size(pieces, IWL_UCODE_REGULAR, IWL_UCODE_SECTION_DATA) > - cfg->max_data_size) { + cfg->max_data_size) { IWL_ERR(drv, "uCode data len %Zd too large to fit in\n", get_sec_size(pieces, IWL_UCODE_REGULAR, - IWL_UCODE_SECTION_DATA)); + IWL_UCODE_SECTION_DATA)); return -1; } - if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) > - cfg->max_inst_size) { + if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_INST) > + cfg->max_inst_size) { IWL_ERR(drv, "uCode init instr len %Zd too large to fit in\n", get_sec_size(pieces, IWL_UCODE_INIT, - IWL_UCODE_SECTION_INST)); + IWL_UCODE_SECTION_INST)); return -1; } if (get_sec_size(pieces, IWL_UCODE_INIT, IWL_UCODE_SECTION_DATA) > - cfg->max_data_size) { + cfg->max_data_size) { IWL_ERR(drv, "uCode init data len %Zd too large to fit in\n", get_sec_size(pieces, IWL_UCODE_REGULAR, - IWL_UCODE_SECTION_DATA)); + IWL_UCODE_SECTION_DATA)); return -1; } return 0; diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 6578498dd5af..d8dacb3be10a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -3343,16 +3343,16 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, (is_legacy(rate)) ? "legacy" : is_vht(rate) ? "VHT" : "HT"); if (!is_legacy(rate)) { - desc += sprintf(buff+desc, " %s", + desc += sprintf(buff + desc, " %s", (is_siso(rate)) ? "SISO" : "MIMO2"); - desc += sprintf(buff+desc, " %s", - (is_ht20(rate)) ? "20MHz" : - (is_ht40(rate)) ? "40MHz" : - (is_ht80(rate)) ? "80Mhz" : "BAD BW"); - desc += sprintf(buff+desc, " %s %s %s\n", - (rate->sgi) ? "SGI" : "NGI", - (rate->ldpc) ? "LDPC" : "BCC", - (lq_sta->is_agg) ? "AGG on" : ""); + desc += sprintf(buff + desc, " %s", + (is_ht20(rate)) ? "20MHz" : + (is_ht40(rate)) ? "40MHz" : + (is_ht80(rate)) ? "80Mhz" : "BAD BW"); + desc += sprintf(buff + desc, " %s %s %s\n", + (rate->sgi) ? "SGI" : "NGI", + (rate->ldpc) ? "LDPC" : "BCC", + (lq_sta->is_agg) ? "AGG on" : ""); } desc += sprintf(buff+desc, "last tx rate=0x%X\n", lq_sta->last_rate_n_flags); From f55286313a6597d075f409f111b4f516a3feb830 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 4 Feb 2015 15:38:56 +0200 Subject: [PATCH 039/567] iwlwifi: use correct NVM offset for LAR enable for new NVMs New NVM versions in LnP platforms have the lar_enable bits in a different offset. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 54e447b9978c..b372105604a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -110,7 +110,8 @@ enum family_8000_nvm_offsets { /* NVM REGULATORY -Section offset (in words) definitions */ NVM_CHANNELS_FAMILY_8000 = 0, - NVM_LAR_OFFSET_FAMILY_8000 = 0x4C7, + NVM_LAR_OFFSET_FAMILY_8000_OLD = 0x4C7, + NVM_LAR_OFFSET_FAMILY_8000 = 0x507, NVM_LAR_ENABLED_FAMILY_8000 = 0x7, /* NVM calibration section offset (in words) definitions */ @@ -656,8 +657,11 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, iwl_init_sbands(dev, cfg, data, nvm_sw, tx_chains, rx_chains, lar_fw_supported); } else { - lar_config = le16_to_cpup(regulatory + - NVM_LAR_OFFSET_FAMILY_8000); + u16 lar_offset = data->nvm_version < 0xE39 ? + NVM_LAR_OFFSET_FAMILY_8000_OLD : + NVM_LAR_OFFSET_FAMILY_8000; + + lar_config = le16_to_cpup(regulatory + lar_offset); data->lar_enabled = !!(lar_config & NVM_LAR_ENABLED_FAMILY_8000); From 7d03182c5d98c86a7bbc58b8878bbed353fb45ee Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 2 Mar 2015 14:35:41 +0200 Subject: [PATCH 040/567] iwlwifi: mvm: remove unneeded include iwl-fw-error-dump.h The functions related to firmware error dump moved. No need for this unclude anymore. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 7b555f6cc580..f94b322124fa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -82,7 +82,6 @@ #include "rs.h" #include "fw-api-scan.h" #include "time-event.h" -#include "iwl-fw-error-dump.h" #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); From 9beda940594f6646f97b7927e202ae9504654f9d Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 2 Mar 2015 14:39:03 +0200 Subject: [PATCH 041/567] iwlwifi: mvm: fix identation mvm->fw->dbg_dest_tlv really needs to be under the right parenthesis. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index f94b322124fa..80121e41ca22 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -872,8 +872,8 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) /* start recording again if the firmware is not crashed */ WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) && - mvm->fw->dbg_dest_tlv && - iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); + mvm->fw->dbg_dest_tlv && + iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); mutex_unlock(&mvm->mutex); From fcf23352e0ff500676ac4923c68c20a1fe55fb5e Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 22 Feb 2015 19:15:04 +0200 Subject: [PATCH 042/567] iwlwifi: mvm: reflect TDLS pm state in mvmvif->pm_enabled When entering D0i3, the MVM mutex cannot be grabbed. This interferes with the calculation of the number of connected TDLS stations during the setup of the power cmd. The goal is to disable power saving for all vifs while any TDLS station is connected. For this purpose it is enough to keep the pm_enabled member of all mvmvifs as false. An update of the power state already occurs when a TDLS station is added/removed, so the values are correctly updated. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 2620dd0c45f9..9c6fce10fe0b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -357,7 +357,7 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); if (!vif->bss_conf.ps || iwl_mvm_vif_low_latency(mvmvif) || - !mvmvif->pm_enabled || iwl_mvm_tdls_sta_count(mvm, vif)) + !mvmvif->pm_enabled) return; cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); @@ -638,6 +638,10 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, if (vifs->ap_vif) ap_mvmvif = iwl_mvm_vif_from_mac80211(vifs->ap_vif); + /* don't allow PM if any TDLS stations exist */ + if (iwl_mvm_tdls_sta_count(mvm, NULL)) + return; + /* enable PM on bss if bss stand alone */ if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { bss_mvmvif->pm_enabled = true; From 4557eaba13c2b9074c64e37bb93f77c4917a81b1 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 1 Mar 2015 18:24:57 +0200 Subject: [PATCH 043/567] iwlwifi: don't allow the FW to return invalid ch indices If the FW returns an invalid channels count in response to an MCC request, make sure we don't reference invalid indices in the channels array. Signed-off-by: Arik Nemtsov Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index b372105604a0..774637746427 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -743,10 +743,15 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int center_freq, prev_center_freq = 0; int valid_rules = 0; bool new_rule; + int max_num_ch = cfg->device_family == IWL_DEVICE_FAMILY_8000 ? + IWL_NUM_CHANNELS_FAMILY_8000 : IWL_NUM_CHANNELS; if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) return ERR_PTR(-EINVAL); + if (WARN_ON(num_of_ch > max_num_ch)) + num_of_ch = max_num_ch; + IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n", num_of_ch); From db7c689d0877d3ba96c4791ff1f255eca51334fb Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 2 Mar 2015 10:35:19 +0200 Subject: [PATCH 044/567] iwlwifi: mvm: rs: improve ss_params debug print Make the print a bit more readable. Reported-by: Joe Perches Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index d8dacb3be10a..98edb18f211a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -3373,13 +3373,13 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, ss_params = le32_to_cpu(lq_sta->lq.ss_params); desc += sprintf(buff+desc, "single stream params: %s%s%s%s\n", (ss_params & LQ_SS_PARAMS_VALID) ? - "VALID," : "INVALID", + "VALID" : "INVALID", (ss_params & LQ_SS_BFER_ALLOWED) ? - "BFER," : "", + ", BFER" : "", (ss_params & LQ_SS_STBC_1SS_ALLOWED) ? - "STBC," : "", + ", STBC" : "", (ss_params & LQ_SS_FORCE) ? - "FORCE" : ""); + ", FORCE" : ""); desc += sprintf(buff+desc, "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n", lq_sta->lq.initial_rate_index[0], From 3a1a61476d749c9aa92d5ce67164fd5e5f7fbe55 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Wed, 4 Mar 2015 16:26:45 +0200 Subject: [PATCH 045/567] iwlwifi: add new 8260 series PCI IDs New sub system IDs were introduced for the 8260 series. This patch adds them so new 8260 cards can be recognized. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index dbd6bcf52205..3f9289d35de8 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -413,10 +413,27 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 8000 Series */ {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x1050, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F4, 0xC030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F4, 0xD030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x9010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F4, 0x8030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F4, 0x9030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x8050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x9050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)}, {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0810, iwl8260_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ {0} From 16bc119b6b6410863c50d0dafed8c04e5cb6122a Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Tue, 3 Mar 2015 13:53:28 +0200 Subject: [PATCH 046/567] iwlwifi: trans: Take ownership on secure machine before FW load When we load the firmware for the 8000 B step device, it'll verify its signature. In the current version of the hardware, there can be a race between the WiFi firmware being loaded and the Bluetooth firmware being loaded. Check that WiFi is authenticated, if not, take ownership on the authentication machine to make sure that the WiFi firmware will be authenticated. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 10 ++++++ drivers/net/wireless/iwlwifi/pcie/trans.c | 42 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index aa6fb584a5a6..bc962888c583 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -381,6 +381,7 @@ enum secure_load_status_reg { #define WFPM_CTRL_REG 0xA03030 enum { ENABLE_WFPM = BIT(31), + WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000, }; #define AUX_MISC_REG 0xA200B0 @@ -388,6 +389,15 @@ enum { HW_STEP_LOCATION_BITS = 24, }; +#define AUX_MISC_MASTER1_EN 0xA20818 +enum aux_misc_master1_en { + AUX_MISC_MASTER1_EN_SBE_MSK = 0x1, +}; + +#define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800 +#define RSA_ENABLE 0xA24B08 +#define PREG_AUX_BUS_WPROT_0 0xA04CC0 + /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 enum { diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 421ef6b5fae2..9ce5e614c324 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -682,6 +682,43 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, return ret; } +/* + * Driver Takes the ownership on secure machine before FW load + * and prevent race with the BT load. + * W/A for ROM bug. (should be remove in the next Si step) + */ +static int iwl_pcie_rsa_race_bug_wa(struct iwl_trans *trans) +{ + u32 val, loop = 1000; + + /* Check the RSA semaphore is accessible - if not, we are in trouble */ + val = iwl_read_prph(trans, PREG_AUX_BUS_WPROT_0); + if (val & (BIT(1) | BIT(17))) { + IWL_ERR(trans, + "can't access the RSA semaphore it is write protected\n"); + return 0; + } + + /* take ownership on the AUX IF */ + iwl_write_prph(trans, WFPM_CTRL_REG, WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK); + iwl_write_prph(trans, AUX_MISC_MASTER1_EN, AUX_MISC_MASTER1_EN_SBE_MSK); + + do { + iwl_write_prph(trans, AUX_MISC_MASTER1_SMPHR_STATUS, 0x1); + val = iwl_read_prph(trans, AUX_MISC_MASTER1_SMPHR_STATUS); + if (val == 0x1) { + iwl_write_prph(trans, RSA_ENABLE, 0); + return 0; + } + + udelay(10); + loop--; + } while (loop > 0); + + IWL_ERR(trans, "Failed to take ownership on secure machine\n"); + return -EIO; +} + static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans, const struct fw_img *image, int cpu, @@ -901,6 +938,11 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans, if (trans->dbg_dest_tlv) iwl_pcie_apply_destination(trans); + /* TODO: remove in the next Si step */ + ret = iwl_pcie_rsa_race_bug_wa(trans); + if (ret) + return ret; + /* configure the ucode to be ready to get the secured image */ /* release CPU reset */ iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); From 36f4631c53cb2fab37e6cb5724727b6a5a1b3899 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 10 Mar 2015 20:32:08 +0100 Subject: [PATCH 047/567] iwlwifi: mvm: remove warning on station exhaustion When using IBSS, it's easily possible to exhaust the number of available stations in the driver, so don't warn on it. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 325cbbb61c0e..50f9288368af 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -273,7 +273,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, else sta_id = mvm_sta->sta_id; - if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT)) + if (sta_id == IWL_MVM_STATION_COUNT) return -ENOSPC; spin_lock_init(&mvm_sta->lock); From 35af15d1312429c9407c75868475c06e459070cb Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 4 Mar 2015 15:08:00 +0200 Subject: [PATCH 048/567] iwlwifi: mvm: don't init MCC during CT-kill RTNL is not taken during CT-kill so regulatory APIs cannot be invoked. That's fine, since the HW is only brought up to check the temperature during CT-kill. We don't expect Tx or scanning. Signed-off-by: Arik Nemtsov Reviewed-by: Luciano Coelho Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index c03bde093927..6cf7d9837ca5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -739,9 +739,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; - ret = iwl_mvm_init_mcc(mvm); - if (ret) - goto error; + /* + * RTNL is not taken during Ct-kill, but we don't need to scan/Tx + * anyway, so don't init MCC. + */ + if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) { + ret = iwl_mvm_init_mcc(mvm); + if (ret) + goto error; + } if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { ret = iwl_mvm_config_scan(mvm); From ad82d8a5366fc3f84ea9ee0fa417cdfb42b28ec8 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 8 Mar 2015 19:43:41 +0200 Subject: [PATCH 049/567] iwlwifi: mvm: rs: update Tx statistics when using fixed rate The Tx statistics weren't updated when using fixed rate for debugging. Fix this as Tx statistics are useful in this use case. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 72 ++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 98edb18f211a..dd457df9601e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1065,6 +1065,37 @@ static inline bool rs_rate_column_match(struct rs_rate *a, && ant_match; } +static inline enum rs_column rs_get_column_from_rate(struct rs_rate *rate) +{ + if (is_legacy(rate)) { + if (rate->ant == ANT_A) + return RS_COLUMN_LEGACY_ANT_A; + + if (rate->ant == ANT_B) + return RS_COLUMN_LEGACY_ANT_B; + + goto err; + } + + if (is_siso(rate)) { + if (rate->ant == ANT_A || rate->stbc || rate->bfer) + return rate->sgi ? RS_COLUMN_SISO_ANT_A_SGI : + RS_COLUMN_SISO_ANT_A; + + if (rate->ant == ANT_B) + return rate->sgi ? RS_COLUMN_SISO_ANT_B_SGI : + RS_COLUMN_SISO_ANT_B; + + goto err; + } + + if (is_mimo(rate)) + return rate->sgi ? RS_COLUMN_MIMO2_SGI : RS_COLUMN_MIMO2; + +err: + return RS_COLUMN_INVALID; +} + static u8 rs_get_tid(struct ieee80211_hdr *hdr) { u8 tid = IWL_MAX_TID_COUNT; @@ -1106,18 +1137,44 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, return; } -#ifdef CONFIG_MAC80211_DEBUGFS - /* Disable last tx check if we are debugging with fixed rate */ - if (lq_sta->pers.dbg_fixed_rate) { - IWL_DEBUG_RATE(mvm, "Fixed rate. avoid rate scaling\n"); - return; - } -#endif /* This packet was aggregated but doesn't carry status info */ if ((info->flags & IEEE80211_TX_CTL_AMPDU) && !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; + rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate); + +#ifdef CONFIG_MAC80211_DEBUGFS + /* Disable last tx check if we are debugging with fixed rate but + * update tx stats */ + if (lq_sta->pers.dbg_fixed_rate) { + int index = tx_resp_rate.index; + enum rs_column column; + int attempts, success; + + column = rs_get_column_from_rate(&tx_resp_rate); + if (WARN_ONCE(column == RS_COLUMN_INVALID, + "Can't map rate 0x%x to column", + tx_resp_hwrate)) + return; + + if (info->flags & IEEE80211_TX_STAT_AMPDU) { + attempts = info->status.ampdu_len; + success = info->status.ampdu_ack_len; + } else { + attempts = info->status.rates[0].count; + success = !!(info->flags & IEEE80211_TX_STAT_ACK); + } + + lq_sta->pers.tx_stats[column][index].total += attempts; + lq_sta->pers.tx_stats[column][index].success += success; + + IWL_DEBUG_RATE(mvm, "Fixed rate 0x%x success %d attempts %d\n", + tx_resp_hwrate, success, attempts); + return; + } +#endif + if (time_after(jiffies, (unsigned long)(lq_sta->last_tx + (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { @@ -1142,7 +1199,6 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, table = &lq_sta->lq; lq_hwrate = le32_to_cpu(table->rs_table[0]); rs_rate_from_ucode_rate(lq_hwrate, info->band, &lq_rate); - rs_rate_from_ucode_rate(tx_resp_hwrate, info->band, &tx_resp_rate); /* Here we actually compare this rate to the latest LQ command */ if (!rs_rate_equal(&tx_resp_rate, &lq_rate, allow_ant_mismatch)) { From e0b8d405132db38fafc9da86ef4de0ebe2be468e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 20 Jan 2015 17:02:40 +0200 Subject: [PATCH 050/567] iwlwifi: pcie: allow the op_mode to freeze the stuck queue timer This allows the op_mode to let the transport know that a queue is currently frozen and that its timer should be stopped. When the queue is unfrozen, its timer should be set to expire after the remainder of the timeout has elapsed. This can be used when stations go to sleep. When a station goes to sleep, the op_mode can freeze the timer so that the queue will never be considered as stuck. When the station wakes up, the queue will be unfrozen. This is meant to avoid false positives that would happen if a buggy station goes to sleep for a very long time. In case we have a dedicated queue for this station (BA agreement) and it goes to sleep for a very long time, the queue would rightfully be stopped during all that time. In this case, the stuck queue timer could fire and that would be a false positive. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 15 +++++ drivers/net/wireless/iwlwifi/pcie/internal.h | 4 ++ drivers/net/wireless/iwlwifi/pcie/trans.c | 61 +++++++++++++++++++- drivers/net/wireless/iwlwifi/pcie/tx.c | 12 ++++ 4 files changed, 89 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 542a6810c81c..11ac5c58527f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -458,6 +458,8 @@ struct iwl_trans_txq_scd_cfg { * @txq_disable: de-configure a Tx queue to send AMPDUs * Must be atomic * @wait_tx_queue_empty: wait until tx queues are empty. May sleep. + * @freeze_txq_timer: prevents the timer of the queue from firing until the + * queue is set to awake. Must be atomic. * @dbgfs_register: add the dbgfs files under this directory. Files will be * automatically deleted. * @write8: write a u8 to a register at offset ofs from the BAR @@ -517,6 +519,8 @@ struct iwl_trans_ops { int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm); + void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs, + bool freeze); void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); @@ -873,6 +877,17 @@ void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo, iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout); } +static inline void iwl_trans_freeze_txq_timer(struct iwl_trans *trans, + unsigned long txqs, + bool freeze) +{ + if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) + IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + + if (trans->ops->freeze_txq_timer) + trans->ops->freeze_txq_timer(trans, txqs, freeze); +} + static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans, u32 txqs) { diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index cae0eb8835ce..01996c9d98a7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -217,6 +217,8 @@ struct iwl_pcie_txq_scratch_buf { * @active: stores if queue is active * @ampdu: true if this queue is an ampdu queue for an specific RA/TID * @wd_timeout: queue watchdog timeout (jiffies) - per queue + * @frozen: tx stuck queue timer is frozen + * @frozen_expiry_remainder: remember how long until the timer fires * * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * descriptors) and required locking structures. @@ -228,9 +230,11 @@ struct iwl_txq { dma_addr_t scratchbufs_dma; struct iwl_pcie_txq_entry *entries; spinlock_t lock; + unsigned long frozen_expiry_remainder; struct timer_list stuck_timer; struct iwl_trans_pcie *trans_pcie; bool need_update; + bool frozen; u8 active; bool ampdu; unsigned long wd_timeout; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 9ce5e614c324..dc247325d8d7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1504,6 +1504,60 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, return ret; } +static void iwl_trans_pcie_freeze_txq_timer(struct iwl_trans *trans, + unsigned long txqs, + bool freeze) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int queue; + + for_each_set_bit(queue, &txqs, BITS_PER_LONG) { + struct iwl_txq *txq = &trans_pcie->txq[queue]; + unsigned long now; + + spin_lock_bh(&txq->lock); + + now = jiffies; + + if (txq->frozen == freeze) + goto next_queue; + + IWL_DEBUG_TX_QUEUES(trans, "%s TXQ %d\n", + freeze ? "Freezing" : "Waking", queue); + + txq->frozen = freeze; + + if (txq->q.read_ptr == txq->q.write_ptr) + goto next_queue; + + if (freeze) { + if (unlikely(time_after(now, + txq->stuck_timer.expires))) { + /* + * The timer should have fired, maybe it is + * spinning right now on the lock. + */ + goto next_queue; + } + /* remember how long until the timer fires */ + txq->frozen_expiry_remainder = + txq->stuck_timer.expires - now; + del_timer(&txq->stuck_timer); + goto next_queue; + } + + /* + * Wake a non-empty queue -> arm timer with the + * remainder before it froze + */ + mod_timer(&txq->stuck_timer, + now + txq->frozen_expiry_remainder); + +next_queue: + spin_unlock_bh(&txq->lock); + } +} + #define IWL_FLUSH_WAIT_MS 2000 static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) @@ -1755,7 +1809,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, int ret; size_t bufsz; - bufsz = sizeof(char) * 64 * trans->cfg->base_params->num_of_queues; + bufsz = sizeof(char) * 75 * trans->cfg->base_params->num_of_queues; if (!trans_pcie->txq) return -EAGAIN; @@ -1768,11 +1822,11 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, txq = &trans_pcie->txq[cnt]; q = &txq->q; pos += scnprintf(buf + pos, bufsz - pos, - "hwq %.2d: read=%u write=%u use=%d stop=%d need_update=%d%s\n", + "hwq %.2d: read=%u write=%u use=%d stop=%d need_update=%d frozen=%d%s\n", cnt, q->read_ptr, q->write_ptr, !!test_bit(cnt, trans_pcie->queue_used), !!test_bit(cnt, trans_pcie->queue_stopped), - txq->need_update, + txq->need_update, txq->frozen, (cnt == trans_pcie->cmd_queue ? " HCMD" : "")); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); @@ -2348,6 +2402,7 @@ static const struct iwl_trans_ops trans_ops_pcie = { .dbgfs_register = iwl_trans_pcie_dbgfs_register, .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty, + .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, .write8 = iwl_trans_pcie_write8, .write32 = iwl_trans_pcie_write32, diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 26e6dd0e9f05..06952aadfd7b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -929,9 +929,18 @@ error: static inline void iwl_pcie_txq_progress(struct iwl_txq *txq) { + lockdep_assert_held(&txq->lock); + if (!txq->wd_timeout) return; + /* + * station is asleep and we send data - that must + * be uAPSD or PS-Poll. Don't rearm the timer. + */ + if (txq->frozen) + return; + /* * if empty delete timer, otherwise move timer forward * since we're making progress on this queue @@ -1265,6 +1274,9 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, SCD_TX_STTS_QUEUE_OFFSET(txq_id); static const u32 zero_val[4] = {}; + trans_pcie->txq[txq_id].frozen_expiry_remainder = 0; + trans_pcie->txq[txq_id].frozen = false; + /* * Upon HW Rfkill - we stop the device, and then stop the queues * in the op_mode. Just for the sake of the simplicity of the op_mode, From c22b0ff572e4b3723a3c552e74a4ba2497606040 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 22 Jan 2015 13:15:15 +0200 Subject: [PATCH 051/567] iwlwifi: mvm: freeze the non-shared queues when a station goes to sleep When a station goes to sleep, we can't transmit any frame to it. This means that until that station will wake up, a queue that is dedicated to this station won't progress at all. Take this into account when monitoring stuck queues and don't account for the time the station was asleep. This allows to mask false positives where the queues are stuck not because of a bug, but because of the station being asleep. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 36 ++++++++++++++------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 7eab892de29b..6b3f4d0284a7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2427,25 +2427,35 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + unsigned long txqs = 0, tids = 0; int tid; + spin_lock_bh(&mvmsta->lock); + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { + struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; + + if (tid_data->state != IWL_AGG_ON && + tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) + continue; + + __set_bit(tid_data->txq_id, &txqs); + + if (iwl_mvm_tid_queued(tid_data) == 0) + continue; + + __set_bit(tid, &tids); + } + switch (cmd) { case STA_NOTIFY_SLEEP: if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) ieee80211_sta_block_awake(hw, sta, true); - spin_lock_bh(&mvmsta->lock); - for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { - struct iwl_mvm_tid_data *tid_data; - tid_data = &mvmsta->tid_data[tid]; - if (tid_data->state != IWL_AGG_ON && - tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) - continue; - if (iwl_mvm_tid_queued(tid_data) == 0) - continue; + for_each_set_bit(tid, &tids, IWL_MAX_TID_COUNT) ieee80211_sta_set_buffered(sta, tid, true); - } - spin_unlock_bh(&mvmsta->lock); + + if (txqs) + iwl_trans_freeze_txq_timer(mvm->trans, txqs, true); /* * The fw updates the STA to be asleep. Tx packets on the Tx * queues to this station will not be transmitted. The fw will @@ -2455,11 +2465,15 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, case STA_NOTIFY_AWAKE: if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) break; + + if (txqs) + iwl_trans_freeze_txq_timer(mvm->trans, txqs, false); iwl_mvm_sta_modify_ps_wake(mvm, sta); break; default: break; } + spin_unlock_bh(&mvmsta->lock); } static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, From 9b666db49253f7d65833dd02c00a2b026309c619 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 9 Mar 2015 12:37:59 +0200 Subject: [PATCH 052/567] iwlwifi: mvm: fix force NMI for 8000 The newer devices will enable a new register for this (DEVICE_SET_NMI_8000B_REG), but the interrupt handler isn't wired yet. Keep the old register for now. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-io.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 03250a45272e..78cac43e2bcd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -201,6 +201,8 @@ void iwl_force_nmi(struct iwl_trans *trans) } else { iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG, DEVICE_SET_NMI_8000B_VAL); + iwl_write_prph(trans, DEVICE_SET_NMI_REG, + DEVICE_SET_NMI_VAL_DRV); } } IWL_EXPORT_SYMBOL(iwl_force_nmi); From aee8bf5d269ace14f8b31daff34add21b802e7cd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 19 Feb 2015 15:00:18 +0200 Subject: [PATCH 053/567] iwlwifi: mvm: BT Coex - update the new API The firmware was not using the new API, so we don't need to differentiate between the different stages of this new API. The main difference here is that most of the hard coded values are not sent through the command anymore. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 220 ------------------ .../net/wireless/iwlwifi/mvm/coex_legacy.c | 59 +++++ drivers/net/wireless/iwlwifi/mvm/debugfs.c | 26 +-- .../net/wireless/iwlwifi/mvm/fw-api-coex.h | 47 ---- drivers/net/wireless/iwlwifi/mvm/mvm.h | 11 - 5 files changed, 65 insertions(+), 298 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index ce99572a982d..c7358a9d5b71 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -72,158 +72,6 @@ #include "mvm.h" #include "iwl-debug.h" -const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { - [BT_KILL_MSK_DEFAULT] = 0xfffffc00, - [BT_KILL_MSK_NEVER] = 0xffffffff, - [BT_KILL_MSK_ALWAYS] = 0, -}; - -const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { - { - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_ALWAYS, - }, - { - BT_KILL_MSK_NEVER, - BT_KILL_MSK_NEVER, - BT_KILL_MSK_NEVER, - }, - { - BT_KILL_MSK_NEVER, - BT_KILL_MSK_NEVER, - BT_KILL_MSK_NEVER, - }, - { - BT_KILL_MSK_DEFAULT, - BT_KILL_MSK_NEVER, - BT_KILL_MSK_DEFAULT, - }, -}; - -const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { - { - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_ALWAYS, - }, - { - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_ALWAYS, - }, - { - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_ALWAYS, - }, - { - BT_KILL_MSK_DEFAULT, - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_DEFAULT, - }, -}; - -static const __le32 iwl_bt_prio_boost[BT_COEX_BOOST_SIZE] = { - cpu_to_le32(0xf0f0f0f0), /* 50% */ - cpu_to_le32(0xc0c0c0c0), /* 25% */ - cpu_to_le32(0xfcfcfcfc), /* 75% */ - cpu_to_le32(0xfefefefe), /* 87.5% */ -}; - -static const __le32 iwl_single_shared_ant[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { - { - cpu_to_le32(0x40000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0x44000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0x40000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0x44000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0xc0004000), - cpu_to_le32(0xf0005000), - cpu_to_le32(0xc0004000), - cpu_to_le32(0xf0005000), - }, - { - cpu_to_le32(0x40000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0x44000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0x40000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0x44000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0xc0004000), - cpu_to_le32(0xf0005000), - cpu_to_le32(0xc0004000), - cpu_to_le32(0xf0005000), - }, - { - cpu_to_le32(0x40000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0x44000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0x40000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0x44000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0xc0004000), - cpu_to_le32(0xf0005000), - cpu_to_le32(0xc0004000), - cpu_to_le32(0xf0005000), - }, -}; - -static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { - { - /* Tight */ - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xaeaaaaaa), - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xcc00ff28), - cpu_to_le32(0x0000aaaa), - cpu_to_le32(0xcc00aaaa), - cpu_to_le32(0x0000aaaa), - cpu_to_le32(0xc0004000), - cpu_to_le32(0x00004000), - cpu_to_le32(0xf0005000), - cpu_to_le32(0xf0005000), - }, - { - /* Loose */ - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xcc00ff28), - cpu_to_le32(0x0000aaaa), - cpu_to_le32(0xcc00aaaa), - cpu_to_le32(0x0000aaaa), - cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), - cpu_to_le32(0xf0005000), - cpu_to_le32(0xf0005000), - }, - { - /* Tx Tx disabled */ - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xeeaaaaaa), - cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xcc00ff28), - cpu_to_le32(0x0000aaaa), - cpu_to_le32(0xcc00aaaa), - cpu_to_le32(0x0000aaaa), - cpu_to_le32(0xc0004000), - cpu_to_le32(0xc0004000), - cpu_to_le32(0xf0005000), - cpu_to_le32(0xf0005000), - }, -}; - /* 20MHz / 40MHz below / 40Mhz above*/ static const __le64 iwl_ci_mask[][3] = { /* dummy entry for channel 0 */ @@ -596,14 +444,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) goto send_cmd; } - bt_cmd->max_kill = cpu_to_le32(5); - bt_cmd->bt4_antenna_isolation_thr = - cpu_to_le32(IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS); - bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15); - bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15); - bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); - bt_cmd->override_secondary_lut = cpu_to_le32(BT_COEX_INVALID_LUT); - mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE; bt_cmd->mode = cpu_to_le32(mode); @@ -622,18 +462,6 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_HIGH_BAND_RET); - if (mvm->cfg->bt_shared_single_ant) - memcpy(&bt_cmd->decision_lut, iwl_single_shared_ant, - sizeof(iwl_single_shared_ant)); - else - memcpy(&bt_cmd->decision_lut, iwl_combined_lookup, - sizeof(iwl_combined_lookup)); - - memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost, - sizeof(iwl_bt_prio_boost)); - bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0); - bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1); - send_cmd: memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); @@ -644,48 +472,6 @@ send_cmd: return ret; } -static int iwl_mvm_bt_udpate_sw_boost(struct iwl_mvm *mvm) -{ - struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; - u32 primary_lut = le32_to_cpu(notif->primary_ch_lut); - u32 secondary_lut = le32_to_cpu(notif->secondary_ch_lut); - u32 ag = le32_to_cpu(notif->bt_activity_grading); - struct iwl_bt_coex_sw_boost_update_cmd cmd = {}; - u8 ack_kill_msk[NUM_PHY_CTX] = {}; - u8 cts_kill_msk[NUM_PHY_CTX] = {}; - int i; - - lockdep_assert_held(&mvm->mutex); - - ack_kill_msk[0] = iwl_bt_ack_kill_msk[ag][primary_lut]; - cts_kill_msk[0] = iwl_bt_cts_kill_msk[ag][primary_lut]; - - ack_kill_msk[1] = iwl_bt_ack_kill_msk[ag][secondary_lut]; - cts_kill_msk[1] = iwl_bt_cts_kill_msk[ag][secondary_lut]; - - /* Don't send HCMD if there is no update */ - if (!memcmp(ack_kill_msk, mvm->bt_ack_kill_msk, sizeof(ack_kill_msk)) || - !memcmp(cts_kill_msk, mvm->bt_cts_kill_msk, sizeof(cts_kill_msk))) - return 0; - - memcpy(mvm->bt_ack_kill_msk, ack_kill_msk, - sizeof(mvm->bt_ack_kill_msk)); - memcpy(mvm->bt_cts_kill_msk, cts_kill_msk, - sizeof(mvm->bt_cts_kill_msk)); - - BUILD_BUG_ON(ARRAY_SIZE(ack_kill_msk) < ARRAY_SIZE(cmd.boost_values)); - - for (i = 0; i < ARRAY_SIZE(cmd.boost_values); i++) { - cmd.boost_values[i].kill_ack_msk = - cpu_to_le32(iwl_bt_ctl_kill_msk[ack_kill_msk[i]]); - cmd.boost_values[i].kill_cts_msk = - cpu_to_le32(iwl_bt_ctl_kill_msk[cts_kill_msk[i]]); - } - - return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_SW_BOOST, 0, - sizeof(cmd), &cmd); -} - static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) { @@ -950,9 +736,6 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) IWL_ERR(mvm, "Failed to send BT_CI cmd\n"); memcpy(&mvm->last_bt_ci_cmd, &cmd, sizeof(cmd)); } - - if (iwl_mvm_bt_udpate_sw_boost(mvm)) - IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, @@ -1073,9 +856,6 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bt_rssi_iterator, &data); - - if (iwl_mvm_bt_udpate_sw_boost(mvm)) - IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 593bed7adad7..897dd5330b0d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -288,6 +288,65 @@ static const __le64 iwl_ci_mask[][3] = { }, }; +enum iwl_bt_kill_msk { + BT_KILL_MSK_DEFAULT, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_MAX, +}; + +static const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = { + [BT_KILL_MSK_DEFAULT] = 0xfffffc00, + [BT_KILL_MSK_NEVER] = 0xffffffff, + [BT_KILL_MSK_ALWAYS] = 0, +}; + +static const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + }, + { + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_NEVER, + }, + { + BT_KILL_MSK_DEFAULT, + BT_KILL_MSK_NEVER, + BT_KILL_MSK_DEFAULT, + }, +}; + +static const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT] = { + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_ALWAYS, + }, + { + BT_KILL_MSK_DEFAULT, + BT_KILL_MSK_ALWAYS, + BT_KILL_MSK_DEFAULT, + }, +}; + struct corunning_block_luts { u8 range; __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 8cbe77dc1dbb..8c5229892e57 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -562,11 +562,12 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, "\tSecondary Channel Bitmap 0x%016llx\n", le64_to_cpu(cmd->bt_secondary_ci)); - pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); - pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill Mask 0x%08x\n", - iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); - pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill Mask 0x%08x\n", - iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); + pos += scnprintf(buf+pos, bufsz-pos, + "BT Configuration CMD - 0=default, 1=never, 2=always\n"); + pos += scnprintf(buf+pos, bufsz-pos, "\tACK Kill msk idx %d\n", + mvm->bt_ack_kill_msk[0]); + pos += scnprintf(buf+pos, bufsz-pos, "\tCTS Kill msk idx %d\n", + mvm->bt_cts_kill_msk[0]); } else { struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; @@ -579,21 +580,6 @@ static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, pos += scnprintf(buf+pos, bufsz-pos, "\tSecondary Channel Bitmap 0x%016llx\n", le64_to_cpu(cmd->bt_secondary_ci)); - - pos += scnprintf(buf+pos, bufsz-pos, "BT Configuration CMD\n"); - pos += scnprintf(buf+pos, bufsz-pos, - "\tPrimary: ACK Kill Mask 0x%08x\n", - iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[0]]); - pos += scnprintf(buf+pos, bufsz-pos, - "\tPrimary: CTS Kill Mask 0x%08x\n", - iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[0]]); - pos += scnprintf(buf+pos, bufsz-pos, - "\tSecondary: ACK Kill Mask 0x%08x\n", - iwl_bt_ctl_kill_msk[mvm->bt_ack_kill_msk[1]]); - pos += scnprintf(buf+pos, bufsz-pos, - "\tSecondary: CTS Kill Mask 0x%08x\n", - iwl_bt_ctl_kill_msk[mvm->bt_cts_kill_msk[1]]); - } mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h index f3b11897991e..d398a6102805 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h @@ -235,36 +235,12 @@ enum iwl_bt_coex_enabled_modules { * struct iwl_bt_coex_cmd - bt coex configuration command * @mode: enum %iwl_bt_coex_mode * @enabled_modules: enum %iwl_bt_coex_enabled_modules - * @max_kill: max count of Tx retries due to kill from PTA - * @override_primary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT - * should be set by default - * @override_secondary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT - * should be set by default - * @bt4_antenna_isolation_thr: antenna threshold value - * @bt4_tx_tx_delta_freq_thr: TxTx delta frequency - * @bt4_tx_rx_max_freq0: TxRx max frequency - * @multiprio_lut: multi priority LUT configuration - * @mplut_prio_boost: BT priority boost registers - * @decision_lut: PTA decision LUT, per Prio-Ch * * The structure is used for the BT_COEX command. */ struct iwl_bt_coex_cmd { __le32 mode; __le32 enabled_modules; - - __le32 max_kill; - __le32 override_primary_lut; - __le32 override_secondary_lut; - __le32 bt4_antenna_isolation_thr; - - __le32 bt4_tx_tx_delta_freq_thr; - __le32 bt4_tx_rx_max_freq0; - - __le32 multiprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE]; - __le32 mplut_prio_boost[BT_COEX_BOOST_SIZE]; - - __le32 decision_lut[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE]; } __packed; /* BT_COEX_CMD_API_S_VER_6 */ /** @@ -279,29 +255,6 @@ struct iwl_bt_coex_corun_lut_update_cmd { __le32 corun_lut40[BT_COEX_CORUN_LUT_SIZE]; } __packed; /* BT_COEX_UPDATE_CORUN_LUT_API_S_VER_1 */ -/** - * struct iwl_bt_coex_sw_boost - SW boost values - * @wifi_tx_prio_boost: SW boost of wifi tx priority - * @wifi_rx_prio_boost: SW boost of wifi rx priority - * @kill_ack_msk: kill ACK mask. 1 - Tx ACK, 0 - kill Tx of ACK. - * @kill_cts_msk: kill CTS mask. 1 - Tx CTS, 0 - kill Tx of CTS. - */ -struct iwl_bt_coex_sw_boost { - __le32 wifi_tx_prio_boost; - __le32 wifi_rx_prio_boost; - __le32 kill_ack_msk; - __le32 kill_cts_msk; -}; - -/** - * struct iwl_bt_coex_sw_boost_update_cmd - command to update the SW boost - * @boost_values: check struct %iwl_bt_coex_sw_boost - one for each channel - * primary / secondary / low priority - */ -struct iwl_bt_coex_sw_boost_update_cmd { - struct iwl_bt_coex_sw_boost boost_values[3]; -} __packed; /* BT_COEX_UPDATE_SW_BOOST_S_VER_1 */ - /** * struct iwl_bt_coex_reduced_txp_update_cmd * @reduced_txp: bit BT_REDUCED_TX_POWER_BIT to enable / disable, rest of the diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 52135a4fd8d3..432265eb0dd7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1315,17 +1315,6 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); -enum iwl_bt_kill_msk { - BT_KILL_MSK_DEFAULT, - BT_KILL_MSK_NEVER, - BT_KILL_MSK_ALWAYS, - BT_KILL_MSK_MAX, -}; - -extern const u8 iwl_bt_ack_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT]; -extern const u8 iwl_bt_cts_kill_msk[BT_MAX_AG][BT_COEX_MAX_LUT]; -extern const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX]; - /* beacon filtering */ #ifdef CONFIG_IWLWIFI_DEBUGFS void From 2bccec4e1283fc74d2b52c0534816c8ad0f9ac3f Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Mon, 9 Mar 2015 11:25:59 +0200 Subject: [PATCH 054/567] iwlwifi: add more new 8260 series PCI IDs More sub system IDs were introduced for the 8260 series. Add the new sub system IDs so the cards can be recognized. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 3f9289d35de8..2794cd2d3a64 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -414,9 +414,14 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 8000 Series */ {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0110, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x1110, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0250, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x1050, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0150, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)}, @@ -434,6 +439,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)}, {IWL_PCI_DEVICE(0x24F3, 0x0810, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0910, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0850, iwl8260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x24F3, 0x0950, iwl8260_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ {0} From 82f0a9e602216e9216fa81a98bd3e38b030964cb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 8 Mar 2015 14:18:17 +0200 Subject: [PATCH 055/567] iwlwifi: update copyright to include 2015 Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index adf522c756e6..67a3a241b331 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -68,7 +68,7 @@ /* for all modules */ #define DRV_NAME "iwlwifi" -#define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003- 2015 Intel Corporation" #define DRV_AUTHOR "" /* radio config bits (actual values from NVM definition) */ From f4a3ee493e69239ad9e76e42524d08c58ac31f11 Mon Sep 17 00:00:00 2001 From: Eran Harary Date: Sun, 8 Feb 2015 13:58:50 +0200 Subject: [PATCH 056/567] iwlwifi: mvm: Always enable the smart FIFO We previously enabled the smart FIFO (SF) in BSS only after association. This cause interrupt latency on P2P on certain devices. Change the working model to enable the SF all the time and play with the timeout values based on the association state. This change was not tested on older firwmares, so make it happen only on -13.ucode and up. Signed-off-by: Eran Harary Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api.h | 14 ++++- drivers/net/wireless/iwlwifi/mvm/sf.c | 64 +++++++++++++++++++---- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index d89b0dd9e728..aab68cbae754 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -1447,7 +1447,19 @@ enum iwl_sf_scenario { #define SF_W_MARK_LEGACY 4096 #define SF_W_MARK_SCAN 4096 -/* SF Scenarios timers for FULL_ON state (aligned to 32 uSec) */ +/* SF Scenarios timers for default configuration (aligned to 32 uSec) */ +#define SF_SINGLE_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ +#define SF_SINGLE_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ +#define SF_AGG_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ +#define SF_AGG_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ +#define SF_MCAST_IDLE_TIMER_DEF 160 /* 150 mSec */ +#define SF_MCAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ +#define SF_BA_IDLE_TIMER_DEF 160 /* 150 uSec */ +#define SF_BA_AGING_TIMER_DEF 400 /* 0.4 mSec */ +#define SF_TX_RE_IDLE_TIMER_DEF 160 /* 150 uSec */ +#define SF_TX_RE_AGING_TIMER_DEF 400 /* 0.4 mSec */ + +/* SF Scenarios timers for BSS MAC configuration (aligned to 32 uSec) */ #define SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */ #define SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */ #define SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */ diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index 4b9f6c6fb614..b0f59fdd287c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -99,7 +99,35 @@ static void iwl_mvm_bound_iface_iterator(void *_data, u8 *mac, /* * Aging and idle timeouts for the different possible scenarios - * in SF_FULL_ON state. + * in default configuration + */ +static const +__le32 sf_full_timeout_def[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = { + { + cpu_to_le32(SF_SINGLE_UNICAST_AGING_TIMER_DEF), + cpu_to_le32(SF_SINGLE_UNICAST_IDLE_TIMER_DEF) + }, + { + cpu_to_le32(SF_AGG_UNICAST_AGING_TIMER_DEF), + cpu_to_le32(SF_AGG_UNICAST_IDLE_TIMER_DEF) + }, + { + cpu_to_le32(SF_MCAST_AGING_TIMER_DEF), + cpu_to_le32(SF_MCAST_IDLE_TIMER_DEF) + }, + { + cpu_to_le32(SF_BA_AGING_TIMER_DEF), + cpu_to_le32(SF_BA_IDLE_TIMER_DEF) + }, + { + cpu_to_le32(SF_TX_RE_AGING_TIMER_DEF), + cpu_to_le32(SF_TX_RE_IDLE_TIMER_DEF) + }, +}; + +/* + * Aging and idle timeouts for the different possible scenarios + * in single BSS MAC configuration. */ static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = { { @@ -124,7 +152,8 @@ static const __le32 sf_full_timeout[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES] = { }, }; -static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd, +static void iwl_mvm_fill_sf_command(struct iwl_mvm *mvm, + struct iwl_sf_cfg_cmd *sf_cmd, struct ieee80211_sta *sta) { int i, j, watermark; @@ -163,22 +192,37 @@ static void iwl_mvm_fill_sf_command(struct iwl_sf_cfg_cmd *sf_cmd, cpu_to_le32(SF_LONG_DELAY_AGING_TIMER); } } - BUILD_BUG_ON(sizeof(sf_full_timeout) != - sizeof(__le32) * SF_NUM_SCENARIO * SF_NUM_TIMEOUT_TYPES); - memcpy(sf_cmd->full_on_timeouts, sf_full_timeout, - sizeof(sf_full_timeout)); + if (sta || IWL_UCODE_API(mvm->fw->ucode_ver) < 13) { + BUILD_BUG_ON(sizeof(sf_full_timeout) != + sizeof(__le32) * SF_NUM_SCENARIO * + SF_NUM_TIMEOUT_TYPES); + + memcpy(sf_cmd->full_on_timeouts, sf_full_timeout, + sizeof(sf_full_timeout)); + } else { + BUILD_BUG_ON(sizeof(sf_full_timeout_def) != + sizeof(__le32) * SF_NUM_SCENARIO * + SF_NUM_TIMEOUT_TYPES); + + memcpy(sf_cmd->full_on_timeouts, sf_full_timeout_def, + sizeof(sf_full_timeout_def)); + } + } static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, enum iwl_sf_state new_state) { struct iwl_sf_cfg_cmd sf_cmd = { - .state = cpu_to_le32(new_state), + .state = cpu_to_le32(SF_FULL_ON), }; struct ieee80211_sta *sta; int ret = 0; + if (IWL_UCODE_API(mvm->fw->ucode_ver) < 13) + sf_cmd.state = cpu_to_le32(new_state); + if (mvm->cfg->disable_dummy_notification) sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); @@ -191,6 +235,8 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, switch (new_state) { case SF_UNINIT: + if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 13) + iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL); break; case SF_FULL_ON: if (sta_id == IWL_MVM_STATION_COUNT) { @@ -205,11 +251,11 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, rcu_read_unlock(); return -EINVAL; } - iwl_mvm_fill_sf_command(&sf_cmd, sta); + iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta); rcu_read_unlock(); break; case SF_INIT_OFF: - iwl_mvm_fill_sf_command(&sf_cmd, NULL); + iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL); break; default: WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n", From bca13904d0558ad4160441ebb00b37e44a19483f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 11 Mar 2015 20:27:06 +0100 Subject: [PATCH 057/567] iwlwifi: mvm: clarify time event end handling The code here is a little confusing, the iwl_mvm_te_check_disconnect() will check that the interface is a station, but going into it after already having processed the time even end for P2P seems strange at first look. Put a switch statement there to distinguish the interface types and make this more readable. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/time-event.c | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 54fafbf9a711..1dbfcc43d82c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -261,17 +261,23 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, "TE ended - current time %lu, estimated end %lu\n", jiffies, te_data->end_jiffies); - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { + switch (te_data->vif->type) { + case NL80211_IFTYPE_P2P_DEVICE: ieee80211_remain_on_channel_expired(mvm->hw); iwl_mvm_roc_finished(mvm); + break; + case NL80211_IFTYPE_STATION: + /* + * By now, we should have finished association + * and know the dtim period. + */ + iwl_mvm_te_check_disconnect(mvm, te_data->vif, + "No association and the time event is over already..."); + break; + default: + break; } - /* - * By now, we should have finished association - * and know the dtim period. - */ - iwl_mvm_te_check_disconnect(mvm, te_data->vif, - "No association and the time event is over already..."); iwl_mvm_te_clear_data(mvm, te_data); } else if (le32_to_cpu(notif->action) & TE_V2_NOTIF_HOST_EVENT_START) { te_data->running = true; From 0c2ae049aef7fe1b8800db3f28c23520150bfd78 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 12 Mar 2015 09:25:15 +0200 Subject: [PATCH 058/567] iwlwifi: mvm: don't double unlock the mutex in __iwl_mvm_resume() When IWLWIFI_DEBUGFS is not set, we should not unlock the mutex after calling iwl_mvm_query_wakeup_reasons(), because this function unlocks it already. Move the goto out_iterate outside the #ifdef. Change-Id: I13d86402aecf0eeec44b1abbe2b244fbc706a5eb Signed-off-by: Luciano Coelho --- drivers/net/wireless/iwlwifi/mvm/d3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 486fd4c259c3..e3c308435bee 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1892,9 +1892,9 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) #ifdef CONFIG_IWLWIFI_DEBUGFS if (keep) mvm->keep_vif = vif; +#endif /* has unlocked the mutex, so skip that */ goto out_iterate; -#endif } out_unlock: From e111e9685790ccd9acce5de51fa7ed6b9ae8a746 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 3 Mar 2015 20:23:47 +0100 Subject: [PATCH 059/567] iwlwifi: mvm: simplify iwl_mvm_get_wakeup_status() return The return value in iwl_mvm_get_wakeup_status() is a bit unclear in that it's not obvious that we don't leak fw_status in some cases. Use fw_status directly with ERR_PTR() and return only it, that way the compiler has a chance of proving that it's uninitialized (if it ever is due to new changes.) Additionally, this removes a smatch warning since smatch couldn't figure out that fw_status can't, in fact, leak here. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index e3c308435bee..5f8afa5f11a3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1599,7 +1599,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) /* RF-kill already asserted again... */ if (!cmd.resp_pkt) { - ret = -ERFKILL; + fw_status = ERR_PTR(-ERFKILL); goto out_free_resp; } @@ -1608,7 +1608,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) len = iwl_rx_packet_payload_len(cmd.resp_pkt); if (len < status_size) { IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); - ret = -EIO; + fw_status = ERR_PTR(-EIO); goto out_free_resp; } @@ -1616,7 +1616,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (len != (status_size + ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4))) { IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); - ret = -EIO; + fw_status = ERR_PTR(-EIO); goto out_free_resp; } @@ -1624,7 +1624,7 @@ iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) out_free_resp: iwl_free_resp(&cmd); - return ret ? ERR_PTR(ret) : fw_status; + return fw_status; } /* releases the MVM mutex */ From 3a43477fa36eee2997313380cb52f486e2bff316 Mon Sep 17 00:00:00 2001 From: Roger Tseng Date: Fri, 6 Mar 2015 11:36:06 +0800 Subject: [PATCH 060/567] mfd: rtsx_usb: Prevent DMA from stack Functions rtsx_usb_ep0_read_register() and rtsx_usb_get_card_status() both use arbitrary buffer addresses from arguments directly for DMA and the buffers could be located in stack. This was caught by DMA-API debug check. Fixes this by using double-buffers via kzalloc in both functions to guarantee the validity of DMA buffer. WARNING: CPU: 1 PID: 25 at lib/dma-debug.c:1166 check_for_stack+0x96/0xe0() ehci-pci 0000:00:1a.0: DMA-API: device driver maps memory from stack [addr=ffff8801199e3cef] Modules linked in: rtsx_usb_ms arc4 memstick intel_rapl iosf_mbi rtl8192ce snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel rtl_pci rtl8192c_common snd_hda_controller x86_pkg_temp_thermal snd_hda_codec rtlwifi mac80211 coretemp kvm_intel kvm iTCO_wdt snd_hwdep snd_seq snd_seq_device crct10dif_pclmul iTCO_vendor_support sparse_keymap cfg80211 crc32_pclmul snd_pcm crc32c_intel ghash_clmulni_intel rfkill i2c_i801 snd_timer shpchp snd serio_raw mei_me lpc_ich soundcore mei tpm_tis tpm wmi nfsd auth_rpcgss nfs_acl lockd grace sunrpc i915 rtsx_usb_sdmmc mmc_core 8021q uas garp stp i2c_algo_bit llc mrp drm_kms_helper usb_storage drm rtsx_usb mfd_core r8169 mii video CPU: 1 PID: 25 Comm: kworker/1:2 Not tainted 3.20.0-0.rc0.git7.3.fc22.x86_64 #1 Hardware name: WB WB-B06211/WB-B0621, BIOS EB062IWB V1.0 12/12/2013 Workqueue: events rtsx_usb_ms_handle_req [rtsx_usb_ms] 0000000000000000 000000003d188e66 ffff8801199e3808 ffffffff8187642b 0000000000000000 ffff8801199e3860 ffff8801199e3848 ffffffff810ab39a ffff8801199e3864 ffff8801199e3cef ffff880119b57098 ffff880119b37320 Call Trace: [] dump_stack+0x4c/0x65 [] warn_slowpath_common+0x8a/0xc0 [] warn_slowpath_fmt+0x55/0x70 [] ? _raw_spin_unlock_irqrestore+0x36/0x70 [] check_for_stack+0x96/0xe0 [] debug_dma_map_page+0x104/0x150 [] usb_hcd_map_urb_for_dma+0x646/0x790 [] usb_hcd_submit_urb+0x1d5/0xa90 [] ? mark_held_locks+0x7f/0xc0 [] ? mark_held_locks+0x7f/0xc0 [] ? lockdep_init_map+0x65/0x5d0 [] usb_submit_urb+0x42e/0x5f0 [] usb_start_wait_urb+0x77/0x190 [] ? __kmalloc+0x205/0x2d0 [] usb_control_msg+0xdc/0x130 [] rtsx_usb_ep0_read_register+0x59/0x70 [rtsx_usb] [] ? rtsx_usb_get_rsp+0x41/0x50 [rtsx_usb] [] rtsx_usb_ms_handle_req+0x7ce/0x9c5 [rtsx_usb_ms] Reported-by: Josh Boyer Signed-off-by: Roger Tseng Signed-off-by: Lee Jones --- drivers/mfd/rtsx_usb.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c index ede50244f265..dbd907d7170e 100644 --- a/drivers/mfd/rtsx_usb.c +++ b/drivers/mfd/rtsx_usb.c @@ -196,18 +196,27 @@ EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register); int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data) { u16 value; + u8 *buf; + int ret; if (!data) return -EINVAL; - *data = 0; + + buf = kzalloc(sizeof(u8), GFP_KERNEL); + if (!buf) + return -ENOMEM; addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT; value = swab16(addr); - return usb_control_msg(ucr->pusb_dev, + ret = usb_control_msg(ucr->pusb_dev, usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, 0, data, 1, 100); + value, 0, buf, 1, 100); + *data = *buf; + + kfree(buf); + return ret; } EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register); @@ -288,18 +297,27 @@ static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status) int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status) { int ret; + u16 *buf; if (!status) return -EINVAL; - if (polling_pipe == 0) + if (polling_pipe == 0) { + buf = kzalloc(sizeof(u16), GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = usb_control_msg(ucr->pusb_dev, usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_POLL, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, 0, status, 2, 100); - else + 0, 0, buf, 2, 100); + *status = *buf; + + kfree(buf); + } else { ret = rtsx_usb_get_status_with_bulk(ucr, status); + } /* usb_control_msg may return positive when success */ if (ret < 0) From c8648508ebfc597058d2cd00b6c539110264a167 Mon Sep 17 00:00:00 2001 From: Ameya Palande <2ameya@gmail.com> Date: Thu, 26 Feb 2015 12:05:51 -0800 Subject: [PATCH 061/567] mfd: kempld-core: Fix callback return value check On success, callback function returns 0. So invert the if condition check so that we can break out of loop. Cc: stable@vger.kernel.org Signed-off-by: Ameya Palande <2ameya@gmail.com> Signed-off-by: Lee Jones --- drivers/mfd/kempld-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index f38ec424872e..5615522f8d62 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -739,7 +739,7 @@ static int __init kempld_init(void) for (id = kempld_dmi_table; id->matches[0].slot != DMI_NONE; id++) if (strstr(id->ident, force_device_id)) - if (id->callback && id->callback(id)) + if (id->callback && !id->callback(id)) break; if (id->matches[0].slot == DMI_NONE) return -ENODEV; From 0a64815091bd0ad6c6cdfaac2fae55b0f3ecf974 Mon Sep 17 00:00:00 2001 From: Hendrik Brueckner Date: Mon, 9 Mar 2015 17:34:18 +0100 Subject: [PATCH 062/567] s390/cpum_sf: add diagnostic sampling event only if it is authorized The SF_CYCLES_BASIC_DIAG is always registered even if it is turned of in the current hardware configuration. Because diagnostic-sampling is typically not turned on in the hardware configuration, do not register this perf event by default. Enable it only if the diagnostic-sampling function is authorized. Signed-off-by: Hendrik Brueckner Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/perf_cpum_sf.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index c3f8d157cb0d..e6a1578fc000 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -1415,7 +1415,7 @@ CPUMF_EVENT_ATTR(SF, SF_CYCLES_BASIC_DIAG, PERF_EVENT_CPUM_SF_DIAG); static struct attribute *cpumsf_pmu_events_attr[] = { CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC), - CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG), + NULL, NULL, }; @@ -1606,8 +1606,11 @@ static int __init init_cpum_sampling_pmu(void) return -EINVAL; } - if (si.ad) + if (si.ad) { sfb_set_limits(CPUM_SF_MIN_SDB, CPUM_SF_MAX_SDB); + cpumsf_pmu_events_attr[1] = + CPUMF_EVENT_PTR(SF, SF_CYCLES_BASIC_DIAG); + } sfdbg = debug_register(KMSG_COMPONENT, 2, 1, 80); if (!sfdbg) From 20e76ee184a7cea155268377c4e414eea1dab6fd Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 13 Mar 2015 10:31:42 +0100 Subject: [PATCH 063/567] s390/ftrace: fix compile error if CONFIG_KPROBES is disabled Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/ftrace.c | 61 +++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 82c19899574f..6c79f1b44fe7 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -57,6 +57,44 @@ unsigned long ftrace_plt; +static inline void ftrace_generate_orig_insn(struct ftrace_insn *insn) +{ +#ifdef CC_USING_HOTPATCH + /* brcl 0,0 */ + insn->opc = 0xc004; + insn->disp = 0; +#else + /* stg r14,8(r15) */ + insn->opc = 0xe3e0; + insn->disp = 0xf0080024; +#endif +} + +static inline int is_kprobe_on_ftrace(struct ftrace_insn *insn) +{ +#ifdef CONFIG_KPROBES + if (insn->opc == BREAKPOINT_INSTRUCTION) + return 1; +#endif + return 0; +} + +static inline void ftrace_generate_kprobe_nop_insn(struct ftrace_insn *insn) +{ +#ifdef CONFIG_KPROBES + insn->opc = BREAKPOINT_INSTRUCTION; + insn->disp = KPROBE_ON_FTRACE_NOP; +#endif +} + +static inline void ftrace_generate_kprobe_call_insn(struct ftrace_insn *insn) +{ +#ifdef CONFIG_KPROBES + insn->opc = BREAKPOINT_INSTRUCTION; + insn->disp = KPROBE_ON_FTRACE_CALL; +#endif +} + int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr) { @@ -72,16 +110,9 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, return -EFAULT; if (addr == MCOUNT_ADDR) { /* Initial code replacement */ -#ifdef CC_USING_HOTPATCH - /* We expect to see brcl 0,0 */ - ftrace_generate_nop_insn(&orig); -#else - /* We expect to see stg r14,8(r15) */ - orig.opc = 0xe3e0; - orig.disp = 0xf0080024; -#endif + ftrace_generate_orig_insn(&orig); ftrace_generate_nop_insn(&new); - } else if (old.opc == BREAKPOINT_INSTRUCTION) { + } else if (is_kprobe_on_ftrace(&old)) { /* * If we find a breakpoint instruction, a kprobe has been * placed at the beginning of the function. We write the @@ -89,9 +120,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, * bytes of the original instruction so that the kprobes * handler can execute a nop, if it reaches this breakpoint. */ - new.opc = orig.opc = BREAKPOINT_INSTRUCTION; - orig.disp = KPROBE_ON_FTRACE_CALL; - new.disp = KPROBE_ON_FTRACE_NOP; + ftrace_generate_kprobe_call_insn(&orig); + ftrace_generate_kprobe_nop_insn(&new); } else { /* Replace ftrace call with a nop. */ ftrace_generate_call_insn(&orig, rec->ip); @@ -111,7 +141,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) return -EFAULT; - if (old.opc == BREAKPOINT_INSTRUCTION) { + if (is_kprobe_on_ftrace(&old)) { /* * If we find a breakpoint instruction, a kprobe has been * placed at the beginning of the function. We write the @@ -119,9 +149,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) * bytes of the original instruction so that the kprobes * handler can execute a brasl if it reaches this breakpoint. */ - new.opc = orig.opc = BREAKPOINT_INSTRUCTION; - orig.disp = KPROBE_ON_FTRACE_NOP; - new.disp = KPROBE_ON_FTRACE_CALL; + ftrace_generate_kprobe_nop_insn(&orig); + ftrace_generate_kprobe_call_insn(&new); } else { /* Replace nop with an ftrace call. */ ftrace_generate_nop_insn(&orig); From e143fa93c28669a7f0851e6850b1da5b1945fd53 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 13 Mar 2015 11:19:09 +0100 Subject: [PATCH 064/567] s390/mm: limit STACK_RND_MASK for compat tasks For compat tasks the mmap randomization does not use the maximum randomization value from mmap_rnd_mask but the fixed value of 0x7ff. This needs to be respected in the definition of STACK_RND_MASK as well. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index c9df40b5c0ac..c9c875d9ed31 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -211,7 +211,7 @@ do { \ extern unsigned long mmap_rnd_mask; -#define STACK_RND_MASK (mmap_rnd_mask) +#define STACK_RND_MASK (test_thread_flag(TIF_31BIT) ? 0x7ff : mmap_rnd_mask) #define ARCH_DLINFO \ do { \ From 4a2f248f9eafcf64c7649324a294a4dd337efd18 Mon Sep 17 00:00:00 2001 From: Sergey Ryazanov Date: Wed, 4 Mar 2015 05:12:10 +0300 Subject: [PATCH 065/567] ath5k: channel change fix ath5k updates the channel pointer and after that it stops the Rx logic and apply channel to HW. In case of channel switch, such sequence creates a small window when a frame, which is received on the old channel is considered as a frame received on the new one. The most notable consequence of this situation occurs during the switch from 2 GHz band (CCK+OFDM) to the 5GHz band (OFDM-only). Frame received with CCK rate, e.g. beacon received at the 1mbps, causes the following warning: WARNING: at ath5k/base.c:589 ath5k_tasklet_rx+0x318/0x6ec [ath5k]() invalid hw_rix: 1a [..] Call Trace: [<802656a8>] show_stack+0x48/0x70 [<802dd92c>] warn_slowpath_common+0x88/0xbc [<802dd98c>] warn_slowpath_fmt+0x2c/0x38 [<81b51be8>] ath5k_tasklet_rx+0x318/0x6ec [ath5k] [<8028ac64>] tasklet_action+0x8c/0xf0 [<80075804>] __do_softirq+0x180/0x32c [<80196ce8>] irq_exit+0x54/0x70 [<80041848>] ret_from_irq+0x0/0x4 [<80182fdc>] ioread32+0x4/0xc [<81b4c42c>] ath5k_hw_set_sleep_clock+0x2ec/0x474 [ath5k] [<81b4cf28>] ath5k_hw_reset+0x50/0xeb8 [ath5k] [<81b50900>] ath5k_reset+0xd4/0x310 [ath5k] [<81b557e8>] ath5k_config+0x4c/0x104 [ath5k] [<80d01770>] ieee80211_hw_config+0x2f4/0x35c [mac80211] [<80d09aa8>] ieee80211_scan_work+0x2e4/0x414 [mac80211] [<8022c3f4>] process_one_work+0x28c/0x400 [<802df8f8>] worker_thread+0x258/0x3c0 [<801b5710>] kthread+0xe0/0xec [<800418a8>] ret_from_kernel_thread+0x14/0x1c The easiest way to reproduce this warning is to run scan with dualband NIC in noisy environments, when the channel 11 runs multiple APs. In my tests if the APs num >= 12, the warning appears in the first few seconds of scanning. In order to fix this, the Rx disable code moved to a higher level and placed before the channel pointer update. This is also makes the code a bit more symmetrical, since we disable and enable the Rx in the same function. In fact, at the pointer update time new frames should not appear, because interrupt generation at this point should already be disabled. The next patch should address this issue. CC: Jiri Slaby CC: Nick Kossifidis CC: Luis R. Rodriguez Reported-by: Christophe Prevotaux Tested-by: Christophe Prevotaux Tested-by: Eric Bree Signed-off-by: Sergey Ryazanov Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath5k/base.c | 24 +++++++++++++++++++++--- drivers/net/wireless/ath/ath5k/reset.c | 24 ------------------------ 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 57a80e89822d..c186963ad7c0 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2858,7 +2858,7 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, { struct ath_common *common = ath5k_hw_common(ah); int ret, ani_mode; - bool fast; + bool fast = chan && modparam_fastchanswitch ? 1 : 0; ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "resetting\n"); @@ -2876,11 +2876,29 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, * so we should also free any remaining * tx buffers */ ath5k_drain_tx_buffs(ah); + + /* Stop PCU */ + ath5k_hw_stop_rx_pcu(ah); + + /* Stop DMA + * + * Note: If DMA didn't stop continue + * since only a reset will fix it. + */ + ret = ath5k_hw_dma_stop(ah); + + /* RF Bus grant won't work if we have pending + * frames + */ + if (ret && fast) { + ATH5K_DBG(ah, ATH5K_DEBUG_RESET, + "DMA didn't stop, falling back to normal reset\n"); + fast = false; + } + if (chan) ah->curchan = chan; - fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0; - ret = ath5k_hw_reset(ah, ah->opmode, ah->curchan, fast, skip_pcu); if (ret) { ATH5K_ERR(ah, "can't reset hardware (%d)\n", ret); diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index b9b651ea9851..99e62f99a182 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1169,30 +1169,6 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, if (ah->ah_version == AR5K_AR5212) ath5k_hw_set_sleep_clock(ah, false); - /* - * Stop PCU - */ - ath5k_hw_stop_rx_pcu(ah); - - /* - * Stop DMA - * - * Note: If DMA didn't stop continue - * since only a reset will fix it. - */ - ret = ath5k_hw_dma_stop(ah); - - /* RF Bus grant won't work if we have pending - * frames */ - if (ret && fast) { - ATH5K_DBG(ah, ATH5K_DEBUG_RESET, - "DMA didn't stop, falling back to normal reset\n"); - fast = false; - /* Non fatal, just continue with - * normal reset */ - ret = 0; - } - mode = channel->hw_value; switch (mode) { case AR5K_MODE_11A: From ab5e290a86075c09201deb55c566f875ef4649d7 Mon Sep 17 00:00:00 2001 From: Sergey Ryazanov Date: Wed, 4 Mar 2015 05:12:11 +0300 Subject: [PATCH 066/567] ath5k: fix reset race To prepare for reset ath5k should finish all asynchronous tasks. At first, it disables the interrupt generation, then it waits for the interrupt handler and tasklets completion, and then proceeds to the HW configuration update. But it does not consider that the interrupt handler or tasklet re-enables the interrupt generation. And we fall in a situation when ath5k assumes that interrupts are disabled, but it is not. This can lead to different consequences, such as reception of the frame, when we do not expect it. Under certain circumstances, this can lead to the following warning: WARNING: at ath5k/base.c:589 ath5k_tasklet_rx+0x318/0x6ec [ath5k]() invalid hw_rix: 1a [..] Call Trace: [<802656a8>] show_stack+0x48/0x70 [<802dd92c>] warn_slowpath_common+0x88/0xbc [<802dd98c>] warn_slowpath_fmt+0x2c/0x38 [<81b51be8>] ath5k_tasklet_rx+0x318/0x6ec [ath5k] [<8028ac64>] tasklet_action+0x8c/0xf0 [<80075804>] __do_softirq+0x180/0x32c [<80196ce8>] irq_exit+0x54/0x70 [<80041848>] ret_from_irq+0x0/0x4 [<80182fdc>] ioread32+0x4/0xc [<81b4c42c>] ath5k_hw_set_sleep_clock+0x2ec/0x474 [ath5k] [<81b4cf28>] ath5k_hw_reset+0x50/0xeb8 [ath5k] [<81b50900>] ath5k_reset+0xd4/0x310 [ath5k] [<81b557e8>] ath5k_config+0x4c/0x104 [ath5k] [<80d01770>] ieee80211_hw_config+0x2f4/0x35c [mac80211] [<80d09aa8>] ieee80211_scan_work+0x2e4/0x414 [mac80211] [<8022c3f4>] process_one_work+0x28c/0x400 [<802df8f8>] worker_thread+0x258/0x3c0 [<801b5710>] kthread+0xe0/0xec [<800418a8>] ret_from_kernel_thread+0x14/0x1c Fix this issue by adding a new status flag, which forbids to re-enable the interrupt generation until the HW configuration is completed. Note: previous patch, which reorders the Rx disable code helps to avoid the above warning, but not fixes the root cause of unexpected frame receiving. CC: Jiri Slaby CC: Nick Kossifidis CC: Luis R. Rodriguez Reported-by: Christophe Prevotaux Tested-by: Christophe Prevotaux Tested-by: Eric Bree Signed-off-by: Sergey Ryazanov Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 + drivers/net/wireless/ath/ath5k/base.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 1ed7a88aeea9..7ca0d6f930fd 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1283,6 +1283,7 @@ struct ath5k_hw { #define ATH_STAT_PROMISC 1 #define ATH_STAT_LEDSOFT 2 /* enable LED gpio status */ #define ATH_STAT_STARTED 3 /* opened & irqs enabled */ +#define ATH_STAT_RESET 4 /* hw reset */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ unsigned int fif_filter_flags; /* Current FIF_* filter flags */ diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c186963ad7c0..a6131825c9f6 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1523,6 +1523,9 @@ ath5k_set_current_imask(struct ath5k_hw *ah) enum ath5k_int imask; unsigned long flags; + if (test_bit(ATH_STAT_RESET, ah->status)) + return; + spin_lock_irqsave(&ah->irqlock, flags); imask = ah->imask; if (ah->rx_pending) @@ -2862,6 +2865,8 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "resetting\n"); + __set_bit(ATH_STAT_RESET, ah->status); + ath5k_hw_set_imr(ah, 0); synchronize_irq(ah->irq); ath5k_stop_tasklets(ah); @@ -2952,6 +2957,8 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, */ /* ath5k_chan_change(ah, c); */ + __clear_bit(ATH_STAT_RESET, ah->status); + ath5k_beacon_config(ah); /* intrs are enabled by ath5k_beacon_config */ From 933ef44cb130b28f88ab92900bda1176ed758854 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sat, 7 Mar 2015 00:47:17 +0900 Subject: [PATCH 067/567] rtlwifi: Remove duplicated prototype Remove duplicated prototype in base.h Signed-off-by: Taehee Yoo Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/base.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index dee4ac2f27e2..ff9a4bfd4515 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -123,7 +123,6 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb); -void rtl_watch_dog_timer_callback(unsigned long data); int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, From de6878c8354d1524940055fe1b802c799f4fc318 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Fri, 6 Mar 2015 18:40:38 +0100 Subject: [PATCH 068/567] brcmfmac: Fix oops when SDIO device is removed. On removal of SDIO card both functions of card will be getting a remove call. When the first is hanging in ctrl frame xmit then the second will cause oops. This patch fixes the xmit ctrl handling in case of serious errors and also limits the handling for remove to function 1 only. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 2 +- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index c438ccdb6ed8..ffb0e2d382ea 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1194,7 +1194,7 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func) brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); brcmf_dbg(SDIO, "Function: %d\n", func->num); - if (func->num != 1 && func->num != 2) + if (func->num != 1) return; bus_if = dev_get_drvdata(&func->dev); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 257ee70feb5b..c54ba4f8b489 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -2740,6 +2740,11 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) if ((bus->sdiodev->state != BRCMF_SDIOD_DATA) || (err != 0)) { brcmf_err("failed backplane access over SDIO, halting operation\n"); atomic_set(&bus->intstatus, 0); + if (bus->ctrl_frame_stat) { + bus->ctrl_frame_err = -ENODEV; + bus->ctrl_frame_stat = false; + brcmf_sdio_wait_event_wakeup(bus); + } } else if (atomic_read(&bus->intstatus) || atomic_read(&bus->ipend) > 0 || (!atomic_read(&bus->fcstate) && From b441ba8dc34136dc418d85299757514c3a08913d Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Fri, 6 Mar 2015 18:40:39 +0100 Subject: [PATCH 069/567] brcmfmac: Simplify watchdog sleep. The watchdog thread is used to put the SDIO bus to sleep when the system is idling. This patch simplifies the way it is determined when sleep can be entered. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/brcm80211/brcmfmac/sdio.c | 60 +++++++------------ 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index c54ba4f8b489..161acd046451 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -485,10 +485,9 @@ struct brcmf_sdio { #endif /* DEBUG */ uint clkstate; /* State of sd and backplane clock(s) */ - bool activity; /* Activity flag for clock down */ s32 idletime; /* Control for activity timeout */ - s32 idlecount; /* Activity timeout counter */ - s32 idleclock; /* How to set bus driver when idle */ + s32 idlecount; /* Activity timeout counter */ + s32 idleclock; /* How to set bus driver when idle */ bool rxflow_mode; /* Rx flow control mode */ bool rxflow; /* Is rx flow control on */ bool alp_only; /* Don't use HT clock (ALP only) */ @@ -511,6 +510,7 @@ struct brcmf_sdio { struct workqueue_struct *brcmf_wq; struct work_struct datawork; atomic_t dpc_tskcnt; + atomic_t dpc_running; bool txoff; /* Transmit flow-controlled */ struct brcmf_sdio_count sdcnt; @@ -959,13 +959,8 @@ static int brcmf_sdio_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) brcmf_dbg(SDIO, "Enter\n"); /* Early exit if we're already there */ - if (bus->clkstate == target) { - if (target == CLK_AVAIL) { - brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); - bus->activity = true; - } + if (bus->clkstate == target) return 0; - } switch (target) { case CLK_AVAIL: @@ -975,7 +970,6 @@ static int brcmf_sdio_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) /* Now request HT Avail on the backplane */ brcmf_sdio_htclk(bus, true, pendok); brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); - bus->activity = true; break; case CLK_SDONLY: @@ -1024,17 +1018,6 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) /* Going to sleep */ if (sleep) { - /* Don't sleep if something is pending */ - if (atomic_read(&bus->intstatus) || - atomic_read(&bus->ipend) > 0 || - bus->ctrl_frame_stat || - (!atomic_read(&bus->fcstate) && - brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && - data_ok(bus))) { - err = -EBUSY; - goto done; - } - clkcsr = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, &err); @@ -1045,11 +1028,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) SBSDIO_ALP_AVAIL_REQ, &err); } err = brcmf_sdio_kso_control(bus, false); - /* disable watchdog */ - if (!err) - brcmf_sdio_wd_timer(bus, 0); } else { - bus->idlecount = 0; err = brcmf_sdio_kso_control(bus, true); } if (err) { @@ -3566,7 +3545,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus) queue_work(bus->brcmf_wq, &bus->datawork); } -static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) +static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) { brcmf_dbg(TIMER, "Enter\n"); @@ -3627,22 +3606,21 @@ static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) #endif /* DEBUG */ /* On idle timeout clear activity flag and/or turn off clock */ - if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { - if (++bus->idlecount >= bus->idletime) { + if ((atomic_read(&bus->dpc_tskcnt) == 0) && + (atomic_read(&bus->dpc_running) == 0) && + (bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { + bus->idlecount++; + if (bus->idlecount > bus->idletime) { + brcmf_dbg(SDIO, "idle\n"); + sdio_claim_host(bus->sdiodev->func[1]); + brcmf_sdio_wd_timer(bus, 0); bus->idlecount = 0; - if (bus->activity) { - bus->activity = false; - brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); - } else { - brcmf_dbg(SDIO, "idle\n"); - sdio_claim_host(bus->sdiodev->func[1]); - brcmf_sdio_bus_sleep(bus, true, false); - sdio_release_host(bus->sdiodev->func[1]); - } + brcmf_sdio_bus_sleep(bus, true, false); + sdio_release_host(bus->sdiodev->func[1]); } + } else { + bus->idlecount = 0; } - - return (atomic_read(&bus->ipend) > 0); } static void brcmf_sdio_dataworker(struct work_struct *work) @@ -3651,8 +3629,11 @@ static void brcmf_sdio_dataworker(struct work_struct *work) datawork); while (atomic_read(&bus->dpc_tskcnt)) { + atomic_set(&bus->dpc_running, 1); atomic_set(&bus->dpc_tskcnt, 0); brcmf_sdio_dpc(bus); + bus->idlecount = 0; + atomic_set(&bus->dpc_running, 0); } if (brcmf_sdiod_freezing(bus->sdiodev)) { brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN); @@ -4154,6 +4135,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) } /* Initialize DPC thread */ atomic_set(&bus->dpc_tskcnt, 0); + atomic_set(&bus->dpc_running, 0); /* Assign bus interface call back */ bus->sdiodev->bus_if->dev = bus->sdiodev->dev; From 449e58b85c0051117bf8428777b4ae38e098506a Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Fri, 6 Mar 2015 18:40:40 +0100 Subject: [PATCH 070/567] brcmfmac: Fix possible race-condition. SDIO is using a "shared" variable to handoff ctl frames to DPC and to see when they are done. In a timeout situation this can lead to erroneous situation where DPC started to handle the ctl frame while the timeout expired. This patch will fix this by adding locking around the shared variable. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/brcm80211/brcmfmac/sdio.c | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 161acd046451..c9a9ff191616 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -2700,11 +2700,13 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && data_ok(bus)) { sdio_claim_host(bus->sdiodev->func[1]); - err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, - bus->ctrl_frame_len); + if (bus->ctrl_frame_stat) { + err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, + bus->ctrl_frame_len); + bus->ctrl_frame_err = err; + bus->ctrl_frame_stat = false; + } sdio_release_host(bus->sdiodev->func[1]); - bus->ctrl_frame_err = err; - bus->ctrl_frame_stat = false; brcmf_sdio_wait_event_wakeup(bus); } /* Send queued frames (limit 1 if rx may still be pending) */ @@ -2720,9 +2722,13 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_err("failed backplane access over SDIO, halting operation\n"); atomic_set(&bus->intstatus, 0); if (bus->ctrl_frame_stat) { - bus->ctrl_frame_err = -ENODEV; - bus->ctrl_frame_stat = false; - brcmf_sdio_wait_event_wakeup(bus); + sdio_claim_host(bus->sdiodev->func[1]); + if (bus->ctrl_frame_stat) { + bus->ctrl_frame_err = -ENODEV; + bus->ctrl_frame_stat = false; + brcmf_sdio_wait_event_wakeup(bus); + } + sdio_release_host(bus->sdiodev->func[1]); } } else if (atomic_read(&bus->intstatus) || atomic_read(&bus->ipend) > 0 || @@ -2930,15 +2936,20 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) brcmf_sdio_trigger_dpc(bus); wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat, msecs_to_jiffies(CTL_DONE_TIMEOUT)); - - if (!bus->ctrl_frame_stat) { + ret = 0; + if (bus->ctrl_frame_stat) { + sdio_claim_host(bus->sdiodev->func[1]); + if (bus->ctrl_frame_stat) { + brcmf_dbg(SDIO, "ctrl_frame timeout\n"); + bus->ctrl_frame_stat = false; + ret = -ETIMEDOUT; + } + sdio_release_host(bus->sdiodev->func[1]); + } + if (!ret) { brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n", bus->ctrl_frame_err); ret = bus->ctrl_frame_err; - } else { - brcmf_dbg(SDIO, "ctrl_frame timeout\n"); - bus->ctrl_frame_stat = false; - ret = -ETIMEDOUT; } if (ret) From d375bc8a85a49bf4d2897f59fab4d4afb34d5d44 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Fri, 6 Mar 2015 18:40:41 +0100 Subject: [PATCH 071/567] brcmfmac: Fix race condition in msgbuf ioctl processing. Msgbuf is using a wait_event_timeout to wait for the response on an ioctl. The wakeup routine uses waitqueue_active to see if wait_event_timeout has been called. There is a chance that the response arrives before wait_event_timeout is called, this will result in situation that wait_event_timeout never gets woken again and assumed result will be a timeout. This patch removes that errornous situation by always setting the ctl_completed var before checking for queue active. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 6262612dec45..4ec9811f49c8 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -481,10 +481,9 @@ static int brcmf_msgbuf_ioctl_resp_wait(struct brcmf_msgbuf *msgbuf) static void brcmf_msgbuf_ioctl_resp_wake(struct brcmf_msgbuf *msgbuf) { - if (waitqueue_active(&msgbuf->ioctl_resp_wait)) { - msgbuf->ctl_completed = true; + msgbuf->ctl_completed = true; + if (waitqueue_active(&msgbuf->ioctl_resp_wait)) wake_up(&msgbuf->ioctl_resp_wait); - } } From 9c51026509d7fd11d84e0035008e1a9768960f2b Mon Sep 17 00:00:00 2001 From: Syed Asifful Dayyan Date: Fri, 6 Mar 2015 18:40:42 +0100 Subject: [PATCH 072/567] brcmfmac: Add support for BCM4345 SDIO chipset. These changes add support for BCM4345 SDIO chipset. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Arend Van Spriel Reviewed-by: Hante Meuleman Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Syed Asifful Dayyan Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 1 + drivers/net/wireless/brcm80211/brcmfmac/chip.c | 4 ++++ drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 5 +++++ drivers/net/wireless/brcm80211/include/brcm_hw_ids.h | 1 + include/linux/mmc/sdio_ids.h | 1 + 5 files changed, 12 insertions(+) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index ffb0e2d382ea..43995308307d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1096,6 +1096,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354), { /* end: all zeroes */ } }; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index 04d2ca0d87d6..e679edca081d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -491,6 +491,10 @@ static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) case BRCM_CC_43362_CHIP_ID: ci->pub.ramsize = 0x3c000; break; + case BRCM_CC_4345_CHIP_ID: + ci->pub.ramsize = 0xc8000; + ci->pub.rambase = 0x198000; + break; case BRCM_CC_4339_CHIP_ID: case BRCM_CC_4354_CHIP_ID: case BRCM_CC_4356_CHIP_ID: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index c9a9ff191616..973fa2afc2fc 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -617,6 +617,8 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { #define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt" #define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin" #define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt" +#define BCM4345_FIRMWARE_NAME "brcm/brcmfmac4345-sdio.bin" +#define BCM4345_NVRAM_NAME "brcm/brcmfmac4345-sdio.txt" #define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin" #define BCM4354_NVRAM_NAME "brcm/brcmfmac4354-sdio.txt" @@ -640,6 +642,8 @@ MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME); MODULE_FIRMWARE(BCM43362_NVRAM_NAME); MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4339_NVRAM_NAME); +MODULE_FIRMWARE(BCM4345_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM4345_NVRAM_NAME); MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4354_NVRAM_NAME); @@ -669,6 +673,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { { BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, { BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, { BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, + { BRCM_CC_4345_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4345) }, { BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) } }; diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 2124a17d0bfd..b599e7e41148 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -37,6 +37,7 @@ #define BRCM_CC_43362_CHIP_ID 43362 #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 +#define BRCM_CC_4345_CHIP_ID 0x4345 #define BRCM_CC_4354_CHIP_ID 0x4354 #define BRCM_CC_4356_CHIP_ID 0x4356 #define BRCM_CC_43566_CHIP_ID 43566 diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 996807963716..91397858dc95 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -33,6 +33,7 @@ #define SDIO_DEVICE_ID_BROADCOM_43341 0xa94d #define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335 #define SDIO_DEVICE_ID_BROADCOM_43362 0xa962 +#define SDIO_DEVICE_ID_BROADCOM_4345 0x4345 #define SDIO_DEVICE_ID_BROADCOM_4354 0x4354 #define SDIO_VENDOR_ID_INTEL 0x0089 From 7308a20e7579f91e103398366d9bb382653cbb89 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 8 Mar 2015 15:42:01 +0200 Subject: [PATCH 073/567] wil6210: NAPI completion refactor It is expected that driver completes NAPI when less than full budget is consumed. Fulfill this requirement. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index ace30c1b5c64..f2f7ea29558e 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -82,7 +82,7 @@ static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) wil_rx_handle(wil, "a); done = budget - quota; - if (done <= 1) { /* burst ends - only one packet processed */ + if (done < budget) { napi_complete(napi); wil6210_unmask_irq_rx(wil); wil_dbg_txrx(wil, "NAPI RX complete\n"); @@ -110,7 +110,7 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) tx_done += wil_tx_complete(wil, i); } - if (tx_done <= 1) { /* burst ends - only one packet processed */ + if (tx_done < budget) { napi_complete(napi); wil6210_unmask_irq_tx(wil); wil_dbg_txrx(wil, "NAPI TX complete\n"); From c42da9993a4cc32f48dad89eedf7b7ad4dfd41bc Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 8 Mar 2015 15:42:02 +0200 Subject: [PATCH 074/567] wil6210: re-submit Rx frames to the wireless media if appropriate This is for AP only. If Rx data frame targeted to one of associated clients, transmit it back to the wireless media and don't deliver to the host. For the multicast frames, deliver to both host and wireless media. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 72 ++++++++++++++++++++----- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 7f2f560b8638..08d3cac4f004 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -492,17 +492,71 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) */ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) { - gro_result_t rc; + gro_result_t rc = GRO_NORMAL; struct wil6210_priv *wil = ndev_to_wil(ndev); + struct wireless_dev *wdev = wil_to_wdev(wil); unsigned int len = skb->len; struct vring_rx_desc *d = wil_skb_rxdesc(skb); int cid = wil_rxdesc_cid(d); + struct ethhdr *eth = (void *)skb->data; + /* here looking for DA, not A1, thus Rxdesc's 'mcast' indication + * is not suitable, need to look at data + */ + int mcast = is_multicast_ether_addr(eth->h_dest); struct wil_net_stats *stats = &wil->sta[cid].stats; + struct sk_buff *xmit_skb = NULL; + static const char * const gro_res_str[] = { + [GRO_MERGED] = "GRO_MERGED", + [GRO_MERGED_FREE] = "GRO_MERGED_FREE", + [GRO_HELD] = "GRO_HELD", + [GRO_NORMAL] = "GRO_NORMAL", + [GRO_DROP] = "GRO_DROP", + }; skb_orphan(skb); - rc = napi_gro_receive(&wil->napi_rx, skb); + if (wdev->iftype == NL80211_IFTYPE_AP) { + if (mcast) { + /* send multicast frames both to higher layers in + * local net stack and back to the wireless medium + */ + xmit_skb = skb_copy(skb, GFP_ATOMIC); + } else { + int xmit_cid = wil_find_cid(wil, eth->h_dest); + if (xmit_cid >= 0) { + /* The destination station is associated to + * this AP (in this VLAN), so send the frame + * directly to it and do not pass it to local + * net stack. + */ + xmit_skb = skb; + skb = NULL; + } + } + } + if (xmit_skb) { + /* Send to wireless media and increase priority by 256 to + * keep the received priority instead of reclassifying + * the frame (see cfg80211_classify8021d). + */ + xmit_skb->dev = ndev; + xmit_skb->priority += 256; + xmit_skb->protocol = htons(ETH_P_802_3); + skb_reset_network_header(xmit_skb); + skb_reset_mac_header(xmit_skb); + wil_dbg_txrx(wil, "Rx -> Tx %d bytes\n", len); + dev_queue_xmit(xmit_skb); + } + + if (skb) { /* deliver to local stack */ + + skb->protocol = eth_type_trans(skb, ndev); + rc = napi_gro_receive(&wil->napi_rx, skb); + wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n", + len, gro_res_str[rc]); + } + /* statistics. rc set to GRO_NORMAL for AP bridging */ if (unlikely(rc == GRO_DROP)) { ndev->stats.rx_dropped++; stats->rx_dropped++; @@ -512,17 +566,8 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) stats->rx_packets++; ndev->stats.rx_bytes += len; stats->rx_bytes += len; - } - { - static const char * const gro_res_str[] = { - [GRO_MERGED] = "GRO_MERGED", - [GRO_MERGED_FREE] = "GRO_MERGED_FREE", - [GRO_HELD] = "GRO_HELD", - [GRO_NORMAL] = "GRO_NORMAL", - [GRO_DROP] = "GRO_DROP", - }; - wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n", - len, gro_res_str[rc]); + if (mcast) + ndev->stats.multicast++; } } @@ -553,7 +598,6 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) skb->protocol = htons(ETH_P_802_2); wil_netif_rx_any(skb, ndev); } else { - skb->protocol = eth_type_trans(skb, ndev); wil_rx_reorder(wil, skb); } } From 02beaf1a5b8f05ead295d781522b1684dc5e7263 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 8 Mar 2015 15:42:03 +0200 Subject: [PATCH 075/567] wil6210: support AP isolation For the AP, configuration may say not to bridge traffic between wireless clients. This is conveyed from user space (ex: hostapd has ap_isolate parameter) with NL80211_CMD_SET_BSS, to the driver's cfg80211 ops method change_bss Add support for this setting. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 16 ++++++++++++++++ drivers/net/wireless/ath/wil6210/debugfs.c | 1 + drivers/net/wireless/ath/wil6210/main.c | 1 + drivers/net/wireless/ath/wil6210/txrx.c | 2 +- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 4bd708c8716c..5db6a6dc691e 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -917,6 +917,21 @@ static int wil_cfg80211_probe_client(struct wiphy *wiphy, return 0; } +static int wil_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + if (params->ap_isolate >= 0) { + wil_dbg_misc(wil, "%s(ap_isolate %d => %d)\n", __func__, + wil->ap_isolate, params->ap_isolate); + wil->ap_isolate = params->ap_isolate; + } + + return 0; +} + static struct cfg80211_ops wil_cfg80211_ops = { .scan = wil_cfg80211_scan, .connect = wil_cfg80211_connect, @@ -937,6 +952,7 @@ static struct cfg80211_ops wil_cfg80211_ops = { .stop_ap = wil_cfg80211_stop_ap, .del_station = wil_cfg80211_del_station, .probe_client = wil_cfg80211_probe_client, + .change_bss = wil_cfg80211_change_bss, }; static void wil_wiphy_init(struct wiphy *wiphy) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 3830cc20d4fa..a42cb89ff725 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1405,6 +1405,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(fw_version, S_IRUGO, doff_u32), WIL_FIELD(hw_version, S_IRUGO, doff_x32), WIL_FIELD(recovery_count, S_IRUGO, doff_u32), + WIL_FIELD(ap_isolate, S_IRUGO, doff_u32), {}, }; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index db74e811f5c4..afff8d33c562 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -714,6 +714,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* init after reset */ wil->pending_connect_cid = -1; + wil->ap_isolate = 0; reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 08d3cac4f004..689081c2c37b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -515,7 +515,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) skb_orphan(skb); - if (wdev->iftype == NL80211_IFTYPE_AP) { + if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) { if (mcast) { /* send multicast frames both to higher layers in * local net stack and back to the wireless medium diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b6e65c37d410..c1a71ab75a0e 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -542,6 +542,7 @@ struct wil6210_priv { u32 monitor_flags; u32 privacy; /* secure connection? */ int sinfo_gen; + u32 ap_isolate; /* no intra-BSS communication */ /* interrupt moderation */ u32 tx_max_burst_duration; u32 tx_interframe_timeout; From e519f78f1191007604c056dfcb372d4fe3a4b05b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 9 Mar 2015 14:20:06 +0530 Subject: [PATCH 076/567] ath9k: Add PCIE powersave macros These will be used to handle chip-specific power save configuration. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 29a25d92add7..2bb3b334a23f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -309,6 +309,12 @@ enum ath9k_hw_hang_checks { HW_MAC_HANG = BIT(5), }; +#define AR_PCIE_PLL_PWRSAVE_CONTROL BIT(0) +#define AR_PCIE_PLL_PWRSAVE_ON_D3 BIT(1) +#define AR_PCIE_PLL_PWRSAVE_ON_D0 BIT(2) +#define AR_PCIE_CDR_PWRSAVE_ON_D3 BIT(3) +#define AR_PCIE_CDR_PWRSAVE_ON_D0 BIT(4) + struct ath9k_ops_config { int dma_beacon_response_time; int sw_beacon_response_time; From afa7e6dbd91d3d9e18d224116353087082479dc5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 9 Mar 2015 14:20:07 +0530 Subject: [PATCH 077/567] ath9k: Fix PLL powersave for AR9485 Use the value in ah->config.pll_pwrsave to determine which array needs to be loaded. Also, initialize pll_pwrsave to 1 by default. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 10 +++++----- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/init.c | 8 +++++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 4335ccbe7d7e..ea33f8dcc171 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -195,16 +195,16 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9485_1_1_baseband_core_txfir_coeff_japan_2484); - if (ah->config.no_pll_pwrsave) { + if (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) { INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9485_1_1_pcie_phy_clkreq_disable_L1); + ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1); INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9485_1_1_pcie_phy_clkreq_disable_L1); + ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1); } else { INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1); + ar9485_1_1_pcie_phy_clkreq_disable_L1); INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9485_1_1_pll_on_cdr_on_clkreq_disable_L1); + ar9485_1_1_pcie_phy_clkreq_disable_L1); } } else if (AR_SREV_9462_21(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 2bb3b334a23f..e124ee240dc8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -341,7 +341,7 @@ struct ath9k_ops_config { u32 ant_ctrl_comm2g_switch_enable; bool xatten_margin_cfg; bool alt_mingainidx; - bool no_pll_pwrsave; + bool pll_pwrsave; bool tx_gain_buffalo; bool led_active_high; }; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 6c6e88495394..ca66fab78fba 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -437,8 +437,14 @@ static void ath9k_init_pcoem_platform(struct ath_softc *sc) ath_info(common, "Enable WAR for ASPM D3/L1\n"); } + /* + * The default value of pll_pwrsave is 1. + * For certain AR9485 cards, it is set to 0. + */ + ah->config.pll_pwrsave = 1; + if (sc->driver_data & ATH9K_PCI_NO_PLL_PWRSAVE) { - ah->config.no_pll_pwrsave = true; + ah->config.pll_pwrsave = 0; ath_info(common, "Disable PLL PowerSave\n"); } From 656cd75c387383fe3a63e21204107abf5515ecfc Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 9 Mar 2015 14:20:08 +0530 Subject: [PATCH 078/567] ath9k: Initialize pll_pwrsave for AR9462/AR9565 Cards based on AR9462/AR9565 support more PCIE power save mechanisms, so register them correctly. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 3 +++ drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/init.c | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 60aa8d71e753..cc8bea8a957f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -366,6 +366,9 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.rimt_first = 700; } + if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) + ah->config.pll_pwrsave = 7; + /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) * _and_ if on non-uniprocessor systems (Multiprocessor/HT). diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e124ee240dc8..2067cb523ca8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -341,7 +341,7 @@ struct ath9k_ops_config { u32 ant_ctrl_comm2g_switch_enable; bool xatten_margin_cfg; bool alt_mingainidx; - bool pll_pwrsave; + u8 pll_pwrsave; bool tx_gain_buffalo; bool led_active_high; }; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index ca66fab78fba..de862ad13b51 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -440,6 +440,7 @@ static void ath9k_init_pcoem_platform(struct ath_softc *sc) /* * The default value of pll_pwrsave is 1. * For certain AR9485 cards, it is set to 0. + * For AR9462, AR9565 it's set to 7. */ ah->config.pll_pwrsave = 1; From 93f7d6f3d5aa86bc9cce38a1d7eb71524ac85e0b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 9 Mar 2015 14:20:09 +0530 Subject: [PATCH 079/567] ath9k: Check allowed PCIE powersave configuration When assigning the initvals for PCIE sleep/awake registers, check the configuration that has been assigned to pll_pwrsave during initialization. Also, display a warning if we don't have valid arrays. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 73 +++++++++++++++++----- 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index ea33f8dcc171..df176e6a30d1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -231,10 +231,20 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_2p1_modes_fast_clock); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, ar9462_2p1_baseband_core_txfir_coeff_japan_2484); - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9462_2p1_pciephy_clkreq_disable_L1); - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9462_2p1_pciephy_clkreq_disable_L1); + + /* Awake -> Sleep Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D3)) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9462_2p1_pciephy_clkreq_disable_L1); + } + + /* Sleep -> Awake Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D0)) { + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9462_2p1_pciephy_clkreq_disable_L1); + } } else if (AR_SREV_9462_20(ah)) { INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core); @@ -262,11 +272,18 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_2p0_common_rx_gain); /* Awake -> Sleep Setting */ - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9462_2p0_pciephy_clkreq_disable_L1); + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D3)) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9462_2p0_pciephy_clkreq_disable_L1); + } + /* Sleep -> Awake Setting */ - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9462_2p0_pciephy_clkreq_disable_L1); + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D0)) { + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9462_2p0_pciephy_clkreq_disable_L1); + } /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, @@ -456,10 +473,19 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p1_Modes_lowest_ob_db_tx_gain_table); - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9565_1p1_pciephy_clkreq_disable_L1); - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9565_1p1_pciephy_clkreq_disable_L1); + /* Awake -> Sleep Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D3)) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9565_1p1_pciephy_clkreq_disable_L1); + } + + /* Sleep -> Awake Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D0)) { + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9565_1p1_pciephy_clkreq_disable_L1); + } INIT_INI_ARRAY(&ah->iniModesFastClock, ar9565_1p1_modes_fast_clock); @@ -491,10 +517,19 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_Modes_lowest_ob_db_tx_gain_table); - INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9565_1p0_pciephy_clkreq_disable_L1); - INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9565_1p0_pciephy_clkreq_disable_L1); + /* Awake -> Sleep Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D3)) { + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9565_1p0_pciephy_clkreq_disable_L1); + } + + /* Sleep -> Awake Setting */ + if ((ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_CONTROL) && + (ah->config.pll_pwrsave & AR_PCIE_PLL_PWRSAVE_ON_D0)) { + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9565_1p0_pciephy_clkreq_disable_L1); + } INIT_INI_ARRAY(&ah->iniModesFastClock, ar9565_1p0_modes_fast_clock); @@ -1130,6 +1165,12 @@ void ar9003_hw_attach_ops(struct ath_hw *ah) struct ath_hw_ops *ops = ath9k_hw_ops(ah); ar9003_hw_init_mode_regs(ah); + + if (AR_SREV_9003_PCOEM(ah)) { + WARN_ON(!ah->iniPcieSerdes.ia_array); + WARN_ON(!ah->iniPcieSerdesLowPower.ia_array); + } + priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs; priv_ops->init_hang_checks = ar9003_hw_init_hang_checks; priv_ops->detect_mac_hang = ar9003_hw_detect_mac_hang; From dd2951124838843809f75117d17c32d053ee3262 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 9 Mar 2015 14:20:10 +0530 Subject: [PATCH 080/567] ath9k: Fix RTT chainmask usage Since the RTT registers need to be configured for all valid chains irrespective of the runtime chainmask, use the actual chainmask of the chip. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_rtt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c index 934418872e8e..e4d11fa7fe8c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c @@ -106,7 +106,7 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah) int chain, i; for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->rxchainmask & (1 << chain))) + if (!(ah->caps.rx_chainmask & (1 << chain))) continue; for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) { ar9003_hw_rtt_load_hist_entry(ah, chain, i, @@ -171,7 +171,7 @@ void ar9003_hw_rtt_fill_hist(struct ath_hw *ah) int chain, i; for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->rxchainmask & (1 << chain))) + if (!(ah->caps.rx_chainmask & (1 << chain))) continue; for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) { ah->caldata->rtt_table[chain][i] = @@ -193,7 +193,7 @@ void ar9003_hw_rtt_clear_hist(struct ath_hw *ah) int chain, i; for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->rxchainmask & (1 << chain))) + if (!(ah->caps.rx_chainmask & (1 << chain))) continue; for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) ar9003_hw_rtt_load_hist_entry(ah, chain, i, 0); From 6faf22d9cabeec6f8f623d58a2e88ca9edf4c946 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 10 Mar 2015 15:25:39 +0100 Subject: [PATCH 081/567] ar5523: use container_of If we want to shrink skb->cb then we'd have to see about reducing struct ieee80211_tx_info, which gets embedded inside skb->cb[]. It provides a scratch space to be used by wireless drivers. ar5523 uses the maximum space available today (40 bytes), but it seems we don't need this -- data->skb pointer seems to always point back to the skb whose cb buffer the data structure resides, iow, given a pointer to the embedded control buffer we can infer the skb address. Tested-by: Pontus Fuchs Signed-off-by: Florian Westphal Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ar5523/ar5523.c | 9 +++++---- drivers/net/wireless/ath/ar5523/ar5523.h | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index f92050617ae6..5147ebe4cd05 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -779,8 +779,6 @@ static void ar5523_tx(struct ieee80211_hw *hw, ieee80211_stop_queues(hw); } - data->skb = skb; - spin_lock_irqsave(&ar->tx_data_list_lock, flags); list_add_tail(&data->list, &ar->tx_queue_pending); spin_unlock_irqrestore(&ar->tx_data_list_lock, flags); @@ -817,10 +815,13 @@ static void ar5523_tx_work_locked(struct ar5523 *ar) if (!data) break; - skb = data->skb; + txi = container_of((void *)data, struct ieee80211_tx_info, + driver_data); txqid = 0; - txi = IEEE80211_SKB_CB(skb); + + skb = container_of((void *)txi, struct sk_buff, cb); paylen = skb->len; + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { ar5523_err(ar, "Failed to allocate TX urb\n"); diff --git a/drivers/net/wireless/ath/ar5523/ar5523.h b/drivers/net/wireless/ath/ar5523/ar5523.h index 00c6fd346d48..9a322a65cdb5 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.h +++ b/drivers/net/wireless/ath/ar5523/ar5523.h @@ -74,7 +74,6 @@ struct ar5523_tx_cmd { struct ar5523_tx_data { struct list_head list; struct ar5523 *ar; - struct sk_buff *skb; struct urb *urb; }; From 3a79e1dfa23f69cb7b29e002ccf718ebc8e30b21 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 10 Mar 2015 15:44:22 +0100 Subject: [PATCH 082/567] ath9k: make ath_frame_info fit into reduced-size rate_driver_data pre-requisite to shrink size of ieee80211_tx_info which in turn is needed to shrink skb->cb to 40 bytes again. Signed-off-by: Florian Westphal Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7e89236c0e13..a7a81b3969ce 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -184,12 +184,12 @@ struct ath_frame_info { struct ath_buf *bf; u16 framelen; s8 txq; - enum ath9k_key_type keytype; u8 keyix; u8 rtscts_rate; u8 retries : 7; u8 baw_tracked : 1; u8 tx_power; + enum ath9k_key_type keytype:2; }; struct ath_rxbuf { From 55b59fba0f0c700493a63157db8e3ef4300908dc Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 11 Mar 2015 16:11:27 +0100 Subject: [PATCH 083/567] brcmfmac: remove duplication of ramsize info Removing the ramsize from the brcmf_sdio structure to avoid duplication. The information is available in brcmf_chip structure. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 973fa2afc2fc..9df16c16ef29 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -432,8 +432,6 @@ struct brcmf_sdio { struct brcmf_sdio_dev *sdiodev; /* sdio device handler */ struct brcmf_chip *ci; /* Chip info struct */ - u32 ramsize; /* Size of RAM in SOCRAM (bytes) */ - u32 hostintmask; /* Copy of Host Interrupt Mask */ atomic_t intstatus; /* Intstatus bits (events) pending */ atomic_t fcstate; /* State of dongle flow-control */ @@ -1075,7 +1073,7 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, struct sdpcm_shared_le sh_le; __le32 addr_le; - shaddr = bus->ci->rambase + bus->ramsize - 4; + shaddr = bus->ci->rambase + bus->ci->ramsize - 4; /* * Read last word in socram to determine @@ -3871,13 +3869,6 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH; brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength); - /* Get info on the SOCRAM cores... */ - bus->ramsize = bus->ci->ramsize; - if (!(bus->ramsize)) { - brcmf_err("failed to find SOCRAM memory!\n"); - goto fail; - } - /* Set card control so an SDIO card reset does a WLAN backplane reset */ reg_val = brcmf_sdiod_regrb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCTRL, &err); From 5ded1c251f8e6c93012ef007e2bade61bff20c7e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 11 Mar 2015 16:11:28 +0100 Subject: [PATCH 084/567] brcmfmac: always perform cores checks Instead of checking the cores in the chip only if CONFIG_BRCMDBG is selected perform the check always and extend it with more sanity checking. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/chip.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index e679edca081d..cb08f4ecec99 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -419,13 +419,13 @@ static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci, return &core->pub; } -#ifdef DEBUG /* safety check for chipinfo */ static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) { struct brcmf_core_priv *core; bool need_socram = false; bool has_socram = false; + bool cpu_found = false; int idx = 1; list_for_each_entry(core, &ci->cores, list) { @@ -435,12 +435,14 @@ static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) switch (core->pub.id) { case BCMA_CORE_ARM_CM3: + cpu_found = true; need_socram = true; break; case BCMA_CORE_INTERNAL_MEM: has_socram = true; break; case BCMA_CORE_ARM_CR4: + cpu_found = true; if (ci->pub.rambase == 0) { brcmf_err("RAM base not provided with ARM CR4 core\n"); return -ENOMEM; @@ -451,19 +453,21 @@ static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) } } + if (!cpu_found) { + brcmf_err("CPU core not detected\n"); + return -ENXIO; + } /* check RAM core presence for ARM CM3 core */ if (need_socram && !has_socram) { brcmf_err("RAM core not provided with ARM CM3 core\n"); return -ENODEV; } + if (!ci->pub.ramsize) { + brcmf_err("RAM size is undetermined\n"); + return -ENOMEM; + } return 0; } -#else /* DEBUG */ -static inline int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) -{ - return 0; -} -#endif static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) { From d380ebc9b6fb552345de3051d9b64e963eaadf46 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 11 Mar 2015 16:11:29 +0100 Subject: [PATCH 085/567] brcmfmac: rename chip download functions The functions brcmf_chip_[enter/exit]_download() are not exclusively used for firmware download so rename these more appropriate. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/brcm80211/brcmfmac/chip.c | 26 +++++++++---------- .../net/wireless/brcm80211/brcmfmac/chip.h | 8 +++--- .../net/wireless/brcm80211/brcmfmac/pcie.c | 10 +++---- .../net/wireless/brcm80211/brcmfmac/sdio.c | 17 ++++++------ 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index cb08f4ecec99..d68e37d3a42f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -807,7 +807,7 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, err = -EINVAL; if (WARN_ON(!ops->prepare)) err = -EINVAL; - if (WARN_ON(!ops->exit_dl)) + if (WARN_ON(!ops->activate)) err = -EINVAL; if (err < 0) return ERR_PTR(-EINVAL); @@ -905,7 +905,7 @@ void brcmf_chip_resetcore(struct brcmf_core *pub, u32 prereset, u32 reset, } static void -brcmf_chip_cm3_enterdl(struct brcmf_chip_priv *chip) +brcmf_chip_cm3_set_passive(struct brcmf_chip_priv *chip) { struct brcmf_core *core; @@ -919,7 +919,7 @@ brcmf_chip_cm3_enterdl(struct brcmf_chip_priv *chip) brcmf_chip_resetcore(core, 0, 0, 0); } -static bool brcmf_chip_cm3_exitdl(struct brcmf_chip_priv *chip) +static bool brcmf_chip_cm3_set_active(struct brcmf_chip_priv *chip) { struct brcmf_core *core; @@ -929,7 +929,7 @@ static bool brcmf_chip_cm3_exitdl(struct brcmf_chip_priv *chip) return false; } - chip->ops->exit_dl(chip->ctx, &chip->pub, 0); + chip->ops->activate(chip->ctx, &chip->pub, 0); core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CM3); brcmf_chip_resetcore(core, 0, 0, 0); @@ -938,7 +938,7 @@ static bool brcmf_chip_cm3_exitdl(struct brcmf_chip_priv *chip) } static inline void -brcmf_chip_cr4_enterdl(struct brcmf_chip_priv *chip) +brcmf_chip_cr4_set_passive(struct brcmf_chip_priv *chip) { struct brcmf_core *core; @@ -951,11 +951,11 @@ brcmf_chip_cr4_enterdl(struct brcmf_chip_priv *chip) D11_BCMA_IOCTL_PHYCLOCKEN); } -static bool brcmf_chip_cr4_exitdl(struct brcmf_chip_priv *chip, u32 rstvec) +static bool brcmf_chip_cr4_set_active(struct brcmf_chip_priv *chip, u32 rstvec) { struct brcmf_core *core; - chip->ops->exit_dl(chip->ctx, &chip->pub, rstvec); + chip->ops->activate(chip->ctx, &chip->pub, rstvec); /* restore ARM */ core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CR4); @@ -964,7 +964,7 @@ static bool brcmf_chip_cr4_exitdl(struct brcmf_chip_priv *chip, u32 rstvec) return true; } -void brcmf_chip_enter_download(struct brcmf_chip *pub) +void brcmf_chip_set_passive(struct brcmf_chip *pub) { struct brcmf_chip_priv *chip; struct brcmf_core *arm; @@ -974,14 +974,14 @@ void brcmf_chip_enter_download(struct brcmf_chip *pub) chip = container_of(pub, struct brcmf_chip_priv, pub); arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4); if (arm) { - brcmf_chip_cr4_enterdl(chip); + brcmf_chip_cr4_set_passive(chip); return; } - brcmf_chip_cm3_enterdl(chip); + brcmf_chip_cm3_set_passive(chip); } -bool brcmf_chip_exit_download(struct brcmf_chip *pub, u32 rstvec) +bool brcmf_chip_set_active(struct brcmf_chip *pub, u32 rstvec) { struct brcmf_chip_priv *chip; struct brcmf_core *arm; @@ -991,9 +991,9 @@ bool brcmf_chip_exit_download(struct brcmf_chip *pub, u32 rstvec) chip = container_of(pub, struct brcmf_chip_priv, pub); arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4); if (arm) - return brcmf_chip_cr4_exitdl(chip, rstvec); + return brcmf_chip_cr4_set_active(chip, rstvec); - return brcmf_chip_cm3_exitdl(chip); + return brcmf_chip_cm3_set_active(chip); } bool brcmf_chip_sr_capable(struct brcmf_chip *pub) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/brcm80211/brcmfmac/chip.h index c32908da90c8..7b7b62938ca3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.h @@ -64,7 +64,7 @@ struct brcmf_core { * @write32: write 32-bit value over bus. * @prepare: prepare bus for core configuration. * @setup: bus-specific core setup. - * @exit_dl: exit download state. + * @active: chip becomes active. * The callback should use the provided @rstvec when non-zero. */ struct brcmf_buscore_ops { @@ -72,7 +72,7 @@ struct brcmf_buscore_ops { void (*write32)(void *ctx, u32 addr, u32 value); int (*prepare)(void *ctx); int (*setup)(void *ctx, struct brcmf_chip *chip); - void (*exit_dl)(void *ctx, struct brcmf_chip *chip, u32 rstvec); + void (*activate)(void *ctx, struct brcmf_chip *chip, u32 rstvec); }; struct brcmf_chip *brcmf_chip_attach(void *ctx, @@ -84,8 +84,8 @@ bool brcmf_chip_iscoreup(struct brcmf_core *core); void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset); void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset, u32 postreset); -void brcmf_chip_enter_download(struct brcmf_chip *ci); -bool brcmf_chip_exit_download(struct brcmf_chip *ci, u32 rstvec); +void brcmf_chip_set_passive(struct brcmf_chip *ci); +bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec); bool brcmf_chip_sr_capable(struct brcmf_chip *pub); #endif /* BRCMF_AXIDMP_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index 61c053a729be..81e544f2f2fe 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -509,7 +509,7 @@ static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo) static int brcmf_pcie_enter_download_state(struct brcmf_pciedev_info *devinfo) { - brcmf_chip_enter_download(devinfo->ci); + brcmf_chip_set_passive(devinfo->ci); if (devinfo->ci->chip == BRCM_CC_43602_CHIP_ID) { brcmf_pcie_select_core(devinfo, BCMA_CORE_ARM_CR4); @@ -536,7 +536,7 @@ static int brcmf_pcie_exit_download_state(struct brcmf_pciedev_info *devinfo, brcmf_chip_resetcore(core, 0, 0, 0); } - return !brcmf_chip_exit_download(devinfo->ci, resetintr); + return !brcmf_chip_set_active(devinfo->ci, resetintr); } @@ -1566,8 +1566,8 @@ static int brcmf_pcie_buscoreprep(void *ctx) } -static void brcmf_pcie_buscore_exitdl(void *ctx, struct brcmf_chip *chip, - u32 rstvec) +static void brcmf_pcie_buscore_activate(void *ctx, struct brcmf_chip *chip, + u32 rstvec) { struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)ctx; @@ -1577,7 +1577,7 @@ static void brcmf_pcie_buscore_exitdl(void *ctx, struct brcmf_chip *chip, static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = { .prepare = brcmf_pcie_buscoreprep, - .exit_dl = brcmf_pcie_buscore_exitdl, + .activate = brcmf_pcie_buscore_activate, .read32 = brcmf_pcie_buscore_read32, .write32 = brcmf_pcie_buscore_write32, }; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 9df16c16ef29..fff3b26975fe 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -3357,7 +3357,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, brcmf_sdio_clkctl(bus, CLK_AVAIL, false); /* Keep arm in reset */ - brcmf_chip_enter_download(bus->ci); + brcmf_chip_set_passive(bus->ci); rstvec = get_unaligned_le32(fw->data); brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec); @@ -3378,7 +3378,7 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, } /* Take arm out of reset */ - if (!brcmf_chip_exit_download(bus->ci, rstvec)) { + if (!brcmf_chip_set_active(bus->ci, rstvec)) { brcmf_err("error getting out of ARM core reset\n"); goto err; } @@ -3771,8 +3771,8 @@ static int brcmf_sdio_buscoreprep(void *ctx) return 0; } -static void brcmf_sdio_buscore_exitdl(void *ctx, struct brcmf_chip *chip, - u32 rstvec) +static void brcmf_sdio_buscore_activate(void *ctx, struct brcmf_chip *chip, + u32 rstvec) { struct brcmf_sdio_dev *sdiodev = ctx; struct brcmf_core *core; @@ -3815,7 +3815,7 @@ static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val) static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = { .prepare = brcmf_sdio_buscoreprep, - .exit_dl = brcmf_sdio_buscore_exitdl, + .activate = brcmf_sdio_buscore_activate, .read32 = brcmf_sdio_buscore_read32, .write32 = brcmf_sdio_buscore_write32, }; @@ -4239,12 +4239,11 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdio_clkctl(bus, CLK_AVAIL, false); /* Leave the device in state where it is - * 'quiet'. This is done by putting it in - * download_state which essentially resets - * all necessary cores. + * 'passive'. This is done by resetting all + * necessary cores. */ msleep(20); - brcmf_chip_enter_download(bus->ci); + brcmf_chip_set_passive(bus->ci); brcmf_sdio_clkctl(bus, CLK_NONE, false); sdio_release_host(bus->sdiodev->func[1]); } From 38f29e1f42b114105e1ffefba0bc183e1e144d0b Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 11 Mar 2015 16:11:30 +0100 Subject: [PATCH 086/567] brcmfmac: assure device is ready for download after brcmf_chip_attach() Make the brcmf_chip_attach() function responsible for putting the device in a state where it is accessible for firmware download. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/chip.c | 8 ++------ drivers/net/wireless/brcm80211/brcmfmac/pcie.c | 2 -- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 3 --- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index d68e37d3a42f..c11137e290b1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -786,12 +786,6 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip) if (chip->ops->setup) ret = chip->ops->setup(chip->ctx, pub); - /* - * Make sure any on-chip ARM is off (in case strapping is wrong), - * or downloaded code was already running. - */ - brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3); - brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); return ret; } @@ -833,6 +827,8 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, if (err < 0) goto fail; + /* assure chip is passive for download */ + brcmf_chip_set_passive(&chip->pub); return &chip->pub; fail: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index 81e544f2f2fe..aa7a4dfb8beb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -509,8 +509,6 @@ static void brcmf_pcie_attach(struct brcmf_pciedev_info *devinfo) static int brcmf_pcie_enter_download_state(struct brcmf_pciedev_info *devinfo) { - brcmf_chip_set_passive(devinfo->ci); - if (devinfo->ci->chip == BRCM_CC_43602_CHIP_ID) { brcmf_pcie_select_core(devinfo, BCMA_CORE_ARM_CR4); brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_ARMCR4REG_BANKIDX, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index fff3b26975fe..c783c25b9ee0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -3356,9 +3356,6 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, sdio_claim_host(bus->sdiodev->func[1]); brcmf_sdio_clkctl(bus, CLK_AVAIL, false); - /* Keep arm in reset */ - brcmf_chip_set_passive(bus->ci); - rstvec = get_unaligned_le32(fw->data); brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec); From 0da32ba4ee667ef3c837ee4ebaa230f6f826a822 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 11 Mar 2015 16:11:31 +0100 Subject: [PATCH 087/567] brcmfmac: extract ram size info from internal memory registers Instead of hard-coded memory sizes it is possible to obtain that information from the internal memory registers. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/brcm80211/brcmfmac/chip.c | 264 ++++++++++++++---- .../net/wireless/brcm80211/brcmfmac/chip.h | 4 +- 2 files changed, 219 insertions(+), 49 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index c11137e290b1..734172570054 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -100,9 +100,6 @@ #define BCM4329_CORE_SOCRAM_BASE 0x18003000 /* ARM Cortex M3 core, ID 0x82a */ #define BCM4329_CORE_ARM_BASE 0x18002000 -#define BCM4329_RAMSIZE 0x48000 -/* bcm43143 */ -#define BCM43143_RAMSIZE 0x70000 #define CORE_SB(base, field) \ (base + SBCONFIGOFF + offsetof(struct sbconfig, field)) @@ -150,6 +147,78 @@ struct sbconfig { u32 sbidhigh; /* identification */ }; +/* bankidx and bankinfo reg defines corerev >= 8 */ +#define SOCRAM_BANKINFO_RETNTRAM_MASK 0x00010000 +#define SOCRAM_BANKINFO_SZMASK 0x0000007f +#define SOCRAM_BANKIDX_ROM_MASK 0x00000100 + +#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8 +/* socram bankinfo memtype */ +#define SOCRAM_MEMTYPE_RAM 0 +#define SOCRAM_MEMTYPE_R0M 1 +#define SOCRAM_MEMTYPE_DEVRAM 2 + +#define SOCRAM_BANKINFO_SZBASE 8192 +#define SRCI_LSS_MASK 0x00f00000 +#define SRCI_LSS_SHIFT 20 +#define SRCI_SRNB_MASK 0xf0 +#define SRCI_SRNB_SHIFT 4 +#define SRCI_SRBSZ_MASK 0xf +#define SRCI_SRBSZ_SHIFT 0 +#define SR_BSZ_BASE 14 + +struct sbsocramregs { + u32 coreinfo; + u32 bwalloc; + u32 extracoreinfo; + u32 biststat; + u32 bankidx; + u32 standbyctrl; + + u32 errlogstatus; /* rev 6 */ + u32 errlogaddr; /* rev 6 */ + /* used for patching rev 3 & 5 */ + u32 cambankidx; + u32 cambankstandbyctrl; + u32 cambankpatchctrl; + u32 cambankpatchtblbaseaddr; + u32 cambankcmdreg; + u32 cambankdatareg; + u32 cambankmaskreg; + u32 PAD[1]; + u32 bankinfo; /* corev 8 */ + u32 bankpda; + u32 PAD[14]; + u32 extmemconfig; + u32 extmemparitycsr; + u32 extmemparityerrdata; + u32 extmemparityerrcnt; + u32 extmemwrctrlandsize; + u32 PAD[84]; + u32 workaround; + u32 pwrctl; /* corerev >= 2 */ + u32 PAD[133]; + u32 sr_control; /* corerev >= 15 */ + u32 sr_status; /* corerev >= 15 */ + u32 sr_address; /* corerev >= 15 */ + u32 sr_data; /* corerev >= 15 */ +}; + +#define SOCRAMREGOFFS(_f) offsetof(struct sbsocramregs, _f) + +#define ARMCR4_CAP (0x04) +#define ARMCR4_BANKIDX (0x40) +#define ARMCR4_BANKINFO (0x44) +#define ARMCR4_BANKPDA (0x4C) + +#define ARMCR4_TCBBNB_MASK 0xf0 +#define ARMCR4_TCBBNB_SHIFT 4 +#define ARMCR4_TCBANB_MASK 0xf +#define ARMCR4_TCBANB_SHIFT 0 + +#define ARMCR4_BSZ_MASK 0x3f +#define ARMCR4_BSZ_MULT 8192 + struct brcmf_core_priv { struct brcmf_core pub; u32 wrapbase; @@ -443,10 +512,6 @@ static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) break; case BCMA_CORE_ARM_CR4: cpu_found = true; - if (ci->pub.rambase == 0) { - brcmf_err("RAM base not provided with ARM CR4 core\n"); - return -ENOMEM; - } break; default: break; @@ -462,60 +527,160 @@ static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) brcmf_err("RAM core not provided with ARM CM3 core\n"); return -ENODEV; } - if (!ci->pub.ramsize) { - brcmf_err("RAM size is undetermined\n"); - return -ENOMEM; - } return 0; } -static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) +static u32 brcmf_chip_core_read32(struct brcmf_core_priv *core, u16 reg) +{ + return core->chip->ops->read32(core->chip->ctx, core->pub.base + reg); +} + +static void brcmf_chip_core_write32(struct brcmf_core_priv *core, + u16 reg, u32 val) +{ + core->chip->ops->write32(core->chip->ctx, core->pub.base + reg, val); +} + +static bool brcmf_chip_socram_banksize(struct brcmf_core_priv *core, u8 idx, + u32 *banksize) +{ + u32 bankinfo; + u32 bankidx = (SOCRAM_MEMTYPE_RAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT); + + bankidx |= idx; + brcmf_chip_core_write32(core, SOCRAMREGOFFS(bankidx), bankidx); + bankinfo = brcmf_chip_core_read32(core, SOCRAMREGOFFS(bankinfo)); + *banksize = (bankinfo & SOCRAM_BANKINFO_SZMASK) + 1; + *banksize *= SOCRAM_BANKINFO_SZBASE; + return !!(bankinfo & SOCRAM_BANKINFO_RETNTRAM_MASK); +} + +static void brcmf_chip_socram_ramsize(struct brcmf_core_priv *sr, u32 *ramsize, + u32 *srsize) +{ + u32 coreinfo; + uint nb, banksize, lss; + bool retent; + int i; + + *ramsize = 0; + *srsize = 0; + + if (WARN_ON(sr->pub.rev < 4)) + return; + + if (!brcmf_chip_iscoreup(&sr->pub)) + brcmf_chip_resetcore(&sr->pub, 0, 0, 0); + + /* Get info for determining size */ + coreinfo = brcmf_chip_core_read32(sr, SOCRAMREGOFFS(coreinfo)); + nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + + if ((sr->pub.rev <= 7) || (sr->pub.rev == 12)) { + banksize = (coreinfo & SRCI_SRBSZ_MASK); + lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; + if (lss != 0) + nb--; + *ramsize = nb * (1 << (banksize + SR_BSZ_BASE)); + if (lss != 0) + *ramsize += (1 << ((lss - 1) + SR_BSZ_BASE)); + } else { + nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; + for (i = 0; i < nb; i++) { + retent = brcmf_chip_socram_banksize(sr, i, &banksize); + *ramsize += banksize; + if (retent) + *srsize += banksize; + } + } + + /* hardcoded save&restore memory sizes */ + switch (sr->chip->pub.chip) { + case BRCM_CC_4334_CHIP_ID: + if (sr->chip->pub.chiprev < 2) + *srsize = (32 * 1024); + break; + default: + break; + } +} + +/** Return the TCM-RAM size of the ARMCR4 core. */ +static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4) +{ + u32 corecap; + u32 memsize = 0; + u32 nab; + u32 nbb; + u32 totb; + u32 bxinfo; + u32 idx; + + corecap = brcmf_chip_core_read32(cr4, ARMCR4_CAP); + + nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT; + nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT; + totb = nab + nbb; + + for (idx = 0; idx < totb; idx++) { + brcmf_chip_core_write32(cr4, ARMCR4_BANKIDX, idx); + bxinfo = brcmf_chip_core_read32(cr4, ARMCR4_BANKINFO); + memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT; + } + + return memsize; +} + +static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) { switch (ci->pub.chip) { - case BRCM_CC_4329_CHIP_ID: - ci->pub.ramsize = BCM4329_RAMSIZE; - break; - case BRCM_CC_43143_CHIP_ID: - ci->pub.ramsize = BCM43143_RAMSIZE; - break; - case BRCM_CC_43241_CHIP_ID: - ci->pub.ramsize = 0x90000; - break; - case BRCM_CC_4330_CHIP_ID: - ci->pub.ramsize = 0x48000; - break; - case BRCM_CC_4334_CHIP_ID: - case BRCM_CC_43340_CHIP_ID: - ci->pub.ramsize = 0x80000; - break; - case BRCM_CC_4335_CHIP_ID: - ci->pub.ramsize = 0xc0000; - ci->pub.rambase = 0x180000; - break; - case BRCM_CC_43362_CHIP_ID: - ci->pub.ramsize = 0x3c000; - break; case BRCM_CC_4345_CHIP_ID: - ci->pub.ramsize = 0xc8000; - ci->pub.rambase = 0x198000; - break; + return 0x198000; + case BRCM_CC_4335_CHIP_ID: case BRCM_CC_4339_CHIP_ID: case BRCM_CC_4354_CHIP_ID: case BRCM_CC_4356_CHIP_ID: case BRCM_CC_43567_CHIP_ID: case BRCM_CC_43569_CHIP_ID: case BRCM_CC_43570_CHIP_ID: - ci->pub.ramsize = 0xc0000; - ci->pub.rambase = 0x180000; - break; case BRCM_CC_43602_CHIP_ID: - ci->pub.ramsize = 0xf0000; - ci->pub.rambase = 0x180000; - break; + return 0x180000; default: brcmf_err("unknown chip: %s\n", ci->pub.name); break; } + return 0; +} + +static int brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) +{ + struct brcmf_core_priv *mem_core; + struct brcmf_core *mem; + + mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_ARM_CR4); + if (mem) { + mem_core = container_of(mem, struct brcmf_core_priv, pub); + ci->pub.ramsize = brcmf_chip_tcm_ramsize(mem_core); + ci->pub.rambase = brcmf_chip_tcm_rambase(ci); + if (!ci->pub.rambase) { + brcmf_err("RAM base not provided with ARM CR4 core\n"); + return -EINVAL; + } + } else { + mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_INTERNAL_MEM); + mem_core = container_of(mem, struct brcmf_core_priv, pub); + brcmf_chip_socram_ramsize(mem_core, &ci->pub.ramsize, + &ci->pub.srsize); + } + brcmf_dbg(INFO, "RAM: base=0x%x size=%d (0x%x) sr=%d (0x%x)\n", + ci->pub.rambase, ci->pub.ramsize, ci->pub.ramsize, + ci->pub.srsize, ci->pub.srsize); + + if (!ci->pub.ramsize) { + brcmf_err("RAM size is undetermined\n"); + return -ENOMEM; + } + return 0; } static u32 brcmf_chip_dmp_get_desc(struct brcmf_chip_priv *ci, u32 *eromaddr, @@ -668,6 +833,7 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) struct brcmf_core *core; u32 regdata; u32 socitype; + int ret; /* Get CC core rev * Chipid is assume to be at offset 0 from SI_ENUM_BASE @@ -720,9 +886,13 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) return -ENODEV; } - brcmf_chip_get_raminfo(ci); + ret = brcmf_chip_cores_check(ci); + if (ret) + return ret; - return brcmf_chip_cores_check(ci); + /* assure chip is passive for core access */ + brcmf_chip_set_passive(&ci->pub); + return brcmf_chip_get_raminfo(ci); } static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id) @@ -827,8 +997,6 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, if (err < 0) goto fail; - /* assure chip is passive for download */ - brcmf_chip_set_passive(&chip->pub); return &chip->pub; fail: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/brcm80211/brcmfmac/chip.h index 7b7b62938ca3..60dcb38fc77a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.h @@ -30,7 +30,8 @@ * @pmucaps: PMU capabilities. * @pmurev: PMU revision. * @rambase: RAM base address (only applicable for ARM CR4 chips). - * @ramsize: amount of RAM on chip. + * @ramsize: amount of RAM on chip including retention. + * @srsize: amount of retention RAM on chip. * @name: string representation of the chip identifier. */ struct brcmf_chip { @@ -41,6 +42,7 @@ struct brcmf_chip { u32 pmurev; u32 rambase; u32 ramsize; + u32 srsize; char name[8]; }; From 9819a9024eabee7bb793bbbb3f3833dfaf222dc9 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 11 Mar 2015 16:11:32 +0100 Subject: [PATCH 088/567] brcmfmac: take save&restore memory into account for SDIO shared info The firmware provides pointer to SDIO shared information at end of RAM during firmware initialization. End of RAM is obviously determined by the actual ram size, but part of that may be used for save&restore memory. In that case another location in RAM will hold the pointer. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/brcm80211/brcmfmac/sdio.c | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index c783c25b9ee0..5202e766535d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -1067,44 +1067,47 @@ static inline bool brcmf_sdio_valid_shared_address(u32 addr) static int brcmf_sdio_readshared(struct brcmf_sdio *bus, struct sdpcm_shared *sh) { - u32 addr; + u32 addr = 0; int rv; u32 shaddr = 0; struct sdpcm_shared_le sh_le; __le32 addr_le; - shaddr = bus->ci->rambase + bus->ci->ramsize - 4; + sdio_claim_host(bus->sdiodev->func[1]); + brcmf_sdio_bus_sleep(bus, false, false); /* * Read last word in socram to determine * address of sdpcm_shared structure */ - sdio_claim_host(bus->sdiodev->func[1]); - brcmf_sdio_bus_sleep(bus, false, false); - rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4); - sdio_release_host(bus->sdiodev->func[1]); + shaddr = bus->ci->rambase + bus->ci->ramsize - 4; + if (!bus->ci->rambase && brcmf_chip_sr_capable(bus->ci)) + shaddr -= bus->ci->srsize; + rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, + (u8 *)&addr_le, 4); if (rv < 0) - return rv; - - addr = le32_to_cpu(addr_le); - - brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr); + goto fail; /* * Check if addr is valid. * NVRAM length at the end of memory should have been overwritten. */ + addr = le32_to_cpu(addr_le); if (!brcmf_sdio_valid_shared_address(addr)) { - brcmf_err("invalid sdpcm_shared address 0x%08X\n", - addr); - return -EINVAL; + brcmf_err("invalid sdpcm_shared address 0x%08X\n", addr); + rv = -EINVAL; + goto fail; } + brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr); + /* Read hndrte_shared structure */ rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le, sizeof(struct sdpcm_shared_le)); if (rv < 0) - return rv; + goto fail; + + sdio_release_host(bus->sdiodev->func[1]); /* Endianness */ sh->flags = le32_to_cpu(sh_le.flags); @@ -1121,8 +1124,13 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, sh->flags & SDPCM_SHARED_VERSION_MASK); return -EPROTO; } - return 0; + +fail: + brcmf_err("unable to obtain sdpcm_shared info: rv=%d (addr=0x%x)\n", + rv, addr); + sdio_release_host(bus->sdiodev->func[1]); + return rv; } static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus) From cf45932a74d4d07c2d05c4e871f2ea5bc0e5891c Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 11 Mar 2015 16:11:33 +0100 Subject: [PATCH 089/567] brcmfmac: fix watchdog timer regression The watchdog timer is used to put the device in a low-power mode when it is idle for some time. This timer is stopped during that mode and should be restarted upon activity. This has been broken by commit d4150fced0365 ("brcmfmac: Simplify watchdog sleep."). This patch restores the behaviour as it was before that commit. Reported-by: Pontus Fuchs Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 5202e766535d..17a7212cfd70 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -972,7 +972,6 @@ static int brcmf_sdio_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) brcmf_sdio_sdclk(bus, true); /* Now request HT Avail on the backplane */ brcmf_sdio_htclk(bus, true, pendok); - brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); break; case CLK_SDONLY: @@ -984,7 +983,6 @@ static int brcmf_sdio_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) else brcmf_err("request for %d -> %d\n", bus->clkstate, target); - brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); break; case CLK_NONE: @@ -993,7 +991,6 @@ static int brcmf_sdio_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) brcmf_sdio_htclk(bus, false, false); /* Now remove the SD clock */ brcmf_sdio_sdclk(bus, false); - brcmf_sdio_wd_timer(bus, 0); break; } #ifdef DEBUG @@ -1048,6 +1045,7 @@ end: brcmf_sdio_clkctl(bus, CLK_NONE, pendok); } else { brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok); + brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); } bus->sleeping = sleep; brcmf_dbg(SDIO, "new state %s\n", @@ -4242,6 +4240,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) if (bus->ci) { if (bus->sdiodev->state != BRCMF_SDIOD_NOMEDIUM) { sdio_claim_host(bus->sdiodev->func[1]); + brcmf_sdio_wd_timer(bus, 0); brcmf_sdio_clkctl(bus, CLK_AVAIL, false); /* Leave the device in state where it is * 'passive'. This is done by resetting all From 76830b267aecf127aea6e9c86230a01b57eb9282 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 11 Mar 2015 17:56:30 +0100 Subject: [PATCH 090/567] libertas_tf: if_usb.c: don't export static symbol The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @r@ type T; identifier f; @@ static T f (...) { ... } @@ identifier r.f; declarer name EXPORT_SYMBOL_GPL; @@ -EXPORT_SYMBOL_GPL(f); // Signed-off-by: Julia Lawall Signed-off-by: Kalle Valo --- drivers/net/wireless/libertas_tf/if_usb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c index d576dd6665d3..1a20cee5febe 100644 --- a/drivers/net/wireless/libertas_tf/if_usb.c +++ b/drivers/net/wireless/libertas_tf/if_usb.c @@ -365,7 +365,6 @@ static int if_usb_reset_device(struct if_usb_card *cardp) return ret; } -EXPORT_SYMBOL_GPL(if_usb_reset_device); /** * usb_tx_block - transfer data to the device @@ -907,7 +906,6 @@ restart: lbtf_deb_leave_args(LBTF_DEB_USB, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(if_usb_prog_firmware); #define if_usb_suspend NULL From 708c964c5df8536f555bb86a8acb837835808e38 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Tue, 10 Mar 2015 00:07:08 +0900 Subject: [PATCH 091/567] rtlwifi: rtl8192cu: remove unused arguments from _beacon_function_enable() Remove unnecessary parameter in rtl8192cu/hw.c Signed-off-by: Taehee Yoo Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 0c20dd74d6ec..43b2b20e3fcf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1471,8 +1471,7 @@ static void _InitBeaconParameters(struct ieee80211_hw *hw) rtl_write_word(rtlpriv, REG_BCNTCFG, 0x66FF); } -static void _beacon_function_enable(struct ieee80211_hw *hw, bool Enable, - bool Linked) +static void _beacon_function_enable(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1517,7 +1516,7 @@ void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x50); rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x50); } - _beacon_function_enable(hw, true, true); + _beacon_function_enable(hw); } void rtl92cu_set_beacon_interval(struct ieee80211_hw *hw) From 9a30b096b543932de218dd3501b5562e00a8792d Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 12 Mar 2015 23:53:26 -0400 Subject: [PATCH 092/567] blk-mq: fix use of incorrect goto label in blk_mq_init_queue error path If percpu_ref_init() fails the allocated q and hctxs must get cleaned up; using 'err_map' doesn't allow that to happen. Signed-off-by: Mike Snitzer Reviewed-by: Ming Lei Cc: stable@kernel.org Signed-off-by: Jens Axboe --- block/blk-mq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 4f4bea21052e..b7b8933ec241 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1938,7 +1938,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) */ if (percpu_ref_init(&q->mq_usage_counter, blk_mq_usage_counter_release, PERCPU_REF_INIT_ATOMIC, GFP_KERNEL)) - goto err_map; + goto err_mq_usage; setup_timer(&q->timeout, blk_mq_rq_timer, (unsigned long) q); blk_queue_rq_timeout(q, 30000); @@ -1981,7 +1981,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) blk_mq_init_cpu_queues(q, set->nr_hw_queues); if (blk_mq_init_hw_queues(q, set)) - goto err_hw; + goto err_mq_usage; mutex_lock(&all_q_mutex); list_add_tail(&q->all_q_node, &all_q_list); @@ -1993,7 +1993,7 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) return q; -err_hw: +err_mq_usage: blk_cleanup_queue(q); err_hctxs: kfree(map); From 702131e2a393b45174be326f1dbe20b658b4f157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 5 Mar 2015 18:25:10 +0100 Subject: [PATCH 093/567] bcma: move PCI IRQ control function to host specific code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function isn't really related to any bus core. It touches PCI device config registers only, so move it to the (PCI) host file. Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/bcma/driver_pci.c | 33 ------------------ drivers/bcma/host_pci.c | 34 +++++++++++++++++++ drivers/net/wireless/b43/main.c | 2 +- .../net/wireless/brcm80211/brcmsmac/main.c | 2 +- include/linux/bcma/bcma.h | 9 +++++ include/linux/bcma/bcma_driver_pci.h | 2 -- 6 files changed, 45 insertions(+), 37 deletions(-) diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index cfd35bc1c5a3..f499a469e66d 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -282,39 +282,6 @@ void bcma_core_pci_power_save(struct bcma_bus *bus, bool up) } EXPORT_SYMBOL_GPL(bcma_core_pci_power_save); -int bcma_core_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core, - bool enable) -{ - struct pci_dev *pdev; - u32 coremask, tmp; - int err = 0; - - if (bus->hosttype != BCMA_HOSTTYPE_PCI) { - /* This bcma device is not on a PCI host-bus. So the IRQs are - * not routed through the PCI core. - * So we must not enable routing through the PCI core. */ - goto out; - } - - pdev = bus->host_pci; - - err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); - if (err) - goto out; - - coremask = BIT(core->core_index) << 8; - if (enable) - tmp |= coremask; - else - tmp &= ~coremask; - - err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp); - -out: - return err; -} -EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl); - static void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend) { u32 w; diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index a62a2f9091f5..0856189c065f 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -351,3 +351,37 @@ void bcma_host_pci_down(struct bcma_bus *bus) bcma_core_pci_down(&bus->drv_pci[0]); } EXPORT_SYMBOL_GPL(bcma_host_pci_down); + +/* See also si_pci_setup */ +int bcma_host_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core, + bool enable) +{ + struct pci_dev *pdev; + u32 coremask, tmp; + int err = 0; + + if (bus->hosttype != BCMA_HOSTTYPE_PCI) { + /* This bcma device is not on a PCI host-bus. So the IRQs are + * not routed through the PCI core. + * So we must not enable routing through the PCI core. */ + goto out; + } + + pdev = bus->host_pci; + + err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp); + if (err) + goto out; + + coremask = BIT(core->core_index) << 8; + if (enable) + tmp |= coremask; + else + tmp &= ~coremask; + + err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp); + +out: + return err; +} +EXPORT_SYMBOL_GPL(bcma_host_pci_irq_ctl); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ac99798570e8..998490a7b167 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4866,7 +4866,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) switch (dev->dev->bus_type) { #ifdef CONFIG_B43_BCMA case B43_BUS_BCMA: - bcma_core_pci_irq_ctl(dev->dev->bdev->bus, + bcma_host_pci_irq_ctl(dev->dev->bdev->bus, dev->dev->bdev, true); bcma_host_pci_up(dev->dev->bdev->bus); break; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index c84af1dfc88f..369527e27689 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -4959,7 +4959,7 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) * Configure pci/pcmcia here instead of in brcms_c_attach() * to allow mfg hotswap: down, hotswap (chip power cycle), up. */ - bcma_core_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core, + bcma_host_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core, true); /* diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 44057b45ed32..e34f906647d3 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -437,6 +437,8 @@ static inline struct bcma_device *bcma_find_core(struct bcma_bus *bus, #ifdef CONFIG_BCMA_HOST_PCI extern void bcma_host_pci_up(struct bcma_bus *bus); extern void bcma_host_pci_down(struct bcma_bus *bus); +extern int bcma_host_pci_irq_ctl(struct bcma_bus *bus, + struct bcma_device *core, bool enable); #else static inline void bcma_host_pci_up(struct bcma_bus *bus) { @@ -444,6 +446,13 @@ static inline void bcma_host_pci_up(struct bcma_bus *bus) static inline void bcma_host_pci_down(struct bcma_bus *bus) { } +static inline int bcma_host_pci_irq_ctl(struct bcma_bus *bus, + struct bcma_device *core, bool enable) +{ + if (bus->hosttype == BCMA_HOSTTYPE_PCI) + return -ENOTSUPP; + return 0; +} #endif extern bool bcma_core_is_enabled(struct bcma_device *core); diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 8e90004fdfd7..3a468687c170 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -238,8 +238,6 @@ struct bcma_drv_pci { #define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val) #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) -extern int bcma_core_pci_irq_ctl(struct bcma_bus *bus, - struct bcma_device *core, bool enable); extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up); extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); From 982a40f5c0bb03368989a6b1ae833b474854e931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 5 Mar 2015 18:25:11 +0100 Subject: [PATCH 094/567] bcma: allow disabling (not building) PCI driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It isn't required for bcma bus on SoCs, so provide some empty functions and allow disabling it. Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/bcma/Kconfig | 4 ++-- drivers/bcma/bcma_private.h | 20 ++++++++++++++++++++ include/linux/bcma/bcma_driver_pci.h | 6 ++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 9be17d3431bb..1500b7120fc7 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -45,9 +45,9 @@ config BCMA_HOST_SOC If unsure, say N -# TODO: make it depend on PCI when ready config BCMA_DRIVER_PCI - bool + bool "BCMA Broadcom PCI core driver" + depends on BCMA && PCI default y help BCMA bus may have many versions of PCIe core. This driver diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 5a1d22489afc..15f2b2e242ea 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -106,15 +106,35 @@ static inline void __exit bcma_host_soc_unregister_driver(void) #endif /* CONFIG_BCMA_HOST_SOC && CONFIG_OF */ /* driver_pci.c */ +#ifdef CONFIG_BCMA_DRIVER_PCI u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address); void bcma_core_pci_early_init(struct bcma_drv_pci *pc); void bcma_core_pci_init(struct bcma_drv_pci *pc); void bcma_core_pci_up(struct bcma_drv_pci *pc); void bcma_core_pci_down(struct bcma_drv_pci *pc); +#else +static inline void bcma_core_pci_early_init(struct bcma_drv_pci *pc) +{ + WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI); +} +static inline void bcma_core_pci_init(struct bcma_drv_pci *pc) +{ + /* Initialization is required for PCI hosted bus */ + WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI); +} +#endif /* driver_pcie2.c */ +#ifdef CONFIG_BCMA_DRIVER_PCI void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2); void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2); +#else +static inline void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2) +{ + /* Initialization is required for PCI hosted bus */ + WARN_ON(pcie2->core->bus->hosttype == BCMA_HOSTTYPE_PCI); +} +#endif extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc); diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 3a468687c170..5ba6918ca20b 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -238,7 +238,13 @@ struct bcma_drv_pci { #define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val) #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) +#ifdef CONFIG_BCMA_DRIVER_PCI extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up); +#else +static inline void bcma_core_pci_power_save(struct bcma_bus *bus, bool up) +{ +} +#endif extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); From 6029e0c59b1c80b9669717f055b65588bde9754e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 5 Mar 2015 18:25:12 +0100 Subject: [PATCH 095/567] Revert "bcma: Kconfig: Let it depend on PCI" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit b09f5ec18b16b82f4db8a735e453332db7514275. Now that we have fully working BCMA_DRIVER_PCI symbol (in can be safely disabled), there is no risk bcma will try to use PCI code without PCI available. Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/bcma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index 1500b7120fc7..fc6ffcfa8061 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -1,6 +1,6 @@ config BCMA_POSSIBLE bool - depends on HAS_IOMEM && HAS_DMA && PCI + depends on HAS_IOMEM && HAS_DMA default y menu "Broadcom specific AMBA" From b4331b433a2860389c9e35a523f0127788248500 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sat, 14 Mar 2015 19:32:06 +0100 Subject: [PATCH 096/567] MAINTAINERS: add rockchip regexp to the ARM/Rockchip entry The regexp option is a nice way to catch even weirder paths like the current drivers/gpu/drm/rockchip/* or others in the future. Signed-off-by: Heiko Stuebner --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ddc5a8cf9a8a..0d273bd264ac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1351,6 +1351,7 @@ F: drivers/i2c/busses/i2c-rk3x.c F: drivers/*/*rockchip* F: drivers/*/*/*rockchip* F: sound/soc/rockchip/ +N: rockchip ARM/SAMSUNG EXYNOS ARM ARCHITECTURES M: Kukjin Kim From 54b0bc602541fcc2dd9f2480623c00552e0b220e Mon Sep 17 00:00:00 2001 From: Alexandru M Stan Date: Fri, 13 Mar 2015 17:55:32 -0700 Subject: [PATCH 097/567] ARM: dts: rockchip: disable gmac by default in rk3288.dtsi This block should not be enabled by default or else if the kconfig is set, it will try to load/probe even if there's no phy connected. Signed-off-by: Alexandru M Stan Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rk3288.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index d771f687a13b..eccc78d3220b 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -411,6 +411,7 @@ "mac_clk_rx", "mac_clk_tx", "clk_mac_ref", "clk_mac_refout", "aclk_mac", "pclk_mac"; + status = "disabled"; }; usb_host0_ehci: usb@ff500000 { From 0ba8da961bd868c67a8dae3dbbee145514515e9c Mon Sep 17 00:00:00 2001 From: Sathyanarayanan Kuppuswamy Date: Tue, 3 Mar 2015 18:17:56 +0200 Subject: [PATCH 098/567] iio: bmc150: change sampling frequency Currently driver reports device bandwidth list as available sampling frequency. But sampling frequency is actually twice the device bandwidth. This patch fixes this issue. Signed-off-by: Sathyanarayanan Kuppuswamy Signed-off-by: Octavian Purdila Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 7d1383de3e85..75567fd457dc 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -168,14 +168,14 @@ static const struct { int val; int val2; u8 bw_bits; -} bmc150_accel_samp_freq_table[] = { {7, 810000, 0x08}, - {15, 630000, 0x09}, - {31, 250000, 0x0A}, - {62, 500000, 0x0B}, - {125, 0, 0x0C}, - {250, 0, 0x0D}, - {500, 0, 0x0E}, - {1000, 0, 0x0F} }; +} bmc150_accel_samp_freq_table[] = { {15, 620000, 0x08}, + {31, 260000, 0x09}, + {62, 500000, 0x0A}, + {125, 0, 0x0B}, + {250, 0, 0x0C}, + {500, 0, 0x0D}, + {1000, 0, 0x0E}, + {2000, 0, 0x0F} }; static const struct { int bw_bits; @@ -840,7 +840,7 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev, } static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( - "7.810000 15.630000 31.250000 62.500000 125 250 500 1000"); + "15.620000 31.260000 62.50000 125 250 500 1000 2000"); static struct attribute *bmc150_accel_attributes[] = { &iio_const_attr_sampling_frequency_available.dev_attr.attr, From 8d09f48adfd282157f6afc94d2502b44156cb12f Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Sat, 28 Feb 2015 21:54:42 +0100 Subject: [PATCH 099/567] staging: iio: hmc5843: Set iio name property in sysfs Without this change file name for hmc5843 is empty in /sys/bus/iio/devices/iio\:device*/name With this change name is reported correctly: cat /sys/bus/iio/devices/iio\:device*/name hmc5843 Signed-off-by: Marek Belisko Signed-off-by: Jonathan Cameron --- drivers/staging/iio/magnetometer/hmc5843_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/iio/magnetometer/hmc5843_core.c b/drivers/staging/iio/magnetometer/hmc5843_core.c index fd171d8b38fb..90cc18b703cf 100644 --- a/drivers/staging/iio/magnetometer/hmc5843_core.c +++ b/drivers/staging/iio/magnetometer/hmc5843_core.c @@ -592,6 +592,7 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap, mutex_init(&data->lock); indio_dev->dev.parent = dev; + indio_dev->name = dev->driver->name; indio_dev->info = &hmc5843_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = data->variant->channels; From 4dac0a8eefd55bb1f157d1a5a084531334a2d74c Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Wed, 18 Feb 2015 20:05:21 +0200 Subject: [PATCH 100/567] iio: inv_mpu6050: Clear timestamps fifo while resetting hardware fifo A hardware fifo reset always imply an invalidation of the existing timestamps, so we'll clear timestamps fifo on successfull hardware fifo reset. Signed-off-by: Viorel Suman Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 0cd306a72a6e..ba27e277511f 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -24,6 +24,16 @@ #include #include "inv_mpu_iio.h" +static void inv_clear_kfifo(struct inv_mpu6050_state *st) +{ + unsigned long flags; + + /* take the spin lock sem to avoid interrupt kick in */ + spin_lock_irqsave(&st->time_stamp_lock, flags); + kfifo_reset(&st->timestamps); + spin_unlock_irqrestore(&st->time_stamp_lock, flags); +} + int inv_reset_fifo(struct iio_dev *indio_dev) { int result; @@ -50,6 +60,10 @@ int inv_reset_fifo(struct iio_dev *indio_dev) INV_MPU6050_BIT_FIFO_RST); if (result) goto reset_fifo_fail; + + /* clear timestamps fifo */ + inv_clear_kfifo(st); + /* enable interrupt */ if (st->chip_config.accl_fifo_enable || st->chip_config.gyro_fifo_enable) { @@ -83,16 +97,6 @@ reset_fifo_fail: return result; } -static void inv_clear_kfifo(struct inv_mpu6050_state *st) -{ - unsigned long flags; - - /* take the spin lock sem to avoid interrupt kick in */ - spin_lock_irqsave(&st->time_stamp_lock, flags); - kfifo_reset(&st->timestamps); - spin_unlock_irqrestore(&st->time_stamp_lock, flags); -} - /** * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt. */ @@ -184,7 +188,6 @@ end_session: flush_fifo: /* Flush HW and SW FIFOs. */ inv_reset_fifo(indio_dev); - inv_clear_kfifo(st); mutex_unlock(&indio_dev->mlock); iio_trigger_notify_done(indio_dev->trig); From ed170dedd1ddd316c5cd17fec3dd7937981e2fb7 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 9 Mar 2015 12:15:53 +0200 Subject: [PATCH 101/567] staging: iio: dummy: Fix undefined symbol build error CONFIG_SIMPLE_DUMMY_BUFFER compiles in iio_simple_dummy_buffer.c file which uses functions from industrialio-trigger.c. So, CONFIG_SIMPLE_DUMMY_BUFFER needs to select IIO_TRIGGER in order to avoid build error like this: > ERROR: "iio_trigger_notify_done" [drivers/staging/iio/iio_dummy.ko] undefined! > ERROR: "iio_triggered_buffer_postenable" [drivers/staging/iio/iio_dummy.ko] undefined! > ERROR: "iio_triggered_buffer_predisable" [drivers/staging/iio/iio_dummy.ko] undefined! > ERROR: "iio_alloc_pollfunc" [drivers/staging/iio/iio_dummy.ko] undefined! > ERROR: "iio_dealloc_pollfunc" [drivers/staging/iio/iio_dummy.ko] undefined! Cc: Arnd Bergmann Reported-by: kbuild test robot Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/staging/iio/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index 24183028bd71..6d5b38d69578 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -38,6 +38,7 @@ config IIO_SIMPLE_DUMMY_EVENTS config IIO_SIMPLE_DUMMY_BUFFER bool "Buffered capture support" select IIO_BUFFER + select IIO_TRIGGER select IIO_KFIFO_BUF help Add buffered data capture to the simple dummy driver. From af5e1a68318e2ed2de22fc2d7a02f2882abe073c Mon Sep 17 00:00:00 2001 From: Adriana Reus Date: Mon, 23 Feb 2015 16:40:51 +0200 Subject: [PATCH 102/567] iio:inv-mpu6050: Fix inconsistency for the scale channel Fix inconsistency in the semantics of the scale attribute. For scale the write_raw function was considering the scale table index and writing the appropriate value into the range register, while for read_raw it was outputting the actual scale. Fix this behaviour and adhere to the iio ABI specification. Signed-off-by: Adriana Reus Reviewed-by: Viorel Suman Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 56 ++++++++++++---------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index d8d5bed65e07..ef76afe2643c 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -410,42 +410,46 @@ error_read_raw: } } -static int inv_mpu6050_write_fsr(struct inv_mpu6050_state *st, int fsr) +static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val) { - int result; + int result, i; u8 d; - if (fsr < 0 || fsr > INV_MPU6050_MAX_GYRO_FS_PARAM) - return -EINVAL; - if (fsr == st->chip_config.fsr) - return 0; + for (i = 0; i < ARRAY_SIZE(gyro_scale_6050); ++i) { + if (gyro_scale_6050[i] == val) { + d = (i << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, + st->reg->gyro_config, d); + if (result) + return result; - d = (fsr << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); - result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d); - if (result) - return result; - st->chip_config.fsr = fsr; + st->chip_config.fsr = i; + return 0; + } + } - return 0; + return -EINVAL; } -static int inv_mpu6050_write_accel_fs(struct inv_mpu6050_state *st, int fs) +static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val) { - int result; + int result, i; u8 d; - if (fs < 0 || fs > INV_MPU6050_MAX_ACCL_FS_PARAM) - return -EINVAL; - if (fs == st->chip_config.accl_fs) - return 0; + for (i = 0; i < ARRAY_SIZE(accel_scale); ++i) { + if (accel_scale[i] == val) { + d = (i << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, + st->reg->accl_config, d); + if (result) + return result; - d = (fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); - result = inv_mpu6050_write_reg(st, st->reg->accl_config, d); - if (result) - return result; - st->chip_config.accl_fs = fs; + st->chip_config.accl_fs = i; + return 0; + } + } - return 0; + return -EINVAL; } static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, @@ -471,10 +475,10 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - result = inv_mpu6050_write_fsr(st, val); + result = inv_mpu6050_write_gyro_scale(st, val2); break; case IIO_ACCEL: - result = inv_mpu6050_write_accel_fs(st, val); + result = inv_mpu6050_write_accel_scale(st, val2); break; default: result = -EINVAL; From c1b03ab5e886760bdd38c9c7a27af149046ffe01 Mon Sep 17 00:00:00 2001 From: Martin Fuzzey Date: Thu, 19 Feb 2015 15:17:44 +0100 Subject: [PATCH 103/567] iio: core: Fix double free. When an error occurred during event registration memory was freed twice resulting in kernel memory corruption and a crash in unrelated code. The problem was caused by iio_device_unregister_eventset() iio_device_unregister_sysfs() being called twice, once on the error path and then again via iio_dev_release(). Fix this by making these two functions idempotent so they may be called multiple times. The problem was observed before applying 78b33216 iio:core: Handle error when mask type is not separate Signed-off-by: Martin Fuzzey Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 5 +++-- drivers/iio/industrialio-event.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index aaba9d3d980e..4df97f650e44 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -847,8 +847,7 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, * @attr_list: List of IIO device attributes * * This function frees the memory allocated for each of the IIO device - * attributes in the list. Note: if you want to reuse the list after calling - * this function you have to reinitialize it using INIT_LIST_HEAD(). + * attributes in the list. */ void iio_free_chan_devattr_list(struct list_head *attr_list) { @@ -856,6 +855,7 @@ void iio_free_chan_devattr_list(struct list_head *attr_list) list_for_each_entry_safe(p, n, attr_list, l) { kfree(p->dev_attr.attr.name); + list_del(&p->l); kfree(p); } } @@ -936,6 +936,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) iio_free_chan_devattr_list(&indio_dev->channel_attr_list); kfree(indio_dev->chan_attr_group.attrs); + indio_dev->chan_attr_group.attrs = NULL; } static void iio_dev_release(struct device *device) diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index a4b397048f71..a99692ba91bc 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -500,6 +500,7 @@ int iio_device_register_eventset(struct iio_dev *indio_dev) error_free_setup_event_lines: iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list); kfree(indio_dev->event_interface); + indio_dev->event_interface = NULL; return ret; } From 1cf48f22c98ae24a49a3f1b6900e4c9a9a0fcc62 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 12 Mar 2015 17:17:18 +0100 Subject: [PATCH 104/567] ath9k: fix tracking of enabled AP beacons sc->nbcnvifs tracks assigned beacon slots, not enabled beacons. Therefore, it cannot be used to decide if cur_conf->enable_beacon (bool) should be updated, or if beacons have been enabled already. With the current code (depending on the order of calls), beacons often do not get enabled in an AP+STA setup. To fix tracking of enabled beacons, convert cur_conf->enable_beacon to a bitmask of enabled beacon slots. Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/beacon.c | 20 ++++++++++++-------- drivers/net/wireless/ath/ath9k/common.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index cb366adc820b..f50a6bc5d06e 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -219,12 +219,15 @@ void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif) struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (void *)vif->drv_priv; struct ath_buf *bf = avp->av_bcbuf; + struct ath_beacon_config *cur_conf = &sc->cur_chan->beacon; ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n", avp->av_bslot); tasklet_disable(&sc->bcon_tasklet); + cur_conf->enable_beacon &= ~BIT(avp->av_bslot); + if (bf && bf->bf_mpdu) { struct sk_buff *skb = bf->bf_mpdu; dma_unmap_single(sc->dev, bf->bf_buf_addr, @@ -521,8 +524,7 @@ static bool ath9k_allow_beacon_config(struct ath_softc *sc, } if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { - if ((vif->type != NL80211_IFTYPE_AP) || - (sc->nbcnvifs > 1)) { + if (vif->type != NL80211_IFTYPE_AP) { ath_dbg(common, CONFIG, "An AP interface is already present !\n"); return false; @@ -616,12 +618,14 @@ void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, * enabling/disabling SWBA. */ if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (!bss_conf->enable_beacon && - (sc->nbcnvifs <= 1)) { - cur_conf->enable_beacon = false; - } else if (bss_conf->enable_beacon) { - cur_conf->enable_beacon = true; - ath9k_cache_beacon_config(sc, ctx, bss_conf); + bool enabled = cur_conf->enable_beacon; + + if (!bss_conf->enable_beacon) { + cur_conf->enable_beacon &= ~BIT(avp->av_bslot); + } else { + cur_conf->enable_beacon |= BIT(avp->av_bslot); + if (!enabled) + ath9k_cache_beacon_config(sc, ctx, bss_conf); } } diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 2b79a568e803..d23737342f4f 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -54,7 +54,7 @@ struct ath_beacon_config { u16 dtim_period; u16 bmiss_timeout; u8 dtim_count; - bool enable_beacon; + u8 enable_beacon; bool ibss_creator; u32 nexttbtt; u32 intval; From c09396eb8e5a8df668174993c6400763022b2466 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 15 Mar 2015 08:07:04 +0100 Subject: [PATCH 105/567] ath9k: disable TPC support again (for now) TPC support has been observed to cause some tx power fluctuations on some devices with at least AR934x and AR938x chips. Disable it for now until the bugs have been found and fixed Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 60aa8d71e753..8529014e1a5e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -424,7 +424,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->power_mode = ATH9K_PM_UNDEFINED; ah->htc_reset_init = true; - ah->tpc_enabled = true; + ah->tpc_enabled = false; ah->ani_function = ATH9K_ANI_ALL; if (!AR_SREV_9300_20_OR_LATER(ah)) From 4899c054a90439477b24da8977db8d738376fe90 Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Sun, 15 Mar 2015 21:56:04 -0500 Subject: [PATCH 106/567] USB: ftdi_sio: Added custom PID for Synapse Wireless product Synapse Wireless uses the FTDI VID with a custom PID of 0x9090 for their SNAP Stick 200 product. Signed-off-by: Doug Goldstein Cc: stable Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3086dec0ef53..130b354a8fd7 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -604,6 +604,7 @@ static const struct usb_device_id id_table_combined[] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) }, /* * ELV devices: */ diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 56b1b55c4751..4e4f46f3c89c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -561,6 +561,12 @@ */ #define FTDI_NT_ORIONLXM_PID 0x7c90 /* OrionLXm Substation Automation Platform */ +/* + * Synapse Wireless product ids (FTDI_VID) + * http://www.synapse-wireless.com + */ +#define FTDI_SYNAPSE_SS200_PID 0x9090 /* SS200 - SNAP Stick 200 */ + /********************************/ /** third-party VID/PID combos **/ From 8252a35ab4f6ee703977f527296dc42ee9486ce2 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 10 Mar 2015 17:49:29 +0100 Subject: [PATCH 107/567] ath9k: restart only triggering DFS detector line To support HT40 DFS mode, a triggering detector must reset only itself but not other detector lines. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/dfs_pattern_detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index 3d57f8772389..c657ca26a71a 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c @@ -289,7 +289,7 @@ dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event) "count=%d, count_false=%d\n", event->freq, pd->rs->type_id, ps->pri, ps->count, ps->count_falses); - channel_detector_reset(dpd, cd); + pd->reset(pd, dpd->last_pulse_ts); return true; } } From 58766977ad12b90ca7d7fa4d9ffd2dfde1bcf469 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 10 Mar 2015 17:49:30 +0100 Subject: [PATCH 108/567] ath9k: add DFS support for extension channel In HT40 modes, pulse events on primary and extension channel are processed individually. If valid, a pulse event will be fed into the detector * for primary frequency, or * for extension frequency (+/-20MHz based on HT40-mode) * or both With that, a 40MHz radar will result in two individual radar events. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/dfs.c | 44 ++++++++++++++++++---------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index 726271c7c330..e98a9eaba7ff 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -126,8 +126,19 @@ ath9k_postprocess_radar_event(struct ath_softc *sc, DFS_STAT_INC(sc, pulses_detected); return true; } -#undef PRI_CH_RADAR_FOUND -#undef EXT_CH_RADAR_FOUND + +static void +ath9k_dfs_process_radar_pulse(struct ath_softc *sc, struct pulse_event *pe) +{ + struct dfs_pattern_detector *pd = sc->dfs_detector; + DFS_STAT_INC(sc, pulses_processed); + if (pd == NULL) + return; + if (!pd->add_pulse(pd, pe)) + return; + DFS_STAT_INC(sc, radar_detected); + ieee80211_radar_detected(sc->hw); +} /* * DFS: check PHY-error for radar pulse and feed the detector @@ -176,18 +187,21 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, ard.pulse_length_pri = vdata_end[-3]; pe.freq = ah->curchan->channel; pe.ts = mactime; - if (ath9k_postprocess_radar_event(sc, &ard, &pe)) { - struct dfs_pattern_detector *pd = sc->dfs_detector; - ath_dbg(common, DFS, - "ath9k_dfs_process_phyerr: channel=%d, ts=%llu, " - "width=%d, rssi=%d, delta_ts=%llu\n", - pe.freq, pe.ts, pe.width, pe.rssi, - pe.ts - sc->dfs_prev_pulse_ts); - sc->dfs_prev_pulse_ts = pe.ts; - DFS_STAT_INC(sc, pulses_processed); - if (pd != NULL && pd->add_pulse(pd, &pe)) { - DFS_STAT_INC(sc, radar_detected); - ieee80211_radar_detected(sc->hw); - } + if (!ath9k_postprocess_radar_event(sc, &ard, &pe)) + return; + + ath_dbg(common, DFS, + "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, " + "width=%d, rssi=%d, delta_ts=%llu\n", + ard.pulse_bw_info, pe.freq, pe.ts, pe.width, pe.rssi, + pe.ts - sc->dfs_prev_pulse_ts); + sc->dfs_prev_pulse_ts = pe.ts; + if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND) + ath9k_dfs_process_radar_pulse(sc, &pe); + if (ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { + pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20; + ath9k_dfs_process_radar_pulse(sc, &pe); } } +#undef PRI_CH_RADAR_FOUND +#undef EXT_CH_RADAR_FOUND From 387f149a2ace2e2569fb8fde6011cce2a84e07b8 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 10 Mar 2015 17:49:31 +0100 Subject: [PATCH 109/567] ath9k: allow 40MHz radar detection width Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index de862ad13b51..b889a8fc1982 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -770,7 +770,8 @@ static const struct ieee80211_iface_combination if_comb[] = { .num_different_channels = 1, .beacon_int_infra_match = true, .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | - BIT(NL80211_CHAN_WIDTH_20), + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40), } #endif }; From 54fb66d6fe98c75d5cb0b0487f0e2b00cb412be7 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 11 Mar 2015 22:03:25 +0200 Subject: [PATCH 110/567] rtlwifi: Clean rtl_evm_db_to_percentage a bit Signed-off-by: Priit Laes Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/stats.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/stats.c b/drivers/net/wireless/rtlwifi/stats.c index 2d0736a09fc0..4201d7340d49 100644 --- a/drivers/net/wireless/rtlwifi/stats.c +++ b/drivers/net/wireless/rtlwifi/stats.c @@ -39,15 +39,8 @@ EXPORT_SYMBOL(rtl_query_rxpwrpercentage); u8 rtl_evm_db_to_percentage(char value) { - char ret_val; - ret_val = value; + char ret_val = clamp(-value, 0, 33) * 3; - if (ret_val >= 0) - ret_val = 0; - if (ret_val <= -33) - ret_val = -33; - ret_val = 0 - ret_val; - ret_val *= 3; if (ret_val == 99) ret_val = 100; From 52f119ddea412af870fb84412c0f7832e85c7663 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 11 Mar 2015 22:03:27 +0200 Subject: [PATCH 111/567] rtlwifi: No need to export rtl_evm_dbm_jaguar anymore This function is used only by rtl8821ae so move it there Signed-off-by: Priit Laes Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8821ae/trx.c | 16 +++++++++++++++- drivers/net/wireless/rtlwifi/stats.c | 15 --------------- drivers/net/wireless/rtlwifi/stats.h | 1 - 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c index 72af4b9ee32b..174743aef943 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c @@ -64,6 +64,20 @@ static u16 odm_cfo(char value) return ret_val; } +static u8 _rtl8821ae_evm_dbm_jaguar(char value) +{ + char ret_val = value; + + /* -33dB~0dB to 33dB ~ 0dB*/ + if (ret_val == -128) + ret_val = 127; + else if (ret_val < 0) + ret_val = 0 - ret_val; + + ret_val = ret_val >> 1; + return ret_val; +} + static void query_rxphystatus(struct ieee80211_hw *hw, struct rtl_stats *pstatus, u8 *pdesc, struct rx_fwinfo_8821ae *p_drvinfo, @@ -246,7 +260,7 @@ static void query_rxphystatus(struct ieee80211_hw *hw, for (i = 0; i < max_spatial_stream; i++) { evm = rtl_evm_db_to_percentage(p_phystrpt->rxevm[i]); - evmdbm = rtl_evm_dbm_jaguar(p_phystrpt->rxevm[i]); + evmdbm = _rtl8821ae_evm_dbm_jaguar(p_phystrpt->rxevm[i]); if (bpacket_match_bssid) { /* Fill value in RFD, Get the first diff --git a/drivers/net/wireless/rtlwifi/stats.c b/drivers/net/wireless/rtlwifi/stats.c index 4201d7340d49..d8b30690b00d 100644 --- a/drivers/net/wireless/rtlwifi/stats.c +++ b/drivers/net/wireless/rtlwifi/stats.c @@ -48,21 +48,6 @@ u8 rtl_evm_db_to_percentage(char value) } EXPORT_SYMBOL(rtl_evm_db_to_percentage); -u8 rtl_evm_dbm_jaguar(char value) -{ - char ret_val = value; - - /* -33dB~0dB to 33dB ~ 0dB*/ - if (ret_val == -128) - ret_val = 127; - else if (ret_val < 0) - ret_val = 0 - ret_val; - - ret_val = ret_val >> 1; - return ret_val; -} -EXPORT_SYMBOL(rtl_evm_dbm_jaguar); - static long rtl_translate_todbm(struct ieee80211_hw *hw, u8 signal_strength_index) { diff --git a/drivers/net/wireless/rtlwifi/stats.h b/drivers/net/wireless/rtlwifi/stats.h index aa4eec80ccf7..2b57dffef572 100644 --- a/drivers/net/wireless/rtlwifi/stats.h +++ b/drivers/net/wireless/rtlwifi/stats.h @@ -35,7 +35,6 @@ u8 rtl_query_rxpwrpercentage(char antpower); u8 rtl_evm_db_to_percentage(char value); -u8 rtl_evm_dbm_jaguar(char value); long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig); void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer, struct rtl_stats *pstatus); From 2c11ab90067a8bb9d7dca3e65ace950fcd9c2f1b Mon Sep 17 00:00:00 2001 From: Cathy Luo Date: Thu, 12 Mar 2015 01:29:31 -0700 Subject: [PATCH 112/567] mwifiex: fix a bug in Rx multiport aggregation logic It's been observed Rx aggregated packets are always followed by a single Rx packet. This patch improves our logic to add that extra packet in next aggregation. Signed-off-by: Cathy Luo Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 57d85ab442bf..9ef010bfa7d9 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1133,6 +1133,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, s32 f_do_rx_aggr = 0; s32 f_do_rx_cur = 0; s32 f_aggr_cur = 0; + s32 f_post_aggr_cur = 0; struct sk_buff *skb_deaggr; u32 pind; u32 pkt_len, pkt_type, mport; @@ -1169,7 +1170,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, } else { /* No room in Aggr buf, do rx aggr now */ f_do_rx_aggr = 1; - f_do_rx_cur = 1; + f_post_aggr_cur = 1; } } else { /* Rx aggr not in progress */ @@ -1280,9 +1281,13 @@ rx_curr_single: mwifiex_decode_rx_packet(adapter, skb, pkt_type); } + if (f_post_aggr_cur) { + dev_dbg(adapter->dev, "info: current packet aggregation\n"); + /* Curr pkt can be aggregated */ + mp_rx_aggr_setup(card, skb, port); + } return 0; - error: if (MP_RX_AGGR_IN_PROGRESS(card)) { /* Multiport-aggregation transfer failed - cleanup */ From b533be189732e93c6d3306773b7120722568444d Mon Sep 17 00:00:00 2001 From: Maithili Hinge Date: Thu, 12 Mar 2015 00:38:39 -0700 Subject: [PATCH 113/567] mwifiex: Add support for auto ARP in mwifiex. This patch adds support for auto ARP feature in mwifiex. The device will respond to ARP requests from the network with ARP response in suspended state without waking up the host. This feature is enabled in the driver by default. Signed-off-by: Maithili Hinge Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 120 +++++++++++++++++++----- drivers/net/wireless/mwifiex/fw.h | 2 + drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sta_cmd.c | 21 +++-- 4 files changed, 113 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 8e1f681f960b..b0778a699bbc 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2732,24 +2732,71 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq, } #ifdef CONFIG_PM -static int mwifiex_set_mef_filter(struct mwifiex_private *priv, - struct cfg80211_wowlan *wowlan) +static void mwifiex_set_auto_arp_mef_entry(struct mwifiex_private *priv, + struct mwifiex_mef_entry *mef_entry) +{ + int i, filt_num = 0, num_ipv4 = 0; + struct in_device *in_dev; + struct in_ifaddr *ifa; + __be32 ips[MWIFIEX_MAX_SUPPORTED_IPADDR]; + struct mwifiex_adapter *adapter = priv->adapter; + + mef_entry->mode = MEF_MODE_HOST_SLEEP; + mef_entry->action = MEF_ACTION_AUTO_ARP; + + /* Enable ARP offload feature */ + memset(ips, 0, sizeof(ips)); + for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { + if (adapter->priv[i]->netdev) { + in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev); + if (!in_dev) + continue; + ifa = in_dev->ifa_list; + if (!ifa || !ifa->ifa_local) + continue; + ips[i] = ifa->ifa_local; + num_ipv4++; + } + } + + for (i = 0; i < num_ipv4; i++) { + if (!ips[i]) + continue; + mef_entry->filter[filt_num].repeat = 1; + memcpy(mef_entry->filter[filt_num].byte_seq, + (u8 *)&ips[i], sizeof(ips[i])); + mef_entry->filter[filt_num]. + byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = + sizeof(ips[i]); + mef_entry->filter[filt_num].offset = 46; + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + if (filt_num) { + mef_entry->filter[filt_num].filt_action = + TYPE_OR; + } + filt_num++; + } + + mef_entry->filter[filt_num].repeat = 1; + mef_entry->filter[filt_num].byte_seq[0] = 0x08; + mef_entry->filter[filt_num].byte_seq[1] = 0x06; + mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] = 2; + mef_entry->filter[filt_num].offset = 20; + mef_entry->filter[filt_num].filt_type = TYPE_EQ; + mef_entry->filter[filt_num].filt_action = TYPE_AND; +} + +static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, + struct mwifiex_ds_mef_cfg *mef_cfg, + struct mwifiex_mef_entry *mef_entry, + struct cfg80211_wowlan *wowlan) { int i, filt_num = 0, ret = 0; bool first_pat = true; u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1]; const u8 ipv4_mc_mac[] = {0x33, 0x33}; const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e}; - struct mwifiex_ds_mef_cfg mef_cfg; - struct mwifiex_mef_entry *mef_entry; - mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL); - if (!mef_entry) - return -ENOMEM; - - memset(&mef_cfg, 0, sizeof(mef_cfg)); - mef_cfg.num_entries = 1; - mef_cfg.mef_entry = mef_entry; mef_entry->mode = MEF_MODE_HOST_SLEEP; mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST; @@ -2766,20 +2813,19 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, if (!wowlan->patterns[i].pkt_offset) { if (!(byte_seq[0] & 0x01) && (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) { - mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; + mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST; continue; } else if (is_broadcast_ether_addr(byte_seq)) { - mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST; + mef_cfg->criteria |= MWIFIEX_CRITERIA_BROADCAST; continue; } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) && (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 2)) || (!memcmp(byte_seq, ipv6_mc_mac, 3) && (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 3))) { - mef_cfg.criteria |= MWIFIEX_CRITERIA_MULTICAST; + mef_cfg->criteria |= MWIFIEX_CRITERIA_MULTICAST; continue; } } - mef_entry->filter[filt_num].repeat = 1; mef_entry->filter[filt_num].offset = wowlan->patterns[i].pkt_offset; @@ -2796,7 +2842,7 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, } if (wowlan->magic_pkt) { - mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST; + mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST; mef_entry->filter[filt_num].repeat = 16; memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr, ETH_ALEN); @@ -2817,6 +2863,34 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, mef_entry->filter[filt_num].filt_type = TYPE_EQ; mef_entry->filter[filt_num].filt_action = TYPE_OR; } + return ret; +} + +static int mwifiex_set_mef_filter(struct mwifiex_private *priv, + struct cfg80211_wowlan *wowlan) +{ + int ret = 0, num_entries = 1; + struct mwifiex_ds_mef_cfg mef_cfg; + struct mwifiex_mef_entry *mef_entry; + + if (wowlan->n_patterns || wowlan->magic_pkt) + num_entries++; + + mef_entry = kcalloc(num_entries, sizeof(*mef_entry), GFP_KERNEL); + if (!mef_entry) + return -ENOMEM; + + memset(&mef_cfg, 0, sizeof(mef_cfg)); + mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST | + MWIFIEX_CRITERIA_UNICAST; + mef_cfg.num_entries = num_entries; + mef_cfg.mef_entry = mef_entry; + + mwifiex_set_auto_arp_mef_entry(priv, &mef_entry[0]); + + if (wowlan->n_patterns || wowlan->magic_pkt) + ret = mwifiex_set_wowlan_mef_entry(priv, &mef_cfg, + &mef_entry[1], wowlan); if (!mef_cfg.criteria) mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | @@ -2824,8 +2898,8 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, MWIFIEX_CRITERIA_MULTICAST; ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, - HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); - + HostCmd_ACT_GEN_SET, 0, + &mef_cfg, true); kfree(mef_entry); return ret; } @@ -2850,12 +2924,10 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, return 0; } - if (wowlan->n_patterns || wowlan->magic_pkt) { - ret = mwifiex_set_mef_filter(priv, wowlan); - if (ret) { - dev_err(adapter->dev, "Failed to set MEF filter\n"); - return ret; - } + ret = mwifiex_set_mef_filter(priv, wowlan); + if (ret) { + dev_err(adapter->dev, "Failed to set MEF filter\n"); + return ret; } if (wowlan->disconnect) { diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index df553e86a0ad..21a942fd2226 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -523,9 +523,11 @@ enum P2P_MODES { #define TYPE_OR (MAX_OPERAND+5) #define MEF_MODE_HOST_SLEEP 1 #define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3 +#define MEF_ACTION_AUTO_ARP 0x10 #define MWIFIEX_CRITERIA_BROADCAST BIT(0) #define MWIFIEX_CRITERIA_UNICAST BIT(1) #define MWIFIEX_CRITERIA_MULTICAST BIT(3) +#define MWIFIEX_MAX_SUPPORTED_IPADDR 4 #define ACT_TDLS_DELETE 0x00 #define ACT_TDLS_CREATE 0x01 diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 16be45e9a66a..a0908c64103a 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -35,6 +35,7 @@ #include #include #include +#include #include "decl.h" #include "ioctl.h" diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index f7d204ffd6e9..b23eaed84701 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1370,22 +1370,29 @@ mwifiex_cmd_mef_cfg(struct mwifiex_private *priv, struct mwifiex_ds_mef_cfg *mef) { struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg; + struct mwifiex_fw_mef_entry *mef_entry = NULL; u8 *pos = (u8 *)mef_cfg; + u16 i; cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG); mef_cfg->criteria = cpu_to_le32(mef->criteria); mef_cfg->num_entries = cpu_to_le16(mef->num_entries); pos += sizeof(*mef_cfg); - mef_cfg->mef_entry->mode = mef->mef_entry->mode; - mef_cfg->mef_entry->action = mef->mef_entry->action; - pos += sizeof(*(mef_cfg->mef_entry)); - if (mwifiex_cmd_append_rpn_expression(priv, mef->mef_entry, &pos)) - return -1; + for (i = 0; i < mef->num_entries; i++) { + mef_entry = (struct mwifiex_fw_mef_entry *)pos; + mef_entry->mode = mef->mef_entry[i].mode; + mef_entry->action = mef->mef_entry[i].action; + pos += sizeof(*mef_cfg->mef_entry); - mef_cfg->mef_entry->exprsize = - cpu_to_le16(pos - mef_cfg->mef_entry->expr); + if (mwifiex_cmd_append_rpn_expression(priv, + &mef->mef_entry[i], &pos)) + return -1; + + mef_entry->exprsize = + cpu_to_le16(pos - mef_entry->expr); + } cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN); return 0; From 6e9344fd8e90ff0bd8e74c15ec7c21eae7d54bd3 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Thu, 12 Mar 2015 00:38:40 -0700 Subject: [PATCH 114/567] mwifiex: use del_timer variant in interrupt context We might be in interrupt context at few places. So replace del_timer_sync() with del_timer(). This patch fixes a kernel trace problem seen occasionally during our testing. Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.c | 2 +- drivers/net/wireless/mwifiex/sta_event.c | 4 ++-- drivers/net/wireless/mwifiex/usb.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 74488aba92bd..42bf8846771b 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -247,7 +247,7 @@ process_start: if (IS_CARD_RX_RCVD(adapter)) { adapter->data_received = false; adapter->pm_wakeup_fw_try = false; - del_timer_sync(&adapter->wakeup_timer); + del_timer(&adapter->wakeup_timer); if (adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; } else { diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 64c4223a1e1e..0dc7a1d3993d 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -312,7 +312,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; - del_timer_sync(&adapter->wakeup_timer); + del_timer(&adapter->wakeup_timer); break; } if (!mwifiex_send_null_packet @@ -327,7 +327,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) adapter->ps_state = PS_STATE_AWAKE; adapter->pm_wakeup_card_req = false; adapter->pm_wakeup_fw_try = false; - del_timer_sync(&adapter->wakeup_timer); + del_timer(&adapter->wakeup_timer); break; diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 223873022ffe..8beb38c578d0 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -1006,7 +1006,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) { /* Simulation of HS_AWAKE event */ adapter->pm_wakeup_fw_try = false; - del_timer_sync(&adapter->wakeup_timer); + del_timer(&adapter->wakeup_timer); adapter->pm_wakeup_card_req = false; adapter->ps_state = PS_STATE_AWAKE; From e4fcfaf802bf75e20c65a501edc5c159e812ebd3 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 12 Mar 2015 15:35:44 +0100 Subject: [PATCH 115/567] rt2x00usb: initialize the read value in case of failure My understanding ist that rt2x00usb_register_read() is void and so the reader is unaware of read errors and assumes that whatever was on the stack as it was about to read. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Kalle Valo --- drivers/net/wireless/rt2x00/rt2x00usb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 8f85fbd5f237..569363da00a2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -199,7 +199,7 @@ static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 *value) { - __le32 reg; + __le32 reg = 0; rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, ®, sizeof(reg)); @@ -219,7 +219,7 @@ static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 *value) { - __le32 reg; + __le32 reg = 0; rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, ®, sizeof(reg), REGISTER_TIMEOUT); From 92d5e2456d39d8593bfb19429f2d83297836ad5c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 12 Mar 2015 15:35:45 +0100 Subject: [PATCH 116/567] rt2x00usb: check USB's request error code in rt2800usb_autorun_detect() rt2800usb_autorun_detect() blindly assumes assumes that it worked while it could have failed. Check the error code here. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Kalle Valo --- drivers/net/wireless/rt2x00/rt2800usb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 8444313eabe2..e692e5fe4e01 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -233,6 +233,7 @@ static int rt2800usb_autorun_detect(struct rt2x00_dev *rt2x00dev) { __le32 *reg; u32 fw_mode; + int ret; reg = kmalloc(sizeof(*reg), GFP_KERNEL); if (reg == NULL) @@ -242,11 +243,14 @@ static int rt2800usb_autorun_detect(struct rt2x00_dev *rt2x00dev) * magic value USB_MODE_AUTORUN (0x11) to the device, thus the * returned value would be invalid. */ - rt2x00usb_vendor_request(rt2x00dev, USB_DEVICE_MODE, - USB_VENDOR_REQUEST_IN, 0, USB_MODE_AUTORUN, - reg, sizeof(*reg), REGISTER_TIMEOUT_FIRMWARE); + ret = rt2x00usb_vendor_request(rt2x00dev, USB_DEVICE_MODE, + USB_VENDOR_REQUEST_IN, 0, + USB_MODE_AUTORUN, reg, sizeof(*reg), + REGISTER_TIMEOUT_FIRMWARE); fw_mode = le32_to_cpu(*reg); kfree(reg); + if (ret < 0) + return ret; if ((fw_mode & 0x00000003) == 2) return 1; From 7daa54b747ddddf03737178f2473098a29d1b05c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 12 Mar 2015 15:35:46 +0100 Subject: [PATCH 117/567] rt2x00usb: drop rt2x00usb_disable_radio() from rt2800usb_disable_radio() I have here FRITZ!WLAN USB Stick N v2 / idVendor=057c, idProduct=8501 and every single of this requests ends up with: |ieee80211 phy0: rt2x00usb_vendor_request: Error - Vendor Request 0x0c failed for offset 0x0000 with error -32 I was browsing the the vedor code and I haven't seen such request so I remove it with this patch. If I wasn't look enough or if this error is expected then please excuse :) Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Kalle Valo --- drivers/net/wireless/rt2x00/rt2800usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index e692e5fe4e01..9a2f44a54d94 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -378,7 +378,6 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) { rt2800_disable_radio(rt2x00dev); - rt2x00usb_disable_radio(rt2x00dev); } static int rt2800usb_set_state(struct rt2x00_dev *rt2x00dev, From a3fa71c40f1853d0c27e8f5bc01a722a705d9682 Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Fri, 13 Mar 2015 15:17:14 +0800 Subject: [PATCH 118/567] wl18xx: show rx_frames_per_rates as an array as it really is In struct wl18xx_acx_rx_rate_stat, rx_frames_per_rates field is an array, not a number. This means WL18XX_DEBUGFS_FWSTATS_FILE can't be used to display this field in debugfs (it would display a pointer, not the actual data). Use WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY instead. This bug has been found by adding a __printf attribute to wl1271_format_buffer. gcc complained about "format '%u' expects argument of type 'unsigned int', but argument 5 has type 'u32 *'". Fixes: c5d94169e818 ("wl18xx: use new fw stats structures") Signed-off-by: Nicolas Iooss Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/debugfs.c | 2 +- drivers/net/wireless/ti/wlcore/debugfs.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index c93fae95baac..5fbd2230f372 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -139,7 +139,7 @@ WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, protection_filter, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, accum_arp_pend_requests, "%u"); WL18XX_DEBUGFS_FWSTATS_FILE(rx_filter, max_arp_queue_dep, "%u"); -WL18XX_DEBUGFS_FWSTATS_FILE(rx_rate, rx_frames_per_rates, "%u"); +WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(rx_rate, rx_frames_per_rates, 50); WL18XX_DEBUGFS_FWSTATS_FILE_ARRAY(aggr_size, tx_agg_vs_rate, AGGR_STATS_TX_AGG*AGGR_STATS_TX_RATE); diff --git a/drivers/net/wireless/ti/wlcore/debugfs.h b/drivers/net/wireless/ti/wlcore/debugfs.h index 0f2cfb0d2a9e..bf14676e6515 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.h +++ b/drivers/net/wireless/ti/wlcore/debugfs.h @@ -26,8 +26,8 @@ #include "wlcore.h" -int wl1271_format_buffer(char __user *userbuf, size_t count, - loff_t *ppos, char *fmt, ...); +__printf(4, 5) int wl1271_format_buffer(char __user *userbuf, size_t count, + loff_t *ppos, char *fmt, ...); int wl1271_debugfs_init(struct wl1271 *wl); void wl1271_debugfs_exit(struct wl1271 *wl); From a9adbcb3355c31faf4274932f513f19225b61747 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 13 Mar 2015 17:37:51 +0530 Subject: [PATCH 119/567] mwifiex: lock main process till reinitialization of vif is over A crash was detected while changing virtual interface type is in progress. This was tracked to race condition in accessing bss_priority table while change is in progress. This patch ensures that main_process and rx_process works are locked while we change virtual interface. Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 33 +++++++++++++++++++++++++ drivers/net/wireless/mwifiex/main.c | 2 +- drivers/net/wireless/mwifiex/main.h | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b0778a699bbc..fc3bbe77eb18 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -717,6 +717,9 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv) static int mwifiex_deinit_priv_params(struct mwifiex_private *priv) { + struct mwifiex_adapter *adapter = priv->adapter; + unsigned long flags; + priv->mgmt_frame_mask = 0; if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, HostCmd_ACT_GEN_SET, 0, @@ -727,6 +730,25 @@ static int mwifiex_deinit_priv_params(struct mwifiex_private *priv) } mwifiex_deauthenticate(priv, NULL); + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + adapter->main_locked = true; + if (adapter->mwifiex_processing) { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + flush_workqueue(adapter->workqueue); + } else { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + } + + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + adapter->rx_locked = true; + if (adapter->rx_processing) { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + flush_workqueue(adapter->rx_workqueue); + } else { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + } + mwifiex_free_priv(priv); priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; @@ -740,6 +762,9 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, struct net_device *dev, enum nl80211_iftype type) { + struct mwifiex_adapter *adapter = priv->adapter; + unsigned long flags; + mwifiex_init_priv(priv); priv->bss_mode = type; @@ -770,6 +795,14 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, return -EOPNOTSUPP; } + spin_lock_irqsave(&adapter->main_proc_lock, flags); + adapter->main_locked = false; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + adapter->rx_locked = false; + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + return 0; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 42bf8846771b..9c11eb882a0e 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -189,7 +189,7 @@ int mwifiex_main_process(struct mwifiex_adapter *adapter) spin_lock_irqsave(&adapter->main_proc_lock, flags); /* Check if already processing */ - if (adapter->mwifiex_processing) { + if (adapter->mwifiex_processing || adapter->main_locked) { adapter->more_task_flag = true; spin_unlock_irqrestore(&adapter->main_proc_lock, flags); goto exit_main_proc; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index a0908c64103a..04ef618de23c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -772,6 +772,7 @@ struct mwifiex_adapter { bool rx_processing; bool delay_main_work; bool rx_locked; + bool main_locked; struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM]; /* spin lock for init/shutdown */ spinlock_t mwifiex_lock; From 621599446daeaa80f65ca27190141bbc82dd95ec Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 13 Mar 2015 17:37:52 +0530 Subject: [PATCH 120/567] mwifiex: rename alloc_rx_buf to alloc_dma_aligned_buf Rename this function to reflect its purpose correctly. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.h | 2 +- drivers/net/wireless/mwifiex/pcie.c | 8 ++++---- drivers/net/wireless/mwifiex/sdio.c | 7 ++++--- drivers/net/wireless/mwifiex/util.c | 4 ++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 04ef618de23c..d609d16cf18c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1423,7 +1423,7 @@ u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, u8 rx_rate, u8 ht_info); void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter); -void *mwifiex_alloc_rx_buf(int rx_len, gfp_t flags); +void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 4b463c3b9906..fc59c1db3615 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -498,8 +498,8 @@ static int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter) for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { /* Allocate skb here so that firmware can DMA data from it */ - skb = mwifiex_alloc_rx_buf(MWIFIEX_RX_DATA_BUF_SIZE, - GFP_KERNEL | GFP_DMA); + skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE, + GFP_KERNEL | GFP_DMA); if (!skb) { dev_err(adapter->dev, "Unable to allocate skb for RX ring.\n"); @@ -1298,8 +1298,8 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) } } - skb_tmp = mwifiex_alloc_rx_buf(MWIFIEX_RX_DATA_BUF_SIZE, - GFP_KERNEL | GFP_DMA); + skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE, + GFP_KERNEL | GFP_DMA); if (!skb_tmp) { dev_err(adapter->dev, "Unable to allocate skb.\n"); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 9ef010bfa7d9..509204f5ae6f 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1362,7 +1362,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) return -1; rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); - skb = mwifiex_alloc_rx_buf(rx_len, GFP_KERNEL | GFP_DMA); + skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); if (!skb) return -1; @@ -1459,8 +1459,9 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) } rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); - skb = mwifiex_alloc_rx_buf(rx_len, - GFP_KERNEL | GFP_DMA); + skb = mwifiex_alloc_dma_align_buf(rx_len, + GFP_KERNEL | + GFP_DMA); if (!skb) { dev_err(adapter->dev, "%s: failed to alloc skb", diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 2148a573396b..b8a45872354d 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -632,7 +632,7 @@ void mwifiex_hist_data_reset(struct mwifiex_private *priv) atomic_set(&phist_data->sig_str[ix], 0); } -void *mwifiex_alloc_rx_buf(int rx_len, gfp_t flags) +void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags) { struct sk_buff *skb; int buf_len, pad; @@ -653,4 +653,4 @@ void *mwifiex_alloc_rx_buf(int rx_len, gfp_t flags) return skb; } -EXPORT_SYMBOL_GPL(mwifiex_alloc_rx_buf); +EXPORT_SYMBOL_GPL(mwifiex_alloc_dma_align_buf); From ea44f4d04c9356dc844af5312a376b6528cec7c5 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Fri, 13 Mar 2015 17:37:53 +0530 Subject: [PATCH 121/567] mwifiex: enhance SD8897 MP aggregation limits SD8897 support buffers of 4K and 16 such ports can be accomodated. So basically 64K buffer size in single aggregation is supported. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index c636944c77bc..264bc9b9e02a 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -67,6 +67,8 @@ #define MWIFIEX_MP_AGGR_BUF_SIZE_16K (16384) #define MWIFIEX_MP_AGGR_BUF_SIZE_32K (32768) +/* we leave one block of 256 bytes for DMA alignment*/ +#define MWIFIEX_MP_AGGR_BUF_SIZE_MAX (65280) /* Misc. Config Register : Auto Re-enable interrupts */ #define AUTO_RE_ENABLE_INT BIT(4) @@ -458,8 +460,8 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { .max_ports = 32, .mp_agg_pkt_limit = 16, .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, - .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, - .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K, + .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, + .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_MAX, .supports_sdio_new_mode = true, .has_control_mask = false, .can_dump_fw = true, From b2713f67f7a4c3226772c5ac581c7f37d7c473f1 Mon Sep 17 00:00:00 2001 From: Shengzhen Li Date: Fri, 13 Mar 2015 17:37:54 +0530 Subject: [PATCH 122/567] mwifiex: avoid queue_work while work is ongoing Current code does not check whether main_work_queue or rx_work_queue is running when preparing to do queue_work, this code fix add check before calling queue_work, reducing unnecessary queue_work switch. This change instead sets more_task flag to ensure we run main_process superloop once again. Signed-off-by: Shengzhen Li Signed-off-by: Zhaoyang Liu Reviewed-by: Cathy Luo Reviewed-by: Amitkumar Karwar Reviewed-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.c | 38 ++++++++++++++++++++++++----- drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/pcie.c | 2 +- drivers/net/wireless/mwifiex/usb.c | 4 +-- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 9c11eb882a0e..d96d60a7ae7c 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -131,6 +131,34 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) return 0; } +void mwifiex_queue_main_work(struct mwifiex_adapter *adapter) +{ + unsigned long flags; + + spin_lock_irqsave(&adapter->main_proc_lock, flags); + if (adapter->mwifiex_processing) { + adapter->more_task_flag = true; + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + } else { + spin_unlock_irqrestore(&adapter->main_proc_lock, flags); + queue_work(adapter->workqueue, &adapter->main_work); + } +} +EXPORT_SYMBOL_GPL(mwifiex_queue_main_work); + +static void mwifiex_queue_rx_work(struct mwifiex_adapter *adapter) +{ + unsigned long flags; + + spin_lock_irqsave(&adapter->rx_proc_lock, flags); + if (adapter->rx_processing) { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + } else { + spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + queue_work(adapter->rx_workqueue, &adapter->rx_work); + } +} + static int mwifiex_process_rx(struct mwifiex_adapter *adapter) { unsigned long flags; @@ -154,7 +182,7 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter) if (adapter->if_ops.submit_rem_rx_urbs) adapter->if_ops.submit_rem_rx_urbs(adapter); adapter->delay_main_work = false; - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_queue_main_work(adapter); } mwifiex_handle_rx_packet(adapter, skb); } @@ -214,9 +242,7 @@ process_start: if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING && adapter->iface_type != MWIFIEX_USB) { adapter->delay_main_work = true; - if (!adapter->rx_processing) - queue_work(adapter->rx_workqueue, - &adapter->rx_work); + mwifiex_queue_rx_work(adapter); break; } @@ -229,7 +255,7 @@ process_start: } if (adapter->rx_work_enabled && adapter->data_received) - queue_work(adapter->rx_workqueue, &adapter->rx_work); + mwifiex_queue_rx_work(adapter); /* Need to wake up the card ? */ if ((adapter->ps_state == PS_STATE_SLEEP) && @@ -606,7 +632,7 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) atomic_inc(&priv->adapter->tx_pending); mwifiex_wmm_add_buf_txqueue(priv, skb); - queue_work(priv->adapter->workqueue, &priv->adapter->main_work); + mwifiex_queue_main_work(priv->adapter); return 0; } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d609d16cf18c..a319abe84423 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1424,6 +1424,7 @@ u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv, void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter); void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags); +void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index fc59c1db3615..b31c9a70ffaa 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -2101,7 +2101,7 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) goto exit; mwifiex_interrupt_status(adapter); - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_queue_main_work(adapter); exit: return IRQ_HANDLED; diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 8beb38c578d0..fd8027f200a0 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -193,7 +193,7 @@ static void mwifiex_usb_rx_complete(struct urb *urb) dev_dbg(adapter->dev, "info: recv_length=%d, status=%d\n", recv_length, status); if (status == -EINPROGRESS) { - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_queue_main_work(adapter); /* urb for data_ep is re-submitted now; * urb for cmd_ep will be re-submitted in callback @@ -262,7 +262,7 @@ static void mwifiex_usb_tx_complete(struct urb *urb) urb->status ? -1 : 0); } - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_queue_main_work(adapter); return; } From 39df5e8233bf34696204207c7594a0a6320fa044 Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Fri, 13 Mar 2015 17:37:55 +0530 Subject: [PATCH 123/567] mwifiex: get rid of BA setup helper functions This patch removes BA setup helper routines mwifiex_is_bastream_setup and mwifiex_is_amsdu_in_ampdu_allowed. Current code will use two functions to check bastream setup and amsdu in ampdu. This patch change these functions to flags, thus avoiding redundant spin_lock check while dequeuing TX packets. Signed-off-by: Zhaoyang Liu Reviewed-by: Cathy Luo Reviewed-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11n.c | 18 ++++++++++- drivers/net/wireless/mwifiex/11n.h | 32 -------------------- drivers/net/wireless/mwifiex/11n_rxreorder.c | 7 ++++- drivers/net/wireless/mwifiex/main.h | 13 +++++--- drivers/net/wireless/mwifiex/wmm.c | 16 +++++----- drivers/net/wireless/mwifiex/wmm.h | 2 ++ 6 files changed, 42 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index 543148d27b01..433bd6837c79 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -159,6 +159,7 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, int tid; struct host_cmd_ds_11n_addba_rsp *add_ba_rsp = &resp->params.add_ba_rsp; struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl; + struct mwifiex_ra_list_tbl *ra_list; u16 block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set); add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn)) @@ -166,7 +167,13 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK) >> BLOCKACKPARAM_TID_POS; + ra_list = mwifiex_wmm_get_ralist_node(priv, tid, add_ba_rsp-> + peer_mac_addr); if (le16_to_cpu(add_ba_rsp->status_code) != BA_RESULT_SUCCESS) { + if (ra_list) { + ra_list->ba_status = BA_SETUP_NONE; + ra_list->amsdu_in_ampdu = false; + } mwifiex_del_ba_tbl(priv, tid, add_ba_rsp->peer_mac_addr, TYPE_DELBA_SENT, true); if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT) @@ -185,6 +192,10 @@ int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv, tx_ba_tbl->amsdu = true; else tx_ba_tbl->amsdu = false; + if (ra_list) { + ra_list->amsdu_in_ampdu = tx_ba_tbl->amsdu; + ra_list->ba_status = BA_SETUP_COMPLETE; + } } else { dev_err(priv->adapter->dev, "BA stream not created\n"); } @@ -515,6 +526,7 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, enum mwifiex_ba_status ba_status) { struct mwifiex_tx_ba_stream_tbl *new_node; + struct mwifiex_ra_list_tbl *ra_list; unsigned long flags; if (!mwifiex_get_ba_tbl(priv, tid, ra)) { @@ -522,7 +534,11 @@ void mwifiex_create_ba_tbl(struct mwifiex_private *priv, u8 *ra, int tid, GFP_ATOMIC); if (!new_node) return; - + ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra); + if (ra_list) { + ra_list->ba_status = ba_status; + ra_list->amsdu_in_ampdu = false; + } INIT_LIST_HEAD(&new_node->list); new_node->tid = tid; diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 8e2e39422ad8..afdd58aa90de 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -77,22 +77,6 @@ mwifiex_is_station_ampdu_allowed(struct mwifiex_private *priv, return (node->ampdu_sta[tid] != BA_STREAM_NOT_ALLOWED) ? true : false; } -/* This function checks whether AMSDU is allowed for BA stream. */ -static inline u8 -mwifiex_is_amsdu_in_ampdu_allowed(struct mwifiex_private *priv, - struct mwifiex_ra_list_tbl *ptr, int tid) -{ - struct mwifiex_tx_ba_stream_tbl *tx_tbl; - - if (is_broadcast_ether_addr(ptr->ra)) - return false; - tx_tbl = mwifiex_get_ba_tbl(priv, tid, ptr->ra); - if (tx_tbl) - return tx_tbl->amsdu; - - return false; -} - /* This function checks whether AMPDU is allowed or not for a particular TID. */ static inline u8 mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, @@ -181,22 +165,6 @@ mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid, return ret; } -/* - * This function checks whether BA stream is set up or not. - */ -static inline int -mwifiex_is_ba_stream_setup(struct mwifiex_private *priv, - struct mwifiex_ra_list_tbl *ptr, int tid) -{ - struct mwifiex_tx_ba_stream_tbl *tx_tbl; - - tx_tbl = mwifiex_get_ba_tbl(priv, tid, ptr->ra); - if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl)) - return true; - - return false; -} - /* * This function checks whether associated station is 11n enabled */ diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index a2e8817b56d8..f75f8acfaca0 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -659,6 +659,7 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac, { struct mwifiex_rx_reorder_tbl *tbl; struct mwifiex_tx_ba_stream_tbl *ptx_tbl; + struct mwifiex_ra_list_tbl *ra_list; u8 cleanup_rx_reorder_tbl; unsigned long flags; @@ -686,7 +687,11 @@ mwifiex_del_ba_tbl(struct mwifiex_private *priv, int tid, u8 *peer_mac, "event: TID, RA not found in table\n"); return; } - + ra_list = mwifiex_wmm_get_ralist_node(priv, tid, peer_mac); + if (ra_list) { + ra_list->amsdu_in_ampdu = false; + ra_list->ba_status = BA_SETUP_NONE; + } spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags); mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl); spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index a319abe84423..439db1734904 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -211,6 +211,12 @@ struct mwifiex_tx_aggr { u8 amsdu; }; +enum mwifiex_ba_status { + BA_SETUP_NONE = 0, + BA_SETUP_INPROGRESS, + BA_SETUP_COMPLETE +}; + struct mwifiex_ra_list_tbl { struct list_head list; struct sk_buff_head skb_head; @@ -219,6 +225,8 @@ struct mwifiex_ra_list_tbl { u16 max_amsdu; u16 ba_pkt_count; u8 ba_packet_thr; + enum mwifiex_ba_status ba_status; + u8 amsdu_in_ampdu; u16 total_pkt_count; bool tdls_link; }; @@ -602,11 +610,6 @@ struct mwifiex_private { struct mwifiex_11h_intf_state state_11h; }; -enum mwifiex_ba_status { - BA_SETUP_NONE = 0, - BA_SETUP_INPROGRESS, - BA_SETUP_COMPLETE -}; struct mwifiex_tx_ba_stream_tbl { struct list_head list; diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 0cd4f6bed9fc..2d14dd5856c3 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -157,6 +157,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra) ra_list->is_11n_enabled = 0; ra_list->tdls_link = false; + ra_list->ba_status = BA_SETUP_NONE; + ra_list->amsdu_in_ampdu = false; if (!mwifiex_queuing_ra_based(priv)) { if (mwifiex_get_tdls_link_status(priv, ra) == TDLS_SETUP_COMPLETE) { @@ -574,7 +576,7 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) * This function retrieves a particular RA list node, matching with the * given TID and RA address. */ -static struct mwifiex_ra_list_tbl * +struct mwifiex_ra_list_tbl * mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr) { @@ -1276,13 +1278,13 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) } if (!ptr->is_11n_enabled || - mwifiex_is_ba_stream_setup(priv, ptr, tid) || - priv->wps.session_enable) { + ptr->ba_status || + priv->wps.session_enable) { if (ptr->is_11n_enabled && - mwifiex_is_ba_stream_setup(priv, ptr, tid) && - mwifiex_is_amsdu_in_ampdu_allowed(priv, ptr, tid) && - mwifiex_is_amsdu_allowed(priv, tid) && - mwifiex_is_11n_aggragation_possible(priv, ptr, + ptr->ba_status && + ptr->amsdu_in_ampdu && + mwifiex_is_amsdu_allowed(priv, tid) && + mwifiex_is_11n_aggragation_possible(priv, ptr, adapter->tx_buf_size)) mwifiex_11n_aggregate_pkt(priv, ptr, ptr_index, flags); /* ra_list_spinlock has been freed in diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 569bd73f33c5..48ece0b35591 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -127,4 +127,6 @@ mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid); +struct mwifiex_ra_list_tbl *mwifiex_wmm_get_ralist_node(struct mwifiex_private + *priv, u8 tid, const u8 *ra_addr); #endif /* !_MWIFIEX_WMM_H_ */ From 690e792cb9d78c3bcaf4a6a8387dbbfbafad579f Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Fri, 13 Mar 2015 17:37:56 +0530 Subject: [PATCH 124/567] mwifiex: remove_bss_prio_lock This patch does away with spinlock in mwifiex_wmm_get_highest_priolist_ptr in order to improve TP. Signed-off-by: Zhaoyang Liu Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/wmm.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 2d14dd5856c3..a6db12cae769 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -944,14 +944,11 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, struct mwifiex_ra_list_tbl *ptr; struct mwifiex_tid_tbl *tid_ptr; atomic_t *hqp; - unsigned long flags_bss, flags_ra; + unsigned long flags_ra; int i, j; /* check the BSS with highest priority first */ for (j = adapter->priv_num - 1; j >= 0; --j) { - spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock, - flags_bss); - /* iterate over BSS with the equal priority */ list_for_each_entry(adapter->bss_prio_tbl[j].bss_prio_cur, &adapter->bss_prio_tbl[j].bss_prio_head, @@ -987,19 +984,15 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, } } - spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock, - flags_bss); } return NULL; found: - /* holds bss_prio_lock / ra_list_spinlock */ + /* holds ra_list_spinlock */ if (atomic_read(hqp) > i) atomic_set(hqp, i); spin_unlock_irqrestore(&priv_tmp->wmm.ra_list_spinlock, flags_ra); - spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock, - flags_bss); *priv = priv_tmp; *tid = tos_to_tid[i]; From e35000ead491d71e59ab6f7458971321e06150a0 Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Fri, 13 Mar 2015 17:37:57 +0530 Subject: [PATCH 125/567] mwifiex: preprocess packets from TX queue During profiling, we discovered that driver remains idle for time when pakcet is downloaded to FW but no TX_DONE has been received i.e. while data_sent is true. This patch adds enhancement to TX routine where we preprocess packets from TX queue, make them ready for TX and add them to separate TX queue. Signed-off-by: Zhaoyang Liu Signed-off-by: Marc Yang Signed-off-by: Chin-ran Lo Reviewed-by: Cathy Luo Reviewed-by: Amitkumar Karwar Reviewed-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/11n_aggr.c | 16 ++- drivers/net/wireless/mwifiex/decl.h | 2 + drivers/net/wireless/mwifiex/init.c | 5 + drivers/net/wireless/mwifiex/main.c | 21 +++- drivers/net/wireless/mwifiex/main.h | 6 ++ drivers/net/wireless/mwifiex/txrx.c | 125 ++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.c | 21 +++- 7 files changed, 185 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 9b983b5cebbd..6183e255e62a 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -170,7 +170,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct sk_buff *skb_aggr, *skb_src; struct mwifiex_txinfo *tx_info_aggr, *tx_info_src; - int pad = 0, ret; + int pad = 0, aggr_num = 0, ret; struct mwifiex_tx_param tx_param; struct txpd *ptx_pd = NULL; struct timeval tv; @@ -184,7 +184,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, } tx_info_src = MWIFIEX_SKB_TXCB(skb_src); - skb_aggr = dev_alloc_skb(adapter->tx_buf_size); + skb_aggr = mwifiex_alloc_dma_align_buf(adapter->tx_buf_size, + GFP_ATOMIC | GFP_DMA); if (!skb_aggr) { dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, @@ -200,6 +201,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, if (tx_info_src->flags & MWIFIEX_BUF_FLAG_TDLS_PKT) tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; + tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_AGGR_PKT; skb_aggr->priority = skb_src->priority; do_gettimeofday(&tv); @@ -211,11 +213,9 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, break; skb_src = skb_dequeue(&pra_list->skb_head); - pra_list->total_pkt_count--; - atomic_dec(&priv->wmm.tx_pkts_queued); - + aggr_num++; spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad); @@ -251,6 +251,12 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, ptx_pd = (struct txpd *)skb_aggr->data; skb_push(skb_aggr, headroom); + tx_info_aggr->aggr_num = aggr_num * 2; + if (adapter->data_sent || adapter->tx_lock_flag) { + atomic_add(aggr_num * 2, &adapter->tx_queued); + skb_queue_tail(&adapter->tx_data_q, skb_aggr); + return 0; + } if (adapter->iface_type == MWIFIEX_USB) { adapter->data_sent = true; diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index cf2fa110e251..6ce19bed0e91 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -83,6 +83,7 @@ #define MWIFIEX_BUF_FLAG_TDLS_PKT BIT(2) #define MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS BIT(3) #define MWIFIEX_BUF_FLAG_ACTION_TX_STATUS BIT(4) +#define MWIFIEX_BUF_FLAG_AGGR_PKT BIT(5) #define MWIFIEX_BRIDGED_PKTS_THR_HIGH 1024 #define MWIFIEX_BRIDGED_PKTS_THR_LOW 128 @@ -179,6 +180,7 @@ struct mwifiex_txinfo { u8 flags; u8 bss_num; u8 bss_type; + u8 aggr_num; u32 pkt_len; u8 ack_frame_id; u64 cookie; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 0153ce6d5879..6936de8c8a94 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -481,6 +481,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) spin_lock_init(&adapter->rx_proc_lock); skb_queue_head_init(&adapter->rx_data_q); + skb_queue_head_init(&adapter->tx_data_q); for (i = 0; i < adapter->priv_num; ++i) { INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head); @@ -688,6 +689,10 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) } } + atomic_set(&adapter->tx_queued, 0); + while ((skb = skb_dequeue(&adapter->tx_data_q))) + mwifiex_write_data_complete(adapter, skb, 0, 0); + spin_lock_irqsave(&adapter->rx_proc_lock, flags); while ((skb = skb_dequeue(&adapter->rx_data_q))) { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index d96d60a7ae7c..b242c3e8df3f 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -262,6 +262,7 @@ process_start: (adapter->pm_wakeup_card_req && !adapter->pm_wakeup_fw_try) && (is_command_pending(adapter) || + !skb_queue_empty(&adapter->tx_data_q) || !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); @@ -286,7 +287,8 @@ process_start: if ((!adapter->scan_chan_gap_enabled && adapter->scan_processing) || adapter->data_sent || - mwifiex_wmm_lists_empty(adapter)) { + (mwifiex_wmm_lists_empty(adapter) && + skb_queue_empty(&adapter->tx_data_q))) { if (adapter->cmd_sent || adapter->curr_cmd || (!is_command_pending(adapter))) break; @@ -336,6 +338,20 @@ process_start: } } + if ((adapter->scan_chan_gap_enabled || + !adapter->scan_processing) && + !adapter->data_sent && + !skb_queue_empty(&adapter->tx_data_q)) { + mwifiex_process_tx_queue(adapter); + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event + (mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + false); + } + } + if ((adapter->scan_chan_gap_enabled || !adapter->scan_processing) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { @@ -351,7 +367,8 @@ process_start: if (adapter->delay_null_pkt && !adapter->cmd_sent && !adapter->curr_cmd && !is_command_pending(adapter) && - mwifiex_wmm_lists_empty(adapter)) { + (mwifiex_wmm_lists_empty(adapter) && + skb_queue_empty(&adapter->tx_data_q))) { if (!mwifiex_send_null_packet (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 439db1734904..11db09c73e85 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -59,6 +59,8 @@ enum { #define MWIFIEX_MAX_AP 64 +#define MWIFIEX_MAX_PKTS_TXQ 16 + #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) #define MWIFIEX_TIMER_10S 10000 @@ -819,6 +821,8 @@ struct mwifiex_adapter { spinlock_t scan_pending_q_lock; /* spin lock for RX processing routine */ spinlock_t rx_proc_lock; + struct sk_buff_head tx_data_q; + atomic_t tx_queued; u32 scan_processing; u16 region_code; struct mwifiex_802_11d_domain_reg domain_reg; @@ -905,6 +909,8 @@ struct mwifiex_adapter { bool auto_tdls; }; +void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); + int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); void mwifiex_set_trans_start(struct net_device *dev); diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index ea4549f0e0b9..4d43371583cf 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -92,6 +92,12 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, else head_ptr = mwifiex_process_sta_txpd(priv, skb); + if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) { + skb_queue_tail(&adapter->tx_data_q, skb); + atomic_inc(&adapter->tx_queued); + return 0; + } + if (head_ptr) { if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) local_tx_pd = (struct txpd *)(head_ptr + hroom); @@ -142,6 +148,123 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, return ret; } +static int mwifiex_host_to_card(struct mwifiex_adapter *adapter, + struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + struct txpd *local_tx_pd = NULL; + u8 *head_ptr = skb->data; + int ret = 0; + struct mwifiex_private *priv; + struct mwifiex_txinfo *tx_info; + + tx_info = MWIFIEX_SKB_TXCB(skb); + priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num, + tx_info->bss_type); + if (!priv) { + dev_err(adapter->dev, "data: priv not found. Drop TX packet\n"); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, 0, 0); + return ret; + } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { + if (adapter->iface_type == MWIFIEX_USB) + local_tx_pd = (struct txpd *)head_ptr; + else + local_tx_pd = (struct txpd *) (head_ptr + + INTF_HEADER_LEN); + } + + if (adapter->iface_type == MWIFIEX_USB) { + adapter->data_sent = true; + ret = adapter->if_ops.host_to_card(adapter, + MWIFIEX_USB_EP_DATA, + skb, NULL); + } else { + ret = adapter->if_ops.host_to_card(adapter, + MWIFIEX_TYPE_DATA, + skb, tx_param); + } + switch (ret) { + case -ENOSR: + dev_err(adapter->dev, "data: -ENOSR is returned\n"); + break; + case -EBUSY: + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && + (adapter->pps_uapsd_mode) && + (adapter->tx_lock_flag)) { + priv->adapter->tx_lock_flag = false; + if (local_tx_pd) + local_tx_pd->flags = 0; + } + skb_queue_head(&adapter->tx_data_q, skb); + if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) + atomic_add(tx_info->aggr_num, &adapter->tx_queued); + else + atomic_inc(&adapter->tx_queued); + dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); + break; + case -1: + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; + dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n", + ret); + adapter->dbg.num_tx_host_to_card_failure++; + mwifiex_write_data_complete(adapter, skb, 0, ret); + break; + case -EINPROGRESS: + if (adapter->iface_type != MWIFIEX_PCIE) + adapter->data_sent = false; + break; + case 0: + mwifiex_write_data_complete(adapter, skb, 0, ret); + break; + default: + break; + } + return ret; +} + +static int +mwifiex_dequeue_tx_queue(struct mwifiex_adapter *adapter) +{ + struct sk_buff *skb, *skb_next; + struct mwifiex_txinfo *tx_info; + struct mwifiex_tx_param tx_param; + + skb = skb_dequeue(&adapter->tx_data_q); + if (!skb) + return -1; + + tx_info = MWIFIEX_SKB_TXCB(skb); + if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) + atomic_sub(tx_info->aggr_num, &adapter->tx_queued); + else + atomic_dec(&adapter->tx_queued); + + if (!skb_queue_empty(&adapter->tx_data_q)) + skb_next = skb_peek(&adapter->tx_data_q); + else + skb_next = NULL; + tx_param.next_pkt_len = ((skb_next) ? skb_next->len : 0); + if (!tx_param.next_pkt_len) { + if (!mwifiex_wmm_lists_empty(adapter)) + tx_param.next_pkt_len = 1; + } + return mwifiex_host_to_card(adapter, skb, &tx_param); +} + +void +mwifiex_process_tx_queue(struct mwifiex_adapter *adapter) +{ + do { + if (adapter->data_sent || adapter->tx_lock_flag) + break; + if (mwifiex_dequeue_tx_queue(adapter)) + break; + } while (!skb_queue_empty(&adapter->tx_data_q)); +} + /* * Packet send completion callback handler. * @@ -181,6 +304,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) atomic_dec_return(&adapter->pending_bridged_pkts); + if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) + goto done; if (aggr) /* For skb_aggr, do not wake up tx queue */ diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index a6db12cae769..b2e99569a0f8 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1174,6 +1174,14 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, skb = skb_dequeue(&ptr->skb_head); + if (adapter->data_sent || adapter->tx_lock_flag) { + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, + ra_list_flags); + skb_queue_tail(&adapter->tx_data_q, skb); + atomic_inc(&adapter->tx_queued); + return; + } + if (!skb_queue_empty(&ptr->skb_head)) skb_next = skb_peek(&ptr->skb_head); else @@ -1324,11 +1332,16 @@ void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter) { do { - /* Check if busy */ - if (adapter->data_sent || adapter->tx_lock_flag) - break; - if (mwifiex_dequeue_tx_packet(adapter)) break; + if (adapter->iface_type != MWIFIEX_SDIO) { + if (adapter->data_sent || + adapter->tx_lock_flag) + break; + } else { + if (atomic_read(&adapter->tx_queued) >= + MWIFIEX_MAX_PKTS_TXQ) + break; + } } while (!mwifiex_wmm_lists_empty(adapter)); } From 92263a841b1502d2ef19199deaa669fe4c0102e9 Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Fri, 13 Mar 2015 17:37:58 +0530 Subject: [PATCH 126/567] mwifiex: add SDIO rx single port aggregation This patch brings in support for SDIO single port rx aggregation to mwifiex. Maximum read size support by SDIO cmd53 is 64K. Based on multi port aggregation which is already part of mwifiex, idea here is multiple packets received in FW can be aggregated into single buffer. A separate upload type is defined for such packet aggregated to single port. Packets from this single buffer are later deaggregated into individual packets. This way, driver can receive more packets each time through single SDIO cmd53; thereby reducing no of times MMC bus is accessed. SDIO SP aggregation support is advertised by FW during load time and driver would get FW block size in command response of HostCmd_CMD_SDIO_SP_RX_AGGR_CFG. Signed-off-by: Zhaoyang Liu Signed-off-by: Marc Yang Reviewed-by: Amitkumar Karwar Reviewed-by: Cathy Luo Reviewed-by: Avinash Patil Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/decl.h | 8 +- drivers/net/wireless/mwifiex/fw.h | 9 ++ drivers/net/wireless/mwifiex/main.c | 10 +- drivers/net/wireless/mwifiex/main.h | 4 + drivers/net/wireless/mwifiex/sdio.c | 103 +++++++++++++++++++-- drivers/net/wireless/mwifiex/sta_cmd.c | 40 ++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 21 +++++ 7 files changed, 184 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 6ce19bed0e91..38f24e0427d2 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -112,6 +112,11 @@ #define MWIFIEX_A_BAND_START_FREQ 5000 +/* SDIO Aggr data packet special info */ +#define SDIO_MAX_AGGR_BUF_SIZE (256 * 255) +#define BLOCK_NUMBER_OFFSET 15 +#define SDIO_HEADER_OFFSET 28 + enum mwifiex_bss_type { MWIFIEX_BSS_TYPE_STA = 0, MWIFIEX_BSS_TYPE_UAP = 1, @@ -169,10 +174,11 @@ struct mwifiex_wait_queue { }; struct mwifiex_rxinfo { + struct sk_buff *parent; u8 bss_num; u8 bss_type; - struct sk_buff *parent; u8 use_count; + u8 buf_type; }; struct mwifiex_txinfo { diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 21a942fd2226..59d8964dd0dc 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -197,6 +197,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) #define ISSUPP_TDLS_ENABLED(FwCapInfo) (FwCapInfo & BIT(14)) +#define ISSUPP_SDIO_SPA_ENABLED(FwCapInfo) (FwCapInfo & BIT(16)) #define MWIFIEX_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \ @@ -353,6 +354,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 #define HostCmd_CMD_TDLS_OPER 0x0122 +#define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 #define PROTOCOL_NO_SECURITY 0x01 #define PROTOCOL_STATIC_WEP 0x02 @@ -1242,6 +1244,12 @@ struct host_cmd_ds_chan_rpt_event { u8 tlvbuf[0]; } __packed; +struct host_cmd_sdio_sp_rx_aggr_cfg { + u8 action; + u8 enable; + __le16 block_size; +} __packed; + struct mwifiex_fixed_bcn_param { __le64 timestamp; __le16 beacon_period; @@ -1964,6 +1972,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_coalesce_cfg coalesce_cfg; struct host_cmd_ds_tdls_oper tdls_oper; struct host_cmd_ds_chan_rpt_req chan_rpt_req; + struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index b242c3e8df3f..eaaacecbdef6 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -163,6 +163,7 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter) { unsigned long flags; struct sk_buff *skb; + struct mwifiex_rxinfo *rx_info; spin_lock_irqsave(&adapter->rx_proc_lock, flags); if (adapter->rx_processing || adapter->rx_locked) { @@ -184,7 +185,14 @@ static int mwifiex_process_rx(struct mwifiex_adapter *adapter) adapter->delay_main_work = false; mwifiex_queue_main_work(adapter); } - mwifiex_handle_rx_packet(adapter, skb); + rx_info = MWIFIEX_SKB_RXCB(skb); + if (rx_info->buf_type == MWIFIEX_TYPE_AGGR_DATA) { + if (adapter->if_ops.deaggr_pkt) + adapter->if_ops.deaggr_pkt(adapter, skb); + dev_kfree_skb_any(skb); + } else { + mwifiex_handle_rx_packet(adapter, skb); + } } spin_lock_irqsave(&adapter->rx_proc_lock, flags); adapter->rx_processing = false; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 11db09c73e85..842fa0beb188 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -121,6 +121,7 @@ enum { #define MWIFIEX_TYPE_CMD 1 #define MWIFIEX_TYPE_DATA 0 +#define MWIFIEX_TYPE_AGGR_DATA 10 #define MWIFIEX_TYPE_EVENT 3 #define MAX_BITMAP_RATES_SIZE 18 @@ -744,6 +745,7 @@ struct mwifiex_if_ops { int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); void (*iface_work)(struct work_struct *work); void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter); + void (*deaggr_pkt)(struct mwifiex_adapter *, struct sk_buff *); }; struct mwifiex_adapter { @@ -787,6 +789,8 @@ struct mwifiex_adapter { u8 more_task_flag; u16 tx_buf_size; u16 curr_tx_buf_size; + bool sdio_rx_aggr_enable; + u16 sdio_rx_block_size; u32 ioport; enum MWIFIEX_HARDWARE_STATUS hw_status; u16 number_of_antenna; diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 509204f5ae6f..fdeeb67f790a 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1042,6 +1042,59 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, return ret; } +/* + * This function decode sdio aggreation pkt. + * + * Based on the the data block size and pkt_len, + * skb data will be decoded to few packets. + */ +static void mwifiex_deaggr_sdio_pkt(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + u32 total_pkt_len, pkt_len; + struct sk_buff *skb_deaggr; + u32 pkt_type; + u16 blk_size; + u8 blk_num; + u8 *data; + + data = skb->data; + total_pkt_len = skb->len; + + while (total_pkt_len >= (SDIO_HEADER_OFFSET + INTF_HEADER_LEN)) { + if (total_pkt_len < adapter->sdio_rx_block_size) + break; + blk_num = *(data + BLOCK_NUMBER_OFFSET); + blk_size = adapter->sdio_rx_block_size * blk_num; + if (blk_size > total_pkt_len) { + dev_err(adapter->dev, "%s: error in pkt,\t" + "blk_num=%d, blk_size=%d, total_pkt_len=%d\n", + __func__, blk_num, blk_size, total_pkt_len); + break; + } + pkt_len = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET)); + pkt_type = le16_to_cpu(*(__le16 *)(data + SDIO_HEADER_OFFSET + + 2)); + if ((pkt_len + SDIO_HEADER_OFFSET) > blk_size) { + dev_err(adapter->dev, "%s: error in pkt,\t" + "pkt_len=%d, blk_size=%d\n", + __func__, pkt_len, blk_size); + break; + } + skb_deaggr = mwifiex_alloc_dma_align_buf(pkt_len, + GFP_KERNEL | GFP_DMA); + if (!skb_deaggr) + break; + skb_put(skb_deaggr, pkt_len); + memcpy(skb_deaggr->data, data + SDIO_HEADER_OFFSET, pkt_len); + skb_pull(skb_deaggr, INTF_HEADER_LEN); + + mwifiex_handle_rx_packet(adapter, skb_deaggr); + data += blk_size; + total_pkt_len -= blk_size; + } +} + /* * This function decodes a received packet. * @@ -1055,11 +1108,28 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, u8 *cmd_buf; __le16 *curr_ptr = (__le16 *)skb->data; u16 pkt_len = le16_to_cpu(*curr_ptr); + struct mwifiex_rxinfo *rx_info; - skb_trim(skb, pkt_len); - skb_pull(skb, INTF_HEADER_LEN); + if (upld_typ != MWIFIEX_TYPE_AGGR_DATA) { + skb_trim(skb, pkt_len); + skb_pull(skb, INTF_HEADER_LEN); + } switch (upld_typ) { + case MWIFIEX_TYPE_AGGR_DATA: + dev_dbg(adapter->dev, "info: --- Rx: Aggr Data packet ---\n"); + rx_info = MWIFIEX_SKB_RXCB(skb); + rx_info->buf_type = MWIFIEX_TYPE_AGGR_DATA; + if (adapter->rx_work_enabled) { + skb_queue_tail(&adapter->rx_data_q, skb); + atomic_inc(&adapter->rx_pending); + adapter->data_received = true; + } else { + mwifiex_deaggr_sdio_pkt(adapter, skb); + dev_kfree_skb_any(skb); + } + break; + case MWIFIEX_TYPE_DATA: dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n"); if (adapter->rx_work_enabled) { @@ -1247,8 +1317,10 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, /* copy pkt to deaggr buf */ skb_deaggr = card->mpa_rx.skb_arr[pind]; - if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= - card->mpa_rx.len_arr[pind])) { + if ((pkt_type == MWIFIEX_TYPE_DATA || + (pkt_type == MWIFIEX_TYPE_AGGR_DATA && + adapter->sdio_rx_aggr_enable)) && + (pkt_len <= card->mpa_rx.len_arr[pind])) { memcpy(skb_deaggr->data, curr_ptr, pkt_len); @@ -1258,8 +1330,10 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, mwifiex_decode_rx_packet(adapter, skb_deaggr, pkt_type); } else { - dev_err(adapter->dev, "wrong aggr pkt:" - " type=%d len=%d max_len=%d\n", + dev_err(adapter->dev, "wrong aggr pkt:\t" + "sdio_single_port_rx_aggr=%d\t" + "type=%d len=%d max_len=%d\n", + adapter->sdio_rx_aggr_enable, pkt_type, pkt_len, card->mpa_rx.len_arr[pind]); dev_kfree_skb_any(skb_deaggr); @@ -1278,6 +1352,13 @@ rx_curr_single: skb->data, skb->len, adapter->ioport + port)) goto error; + if (!adapter->sdio_rx_aggr_enable && + pkt_type == MWIFIEX_TYPE_AGGR_DATA) { + dev_err(adapter->dev, "Wrong pkt type %d\t" + "Current SDIO RX Aggr not enabled\n", + pkt_type); + goto error; + } mwifiex_decode_rx_packet(adapter, skb, pkt_type); } @@ -1452,7 +1533,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) 1) / MWIFIEX_SDIO_BLOCK_SIZE; if (rx_len <= INTF_HEADER_LEN || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > - MWIFIEX_RX_DATA_BUF_SIZE) { + card->mpa_rx.buf_size) { dev_err(adapter->dev, "invalid rx_len=%d\n", rx_len); return -1; @@ -1742,6 +1823,7 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, u32 mpa_tx_buf_size, u32 mpa_rx_buf_size) { struct sdio_mmc_card *card = adapter->card; + u32 rx_buf_size; int ret = 0; card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL); @@ -1752,13 +1834,15 @@ static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter, card->mpa_tx.buf_size = mpa_tx_buf_size; - card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL); + rx_buf_size = max_t(u32, mpa_rx_buf_size, + (u32)SDIO_MAX_AGGR_BUF_SIZE); + card->mpa_rx.buf = kzalloc(rx_buf_size, GFP_KERNEL); if (!card->mpa_rx.buf) { ret = -1; goto error; } - card->mpa_rx.buf_size = mpa_rx_buf_size; + card->mpa_rx.buf_size = rx_buf_size; error: if (ret) { @@ -2298,6 +2382,7 @@ static struct mwifiex_if_ops sdio_ops = { .iface_work = mwifiex_sdio_work, .fw_dump = mwifiex_sdio_fw_dump, .reg_dump = mwifiex_sdio_reg_dump, + .deaggr_pkt = mwifiex_deaggr_sdio_pkt, }; /* diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index b23eaed84701..49422f2a5380 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1671,6 +1671,25 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, return 0; } + +/* This function prepares command of sdio rx aggr info. */ +static int mwifiex_cmd_sdio_rx_aggr_cfg(struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_sdio_sp_rx_aggr_cfg *cfg = + &cmd->params.sdio_rx_aggr_cfg; + + cmd->command = cpu_to_le16(HostCmd_CMD_SDIO_SP_RX_AGGR_CFG); + cmd->size = + cpu_to_le16(sizeof(struct host_cmd_sdio_sp_rx_aggr_cfg) + + S_DS_GEN); + cfg->action = cmd_action; + if (cmd_action == HostCmd_ACT_GEN_SET) + cfg->enable = *(u8 *)data_buf; + + return 0; +} + /* * This function prepares the commands before sending them to the firmware. * @@ -1908,6 +1927,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr, data_buf); break; + case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: + ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action, + data_buf); + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -1947,6 +1970,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) struct mwifiex_ds_auto_ds auto_ds; enum state_11d_t state_11d; struct mwifiex_ds_11n_tx_cfg tx_cfg; + u8 sdio_sp_rx_aggr_enable; if (first_sta) { if (priv->adapter->iface_type == MWIFIEX_PCIE) { @@ -1990,6 +2014,22 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) if (ret) return -1; + /** Set SDIO Single Port RX Aggr Info */ + if (priv->adapter->iface_type == MWIFIEX_SDIO && + ISSUPP_SDIO_SPA_ENABLED(priv->adapter->fw_cap_info)) { + sdio_sp_rx_aggr_enable = true; + ret = mwifiex_send_cmd(priv, + HostCmd_CMD_SDIO_SP_RX_AGGR_CFG, + HostCmd_ACT_GEN_SET, 0, + &sdio_sp_rx_aggr_enable, + true); + if (ret) { + dev_err(priv->adapter->dev, + "error while enabling SP aggregation..disable it"); + adapter->sdio_rx_aggr_enable = false; + } + } + /* Reconfigure tx buf size */ ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, HostCmd_ACT_GEN_SET, 0, diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 5f8da5924666..88dc6b672ef4 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -90,6 +90,10 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv, case HostCmd_CMD_MAC_CONTROL: break; + case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: + dev_err(priv->adapter->dev, "SDIO RX single-port aggregation Not support\n"); + break; + default: break; } @@ -943,6 +947,20 @@ static int mwifiex_ret_cfg_data(struct mwifiex_private *priv, return 0; } +/** This Function handles the command response of sdio rx aggr */ +static int mwifiex_ret_sdio_rx_aggr_cfg(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct host_cmd_sdio_sp_rx_aggr_cfg *cfg = + &resp->params.sdio_rx_aggr_cfg; + + adapter->sdio_rx_aggr_enable = cfg->enable; + adapter->sdio_rx_block_size = le16_to_cpu(cfg->block_size); + + return 0; +} + /* * This function handles the command responses. * @@ -1124,6 +1142,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_CHAN_REPORT_REQUEST: break; + case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: + ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp); + break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", resp->command); From 960d6d08e395d5441d53caa21083c0b6d38995f9 Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Fri, 13 Mar 2015 17:37:59 +0530 Subject: [PATCH 127/567] mwifiex: delay skb allocation for RX until cmd53 over This patch moves SKB allocation for RX packets from current place i.e. after reading MP regs to place where we already have read data from SDIO bus ie after cmd53. mp_rx_aggr_setup has been modified accordingly to set skb_arr to NULL. Signed-off-by: Zhaoyang Liu Signed-off-by: Shengzhen Li Reviewed-by: Amitkumar Karwar Reviewed-by: Cathy Luo Reviewed-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 59 ++++++++++++++--------------- drivers/net/wireless/mwifiex/sdio.h | 8 ++-- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index fdeeb67f790a..330e9d06729d 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1197,7 +1197,7 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, * provided there is space left, processed and finally uploaded. */ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, - struct sk_buff *skb, u8 port) + u16 rx_len, u8 port) { struct sdio_mmc_card *card = adapter->card; s32 f_do_rx_aggr = 0; @@ -1205,10 +1205,9 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, s32 f_aggr_cur = 0; s32 f_post_aggr_cur = 0; struct sk_buff *skb_deaggr; - u32 pind; - u32 pkt_len, pkt_type, mport; + struct sk_buff *skb = NULL; + u32 pkt_len, pkt_type, mport, pind; u8 *curr_ptr; - u32 rx_len = skb->len; if ((card->has_control_mask) && (port == CTRL_PORT)) { /* Read the command Resp without aggr */ @@ -1235,7 +1234,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { - if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { + if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) { f_aggr_cur = 1; } else { /* No room in Aggr buf, do rx aggr now */ @@ -1253,7 +1252,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, if (MP_RX_AGGR_IN_PROGRESS(card)) { f_do_rx_aggr = 1; - if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) + if (MP_RX_AGGR_BUF_HAS_ROOM(card, rx_len)) f_aggr_cur = 1; else /* No room in Aggr buf, do rx aggr now */ @@ -1266,7 +1265,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, if (f_aggr_cur) { dev_dbg(adapter->dev, "info: current packet aggregation\n"); /* Curr pkt can be aggregated */ - mp_rx_aggr_setup(card, skb, port); + mp_rx_aggr_setup(card, rx_len, port); if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || mp_rx_aggr_port_limit_reached(card)) { @@ -1309,18 +1308,25 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, curr_ptr = card->mpa_rx.buf; for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { + u32 *len_arr = card->mpa_rx.len_arr; /* get curr PKT len & type */ pkt_len = le16_to_cpu(*(__le16 *) &curr_ptr[0]); pkt_type = le16_to_cpu(*(__le16 *) &curr_ptr[2]); /* copy pkt to deaggr buf */ - skb_deaggr = card->mpa_rx.skb_arr[pind]; + skb_deaggr = mwifiex_alloc_dma_align_buf(len_arr[pind], + GFP_KERNEL | + GFP_DMA); + if (!skb_deaggr) + goto error; + skb_put(skb_deaggr, len_arr[pind]); + card->mpa_rx.skb_arr[pind] = skb_deaggr; if ((pkt_type == MWIFIEX_TYPE_DATA || (pkt_type == MWIFIEX_TYPE_AGGR_DATA && adapter->sdio_rx_aggr_enable)) && - (pkt_len <= card->mpa_rx.len_arr[pind])) { + (pkt_len <= len_arr[pind])) { memcpy(skb_deaggr->data, curr_ptr, pkt_len); @@ -1335,10 +1341,10 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, "type=%d len=%d max_len=%d\n", adapter->sdio_rx_aggr_enable, pkt_type, pkt_len, - card->mpa_rx.len_arr[pind]); + len_arr[pind]); dev_kfree_skb_any(skb_deaggr); } - curr_ptr += card->mpa_rx.len_arr[pind]; + curr_ptr += len_arr[pind]; } MP_RX_AGGR_BUF_RESET(card); } @@ -1347,6 +1353,10 @@ rx_curr_single: if (f_do_rx_cur) { dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", port, rx_len); + skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); + if (!skb) + goto error; + skb_put(skb, rx_len); if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, skb->len, @@ -1365,7 +1375,7 @@ rx_curr_single: if (f_post_aggr_cur) { dev_dbg(adapter->dev, "info: current packet aggregation\n"); /* Curr pkt can be aggregated */ - mp_rx_aggr_setup(card, skb, port); + mp_rx_aggr_setup(card, skb->len, port); } return 0; @@ -1375,12 +1385,13 @@ error: for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { /* copy pkt to deaggr buf */ skb_deaggr = card->mpa_rx.skb_arr[pind]; - dev_kfree_skb_any(skb_deaggr); + if (skb_deaggr) + dev_kfree_skb_any(skb_deaggr); } MP_RX_AGGR_BUF_RESET(card); } - if (f_do_rx_cur) + if (f_do_rx_cur && skb) /* Single transfer pending. Free curr buff also */ dev_kfree_skb_any(skb); @@ -1442,6 +1453,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) MWIFIEX_RX_DATA_BUF_SIZE) return -1; rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); + dev_dbg(adapter->dev, "info: rx_len = %d\n", rx_len); skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); if (!skb) @@ -1538,24 +1550,11 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) rx_len); return -1; } + rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); + dev_dbg(adapter->dev, "info: rx_len = %d\n", rx_len); - skb = mwifiex_alloc_dma_align_buf(rx_len, - GFP_KERNEL | - GFP_DMA); - - if (!skb) { - dev_err(adapter->dev, "%s: failed to alloc skb", - __func__); - return -1; - } - - skb_put(skb, rx_len); - - dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n", - rx_len, skb->len); - - if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, + if (mwifiex_sdio_card_to_host_mp_aggr(adapter, rx_len, port)) { dev_err(adapter->dev, "card_to_host_mpa failed:" " int status=%#x\n", sdio_ireg); diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 264bc9b9e02a..6f645cf47369 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -573,9 +573,9 @@ mp_tx_aggr_port_limit_reached(struct sdio_mmc_card *card) /* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ static inline void mp_rx_aggr_setup(struct sdio_mmc_card *card, - struct sk_buff *skb, u8 port) + u16 rx_len, u8 port) { - card->mpa_rx.buf_len += skb->len; + card->mpa_rx.buf_len += rx_len; if (!card->mpa_rx.pkt_cnt) card->mpa_rx.start_port = port; @@ -588,8 +588,8 @@ static inline void mp_rx_aggr_setup(struct sdio_mmc_card *card, else card->mpa_rx.ports |= 1 << (card->mpa_rx.pkt_cnt + 1); } - card->mpa_rx.skb_arr[card->mpa_rx.pkt_cnt] = skb; - card->mpa_rx.len_arr[card->mpa_rx.pkt_cnt] = skb->len; + card->mpa_rx.skb_arr[card->mpa_rx.pkt_cnt] = NULL; + card->mpa_rx.len_arr[card->mpa_rx.pkt_cnt] = rx_len; card->mpa_rx.pkt_cnt++; } #endif /* _MWIFIEX_SDIO_H */ From d6e5b7cc9819f9a108294f256dd80939e91a0a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 26 Feb 2015 14:49:56 +0100 Subject: [PATCH 128/567] ARM: dts: omap3: Add missing dmas for crypto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds missing dma DTS definitions for omap aes and sham drivers. Without it kernel drivers do not work for device tree based booting while it works for legacy booting on general purpose SoCs. Note that further changes are still needed for high secure SoCs. But since that never worked in legacy boot mode either, those will be sent separately. Signed-off-by: Pali Rohár Acked-by: Pavel Machek [tony@atomide.com: updated comments] Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index f4f78c40b564..3fdc84fddb70 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -92,6 +92,8 @@ ti,hwmods = "aes"; reg = <0x480c5000 0x50>; interrupts = <0>; + dmas = <&sdma 65 &sdma 66>; + dma-names = "tx", "rx"; }; prm: prm@48306000 { @@ -550,6 +552,8 @@ ti,hwmods = "sham"; reg = <0x480c3000 0x64>; interrupts = <49>; + dmas = <&sdma 69>; + dma-names = "rx"; }; smartreflex_core: smartreflex@480cb000 { From e5ed5b60272871786b1c5434079925bc60d771b7 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 11 Mar 2015 18:38:38 -0500 Subject: [PATCH 129/567] ARM: OMAP2+: Fix socbus family info for AM33xx devices The family information in the soc-bus data is currently not classified properly for AM33xx devices, and a read of /sys/bus/soc/devices/soc0/family currently shows "Unknown". Fix the same. Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/id.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index 2a2f4d56e4c8..25f1beea453e 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -720,6 +720,8 @@ static const char * __init omap_get_family(void) return kasprintf(GFP_KERNEL, "OMAP4"); else if (soc_is_omap54xx()) return kasprintf(GFP_KERNEL, "OMAP5"); + else if (soc_is_am33xx() || soc_is_am335x()) + return kasprintf(GFP_KERNEL, "AM33xx"); else if (soc_is_am43xx()) return kasprintf(GFP_KERNEL, "AM43xx"); else if (soc_is_dra7xx()) From e03826d5045e81a66a4fad7be9a8ecdaeb7911cf Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 17 Mar 2015 15:56:04 +0530 Subject: [PATCH 130/567] regulator: palmas: Correct TPS659038 register definition for REGEN2 The register offset for REGEN2_CTRL in different for TPS659038 chip as when compared with other Palmas family PMICs. In the case of TPS659038 the wrong offset pointed to PLLEN_CTRL and was causing a hang. Correcting the same. Signed-off-by: Keerthy Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/regulator/palmas-regulator.c | 4 ++++ include/linux/mfd/palmas.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 9205f433573c..18198316b6cf 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -1572,6 +1572,10 @@ static int palmas_regulators_probe(struct platform_device *pdev) if (!pmic) return -ENOMEM; + if (of_device_is_compatible(node, "ti,tps659038-pmic")) + palmas_generic_regs_info[PALMAS_REG_REGEN2].ctrl_addr = + TPS659038_REGEN2_CTRL; + pmic->dev = &pdev->dev; pmic->palmas = palmas; palmas->pmic = pmic; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index fb0390a1a498..ee7b1ce7a6f8 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -2999,6 +2999,9 @@ enum usb_irq_events { #define PALMAS_GPADC_TRIM15 0x0E #define PALMAS_GPADC_TRIM16 0x0F +/* TPS659038 regen2_ctrl offset iss different from palmas */ +#define TPS659038_REGEN2_CTRL 0x12 + /* TPS65917 Interrupt registers */ /* Registers for function INTERRUPT */ From a2f4870697a5bcf4a87073ec6b32dd2928c1211d Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 17 Mar 2015 12:23:19 -0400 Subject: [PATCH 131/567] fs: make sure the timestamps for lazytime inodes eventually get written Jan Kara pointed out that if there is an inode which is constantly getting dirtied with I_DIRTY_PAGES, an inode with an updated timestamp will never be written since inode->dirtied_when is constantly getting updated. We fix this by adding an extra field to the inode, dirtied_time_when, so inodes with a stale dirtytime can get detected and handled. In addition, if we have a dirtytime inode caused by an atime update, and there is no write activity on the file system, we need to have a secondary system to make sure these inodes get written out. We do this by setting up a second delayed work structure which wakes up the CPU much more rarely compared to writeback_expire_centisecs. Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara --- fs/fs-writeback.c | 82 ++++++++++++++++++++++++++++++++++++++++------ include/linux/fs.h | 1 + 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index e907052eeadb..2cfcd74faf87 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -53,6 +53,18 @@ struct wb_writeback_work { struct completion *done; /* set if the caller waits */ }; +/* + * If an inode is constantly having its pages dirtied, but then the + * updates stop dirtytime_expire_interval seconds in the past, it's + * possible for the worst case time between when an inode has its + * timestamps updated and when they finally get written out to be two + * dirtytime_expire_intervals. We set the default to 12 hours (in + * seconds), which means most of the time inodes will have their + * timestamps written to disk after 12 hours, but in the worst case a + * few inodes might not their timestamps updated for 24 hours. + */ +unsigned int dirtytime_expire_interval = 12 * 60 * 60; + /** * writeback_in_progress - determine whether there is writeback in progress * @bdi: the device's backing_dev_info structure. @@ -275,8 +287,8 @@ static int move_expired_inodes(struct list_head *delaying_queue, if ((flags & EXPIRE_DIRTY_ATIME) == 0) older_than_this = work->older_than_this; - else if ((work->reason == WB_REASON_SYNC) == 0) { - expire_time = jiffies - (HZ * 86400); + else if (!work->for_sync) { + expire_time = jiffies - (dirtytime_expire_interval * HZ); older_than_this = &expire_time; } while (!list_empty(delaying_queue)) { @@ -458,6 +470,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb, */ redirty_tail(inode, wb); } else if (inode->i_state & I_DIRTY_TIME) { + inode->dirtied_when = jiffies; list_move(&inode->i_wb_list, &wb->b_dirty_time); } else { /* The inode is clean. Remove from writeback lists. */ @@ -505,12 +518,17 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) spin_lock(&inode->i_lock); dirty = inode->i_state & I_DIRTY; - if (((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) && - (inode->i_state & I_DIRTY_TIME)) || - (inode->i_state & I_DIRTY_TIME_EXPIRED)) { - dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED; - trace_writeback_lazytime(inode); - } + if (inode->i_state & I_DIRTY_TIME) { + if ((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) || + unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) || + unlikely(time_after(jiffies, + (inode->dirtied_time_when + + dirtytime_expire_interval * HZ)))) { + dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED; + trace_writeback_lazytime(inode); + } + } else + inode->i_state &= ~I_DIRTY_TIME_EXPIRED; inode->i_state &= ~dirty; /* @@ -1131,6 +1149,45 @@ void wakeup_flusher_threads(long nr_pages, enum wb_reason reason) rcu_read_unlock(); } +/* + * Wake up bdi's periodically to make sure dirtytime inodes gets + * written back periodically. We deliberately do *not* check the + * b_dirtytime list in wb_has_dirty_io(), since this would cause the + * kernel to be constantly waking up once there are any dirtytime + * inodes on the system. So instead we define a separate delayed work + * function which gets called much more rarely. (By default, only + * once every 12 hours.) + * + * If there is any other write activity going on in the file system, + * this function won't be necessary. But if the only thing that has + * happened on the file system is a dirtytime inode caused by an atime + * update, we need this infrastructure below to make sure that inode + * eventually gets pushed out to disk. + */ +static void wakeup_dirtytime_writeback(struct work_struct *w); +static DECLARE_DELAYED_WORK(dirtytime_work, wakeup_dirtytime_writeback); + +static void wakeup_dirtytime_writeback(struct work_struct *w) +{ + struct backing_dev_info *bdi; + + rcu_read_lock(); + list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) { + if (list_empty(&bdi->wb.b_dirty_time)) + continue; + bdi_wakeup_thread(bdi); + } + rcu_read_unlock(); + schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ); +} + +static int __init start_dirtytime_writeback(void) +{ + schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ); + return 0; +} +__initcall(start_dirtytime_writeback); + static noinline void block_dump___mark_inode_dirty(struct inode *inode) { if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { @@ -1269,8 +1326,13 @@ void __mark_inode_dirty(struct inode *inode, int flags) } inode->dirtied_when = jiffies; - list_move(&inode->i_wb_list, dirtytime ? - &bdi->wb.b_dirty_time : &bdi->wb.b_dirty); + if (dirtytime) + inode->dirtied_time_when = jiffies; + if (inode->i_state & (I_DIRTY_INODE | I_DIRTY_PAGES)) + list_move(&inode->i_wb_list, &bdi->wb.b_dirty); + else + list_move(&inode->i_wb_list, + &bdi->wb.b_dirty_time); spin_unlock(&bdi->wb.list_lock); trace_writeback_dirty_inode_enqueue(inode); diff --git a/include/linux/fs.h b/include/linux/fs.h index b4d71b5e1ff2..f4131e8ead74 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -604,6 +604,7 @@ struct inode { struct mutex i_mutex; unsigned long dirtied_when; /* jiffies of first dirtying */ + unsigned long dirtied_time_when; struct hlist_node i_hash; struct list_head i_wb_list; /* backing dev IO list */ From 1efff914afac8a965ad63817ecf8861a927c2ace Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 17 Mar 2015 12:23:32 -0400 Subject: [PATCH 132/567] fs: add dirtytime_expire_seconds sysctl Add a tuning knob so we can adjust the dirtytime expiration timeout, which is very useful for testing lazytime. Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara --- fs/fs-writeback.c | 11 +++++++++++ include/linux/writeback.h | 3 +++ kernel/sysctl.c | 8 ++++++++ 3 files changed, 22 insertions(+) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 2cfcd74faf87..32a8bbd7a9ad 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1188,6 +1188,17 @@ static int __init start_dirtytime_writeback(void) } __initcall(start_dirtytime_writeback); +int dirtytime_interval_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + if (ret == 0 && write) + mod_delayed_work(system_wq, &dirtytime_work, 0); + return ret; +} + static noinline void block_dump___mark_inode_dirty(struct inode *inode) { if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 00048339c23e..b2dd371ec0ca 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -130,6 +130,7 @@ extern int vm_dirty_ratio; extern unsigned long vm_dirty_bytes; extern unsigned int dirty_writeback_interval; extern unsigned int dirty_expire_interval; +extern unsigned int dirtytime_expire_interval; extern int vm_highmem_is_dirtyable; extern int block_dump; extern int laptop_mode; @@ -146,6 +147,8 @@ extern int dirty_ratio_handler(struct ctl_table *table, int write, extern int dirty_bytes_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); +int dirtytime_interval_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); struct ctl_table; int dirty_writeback_centisecs_handler(struct ctl_table *, int, diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 88ea2d6e0031..ce410bb9f2e1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1227,6 +1227,14 @@ static struct ctl_table vm_table[] = { .proc_handler = proc_dointvec_minmax, .extra1 = &zero, }, + { + .procname = "dirtytime_expire_seconds", + .data = &dirtytime_expire_interval, + .maxlen = sizeof(dirty_expire_interval), + .mode = 0644, + .proc_handler = dirtytime_interval_handler, + .extra1 = &zero, + }, { .procname = "nr_pdflush_threads", .mode = 0444 /* read-only */, From a76fc9dda87b51010e4bc60b5e0065a70180b465 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 16 Mar 2015 20:14:02 -0500 Subject: [PATCH 133/567] ARM: OMAP: dmtimer: check for pm_runtime_get_sync() failure The current OMAP dmtimer probe does not check for the return status of pm_runtime_get_sync() before initializing the timer registers. Any timer with missing hwmod data would return a failure here, and the access of registers without enabling the clocks for the timer would trigger a l3_noc interrupt and a kernel boot hang. Add proper checking so that the probe would return a failure graciously without hanging the kernel boot. Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dmtimer.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index db10169a08de..f32c74c0e1de 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -799,6 +799,7 @@ static int omap_dm_timer_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct of_device_id *match; const struct dmtimer_platform_data *pdata; + int ret; match = of_match_device(of_match_ptr(omap_timer_match), dev); pdata = match ? match->data : dev->platform_data; @@ -860,7 +861,12 @@ static int omap_dm_timer_probe(struct platform_device *pdev) } if (!timer->reserved) { - pm_runtime_get_sync(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "%s: pm_runtime_get_sync failed!\n", + __func__); + goto err_get_sync; + } __omap_dm_timer_init_regs(timer); pm_runtime_put(dev); } @@ -873,6 +879,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev) dev_dbg(dev, "Device Probed.\n"); return 0; + +err_get_sync: + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + return ret; } /** From 51b7e5728ebcded3f2ced9cd3ff71076c91e85de Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 16 Mar 2015 20:14:03 -0500 Subject: [PATCH 134/567] ARM: OMAP: dmtimer: disable pm runtime on remove Disable the pm_runtime of the device upon remove. This is added to balance the pm_runtime_enable() invoked in the probe. Signed-off-by: Suman Anna Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dmtimer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index f32c74c0e1de..8ca94d379bc3 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -910,6 +910,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev) } spin_unlock_irqrestore(&dm_timer_lock, flags); + pm_runtime_disable(&pdev->dev); + return ret; } From 0790ec172de1bd2e23f1dbd4925426b6cc3c1b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Tue, 17 Mar 2015 14:02:32 +0100 Subject: [PATCH 135/567] KVM: nVMX: mask unrestricted_guest if disabled on L0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If EPT was enabled, unrestricted_guest was allowed in L1 regardless of L0. L1 triple faulted when running L2 guest that required emulation. Another side effect was 'WARN_ON_ONCE(vmx->nested.nested_run_pending)' in L0's dmesg: WARNING: CPU: 0 PID: 0 at arch/x86/kvm/vmx.c:9190 nested_vmx_vmexit+0x96e/0xb00 [kvm_intel] () Prevent this scenario by masking SECONDARY_EXEC_UNRESTRICTED_GUEST when the host doesn't have it enabled. Fixes: 78051e3b7e35 ("KVM: nVMX: Disable unrestricted mode if ept=0") Cc: stable@vger.kernel.org Tested-By: Kashyap Chamarthy Signed-off-by: Radim Krčmář Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/vmx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 10a481b7674d..ae4f6d35d19c 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2479,8 +2479,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx) if (enable_ept) { /* nested EPT: emulate EPT also to L1 */ vmx->nested.nested_vmx_secondary_ctls_high |= - SECONDARY_EXEC_ENABLE_EPT | - SECONDARY_EXEC_UNRESTRICTED_GUEST; + SECONDARY_EXEC_ENABLE_EPT; vmx->nested.nested_vmx_ept_caps = VMX_EPT_PAGE_WALK_4_BIT | VMX_EPTP_WB_BIT | VMX_EPT_2MB_PAGE_BIT | VMX_EPT_INVEPT_BIT; @@ -2494,6 +2493,10 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx) } else vmx->nested.nested_vmx_ept_caps = 0; + if (enable_unrestricted_guest) + vmx->nested.nested_vmx_secondary_ctls_high |= + SECONDARY_EXEC_UNRESTRICTED_GUEST; + /* miscellaneous data */ rdmsr(MSR_IA32_VMX_MISC, vmx->nested.nested_vmx_misc_low, From 391949b6f02121371e3d7d9082c6d17fd9853034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 18 Mar 2015 11:27:28 +0100 Subject: [PATCH 136/567] spi: trigger trace event for message-done before mesg->complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With spidev the mesg->complete callback points to spidev_complete. Calling this unblocks spidev_sync and so spidev_sync_write finishes. As the struct spi_message just read is a local variable in spidev_sync_write and recording the trace event accesses this message the recording is better done first. The same can happen for spidev_sync_read. This fixes an oops observed on a 3.14-rt system with spidev activity after echo 1 > /sys/kernel/debug/tracing/events/spi/enable . Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index c64a3e59fce3..57a195041dc7 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1105,13 +1105,14 @@ void spi_finalize_current_message(struct spi_master *master) "failed to unprepare message: %d\n", ret); } } + + trace_spi_message_done(mesg); + master->cur_msg_prepared = false; mesg->state = NULL; if (mesg->complete) mesg->complete(mesg->context); - - trace_spi_message_done(mesg); } EXPORT_SYMBOL_GPL(spi_finalize_current_message); From cf39284d41f67964cf42b21bb386c012cf5b7f65 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 18 Mar 2015 08:57:41 +0800 Subject: [PATCH 137/567] regulator: Fix documentation for regmap in the config dev_get_regulator() does not exist, fix the typo. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index d4ad5b5a02bb..045f709cb89b 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -316,7 +316,7 @@ struct regulator_desc { * @driver_data: private regulator data * @of_node: OpenFirmware node to parse for device tree bindings (may be * NULL). - * @regmap: regmap to use for core regmap helpers if dev_get_regulator() is + * @regmap: regmap to use for core regmap helpers if dev_get_regmap() is * insufficient. * @ena_gpio_initialized: GPIO controlling regulator enable was properly * initialized, meaning that >= 0 is a valid gpio From 077155332265f1d64c57bd6c49748a8b7e72a3f9 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 20 Feb 2015 14:21:14 +0530 Subject: [PATCH 138/567] ARM: dts: dra7: remove ti,hwmod property from pcie phy Now that we don't have hwmod entry for pcie PHY remove the ti,hwmod property from PCIE PHY's. Otherwise we will get: platform 4a094000.pciephy: Cannot lookup hwmod 'pcie1-phy' Signed-off-by: Kishon Vijay Abraham I [tony@atomide.com: updated comments] Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/dra7.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 127608d79033..c4659a979c41 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1111,7 +1111,6 @@ "wkupclk", "refclk", "div-clk", "phy-div"; #phy-cells = <0>; - ti,hwmods = "pcie1-phy"; }; pcie2_phy: pciephy@4a095000 { @@ -1130,7 +1129,6 @@ "wkupclk", "refclk", "div-clk", "phy-div"; #phy-cells = <0>; - ti,hwmods = "pcie2-phy"; status = "disabled"; }; }; From 599c376c49323127c9bdbb0fa61a3d4743819bc2 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 18 Mar 2015 13:41:34 -0700 Subject: [PATCH 139/567] ARM: dts: Fix gpio interrupts for dm816x Commit 7800064ba507 ("ARM: dts: Add basic dm816x device tree configuration") added basic devices for dm816x, but I was not able to test the GPIO interrupts earlier until I found some suitable pins to test with. We can mux the MMC card detect and write protect pins from SD_SDCD and SD_SDWP mode to use a normal GPIO interrupts that are also suitable for the MMC subsystem. This turned out several issues that need to be fixed: - I set the GPIO type wrong to be compatible with omap3 instead of omap4. The GPIO controller on dm816x has EOI interrupt register like omap4 and am335x. - I got the GPIO interrupt numbers wrong as each bank has two and we only use one. They need to be set up the same way as on am335x. - The gpio banks are missing interrupt controller related properties. With these changes the GPIO interrupts can be used with the MMC card detect pin, so let's wire that up. Let's also mux all the MMC lines for completeness while at it. For the first GPIO bank I tested using GPMC lines temporarily muxed to GPIOs on the dip switch 10. Cc: Brian Hutchinson Cc: Matthijs van Duin Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/dm8168-evm.dts | 19 +++++++++++++++++++ arch/arm/boot/dts/dm816x.dtsi | 18 ++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/dm8168-evm.dts b/arch/arm/boot/dts/dm8168-evm.dts index d3a29c1b8417..afe678f6d2e9 100644 --- a/arch/arm/boot/dts/dm8168-evm.dts +++ b/arch/arm/boot/dts/dm8168-evm.dts @@ -36,6 +36,20 @@ >; }; + mmc_pins: pinmux_mmc_pins { + pinctrl-single,pins = < + DM816X_IOPAD(0x0a70, MUX_MODE0) /* SD_POW */ + DM816X_IOPAD(0x0a74, MUX_MODE0) /* SD_CLK */ + DM816X_IOPAD(0x0a78, MUX_MODE0) /* SD_CMD */ + DM816X_IOPAD(0x0a7C, MUX_MODE0) /* SD_DAT0 */ + DM816X_IOPAD(0x0a80, MUX_MODE0) /* SD_DAT1 */ + DM816X_IOPAD(0x0a84, MUX_MODE0) /* SD_DAT2 */ + DM816X_IOPAD(0x0a88, MUX_MODE0) /* SD_DAT2 */ + DM816X_IOPAD(0x0a8c, MUX_MODE2) /* GP1[7] */ + DM816X_IOPAD(0x0a90, MUX_MODE2) /* GP1[8] */ + >; + }; + usb0_pins: pinmux_usb0_pins { pinctrl-single,pins = < DM816X_IOPAD(0x0d00, MUX_MODE0) /* USB0_DRVVBUS */ @@ -137,7 +151,12 @@ }; &mmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc_pins>; vmmc-supply = <&vmmcsd_fixed>; + bus-width = <4>; + cd-gpios = <&gpio2 7 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>; }; /* At least dm8168-evm rev c won't support multipoint, later may */ diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi index 3c97b5f2addc..f35715bc6992 100644 --- a/arch/arm/boot/dts/dm816x.dtsi +++ b/arch/arm/boot/dts/dm816x.dtsi @@ -150,17 +150,27 @@ }; gpio1: gpio@48032000 { - compatible = "ti,omap3-gpio"; + compatible = "ti,omap4-gpio"; ti,hwmods = "gpio1"; + ti,gpio-always-on; reg = <0x48032000 0x1000>; - interrupts = <97>; + interrupts = <96>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; }; gpio2: gpio@4804c000 { - compatible = "ti,omap3-gpio"; + compatible = "ti,omap4-gpio"; ti,hwmods = "gpio2"; + ti,gpio-always-on; reg = <0x4804c000 0x1000>; - interrupts = <99>; + interrupts = <98>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; }; gpmc: gpmc@50000000 { From bc188d818edf325ae38cfa43254a0b10a4defd65 Mon Sep 17 00:00:00 2001 From: Sam Bradshaw Date: Wed, 18 Mar 2015 17:06:18 -0600 Subject: [PATCH 140/567] blkmq: Fix NULL pointer deref when all reserved tags in When allocating from the reserved tags pool, bt_get() is called with a NULL hctx. If all tags are in use, the hw queue is kicked to push out any pending IO, potentially freeing tags, and tag allocation is retried. The problem is that blk_mq_run_hw_queue() doesn't check for a NULL hctx. So we avoid it with a simple NULL hctx test. Tested by hammering mtip32xx with concurrent smartctl/hdparm. Signed-off-by: Sam Bradshaw Signed-off-by: Selvan Mani Fixes: b32232073e80 ("blk-mq: fix hang in bt_get()") Cc: stable@kernel.org Added appropriate comment. Signed-off-by: Jens Axboe --- block/blk-mq-tag.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index d53a764b05ea..be3290cc0644 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -278,9 +278,11 @@ static int bt_get(struct blk_mq_alloc_data *data, /* * We're out of tags on this hardware queue, kick any * pending IO submits before going to sleep waiting for - * some to complete. + * some to complete. Note that hctx can be NULL here for + * reserved tag allocation. */ - blk_mq_run_hw_queue(hctx, false); + if (hctx) + blk_mq_run_hw_queue(hctx, false); /* * Retry tag allocation after running the hardware queue, From 4de60970abf9f49737f51ec6e7a1e3bcf6d36742 Mon Sep 17 00:00:00 2001 From: "qipeng.zha" Date: Wed, 11 Mar 2015 01:15:38 +0800 Subject: [PATCH 141/567] gpiolib: translate pin number in GPIO ACPI callbacks If GPIO driver use pin mapping, need to translate pin number between ACPI table and GPIO driver. This issue is found on one platform with Cherryview gpio controller, kernel is hang when executed _PS0 method of one ACPI device, since without this translation, it access invalid gpiodesc array. Verified it works again with this patch. Signed-off-by: qipeng.zha Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index c0929d938ced..df990f29757a 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -201,6 +201,10 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, if (!handler) return AE_BAD_PARAMETER; + pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin); + if (pin < 0) + return AE_BAD_PARAMETER; + desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event"); if (IS_ERR(desc)) { dev_err(chip->dev, "Failed to request GPIO\n"); @@ -551,6 +555,12 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, struct gpio_desc *desc; bool found; + pin = acpi_gpiochip_pin_to_gpio_offset(chip, pin); + if (pin < 0) { + status = AE_BAD_PARAMETER; + goto out; + } + mutex_lock(&achip->conn_lock); found = false; From 9c8928f5176766bec79f272bd47b7124e11cccbd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 16 Mar 2015 09:08:07 +0200 Subject: [PATCH 142/567] iwlwifi: dvm: run INIT firmware again upon .start() The assumption before this patch was that we don't need to run again the INIT firmware after the system booted. The INIT firmware runs calibrations which impact the physical layer's behavior. Users reported that it may be helpful to run these calibrations again every time the interface is brought up. The penatly is minimal, since the calibrations run fast. This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=94341 CC: Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/dev.h | 1 - drivers/net/wireless/iwlwifi/dvm/ucode.c | 5 ----- 2 files changed, 6 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index a6f22c32a279..3811878ab9cd 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -708,7 +708,6 @@ struct iwl_priv { unsigned long reload_jiffies; int reload_count; bool ucode_loaded; - bool init_ucode_run; /* Don't run init uCode again */ u8 plcp_delta_threshold; diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 4dbef7e58c2e..5244e43bfafb 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -418,9 +418,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv) if (!priv->fw->img[IWL_UCODE_INIT].sec[0].len) return 0; - if (priv->init_ucode_run) - return 0; - iwl_init_notification_wait(&priv->notif_wait, &calib_wait, calib_complete, ARRAY_SIZE(calib_complete), iwlagn_wait_calib, priv); @@ -440,8 +437,6 @@ int iwl_run_init_ucode(struct iwl_priv *priv) */ ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, UCODE_CALIB_TIMEOUT); - if (!ret) - priv->init_ucode_run = true; goto out; From dcbc17ad7c7525ed04a45a94cfc5640d5cccf480 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 10 Mar 2015 21:24:34 +0100 Subject: [PATCH 143/567] iwlwifi: mvm: protect rate scaling against non-mvm IBSS stations When the driver callback returns that it's out of space for new stations, the mac80211 IBSS code still keeps the station so it doesn't try to add it over and over again. Since the rate scaling algorithm is separate in mac80211, it also invokes the rate scaling algorithm for such stations. It doesn't know that our rate scaling algorithm is tightly integrated with the MVM code and relies on those data structures, and it cannot as the abstraction doesn't allow for it. This leads to crashes when the rate scaling algorithm tries to use uninitialized data, notably the mvmsta->vif pointer. Protect against this in the rate scaling algorithm. We cannot get good rates with such peers anyway since the firmware cannot do anything with them. This should fix https://bugzilla.kernel.org/show_bug.cgi?id=93461 CC: Reported-by: Richard Taylor Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index efa9688a4cf1..078f24cf4af3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1278,6 +1278,9 @@ static void rs_mac80211_tx_status(void *mvm_r, struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + if (!iwl_mvm_sta_from_mac80211(sta)->vif) + return; + if (!ieee80211_is_data(hdr->frame_control) || info->flags & IEEE80211_TX_CTL_NO_ACK) return; @@ -2511,6 +2514,14 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = mvm_sta; + if (sta && !iwl_mvm_sta_from_mac80211(sta)->vif) { + /* if vif isn't initialized mvm doesn't know about + * this station, so don't do anything with the it + */ + sta = NULL; + mvm_sta = NULL; + } + /* TODO: handle rate_idx_mask and rate_idx_mcs_mask */ /* Treat uninitialized rate scaling data same as non-existing. */ @@ -2827,6 +2838,9 @@ static void rs_rate_update(void *mvm_r, (struct iwl_op_mode *)mvm_r; struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + if (!iwl_mvm_sta_from_mac80211(sta)->vif) + return; + /* Stop any ongoing aggregations as rs starts off assuming no agg */ for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) ieee80211_stop_tx_ba_session(sta, tid); @@ -3587,9 +3601,15 @@ static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf, MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32); -static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir) +static void rs_add_debugfs(void *mvm, void *priv_sta, struct dentry *dir) { - struct iwl_lq_sta *lq_sta = mvm_sta; + struct iwl_lq_sta *lq_sta = priv_sta; + struct iwl_mvm_sta *mvmsta; + + mvmsta = container_of(lq_sta, struct iwl_mvm_sta, lq_sta); + + if (!mvmsta->vif) + return; debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, lq_sta, &rs_sta_dbgfs_scale_table_ops); From 132fee062655e90948e189c8c14ce21f115ebbda Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Thu, 19 Mar 2015 12:46:06 +0200 Subject: [PATCH 144/567] iwlwifi: add new 3165 series PCI IDs Add new 3165 PCI IDs for new 1x1 cards. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index dbd6bcf52205..686dd301cd53 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -368,10 +368,12 @@ static const struct pci_device_id iwl_hw_card_ids[] = { /* 3165 Series */ {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)}, - {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)}, - {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)}, {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3166, 0x4310, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3166, 0x4210, iwl3165_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3165, 0x8010, iwl3165_2ac_cfg)}, /* 7265 Series */ {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)}, From 1f16ea294d2ef63013740f4c8539e430b6c12dff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 6 Mar 2015 09:17:37 +0100 Subject: [PATCH 145/567] iwlwifi: mvm: remove WARN_ON for invalid BA notification The firmware frequently manages to trigger this, and there's no known driver workaround, so stop warning. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 07304e1fd64a..96a05406babf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -949,8 +949,10 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, mvmsta = iwl_mvm_sta_from_mac80211(sta); tid_data = &mvmsta->tid_data[tid]; - if (WARN_ONCE(tid_data->txq_id != scd_flow, "Q %d, tid %d, flow %d", - tid_data->txq_id, tid, scd_flow)) { + if (tid_data->txq_id != scd_flow) { + IWL_ERR(mvm, + "invalid BA notification: Q %d, tid %d, flow %d\n", + tid_data->txq_id, tid, scd_flow); rcu_read_unlock(); return 0; } From 1ac31de744202a3a14601170a57f155b4a8d2c21 Mon Sep 17 00:00:00 2001 From: Mark James Date: Tue, 17 Mar 2015 21:35:23 +0000 Subject: [PATCH 146/567] ARM: socfpga: dts: fix spi1 interrupt The socfpga.dtsi currently has the wrong interrupt number set for SPI master 1 Trying to use the master without this change results in the kernel boot process waiting forever for an interrupt that will never occur while attempting to probe any slave devices configured in the device tree as being under SPI master 1. The change works for the Cyclone V, and according to the Arria 5 handbook should be good there too. Signed-off-by: Mark James Acked-by: Steffen Trumtrar Signed-off-by: Dinh Nguyen --- arch/arm/boot/dts/socfpga.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 9d8760956752..d9176e606173 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -660,7 +660,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0xfff01000 0x1000>; - interrupts = <0 156 4>; + interrupts = <0 155 4>; num-cs = <4>; clocks = <&spi_m_clk>; status = "disabled"; From 67d8712dcc70aa16d8e14a52eb73870e3cbddfc2 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 18 Mar 2015 11:57:39 -0600 Subject: [PATCH 147/567] selftests: Fix build failures when invoked from kselftest target Several tests that rely on implicit build rules fail to build, when invoked from the main Makefile kselftest target. These failures are due to --no-builtin-rules and --no-builtin-variables options set in the inherited MAKEFLAGS. --no-builtin-rules eliminates the use of built-in implicit rules and --no-builtin-variables is for not defining built-in variables. These two options override the use of implicit rules resulting in build failures. In addition, inherited LDFLAGS result in build failures and there is no need to define LDFLAGS. Clear LDFLAGS and MAKEFLAG when make is invoked from the main Makefile kselftest target. Fixing this at selftests Makefile avoids changing the main Makefile and keeps this change self contained at selftests level. Signed-off-by: Shuah Khan Acked-by: Michael Ellerman --- tools/testing/selftests/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 4e511221a0c1..0db571340edb 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -22,6 +22,14 @@ TARGETS += vm TARGETS_HOTPLUG = cpu-hotplug TARGETS_HOTPLUG += memory-hotplug +# Clear LDFLAGS and MAKEFLAGS if called from main +# Makefile to avoid test build failures when test +# Makefile doesn't have explicit build rules. +ifeq (1,$(MAKELEVEL)) +undefine LDFLAGS +override MAKEFLAGS = +endif + all: for TARGET in $(TARGETS); do \ make -C $$TARGET; \ From 5e71fc8629cefae5f3c1a4f498de3fe4f631924a Mon Sep 17 00:00:00 2001 From: Nathaniel W Filardo Date: Mon, 16 Mar 2015 11:19:55 -0400 Subject: [PATCH 148/567] USB: keyspan_pda: add new device id Add USB VID/PID for Xircom PGMFHUB USB/serial component. (The hub and SCSI bridge on that hardware are recognized out of the box by existing drivers.) Tested VID/PID using new_id and loopback connection and was met with success, but that's all the testing done. Signed-off-by: Nathaniel Wesley Filardo Cc: stable Signed-off-by: Johan Hovold --- drivers/usb/serial/keyspan_pda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index dd97d8b572c3..4f7e072e4e00 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -61,6 +61,7 @@ struct keyspan_pda_private { /* For Xircom PGSDB9 and older Entrega version of the same device */ #define XIRCOM_VENDOR_ID 0x085a #define XIRCOM_FAKE_ID 0x8027 +#define XIRCOM_FAKE_ID_2 0x8025 /* "PGMFHUB" serial */ #define ENTREGA_VENDOR_ID 0x1645 #define ENTREGA_FAKE_ID 0x8093 @@ -70,6 +71,7 @@ static const struct usb_device_id id_table_combined[] = { #endif #ifdef XIRCOM { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, + { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) }, { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, #endif { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, @@ -93,6 +95,7 @@ static const struct usb_device_id id_table_fake[] = { #ifdef XIRCOM static const struct usb_device_id id_table_fake_xircom[] = { { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, + { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) }, { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, { } }; From 5067c0469c643512f24786990e315f9c15cc7d24 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Thu, 12 Mar 2015 10:32:18 -0700 Subject: [PATCH 149/567] ata: Add a new flag to destinguish sas controller SAS controller has its own tag allocation, which doesn't directly match to ATA tag, so SAS and SATA have different code path for ata tags. Originally we use port->scsi_host (98bd4be1) to destinguish SAS controller, but libsas set ->scsi_host too, so we can't use it for the destinguish, we add a new flag for this purpose. Without this patch, the following oops can happen because scsi-mq uses a host-wide tag map shared among all devices with some integer tag values >= ATA_MAX_QUEUE. These unexpectedly high tag values cause __ata_qc_from_tag() to return NULL, which is then dereferenced in ata_qc_new_init(). BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 IP: [] ata_qc_new_init+0x3e/0x120 PGD 32adf0067 PUD 32adf1067 PMD 0 Oops: 0002 [#1] SMP DEBUG_PAGEALLOC Modules linked in: iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi igb i2c_algo_bit ptp pps_core pm80xx libsas scsi_transport_sas sg coretemp eeprom w83795 i2c_i801 CPU: 4 PID: 1450 Comm: cydiskbench Not tainted 4.0.0-rc3 #1 Hardware name: Supermicro X8DTH-i/6/iF/6F/X8DTH, BIOS 2.1b 05/04/12 task: ffff8800ba86d500 ti: ffff88032a064000 task.ti: ffff88032a064000 RIP: 0010:[] [] ata_qc_new_init+0x3e/0x120 RSP: 0018:ffff88032a067858 EFLAGS: 00010046 RAX: 0000000000000000 RBX: ffff8800ba0d2230 RCX: 000000000000002a RDX: ffffffff80505ae0 RSI: 0000000000000020 RDI: ffff8800ba0d2230 RBP: ffff88032a067868 R08: 0000000000000201 R09: 0000000000000001 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8800ba0d0000 R13: ffff8800ba0d2230 R14: ffffffff80505ae0 R15: ffff8800ba0d0000 FS: 0000000041223950(0063) GS:ffff88033e480000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000058 CR3: 000000032a0a3000 CR4: 00000000000006e0 Stack: ffff880329eee758 ffff880329eee758 ffff88032a0678a8 ffffffff80502dad ffff8800ba167978 ffff880329eee758 ffff88032bf9c520 ffff8800ba167978 ffff88032bf9c520 ffff88032bf9a290 ffff88032a0678b8 ffffffff80506909 Call Trace: [] ata_scsi_translate+0x3d/0x1b0 [] ata_sas_queuecmd+0x149/0x2a0 [] sas_queuecommand+0xa0/0x1f0 [libsas] [] scsi_dispatch_cmd+0xd4/0x1a0 [] scsi_queue_rq+0x66f/0x7f0 [] __blk_mq_run_hw_queue+0x208/0x3f0 [] blk_mq_run_hw_queue+0x88/0xc0 [] blk_mq_insert_request+0xc4/0x130 [] blk_execute_rq_nowait+0x73/0x160 [] sg_common_write+0x3da/0x720 [sg] [] sg_new_write+0x250/0x360 [sg] [] sg_write+0x13b/0x450 [sg] [] vfs_write+0xd1/0x1b0 [] SyS_write+0x54/0xc0 [] system_call_fastpath+0x12/0x17 tj: updated description. Fixes: 12cb5ce101ab ("libata: use blk taging") Reported-and-tested-by: Tony Battersby Signed-off-by: Shaohua Li Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 4 ++-- drivers/scsi/ipr.c | 3 ++- drivers/scsi/libsas/sas_ata.c | 3 ++- include/linux/libata.h | 1 + 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 4c35f0822d06..ef150ebb4c30 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4737,7 +4737,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag) return NULL; /* libsas case */ - if (!ap->scsi_host) { + if (ap->flags & ATA_FLAG_SAS_HOST) { tag = ata_sas_allocate_tag(ap); if (tag < 0) return NULL; @@ -4776,7 +4776,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) tag = qc->tag; if (likely(ata_tag_valid(tag))) { qc->tag = ATA_TAG_POISON; - if (!ap->scsi_host) + if (ap->flags & ATA_FLAG_SAS_HOST) ata_sas_free_tag(tag, ap); } } diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 9219953ee949..d9afc51af7d3 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6815,7 +6815,8 @@ static struct ata_port_operations ipr_sata_ops = { }; static struct ata_port_info sata_port_info = { - .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA, + .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | + ATA_FLAG_SAS_HOST, .pio_mask = ATA_PIO4_ONLY, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA6, diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 932d9cc98d2f..9c706d8c1441 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -547,7 +547,8 @@ static struct ata_port_operations sas_sata_ops = { }; static struct ata_port_info sata_port_info = { - .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ, + .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ | + ATA_FLAG_SAS_HOST, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA6, diff --git a/include/linux/libata.h b/include/linux/libata.h index fc03efa64ffe..6b08cc106c21 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -232,6 +232,7 @@ enum { * led */ ATA_FLAG_NO_DIPM = (1 << 23), /* host not happy with DIPM */ ATA_FLAG_LOWTAG = (1 << 24), /* host wants lowest available tag */ + ATA_FLAG_SAS_HOST = (1 << 25), /* SAS host */ /* bits 24:31 of ap->flags are reserved for LLD specific flags */ From c6b570d97c0e77f570bb6b2ed30d372b2b1e9aae Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 9 Mar 2015 12:20:13 +0100 Subject: [PATCH 150/567] regmap: introduce regmap_name to fix syscon regmap trace events This patch fixes a NULL pointer dereference when enabling regmap event tracing in the presence of a syscon regmap, introduced by commit bdb0066df96e ("mfd: syscon: Decouple syscon interface from platform devices"). That patch introduced syscon regmaps that have their dev field set to NULL. The regmap trace events expect it to point to a valid struct device and feed it to dev_name(): $ echo 1 > /sys/kernel/debug/tracing/events/regmap/enable Unable to handle kernel NULL pointer dereference at virtual address 0000002c pgd = 80004000 [0000002c] *pgd=00000000 Internal error: Oops: 17 [#1] SMP ARM Modules linked in: coda videobuf2_vmalloc CPU: 0 PID: 304 Comm: kworker/0:2 Not tainted 4.0.0-rc2+ #9197 Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) Workqueue: events_freezable thermal_zone_device_check task: 9f25a200 ti: 9f1ee000 task.ti: 9f1ee000 PC is at ftrace_raw_event_regmap_block+0x3c/0xe4 LR is at _regmap_raw_read+0x1bc/0x1cc pc : [<803636e8>] lr : [<80365f2c>] psr: 600f0093 sp : 9f1efd78 ip : 9f1efdb8 fp : 9f1efdb4 r10: 00000004 r9 : 00000001 r8 : 00000001 r7 : 00000180 r6 : 00000000 r5 : 9f00e3c0 r4 : 00000003 r3 : 00000001 r2 : 00000180 r1 : 00000000 r0 : 9f00e3c0 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5387d Table: 2d91004a DAC: 00000015 Process kworker/0:2 (pid: 304, stack limit = 0x9f1ee210) Stack: (0x9f1efd78 to 0x9f1f0000) fd60: 9f1efda4 9f1efd88 fd80: 800708c0 805f9510 80927140 800f0013 9f1fc800 9eb2f490 00000000 00000180 fda0: 808e3840 00000001 9f1efdfc 9f1efdb8 80365f2c 803636b8 805f8958 800708e0 fdc0: a00f0013 803636ac 9f16de00 00000180 80927140 9f1fc800 9f1fc800 9f1efe6c fde0: 9f1efe6c 9f732400 00000000 00000000 9f1efe1c 9f1efe00 80365f70 80365d7c fe00: 80365f3c 9f1fc800 9f1fc800 00000180 9f1efe44 9f1efe20 803656a4 80365f48 fe20: 9f1fc800 00000180 9f1efe6c 9f1efe6c 9f732400 00000000 9f1efe64 9f1efe48 fe40: 803657bc 80365634 00000001 9e95f910 9f1fc800 9f1efeb4 9f1efe8c 9f1efe68 fe60: 80452ac0 80365778 9f1efe8c 9f1efe78 9e93d400 9e93d5e8 9f1efeb4 9f72ef40 fe80: 9f1efeac 9f1efe90 8044e11c 80452998 8045298c 9e93d608 9e93d400 808e1978 fea0: 9f1efecc 9f1efeb0 8044fd14 8044e0d0 ffffffff 9f25a200 9e93d608 9e481380 fec0: 9f1efedc 9f1efed0 8044fde8 8044fcec 9f1eff1c 9f1efee0 80038d50 8044fdd8 fee0: 9f1ee020 9f72ef40 9e481398 00000000 00000008 9f72ef54 9f1ee020 9f72ef40 ff00: 9e481398 9e481380 00000008 9f72ef40 9f1eff5c 9f1eff20 80039754 80038bfc ff20: 00000000 9e481380 80894100 808e1662 00000000 9e4f2ec0 00000000 9e481380 ff40: 800396f8 00000000 00000000 00000000 9f1effac 9f1eff60 8003e020 80039704 ff60: ffffffff 00000000 ffffffff 9e481380 00000000 00000000 9f1eff78 9f1eff78 ff80: 00000000 00000000 9f1eff88 9f1eff88 9e4f2ec0 8003df30 00000000 00000000 ffa0: 00000000 9f1effb0 8000eb60 8003df3c 00000000 00000000 00000000 00000000 ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 ffffffff ffffffff Backtrace: [<803636ac>] (ftrace_raw_event_regmap_block) from [<80365f2c>] (_regmap_raw_read+0x1bc/0x1cc) r9:00000001 r8:808e3840 r7:00000180 r6:00000000 r5:9eb2f490 r4:9f1fc800 [<80365d70>] (_regmap_raw_read) from [<80365f70>] (_regmap_bus_read+0x34/0x6c) r10:00000000 r9:00000000 r8:9f732400 r7:9f1efe6c r6:9f1efe6c r5:9f1fc800 r4:9f1fc800 [<80365f3c>] (_regmap_bus_read) from [<803656a4>] (_regmap_read+0x7c/0x144) r6:00000180 r5:9f1fc800 r4:9f1fc800 r3:80365f3c [<80365628>] (_regmap_read) from [<803657bc>] (regmap_read+0x50/0x70) r9:00000000 r8:9f732400 r7:9f1efe6c r6:9f1efe6c r5:00000180 r4:9f1fc800 [<8036576c>] (regmap_read) from [<80452ac0>] (imx_get_temp+0x134/0x1a4) r6:9f1efeb4 r5:9f1fc800 r4:9e95f910 r3:00000001 [<8045298c>] (imx_get_temp) from [<8044e11c>] (thermal_zone_get_temp+0x58/0x74) r7:9f72ef40 r6:9f1efeb4 r5:9e93d5e8 r4:9e93d400 [<8044e0c4>] (thermal_zone_get_temp) from [<8044fd14>] (thermal_zone_device_update+0x34/0xec) r6:808e1978 r5:9e93d400 r4:9e93d608 r3:8045298c [<8044fce0>] (thermal_zone_device_update) from [<8044fde8>] (thermal_zone_device_check+0x1c/0x20) r5:9e481380 r4:9e93d608 [<8044fdcc>] (thermal_zone_device_check) from [<80038d50>] (process_one_work+0x160/0x3d4) [<80038bf0>] (process_one_work) from [<80039754>] (worker_thread+0x5c/0x4f4) r10:9f72ef40 r9:00000008 r8:9e481380 r7:9e481398 r6:9f72ef40 r5:9f1ee020 r4:9f72ef54 [<800396f8>] (worker_thread) from [<8003e020>] (kthread+0xf0/0x108) r10:00000000 r9:00000000 r8:00000000 r7:800396f8 r6:9e481380 r5:00000000 r4:9e4f2ec0 [<8003df30>] (kthread) from [<8000eb60>] (ret_from_fork+0x14/0x34) r7:00000000 r6:00000000 r5:8003df30 r4:9e4f2ec0 Code: e3140040 1a00001a e3140020 1a000016 (e596002c) ---[ end trace 193c15c2494ec960 ]--- Fixes: bdb0066df96e (mfd: syscon: Decouple syscon interface from platform devices) Signed-off-by: Philipp Zabel Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/base/regmap/internal.h | 8 +++ drivers/base/regmap/regcache.c | 16 ++--- drivers/base/regmap/regmap.c | 32 ++++----- include/trace/events/regmap.h | 123 ++++++++++++++++----------------- 4 files changed, 91 insertions(+), 88 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index beb8b27d4621..a13587b5c2be 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -243,4 +243,12 @@ extern struct regcache_ops regcache_rbtree_ops; extern struct regcache_ops regcache_lzo_ops; extern struct regcache_ops regcache_flat_ops; +static inline const char *regmap_name(const struct regmap *map) +{ + if (map->dev) + return dev_name(map->dev); + + return map->name; +} + #endif diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index f373c35f9e1d..f5db662e951e 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -218,7 +218,7 @@ int regcache_read(struct regmap *map, ret = map->cache_ops->read(map, reg, value); if (ret == 0) - trace_regmap_reg_read_cache(map->dev, reg, *value); + trace_regmap_reg_read_cache(map, reg, *value); return ret; } @@ -311,7 +311,7 @@ int regcache_sync(struct regmap *map) dev_dbg(map->dev, "Syncing %s cache\n", map->cache_ops->name); name = map->cache_ops->name; - trace_regcache_sync(map->dev, name, "start"); + trace_regcache_sync(map, name, "start"); if (!map->cache_dirty) goto out; @@ -346,7 +346,7 @@ out: regmap_async_complete(map); - trace_regcache_sync(map->dev, name, "stop"); + trace_regcache_sync(map, name, "stop"); return ret; } @@ -381,7 +381,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min, name = map->cache_ops->name; dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max); - trace_regcache_sync(map->dev, name, "start region"); + trace_regcache_sync(map, name, "start region"); if (!map->cache_dirty) goto out; @@ -401,7 +401,7 @@ out: regmap_async_complete(map); - trace_regcache_sync(map->dev, name, "stop region"); + trace_regcache_sync(map, name, "stop region"); return ret; } @@ -428,7 +428,7 @@ int regcache_drop_region(struct regmap *map, unsigned int min, map->lock(map->lock_arg); - trace_regcache_drop_region(map->dev, min, max); + trace_regcache_drop_region(map, min, max); ret = map->cache_ops->drop(map, min, max); @@ -455,7 +455,7 @@ void regcache_cache_only(struct regmap *map, bool enable) map->lock(map->lock_arg); WARN_ON(map->cache_bypass && enable); map->cache_only = enable; - trace_regmap_cache_only(map->dev, enable); + trace_regmap_cache_only(map, enable); map->unlock(map->lock_arg); } EXPORT_SYMBOL_GPL(regcache_cache_only); @@ -493,7 +493,7 @@ void regcache_cache_bypass(struct regmap *map, bool enable) map->lock(map->lock_arg); WARN_ON(map->cache_only && enable); map->cache_bypass = enable; - trace_regmap_cache_bypass(map->dev, enable); + trace_regmap_cache_bypass(map, enable); map->unlock(map->lock_arg); } EXPORT_SYMBOL_GPL(regcache_cache_bypass); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index f99b098ddabf..dbfe6a69c3da 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1281,7 +1281,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, if (map->async && map->bus->async_write) { struct regmap_async *async; - trace_regmap_async_write_start(map->dev, reg, val_len); + trace_regmap_async_write_start(map, reg, val_len); spin_lock_irqsave(&map->async_lock, flags); async = list_first_entry_or_null(&map->async_free, @@ -1339,8 +1339,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, return ret; } - trace_regmap_hw_write_start(map->dev, reg, - val_len / map->format.val_bytes); + trace_regmap_hw_write_start(map, reg, val_len / map->format.val_bytes); /* If we're doing a single register write we can probably just * send the work_buf directly, otherwise try to do a gather @@ -1372,8 +1371,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, kfree(buf); } - trace_regmap_hw_write_done(map->dev, reg, - val_len / map->format.val_bytes); + trace_regmap_hw_write_done(map, reg, val_len / map->format.val_bytes); return ret; } @@ -1407,12 +1405,12 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, map->format.format_write(map, reg, val); - trace_regmap_hw_write_start(map->dev, reg, 1); + trace_regmap_hw_write_start(map, reg, 1); ret = map->bus->write(map->bus_context, map->work_buf, map->format.buf_size); - trace_regmap_hw_write_done(map->dev, reg, 1); + trace_regmap_hw_write_done(map, reg, 1); return ret; } @@ -1470,7 +1468,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, dev_info(map->dev, "%x <= %x\n", reg, val); #endif - trace_regmap_reg_write(map->dev, reg, val); + trace_regmap_reg_write(map, reg, val); return map->reg_write(context, reg, val); } @@ -1773,7 +1771,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map, for (i = 0; i < num_regs; i++) { int reg = regs[i].reg; int val = regs[i].def; - trace_regmap_hw_write_start(map->dev, reg, 1); + trace_regmap_hw_write_start(map, reg, 1); map->format.format_reg(u8, reg, map->reg_shift); u8 += reg_bytes + pad_bytes; map->format.format_val(u8, val, 0); @@ -1788,7 +1786,7 @@ static int _regmap_raw_multi_reg_write(struct regmap *map, for (i = 0; i < num_regs; i++) { int reg = regs[i].reg; - trace_regmap_hw_write_done(map->dev, reg, 1); + trace_regmap_hw_write_done(map, reg, 1); } return ret; } @@ -2059,15 +2057,13 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, */ u8[0] |= map->read_flag_mask; - trace_regmap_hw_read_start(map->dev, reg, - val_len / map->format.val_bytes); + trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes); ret = map->bus->read(map->bus_context, map->work_buf, map->format.reg_bytes + map->format.pad_bytes, val, val_len); - trace_regmap_hw_read_done(map->dev, reg, - val_len / map->format.val_bytes); + trace_regmap_hw_read_done(map, reg, val_len / map->format.val_bytes); return ret; } @@ -2123,7 +2119,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg, dev_info(map->dev, "%x => %x\n", reg, *val); #endif - trace_regmap_reg_read(map->dev, reg, *val); + trace_regmap_reg_read(map, reg, *val); if (!map->cache_bypass) regcache_write(map, reg, *val); @@ -2480,7 +2476,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) struct regmap *map = async->map; bool wake; - trace_regmap_async_io_complete(map->dev); + trace_regmap_async_io_complete(map); spin_lock(&map->async_lock); list_move(&async->list, &map->async_free); @@ -2525,7 +2521,7 @@ int regmap_async_complete(struct regmap *map) if (!map->bus || !map->bus->async_write) return 0; - trace_regmap_async_complete_start(map->dev); + trace_regmap_async_complete_start(map); wait_event(map->async_waitq, regmap_async_is_done(map)); @@ -2534,7 +2530,7 @@ int regmap_async_complete(struct regmap *map) map->async_ret = 0; spin_unlock_irqrestore(&map->async_lock, flags); - trace_regmap_async_complete_done(map->dev); + trace_regmap_async_complete_done(map); return ret; } diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h index 23d561512f64..22317d2b52ab 100644 --- a/include/trace/events/regmap.h +++ b/include/trace/events/regmap.h @@ -7,27 +7,26 @@ #include #include -struct device; -struct regmap; +#include "../../../drivers/base/regmap/internal.h" /* * Log register events */ DECLARE_EVENT_CLASS(regmap_reg, - TP_PROTO(struct device *dev, unsigned int reg, + TP_PROTO(struct regmap *map, unsigned int reg, unsigned int val), - TP_ARGS(dev, reg, val), + TP_ARGS(map, reg, val), TP_STRUCT__entry( - __string( name, dev_name(dev) ) - __field( unsigned int, reg ) - __field( unsigned int, val ) + __string( name, regmap_name(map) ) + __field( unsigned int, reg ) + __field( unsigned int, val ) ), TP_fast_assign( - __assign_str(name, dev_name(dev)); + __assign_str(name, regmap_name(map)); __entry->reg = reg; __entry->val = val; ), @@ -39,45 +38,45 @@ DECLARE_EVENT_CLASS(regmap_reg, DEFINE_EVENT(regmap_reg, regmap_reg_write, - TP_PROTO(struct device *dev, unsigned int reg, + TP_PROTO(struct regmap *map, unsigned int reg, unsigned int val), - TP_ARGS(dev, reg, val) + TP_ARGS(map, reg, val) ); DEFINE_EVENT(regmap_reg, regmap_reg_read, - TP_PROTO(struct device *dev, unsigned int reg, + TP_PROTO(struct regmap *map, unsigned int reg, unsigned int val), - TP_ARGS(dev, reg, val) + TP_ARGS(map, reg, val) ); DEFINE_EVENT(regmap_reg, regmap_reg_read_cache, - TP_PROTO(struct device *dev, unsigned int reg, + TP_PROTO(struct regmap *map, unsigned int reg, unsigned int val), - TP_ARGS(dev, reg, val) + TP_ARGS(map, reg, val) ); DECLARE_EVENT_CLASS(regmap_block, - TP_PROTO(struct device *dev, unsigned int reg, int count), + TP_PROTO(struct regmap *map, unsigned int reg, int count), - TP_ARGS(dev, reg, count), + TP_ARGS(map, reg, count), TP_STRUCT__entry( - __string( name, dev_name(dev) ) - __field( unsigned int, reg ) - __field( int, count ) + __string( name, regmap_name(map) ) + __field( unsigned int, reg ) + __field( int, count ) ), TP_fast_assign( - __assign_str(name, dev_name(dev)); + __assign_str(name, regmap_name(map)); __entry->reg = reg; __entry->count = count; ), @@ -89,48 +88,48 @@ DECLARE_EVENT_CLASS(regmap_block, DEFINE_EVENT(regmap_block, regmap_hw_read_start, - TP_PROTO(struct device *dev, unsigned int reg, int count), + TP_PROTO(struct regmap *map, unsigned int reg, int count), - TP_ARGS(dev, reg, count) + TP_ARGS(map, reg, count) ); DEFINE_EVENT(regmap_block, regmap_hw_read_done, - TP_PROTO(struct device *dev, unsigned int reg, int count), + TP_PROTO(struct regmap *map, unsigned int reg, int count), - TP_ARGS(dev, reg, count) + TP_ARGS(map, reg, count) ); DEFINE_EVENT(regmap_block, regmap_hw_write_start, - TP_PROTO(struct device *dev, unsigned int reg, int count), + TP_PROTO(struct regmap *map, unsigned int reg, int count), - TP_ARGS(dev, reg, count) + TP_ARGS(map, reg, count) ); DEFINE_EVENT(regmap_block, regmap_hw_write_done, - TP_PROTO(struct device *dev, unsigned int reg, int count), + TP_PROTO(struct regmap *map, unsigned int reg, int count), - TP_ARGS(dev, reg, count) + TP_ARGS(map, reg, count) ); TRACE_EVENT(regcache_sync, - TP_PROTO(struct device *dev, const char *type, + TP_PROTO(struct regmap *map, const char *type, const char *status), - TP_ARGS(dev, type, status), + TP_ARGS(map, type, status), TP_STRUCT__entry( - __string( name, dev_name(dev) ) - __string( status, status ) - __string( type, type ) - __field( int, type ) + __string( name, regmap_name(map) ) + __string( status, status ) + __string( type, type ) + __field( int, type ) ), TP_fast_assign( - __assign_str(name, dev_name(dev)); + __assign_str(name, regmap_name(map)); __assign_str(status, status); __assign_str(type, type); ), @@ -141,17 +140,17 @@ TRACE_EVENT(regcache_sync, DECLARE_EVENT_CLASS(regmap_bool, - TP_PROTO(struct device *dev, bool flag), + TP_PROTO(struct regmap *map, bool flag), - TP_ARGS(dev, flag), + TP_ARGS(map, flag), TP_STRUCT__entry( - __string( name, dev_name(dev) ) - __field( int, flag ) + __string( name, regmap_name(map) ) + __field( int, flag ) ), TP_fast_assign( - __assign_str(name, dev_name(dev)); + __assign_str(name, regmap_name(map)); __entry->flag = flag; ), @@ -161,32 +160,32 @@ DECLARE_EVENT_CLASS(regmap_bool, DEFINE_EVENT(regmap_bool, regmap_cache_only, - TP_PROTO(struct device *dev, bool flag), + TP_PROTO(struct regmap *map, bool flag), - TP_ARGS(dev, flag) + TP_ARGS(map, flag) ); DEFINE_EVENT(regmap_bool, regmap_cache_bypass, - TP_PROTO(struct device *dev, bool flag), + TP_PROTO(struct regmap *map, bool flag), - TP_ARGS(dev, flag) + TP_ARGS(map, flag) ); DECLARE_EVENT_CLASS(regmap_async, - TP_PROTO(struct device *dev), + TP_PROTO(struct regmap *map), - TP_ARGS(dev), + TP_ARGS(map), TP_STRUCT__entry( - __string( name, dev_name(dev) ) + __string( name, regmap_name(map) ) ), TP_fast_assign( - __assign_str(name, dev_name(dev)); + __assign_str(name, regmap_name(map)); ), TP_printk("%s", __get_str(name)) @@ -194,50 +193,50 @@ DECLARE_EVENT_CLASS(regmap_async, DEFINE_EVENT(regmap_block, regmap_async_write_start, - TP_PROTO(struct device *dev, unsigned int reg, int count), + TP_PROTO(struct regmap *map, unsigned int reg, int count), - TP_ARGS(dev, reg, count) + TP_ARGS(map, reg, count) ); DEFINE_EVENT(regmap_async, regmap_async_io_complete, - TP_PROTO(struct device *dev), + TP_PROTO(struct regmap *map), - TP_ARGS(dev) + TP_ARGS(map) ); DEFINE_EVENT(regmap_async, regmap_async_complete_start, - TP_PROTO(struct device *dev), + TP_PROTO(struct regmap *map), - TP_ARGS(dev) + TP_ARGS(map) ); DEFINE_EVENT(regmap_async, regmap_async_complete_done, - TP_PROTO(struct device *dev), + TP_PROTO(struct regmap *map), - TP_ARGS(dev) + TP_ARGS(map) ); TRACE_EVENT(regcache_drop_region, - TP_PROTO(struct device *dev, unsigned int from, + TP_PROTO(struct regmap *map, unsigned int from, unsigned int to), - TP_ARGS(dev, from, to), + TP_ARGS(map, from, to), TP_STRUCT__entry( - __string( name, dev_name(dev) ) - __field( unsigned int, from ) - __field( unsigned int, to ) + __string( name, regmap_name(map) ) + __field( unsigned int, from ) + __field( unsigned int, to ) ), TP_fast_assign( - __assign_str(name, dev_name(dev)); + __assign_str(name, regmap_name(map)); __entry->from = from; __entry->to = to; ), From 755563bc79c764c90b9f44db5e4fe6c556d3440c Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 19 Mar 2015 19:29:01 +1100 Subject: [PATCH 151/567] powerpc/powernv: Fixes for hypervisor doorbell handling Since we can now use hypervisor doorbells for host IPIs, this makes sure we clear the host IPI flag when taking a doorbell interrupt, and clears any pending doorbell IPI in pnv_smp_cpu_kill_self() (as we already do for IPIs sent via the XICS interrupt controller). Otherwise if there did happen to be a leftover pending doorbell interrupt for an offline CPU thread for any reason, it would prevent that thread from going into a power-saving mode; it would instead keep waking up because of the interrupt. Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/ppc-opcode.h | 3 +++ arch/powerpc/include/asm/reg.h | 3 +++ arch/powerpc/kernel/dbell.c | 2 ++ arch/powerpc/platforms/powernv/smp.c | 14 ++++++++++++-- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 03cd858a401c..4cbe23af400a 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -153,6 +153,7 @@ #define PPC_INST_MFSPR_PVR_MASK 0xfc1fffff #define PPC_INST_MFTMR 0x7c0002dc #define PPC_INST_MSGSND 0x7c00019c +#define PPC_INST_MSGCLR 0x7c0001dc #define PPC_INST_MSGSNDP 0x7c00011c #define PPC_INST_MTTMR 0x7c0003dc #define PPC_INST_NOP 0x60000000 @@ -309,6 +310,8 @@ ___PPC_RB(b) | __PPC_EH(eh)) #define PPC_MSGSND(b) stringify_in_c(.long PPC_INST_MSGSND | \ ___PPC_RB(b)) +#define PPC_MSGCLR(b) stringify_in_c(.long PPC_INST_MSGCLR | \ + ___PPC_RB(b)) #define PPC_MSGSNDP(b) stringify_in_c(.long PPC_INST_MSGSNDP | \ ___PPC_RB(b)) #define PPC_POPCNTB(a, s) stringify_in_c(.long PPC_INST_POPCNTB | \ diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 1c874fb533bb..af56b5c6c81a 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -608,13 +608,16 @@ #define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */ #define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */ #define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ +#define SRR1_WAKEMASK_P8 0x003c0000 /* reason for wakeup on POWER8 */ #define SRR1_WAKESYSERR 0x00300000 /* System error */ #define SRR1_WAKEEE 0x00200000 /* External interrupt */ #define SRR1_WAKEMT 0x00280000 /* mtctrl */ #define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ #define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ +#define SRR1_WAKEDBELL 0x00140000 /* Privileged doorbell on P8 */ #define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */ #define SRR1_WAKERESET 0x00100000 /* System reset */ +#define SRR1_WAKEHDBELL 0x000c0000 /* Hypervisor doorbell on P8 */ #define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask [46:47] */ #define SRR1_WS_DEEPEST 0x00030000 /* Some resources not maintained, * may not be recoverable */ diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index f4217819cc31..2128f3a96c32 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -17,6 +17,7 @@ #include #include +#include #ifdef CONFIG_SMP void doorbell_setup_this_cpu(void) @@ -41,6 +42,7 @@ void doorbell_exception(struct pt_regs *regs) may_hard_irq_enable(); + kvmppc_set_host_ipi(smp_processor_id(), 0); __this_cpu_inc(irq_stat.doorbell_irqs); smp_ipi_demux(); diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index fc34025ef822..38a45088f633 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "powernv.h" @@ -149,7 +151,7 @@ static int pnv_smp_cpu_disable(void) static void pnv_smp_cpu_kill_self(void) { unsigned int cpu; - unsigned long srr1; + unsigned long srr1, wmask; u32 idle_states; /* Standard hot unplug procedure */ @@ -161,6 +163,10 @@ static void pnv_smp_cpu_kill_self(void) generic_set_cpu_dead(cpu); smp_wmb(); + wmask = SRR1_WAKEMASK; + if (cpu_has_feature(CPU_FTR_ARCH_207S)) + wmask = SRR1_WAKEMASK_P8; + idle_states = pnv_get_supported_cpuidle_states(); /* We don't want to take decrementer interrupts while we are offline, * so clear LPCR:PECE1. We keep PECE2 enabled. @@ -191,10 +197,14 @@ static void pnv_smp_cpu_kill_self(void) * having finished executing in a KVM guest, then srr1 * contains 0. */ - if ((srr1 & SRR1_WAKEMASK) == SRR1_WAKEEE) { + if ((srr1 & wmask) == SRR1_WAKEEE) { icp_native_flush_interrupt(); local_paca->irq_happened &= PACA_IRQ_HARD_DIS; smp_mb(); + } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) { + unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); + asm volatile(PPC_MSGCLR(%0) : : "r" (msg)); + kvmppc_set_host_ipi(cpu, 0); } if (cpu_core_split_required()) From ddee09c099c35074e50aaf9157efd22429d3acdf Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 19 Mar 2015 14:12:06 +1100 Subject: [PATCH 152/567] powerpc: Add PVR for POWER8NVL processor There's a new variant of POWER8 coming called "POWER8 with NVLink". The core is identical to POWER8 but unfortunately they strapped it with a different PVR, so we need to add an explicit entry for it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/cputable.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index f337666768a7..f83046878336 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -437,6 +437,26 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, + { /* Power8NVL */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x004c0000, + .cpu_name = "POWER8NVL (raw)", + .cpu_features = CPU_FTRS_POWER8, + .cpu_user_features = COMMON_USER_POWER8, + .cpu_user_features2 = COMMON_USER2_POWER8, + .mmu_features = MMU_FTRS_POWER8, + .icache_bsize = 128, + .dcache_bsize = 128, + .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, + .oprofile_cpu_type = "ppc64/power8", + .oprofile_type = PPC_OPROFILE_INVALID, + .cpu_setup = __setup_cpu_power8, + .cpu_restore = __restore_cpu_power8, + .flush_tlb = __flush_tlb_power8, + .machine_check_early = __machine_check_early_realmode_p8, + .platform = "power8", + }, { /* Power8 DD1: Does not support doorbell IPIs */ .pvr_mask = 0xffffff00, .pvr_value = 0x004d0100, From f6ff04149637723261aa4738958b0098b929ee9e Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Wed, 4 Mar 2015 11:59:33 -0800 Subject: [PATCH 153/567] powerpc/pseries: Little endian fixes for post mobility device tree update We currently use the device tree update code in the kernel after resuming from a suspend operation to re-sync the kernels view of the device tree with that of the hypervisor. The code as it stands is not endian safe as it relies on parsing buffers returned by RTAS calls that thusly contains data in big endian format. This patch annotates variables and structure members with __be types as well as performing necessary byte swaps to cpu endian for data that needs to be parsed. Signed-off-by: Tyrel Datwyler Cc: Nathan Fontenot Cc: Cyril Bur Cc: stable@vger.kernel.org Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/mobility.c | 44 ++++++++++++----------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index 90cf3dcbd9f2..8f35d525cede 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -25,10 +25,10 @@ static struct kobject *mobility_kobj; struct update_props_workarea { - u32 phandle; - u32 state; - u64 reserved; - u32 nprops; + __be32 phandle; + __be32 state; + __be64 reserved; + __be32 nprops; } __packed; #define NODE_ACTION_MASK 0xff000000 @@ -54,11 +54,11 @@ static int mobility_rtas_call(int token, char *buf, s32 scope) return rc; } -static int delete_dt_node(u32 phandle) +static int delete_dt_node(__be32 phandle) { struct device_node *dn; - dn = of_find_node_by_phandle(phandle); + dn = of_find_node_by_phandle(be32_to_cpu(phandle)); if (!dn) return -ENOENT; @@ -127,7 +127,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop, return 0; } -static int update_dt_node(u32 phandle, s32 scope) +static int update_dt_node(__be32 phandle, s32 scope) { struct update_props_workarea *upwa; struct device_node *dn; @@ -136,6 +136,7 @@ static int update_dt_node(u32 phandle, s32 scope) char *prop_data; char *rtas_buf; int update_properties_token; + u32 nprops; u32 vd; update_properties_token = rtas_token("ibm,update-properties"); @@ -146,7 +147,7 @@ static int update_dt_node(u32 phandle, s32 scope) if (!rtas_buf) return -ENOMEM; - dn = of_find_node_by_phandle(phandle); + dn = of_find_node_by_phandle(be32_to_cpu(phandle)); if (!dn) { kfree(rtas_buf); return -ENOENT; @@ -162,6 +163,7 @@ static int update_dt_node(u32 phandle, s32 scope) break; prop_data = rtas_buf + sizeof(*upwa); + nprops = be32_to_cpu(upwa->nprops); /* On the first call to ibm,update-properties for a node the * the first property value descriptor contains an empty @@ -170,17 +172,17 @@ static int update_dt_node(u32 phandle, s32 scope) */ if (*prop_data == 0) { prop_data++; - vd = *(u32 *)prop_data; + vd = be32_to_cpu(*(__be32 *)prop_data); prop_data += vd + sizeof(vd); - upwa->nprops--; + nprops--; } - for (i = 0; i < upwa->nprops; i++) { + for (i = 0; i < nprops; i++) { char *prop_name; prop_name = prop_data; prop_data += strlen(prop_name) + 1; - vd = *(u32 *)prop_data; + vd = be32_to_cpu(*(__be32 *)prop_data); prop_data += sizeof(vd); switch (vd) { @@ -212,13 +214,13 @@ static int update_dt_node(u32 phandle, s32 scope) return 0; } -static int add_dt_node(u32 parent_phandle, u32 drc_index) +static int add_dt_node(__be32 parent_phandle, __be32 drc_index) { struct device_node *dn; struct device_node *parent_dn; int rc; - parent_dn = of_find_node_by_phandle(parent_phandle); + parent_dn = of_find_node_by_phandle(be32_to_cpu(parent_phandle)); if (!parent_dn) return -ENOENT; @@ -237,7 +239,7 @@ static int add_dt_node(u32 parent_phandle, u32 drc_index) int pseries_devicetree_update(s32 scope) { char *rtas_buf; - u32 *data; + __be32 *data; int update_nodes_token; int rc; @@ -254,17 +256,17 @@ int pseries_devicetree_update(s32 scope) if (rc && rc != 1) break; - data = (u32 *)rtas_buf + 4; - while (*data & NODE_ACTION_MASK) { + data = (__be32 *)rtas_buf + 4; + while (be32_to_cpu(*data) & NODE_ACTION_MASK) { int i; - u32 action = *data & NODE_ACTION_MASK; - int node_count = *data & NODE_COUNT_MASK; + u32 action = be32_to_cpu(*data) & NODE_ACTION_MASK; + u32 node_count = be32_to_cpu(*data) & NODE_COUNT_MASK; data++; for (i = 0; i < node_count; i++) { - u32 phandle = *data++; - u32 drc_index; + __be32 phandle = *data++; + __be32 drc_index; switch (action) { case DELETE_DT_NODE: From d3f193ee65388be5eb255db9b7a1d960f95b3a24 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:47 +0530 Subject: [PATCH 154/567] ath9k: Add initial structures for AIC These are necessary for implementing AIC, supported by chips like WB222. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.h | 49 +++++++++++++++++++++ drivers/net/wireless/ath/ath9k/btcoex.h | 11 +++++ 2 files changed, 60 insertions(+) create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_aic.h diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.h b/drivers/net/wireless/ath/ath9k/ar9003_aic.h new file mode 100644 index 000000000000..b81d5d157ee5 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef AR9003_AIC_H +#define AR9003_AIC_H + +#define ATH_AIC_MAX_COM_ATT_DB_TABLE 6 +#define ATH_AIC_MAX_AIC_LIN_TABLE 69 +#define ATH_AIC_MIN_ROT_DIR_ATT_DB 0 +#define ATH_AIC_MIN_ROT_QUAD_ATT_DB 0 +#define ATH_AIC_MAX_ROT_DIR_ATT_DB 37 +#define ATH_AIC_MAX_ROT_QUAD_ATT_DB 37 +#define ATH_AIC_SRAM_AUTO_INCREMENT 0x80000000 +#define ATH_AIC_SRAM_GAIN_TABLE_OFFSET 0x280 +#define ATH_AIC_SRAM_CAL_OFFSET 0x140 +#define ATH_AIC_SRAM_OFFSET 0x00 +#define ATH_AIC_MEAS_MAG_THRESH 20 +#define ATH_AIC_BT_JUPITER_CTRL 0x66820 +#define ATH_AIC_BT_AIC_ENABLE 0x02 + +struct ath_aic_sram_info { + bool valid:1; + bool vga_quad_sign:1; + bool vga_dir_sign:1; + u8 rot_quad_att_db; + u8 rot_dir_att_db; + u8 com_att_6db; +}; + +struct ath_aic_out_info { + int16_t dir_path_gain_lin; + int16_t quad_path_gain_lin; + struct ath_aic_sram_info sram; +}; + +#endif /* AR9003_AIC_H */ diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 5fe62ff2223b..b3ed738e1142 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -44,6 +44,9 @@ #define AR9300_NUM_BT_WEIGHTS 4 #define AR9300_NUM_WLAN_WEIGHTS 4 + +#define ATH_AIC_MAX_BT_CHANNEL 79 + /* Defines the BT AR_BT_COEX_WGHT used */ enum ath_stomp_type { ATH_BTCOEX_STOMP_ALL, @@ -93,6 +96,14 @@ struct ath9k_hw_mci { u32 last_recovery; }; +struct ath9k_hw_aic { + bool aic_enabled; + u8 aic_cal_state; + u8 aic_caled_chan; + u32 aic_sram[ATH_AIC_MAX_BT_CHANNEL]; + u32 aic_cal_start_time; +}; + struct ath_btcoex_hw { enum ath_btcoex_scheme scheme; struct ath9k_hw_mci mci; From 637625f2db844289058f9af7672a57c094cc97e2 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:48 +0530 Subject: [PATCH 155/567] ath9k: Register private AIC ops AIC can be disabled or enabled on a per-card basis using MCI configuration, so register a function to check its status. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/Makefile | 3 +- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 37 +++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9003_hw.c | 1 + drivers/net/wireless/ath/ath9k/hw-ops.h | 8 +++++ drivers/net/wireless/ath/ath9k/hw.h | 6 ++++ 5 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_aic.c diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 473972288a84..ecda613c2d54 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -46,7 +46,8 @@ ath9k_hw-y:= \ ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ - ar9003_mci.o + ar9003_mci.o \ + ar9003_aic.o ath9k_hw-$(CONFIG_ATH9K_PCOEM) += ar9003_rtt.o diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c new file mode 100644 index 000000000000..0cd159dfc77f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "hw.h" +#include "hw-ops.h" +#include "ar9003_mci.h" +#include "ar9003_aic.h" + +static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + + if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_AIC) + return false; + + return true; +} + +void ar9003_hw_attach_aic_ops(struct ath_hw *ah) +{ + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + + priv_ops->is_aic_enabled = ar9003_hw_is_aic_enabled; +} diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index df176e6a30d1..79fd3b2dcbde 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -1180,4 +1180,5 @@ void ar9003_hw_attach_ops(struct ath_hw *ah) ar9003_hw_attach_phy_ops(ah); ar9003_hw_attach_calib_ops(ah); ar9003_hw_attach_mac_ops(ah); + ar9003_hw_attach_aic_ops(ah); } diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 88769b64b20b..232339b05540 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -108,6 +108,14 @@ static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) ath9k_hw_ops(ah)->set_bt_ant_diversity(ah, enable); } +static inline bool ath9k_hw_is_aic_enabled(struct ath_hw *ah) +{ + if (ath9k_hw_private_ops(ah)->is_aic_enabled) + return ath9k_hw_private_ops(ah)->is_aic_enabled(ah); + + return false; +} + #endif /* Private hardware call ops */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 2067cb523ca8..c22edd3ce716 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -653,6 +653,10 @@ struct ath_hw_private_ops { /* ANI */ void (*ani_cache_ini_regs)(struct ath_hw *ah); + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + bool (*is_aic_enabled)(struct ath_hw *ah); +#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ }; /** @@ -1113,6 +1117,8 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah); int ar9002_hw_attach_ops(struct ath_hw *ah); void ar9003_hw_attach_ops(struct ath_hw *ah); +void ar9003_hw_attach_aic_ops(struct ath_hw *ah); + void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); From 6dacafea2d3a75d2db9b65a2aecebf385f39d3a3 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:49 +0530 Subject: [PATCH 156/567] ath9k: Add register definitions for AIC Various registers to control and check AIC status. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 1 + drivers/net/wireless/ath/ath9k/ar9003_phy.h | 25 --- drivers/net/wireless/ath/ath9k/reg_aic.h | 168 ++++++++++++++++++++ 3 files changed, 169 insertions(+), 25 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/reg_aic.h diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index 0cd159dfc77f..cc1e97b703f9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -18,6 +18,7 @@ #include "hw-ops.h" #include "ar9003_mci.h" #include "ar9003_aic.h" +#include "reg_aic.h" static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah) { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index c311b2bfdb00..fc595b92ac56 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -640,16 +640,6 @@ #define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE 0x0000ff00 #define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE_S 8 -/* AIC Registers */ -#define AR_PHY_AIC_CTRL_0_B0 (AR_SM_BASE + 0x4b0) -#define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4) -#define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8) -#define AR_PHY_AIC_CTRL_3_B0 (AR_SM_BASE + 0x4bc) -#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + 0x4c4)) -#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + 0x4c8)) -#define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0) -#define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc) - #define AR_PHY_65NM_CH0_TXRF3 0x16048 #define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G 0x0000001e #define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G_S 1 @@ -989,21 +979,6 @@ #define AR_PHY_TX_IQCAL_STATUS_B1 (AR_SM1_BASE + 0x48c) #define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i) (AR_SM1_BASE + 0x450 + ((_i) << 2)) -/* SM 1 AIC Registers */ - -#define AR_PHY_AIC_CTRL_0_B1 (AR_SM1_BASE + 0x4b0) -#define AR_PHY_AIC_CTRL_1_B1 (AR_SM1_BASE + 0x4b4) -#define AR_PHY_AIC_CTRL_2_B1 (AR_SM1_BASE + 0x4b8) -#define AR_PHY_AIC_STAT_0_B1 (AR_SM1_BASE + (AR_SREV_9462_10(ah) ? \ - 0x4c0 : 0x4c4)) -#define AR_PHY_AIC_STAT_1_B1 (AR_SM1_BASE + (AR_SREV_9462_10(ah) ? \ - 0x4c4 : 0x4c8)) -#define AR_PHY_AIC_CTRL_4_B1 (AR_SM1_BASE + 0x4c0) -#define AR_PHY_AIC_STAT_2_B1 (AR_SM1_BASE + 0x4cc) - -#define AR_PHY_AIC_SRAM_ADDR_B1 (AR_SM1_BASE + 0x5f0) -#define AR_PHY_AIC_SRAM_DATA_B1 (AR_SM1_BASE + 0x5f4) - #define AR_PHY_RTT_TABLE_SW_INTF_B(i) (0x384 + ((i) ? \ AR_SM1_BASE : AR_SM_BASE)) #define AR_PHY_RTT_TABLE_SW_INTF_1_B(i) (0x388 + ((i) ? \ diff --git a/drivers/net/wireless/ath/ath9k/reg_aic.h b/drivers/net/wireless/ath/ath9k/reg_aic.h new file mode 100644 index 000000000000..955147ab48a2 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/reg_aic.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef REG_AIC_H +#define REG_AIC_H + +#define AR_SM_BASE 0xa200 +#define AR_SM1_BASE 0xb200 +#define AR_AGC_BASE 0x9e00 + +#define AR_PHY_AIC_CTRL_0_B0 (AR_SM_BASE + 0x4b0) +#define AR_PHY_AIC_CTRL_1_B0 (AR_SM_BASE + 0x4b4) +#define AR_PHY_AIC_CTRL_2_B0 (AR_SM_BASE + 0x4b8) +#define AR_PHY_AIC_CTRL_3_B0 (AR_SM_BASE + 0x4bc) +#define AR_PHY_AIC_CTRL_4_B0 (AR_SM_BASE + 0x4c0) + +#define AR_PHY_AIC_STAT_0_B0 (AR_SM_BASE + 0x4c4) +#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + 0x4c8) +#define AR_PHY_AIC_STAT_2_B0 (AR_SM_BASE + 0x4cc) + +#define AR_PHY_AIC_CTRL_0_B1 (AR_SM1_BASE + 0x4b0) +#define AR_PHY_AIC_CTRL_1_B1 (AR_SM1_BASE + 0x4b4) +#define AR_PHY_AIC_CTRL_4_B1 (AR_SM1_BASE + 0x4c0) + +#define AR_PHY_AIC_STAT_0_B1 (AR_SM1_BASE + 0x4c4) +#define AR_PHY_AIC_STAT_1_B1 (AR_SM1_BASE + 0x4c8) +#define AR_PHY_AIC_STAT_2_B1 (AR_SM1_BASE + 0x4cc) + +#define AR_PHY_AIC_SRAM_ADDR_B0 (AR_SM_BASE + 0x5f0) +#define AR_PHY_AIC_SRAM_DATA_B0 (AR_SM_BASE + 0x5f4) + +#define AR_PHY_AIC_SRAM_ADDR_B1 (AR_SM1_BASE + 0x5f0) +#define AR_PHY_AIC_SRAM_DATA_B1 (AR_SM1_BASE + 0x5f4) + +#define AR_PHY_BT_COEX_4 (AR_AGC_BASE + 0x60) +#define AR_PHY_BT_COEX_5 (AR_AGC_BASE + 0x64) + +/* AIC fields */ +#define AR_PHY_AIC_MON_ENABLE 0x80000000 +#define AR_PHY_AIC_MON_ENABLE_S 31 +#define AR_PHY_AIC_CAL_MAX_HOP_COUNT 0x7F000000 +#define AR_PHY_AIC_CAL_MAX_HOP_COUNT_S 24 +#define AR_PHY_AIC_CAL_MIN_VALID_COUNT 0x00FE0000 +#define AR_PHY_AIC_CAL_MIN_VALID_COUNT_S 17 +#define AR_PHY_AIC_F_WLAN 0x0001FC00 +#define AR_PHY_AIC_F_WLAN_S 10 +#define AR_PHY_AIC_CAL_CH_VALID_RESET 0x00000200 +#define AR_PHY_AIC_CAL_CH_VALID_RESET_S 9 +#define AR_PHY_AIC_CAL_ENABLE 0x00000100 +#define AR_PHY_AIC_CAL_ENABLE_S 8 +#define AR_PHY_AIC_BTTX_PWR_THR 0x000000FE +#define AR_PHY_AIC_BTTX_PWR_THR_S 1 +#define AR_PHY_AIC_ENABLE 0x00000001 +#define AR_PHY_AIC_ENABLE_S 0 +#define AR_PHY_AIC_CAL_BT_REF_DELAY 0x00F00000 +#define AR_PHY_AIC_CAL_BT_REF_DELAY_S 20 +#define AR_PHY_AIC_BT_IDLE_CFG 0x00080000 +#define AR_PHY_AIC_BT_IDLE_CFG_S 19 +#define AR_PHY_AIC_STDBY_COND 0x00060000 +#define AR_PHY_AIC_STDBY_COND_S 17 +#define AR_PHY_AIC_STDBY_ROT_ATT_DB 0x0001F800 +#define AR_PHY_AIC_STDBY_ROT_ATT_DB_S 11 +#define AR_PHY_AIC_STDBY_COM_ATT_DB 0x00000700 +#define AR_PHY_AIC_STDBY_COM_ATT_DB_S 8 +#define AR_PHY_AIC_RSSI_MAX 0x000000F0 +#define AR_PHY_AIC_RSSI_MAX_S 4 +#define AR_PHY_AIC_RSSI_MIN 0x0000000F +#define AR_PHY_AIC_RSSI_MIN_S 0 +#define AR_PHY_AIC_RADIO_DELAY 0x7F000000 +#define AR_PHY_AIC_RADIO_DELAY_S 24 +#define AR_PHY_AIC_CAL_STEP_SIZE_CORR 0x00F00000 +#define AR_PHY_AIC_CAL_STEP_SIZE_CORR_S 20 +#define AR_PHY_AIC_CAL_ROT_IDX_CORR 0x000F8000 +#define AR_PHY_AIC_CAL_ROT_IDX_CORR_S 15 +#define AR_PHY_AIC_CAL_CONV_CHECK_FACTOR 0x00006000 +#define AR_PHY_AIC_CAL_CONV_CHECK_FACTOR_S 13 +#define AR_PHY_AIC_ROT_IDX_COUNT_MAX 0x00001C00 +#define AR_PHY_AIC_ROT_IDX_COUNT_MAX_S 10 +#define AR_PHY_AIC_CAL_SYNTH_TOGGLE 0x00000200 +#define AR_PHY_AIC_CAL_SYNTH_TOGGLE_S 9 +#define AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX 0x00000100 +#define AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX_S 8 +#define AR_PHY_AIC_CAL_SYNTH_SETTLING 0x000000FF +#define AR_PHY_AIC_CAL_SYNTH_SETTLING_S 0 +#define AR_PHY_AIC_MON_MAX_HOP_COUNT 0x07F00000 +#define AR_PHY_AIC_MON_MAX_HOP_COUNT_S 20 +#define AR_PHY_AIC_MON_MIN_STALE_COUNT 0x000FE000 +#define AR_PHY_AIC_MON_MIN_STALE_COUNT_S 13 +#define AR_PHY_AIC_MON_PWR_EST_LONG 0x00001000 +#define AR_PHY_AIC_MON_PWR_EST_LONG_S 12 +#define AR_PHY_AIC_MON_PD_TALLY_SCALING 0x00000C00 +#define AR_PHY_AIC_MON_PD_TALLY_SCALING_S 10 +#define AR_PHY_AIC_MON_PERF_THR 0x000003E0 +#define AR_PHY_AIC_MON_PERF_THR_S 5 +#define AR_PHY_AIC_CAL_TARGET_MAG_SETTING 0x00000018 +#define AR_PHY_AIC_CAL_TARGET_MAG_SETTING_S 3 +#define AR_PHY_AIC_CAL_PERF_CHECK_FACTOR 0x00000006 +#define AR_PHY_AIC_CAL_PERF_CHECK_FACTOR_S 1 +#define AR_PHY_AIC_CAL_PWR_EST_LONG 0x00000001 +#define AR_PHY_AIC_CAL_PWR_EST_LONG_S 0 +#define AR_PHY_AIC_MON_DONE 0x80000000 +#define AR_PHY_AIC_MON_DONE_S 31 +#define AR_PHY_AIC_MON_ACTIVE 0x40000000 +#define AR_PHY_AIC_MON_ACTIVE_S 30 +#define AR_PHY_AIC_MEAS_COUNT 0x3F000000 +#define AR_PHY_AIC_MEAS_COUNT_S 24 +#define AR_PHY_AIC_CAL_ANT_ISO_EST 0x00FC0000 +#define AR_PHY_AIC_CAL_ANT_ISO_EST_S 18 +#define AR_PHY_AIC_CAL_HOP_COUNT 0x0003F800 +#define AR_PHY_AIC_CAL_HOP_COUNT_S 11 +#define AR_PHY_AIC_CAL_VALID_COUNT 0x000007F0 +#define AR_PHY_AIC_CAL_VALID_COUNT_S 4 +#define AR_PHY_AIC_CAL_BT_TOO_WEAK_ERR 0x00000008 +#define AR_PHY_AIC_CAL_BT_TOO_WEAK_ERR_S 3 +#define AR_PHY_AIC_CAL_BT_TOO_STRONG_ERR 0x00000004 +#define AR_PHY_AIC_CAL_BT_TOO_STRONG_ERR_S 2 +#define AR_PHY_AIC_CAL_DONE 0x00000002 +#define AR_PHY_AIC_CAL_DONE_S 1 +#define AR_PHY_AIC_CAL_ACTIVE 0x00000001 +#define AR_PHY_AIC_CAL_ACTIVE_S 0 + +#define AR_PHY_AIC_MEAS_MAG_MIN 0xFFC00000 +#define AR_PHY_AIC_MEAS_MAG_MIN_S 22 +#define AR_PHY_AIC_MON_STALE_COUNT 0x003F8000 +#define AR_PHY_AIC_MON_STALE_COUNT_S 15 +#define AR_PHY_AIC_MON_HOP_COUNT 0x00007F00 +#define AR_PHY_AIC_MON_HOP_COUNT_S 8 +#define AR_PHY_AIC_CAL_AIC_SM 0x000000F8 +#define AR_PHY_AIC_CAL_AIC_SM_S 3 +#define AR_PHY_AIC_SM 0x00000007 +#define AR_PHY_AIC_SM_S 0 +#define AR_PHY_AIC_SRAM_VALID 0x00000001 +#define AR_PHY_AIC_SRAM_VALID_S 0 +#define AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB 0x0000007E +#define AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB_S 1 +#define AR_PHY_AIC_SRAM_VGA_QUAD_SIGN 0x00000080 +#define AR_PHY_AIC_SRAM_VGA_QUAD_SIGN_S 7 +#define AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB 0x00003F00 +#define AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB_S 8 +#define AR_PHY_AIC_SRAM_VGA_DIR_SIGN 0x00004000 +#define AR_PHY_AIC_SRAM_VGA_DIR_SIGN_S 14 +#define AR_PHY_AIC_SRAM_COM_ATT_6DB 0x00038000 +#define AR_PHY_AIC_SRAM_COM_ATT_6DB_S 15 +#define AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO 0x0000E000 +#define AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO_S 13 +#define AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO 0x00001E00 +#define AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO_S 9 +#define AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING 0x000001F8 +#define AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING_S 3 +#define AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF 0x00000006 +#define AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF_S 1 +#define AR_PHY_AIC_CAL_COM_ATT_DB_FIXED 0x00000001 +#define AR_PHY_AIC_CAL_COM_ATT_DB_FIXED_S 0 + +#endif /* REG_AIC_H */ From b6ab9ae2eed84eef622d56e00925c68e0c56239e Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:50 +0530 Subject: [PATCH 157/567] ath9k: Handle MCI_STATE_AIC_CAL_SINGLE This patch adds routines to handle the MCI message AIC_CAL_SINGLE, starting the required HW calibration. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 169 ++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9003_aic.h | 9 ++ drivers/net/wireless/ath/ath9k/ar9003_mci.c | 4 + drivers/net/wireless/ath/ath9k/btcoex.h | 1 + 4 files changed, 183 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index cc1e97b703f9..c2cfac3bb528 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -30,6 +30,175 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah) return true; } +static void ar9003_aic_gain_table(struct ath_hw *ah) +{ + u32 aic_atten_word[19], i; + + /* Config LNA gain difference */ + REG_WRITE(ah, AR_PHY_BT_COEX_4, 0x2c200a00); + REG_WRITE(ah, AR_PHY_BT_COEX_5, 0x5c4e4438); + + /* Program gain table */ + aic_atten_word[0] = (0x1 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0x1f & 0x1f); /* -01 dB: 4'd1, 5'd31, 00 dB: 4'd0, 5'd31 */ + aic_atten_word[1] = (0x3 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x1f & 0x1f); /* -03 dB: 4'd3, 5'd31, -02 dB: 4'd2, 5'd31 */ + aic_atten_word[2] = (0x5 & 0xf) << 14 | (0x1f & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x1f & 0x1f); /* -05 dB: 4'd5, 5'd31, -04 dB: 4'd4, 5'd31 */ + aic_atten_word[3] = (0x1 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0x1e & 0x1f); /* -07 dB: 4'd1, 5'd30, -06 dB: 4'd0, 5'd30 */ + aic_atten_word[4] = (0x3 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x1e & 0x1f); /* -09 dB: 4'd3, 5'd30, -08 dB: 4'd2, 5'd30 */ + aic_atten_word[5] = (0x5 & 0xf) << 14 | (0x1e & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x1e & 0x1f); /* -11 dB: 4'd5, 5'd30, -10 dB: 4'd4, 5'd30 */ + aic_atten_word[6] = (0x1 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0xf & 0x1f); /* -13 dB: 4'd1, 5'd15, -12 dB: 4'd0, 5'd15 */ + aic_atten_word[7] = (0x3 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0xf & 0x1f); /* -15 dB: 4'd3, 5'd15, -14 dB: 4'd2, 5'd15 */ + aic_atten_word[8] = (0x5 & 0xf) << 14 | (0xf & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0xf & 0x1f); /* -17 dB: 4'd5, 5'd15, -16 dB: 4'd4, 5'd15 */ + aic_atten_word[9] = (0x1 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0x7 & 0x1f); /* -19 dB: 4'd1, 5'd07, -18 dB: 4'd0, 5'd07 */ + aic_atten_word[10] = (0x3 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x7 & 0x1f); /* -21 dB: 4'd3, 5'd07, -20 dB: 4'd2, 5'd07 */ + aic_atten_word[11] = (0x5 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x7 & 0x1f); /* -23 dB: 4'd5, 5'd07, -22 dB: 4'd4, 5'd07 */ + aic_atten_word[12] = (0x7 & 0xf) << 14 | (0x7 & 0x1f) << 9 | (0x6 & 0xf) << 5 | + (0x7 & 0x1f); /* -25 dB: 4'd7, 5'd07, -24 dB: 4'd6, 5'd07 */ + aic_atten_word[13] = (0x3 & 0xf) << 14 | (0x3 & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x3 & 0x1f); /* -27 dB: 4'd3, 5'd03, -26 dB: 4'd2, 5'd03 */ + aic_atten_word[14] = (0x5 & 0xf) << 14 | (0x3 & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x3 & 0x1f); /* -29 dB: 4'd5, 5'd03, -28 dB: 4'd4, 5'd03 */ + aic_atten_word[15] = (0x1 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x0 & 0xf) << 5 | + (0x1 & 0x1f); /* -31 dB: 4'd1, 5'd01, -30 dB: 4'd0, 5'd01 */ + aic_atten_word[16] = (0x3 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x2 & 0xf) << 5 | + (0x1 & 0x1f); /* -33 dB: 4'd3, 5'd01, -32 dB: 4'd2, 5'd01 */ + aic_atten_word[17] = (0x5 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x4 & 0xf) << 5 | + (0x1 & 0x1f); /* -35 dB: 4'd5, 5'd01, -34 dB: 4'd4, 5'd01 */ + aic_atten_word[18] = (0x7 & 0xf) << 14 | (0x1 & 0x1f) << 9 | (0x6 & 0xf) << 5 | + (0x1 & 0x1f); /* -37 dB: 4'd7, 5'd01, -36 dB: 4'd6, 5'd01 */ + + /* Write to Gain table with auto increment enabled. */ + REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000), + (ATH_AIC_SRAM_AUTO_INCREMENT | + ATH_AIC_SRAM_GAIN_TABLE_OFFSET)); + + for (i = 0; i < 19; i++) { + REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000), + aic_atten_word[i]); + } +} + +static void ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + int i; + + /* Write to Gain table with auto increment enabled. */ + REG_WRITE(ah, (AR_PHY_AIC_SRAM_ADDR_B0 + 0x3000), + (ATH_AIC_SRAM_AUTO_INCREMENT | + ATH_AIC_SRAM_CAL_OFFSET)); + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + REG_WRITE(ah, (AR_PHY_AIC_SRAM_DATA_B0 + 0x3000), 0); + aic->aic_sram[i] = 0; + } + + REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B0, + (SM(0, AR_PHY_AIC_MON_ENABLE) | + SM(127, AR_PHY_AIC_CAL_MAX_HOP_COUNT) | + SM(min_valid_count, AR_PHY_AIC_CAL_MIN_VALID_COUNT) | + SM(37, AR_PHY_AIC_F_WLAN) | + SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) | + SM(0, AR_PHY_AIC_CAL_ENABLE) | + SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) | + SM(0, AR_PHY_AIC_ENABLE))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_0_B1, + (SM(0, AR_PHY_AIC_MON_ENABLE) | + SM(1, AR_PHY_AIC_CAL_CH_VALID_RESET) | + SM(0, AR_PHY_AIC_CAL_ENABLE) | + SM(0x40, AR_PHY_AIC_BTTX_PWR_THR) | + SM(0, AR_PHY_AIC_ENABLE))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B0, + (SM(8, AR_PHY_AIC_CAL_BT_REF_DELAY) | + SM(0, AR_PHY_AIC_BT_IDLE_CFG) | + SM(1, AR_PHY_AIC_STDBY_COND) | + SM(37, AR_PHY_AIC_STDBY_ROT_ATT_DB) | + SM(5, AR_PHY_AIC_STDBY_COM_ATT_DB) | + SM(15, AR_PHY_AIC_RSSI_MAX) | + SM(0, AR_PHY_AIC_RSSI_MIN))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_1_B1, + (SM(15, AR_PHY_AIC_RSSI_MAX) | + SM(0, AR_PHY_AIC_RSSI_MIN))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_2_B0, + (SM(44, AR_PHY_AIC_RADIO_DELAY) | + SM(8, AR_PHY_AIC_CAL_STEP_SIZE_CORR) | + SM(12, AR_PHY_AIC_CAL_ROT_IDX_CORR) | + SM(2, AR_PHY_AIC_CAL_CONV_CHECK_FACTOR) | + SM(5, AR_PHY_AIC_ROT_IDX_COUNT_MAX) | + SM(0, AR_PHY_AIC_CAL_SYNTH_TOGGLE) | + SM(0, AR_PHY_AIC_CAL_SYNTH_AFTER_BTRX) | + SM(200, AR_PHY_AIC_CAL_SYNTH_SETTLING))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_3_B0, + (SM(2, AR_PHY_AIC_MON_MAX_HOP_COUNT) | + SM(1, AR_PHY_AIC_MON_MIN_STALE_COUNT) | + SM(1, AR_PHY_AIC_MON_PWR_EST_LONG) | + SM(2, AR_PHY_AIC_MON_PD_TALLY_SCALING) | + SM(10, AR_PHY_AIC_MON_PERF_THR) | + SM(2, AR_PHY_AIC_CAL_TARGET_MAG_SETTING) | + SM(1, AR_PHY_AIC_CAL_PERF_CHECK_FACTOR) | + SM(1, AR_PHY_AIC_CAL_PWR_EST_LONG))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B0, + (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) | + SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) | + SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) | + SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) | + SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED))); + + REG_WRITE(ah, AR_PHY_AIC_CTRL_4_B1, + (SM(2, AR_PHY_AIC_CAL_ROT_ATT_DB_EST_ISO) | + SM(3, AR_PHY_AIC_CAL_COM_ATT_DB_EST_ISO) | + SM(0, AR_PHY_AIC_CAL_ISO_EST_INIT_SETTING) | + SM(2, AR_PHY_AIC_CAL_COM_ATT_DB_BACKOFF) | + SM(1, AR_PHY_AIC_CAL_COM_ATT_DB_FIXED))); + + ar9003_aic_gain_table(ah); + + /* Need to enable AIC reference signal in BT modem. */ + REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL, + (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) | + ATH_AIC_BT_AIC_ENABLE)); + + aic->aic_cal_start_time = REG_READ(ah, AR_TSF_L32); + + /* Start calibration */ + REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_CH_VALID_RESET); + REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); + + aic->aic_caled_chan = 0; + aic->aic_cal_state = AIC_CAL_STATE_STARTED; +} + +u8 ar9003_aic_calibration_single(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + u8 cal_ret = 0; + int num_chan; + + num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); + + ar9003_aic_cal_start(ah, num_chan); + + return cal_ret; +} + void ar9003_hw_attach_aic_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.h b/drivers/net/wireless/ath/ath9k/ar9003_aic.h index b81d5d157ee5..e31c44e68747 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.h @@ -31,6 +31,13 @@ #define ATH_AIC_BT_JUPITER_CTRL 0x66820 #define ATH_AIC_BT_AIC_ENABLE 0x02 +enum aic_cal_state { + AIC_CAL_STATE_IDLE = 0, + AIC_CAL_STATE_STARTED, + AIC_CAL_STATE_DONE, + AIC_CAL_STATE_ERROR +}; + struct ath_aic_sram_info { bool valid:1; bool vga_quad_sign:1; @@ -46,4 +53,6 @@ struct ath_aic_out_info { struct ath_aic_sram_info sram; }; +u8 ar9003_aic_calibration_single(struct ath_hw *ah); + #endif /* AR9003_AIC_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index bd169fae32a1..20bb5b990127 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -19,6 +19,7 @@ #include "hw-ops.h" #include "ar9003_phy.h" #include "ar9003_mci.h" +#include "ar9003_aic.h" static void ar9003_mci_reset_req_wakeup(struct ath_hw *ah) { @@ -1362,6 +1363,9 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; mci->need_flush_btinfo = false; break; + case MCI_STATE_AIC_CAL_SINGLE: + value = ar9003_aic_calibration_single(ah); + break; default: break; } diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index b3ed738e1142..cd2f0a2373cb 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -107,6 +107,7 @@ struct ath9k_hw_aic { struct ath_btcoex_hw { enum ath_btcoex_scheme scheme; struct ath9k_hw_mci mci; + struct ath9k_hw_aic aic; bool enabled; u8 wlanactive_gpio; u8 btactive_gpio; From 716eed4c0dfb6a7ceeb61730506e43f2755f322b Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:51 +0530 Subject: [PATCH 158/567] ath9k: Finish AIC calibration Set the appropriate bits in the HW after AIC calibration is done. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 78 ++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index c2cfac3bb528..00aaf4dd90e7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -186,15 +186,91 @@ static void ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count) aic->aic_cal_state = AIC_CAL_STATE_STARTED; } +static void ar9003_aic_cal_done(struct ath_hw *ah) +{ + /* Disable AIC reference signal in BT modem. */ + REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL, + (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) & + ~ATH_AIC_BT_AIC_ENABLE)); +} + +static u8 ar9003_aic_cal_continue(struct ath_hw *ah, bool cal_once) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + int i, num_chan; + + num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); + + if (!num_chan) { + aic->aic_cal_state = AIC_CAL_STATE_ERROR; + return aic->aic_cal_state; + } + + if (cal_once) { + for (i = 0; i < 10000; i++) { + if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) & + AR_PHY_AIC_CAL_ENABLE) == 0) + break; + + udelay(100); + } + } + + /* + * Use AR_PHY_AIC_CAL_ENABLE bit instead of AR_PHY_AIC_CAL_DONE. + * Sometimes CAL_DONE bit is not asserted. + */ + if ((REG_READ(ah, AR_PHY_AIC_CTRL_0_B1) & + AR_PHY_AIC_CAL_ENABLE) != 0) { + ath_dbg(common, MCI, "AIC cal is not done after 40ms"); + goto exit; + } + + REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1, + (ATH_AIC_SRAM_CAL_OFFSET | ATH_AIC_SRAM_AUTO_INCREMENT)); + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + u32 value; + + value = REG_READ(ah, AR_PHY_AIC_SRAM_DATA_B1); + + if (value & 0x01) { + if (aic->aic_sram[i] == 0) + aic->aic_caled_chan++; + + aic->aic_sram[i] = value; + + if (!cal_once) + break; + } + } + + if ((aic->aic_caled_chan >= num_chan) || cal_once) { + ar9003_aic_cal_done(ah); + } else { + /* Start calibration */ + REG_CLR_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); + REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, + AR_PHY_AIC_CAL_CH_VALID_RESET); + REG_SET_BIT(ah, AR_PHY_AIC_CTRL_0_B1, AR_PHY_AIC_CAL_ENABLE); + } +exit: + return aic->aic_cal_state; + +} + u8 ar9003_aic_calibration_single(struct ath_hw *ah) { struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; - u8 cal_ret = 0; + u8 cal_ret; int num_chan; num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); ar9003_aic_cal_start(ah, num_chan); + cal_ret = ar9003_aic_cal_continue(ah, true); return cal_ret; } From 188f1a1288d59ed9ae895bdbf22d46017a8a69b8 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:52 +0530 Subject: [PATCH 159/567] ath9k: Process the AIC calibration results This patch adds support for post-processing the AIC calibration results. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 245 ++++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index 00aaf4dd90e7..51ecc9b2df8c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -20,6 +20,22 @@ #include "ar9003_aic.h" #include "reg_aic.h" +static const u8 com_att_db_table[ATH_AIC_MAX_COM_ATT_DB_TABLE] = { + 0, 3, 9, 15, 21, 27 +}; + +static const u16 aic_lin_table[ATH_AIC_MAX_AIC_LIN_TABLE] = { + 8191, 7300, 6506, 5799, 5168, 4606, 4105, 3659, + 3261, 2906, 2590, 2309, 2057, 1834, 1634, 1457, + 1298, 1157, 1031, 919, 819, 730, 651, 580, + 517, 461, 411, 366, 326, 291, 259, 231, + 206, 183, 163, 146, 130, 116, 103, 92, + 82, 73, 65, 58, 52, 46, 41, 37, + 33, 29, 26, 23, 21, 18, 16, 15, + 13, 12, 10, 9, 8, 7, 7, 6, + 5, 5, 4, 4, 3 +}; + static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah) { struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; @@ -30,6 +46,56 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah) return true; } +static int16_t ar9003_aic_find_valid(struct ath_aic_sram_info *cal_sram, + bool dir, u8 index) +{ + int16_t i; + + if (dir) { + for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + if (cal_sram[i].valid) + break; + } + } else { + for (i = index - 1; i >= 0; i--) { + if (cal_sram[i].valid) + break; + } + } + + if ((i >= ATH_AIC_MAX_BT_CHANNEL) || (i < 0)) + i = -1; + + return i; +} + +/* + * type 0: aic_lin_table, 1: com_att_db_table + */ +static int16_t ar9003_aic_find_index(u8 type, int16_t value) +{ + int16_t i = -1; + + if (type == 0) { + for (i = ATH_AIC_MAX_AIC_LIN_TABLE - 1; i >= 0; i--) { + if (aic_lin_table[i] >= value) + break; + } + } else if (type == 1) { + for (i = 0; i < ATH_AIC_MAX_COM_ATT_DB_TABLE; i++) { + if (com_att_db_table[i] > value) { + i--; + break; + } + } + + if (i >= ATH_AIC_MAX_COM_ATT_DB_TABLE) + i = -1; + } + + return i; +} + static void ar9003_aic_gain_table(struct ath_hw *ah) { u32 aic_atten_word[19], i; @@ -186,12 +252,191 @@ static void ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count) aic->aic_cal_state = AIC_CAL_STATE_STARTED; } +static bool ar9003_aic_cal_post_process(struct ath_hw *ah) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + struct ath_aic_sram_info cal_sram[ATH_AIC_MAX_BT_CHANNEL]; + struct ath_aic_out_info aic_sram[ATH_AIC_MAX_BT_CHANNEL]; + u32 dir_path_gain_idx, quad_path_gain_idx, value; + u32 fixed_com_att_db; + int8_t dir_path_sign, quad_path_sign; + int16_t i; + bool ret = true; + + memset(&cal_sram, 0, sizeof(cal_sram)); + memset(&aic_sram, 0, sizeof(aic_sram)); + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + value = aic->aic_sram[i]; + + cal_sram[i].valid = + MS(value, AR_PHY_AIC_SRAM_VALID); + cal_sram[i].rot_quad_att_db = + MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB); + cal_sram[i].vga_quad_sign = + MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN); + cal_sram[i].rot_dir_att_db = + MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB); + cal_sram[i].vga_dir_sign = + MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN); + cal_sram[i].com_att_6db = + MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB); + + if (cal_sram[i].valid) { + dir_path_gain_idx = cal_sram[i].rot_dir_att_db + + com_att_db_table[cal_sram[i].com_att_6db]; + quad_path_gain_idx = cal_sram[i].rot_quad_att_db + + com_att_db_table[cal_sram[i].com_att_6db]; + + dir_path_sign = (cal_sram[i].vga_dir_sign) ? 1 : -1; + quad_path_sign = (cal_sram[i].vga_quad_sign) ? 1 : -1; + + aic_sram[i].dir_path_gain_lin = dir_path_sign * + aic_lin_table[dir_path_gain_idx]; + aic_sram[i].quad_path_gain_lin = quad_path_sign * + aic_lin_table[quad_path_gain_idx]; + } + } + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + int16_t start_idx, end_idx; + + if (cal_sram[i].valid) + continue; + + start_idx = ar9003_aic_find_valid(cal_sram, 0, i); + end_idx = ar9003_aic_find_valid(cal_sram, 1, i); + + if (start_idx < 0) { + /* extrapolation */ + start_idx = end_idx; + end_idx = ar9003_aic_find_valid(cal_sram, 1, start_idx); + + if (end_idx < 0) { + ret = false; + break; + } + + aic_sram[i].dir_path_gain_lin = + ((aic_sram[start_idx].dir_path_gain_lin - + aic_sram[end_idx].dir_path_gain_lin) * + (start_idx - i) + ((end_idx - i) >> 1)) / + (end_idx - i) + + aic_sram[start_idx].dir_path_gain_lin; + aic_sram[i].quad_path_gain_lin = + ((aic_sram[start_idx].quad_path_gain_lin - + aic_sram[end_idx].quad_path_gain_lin) * + (start_idx - i) + ((end_idx - i) >> 1)) / + (end_idx - i) + + aic_sram[start_idx].quad_path_gain_lin; + } + + if (end_idx < 0) { + /* extrapolation */ + end_idx = ar9003_aic_find_valid(cal_sram, 0, start_idx); + + if (end_idx < 0) { + ret = false; + break; + } + + aic_sram[i].dir_path_gain_lin = + ((aic_sram[start_idx].dir_path_gain_lin - + aic_sram[end_idx].dir_path_gain_lin) * + (i - start_idx) + ((start_idx - end_idx) >> 1)) / + (start_idx - end_idx) + + aic_sram[start_idx].dir_path_gain_lin; + aic_sram[i].quad_path_gain_lin = + ((aic_sram[start_idx].quad_path_gain_lin - + aic_sram[end_idx].quad_path_gain_lin) * + (i - start_idx) + ((start_idx - end_idx) >> 1)) / + (start_idx - end_idx) + + aic_sram[start_idx].quad_path_gain_lin; + + } else if (start_idx >= 0){ + /* interpolation */ + aic_sram[i].dir_path_gain_lin = + (((end_idx - i) * aic_sram[start_idx].dir_path_gain_lin) + + ((i - start_idx) * aic_sram[end_idx].dir_path_gain_lin) + + ((end_idx - start_idx) >> 1)) / + (end_idx - start_idx); + aic_sram[i].quad_path_gain_lin = + (((end_idx - i) * aic_sram[start_idx].quad_path_gain_lin) + + ((i - start_idx) * aic_sram[end_idx].quad_path_gain_lin) + + ((end_idx - start_idx) >> 1))/ + (end_idx - start_idx); + } + } + + /* From dir/quad_path_gain_lin to sram. */ + i = ar9003_aic_find_valid(cal_sram, 1, 0); + if (i < 0) { + i = 0; + ret = false; + } + fixed_com_att_db = com_att_db_table[cal_sram[i].com_att_6db]; + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + int16_t rot_dir_path_att_db, rot_quad_path_att_db; + + aic_sram[i].sram.vga_dir_sign = + (aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0; + aic_sram[i].sram.vga_quad_sign= + (aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0; + + rot_dir_path_att_db = + ar9003_aic_find_index(0, abs(aic_sram[i].dir_path_gain_lin)) - + fixed_com_att_db; + rot_quad_path_att_db = + ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) - + fixed_com_att_db; + + aic_sram[i].sram.com_att_6db = + ar9003_aic_find_index(1, fixed_com_att_db); + + aic_sram[i].sram.valid = 1; + + aic_sram[i].sram.rot_dir_att_db = + min(max(rot_dir_path_att_db, + (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB), + ATH_AIC_MAX_ROT_DIR_ATT_DB); + aic_sram[i].sram.rot_quad_att_db = + min(max(rot_quad_path_att_db, + (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB), + ATH_AIC_MAX_ROT_QUAD_ATT_DB); + } + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + aic->aic_sram[i] = (SM(aic_sram[i].sram.vga_dir_sign, + AR_PHY_AIC_SRAM_VGA_DIR_SIGN) | + SM(aic_sram[i].sram.vga_quad_sign, + AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) | + SM(aic_sram[i].sram.com_att_6db, + AR_PHY_AIC_SRAM_COM_ATT_6DB) | + SM(aic_sram[i].sram.valid, + AR_PHY_AIC_SRAM_VALID) | + SM(aic_sram[i].sram.rot_dir_att_db, + AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) | + SM(aic_sram[i].sram.rot_quad_att_db, + AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB)); + } + + return ret; +} + static void ar9003_aic_cal_done(struct ath_hw *ah) { + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + /* Disable AIC reference signal in BT modem. */ REG_WRITE(ah, ATH_AIC_BT_JUPITER_CTRL, (REG_READ(ah, ATH_AIC_BT_JUPITER_CTRL) & ~ATH_AIC_BT_AIC_ENABLE)); + + if (ar9003_aic_cal_post_process(ah)) + aic->aic_cal_state = AIC_CAL_STATE_DONE; + else + aic->aic_cal_state = AIC_CAL_STATE_ERROR; } static u8 ar9003_aic_cal_continue(struct ath_hw *ah, bool cal_once) From 208837eeb925e5fddc514e4f93a69b1639fa15ba Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:53 +0530 Subject: [PATCH 160/567] ath9k: Disable AIC by default Since various MCI messages need to be handled, along with driver-level support in upper layers, disable AIC for now. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 6 ++++++ drivers/net/wireless/ath/ath9k/ar9003_mci.c | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index 51ecc9b2df8c..7bdbc7a7d7ad 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -40,6 +40,12 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah) { struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; + /* + * Disable AIC for now, until we have all the + * HW code and the driver-layer support ready. + */ + return false; + if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_AIC) return false; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 20bb5b990127..6fa98e51fdfc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1364,7 +1364,8 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) mci->need_flush_btinfo = false; break; case MCI_STATE_AIC_CAL_SINGLE: - value = ar9003_aic_calibration_single(ah); + if (ath9k_hw_is_aic_enabled(ah)) + value = ar9003_aic_calibration_single(ah); break; default: break; From 958b6827b781ed14d12bef6323f6692ec761fbb5 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:54 +0530 Subject: [PATCH 161/567] ath9k: Handle MCI_STATE_AIC_CAL_RESET Add a routine to handle the MCI_STATE_AIC_CAL_RESET message. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 8 ++++++++ drivers/net/wireless/ath/ath9k/ar9003_aic.h | 1 + drivers/net/wireless/ath/ath9k/ar9003_mci.c | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index 7bdbc7a7d7ad..4e8cf084d2fa 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -512,6 +512,14 @@ exit: } +u8 ar9003_aic_cal_reset(struct ath_hw *ah) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + + aic->aic_cal_state = AIC_CAL_STATE_IDLE; + return aic->aic_cal_state; +} + u8 ar9003_aic_calibration_single(struct ath_hw *ah) { struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.h b/drivers/net/wireless/ath/ath9k/ar9003_aic.h index e31c44e68747..f7c95466149f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.h @@ -53,6 +53,7 @@ struct ath_aic_out_info { struct ath_aic_sram_info sram; }; +u8 ar9003_aic_cal_reset(struct ath_hw *ah); u8 ar9003_aic_calibration_single(struct ath_hw *ah); #endif /* AR9003_AIC_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 6fa98e51fdfc..d6ed62807a97 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1363,6 +1363,10 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; mci->need_flush_btinfo = false; break; + case MCI_STATE_AIC_CAL_RESET: + if (ath9k_hw_is_aic_enabled(ah)) + value = ar9003_aic_cal_reset(ah); + break; case MCI_STATE_AIC_CAL_SINGLE: if (ath9k_hw_is_aic_enabled(ah)) value = ar9003_aic_calibration_single(ah); From f2ef792a80859ecdabeaf5bf960ad97a9dd81fc6 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:55 +0530 Subject: [PATCH 162/567] ath9k: Handle MCI_STATE_AIC_START This patch adds a function to handle the MCI message MCI_STATE_AIC_START. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 33 +++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9003_aic.h | 1 + drivers/net/wireless/ath/ath9k/ar9003_mci.c | 4 +++ 3 files changed, 38 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index 4e8cf084d2fa..5b4f818264f5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -18,6 +18,7 @@ #include "hw-ops.h" #include "ar9003_mci.h" #include "ar9003_aic.h" +#include "ar9003_phy.h" #include "reg_aic.h" static const u8 com_att_db_table[ATH_AIC_MAX_COM_ATT_DB_TABLE] = { @@ -512,6 +513,38 @@ exit: } +u8 ar9003_aic_start_normal(struct ath_hw *ah) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + int16_t i; + + if (aic->aic_cal_state != AIC_CAL_STATE_DONE) + return 1; + + ar9003_aic_gain_table(ah); + + REG_WRITE(ah, AR_PHY_AIC_SRAM_ADDR_B1, ATH_AIC_SRAM_AUTO_INCREMENT); + + for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) { + REG_WRITE(ah, AR_PHY_AIC_SRAM_DATA_B1, aic->aic_sram[i]); + } + + /* FIXME: Replace these with proper register names */ + REG_WRITE(ah, 0xa6b0, 0x80); + REG_WRITE(ah, 0xa6b4, 0x5b2df0); + REG_WRITE(ah, 0xa6b8, 0x10762cc8); + REG_WRITE(ah, 0xa6bc, 0x1219a4b); + REG_WRITE(ah, 0xa6c0, 0x1e01); + REG_WRITE(ah, 0xb6b4, 0xf0); + REG_WRITE(ah, 0xb6c0, 0x1e01); + REG_WRITE(ah, 0xb6b0, 0x81); + REG_WRITE(ah, AR_PHY_65NM_CH1_RXTX4, 0x40000000); + + aic->aic_enabled = true; + + return 0; +} + u8 ar9003_aic_cal_reset(struct ath_hw *ah) { struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.h b/drivers/net/wireless/ath/ath9k/ar9003_aic.h index f7c95466149f..4dbff96b49cd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.h @@ -53,6 +53,7 @@ struct ath_aic_out_info { struct ath_aic_sram_info sram; }; +u8 ar9003_aic_start_normal(struct ath_hw *ah); u8 ar9003_aic_cal_reset(struct ath_hw *ah); u8 ar9003_aic_calibration_single(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index d6ed62807a97..b559d75b748b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1363,6 +1363,10 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; mci->need_flush_btinfo = false; break; + case MCI_STATE_AIC_START: + if (ath9k_hw_is_aic_enabled(ah)) + ar9003_aic_start_normal(ah); + break; case MCI_STATE_AIC_CAL_RESET: if (ath9k_hw_is_aic_enabled(ah)) value = ar9003_aic_cal_reset(ah); From 60544603b669a25adb90bd6e2ea6fa625e380322 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:56 +0530 Subject: [PATCH 163/567] ath9k: Handle MCI_STATE_AIC_CAL Add the main AIC calibration function to handle MCI_STATE_AIC_CAL. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_aic.c | 28 +++++++++++++++++++-- drivers/net/wireless/ath/ath9k/ar9003_aic.h | 1 + drivers/net/wireless/ath/ath9k/ar9003_mci.c | 4 +++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index 5b4f818264f5..1db119d77783 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -162,7 +162,7 @@ static void ar9003_aic_gain_table(struct ath_hw *ah) } } -static void ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count) +static u8 ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count) { struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; int i; @@ -257,6 +257,8 @@ static void ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count) aic->aic_caled_chan = 0; aic->aic_cal_state = AIC_CAL_STATE_STARTED; + + return aic->aic_cal_state; } static bool ar9003_aic_cal_post_process(struct ath_hw *ah) @@ -513,6 +515,28 @@ exit: } +u8 ar9003_aic_calibration(struct ath_hw *ah) +{ + struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; + u8 cal_ret = AIC_CAL_STATE_ERROR; + + switch (aic->aic_cal_state) { + case AIC_CAL_STATE_IDLE: + cal_ret = ar9003_aic_cal_start(ah, 1); + break; + case AIC_CAL_STATE_STARTED: + cal_ret = ar9003_aic_cal_continue(ah, false); + break; + case AIC_CAL_STATE_DONE: + cal_ret = AIC_CAL_STATE_DONE; + break; + default: + break; + } + + return cal_ret; +} + u8 ar9003_aic_start_normal(struct ath_hw *ah) { struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic; @@ -561,7 +585,7 @@ u8 ar9003_aic_calibration_single(struct ath_hw *ah) num_chan = MS(mci_hw->config, ATH_MCI_CONFIG_AIC_CAL_NUM_CHAN); - ar9003_aic_cal_start(ah, num_chan); + (void) ar9003_aic_cal_start(ah, num_chan); cal_ret = ar9003_aic_cal_continue(ah, true); return cal_ret; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.h b/drivers/net/wireless/ath/ath9k/ar9003_aic.h index 4dbff96b49cd..86f40644be43 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.h @@ -53,6 +53,7 @@ struct ath_aic_out_info { struct ath_aic_sram_info sram; }; +u8 ar9003_aic_calibration(struct ath_hw *ah); u8 ar9003_aic_start_normal(struct ath_hw *ah); u8 ar9003_aic_cal_reset(struct ath_hw *ah); u8 ar9003_aic_calibration_single(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index b559d75b748b..cdd83d4038a3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1363,6 +1363,10 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; mci->need_flush_btinfo = false; break; + case MCI_STATE_AIC_CAL: + if (ath9k_hw_is_aic_enabled(ah)) + value = ar9003_aic_calibration(ah); + break; case MCI_STATE_AIC_START: if (ath9k_hw_is_aic_enabled(ah)) ar9003_aic_start_normal(ah); From 7644317bd39c147c888b5d4cea3e2706d12483dd Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Sat, 14 Mar 2015 11:27:57 +0530 Subject: [PATCH 164/567] ath9k: Start AIC calibration during MCI reset When a MCI reset is done, make sure that AIC is started. Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_mci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index cdd83d4038a3..af5ee416a560 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1017,6 +1017,9 @@ int ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, if (en_int) ar9003_mci_enable_interrupt(ah); + if (ath9k_hw_is_aic_enabled(ah)) + ar9003_aic_start_normal(ah); + return 0; } From 0aef188a361b85d6804ed5fdfc69dde0f5074f59 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Sat, 14 Mar 2015 12:07:17 -0400 Subject: [PATCH 165/567] rtl8188ee: fix build break due to missing rtl_hal_pwrseqcmdparsing definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I've been getting this error when building mainline kernels using Fedora's config files: drivers/net/wireless/rtlwifi/rtl8188ee/hw.c: In function ‘_rtl88ee_init_mac’: drivers/net/wireless/rtlwifi/rtl8188ee/hw.c:853:2: error: implicit declaration of function ‘rtl_hal_pwrseqcmdparsing’ [-Werror=implicit-function-declaration] if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, ^ cc1: some warnings being treated as errors scripts/Makefile.build:258: recipe for target 'drivers/net/wireless/rtlwifi/rtl8188ee/hw.o' failed I'm not sure if this is the correct fix, but it does seem to allow the build to complete. I suspect that this was broken by commit 34ed780a6afc (rtlwifi: Fix problems with building an allyesconfig). Most of the files that removed the include of pwrseqcmd.h, added one for ../pwrseqcmd.h. The rtl8188ee driver had it removed it but didn't add the include of the file in the parent directory. Signed-off-by: Jeff Layton Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c index edc2cbb6253c..bb9f5382da17 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c @@ -30,6 +30,7 @@ #include "../cam.h" #include "../ps.h" #include "../pci.h" +#include "../pwrseqcmd.h" #include "reg.h" #include "def.h" #include "phy.h" From 8fbb2e98fef043019b9d546300406b2f6e9d38f5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 15 Mar 2015 14:26:20 +0100 Subject: [PATCH 166/567] cw1200: Fix suspend The cw1200 driver implements suspend and resume callbacks and assigns them to the suspend and resume fields of the device_driver struct. These callbacks are never actually called by anything though. Modify the driver to properly use dev_pm_ops so that the suspend function is actually executed upon suspend and drop the empty resume function. Signed-off-by: Lars-Peter Clausen Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/cw1200_spi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c index 964b64ab7fe3..7603546d2de3 100644 --- a/drivers/net/wireless/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/cw1200/cw1200_spi.c @@ -447,7 +447,7 @@ static int cw1200_spi_disconnect(struct spi_device *func) } #ifdef CONFIG_PM -static int cw1200_spi_suspend(struct device *dev, pm_message_t state) +static int cw1200_spi_suspend(struct device *dev) { struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev)); @@ -458,10 +458,8 @@ static int cw1200_spi_suspend(struct device *dev, pm_message_t state) return 0; } -static int cw1200_spi_resume(struct device *dev) -{ - return 0; -} +static SIMPLE_DEV_PM_OPS(cw1200_pm_ops, cw1200_spi_suspend, NULL); + #endif static struct spi_driver spi_driver = { @@ -472,8 +470,7 @@ static struct spi_driver spi_driver = { .bus = &spi_bus_type, .owner = THIS_MODULE, #ifdef CONFIG_PM - .suspend = cw1200_spi_suspend, - .resume = cw1200_spi_resume, + .pm = &cw1200_pm_ops, #endif }, }; From 148416a973e0a07fa94a0de90dae92763b282311 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Mar 2015 16:00:16 +0200 Subject: [PATCH 167/567] wil6210: optimize index manipulation in wil_vring_reap_rx Use temporal variable for often used vring->swhead; and use proper index in debug printing - vring->swhead used before was modified in wil_vring_advance_head and then increased value was used in debug print Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 689081c2c37b..3feb86c47795 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -369,6 +369,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, u16 dmalen; u8 ftype; int cid; + int i = (int)vring->swhead; struct wil_net_stats *stats; BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb)); @@ -376,24 +377,28 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, if (unlikely(wil_vring_is_empty(vring))) return NULL; - _d = &vring->va[vring->swhead].rx; + _d = &vring->va[i].rx; if (unlikely(!(_d->dma.status & RX_DMA_STATUS_DU))) { /* it is not error, we just reached end of Rx done area */ return NULL; } - skb = vring->ctx[vring->swhead].skb; + skb = vring->ctx[i].skb; + vring->ctx[i].skb = NULL; + wil_vring_advance_head(vring, 1); + if (!skb) { + wil_err(wil, "No Rx skb at [%d]\n", i); + return NULL; + } d = wil_skb_rxdesc(skb); *d = *_d; pa = wil_desc_addr(&d->dma.addr); - vring->ctx[vring->swhead].skb = NULL; - wil_vring_advance_head(vring, 1); dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); dmalen = le16_to_cpu(d->dma.length); - trace_wil6210_rx(vring->swhead, d); - wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, dmalen); + trace_wil6210_rx(i, d); + wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", i, dmalen); wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, (const void *)d, sizeof(*d), false); From cec94d8cf5c2e5347ed9264cc94210e6376c7a46 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Mar 2015 16:00:17 +0200 Subject: [PATCH 168/567] wil6210: fix check for FW responsiveness "echo" used to be called when no firmware loaded to the NIC, this causes error output. Probe firmware with "echo" only after it returned "ready" event. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 2 ++ drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index afff8d33c562..a5fd605e52eb 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -724,6 +724,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* we just started MAC, wait for FW ready */ rc = wil_wait_for_fw_ready(wil); + if (rc == 0) /* check FW is responsive */ + rc = wmi_echo(wil); } return rc; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 25343cffe229..109986114abf 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -246,8 +246,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil6210_debugfs_init(wil); - /* check FW is alive */ - wmi_echo(wil); return 0; From c406ea7c7406f00aa1fb6c697d47d070fd222037 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Mar 2015 16:00:19 +0200 Subject: [PATCH 169/567] wil6210: Align Rx frames on 4*n+2 by having SNAP For the networking code and for hardware network accelerators, it is better to have IP header 4*n aligned. On the other side, DMA on Rx path require buffer to be aligned on 4*n as well. Having 14 bytes of Ethernet header, these 2 alignment requests are in contradiction. To solve this, order hardware offload block to not remove SNAP header. This adds extra 6 bytes between addresses and ethertype, making it 20 bytes total. This way, both buffer and IP header are 4*n aligned. Remaining is only to remove SNAP by shifting addresses 6 bytes. This involves data copying, so this feature should be disabled unless required by the platform. Module parameter "rx_align_2" (bool, default - false) introduced to control this feature. Feature is completely disabled when parameter is false. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 27 +++++++++++++++++++--- drivers/net/wireless/ath/wil6210/wil6210.h | 1 + drivers/net/wireless/ath/wil6210/wmi.c | 5 ++++ drivers/net/wireless/ath/wil6210/wmi.h | 3 +++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 3feb86c47795..2453470bc191 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -33,6 +33,15 @@ module_param(rtap_include_phy_info, bool, S_IRUGO); MODULE_PARM_DESC(rtap_include_phy_info, " Include PHY info in the radiotap header, default - no"); +bool rx_align_2; +module_param(rx_align_2, bool, S_IRUGO); +MODULE_PARM_DESC(rx_align_2, " align Rx buffers on 4*n+2, default - no"); + +static inline uint wil_rx_snaplen(void) +{ + return rx_align_2 ? 6 : 0; +} + static inline int wil_vring_is_empty(struct vring *vring) { return vring->swhead == vring->swtail; @@ -209,7 +218,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, u32 i, int headroom) { struct device *dev = wil_to_dev(wil); - unsigned int sz = mtu_max + ETH_HLEN; + unsigned int sz = mtu_max + ETH_HLEN + wil_rx_snaplen(); struct vring_rx_desc dd, *d = ⅆ volatile struct vring_rx_desc *_d = &vring->va[i].rx; dma_addr_t pa; @@ -365,7 +374,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, struct vring_rx_desc *d; struct sk_buff *skb; dma_addr_t pa; - unsigned int sz = mtu_max + ETH_HLEN; + unsigned int snaplen = wil_rx_snaplen(); + unsigned int sz = mtu_max + ETH_HLEN + snaplen; u16 dmalen; u8 ftype; int cid; @@ -438,7 +448,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, return NULL; } - if (unlikely(skb->len < ETH_HLEN)) { + if (unlikely(skb->len < ETH_HLEN + snaplen)) { wil_err(wil, "Short frame, len = %d\n", skb->len); /* TODO: process it (i.e. BAR) */ kfree_skb(skb); @@ -460,6 +470,17 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, */ } + if (snaplen) { + /* Packet layout + * +-------+-------+---------+------------+------+ + * | SA(6) | DA(6) | SNAP(6) | ETHTYPE(2) | DATA | + * +-------+-------+---------+------------+------+ + * Need to remove SNAP, shifting SA and DA forward + */ + memmove(skb->data + snaplen, skb->data, 2 * ETH_ALEN); + skb_pull(skb, snaplen); + } + return skb; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c1a71ab75a0e..a6b096eb7dee 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -28,6 +28,7 @@ extern unsigned int mtu_max; extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; extern u32 vring_idle_trsh; +extern bool rx_align_2; #define WIL_NAME "wil6210" #define WIL_FW_NAME "wil6210.fw" /* code */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 021313524913..8c18a46582db 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1109,6 +1109,11 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) */ cmd.l3_l4_ctrl |= (1 << L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS); } + + if (rx_align_2) + cmd.l2_802_3_offload_ctrl |= + L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK; + /* typical time for secure PCP is 840ms */ rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 8a4af613e191..0979650e675d 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -687,6 +687,9 @@ struct wmi_cfg_rx_chain_cmd { #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_POS (0) #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_LEN (1) #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_MSK (0x1) + #define L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_POS (1) + #define L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_LEN (1) + #define L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK (0x2) u8 l2_802_3_offload_ctrl; #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_POS (0) From a82553bb9035ee881f24c38a92cc0dbb3e53cc0e Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Mar 2015 16:00:21 +0200 Subject: [PATCH 170/567] wil6210: Prefer ether_addr_copy() over memcpy() Fix checkpatch warning: WARNING: Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2) Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 7 ++++--- drivers/net/wireless/ath/wil6210/wmi.c | 11 ++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 5db6a6dc691e..c9f362c68c17 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include "wil6210.h" #include "wmi.h" @@ -217,7 +218,7 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy, if (cid < 0) return -ENOENT; - memcpy(mac, wil->sta[cid].addr, ETH_ALEN); + ether_addr_copy(mac, wil->sta[cid].addr); wil_dbg_misc(wil, "%s(%pM) CID %d\n", __func__, mac, cid); rc = wil_cid_fill_sinfo(wil, cid, sinfo); @@ -478,8 +479,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, } conn.channel = ch - 1; - memcpy(conn.bssid, bss->bssid, ETH_ALEN); - memcpy(conn.dst_mac, bss->bssid, ETH_ALEN); + ether_addr_copy(conn.bssid, bss->bssid); + ether_addr_copy(conn.dst_mac, bss->bssid); set_bit(wil_status_fwconnecting, wil->status); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 8c18a46582db..9fe2085be2c5 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -466,7 +466,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) /* FIXME FW can transmit only ucast frames to peer */ /* FIXME real ring_id instead of hard coded 0 */ - memcpy(wil->sta[evt->cid].addr, evt->bssid, ETH_ALEN); + ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid); wil->sta[evt->cid].status = wil_sta_conn_pending; wil->pending_connect_cid = evt->cid; @@ -524,8 +524,8 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, } eth = (struct ethhdr *)skb_put(skb, ETH_HLEN); - memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN); - memcpy(eth->h_source, evt->src_mac, ETH_ALEN); + ether_addr_copy(eth->h_dest, ndev->dev_addr); + ether_addr_copy(eth->h_source, evt->src_mac); eth->h_proto = cpu_to_be16(ETH_P_PAE); memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len); skb->protocol = eth_type_trans(skb, ndev); @@ -851,7 +851,7 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) { struct wmi_set_mac_address_cmd cmd; - memcpy(cmd.mac, addr, ETH_ALEN); + ether_addr_copy(cmd.mac, addr); wil_dbg_wmi(wil, "Set MAC %pM\n", addr); @@ -1162,7 +1162,8 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) struct wmi_disconnect_sta_cmd cmd = { .disconnect_reason = cpu_to_le16(reason), }; - memcpy(cmd.dst_mac, mac, ETH_ALEN); + + ether_addr_copy(cmd.dst_mac, mac); wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason); From 62bfd30031faebcbf25db37bf228eeab0e25b2c3 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Mar 2015 16:00:22 +0200 Subject: [PATCH 171/567] wil6210: add bcast structures to WMI Sync with the wmi definitions from the firmware team Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 0979650e675d..b29055315350 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -70,7 +70,6 @@ enum wmi_command_id { WMI_SET_UCODE_IDLE_CMDID = 0x0813, WMI_SET_WORK_MODE_CMDID = 0x0815, WMI_LO_LEAKAGE_CALIB_CMDID = 0x0816, - WMI_MARLON_R_ACTIVATE_CMDID = 0x0817, WMI_MARLON_R_READ_CMDID = 0x0818, WMI_MARLON_R_WRITE_CMDID = 0x0819, WMI_MARLON_R_TXRX_SEL_CMDID = 0x081a, @@ -80,6 +79,7 @@ enum wmi_command_id { WMI_RF_RX_TEST_CMDID = 0x081e, WMI_CFG_RX_CHAIN_CMDID = 0x0820, WMI_VRING_CFG_CMDID = 0x0821, + WMI_BCAST_VRING_CFG_CMDID = 0x0822, WMI_VRING_BA_EN_CMDID = 0x0823, WMI_VRING_BA_DIS_CMDID = 0x0824, WMI_RCP_ADDBA_RESP_CMDID = 0x0825, @@ -99,6 +99,7 @@ enum wmi_command_id { WMI_BF_TXSS_MGMT_CMDID = 0x0837, WMI_BF_SM_MGMT_CMDID = 0x0838, WMI_BF_RXSS_MGMT_CMDID = 0x0839, + WMI_BF_TRIG_CMDID = 0x083A, WMI_SET_SECTORS_CMDID = 0x0849, WMI_MAINTAIN_PAUSE_CMDID = 0x0850, WMI_MAINTAIN_RESUME_CMDID = 0x0851, @@ -595,6 +596,22 @@ struct wmi_vring_cfg_cmd { struct wmi_vring_cfg vring_cfg; } __packed; +/* + * WMI_BCAST_VRING_CFG_CMDID + */ +struct wmi_bcast_vring_cfg { + struct wmi_sw_ring_cfg tx_sw_ring; + u8 ringid; /* 0-23 vrings */ + u8 encap_trans_type; + u8 ds_cfg; /* 802.3 DS cfg */ + u8 nwifi_ds_trans_type; +} __packed; + +struct wmi_bcast_vring_cfg_cmd { + __le32 action; + struct wmi_bcast_vring_cfg vring_cfg; +} __packed; + /* * WMI_VRING_BA_EN_CMDID */ @@ -844,7 +861,6 @@ enum wmi_event_id { WMI_IQ_RX_CALIB_DONE_EVENTID = 0x1812, WMI_SET_WORK_MODE_DONE_EVENTID = 0x1815, WMI_LO_LEAKAGE_CALIB_DONE_EVENTID = 0x1816, - WMI_MARLON_R_ACTIVATE_DONE_EVENTID = 0x1817, WMI_MARLON_R_READ_DONE_EVENTID = 0x1818, WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819, WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181a, From 41d6b093b7f8f2755a0a64ad4277c01bf78ced3e Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Mar 2015 16:00:23 +0200 Subject: [PATCH 172/567] wil6210: implement broadcast/multicast data Use dedicated vring for multicast frames; this vring allocated for AP and PBSS (both P2P GO and client) configurations For short frames, use MCS0; for long - MCS1 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 11 +- drivers/net/wireless/ath/wil6210/debugfs.c | 18 +- drivers/net/wireless/ath/wil6210/main.c | 33 ++++ drivers/net/wireless/ath/wil6210/txrx.c | 175 ++++++++++++-------- drivers/net/wireless/ath/wil6210/wil6210.h | 6 + 5 files changed, 167 insertions(+), 76 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c9f362c68c17..8f7596f60263 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -783,8 +783,17 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) - netif_carrier_off(ndev); + goto err_pcp_start; + rc = wil_bcast_init(wil); + if (rc) + goto err_bcast; + + goto out; /* success */ +err_bcast: + wmi_pcp_stop(wil); +err_pcp_start: + netif_carrier_off(ndev); out: mutex_unlock(&wil->mutex); return rc; diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index a42cb89ff725..bbc22d88f78f 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -121,12 +121,18 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data) snprintf(name, sizeof(name), "tx_%2d", i); - seq_printf(s, - "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %s\n", - wil->sta[cid].addr, cid, tid, - txdata->agg_wsize, txdata->agg_timeout, - txdata->agg_amsdu ? "+" : "-", - used, avail, sidle); + if (cid < WIL6210_MAX_CID) + seq_printf(s, + "\n%pM CID %d TID %d BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n", + wil->sta[cid].addr, cid, tid, + txdata->agg_wsize, + txdata->agg_timeout, + txdata->agg_amsdu ? "+" : "-", + used, avail, sidle); + else + seq_printf(s, + "\nBroadcast [%3d|%3d] idle %s\n", + used, avail, sidle); wil_print_vring(s, wil, name, vring, '_', 'H'); } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index a5fd605e52eb..c2a238426425 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -68,6 +68,7 @@ MODULE_PARM_DESC(mtu_max, " Max MTU value."); static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; +static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; static int ring_order_set(const char *val, const struct kernel_param *kp) { @@ -216,6 +217,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: + wil_bcast_fini(wil); netif_tx_stop_all_queues(ndev); netif_carrier_off(ndev); @@ -360,6 +362,35 @@ static int wil_find_free_vring(struct wil6210_priv *wil) return -EINVAL; } +int wil_bcast_init(struct wil6210_priv *wil) +{ + int ri = wil->bcast_vring, rc; + + if ((ri >= 0) && wil->vring_tx[ri].va) + return 0; + + ri = wil_find_free_vring(wil); + if (ri < 0) + return ri; + + rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order); + if (rc == 0) + wil->bcast_vring = ri; + + return rc; +} + +void wil_bcast_fini(struct wil6210_priv *wil) +{ + int ri = wil->bcast_vring; + + if (ri < 0) + return; + + wil->bcast_vring = -1; + wil_vring_fini_tx(wil, ri); +} + static void wil_connect_worker(struct work_struct *work) { int rc; @@ -407,6 +438,7 @@ int wil_priv_init(struct wil6210_priv *wil) init_completion(&wil->wmi_call); wil->pending_connect_cid = -1; + wil->bcast_vring = -1; setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil); setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil); @@ -656,6 +688,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); + wil_bcast_fini(wil); /* prevent NAPI from being scheduled */ bitmap_zero(wil->status, wil_status_last); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 2453470bc191..1fe390f6d7d7 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -523,7 +523,7 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) struct wireless_dev *wdev = wil_to_wdev(wil); unsigned int len = skb->len; struct vring_rx_desc *d = wil_skb_rxdesc(skb); - int cid = wil_rxdesc_cid(d); + int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */ struct ethhdr *eth = (void *)skb->data; /* here looking for DA, not A1, thus Rxdesc's 'mcast' indication * is not suitable, need to look at data @@ -749,6 +749,72 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, return rc; } +int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) +{ + int rc; + struct wmi_bcast_vring_cfg_cmd cmd = { + .action = cpu_to_le32(WMI_VRING_CMD_ADD), + .vring_cfg = { + .tx_sw_ring = { + .max_mpdu_size = + cpu_to_le16(wil_mtu2macbuf(mtu_max)), + .ring_size = cpu_to_le16(size), + }, + .ringid = id, + .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, + }, + }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_vring_cfg_done_event cmd; + } __packed reply; + struct vring *vring = &wil->vring_tx[id]; + struct vring_tx_data *txdata = &wil->vring_tx_data[id]; + + wil_dbg_misc(wil, "%s() max_mpdu_size %d\n", __func__, + cmd.vring_cfg.tx_sw_ring.max_mpdu_size); + + if (vring->va) { + wil_err(wil, "Tx ring [%d] already allocated\n", id); + rc = -EINVAL; + goto out; + } + + memset(txdata, 0, sizeof(*txdata)); + spin_lock_init(&txdata->lock); + vring->size = size; + rc = wil_vring_alloc(wil, vring); + if (rc) + goto out; + + wil->vring2cid_tid[id][0] = WIL6210_MAX_CID; /* CID */ + wil->vring2cid_tid[id][1] = 0; /* TID */ + + cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); + + rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd), + WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); + if (rc) + goto out_free; + + if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "Tx config failed, status 0x%02x\n", + reply.cmd.status); + rc = -EINVAL; + goto out_free; + } + vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); + + txdata->enabled = 1; + + return 0; + out_free: + wil_vring_free(wil, vring, 1); + out: + + return rc; +} + void wil_vring_fini_tx(struct wil6210_priv *wil, int id) { struct vring *vring = &wil->vring_tx[id]; @@ -772,7 +838,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) memset(txdata, 0, sizeof(*txdata)); } -static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, +static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil, struct sk_buff *skb) { int i; @@ -805,15 +871,6 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, return NULL; } -static void wil_set_da_for_vring(struct wil6210_priv *wil, - struct sk_buff *skb, int vring_index) -{ - struct ethhdr *eth = (void *)skb->data; - int cid = wil->vring2cid_tid[vring_index][0]; - - memcpy(eth->h_dest, wil->sta[cid].addr, ETH_ALEN); -} - static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, struct sk_buff *skb); @@ -834,6 +891,9 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, continue; cid = wil->vring2cid_tid[i][0]; + if (cid >= WIL6210_MAX_CID) /* skip BCAST */ + continue; + if (!wil->sta[cid].data_port_open && (skb->protocol != cpu_to_be16(ETH_P_PAE))) break; @@ -848,57 +908,17 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, return NULL; } -/* - * Find 1-st vring and return it; set dest address for this vring in skb - * duplicate skb and send it to other active vrings - */ -static struct vring *wil_tx_bcast(struct wil6210_priv *wil, - struct sk_buff *skb) +static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil, + struct sk_buff *skb) { - struct vring *v, *v2; - struct sk_buff *skb2; - int i; - u8 cid; + struct vring *v; + int i = wil->bcast_vring; - /* find 1-st vring eligible for data */ - for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { - v = &wil->vring_tx[i]; - if (!v->va) - continue; - - cid = wil->vring2cid_tid[i][0]; - if (!wil->sta[cid].data_port_open) - continue; - - goto found; - } - - wil_dbg_txrx(wil, "Tx while no vrings active?\n"); - - return NULL; - -found: - wil_dbg_txrx(wil, "BCAST -> ring %d\n", i); - wil_set_da_for_vring(wil, skb, i); - - /* find other active vrings and duplicate skb for each */ - for (i++; i < WIL6210_MAX_TX_RINGS; i++) { - v2 = &wil->vring_tx[i]; - if (!v2->va) - continue; - cid = wil->vring2cid_tid[i][0]; - if (!wil->sta[cid].data_port_open) - continue; - - skb2 = skb_copy(skb, GFP_ATOMIC); - if (skb2) { - wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); - wil_set_da_for_vring(wil, skb2, i); - wil_tx_vring(wil, v2, skb2); - } else { - wil_err(wil, "skb_copy failed\n"); - } - } + if (i < 0) + return NULL; + v = &wil->vring_tx[i]; + if (!v->va) + return NULL; return v; } @@ -995,6 +1015,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, uint i = swhead; dma_addr_t pa; int used; + bool mcast = (vring_index == wil->bcast_vring); + uint len = skb_headlen(skb); wil_dbg_txrx(wil, "%s()\n", __func__); @@ -1020,7 +1042,17 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, return -EINVAL; vring->ctx[i].mapped_as = wil_mapped_as_single; /* 1-st segment */ - wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index); + wil_tx_desc_map(d, pa, len, vring_index); + if (unlikely(mcast)) { + d->mac.d[0] |= BIT(MAC_CFG_DESC_TX_0_MCS_EN_POS); /* MCS 0 */ + if (unlikely(len > WIL_BCAST_MCS0_LIMIT)) { + /* set MCS 1 */ + d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS); + /* packet mode 2 */ + d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS) | + (2 << MAC_CFG_DESC_TX_1_PKT_MODE_POS); + } + } /* Process TCP/UDP checksum offloading */ if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) { wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", @@ -1126,6 +1158,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); struct ethhdr *eth = (void *)skb->data; + bool bcast = is_multicast_ether_addr(eth->h_dest); struct vring *vring; static bool pr_once_fw; int rc; @@ -1153,10 +1186,8 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* in STA mode (ESS), all to same VRING */ vring = wil_find_tx_vring_sta(wil, skb); } else { /* direct communication, find matching VRING */ - if (is_unicast_ether_addr(eth->h_dest)) - vring = wil_find_tx_vring(wil, skb); - else - vring = wil_tx_bcast(wil, skb); + vring = bcast ? wil_find_tx_bcast(wil, skb) : + wil_find_tx_ucast(wil, skb); } if (unlikely(!vring)) { wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); @@ -1219,7 +1250,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; int done = 0; int cid = wil->vring2cid_tid[ringid][0]; - struct wil_net_stats *stats = &wil->sta[cid].stats; + struct wil_net_stats *stats = NULL; volatile struct vring_tx_desc *_d; int used_before_complete; int used_new; @@ -1238,6 +1269,9 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) used_before_complete = wil_vring_used_tx(vring); + if (cid < WIL6210_MAX_CID) + stats = &wil->sta[cid].stats; + while (!wil_vring_is_empty(vring)) { int new_swtail; struct wil_ctx *ctx = &vring->ctx[vring->swtail]; @@ -1279,12 +1313,15 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) if (skb) { if (likely(d->dma.error == 0)) { ndev->stats.tx_packets++; - stats->tx_packets++; ndev->stats.tx_bytes += skb->len; - stats->tx_bytes += skb->len; + if (stats) { + stats->tx_packets++; + stats->tx_bytes += skb->len; + } } else { ndev->stats.tx_errors++; - stats->tx_errors++; + if (stats) + stats->tx_errors++; } wil_consume_skb(skb, d->dma.error == 0); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index a6b096eb7dee..4310972c9e16 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -50,6 +50,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL_TX_Q_LEN_DEFAULT (4000) #define WIL_RX_RING_SIZE_ORDER_DEFAULT (10) #define WIL_TX_RING_SIZE_ORDER_DEFAULT (10) +#define WIL_BCAST_RING_SIZE_ORDER_DEFAULT (7) +#define WIL_BCAST_MCS0_LIMIT (1024) /* limit for MCS0 frame size */ /* limit ring size in range [32..32k] */ #define WIL_RING_SIZE_ORDER_MIN (5) #define WIL_RING_SIZE_ORDER_MAX (15) @@ -595,6 +597,7 @@ struct wil6210_priv { struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ struct wil_sta_info sta[WIL6210_MAX_CID]; + int bcast_vring; /* scan */ struct cfg80211_scan_request *scan_request; @@ -757,6 +760,9 @@ void wil_rx_fini(struct wil6210_priv *wil); int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, int cid, int tid); void wil_vring_fini_tx(struct wil6210_priv *wil, int id); +int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size); +int wil_bcast_init(struct wil6210_priv *wil); +void wil_bcast_fini(struct wil6210_priv *wil); netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); int wil_tx_complete(struct wil6210_priv *wil, int ringid); From 70812421fb15888c809abb0b9b4ad34368094af6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 15 Mar 2015 16:00:24 +0200 Subject: [PATCH 173/567] wil6210: fall back to pseudo-DMS mcast for secure link and PBSS Multicast is not yet properly supported for all connection types; actually, only non-secure AP is supported. For all other cases, fall back to old "pseudo-DMS" approach. Namely, for: - PBSS - secure connection When re-routing MCAST Rx->Tx on the AP, do not Tx back to the origin of the frame Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/txrx.c | 103 +++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 1fe390f6d7d7..e8bd512d81a9 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -908,8 +908,20 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, return NULL; } -static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil, - struct sk_buff *skb) +/* Use one of 2 strategies: + * + * 1. New (real broadcast): + * use dedicated broadcast vring + * 2. Old (pseudo-DMS): + * Find 1-st vring and return it; + * duplicate skb and send it to other active vrings; + * in all cases override dest address to unicast peer's address + * Use old strategy when new is not supported yet: + * - for PBSS + * - for secure link + */ +static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil, + struct sk_buff *skb) { struct vring *v; int i = wil->bcast_vring; @@ -923,6 +935,93 @@ static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil, return v; } +static void wil_set_da_for_vring(struct wil6210_priv *wil, + struct sk_buff *skb, int vring_index) +{ + struct ethhdr *eth = (void *)skb->data; + int cid = wil->vring2cid_tid[vring_index][0]; + + ether_addr_copy(eth->h_dest, wil->sta[cid].addr); +} + +static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + struct vring *v, *v2; + struct sk_buff *skb2; + int i; + u8 cid; + struct ethhdr *eth = (void *)skb->data; + char *src = eth->h_source; + + /* find 1-st vring eligible for data */ + for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { + v = &wil->vring_tx[i]; + if (!v->va) + continue; + + cid = wil->vring2cid_tid[i][0]; + if (cid >= WIL6210_MAX_CID) /* skip BCAST */ + continue; + if (!wil->sta[cid].data_port_open) + continue; + + /* don't Tx back to source when re-routing Rx->Tx at the AP */ + if (0 == memcmp(wil->sta[cid].addr, src, ETH_ALEN)) + continue; + + goto found; + } + + wil_dbg_txrx(wil, "Tx while no vrings active?\n"); + + return NULL; + +found: + wil_dbg_txrx(wil, "BCAST -> ring %d\n", i); + wil_set_da_for_vring(wil, skb, i); + + /* find other active vrings and duplicate skb for each */ + for (i++; i < WIL6210_MAX_TX_RINGS; i++) { + v2 = &wil->vring_tx[i]; + if (!v2->va) + continue; + cid = wil->vring2cid_tid[i][0]; + if (cid >= WIL6210_MAX_CID) /* skip BCAST */ + continue; + if (!wil->sta[cid].data_port_open) + continue; + + if (0 == memcmp(wil->sta[cid].addr, src, ETH_ALEN)) + continue; + + skb2 = skb_copy(skb, GFP_ATOMIC); + if (skb2) { + wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); + wil_set_da_for_vring(wil, skb2, i); + wil_tx_vring(wil, v2, skb2); + } else { + wil_err(wil, "skb_copy failed\n"); + } + } + + return v; +} + +static struct vring *wil_find_tx_bcast(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + struct wireless_dev *wdev = wil->wdev; + + if (wdev->iftype != NL80211_IFTYPE_AP) + return wil_find_tx_bcast_2(wil, skb); + + if (wil->privacy) + return wil_find_tx_bcast_2(wil, skb); + + return wil_find_tx_bcast_1(wil, skb); +} + static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, int vring_index) { From ea345c145ff23197eab34d0c4d0c8a93d7bea8c6 Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Mon, 16 Mar 2015 10:59:52 -0700 Subject: [PATCH 174/567] rt2x00: add new rt2800usb device DWA 130 Add the USB Id to link the D-Link DWA 130 USB Wifi adapter to the rt2830 driver. Signed-off-by: Scott Branden Signed-off-by: Pieter Truter Signed-off-by: Kalle Valo --- drivers/net/wireless/rt2x00/rt2800usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9a2f44a54d94..41b6fb16c661 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -1043,6 +1043,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c17) }, { USB_DEVICE(0x2001, 0x3317) }, { USB_DEVICE(0x2001, 0x3c1b) }, + { USB_DEVICE(0x2001, 0x3c25) }, /* Draytek */ { USB_DEVICE(0x07fa, 0x7712) }, /* DVICO */ From bb408cc78401c53842e17b24b6433c122629f21f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 18 Mar 2015 11:22:35 +0300 Subject: [PATCH 175/567] mwifiex: missing curly braces in mwifiex_write_data_complete() It's clear from the indenting that curly braces were intended here. Fixes: e35000ead491 ('mwifiex: preprocess packets from TX queue') Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/txrx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 4d43371583cf..a245f444aeec 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -302,10 +302,11 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, priv->stats.tx_errors++; } - if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) + if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT) { atomic_dec_return(&adapter->pending_bridged_pkts); if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT) goto done; + } if (aggr) /* For skb_aggr, do not wake up tx queue */ From 063d51776bd60ebf2587682eb394851c792e58d9 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 18 Mar 2015 13:25:21 +0100 Subject: [PATCH 176/567] brcmfmac: avoid runtime-pm for sdio host controller Several host controllers supporting runtime-pm are causing issues with our sdio wireless cards because they disable the sdio interrupt upon going into runtime suspend. This patch avoids that by doing a pm_runtime_forbid() call during the probe. Tested with Sony Vaio Duo 13 which uses sdhci-acpi host controller. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 43995308307d..9667b6aabc00 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1006,6 +1007,7 @@ static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) sg_free_table(&sdiodev->sgtable); sdiodev->sbwad = 0; + pm_runtime_allow(sdiodev->func[1]->card->host->parent); return 0; } @@ -1074,7 +1076,7 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) ret = -ENODEV; goto out; } - + pm_runtime_forbid(host->parent); out: if (ret) brcmf_sdiod_remove(sdiodev); From 2c64e16d1ff1228df837508ab32e8a060cb06907 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 18 Mar 2015 13:25:22 +0100 Subject: [PATCH 177/567] brcmfmac: Add necessary memory barriers for SDIO. SDIO uses a thread to handle all communication with the device, for this data is exchanged between threads. This data needs proper memory barriers to make sure that data "exchange" is going correct. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/brcm80211/brcmfmac/sdio.c | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 17a7212cfd70..38fa0e8f859d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -507,8 +507,8 @@ struct brcmf_sdio { struct workqueue_struct *brcmf_wq; struct work_struct datawork; - atomic_t dpc_tskcnt; - atomic_t dpc_running; + bool dpc_triggered; + bool dpc_running; bool txoff; /* Transmit flow-controlled */ struct brcmf_sdio_count sdcnt; @@ -2713,6 +2713,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, bus->ctrl_frame_len); bus->ctrl_frame_err = err; + wmb(); bus->ctrl_frame_stat = false; } sdio_release_host(bus->sdiodev->func[1]); @@ -2734,6 +2735,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) sdio_claim_host(bus->sdiodev->func[1]); if (bus->ctrl_frame_stat) { bus->ctrl_frame_err = -ENODEV; + wmb(); bus->ctrl_frame_stat = false; brcmf_sdio_wait_event_wakeup(bus); } @@ -2744,7 +2746,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) (!atomic_read(&bus->fcstate) && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && data_ok(bus))) { - atomic_inc(&bus->dpc_tskcnt); + bus->dpc_triggered = true; } } @@ -2940,6 +2942,7 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) /* Send from dpc */ bus->ctrl_frame_buf = msg; bus->ctrl_frame_len = msglen; + wmb(); bus->ctrl_frame_stat = true; brcmf_sdio_trigger_dpc(bus); @@ -2958,6 +2961,7 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) if (!ret) { brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n", bus->ctrl_frame_err); + rmb(); ret = bus->ctrl_frame_err; } @@ -3526,8 +3530,8 @@ done: void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus) { - if (atomic_read(&bus->dpc_tskcnt) == 0) { - atomic_inc(&bus->dpc_tskcnt); + if (!bus->dpc_triggered) { + bus->dpc_triggered = true; queue_work(bus->brcmf_wq, &bus->datawork); } } @@ -3558,7 +3562,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus) if (!bus->intr) brcmf_err("isr w/o interrupt configured!\n"); - atomic_inc(&bus->dpc_tskcnt); + bus->dpc_triggered = true; queue_work(bus->brcmf_wq, &bus->datawork); } @@ -3578,7 +3582,7 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) if (!bus->intr || (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) { - if (atomic_read(&bus->dpc_tskcnt) == 0) { + if (!bus->dpc_triggered) { u8 devpend; sdio_claim_host(bus->sdiodev->func[1]); @@ -3596,7 +3600,7 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) bus->sdcnt.pollcnt++; atomic_set(&bus->ipend, 1); - atomic_inc(&bus->dpc_tskcnt); + bus->dpc_triggered = true; queue_work(bus->brcmf_wq, &bus->datawork); } } @@ -3623,17 +3627,21 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) #endif /* DEBUG */ /* On idle timeout clear activity flag and/or turn off clock */ - if ((atomic_read(&bus->dpc_tskcnt) == 0) && - (atomic_read(&bus->dpc_running) == 0) && - (bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { - bus->idlecount++; - if (bus->idlecount > bus->idletime) { - brcmf_dbg(SDIO, "idle\n"); - sdio_claim_host(bus->sdiodev->func[1]); - brcmf_sdio_wd_timer(bus, 0); + if (!bus->dpc_triggered) { + rmb(); + if ((!bus->dpc_running) && (bus->idletime > 0) && + (bus->clkstate == CLK_AVAIL)) { + bus->idlecount++; + if (bus->idlecount > bus->idletime) { + brcmf_dbg(SDIO, "idle\n"); + sdio_claim_host(bus->sdiodev->func[1]); + brcmf_sdio_wd_timer(bus, 0); + bus->idlecount = 0; + brcmf_sdio_bus_sleep(bus, true, false); + sdio_release_host(bus->sdiodev->func[1]); + } + } else { bus->idlecount = 0; - brcmf_sdio_bus_sleep(bus, true, false); - sdio_release_host(bus->sdiodev->func[1]); } } else { bus->idlecount = 0; @@ -3645,13 +3653,14 @@ static void brcmf_sdio_dataworker(struct work_struct *work) struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio, datawork); - while (atomic_read(&bus->dpc_tskcnt)) { - atomic_set(&bus->dpc_running, 1); - atomic_set(&bus->dpc_tskcnt, 0); + bus->dpc_running = true; + wmb(); + while (ACCESS_ONCE(bus->dpc_triggered)) { + bus->dpc_triggered = false; brcmf_sdio_dpc(bus); bus->idlecount = 0; - atomic_set(&bus->dpc_running, 0); } + bus->dpc_running = false; if (brcmf_sdiod_freezing(bus->sdiodev)) { brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN); brcmf_sdiod_try_freeze(bus->sdiodev); @@ -4144,8 +4153,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) bus->watchdog_tsk = NULL; } /* Initialize DPC thread */ - atomic_set(&bus->dpc_tskcnt, 0); - atomic_set(&bus->dpc_running, 0); + bus->dpc_triggered = false; + bus->dpc_running = false; /* Assign bus interface call back */ bus->sdiodev->bus_if->dev = bus->sdiodev->dev; From a74196bb67c4f21a8308d26ba3bbdd22d766f5a4 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 18 Mar 2015 13:25:23 +0100 Subject: [PATCH 178/567] brcmfmac: Update msgbuf commonring size for improved throughput. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h index 77a51b8c1e12..3d513e407e3d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.h @@ -17,11 +17,11 @@ #ifdef CONFIG_BRCMFMAC_PROTO_MSGBUF -#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 20 -#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 256 -#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 20 +#define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_MAX_ITEM 64 +#define BRCMF_H2D_MSGRING_RXPOST_SUBMIT_MAX_ITEM 512 +#define BRCMF_D2H_MSGRING_CONTROL_COMPLETE_MAX_ITEM 64 #define BRCMF_D2H_MSGRING_TX_COMPLETE_MAX_ITEM 1024 -#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 256 +#define BRCMF_D2H_MSGRING_RX_COMPLETE_MAX_ITEM 512 #define BRCMF_H2D_TXFLOWRING_MAX_ITEM 512 #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT_ITEMSIZE 40 From ef5671d29df558405f454c606c639db3337548e2 Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Wed, 18 Mar 2015 13:25:24 +0100 Subject: [PATCH 179/567] brcmfmac: Remove unnecessary new-line in pcie console logging. Reviewed-by: Arend Van Spriel Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/pcie.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index aa7a4dfb8beb..ec426f38ef96 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -651,10 +651,9 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo) console->log_str[console->log_idx] = ch; console->log_idx++; } - if (ch == '\n') { console->log_str[console->log_idx] = 0; - brcmf_dbg(PCIE, "CONSOLE: %s\n", console->log_str); + brcmf_dbg(PCIE, "CONSOLE: %s", console->log_str); console->log_idx = 0; } } From 7fca40eb003009e09614fb70edb6e48851f3fefc Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 18 Mar 2015 13:25:25 +0100 Subject: [PATCH 180/567] brcmfmac: add MODULE_FIRMWARE() macros for bcm4356 PCIe device The BCM4356 PCIe wireless device was added recently but overlooked the fact that the MODULE_FIRMWARE() macros were missing for the firmwares needed by this device. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/pcie.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index ec426f38ef96..d4066e880dfc 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -189,6 +189,8 @@ MODULE_FIRMWARE(BRCMF_PCIE_43602_FW_NAME); MODULE_FIRMWARE(BRCMF_PCIE_43602_NVRAM_NAME); MODULE_FIRMWARE(BRCMF_PCIE_4354_FW_NAME); MODULE_FIRMWARE(BRCMF_PCIE_4354_NVRAM_NAME); +MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME); +MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME); MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME); MODULE_FIRMWARE(BRCMF_PCIE_43570_NVRAM_NAME); From 25911556283e5093fca235d7ba03faae7ed5dbf2 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 18 Mar 2015 13:25:26 +0100 Subject: [PATCH 181/567] brcmfmac: add support for BCM43430 SDIO chipset This patch added support for the BCM43430 802.11n SDIO chipset. Reviewed-by: Hante Meuleman Reviewed-by: Daniel (Deognyoun) Kim Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/brcm80211/brcmfmac/bcmsdh.c | 1 + drivers/net/wireless/brcm80211/brcmfmac/chip.c | 18 ++++++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 5 +++++ .../wireless/brcm80211/include/brcm_hw_ids.h | 1 + .../wireless/brcm80211/include/chipcommon.h | 9 ++++++++- include/linux/mmc/sdio_ids.h | 1 + 6 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 9667b6aabc00..9b508bd3b839 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -1098,6 +1098,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43430), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4345), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354), { /* end: all zeroes */ } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c index 734172570054..ab2fac8b2760 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -600,6 +600,12 @@ static void brcmf_chip_socram_ramsize(struct brcmf_core_priv *sr, u32 *ramsize, if (sr->chip->pub.chiprev < 2) *srsize = (32 * 1024); break; + case BRCM_CC_43430_CHIP_ID: + /* assume sr for now as we can not check + * firmware sr capability at this point. + */ + *srsize = (64 * 1024); + break; default: break; } @@ -1072,6 +1078,7 @@ static void brcmf_chip_cm3_set_passive(struct brcmf_chip_priv *chip) { struct brcmf_core *core; + struct brcmf_core_priv *sr; brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3); core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); @@ -1081,6 +1088,13 @@ brcmf_chip_cm3_set_passive(struct brcmf_chip_priv *chip) D11_BCMA_IOCTL_PHYCLOCKEN); core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM); brcmf_chip_resetcore(core, 0, 0, 0); + + /* disable bank #3 remap for this device */ + if (chip->pub.chip == BRCM_CC_43430_CHIP_ID) { + sr = container_of(core, struct brcmf_core_priv, pub); + brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankidx), 3); + brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankpda), 0); + } } static bool brcmf_chip_cm3_set_active(struct brcmf_chip_priv *chip) @@ -1188,6 +1202,10 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) addr = CORE_CC_REG(base, chipcontrol_data); reg = chip->ops->read32(chip->ctx, addr); return (reg & pmu_cc3_mask) != 0; + case BRCM_CC_43430_CHIP_ID: + addr = CORE_CC_REG(base, sr_control1); + reg = chip->ops->read32(chip->ctx, addr); + return reg != 0; default: addr = CORE_CC_REG(base, pmucapabilities_ext); reg = chip->ops->read32(chip->ctx, addr); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index 38fa0e8f859d..e162860b265c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -615,6 +615,8 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { #define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt" #define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin" #define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt" +#define BCM43430_FIRMWARE_NAME "brcm/brcmfmac43430-sdio.bin" +#define BCM43430_NVRAM_NAME "brcm/brcmfmac43430-sdio.txt" #define BCM4345_FIRMWARE_NAME "brcm/brcmfmac4345-sdio.bin" #define BCM4345_NVRAM_NAME "brcm/brcmfmac4345-sdio.txt" #define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin" @@ -640,6 +642,8 @@ MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME); MODULE_FIRMWARE(BCM43362_NVRAM_NAME); MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4339_NVRAM_NAME); +MODULE_FIRMWARE(BCM43430_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM43430_NVRAM_NAME); MODULE_FIRMWARE(BCM4345_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4345_NVRAM_NAME); MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME); @@ -671,6 +675,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { { BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, { BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, { BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, + { BRCM_CC_43430_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43430) }, { BRCM_CC_4345_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4345) }, { BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) } }; diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index b599e7e41148..4efdd51af9c8 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -37,6 +37,7 @@ #define BRCM_CC_43362_CHIP_ID 43362 #define BRCM_CC_4335_CHIP_ID 0x4335 #define BRCM_CC_4339_CHIP_ID 0x4339 +#define BRCM_CC_43430_CHIP_ID 43430 #define BRCM_CC_4345_CHIP_ID 0x4345 #define BRCM_CC_4354_CHIP_ID 0x4354 #define BRCM_CC_4356_CHIP_ID 0x4356 diff --git a/drivers/net/wireless/brcm80211/include/chipcommon.h b/drivers/net/wireless/brcm80211/include/chipcommon.h index d242333b7559..e1fd499930a0 100644 --- a/drivers/net/wireless/brcm80211/include/chipcommon.h +++ b/drivers/net/wireless/brcm80211/include/chipcommon.h @@ -183,7 +183,14 @@ struct chipcregs { u8 uart1lsr; u8 uart1msr; u8 uart1scratch; - u32 PAD[126]; + u32 PAD[62]; + + /* save/restore, corerev >= 48 */ + u32 sr_capability; /* 0x500 */ + u32 sr_control0; /* 0x504 */ + u32 sr_control1; /* 0x508 */ + u32 gpio_control; /* 0x50C */ + u32 PAD[60]; /* PMU registers (corerev >= 20) */ u32 pmucontrol; /* 0x600 */ diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 91397858dc95..83430f2ea757 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -33,6 +33,7 @@ #define SDIO_DEVICE_ID_BROADCOM_43341 0xa94d #define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335 #define SDIO_DEVICE_ID_BROADCOM_43362 0xa962 +#define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6 #define SDIO_DEVICE_ID_BROADCOM_4345 0x4345 #define SDIO_DEVICE_ID_BROADCOM_4354 0x4354 From 228a71763d9f24637a6db2d1712f1e1a21a80ec6 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 18 Mar 2015 13:25:27 +0100 Subject: [PATCH 182/567] brcmfmac: only support the BCM43455/7 device Recently support was added for the BCM4345 SDIO chipset by commit 9c51026509d7 ("brcmfmac: Add support for BCM4345 SDIO chipset") however this was verified using a BCM43455 device, which is a more recent revision of the chip. This patch assure that older revisions are not probed as they would fail. Reviewed-by: Hante Meuleman Reviewed-by: Syed Asifful Dayyan Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/sdio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c index e162860b265c..ab0c89833013 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c @@ -617,8 +617,8 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { #define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt" #define BCM43430_FIRMWARE_NAME "brcm/brcmfmac43430-sdio.bin" #define BCM43430_NVRAM_NAME "brcm/brcmfmac43430-sdio.txt" -#define BCM4345_FIRMWARE_NAME "brcm/brcmfmac4345-sdio.bin" -#define BCM4345_NVRAM_NAME "brcm/brcmfmac4345-sdio.txt" +#define BCM43455_FIRMWARE_NAME "brcm/brcmfmac43455-sdio.bin" +#define BCM43455_NVRAM_NAME "brcm/brcmfmac43455-sdio.txt" #define BCM4354_FIRMWARE_NAME "brcm/brcmfmac4354-sdio.bin" #define BCM4354_NVRAM_NAME "brcm/brcmfmac4354-sdio.txt" @@ -644,8 +644,8 @@ MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4339_NVRAM_NAME); MODULE_FIRMWARE(BCM43430_FIRMWARE_NAME); MODULE_FIRMWARE(BCM43430_NVRAM_NAME); -MODULE_FIRMWARE(BCM4345_FIRMWARE_NAME); -MODULE_FIRMWARE(BCM4345_NVRAM_NAME); +MODULE_FIRMWARE(BCM43455_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM43455_NVRAM_NAME); MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4354_NVRAM_NAME); @@ -676,7 +676,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { { BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, { BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, { BRCM_CC_43430_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43430) }, - { BRCM_CC_4345_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4345) }, + { BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, BRCMF_FIRMWARE_NVRAM(BCM43455) }, { BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) } }; From 55ab9a72bd324648987063e283ab3d4228efdaef Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Wed, 18 Mar 2015 13:25:28 +0100 Subject: [PATCH 183/567] brcmfmac: remove support for unreleased BCM4354 PCIe There are no known BCM4354 PCIe devices released so removing support from the driver until proven otherwise. Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/pcie.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c index d4066e880dfc..1831ecd0813e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c @@ -47,8 +47,6 @@ enum brcmf_pcie_state { #define BRCMF_PCIE_43602_FW_NAME "brcm/brcmfmac43602-pcie.bin" #define BRCMF_PCIE_43602_NVRAM_NAME "brcm/brcmfmac43602-pcie.txt" -#define BRCMF_PCIE_4354_FW_NAME "brcm/brcmfmac4354-pcie.bin" -#define BRCMF_PCIE_4354_NVRAM_NAME "brcm/brcmfmac4354-pcie.txt" #define BRCMF_PCIE_4356_FW_NAME "brcm/brcmfmac4356-pcie.bin" #define BRCMF_PCIE_4356_NVRAM_NAME "brcm/brcmfmac4356-pcie.txt" #define BRCMF_PCIE_43570_FW_NAME "brcm/brcmfmac43570-pcie.bin" @@ -187,8 +185,6 @@ enum brcmf_pcie_state { MODULE_FIRMWARE(BRCMF_PCIE_43602_FW_NAME); MODULE_FIRMWARE(BRCMF_PCIE_43602_NVRAM_NAME); -MODULE_FIRMWARE(BRCMF_PCIE_4354_FW_NAME); -MODULE_FIRMWARE(BRCMF_PCIE_4354_NVRAM_NAME); MODULE_FIRMWARE(BRCMF_PCIE_4356_FW_NAME); MODULE_FIRMWARE(BRCMF_PCIE_4356_NVRAM_NAME); MODULE_FIRMWARE(BRCMF_PCIE_43570_FW_NAME); @@ -1327,10 +1323,6 @@ static int brcmf_pcie_get_fwnames(struct brcmf_pciedev_info *devinfo) fw_name = BRCMF_PCIE_43602_FW_NAME; nvram_name = BRCMF_PCIE_43602_NVRAM_NAME; break; - case BRCM_CC_4354_CHIP_ID: - fw_name = BRCMF_PCIE_4354_FW_NAME; - nvram_name = BRCMF_PCIE_4354_NVRAM_NAME; - break; case BRCM_CC_4356_CHIP_ID: fw_name = BRCMF_PCIE_4356_FW_NAME; nvram_name = BRCMF_PCIE_4356_NVRAM_NAME; @@ -1855,7 +1847,6 @@ cleanup: PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } static struct pci_device_id brcmf_pcie_devid_table[] = { - BRCMF_PCIE_DEVICE(BRCM_PCIE_4354_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43570_DEVICE_ID), From 080465f27aca1315cf882297cf31a376452fa188 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 18 Mar 2015 20:12:52 +0530 Subject: [PATCH 184/567] mwifiex: fix crash in SDIO RX path With patch '960d6d08e39 "mwifiex: delay skb allocation for RX until cmd53 over"' we no more pass skb parameter to MP aggregation setup helper function. We instead pass length to be aggregated. This patch fixes an issue where we were passing length parameter of NULL skb to aggregation routine resulting into crash. We should instead pass rx_len received from mp_regs. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 330e9d06729d..4f08c58989af 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1375,7 +1375,7 @@ rx_curr_single: if (f_post_aggr_cur) { dev_dbg(adapter->dev, "info: current packet aggregation\n"); /* Curr pkt can be aggregated */ - mp_rx_aggr_setup(card, skb->len, port); + mp_rx_aggr_setup(card, rx_len, port); } return 0; From 057fcd426e146d0603b7320ea22b8caa24f83b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 15 Mar 2015 19:43:14 +0100 Subject: [PATCH 185/567] bcma: gpio: use predictable base for all BCM47XX buses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some BCM47XX SoC routers have LEDs connected to extra PCIe bcma buses. Handling them in arch code requires predictable GPIO numbers. Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/bcma/driver_gpio.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c index dce34fb52e27..74ccb02e0f10 100644 --- a/drivers/bcma/driver_gpio.c +++ b/drivers/bcma/driver_gpio.c @@ -17,6 +17,8 @@ #include "bcma_private.h" +#define BCMA_GPIO_MAX_PINS 32 + static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip) { return container_of(chip, struct bcma_drv_cc, gpio); @@ -204,6 +206,7 @@ static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc) int bcma_gpio_init(struct bcma_drv_cc *cc) { + struct bcma_bus *bus = cc->core->bus; struct gpio_chip *chip = &cc->gpio; int err; @@ -222,7 +225,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) chip->of_node = cc->core->dev.of_node; #endif - switch (cc->core->bus->chipinfo.id) { + switch (bus->chipinfo.id) { case BCMA_CHIP_ID_BCM5357: case BCMA_CHIP_ID_BCM53572: chip->ngpio = 32; @@ -231,13 +234,17 @@ int bcma_gpio_init(struct bcma_drv_cc *cc) chip->ngpio = 16; } - /* There is just one SoC in one device and its GPIO addresses should be - * deterministic to address them more easily. The other buses could get - * a random base number. */ - if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC) - chip->base = 0; - else - chip->base = -1; + /* + * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO + * pin numbers. We don't have Device Tree there and we can't really use + * relative (per chip) numbers. + * So let's use predictable base for BCM47XX and "random" for all other. + */ +#if IS_BUILTIN(CONFIG_BCM47XX) + chip->base = bus->num * BCMA_GPIO_MAX_PINS; +#else + chip->base = -1; +#endif err = bcma_gpio_irq_domain_init(cc); if (err) From 8f902b005ece690f0f50b217975601b804905dc8 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 20 Mar 2015 20:39:38 +1100 Subject: [PATCH 186/567] KVM: PPC: Book3S HV: Fix spinlock/mutex ordering issue in kvmppc_set_lpcr() Currently, kvmppc_set_lpcr() has a spinlock around the whole function, and inside that does mutex_lock(&kvm->lock). It is not permitted to take a mutex while holding a spinlock, because the mutex_lock might call schedule(). In addition, this causes lockdep to warn about a lock ordering issue: ====================================================== [ INFO: possible circular locking dependency detected ] 3.18.0-kvm-04645-gdfea862-dirty #131 Not tainted ------------------------------------------------------- qemu-system-ppc/8179 is trying to acquire lock: (&kvm->lock){+.+.+.}, at: [] .kvmppc_set_lpcr+0xf4/0x1c0 [kvm_hv] but task is already holding lock: (&(&vcore->lock)->rlock){+.+...}, at: [] .kvmppc_set_lpcr+0x40/0x1c0 [kvm_hv] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&(&vcore->lock)->rlock){+.+...}: [] .mutex_lock_nested+0x80/0x570 [] .kvmppc_vcpu_run_hv+0xc4/0xe40 [kvm_hv] [] .kvmppc_vcpu_run+0x2c/0x40 [kvm] [] .kvm_arch_vcpu_ioctl_run+0x54/0x160 [kvm] [] .kvm_vcpu_ioctl+0x4a8/0x7b0 [kvm] [] .do_vfs_ioctl+0x444/0x770 [] .SyS_ioctl+0xc4/0xe0 [] syscall_exit+0x0/0x98 -> #0 (&kvm->lock){+.+.+.}: [] .lock_acquire+0xcc/0x1a0 [] .mutex_lock_nested+0x80/0x570 [] .kvmppc_set_lpcr+0xf4/0x1c0 [kvm_hv] [] .kvmppc_set_one_reg_hv+0x4dc/0x990 [kvm_hv] [] .kvmppc_set_one_reg+0x44/0x330 [kvm] [] .kvm_vcpu_ioctl_set_one_reg+0x5c/0x150 [kvm] [] .kvm_arch_vcpu_ioctl+0x214/0x2c0 [kvm] [] .kvm_vcpu_ioctl+0xe0/0x7b0 [kvm] [] .do_vfs_ioctl+0x444/0x770 [] .SyS_ioctl+0xc4/0xe0 [] syscall_exit+0x0/0x98 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&(&vcore->lock)->rlock); lock(&kvm->lock); lock(&(&vcore->lock)->rlock); lock(&kvm->lock); *** DEADLOCK *** 2 locks held by qemu-system-ppc/8179: #0: (&vcpu->mutex){+.+.+.}, at: [] .vcpu_load+0x28/0x90 [kvm] #1: (&(&vcore->lock)->rlock){+.+...}, at: [] .kvmppc_set_lpcr+0x40/0x1c0 [kvm_hv] stack backtrace: CPU: 4 PID: 8179 Comm: qemu-system-ppc Not tainted 3.18.0-kvm-04645-gdfea862-dirty #131 Call Trace: [c000001a66c0f310] [c000000000b486ac] .dump_stack+0x88/0xb4 (unreliable) [c000001a66c0f390] [c0000000000f8bec] .print_circular_bug+0x27c/0x3d0 [c000001a66c0f440] [c0000000000fe9e8] .__lock_acquire+0x2028/0x2190 [c000001a66c0f5d0] [c0000000000ff28c] .lock_acquire+0xcc/0x1a0 [c000001a66c0f6a0] [c000000000b3c120] .mutex_lock_nested+0x80/0x570 [c000001a66c0f7c0] [d00000000ecc1f54] .kvmppc_set_lpcr+0xf4/0x1c0 [kvm_hv] [c000001a66c0f860] [d00000000ecc510c] .kvmppc_set_one_reg_hv+0x4dc/0x990 [kvm_hv] [c000001a66c0f8d0] [d00000000eb9f234] .kvmppc_set_one_reg+0x44/0x330 [kvm] [c000001a66c0f960] [d00000000eb9c9dc] .kvm_vcpu_ioctl_set_one_reg+0x5c/0x150 [kvm] [c000001a66c0f9f0] [d00000000eb9ced4] .kvm_arch_vcpu_ioctl+0x214/0x2c0 [kvm] [c000001a66c0faf0] [d00000000eb940b0] .kvm_vcpu_ioctl+0xe0/0x7b0 [kvm] [c000001a66c0fcb0] [c00000000026cbb4] .do_vfs_ioctl+0x444/0x770 [c000001a66c0fd90] [c00000000026cfa4] .SyS_ioctl+0xc4/0xe0 [c000001a66c0fe30] [c000000000009264] syscall_exit+0x0/0x98 This fixes it by moving the mutex_lock()/mutex_unlock() pair outside the spin-locked region. Signed-off-by: Paul Mackerras Signed-off-by: Alexander Graf --- arch/powerpc/kvm/book3s_hv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index de4018a1bc4b..b2731933f807 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -942,20 +942,20 @@ static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu, static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr, bool preserve_top32) { + struct kvm *kvm = vcpu->kvm; struct kvmppc_vcore *vc = vcpu->arch.vcore; u64 mask; + mutex_lock(&kvm->lock); spin_lock(&vc->lock); /* * If ILE (interrupt little-endian) has changed, update the * MSR_LE bit in the intr_msr for each vcpu in this vcore. */ if ((new_lpcr & LPCR_ILE) != (vc->lpcr & LPCR_ILE)) { - struct kvm *kvm = vcpu->kvm; struct kvm_vcpu *vcpu; int i; - mutex_lock(&kvm->lock); kvm_for_each_vcpu(i, vcpu, kvm) { if (vcpu->arch.vcore != vc) continue; @@ -964,7 +964,6 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr, else vcpu->arch.intr_msr &= ~MSR_LE; } - mutex_unlock(&kvm->lock); } /* @@ -981,6 +980,7 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr, mask &= 0xFFFFFFFF; vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask); spin_unlock(&vc->lock); + mutex_unlock(&kvm->lock); } static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, From ecb6d6185b3ae40067330eb889977bf2a51f7429 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 20 Mar 2015 20:39:39 +1100 Subject: [PATCH 187/567] KVM: PPC: Book3S HV: Endian fix for accessing VPA yield count The VPA (virtual processor area) is defined by PAPR and is therefore big-endian, so we need a be32_to_cpu when reading it in kvmppc_get_yield_count(). Without this, H_CONFER always fails on a little-endian host, causing SMP guests to waste time spinning on spinlocks. Signed-off-by: Paul Mackerras Signed-off-by: Alexander Graf --- arch/powerpc/kvm/book3s_hv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index b2731933f807..de747563d29d 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -636,7 +636,7 @@ static int kvmppc_get_yield_count(struct kvm_vcpu *vcpu) spin_lock(&vcpu->arch.vpa_update_lock); lppaca = (struct lppaca *)vcpu->arch.vpa.pinned_addr; if (lppaca) - yield_count = lppaca->yield_count; + yield_count = be32_to_cpu(lppaca->yield_count); spin_unlock(&vcpu->arch.vpa_update_lock); return yield_count; } From 2bf27601c7b50b6ced72f27304109dc52eb52919 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 20 Mar 2015 20:39:40 +1100 Subject: [PATCH 188/567] KVM: PPC: Book3S HV: Fix instruction emulation Commit 4a157d61b48c ("KVM: PPC: Book3S HV: Fix endianness of instruction obtained from HEIR register") had the side effect that we no longer reset vcpu->arch.last_inst to -1 on guest exit in the cases where the instruction is not fetched from the guest. This means that if instruction emulation turns out to be required in those cases, the host will emulate the wrong instruction, since vcpu->arch.last_inst will contain the last instruction that was emulated. This fixes it by making sure that vcpu->arch.last_inst is reset to -1 in those cases. Signed-off-by: Paul Mackerras Signed-off-by: Alexander Graf --- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index bb94e6f20c81..6cbf1630cb70 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1005,6 +1005,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) /* Save HEIR (HV emulation assist reg) in emul_inst if this is an HEI (HV emulation interrupt, e40) */ li r3,KVM_INST_FETCH_FAILED + stw r3,VCPU_LAST_INST(r9) cmpwi r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST bne 11f mfspr r3,SPRN_HEIR From 7ee8e4f3983c4ff700958a6099c8fd212ea67b94 Mon Sep 17 00:00:00 2001 From: Wenbo Wang Date: Fri, 20 Mar 2015 01:04:54 -0400 Subject: [PATCH 189/567] Fix bug in blk_rq_merge_ok Use the right array index to reference the last element of rq->biotail->bi_io_vec[] Signed-off-by: Wenbo Wang Reviewed-by: Chong Yuan Fixes: 66cb45aa41315 ("block: add support for limiting gaps in SG lists") Cc: stable@kernel.org Signed-off-by: Jens Axboe --- block/blk-merge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-merge.c b/block/blk-merge.c index fc1ff3b1ea1f..fd3fee81c23c 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -592,7 +592,7 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) if (q->queue_flags & (1 << QUEUE_FLAG_SG_GAPS)) { struct bio_vec *bprev; - bprev = &rq->biotail->bi_io_vec[bio->bi_vcnt - 1]; + bprev = &rq->biotail->bi_io_vec[rq->biotail->bi_vcnt - 1]; if (bvec_gap_to_prev(bprev, bio->bi_io_vec[0].bv_offset)) return false; } From 715a03d2848275269bd4014a49212cc83452f32d Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Fri, 20 Mar 2015 15:56:40 +0800 Subject: [PATCH 190/567] NFSD: restore trace event lost in mismerge 31ef83dc05 "nfsd: add trace events" had a typo that dropped a trace event and replaced it by an incorrect recursive call to nfsd4_cb_layout_fail. 133d558216d9 "Subject: nfsd: don't recursively call nfsd4_cb_layout_fail" fixed the crash, this restores the tracepoint. Reviewed-by: Christoph Hellwig Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4layouts.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 1028a0629543..0a616b51c5bb 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -587,6 +587,8 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls) rpc_ntop((struct sockaddr *)&clp->cl_addr, addr_str, sizeof(addr_str)); + trace_layout_recall_fail(&ls->ls_stid.sc_stateid); + printk(KERN_WARNING "nfsd: client %s failed to respond to layout recall. " " Fencing..\n", addr_str); From 6f8f28ec5f88715515e70dd52f16b326a5e63f81 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Thu, 19 Mar 2015 19:04:14 +0800 Subject: [PATCH 191/567] NFSD: Check layout type when returning client layouts According to RFC5661: " When lr_returntype is LAYOUTRETURN4_FSID, the current filehandle is used to identify the file system and all layouts matching the client ID, the fsid of the file system, lora_layout_type, and lora_iomode are returned. When lr_returntype is LAYOUTRETURN4_ALL, all layouts matching the client ID, lora_layout_type, and lora_iomode are returned and the current filehandle is not used. " When returning client layouts, always check layout type. Signed-off-by: Kinglong Mee Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4layouts.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 0a616b51c5bb..6964613bad90 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -513,6 +513,9 @@ nfsd4_return_client_layouts(struct svc_rqst *rqstp, spin_lock(&clp->cl_lock); list_for_each_entry_safe(ls, n, &clp->cl_lo_states, ls_perclnt) { + if (ls->ls_layout_type != lrp->lr_layout_type) + continue; + if (lrp->lr_return_type == RETURN_FSID && !fh_fsid_match(&ls->ls_stid.sc_file->fi_fhandle, &cstate->current_fh.fh_handle)) From db59c0ef08ca56758dcee6495d9d6a086682c5ec Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Thu, 19 Mar 2015 19:04:41 +0800 Subject: [PATCH 192/567] NFSD: Take care the return value from nfsd4_decode_stateid Return status after nfsd4_decode_stateid failed. Signed-off-by: Kinglong Mee Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index df5e66caf100..c76654c3605f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1562,7 +1562,11 @@ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, p = xdr_decode_hyper(p, &lgp->lg_seg.offset); p = xdr_decode_hyper(p, &lgp->lg_seg.length); p = xdr_decode_hyper(p, &lgp->lg_minlength); - nfsd4_decode_stateid(argp, &lgp->lg_sid); + + status = nfsd4_decode_stateid(argp, &lgp->lg_sid); + if (status) + return status; + READ_BUF(4); lgp->lg_maxcount = be32_to_cpup(p++); @@ -1580,7 +1584,11 @@ nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, p = xdr_decode_hyper(p, &lcp->lc_seg.offset); p = xdr_decode_hyper(p, &lcp->lc_seg.length); lcp->lc_reclaim = be32_to_cpup(p++); - nfsd4_decode_stateid(argp, &lcp->lc_sid); + + status = nfsd4_decode_stateid(argp, &lcp->lc_sid); + if (status) + return status; + READ_BUF(4); lcp->lc_newoffset = be32_to_cpup(p++); if (lcp->lc_newoffset) { @@ -1628,7 +1636,11 @@ nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, READ_BUF(16); p = xdr_decode_hyper(p, &lrp->lr_seg.offset); p = xdr_decode_hyper(p, &lrp->lr_seg.length); - nfsd4_decode_stateid(argp, &lrp->lr_sid); + + status = nfsd4_decode_stateid(argp, &lrp->lr_sid); + if (status) + return status; + READ_BUF(4); lrp->lrf_body_len = be32_to_cpup(p++); if (lrp->lrf_body_len > 0) { From a68465c9cb435feadb0efe6acbd0a9a7d1038465 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Thu, 19 Mar 2015 19:48:31 +0800 Subject: [PATCH 193/567] NFSD: Error out when register_shrinker() fail If register_shrinker() failed, nfsd will cause a NULL pointer access as, [ 9250.875465] nfsd: last server has exited, flushing export cache [ 9251.427270] BUG: unable to handle kernel NULL pointer dereference at (null) [ 9251.427393] IP: [] __list_del_entry+0x29/0xd0 [ 9251.427579] PGD 13e4d067 PUD 13e4c067 PMD 0 [ 9251.427633] Oops: 0000 [#1] SMP DEBUG_PAGEALLOC [ 9251.427706] Modules linked in: ip6t_rpfilter ip6t_REJECT bnep bluetooth xt_conntrack cfg80211 rfkill ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw btrfs xfs microcode ppdev serio_raw pcspkr xor libcrc32c raid6_pq e1000 parport_pc parport i2c_piix4 i2c_core nfsd(OE-) auth_rpcgss nfs_acl lockd sunrpc(E) ata_generic pata_acpi [ 9251.428240] CPU: 0 PID: 1557 Comm: rmmod Tainted: G OE 3.16.0-rc2+ #22 [ 9251.428366] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/31/2013 [ 9251.428496] task: ffff880000849540 ti: ffff8800136f4000 task.ti: ffff8800136f4000 [ 9251.428593] RIP: 0010:[] [] __list_del_entry+0x29/0xd0 [ 9251.428696] RSP: 0018:ffff8800136f7ea0 EFLAGS: 00010207 [ 9251.428751] RAX: 0000000000000000 RBX: ffffffffa0116d48 RCX: dead000000200200 [ 9251.428814] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffffa0116d48 [ 9251.428876] RBP: ffff8800136f7ea0 R08: ffff8800136f4000 R09: 0000000000000001 [ 9251.428939] R10: 8080808080808080 R11: 0000000000000000 R12: ffffffffa011a5a0 [ 9251.429002] R13: 0000000000000800 R14: 0000000000000000 R15: 00000000018ac090 [ 9251.429064] FS: 00007fb9acef0740(0000) GS:ffff88003fa00000(0000) knlGS:0000000000000000 [ 9251.429164] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 9251.429221] CR2: 0000000000000000 CR3: 0000000031a17000 CR4: 00000000001407f0 [ 9251.429306] Stack: [ 9251.429410] ffff8800136f7eb8 ffffffff8136fcdd ffffffffa0116d20 ffff8800136f7ed0 [ 9251.429511] ffffffff8118a0f2 0000000000000000 ffff8800136f7ee0 ffffffffa00eb765 [ 9251.429610] ffff8800136f7ef0 ffffffffa010e93c ffff8800136f7f78 ffffffff81104ac2 [ 9251.429709] Call Trace: [ 9251.429755] [] list_del+0xd/0x30 [ 9251.429896] [] unregister_shrinker+0x22/0x40 [ 9251.430037] [] nfsd_reply_cache_shutdown+0x15/0x90 [nfsd] [ 9251.430106] [] exit_nfsd+0x9/0x6cd [nfsd] [ 9251.430192] [] SyS_delete_module+0x162/0x200 [ 9251.430280] [] ? do_notify_resume+0x59/0x90 [ 9251.430395] [] system_call_fastpath+0x16/0x1b [ 9251.430457] Code: 00 00 55 48 8b 17 48 b9 00 01 10 00 00 00 ad de 48 8b 47 08 48 89 e5 48 39 ca 74 29 48 b9 00 02 20 00 00 00 ad de 48 39 c8 74 7a <4c> 8b 00 4c 39 c7 75 53 4c 8b 42 08 4c 39 c7 75 2b 48 89 42 08 [ 9251.430691] RIP [] __list_del_entry+0x29/0xd0 [ 9251.430755] RSP [ 9251.430805] CR2: 0000000000000000 [ 9251.431033] ---[ end trace 080f3050d082b4ea ]--- Signed-off-by: Kinglong Mee Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfscache.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 83a9694ec485..46ec934f5dee 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -165,13 +165,17 @@ int nfsd_reply_cache_init(void) { unsigned int hashsize; unsigned int i; + int status = 0; max_drc_entries = nfsd_cache_size_limit(); atomic_set(&num_drc_entries, 0); hashsize = nfsd_hashsize(max_drc_entries); maskbits = ilog2(hashsize); - register_shrinker(&nfsd_reply_cache_shrinker); + status = register_shrinker(&nfsd_reply_cache_shrinker); + if (status) + return status; + drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep), 0, 0, NULL); if (!drc_slab) From a736775db683174269c65c7c5cc8e5ee534e7681 Mon Sep 17 00:00:00 2001 From: Charlie Mooney Date: Fri, 20 Mar 2015 09:40:17 -0700 Subject: [PATCH 194/567] Input: add MT_TOOL_PALM Currently there are only two "tools" that can be specified by a multi-touch driver: MT_TOOL_FINGER and MT_TOOL_PEN. In working with Elan (The touch vendor) and discussing their next-gen devices it seems that it will be useful to have more tools so that their devices can give the upper layers of the stack hints as to what is touching the sensor. In particular they have new experimental firmware that can better differentiate between palms vs fingertips and would like to plumb a patch so that we can use their hints in higher-level gesture soft- ware. The firmware on the device can reasonably do a better job of palm detection because it has access to all of the raw sensor readings as opposed to just the width/pressure/etc that are exposed by the driver. As such, the firmware can characterize what a palm looks like in much finer-grained detail and this change would allow such a device to share its findings with the kernel. Signed-off-by: Charlie Mooney Acked-by: Peter Hutterer Signed-off-by: Dmitry Torokhov --- Documentation/input/multi-touch-protocol.txt | 9 ++++++--- include/uapi/linux/input.h | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/input/multi-touch-protocol.txt b/Documentation/input/multi-touch-protocol.txt index 7b4f59c09ee2..b85d000faeb4 100644 --- a/Documentation/input/multi-touch-protocol.txt +++ b/Documentation/input/multi-touch-protocol.txt @@ -312,9 +312,12 @@ ABS_MT_TOOL_TYPE The type of approaching tool. A lot of kernel drivers cannot distinguish between different tool types, such as a finger or a pen. In such cases, the -event should be omitted. The protocol currently supports MT_TOOL_FINGER and -MT_TOOL_PEN [2]. For type B devices, this event is handled by input core; -drivers should instead use input_mt_report_slot_state(). +event should be omitted. The protocol currently supports MT_TOOL_FINGER, +MT_TOOL_PEN, and MT_TOOL_PALM [2]. For type B devices, this event is handled +by input core; drivers should instead use input_mt_report_slot_state(). +A contact's ABS_MT_TOOL_TYPE may change over time while still touching the +device, because the firmware may not be able to determine which tool is being +used when it first appears. ABS_MT_BLOB_ID diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index a1d7e931ab72..2320b0ce7579 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -972,7 +972,8 @@ struct input_keymap_entry { */ #define MT_TOOL_FINGER 0 #define MT_TOOL_PEN 1 -#define MT_TOOL_MAX 1 +#define MT_TOOL_PALM 2 +#define MT_TOOL_MAX 2 /* * Values describing the status of a force-feedback effect From a1420384e3aa83b4ac8af85ae92d84f320272756 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Sun, 15 Mar 2015 23:12:15 +0800 Subject: [PATCH 195/567] NFSD: Put exports after nfsd4_layout_verify fail Fix commit 9cf514ccfa (nfsd: implement pNFS operations). Signed-off-by: Kinglong Mee Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index d30bea8d0277..92b9d97aff4f 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1237,8 +1237,8 @@ nfsd4_getdeviceinfo(struct svc_rqst *rqstp, nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb, gdp); gdp->gd_notify_types &= ops->notify_types; - exp_put(exp); out: + exp_put(exp); return nfserr; } From f93a25b38cbd840f26c9fd2dd8a6611a57b259b7 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Fri, 20 Mar 2015 22:18:17 +0100 Subject: [PATCH 196/567] brcmfmac: disable MBSS feature for BCM43362 The BCM43362 firmware falsely reports it is capable of providing MBSS. As a result AP mode no longer works for this device. Therefor disable MBSS in the driver for this chipset. Cc: stable@vger.kernel.org # 3.19.y Reported-by: Jorg Krause Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/feature.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/brcm80211/brcmfmac/feature.c index defb7a44e0bc..7748a1ccf14f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/feature.c @@ -126,7 +126,8 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan"); if (drvr->bus_if->wowl_supported) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); - brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0); + if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID) + brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0); /* set chip related quirks */ switch (drvr->bus_if->chip) { From 44a89c82feca565efd44b5aef1f1b99b93621d19 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 20 Mar 2015 19:14:50 +0530 Subject: [PATCH 197/567] ath9k: Fix AIC compilation error AIC needs to be registered only when BTCOEX is enabled. This fixes the error reported by kbuild: >> ERROR: "ar9003_hw_attach_aic_ops" [drivers/net/wireless/ath/ath9k/ath9k_hw.ko] undefined! Signed-off-by: Sujith Manoharan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c22edd3ce716..aaec9451de49 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1117,8 +1117,6 @@ void ar9003_hw_attach_calib_ops(struct ath_hw *ah); int ar9002_hw_attach_ops(struct ath_hw *ah); void ar9003_hw_attach_ops(struct ath_hw *ah); -void ar9003_hw_attach_aic_ops(struct ath_hw *ah); - void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); @@ -1129,6 +1127,7 @@ void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us); void ath9k_hw_setslottime(struct ath_hw *ah, u32 us); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT +void ar9003_hw_attach_aic_ops(struct ath_hw *ah); static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) { return ah->btcoex_hw.enabled; @@ -1146,6 +1145,9 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) return ah->btcoex_hw.scheme; } #else +static inline void ar9003_hw_attach_aic_ops(struct ath_hw *ah) +{ +} static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) { return false; From 2477bc58d49edb1c0baf59df7dc093dce682af2b Mon Sep 17 00:00:00 2001 From: Sachin Prabhu Date: Wed, 4 Feb 2015 13:10:26 +0000 Subject: [PATCH 198/567] cifs: smb2_clone_range() - exit on unhandled error While attempting to clone a file on a samba server, we receive a STATUS_INVALID_DEVICE_REQUEST. This is mapped to -EOPNOTSUPP which isn't handled in smb2_clone_range(). We end up looping in the while loop making same call to the samba server over and over again. The proposed fix is to exit and return the error value when encountered with an unhandled error. Cc: Signed-off-by: Sachin Prabhu Signed-off-by: Steve French Signed-off-by: Steve French --- fs/cifs/smb2ops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 96b5d40a2ece..eab05e1aa587 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -684,7 +684,8 @@ smb2_clone_range(const unsigned int xid, /* No need to change MaxChunks since already set to 1 */ chunk_sizes_updated = true; - } + } else + goto cchunk_out; } cchunk_out: From e1e9bda22d7ddf88515e8fe401887e313922823e Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 13 Mar 2015 14:20:29 +0100 Subject: [PATCH 199/567] cifs: fix use-after-free bug in find_writable_file Under intermittent network outages, find_writable_file() is susceptible to the following race condition, which results in a user-after-free in the cifs_writepages code-path: Thread 1 Thread 2 ======== ======== inv_file = NULL refind = 0 spin_lock(&cifs_file_list_lock) // invalidHandle found on openFileList inv_file = open_file // inv_file->count currently 1 cifsFileInfo_get(inv_file) // inv_file->count = 2 spin_unlock(&cifs_file_list_lock); cifs_reopen_file() cifs_close() // fails (rc != 0) ->cifsFileInfo_put() spin_lock(&cifs_file_list_lock) // inv_file->count = 1 spin_unlock(&cifs_file_list_lock) spin_lock(&cifs_file_list_lock); list_move_tail(&inv_file->flist, &cifs_inode->openFileList); spin_unlock(&cifs_file_list_lock); cifsFileInfo_put(inv_file); ->spin_lock(&cifs_file_list_lock) // inv_file->count = 0 list_del(&cifs_file->flist); // cleanup!! kfree(cifs_file); spin_unlock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock); ++refind; // refind = 1 goto refind_writable; At this point we loop back through with an invalid inv_file pointer and a refind value of 1. On second pass, inv_file is not overwritten on openFileList traversal, and is subsequently dereferenced. Signed-off-by: David Disseldorp Reviewed-by: Jeff Layton CC: Signed-off-by: Steve French --- fs/cifs/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index a94b3e673182..ca30c391a894 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1823,6 +1823,7 @@ refind_writable: cifsFileInfo_put(inv_file); spin_lock(&cifs_file_list_lock); ++refind; + inv_file = NULL; goto refind_writable; } } From 2bd50fb3d4d31f5168ecea221f291534cd0a96e9 Mon Sep 17 00:00:00 2001 From: Taesoo Kim Date: Sat, 21 Mar 2015 19:08:30 -0400 Subject: [PATCH 200/567] cifs: potential memory leaks when parsing mnt opts For example, when mount opt is redundently specified (e.g., "user=A,user=B,user=C"), kernel kept allocating new key/val with kstrdup() and overwrite previous ptr (to be freed). Althouhg mount.cifs in userspace performs a bit of sanitization (e.g., forcing one user option), current implementation is not robust. Other options such as iocharset and domainanme are similarly vulnerable. Signed-off-by: Taesoo Kim Signed-off-by: Steve French --- fs/cifs/connect.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d3aa999ab785..4cb8450e081b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1599,6 +1599,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, pr_warn("CIFS: username too long\n"); goto cifs_parse_mount_err; } + + kfree(vol->username); vol->username = kstrdup(string, GFP_KERNEL); if (!vol->username) goto cifs_parse_mount_err; @@ -1700,6 +1702,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, goto cifs_parse_mount_err; } + kfree(vol->domainname); vol->domainname = kstrdup(string, GFP_KERNEL); if (!vol->domainname) { pr_warn("CIFS: no memory for domainname\n"); @@ -1731,6 +1734,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, } if (strncasecmp(string, "default", 7) != 0) { + kfree(vol->iocharset); vol->iocharset = kstrdup(string, GFP_KERNEL); if (!vol->iocharset) { From be0b5e635883678bfbc695889772fed545f3427d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 21 Mar 2015 15:16:05 -0500 Subject: [PATCH 201/567] rtlwifi: Fix IOMMU mapping leak in AP mode Transmission of an AP beacon does not call the TX interrupt service routine, which usually does the cleanup. Instead, cleanup is handled in a tasklet completion routine. Unfortunately, this routine has a serious bug in that it does not release the DMA mapping before it frees the skb, thus one IOMMU mapping is leaked for each beacon. The test system failed with no free IOMMU mapping slots approximately one hour after hostapd was used to start an AP. This issue was reported and tested at https://github.com/lwfinger/rtlwifi_new/issues/30. Reported-and-tested-by: Kevin Mullican Cc: Kevin Mullican Signed-off-by: Shao Fu Signed-off-by: Larry Finger Cc: Stable [3.18+] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/pci.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index a62170ea0481..8c45cf44ce24 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1124,12 +1124,22 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) /*This is for new trx flow*/ struct rtl_tx_buffer_desc *pbuffer_desc = NULL; u8 temp_one = 1; + u8 *entry; memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); ring = &rtlpci->tx_ring[BEACON_QUEUE]; pskb = __skb_dequeue(&ring->queue); - if (pskb) + if (rtlpriv->use_new_trx_flow) + entry = (u8 *)(&ring->buffer_desc[ring->idx]); + else + entry = (u8 *)(&ring->desc[ring->idx]); + if (pskb) { + pci_unmap_single(rtlpci->pdev, + rtlpriv->cfg->ops->get_desc( + (u8 *)entry, true, HW_DESC_TXBUFF_ADDR), + pskb->len, PCI_DMA_TODEVICE); kfree_skb(pskb); + } /*NB: the beacon data buffer must be 32-bit aligned. */ pskb = ieee80211_beacon_get(hw, mac->vif); From 082d70b6142f623c10f7a032d9b63a2399fb4ded Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Sun, 15 Mar 2015 11:03:38 -0400 Subject: [PATCH 202/567] can: kvaser_usb: Comply with firmware max tx URBs value Current driver code arbitrarily assumes a max outstanding tx value of 16 parallel transmissions. Meanwhile, the device firmware provides its actual maximum inside its reply to the CMD_GET_SOFTWARE_INFO message. Under heavy tx traffic, if the interleaved transmissions count increases above the limit reported by firmware, the firmware breaks up badly, reports a massive list of internal errors, and the candump traces hardly matches the actual frames sent and received. On the other hand, in certain models, the firmware can support up to 48 tx URBs instead of just 16, increasing the driver throughput by two-fold and reducing the possibility of -ENOBUFs. Thus dynamically set the driver's max tx URBs value according to firmware replies. Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/kvaser_usb.c | 62 +++++++++++++++++++------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index e97a08ce0b90..2f9733a8e125 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -25,7 +25,6 @@ #include #include -#define MAX_TX_URBS 16 #define MAX_RX_URBS 4 #define START_TIMEOUT 1000 /* msecs */ #define STOP_TIMEOUT 1000 /* msecs */ @@ -443,6 +442,7 @@ struct kvaser_usb_error_summary { }; }; +/* Context for an outstanding, not yet ACKed, transmission */ struct kvaser_usb_tx_urb_context { struct kvaser_usb_net_priv *priv; u32 echo_index; @@ -456,8 +456,13 @@ struct kvaser_usb { struct usb_endpoint_descriptor *bulk_in, *bulk_out; struct usb_anchor rx_submitted; + /* @max_tx_urbs: Firmware-reported maximum number of oustanding, + * not yet ACKed, transmissions on this device. This value is + * also used as a sentinel for marking free tx contexts. + */ u32 fw_version; unsigned int nchannels; + unsigned int max_tx_urbs; enum kvaser_usb_family family; bool rxinitdone; @@ -467,19 +472,18 @@ struct kvaser_usb { struct kvaser_usb_net_priv { struct can_priv can; - - spinlock_t tx_contexts_lock; - int active_tx_contexts; - struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS]; - - struct usb_anchor tx_submitted; - struct completion start_comp, stop_comp; + struct can_berr_counter bec; struct kvaser_usb *dev; struct net_device *netdev; int channel; - struct can_berr_counter bec; + struct completion start_comp, stop_comp; + struct usb_anchor tx_submitted; + + spinlock_t tx_contexts_lock; + int active_tx_contexts; + struct kvaser_usb_tx_urb_context tx_contexts[]; }; static const struct usb_device_id kvaser_usb_table[] = { @@ -657,9 +661,13 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev) switch (dev->family) { case KVASER_LEAF: dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version); + dev->max_tx_urbs = + le16_to_cpu(msg.u.leaf.softinfo.max_outstanding_tx); break; case KVASER_USBCAN: dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version); + dev->max_tx_urbs = + le16_to_cpu(msg.u.usbcan.softinfo.max_outstanding_tx); break; } @@ -715,7 +723,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, stats = &priv->netdev->stats; - context = &priv->tx_contexts[tid % MAX_TX_URBS]; + context = &priv->tx_contexts[tid % dev->max_tx_urbs]; /* Sometimes the state change doesn't come after a bus-off event */ if (priv->can.restart_ms && @@ -744,7 +752,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, spin_lock_irqsave(&priv->tx_contexts_lock, flags); can_get_echo_skb(priv->netdev, context->echo_index); - context->echo_index = MAX_TX_URBS; + context->echo_index = dev->max_tx_urbs; --priv->active_tx_contexts; netif_wake_queue(priv->netdev); @@ -1512,11 +1520,13 @@ error: static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv) { - int i; + int i, max_tx_urbs; + + max_tx_urbs = priv->dev->max_tx_urbs; priv->active_tx_contexts = 0; - for (i = 0; i < MAX_TX_URBS; i++) - priv->tx_contexts[i].echo_index = MAX_TX_URBS; + for (i = 0; i < max_tx_urbs; i++) + priv->tx_contexts[i].echo_index = max_tx_urbs; } /* This method might sleep. Do not call it in the atomic context @@ -1702,14 +1712,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, *msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME; spin_lock_irqsave(&priv->tx_contexts_lock, flags); - for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) { - if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { + for (i = 0; i < dev->max_tx_urbs; i++) { + if (priv->tx_contexts[i].echo_index == dev->max_tx_urbs) { context = &priv->tx_contexts[i]; context->echo_index = i; can_put_echo_skb(skb, netdev, context->echo_index); ++priv->active_tx_contexts; - if (priv->active_tx_contexts >= MAX_TX_URBS) + if (priv->active_tx_contexts >= dev->max_tx_urbs) netif_stop_queue(netdev); break; @@ -1743,7 +1753,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, spin_lock_irqsave(&priv->tx_contexts_lock, flags); can_free_echo_skb(netdev, context->echo_index); - context->echo_index = MAX_TX_URBS; + context->echo_index = dev->max_tx_urbs; --priv->active_tx_contexts; netif_wake_queue(netdev); @@ -1881,7 +1891,9 @@ static int kvaser_usb_init_one(struct usb_interface *intf, if (err) return err; - netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS); + netdev = alloc_candev(sizeof(*priv) + + dev->max_tx_urbs * sizeof(*priv->tx_contexts), + dev->max_tx_urbs); if (!netdev) { dev_err(&intf->dev, "Cannot alloc candev\n"); return -ENOMEM; @@ -2009,6 +2021,13 @@ static int kvaser_usb_probe(struct usb_interface *intf, return err; } + dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n", + ((dev->fw_version >> 24) & 0xff), + ((dev->fw_version >> 16) & 0xff), + (dev->fw_version & 0xffff)); + + dev_dbg(&intf->dev, "Max oustanding tx = %d URBs\n", dev->max_tx_urbs); + err = kvaser_usb_get_card_info(dev); if (err) { dev_err(&intf->dev, @@ -2016,11 +2035,6 @@ static int kvaser_usb_probe(struct usb_interface *intf, return err; } - dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n", - ((dev->fw_version >> 24) & 0xff), - ((dev->fw_version >> 16) & 0xff), - (dev->fw_version & 0xffff)); - for (i = 0; i < dev->nchannels; i++) { err = kvaser_usb_init_one(intf, id, i); if (err) { From 7e184c28636dce594426cd7d8781d52d1dd447cd Mon Sep 17 00:00:00 2001 From: "Ahmed S. Darwish" Date: Sun, 15 Mar 2015 11:10:49 -0400 Subject: [PATCH 203/567] can: kvaser_usb: Fix sparse warning __le16 degrades to integer USB endpoint's wMaxPacketSize field is an le16 entity. Use appropriate le16_to_cpu macros to maintain endian independence. Reported-by: Marc Kleine-Budde Signed-off-by: Ahmed S. Darwish Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/kvaser_usb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 2f9733a8e125..57611fd91229 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -596,8 +596,8 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, * for further details. */ if (tmp->len == 0) { - pos = round_up(pos, - dev->bulk_in->wMaxPacketSize); + pos = round_up(pos, le16_to_cpu(dev->bulk_in-> + wMaxPacketSize)); continue; } @@ -1337,7 +1337,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb) * number of events in case of a heavy rx load on the bus. */ if (msg->len == 0) { - pos = round_up(pos, dev->bulk_in->wMaxPacketSize); + pos = round_up(pos, le16_to_cpu(dev->bulk_in-> + wMaxPacketSize)); continue; } From 37920a74abd6fdf0696730ba80a07843a62c9c54 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 16 Mar 2015 22:42:24 +0000 Subject: [PATCH 204/567] can: gs_usb: check for kzalloc allocation failure smatch detected the following issue: drivers/net/can/usb/gs_usb.c:904 gs_usb_probe() error: potential null dereference 'dev'. (kzalloc returns null) Add a check for null return from kzalloc and return -ENOMEM Signed-off-by: Colin Ian King Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/gs_usb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 009acc8641fc..8b4d3e6875eb 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -901,6 +901,8 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id * } dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; init_usb_anchor(&dev->rx_submitted); atomic_set(&dev->active_channels, 0); From 3ef5247e033972ddbd16f65ec2ad8a7dfc2e4170 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Mon, 16 Mar 2015 11:57:52 +0100 Subject: [PATCH 205/567] can: peak_usb: rename usb option cmds definition and structs The PUCAN_CMD_RX_FRAME_(ENABLE|DISABLE) command has extended its purpose and was therefore renamed to PUCAN_CMD_SET_(EN|DIS)_OPTION. Signed-off-by: Stephane Grosjean Signed-off-by: Oliver Hartkopp Tested-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_ucan.h | 14 ++++---- drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 42 +++++++++++----------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/net/can/usb/peak_usb/pcan_ucan.h b/drivers/net/can/usb/peak_usb/pcan_ucan.h index 1ba7c25002e1..1fb33307be4e 100644 --- a/drivers/net/can/usb/peak_usb/pcan_ucan.h +++ b/drivers/net/can/usb/peak_usb/pcan_ucan.h @@ -26,8 +26,8 @@ #define PUCAN_CMD_FILTER_STD 0x008 #define PUCAN_CMD_TX_ABORT 0x009 #define PUCAN_CMD_WR_ERR_CNT 0x00a -#define PUCAN_CMD_RX_FRAME_ENABLE 0x00b -#define PUCAN_CMD_RX_FRAME_DISABLE 0x00c +#define PUCAN_CMD_SET_EN_OPTION 0x00b +#define PUCAN_CMD_CLR_DIS_OPTION 0x00c #define PUCAN_CMD_END_OF_COLLECTION 0x3ff /* uCAN received messages list */ @@ -101,14 +101,14 @@ struct __packed pucan_wr_err_cnt { u16 unused; }; -/* uCAN RX_FRAME_ENABLE command fields */ -#define PUCAN_FLTEXT_ERROR 0x0001 -#define PUCAN_FLTEXT_BUSLOAD 0x0002 +/* uCAN SET_EN/CLR_DIS _OPTION command fields */ +#define PUCAN_OPTION_ERROR 0x0001 +#define PUCAN_OPTION_BUSLOAD 0x0002 -struct __packed pucan_filter_ext { +struct __packed pucan_options { __le16 opcode_channel; - __le16 ext_mask; + __le16 options; u32 unused; }; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 0bac0f14edc3..7506a8352edd 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -110,13 +110,13 @@ struct __packed pcan_ufd_led { u8 unused[5]; }; -/* Extended usage of uCAN commands CMD_RX_FRAME_xxxABLE for PCAN-USB Pro FD */ +/* Extended usage of uCAN commands CMD_xxx_xx_OPTION for PCAN-USB Pro FD */ #define PCAN_UFD_FLTEXT_CALIBRATION 0x8000 -struct __packed pcan_ufd_filter_ext { +struct __packed pcan_ufd_options { __le16 opcode_channel; - __le16 ext_mask; + __le16 ucan_mask; u16 unused; __le16 usb_mask; }; @@ -321,21 +321,21 @@ static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx, return pcan_usb_fd_send_cmd(dev, cmd); } -/* set/unset notifications filter: +/* set/unset options * - * onoff sets(1)/unset(0) notifications - * mask each bit defines a kind of notification to set/unset + * onoff set(1)/unset(0) options + * mask each bit defines a kind of options to set/unset */ -static int pcan_usb_fd_set_filter_ext(struct peak_usb_device *dev, - bool onoff, u16 ext_mask, u16 usb_mask) +static int pcan_usb_fd_set_options(struct peak_usb_device *dev, + bool onoff, u16 ucan_mask, u16 usb_mask) { - struct pcan_ufd_filter_ext *cmd = pcan_usb_fd_cmd_buffer(dev); + struct pcan_ufd_options *cmd = pcan_usb_fd_cmd_buffer(dev); cmd->opcode_channel = pucan_cmd_opcode_channel(dev, - (onoff) ? PUCAN_CMD_RX_FRAME_ENABLE : - PUCAN_CMD_RX_FRAME_DISABLE); + (onoff) ? PUCAN_CMD_SET_EN_OPTION : + PUCAN_CMD_CLR_DIS_OPTION); - cmd->ext_mask = cpu_to_le16(ext_mask); + cmd->ucan_mask = cpu_to_le16(ucan_mask); cmd->usb_mask = cpu_to_le16(usb_mask); /* send the command */ @@ -770,9 +770,9 @@ static int pcan_usb_fd_start(struct peak_usb_device *dev) &pcan_usb_pro_fd); /* enable USB calibration messages */ - err = pcan_usb_fd_set_filter_ext(dev, 1, - PUCAN_FLTEXT_ERROR, - PCAN_UFD_FLTEXT_CALIBRATION); + err = pcan_usb_fd_set_options(dev, 1, + PUCAN_OPTION_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); } pdev->usb_if->dev_opened_count++; @@ -806,9 +806,9 @@ static int pcan_usb_fd_stop(struct peak_usb_device *dev) /* turn off special msgs for that interface if no other dev opened */ if (pdev->usb_if->dev_opened_count == 1) - pcan_usb_fd_set_filter_ext(dev, 0, - PUCAN_FLTEXT_ERROR, - PCAN_UFD_FLTEXT_CALIBRATION); + pcan_usb_fd_set_options(dev, 0, + PUCAN_OPTION_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); pdev->usb_if->dev_opened_count--; return 0; @@ -937,9 +937,9 @@ static void pcan_usb_fd_exit(struct peak_usb_device *dev) if (dev->ctrl_idx == 0) { /* turn off calibration message if any device were opened */ if (pdev->usb_if->dev_opened_count > 0) - pcan_usb_fd_set_filter_ext(dev, 0, - PUCAN_FLTEXT_ERROR, - PCAN_UFD_FLTEXT_CALIBRATION); + pcan_usb_fd_set_options(dev, 0, + PUCAN_OPTION_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); /* tell USB adapter that the driver is being unloaded */ pcan_usb_fd_drv_loaded(dev, 0); From 0f251e45c7cbb1a494b5600485ea8ff64f664b3f Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Mon, 16 Mar 2015 11:57:53 +0100 Subject: [PATCH 206/567] can: peak_usb_fd: add support for ISO / non-ISO mode switching The PCAN USB (pro) FD adapters with firmware versions > 2.x support the switching between ISO (default) and non-ISO conform bitstreams on the CAN bus. The setting for the 2.x firmware adapters can be modified with the 'ip' tool from the iproute2 package (option: fd-non-iso [on|off]). Signed-off-by: Stephane Grosjean Signed-off-by: Oliver Hartkopp Tested-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_ucan.h | 1 + drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 31 ++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/usb/peak_usb/pcan_ucan.h b/drivers/net/can/usb/peak_usb/pcan_ucan.h index 1fb33307be4e..e8fc4952c6b0 100644 --- a/drivers/net/can/usb/peak_usb/pcan_ucan.h +++ b/drivers/net/can/usb/peak_usb/pcan_ucan.h @@ -104,6 +104,7 @@ struct __packed pucan_wr_err_cnt { /* uCAN SET_EN/CLR_DIS _OPTION command fields */ #define PUCAN_OPTION_ERROR 0x0001 #define PUCAN_OPTION_BUSLOAD 0x0002 +#define PUCAN_OPTION_CANDFDISO 0x0004 struct __packed pucan_options { __le16 opcode_channel; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 7506a8352edd..a9221ad9f1a0 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -251,6 +251,27 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf) /* moves the pointer forward */ pc += sizeof(struct pucan_wr_err_cnt); + /* add command to switch from ISO to non-ISO mode, if fw allows it */ + if (dev->can.ctrlmode_supported & CAN_CTRLMODE_FD_NON_ISO) { + struct pucan_options *puo = (struct pucan_options *)pc; + + puo->opcode_channel = + (dev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) ? + pucan_cmd_opcode_channel(dev, + PUCAN_CMD_CLR_DIS_OPTION) : + pucan_cmd_opcode_channel(dev, PUCAN_CMD_SET_EN_OPTION); + + puo->options = cpu_to_le16(PUCAN_OPTION_CANDFDISO); + + /* to be sure that no other extended bits will be taken into + * account + */ + puo->unused = 0; + + /* moves the pointer forward */ + pc += sizeof(struct pucan_options); + } + /* next, go back to operational mode */ cmd = (struct pucan_command *)pc; cmd->opcode_channel = pucan_cmd_opcode_channel(dev, @@ -860,8 +881,14 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev) pdev->usb_if->fw_info.fw_version[2], dev->adapter->ctrl_count); - /* the currently supported hw is non-ISO */ - dev->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO; + /* check for ability to switch between ISO/non-ISO modes */ + if (pdev->usb_if->fw_info.fw_version[0] >= 2) { + /* firmware >= 2.x supports ISO/non-ISO switching */ + dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO; + } else { + /* firmware < 2.x only supports fixed(!) non-ISO */ + dev->can.ctrlmode |= CAN_CTRLMODE_FD_NON_ISO; + } /* tell the hardware the can driver is running */ err = pcan_usb_fd_drv_loaded(dev, 1); From 258ce80e19211f06c97a562a71308ec21a9ab98f Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Tue, 17 Mar 2015 13:03:09 +0000 Subject: [PATCH 207/567] can: flexcan: fix bus-off error state handling. Making sure that the bus-off state gets passed to can_change_state(). Signed-off-by: Andri Yngvason Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 80c46ad4cee4..ee944ae6bb96 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -592,13 +592,12 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr) rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ? CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE; new_state = max(tx_state, rx_state); - } else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE)) { + } else { __flexcan_get_berr_counter(dev, &bec); - new_state = CAN_STATE_ERROR_PASSIVE; + new_state = flt == FLEXCAN_ESR_FLT_CONF_PASSIVE ? + CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF; rx_state = bec.rxerr >= bec.txerr ? new_state : 0; tx_state = bec.rxerr <= bec.txerr ? new_state : 0; - } else { - new_state = CAN_STATE_BUS_OFF; } /* state hasn't changed */ From 555828ef45f825d6ee06559f0304163550eed380 Mon Sep 17 00:00:00 2001 From: Andreas Werner Date: Sun, 22 Mar 2015 17:35:52 +0100 Subject: [PATCH 208/567] can: flexcan: Deferred on Regulator return EPROBE_DEFER Return EPROBE_DEFER if Regulator returns EPROBE_DEFER If the Flexcan driver is built into kernel and a regulator is used to enable the CAN transceiver, the Flexcan driver may not use the regulator. When initializing the Flexcan device with a regulator defined in the device tree, but not initialized, the regulator subsystem returns EPROBE_DEFER, hence the Flexcan init fails. The solution for this is to return EPROBE_DEFER if regulator is not initialized and wait until the regulator is initialized. Signed-off-by: Andreas Werner Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index ee944ae6bb96..ad0a7e8c2c2b 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -1157,12 +1157,19 @@ static int flexcan_probe(struct platform_device *pdev) const struct flexcan_devtype_data *devtype_data; struct net_device *dev; struct flexcan_priv *priv; + struct regulator *reg_xceiver; struct resource *mem; struct clk *clk_ipg = NULL, *clk_per = NULL; void __iomem *base; int err, irq; u32 clock_freq = 0; + reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver"); + if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else if (IS_ERR(reg_xceiver)) + reg_xceiver = NULL; + if (pdev->dev.of_node) of_property_read_u32(pdev->dev.of_node, "clock-frequency", &clock_freq); @@ -1223,9 +1230,7 @@ static int flexcan_probe(struct platform_device *pdev) priv->pdata = dev_get_platdata(&pdev->dev); priv->devtype_data = devtype_data; - priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver"); - if (IS_ERR(priv->reg_xceiver)) - priv->reg_xceiver = NULL; + priv->reg_xceiver = reg_xceiver; netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT); From 44d5f6f5901e996744858c175baee320ccf1eda3 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Tue, 17 Mar 2015 16:14:41 +0530 Subject: [PATCH 209/567] powerpc/book3s: Fix the MCE code to use CONFIG_KVM_BOOK3S_64_HANDLER commit id 2ba9f0d has changed CONFIG_KVM_BOOK3S_64_HV to tristate to allow HV/PR bits to be built as modules. But the MCE code still depends on CONFIG_KVM_BOOK3S_64_HV which is wrong. When user selects CONFIG_KVM_BOOK3S_64_HV=m to build HV/PR bits as a separate module the relevant MCE code gets excluded. This patch fixes the MCE code to use CONFIG_KVM_BOOK3S_64_HANDLER. This makes sure that the relevant MCE code is included when HV/PR bits are built as a separate modules. Fixes: 2ba9f0d88750 ("kvm: powerpc: book3s: Support building HV and PR KVM as module") Cc: stable@vger.kernel.org # v3.14+ Signed-off-by: Mahesh Salgaonkar Acked-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/exceptions-64s.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index c2df8150bd7a..9519e6bdc6d7 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1408,7 +1408,7 @@ machine_check_handle_early: bne 9f /* continue in V mode if we are. */ 5: -#ifdef CONFIG_KVM_BOOK3S_64_HV +#ifdef CONFIG_KVM_BOOK3S_64_HANDLER /* * We are coming from kernel context. Check if we are coming from * guest. if yes, then we can continue. We will fall through From d525211f9d1be8b523ec7633f080f2116f5ea536 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 19 Feb 2015 18:03:11 +0100 Subject: [PATCH 210/567] perf: Fix irq_work 'tail' recursion Vince reported a watchdog lockup like: [] perf_tp_event+0xc4/0x210 [] perf_trace_lock+0x12a/0x160 [] lock_release+0x130/0x260 [] _raw_spin_unlock_irqrestore+0x24/0x40 [] do_send_sig_info+0x5d/0x80 [] send_sigio_to_task+0x12f/0x1a0 [] send_sigio+0xae/0x100 [] kill_fasync+0x97/0xf0 [] perf_event_wakeup+0xd4/0xf0 [] perf_pending_event+0x33/0x60 [] irq_work_run_list+0x4c/0x80 [] irq_work_run+0x18/0x40 [] smp_trace_irq_work_interrupt+0x3f/0xc0 [] trace_irq_work_interrupt+0x6d/0x80 Which is caused by an irq_work generating new irq_work and therefore not allowing forward progress. This happens because processing the perf irq_work triggers another perf event (tracepoint stuff) which in turn generates an irq_work ad infinitum. Avoid this by raising the recursion counter in the irq_work -- which effectively disables all software events (including tracepoints) from actually triggering again. Reported-by: Vince Weaver Tested-by: Vince Weaver Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Paul Mackerras Cc: Steven Rostedt Cc: Link: http://lkml.kernel.org/r/20150219170311.GH21418@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- kernel/events/core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index 453ef61311d4..2fabc0627165 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4574,6 +4574,13 @@ static void perf_pending_event(struct irq_work *entry) { struct perf_event *event = container_of(entry, struct perf_event, pending); + int rctx; + + rctx = perf_swevent_get_recursion_context(); + /* + * If we 'fail' here, that's OK, it means recursion is already disabled + * and we won't recurse 'further'. + */ if (event->pending_disable) { event->pending_disable = 0; @@ -4584,6 +4591,9 @@ static void perf_pending_event(struct irq_work *entry) event->pending_wakeup = 0; perf_event_wakeup(event); } + + if (rctx >= 0) + perf_swevent_put_recursion_context(rctx); } /* From 746db9443ea57fd9c059f62c4bfbf41cf224fe13 Mon Sep 17 00:00:00 2001 From: Brian Silverman Date: Wed, 18 Feb 2015 16:23:56 -0800 Subject: [PATCH 211/567] sched: Fix RLIMIT_RTTIME when PI-boosting to RT When non-realtime tasks get priority-inheritance boosted to a realtime scheduling class, RLIMIT_RTTIME starts to apply to them. However, the counter used for checking this (the same one used for SCHED_RR timeslices) was not getting reset. This meant that tasks running with a non-realtime scheduling class which are repeatedly boosted to a realtime one, but never block while they are running realtime, eventually hit the timeout without ever running for a time over the limit. This patch resets the realtime timeslice counter when un-PI-boosting from an RT to a non-RT scheduling class. I have some test code with two threads and a shared PTHREAD_PRIO_INHERIT mutex which induces priority boosting and spins while boosted that gets killed by a SIGXCPU on non-fixed kernels but doesn't with this patch applied. It happens much faster with a CONFIG_PREEMPT_RT kernel, and does happen eventually with PREEMPT_VOLUNTARY kernels. Signed-off-by: Brian Silverman Signed-off-by: Peter Zijlstra (Intel) Cc: austin@peloton-tech.com Cc: Link: http://lkml.kernel.org/r/1424305436-6716-1-git-send-email-brian@peloton-tech.com Signed-off-by: Ingo Molnar --- kernel/sched/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f0f831e8a345..62671f53202a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3034,6 +3034,8 @@ void rt_mutex_setprio(struct task_struct *p, int prio) } else { if (dl_prio(oldprio)) p->dl.dl_boosted = 0; + if (rt_prio(oldprio)) + p->rt.timeout = 0; p->sched_class = &fair_sched_class; } From 35a9393c95b31870a74f51a3e7455f33f5657b6f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 26 Feb 2015 16:23:11 +0100 Subject: [PATCH 212/567] lockdep: Fix the module unload key range freeing logic Module unload calls lockdep_free_key_range(), which removes entries from the data structures. Most of the lockdep code OTOH assumes the data structures are append only; in specific see the comments in add_lock_to_list() and look_up_lock_class(). Clearly this has only worked by accident; make it work proper. The actual scenario to make it go boom would involve the memory freed by the module unlock being re-allocated and re-used for a lock inside of a rcu-sched grace period. This is a very unlikely scenario, still better plug the hole. Use RCU list iteration in all places and ammend the comments. Change lockdep_free_key_range() to issue a sync_sched() between removal from the lists and returning -- which results in the memory being freed. Further ensure the callers are placed correctly and comment the requirements. Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Andrey Tsyvarev Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Rusty Russell Cc: Thomas Gleixner Signed-off-by: Ingo Molnar --- kernel/locking/lockdep.c | 81 +++++++++++++++++++++++++++------------- kernel/module.c | 8 ++-- 2 files changed, 59 insertions(+), 30 deletions(-) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 88d0d4420ad2..ba77ab5f64dd 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -633,7 +633,7 @@ static int count_matching_names(struct lock_class *new_class) if (!new_class->name) return 0; - list_for_each_entry(class, &all_lock_classes, lock_entry) { + list_for_each_entry_rcu(class, &all_lock_classes, lock_entry) { if (new_class->key - new_class->subclass == class->key) return class->name_version; if (class->name && !strcmp(class->name, new_class->name)) @@ -700,10 +700,12 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass) hash_head = classhashentry(key); /* - * We can walk the hash lockfree, because the hash only - * grows, and we are careful when adding entries to the end: + * We do an RCU walk of the hash, see lockdep_free_key_range(). */ - list_for_each_entry(class, hash_head, hash_entry) { + if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) + return NULL; + + list_for_each_entry_rcu(class, hash_head, hash_entry) { if (class->key == key) { /* * Huh! same key, different name? Did someone trample @@ -728,7 +730,8 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) struct lockdep_subclass_key *key; struct list_head *hash_head; struct lock_class *class; - unsigned long flags; + + DEBUG_LOCKS_WARN_ON(!irqs_disabled()); class = look_up_lock_class(lock, subclass); if (likely(class)) @@ -750,28 +753,26 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) key = lock->key->subkeys + subclass; hash_head = classhashentry(key); - raw_local_irq_save(flags); if (!graph_lock()) { - raw_local_irq_restore(flags); return NULL; } /* * We have to do the hash-walk again, to avoid races * with another CPU: */ - list_for_each_entry(class, hash_head, hash_entry) + list_for_each_entry_rcu(class, hash_head, hash_entry) { if (class->key == key) goto out_unlock_set; + } + /* * Allocate a new key from the static array, and add it to * the hash: */ if (nr_lock_classes >= MAX_LOCKDEP_KEYS) { if (!debug_locks_off_graph_unlock()) { - raw_local_irq_restore(flags); return NULL; } - raw_local_irq_restore(flags); print_lockdep_off("BUG: MAX_LOCKDEP_KEYS too low!"); dump_stack(); @@ -798,7 +799,6 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) if (verbose(class)) { graph_unlock(); - raw_local_irq_restore(flags); printk("\nnew class %p: %s", class->key, class->name); if (class->name_version > 1) @@ -806,15 +806,12 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force) printk("\n"); dump_stack(); - raw_local_irq_save(flags); if (!graph_lock()) { - raw_local_irq_restore(flags); return NULL; } } out_unlock_set: graph_unlock(); - raw_local_irq_restore(flags); out_set_class_cache: if (!subclass || force) @@ -870,11 +867,9 @@ static int add_lock_to_list(struct lock_class *class, struct lock_class *this, entry->distance = distance; entry->trace = *trace; /* - * Since we never remove from the dependency list, the list can - * be walked lockless by other CPUs, it's only allocation - * that must be protected by the spinlock. But this also means - * we must make new entries visible only once writes to the - * entry become visible - hence the RCU op: + * Both allocation and removal are done under the graph lock; but + * iteration is under RCU-sched; see look_up_lock_class() and + * lockdep_free_key_range(). */ list_add_tail_rcu(&entry->entry, head); @@ -1025,7 +1020,9 @@ static int __bfs(struct lock_list *source_entry, else head = &lock->class->locks_before; - list_for_each_entry(entry, head, entry) { + DEBUG_LOCKS_WARN_ON(!irqs_disabled()); + + list_for_each_entry_rcu(entry, head, entry) { if (!lock_accessed(entry)) { unsigned int cq_depth; mark_lock_accessed(entry, lock); @@ -2022,7 +2019,7 @@ static inline int lookup_chain_cache(struct task_struct *curr, * We can walk it lock-free, because entries only get added * to the hash: */ - list_for_each_entry(chain, hash_head, entry) { + list_for_each_entry_rcu(chain, hash_head, entry) { if (chain->chain_key == chain_key) { cache_hit: debug_atomic_inc(chain_lookup_hits); @@ -2996,8 +2993,18 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name, if (unlikely(!debug_locks)) return; - if (subclass) + if (subclass) { + unsigned long flags; + + if (DEBUG_LOCKS_WARN_ON(current->lockdep_recursion)) + return; + + raw_local_irq_save(flags); + current->lockdep_recursion = 1; register_lock_class(lock, subclass, 1); + current->lockdep_recursion = 0; + raw_local_irq_restore(flags); + } } EXPORT_SYMBOL_GPL(lockdep_init_map); @@ -3887,9 +3894,17 @@ static inline int within(const void *addr, void *start, unsigned long size) return addr >= start && addr < start + size; } +/* + * Used in module.c to remove lock classes from memory that is going to be + * freed; and possibly re-used by other modules. + * + * We will have had one sync_sched() before getting here, so we're guaranteed + * nobody will look up these exact classes -- they're properly dead but still + * allocated. + */ void lockdep_free_key_range(void *start, unsigned long size) { - struct lock_class *class, *next; + struct lock_class *class; struct list_head *head; unsigned long flags; int i; @@ -3905,7 +3920,7 @@ void lockdep_free_key_range(void *start, unsigned long size) head = classhash_table + i; if (list_empty(head)) continue; - list_for_each_entry_safe(class, next, head, hash_entry) { + list_for_each_entry_rcu(class, head, hash_entry) { if (within(class->key, start, size)) zap_class(class); else if (within(class->name, start, size)) @@ -3916,11 +3931,25 @@ void lockdep_free_key_range(void *start, unsigned long size) if (locked) graph_unlock(); raw_local_irq_restore(flags); + + /* + * Wait for any possible iterators from look_up_lock_class() to pass + * before continuing to free the memory they refer to. + * + * sync_sched() is sufficient because the read-side is IRQ disable. + */ + synchronize_sched(); + + /* + * XXX at this point we could return the resources to the pool; + * instead we leak them. We would need to change to bitmap allocators + * instead of the linear allocators we have now. + */ } void lockdep_reset_lock(struct lockdep_map *lock) { - struct lock_class *class, *next; + struct lock_class *class; struct list_head *head; unsigned long flags; int i, j; @@ -3948,7 +3977,7 @@ void lockdep_reset_lock(struct lockdep_map *lock) head = classhash_table + i; if (list_empty(head)) continue; - list_for_each_entry_safe(class, next, head, hash_entry) { + list_for_each_entry_rcu(class, head, hash_entry) { int match = 0; for (j = 0; j < NR_LOCKDEP_CACHING_CLASSES; j++) diff --git a/kernel/module.c b/kernel/module.c index b3d634ed06c9..99fdf94efce8 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1865,7 +1865,7 @@ static void free_module(struct module *mod) kfree(mod->args); percpu_modfree(mod); - /* Free lock-classes: */ + /* Free lock-classes; relies on the preceding sync_rcu(). */ lockdep_free_key_range(mod->module_core, mod->core_size); /* Finally, free the core (containing the module structure) */ @@ -3349,9 +3349,6 @@ static int load_module(struct load_info *info, const char __user *uargs, module_bug_cleanup(mod); mutex_unlock(&module_mutex); - /* Free lock-classes: */ - lockdep_free_key_range(mod->module_core, mod->core_size); - /* we can't deallocate the module until we clear memory protection */ unset_module_init_ro_nx(mod); unset_module_core_ro_nx(mod); @@ -3375,6 +3372,9 @@ static int load_module(struct load_info *info, const char __user *uargs, synchronize_rcu(); mutex_unlock(&module_mutex); free_module: + /* Free lock-classes; relies on the preceding sync_rcu() */ + lockdep_free_key_range(mod->module_core, mod->core_size); + module_deallocate(mod, info); free_copy: free_copy(info); From a127d2bcf1fbc8c8e0b5cf0dab54f7d3ff50ce47 Mon Sep 17 00:00:00 2001 From: Preeti U Murthy Date: Wed, 18 Mar 2015 16:19:27 +0530 Subject: [PATCH 213/567] timers/tick/broadcast-hrtimer: Fix suspicious RCU usage in idle loop The hrtimer mode of broadcast queues hrtimers in the idle entry path so as to wakeup cpus in deep idle states. The associated call graph is : cpuidle_idle_call() |____ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, ....)) |_____tick_broadcast_set_event() |____clockevents_program_event() |____bc_set_next() The hrtimer_{start/cancel} functions call into tracing which uses RCU. But it is not legal to call into RCU in cpuidle because it is one of the quiescent states. Hence protect this region with RCU_NONIDLE which informs RCU that the cpu is momentarily non-idle. As an aside it is helpful to point out that the clock event device that is programmed here is not a per-cpu clock device; it is a pseudo clock device, used by the broadcast framework alone. The per-cpu clock device programming never goes through bc_set_next(). Signed-off-by: Preeti U Murthy Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Paul E. McKenney Cc: linuxppc-dev@ozlabs.org Cc: mpe@ellerman.id.au Cc: tglx@linutronix.de Link: http://lkml.kernel.org/r/20150318104705.17763.56668.stgit@preeti.in.ibm.com Signed-off-by: Ingo Molnar --- kernel/time/tick-broadcast-hrtimer.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/time/tick-broadcast-hrtimer.c b/kernel/time/tick-broadcast-hrtimer.c index eb682d5c697c..6aac4beedbbe 100644 --- a/kernel/time/tick-broadcast-hrtimer.c +++ b/kernel/time/tick-broadcast-hrtimer.c @@ -49,6 +49,7 @@ static void bc_set_mode(enum clock_event_mode mode, */ static int bc_set_next(ktime_t expires, struct clock_event_device *bc) { + int bc_moved; /* * We try to cancel the timer first. If the callback is on * flight on some other cpu then we let it handle it. If we @@ -60,9 +61,15 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc) * restart the timer because we are in the callback, but we * can set the expiry time and let the callback return * HRTIMER_RESTART. + * + * Since we are in the idle loop at this point and because + * hrtimer_{start/cancel} functions call into tracing, + * calls to these functions must be bound within RCU_NONIDLE. */ - if (hrtimer_try_to_cancel(&bctimer) >= 0) { - hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED); + RCU_NONIDLE(bc_moved = (hrtimer_try_to_cancel(&bctimer) >= 0) ? + !hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED) : + 0); + if (bc_moved) { /* Bind the "device" to the cpu */ bc->bound_on = smp_processor_id(); } else if (bc->bound_on == smp_processor_id()) { From 47514da3ac20150cdf764466fbc2010c0fca0163 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 15 Mar 2015 21:32:12 +0100 Subject: [PATCH 214/567] parisc: Add compile-time check when adding new syscalls Signed-off-by: Helge Deller --- arch/parisc/kernel/syscall_table.S | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 5a8997d63899..8eefb12d1d33 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -55,8 +55,8 @@ #define ENTRY_COMP(_name_) .word sys_##_name_ #endif - ENTRY_SAME(restart_syscall) /* 0 */ - ENTRY_SAME(exit) +90: ENTRY_SAME(restart_syscall) /* 0 */ +91: ENTRY_SAME(exit) ENTRY_SAME(fork_wrapper) ENTRY_SAME(read) ENTRY_SAME(write) @@ -439,7 +439,10 @@ ENTRY_SAME(bpf) ENTRY_COMP(execveat) - /* Nothing yet */ + +.ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b)) +.error "size of syscall table does not fit value of __NR_Linux_syscalls" +.endif #undef ENTRY_SAME #undef ENTRY_DIFF From 0e0da48dee8dfbcc0df4b8e2ff4efc7a2c89ba6b Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 18 Mar 2015 13:42:38 -0400 Subject: [PATCH 215/567] parisc: mm: don't count preallocated pmds The patch dc6c9a35b66b520cf67e05d8ca60ebecad3b0479 that counts pmds allocated for a process introduced a bug on 64-bit PA-RISC kernels. The PA-RISC architecture preallocates one pmd with each pgd. This preallocated pmd can never be freed - pmd_free does nothing when it is called with this pmd. When the kernel attempts to free this preallocated pmd, it decreases the count of allocated pmds. The result is that the counter underflows and this error is reported. This patch fixes the bug by artifically incrementing the counter in pmd_free when the kernel tries to free the preallocated pmd. Signed-off-by: Mikulas Patocka Acked-by: Kirill A. Shutemov Signed-off-by: Helge Deller --- arch/parisc/include/asm/pgalloc.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/parisc/include/asm/pgalloc.h b/arch/parisc/include/asm/pgalloc.h index f213f5b4c423..63e9ecae1310 100644 --- a/arch/parisc/include/asm/pgalloc.h +++ b/arch/parisc/include/asm/pgalloc.h @@ -74,8 +74,13 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) { #ifdef CONFIG_64BIT if(pmd_flag(*pmd) & PxD_FLAG_ATTACHED) - /* This is the permanent pmd attached to the pgd; - * cannot free it */ + /* + * This is the permanent pmd attached to the pgd; + * cannot free it. + * Increment the counter to compensate for the decrement + * done by generic mm code. + */ + mm_inc_nr_pmds(mm); return; #endif free_pages((unsigned long)pmd, PMD_ORDER); From 2e3f0ab2bb4853694570b9610b1fcfbfa8fd295b Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 16 Mar 2015 21:17:50 +0100 Subject: [PATCH 216/567] parisc: Fix pmd code to depend on PT_NLEVELS value, not on CONFIG_64BIT Make the code which sets up the pmd depend on PT_NLEVELS == 3, not on CONFIG_64BIT. The reason is, that a 64bit kernel with a page size greater than 4k doesn't need the pmd and thus has PT_NLEVELS = 2. Signed-off-by: Helge Deller --- arch/parisc/include/asm/pgalloc.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/parisc/include/asm/pgalloc.h b/arch/parisc/include/asm/pgalloc.h index 63e9ecae1310..d17437238a2c 100644 --- a/arch/parisc/include/asm/pgalloc.h +++ b/arch/parisc/include/asm/pgalloc.h @@ -26,7 +26,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm) if (likely(pgd != NULL)) { memset(pgd, 0, PAGE_SIZE< Date: Mon, 23 Mar 2015 11:17:56 +0000 Subject: [PATCH 217/567] metag: Fix ioremap_wc/ioremap_cached build errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When ioremap_wc() or ioremap_cached() are used without first including asm/pgtable.h, the _PAGE_CACHEABLE or _PAGE_WR_COMBINE definitions aren't found, resulting in build errors like the following (in next-20150323 due to "lib: devres: add a helper function for ioremap_wc"): lib/devres.c: In function ‘devm_ioremap_wc’: lib/devres.c:91: error: ‘_PAGE_WR_COMBINE’ undeclared We can't easily include asm/pgtable.h in asm/io.h due to dependency problems, so split out the _PAGE_* definitions from asm/pgtable.h into a separate asm/pgtable-bits.h header (as a couple of other architectures already do), and include that in io.h instead. Signed-off-by: James Hogan Cc: linux-metag@vger.kernel.org Cc: Abhilash Kesavan Cc: Greg Kroah-Hartman --- arch/metag/include/asm/io.h | 1 + arch/metag/include/asm/pgtable-bits.h | 104 ++++++++++++++++++++++++++ arch/metag/include/asm/pgtable.h | 95 +---------------------- 3 files changed, 106 insertions(+), 94 deletions(-) create mode 100644 arch/metag/include/asm/pgtable-bits.h diff --git a/arch/metag/include/asm/io.h b/arch/metag/include/asm/io.h index 9359e5048442..d5779b0ec573 100644 --- a/arch/metag/include/asm/io.h +++ b/arch/metag/include/asm/io.h @@ -2,6 +2,7 @@ #define _ASM_METAG_IO_H #include +#include #define IO_SPACE_LIMIT 0 diff --git a/arch/metag/include/asm/pgtable-bits.h b/arch/metag/include/asm/pgtable-bits.h new file mode 100644 index 000000000000..25ba6729f496 --- /dev/null +++ b/arch/metag/include/asm/pgtable-bits.h @@ -0,0 +1,104 @@ +/* + * Meta page table definitions. + */ + +#ifndef _METAG_PGTABLE_BITS_H +#define _METAG_PGTABLE_BITS_H + +#include + +/* + * Definitions for MMU descriptors + * + * These are the hardware bits in the MMCU pte entries. + * Derived from the Meta toolkit headers. + */ +#define _PAGE_PRESENT MMCU_ENTRY_VAL_BIT +#define _PAGE_WRITE MMCU_ENTRY_WR_BIT +#define _PAGE_PRIV MMCU_ENTRY_PRIV_BIT +/* Write combine bit - this can cause writes to occur out of order */ +#define _PAGE_WR_COMBINE MMCU_ENTRY_WRC_BIT +/* Sys coherent bit - this bit is never used by Linux */ +#define _PAGE_SYS_COHERENT MMCU_ENTRY_SYS_BIT +#define _PAGE_ALWAYS_ZERO_1 0x020 +#define _PAGE_CACHE_CTRL0 0x040 +#define _PAGE_CACHE_CTRL1 0x080 +#define _PAGE_ALWAYS_ZERO_2 0x100 +#define _PAGE_ALWAYS_ZERO_3 0x200 +#define _PAGE_ALWAYS_ZERO_4 0x400 +#define _PAGE_ALWAYS_ZERO_5 0x800 + +/* These are software bits that we stuff into the gaps in the hardware + * pte entries that are not used. Note, these DO get stored in the actual + * hardware, but the hardware just does not use them. + */ +#define _PAGE_ACCESSED _PAGE_ALWAYS_ZERO_1 +#define _PAGE_DIRTY _PAGE_ALWAYS_ZERO_2 + +/* Pages owned, and protected by, the kernel. */ +#define _PAGE_KERNEL _PAGE_PRIV + +/* No cacheing of this page */ +#define _PAGE_CACHE_WIN0 (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S) +/* burst cacheing - good for data streaming */ +#define _PAGE_CACHE_WIN1 (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S) +/* One cache way per thread */ +#define _PAGE_CACHE_WIN2 (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S) +/* Full on cacheing */ +#define _PAGE_CACHE_WIN3 (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S) + +#define _PAGE_CACHEABLE (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE) + +/* which bits are used for cache control ... */ +#define _PAGE_CACHE_MASK (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \ + _PAGE_WR_COMBINE) + +/* This is a mask of the bits that pte_modify is allowed to change. */ +#define _PAGE_CHG_MASK (PAGE_MASK) + +#define _PAGE_SZ_SHIFT 1 +#define _PAGE_SZ_4K (0x0) +#define _PAGE_SZ_8K (0x1 << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_16K (0x2 << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_32K (0x3 << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_64K (0x4 << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_128K (0x5 << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_256K (0x6 << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_512K (0x7 << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_1M (0x8 << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_2M (0x9 << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_4M (0xa << _PAGE_SZ_SHIFT) +#define _PAGE_SZ_MASK (0xf << _PAGE_SZ_SHIFT) + +#if defined(CONFIG_PAGE_SIZE_4K) +#define _PAGE_SZ (_PAGE_SZ_4K) +#elif defined(CONFIG_PAGE_SIZE_8K) +#define _PAGE_SZ (_PAGE_SZ_8K) +#elif defined(CONFIG_PAGE_SIZE_16K) +#define _PAGE_SZ (_PAGE_SZ_16K) +#endif +#define _PAGE_TABLE (_PAGE_SZ | _PAGE_PRESENT) + +#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K) +# define _PAGE_SZHUGE (_PAGE_SZ_8K) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K) +# define _PAGE_SZHUGE (_PAGE_SZ_16K) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K) +# define _PAGE_SZHUGE (_PAGE_SZ_32K) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K) +# define _PAGE_SZHUGE (_PAGE_SZ_64K) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K) +# define _PAGE_SZHUGE (_PAGE_SZ_128K) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K) +# define _PAGE_SZHUGE (_PAGE_SZ_256K) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K) +# define _PAGE_SZHUGE (_PAGE_SZ_512K) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M) +# define _PAGE_SZHUGE (_PAGE_SZ_1M) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M) +# define _PAGE_SZHUGE (_PAGE_SZ_2M) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M) +# define _PAGE_SZHUGE (_PAGE_SZ_4M) +#endif + +#endif /* _METAG_PGTABLE_BITS_H */ diff --git a/arch/metag/include/asm/pgtable.h b/arch/metag/include/asm/pgtable.h index d0604c0a8702..ffa3a3a2ecad 100644 --- a/arch/metag/include/asm/pgtable.h +++ b/arch/metag/include/asm/pgtable.h @@ -5,6 +5,7 @@ #ifndef _METAG_PGTABLE_H #define _METAG_PGTABLE_H +#include #include /* Invalid regions on Meta: 0x00000000-0x001FFFFF and 0xFFFF0000-0xFFFFFFFF */ @@ -20,100 +21,6 @@ #define VMALLOC_END 0x7FFFFFFF #endif -/* - * Definitions for MMU descriptors - * - * These are the hardware bits in the MMCU pte entries. - * Derived from the Meta toolkit headers. - */ -#define _PAGE_PRESENT MMCU_ENTRY_VAL_BIT -#define _PAGE_WRITE MMCU_ENTRY_WR_BIT -#define _PAGE_PRIV MMCU_ENTRY_PRIV_BIT -/* Write combine bit - this can cause writes to occur out of order */ -#define _PAGE_WR_COMBINE MMCU_ENTRY_WRC_BIT -/* Sys coherent bit - this bit is never used by Linux */ -#define _PAGE_SYS_COHERENT MMCU_ENTRY_SYS_BIT -#define _PAGE_ALWAYS_ZERO_1 0x020 -#define _PAGE_CACHE_CTRL0 0x040 -#define _PAGE_CACHE_CTRL1 0x080 -#define _PAGE_ALWAYS_ZERO_2 0x100 -#define _PAGE_ALWAYS_ZERO_3 0x200 -#define _PAGE_ALWAYS_ZERO_4 0x400 -#define _PAGE_ALWAYS_ZERO_5 0x800 - -/* These are software bits that we stuff into the gaps in the hardware - * pte entries that are not used. Note, these DO get stored in the actual - * hardware, but the hardware just does not use them. - */ -#define _PAGE_ACCESSED _PAGE_ALWAYS_ZERO_1 -#define _PAGE_DIRTY _PAGE_ALWAYS_ZERO_2 - -/* Pages owned, and protected by, the kernel. */ -#define _PAGE_KERNEL _PAGE_PRIV - -/* No cacheing of this page */ -#define _PAGE_CACHE_WIN0 (MMCU_CWIN_UNCACHED << MMCU_ENTRY_CWIN_S) -/* burst cacheing - good for data streaming */ -#define _PAGE_CACHE_WIN1 (MMCU_CWIN_BURST << MMCU_ENTRY_CWIN_S) -/* One cache way per thread */ -#define _PAGE_CACHE_WIN2 (MMCU_CWIN_C1SET << MMCU_ENTRY_CWIN_S) -/* Full on cacheing */ -#define _PAGE_CACHE_WIN3 (MMCU_CWIN_CACHED << MMCU_ENTRY_CWIN_S) - -#define _PAGE_CACHEABLE (_PAGE_CACHE_WIN3 | _PAGE_WR_COMBINE) - -/* which bits are used for cache control ... */ -#define _PAGE_CACHE_MASK (_PAGE_CACHE_CTRL0 | _PAGE_CACHE_CTRL1 | \ - _PAGE_WR_COMBINE) - -/* This is a mask of the bits that pte_modify is allowed to change. */ -#define _PAGE_CHG_MASK (PAGE_MASK) - -#define _PAGE_SZ_SHIFT 1 -#define _PAGE_SZ_4K (0x0) -#define _PAGE_SZ_8K (0x1 << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_16K (0x2 << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_32K (0x3 << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_64K (0x4 << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_128K (0x5 << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_256K (0x6 << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_512K (0x7 << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_1M (0x8 << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_2M (0x9 << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_4M (0xa << _PAGE_SZ_SHIFT) -#define _PAGE_SZ_MASK (0xf << _PAGE_SZ_SHIFT) - -#if defined(CONFIG_PAGE_SIZE_4K) -#define _PAGE_SZ (_PAGE_SZ_4K) -#elif defined(CONFIG_PAGE_SIZE_8K) -#define _PAGE_SZ (_PAGE_SZ_8K) -#elif defined(CONFIG_PAGE_SIZE_16K) -#define _PAGE_SZ (_PAGE_SZ_16K) -#endif -#define _PAGE_TABLE (_PAGE_SZ | _PAGE_PRESENT) - -#if defined(CONFIG_HUGETLB_PAGE_SIZE_8K) -# define _PAGE_SZHUGE (_PAGE_SZ_8K) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16K) -# define _PAGE_SZHUGE (_PAGE_SZ_16K) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_32K) -# define _PAGE_SZHUGE (_PAGE_SZ_32K) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64K) -# define _PAGE_SZHUGE (_PAGE_SZ_64K) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_128K) -# define _PAGE_SZHUGE (_PAGE_SZ_128K) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K) -# define _PAGE_SZHUGE (_PAGE_SZ_256K) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512K) -# define _PAGE_SZHUGE (_PAGE_SZ_512K) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1M) -# define _PAGE_SZHUGE (_PAGE_SZ_1M) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_2M) -# define _PAGE_SZHUGE (_PAGE_SZ_2M) -#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4M) -# define _PAGE_SZHUGE (_PAGE_SZ_4M) -#endif - /* * The Linux memory management assumes a three-level page table setup. On * Meta, we use that, but "fold" the mid level into the top-level page From 83a60ed8f0b5ce550afd5802b60468578db4e055 Mon Sep 17 00:00:00 2001 From: Baptiste Reynal Date: Wed, 4 Mar 2015 16:51:06 +0100 Subject: [PATCH 218/567] iommu/arm-smmu: fix ARM_SMMU_FEAT_TRANS_OPS condition This patch is a fix to "iommu/arm-smmu: add support for iova_to_phys through ATS1PR". According to ARM documentation, translation registers are optional even in SMMUv1, so ID0_S1TS needs to be checked to verify their presence. Also, we check that the domain is a stage-1 domain. Signed-off-by: Baptiste Reynal Acked-by: Will Deacon Signed-off-by: Joerg Roedel --- drivers/iommu/arm-smmu.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index fc13dd56953e..a3adde6519f0 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1288,10 +1288,13 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, return 0; spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags); - if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS) + if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS && + smmu_domain->stage == ARM_SMMU_DOMAIN_S1) { ret = arm_smmu_iova_to_phys_hard(domain, iova); - else + } else { ret = ops->iova_to_phys(ops, iova); + } + spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); return ret; @@ -1556,7 +1559,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return -ENODEV; } - if (smmu->version == 1 || (!(id & ID0_ATOSNS) && (id & ID0_S1TS))) { + if ((id & ID0_S1TS) && ((smmu->version == 1) || (id & ID0_ATOSNS))) { smmu->features |= ARM_SMMU_FEAT_TRANS_OPS; dev_notice(smmu->dev, "\taddress translation ops\n"); } From 71684406905f98f86a85e008b51f5c4c5d83af5a Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 4 Mar 2015 11:30:10 -0700 Subject: [PATCH 219/567] iommu/vt-d: Detach domain *only* from attached iommus Device domains never span IOMMU hardware units, which allows the domain ID space for each IOMMU to be an independent address space. Therefore we can have multiple, independent domains, each with the same domain->id, but attached to different hardware units. This is also why we need to do a heavy-weight search for VM domains since they can span multiple IOMMUs hardware units and we don't require a single global ID to use for all hardware units. Therefore, if we call iommu_detach_domain() across all active IOMMU hardware units for a non-VM domain, the result is that we clear domain IDs that are not associated with our domain, allowing them to be re-allocated and causing apparent coherency issues when the device cannot access IOVAs for the intended domain. This bug was introduced in commit fb170fb4c548 ("iommu/vt-d: Introduce helper functions to make code symmetric for readability"), but is significantly exacerbated by the more recent commit 62c22167dd70 ("iommu/vt-d: Fix dmar_domain leak in iommu_attach_device") which calls domain_exit() more frequently to resolve a domain leak. Fixes: fb170fb4c548 ("iommu/vt-d: Introduce helper functions to make code symmetric for readability") Signed-off-by: Alex Williamson Cc: Jiang Liu Cc: stable@vger.kernel.org # v3.17+ Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index ae4c1a854e57..a83c965410e0 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1743,8 +1743,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width) static void domain_exit(struct dmar_domain *domain) { struct dmar_drhd_unit *drhd; - struct intel_iommu *iommu; struct page *freelist = NULL; + int i; /* Domain 0 is reserved, so dont process it */ if (!domain) @@ -1764,8 +1764,8 @@ static void domain_exit(struct dmar_domain *domain) /* clear attached or cached domains */ rcu_read_lock(); - for_each_active_iommu(iommu, drhd) - iommu_detach_domain(domain, iommu); + for_each_set_bit(i, domain->iommu_bmp, g_num_of_iommus) + iommu_detach_domain(domain, g_iommus[i]); rcu_read_unlock(); dma_free_pagelist(freelist); From ac04f85a733b6af1faa10f7603e98bf07d2c4203 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 17 Mar 2015 08:06:45 +0800 Subject: [PATCH 220/567] iommu: ipmmu-vmsa: Add terminating entry for ipmmu_of_ids The of_device_id table is supposed to be zero-terminated. Signed-off-by: Axel Lin Acked-by: Laurent Pinchart Signed-off-by: Joerg Roedel --- drivers/iommu/ipmmu-vmsa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 10186cac7716..bc39bdf7b99b 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -851,6 +851,7 @@ static int ipmmu_remove(struct platform_device *pdev) static const struct of_device_id ipmmu_of_ids[] = { { .compatible = "renesas,ipmmu-vmsa", }, + { } }; static struct platform_driver ipmmu_driver = { From 633d6f17cd91ad5bf2370265946f716e42d388c6 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Fri, 20 Mar 2015 13:55:38 +0100 Subject: [PATCH 221/567] x86/xen: prepare p2m list for memory hotplug Commit 054954eb051f35e74b75a566a96fe756015352c8 ("xen: switch to linear virtual mapped sparse p2m list") introduced a regression regarding to memory hotplug for a pv-domain: as the virtual space for the p2m list is allocated for the to be expected memory size of the domain only, hotplugged memory above that size will not be usable by the domain. Correct this by using a configurable size for the p2m list in case of memory hotplug enabled (default supported memory size is 512 GB for 64 bit domains and 4 GB for 32 bit domains). Signed-off-by: Juergen Gross Cc: # 3.19+ Reviewed-by: Daniel Kiper Signed-off-by: David Vrabel --- arch/x86/xen/p2m.c | 10 +++++++++- drivers/xen/Kconfig | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 9f93af56a5fc..b47124d4cd67 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -91,6 +91,12 @@ EXPORT_SYMBOL_GPL(xen_p2m_size); unsigned long xen_max_p2m_pfn __read_mostly; EXPORT_SYMBOL_GPL(xen_max_p2m_pfn); +#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT +#define P2M_LIMIT CONFIG_XEN_BALLOON_MEMORY_HOTPLUG_LIMIT +#else +#define P2M_LIMIT 0 +#endif + static DEFINE_SPINLOCK(p2m_update_lock); static unsigned long *p2m_mid_missing_mfn; @@ -385,9 +391,11 @@ static void __init xen_rebuild_p2m_list(unsigned long *p2m) void __init xen_vmalloc_p2m_tree(void) { static struct vm_struct vm; + unsigned long p2m_limit; + p2m_limit = (phys_addr_t)P2M_LIMIT * 1024 * 1024 * 1024 / PAGE_SIZE; vm.flags = VM_ALLOC; - vm.size = ALIGN(sizeof(unsigned long) * xen_max_p2m_pfn, + vm.size = ALIGN(sizeof(unsigned long) * max(xen_max_p2m_pfn, p2m_limit), PMD_SIZE * PMDS_PER_MID_PAGE); vm_area_register_early(&vm, PMD_SIZE * PMDS_PER_MID_PAGE); pr_notice("p2m virtual area at %p, size is %lx\n", vm.addr, vm.size); diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index b812462083fc..94d96809e686 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -55,6 +55,23 @@ config XEN_BALLOON_MEMORY_HOTPLUG In that case step 3 should be omitted. +config XEN_BALLOON_MEMORY_HOTPLUG_LIMIT + int "Hotplugged memory limit (in GiB) for a PV guest" + default 512 if X86_64 + default 4 if X86_32 + range 0 64 if X86_32 + depends on XEN_HAVE_PVMMU + depends on XEN_BALLOON_MEMORY_HOTPLUG + help + Maxmium amount of memory (in GiB) that a PV guest can be + expanded to when using memory hotplug. + + A PV guest can have more memory than this limit if is + started with a larger maximum. + + This value is used to allocate enough space in internal + tables needed for physical memory administration. + config XEN_SCRUB_PAGES bool "Scrub pages before returning them to system" depends on XEN_BALLOON From 3c56b3a12ce52f361468cbdd2f79b2f3b8da0ea6 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Fri, 20 Mar 2015 13:55:39 +0100 Subject: [PATCH 222/567] xen/balloon: before adding hotplugged memory, set frames to invalid Commit 25b884a83d487fd62c3de7ac1ab5549979188482 ("x86/xen: set regions above the end of RAM as 1:1") introduced a regression. To be able to add memory pages which were added via memory hotplug to a pv domain, the pages must be "invalid" instead of "identity" in the p2m list before they can be added. Suggested-by: David Vrabel Signed-off-by: Juergen Gross Cc: # 3.16+ Reviewed-by: Daniel Kiper Signed-off-by: David Vrabel --- drivers/xen/balloon.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 0b52d92cb2e5..fd933695f232 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -229,6 +229,29 @@ static enum bp_state reserve_additional_memory(long credit) balloon_hotplug = round_up(balloon_hotplug, PAGES_PER_SECTION); nid = memory_add_physaddr_to_nid(hotplug_start_paddr); +#ifdef CONFIG_XEN_HAVE_PVMMU + /* + * add_memory() will build page tables for the new memory so + * the p2m must contain invalid entries so the correct + * non-present PTEs will be written. + * + * If a failure occurs, the original (identity) p2m entries + * are not restored since this region is now known not to + * conflict with any devices. + */ + if (!xen_feature(XENFEAT_auto_translated_physmap)) { + unsigned long pfn, i; + + pfn = PFN_DOWN(hotplug_start_paddr); + for (i = 0; i < balloon_hotplug; i++) { + if (!set_phys_to_machine(pfn + i, INVALID_P2M_ENTRY)) { + pr_warn("set_phys_to_machine() failed, no memory added\n"); + return BP_ECANCELED; + } + } + } +#endif + rc = add_memory(nid, hotplug_start_paddr, balloon_hotplug << PAGE_SHIFT); if (rc) { From e6e96d73a2aaaa54ed2c0f98693f4bf572712f1c Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 23 Mar 2015 09:32:37 -0600 Subject: [PATCH 223/567] NVMe: Initialize device list head before starting Driver recovery requires the device's list node to have been initialized. Fixes: https://lkml.org/lkml/2015/3/22/262 Reported-by: Steven Noonan Signed-off-by: Keith Busch Cc: Matthew Wilcox Cc: Jens Axboe Signed-off-by: Jens Axboe --- drivers/block/nvme-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index ceb32dd52a6c..e23be20a3417 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -3003,6 +3003,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) } get_device(dev->device); + INIT_LIST_HEAD(&dev->node); INIT_WORK(&dev->probe_work, nvme_async_probe); schedule_work(&dev->probe_work); return 0; From c72efb658f7c8b27ca3d0efb5cfd5ded9fcac89e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 Mar 2015 00:18:48 -0400 Subject: [PATCH 224/567] writeback: fix possible underflow in write bandwidth calculation From 1ebf33901ecc75d9496862dceb1ef0377980587c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 23 Mar 2015 00:08:19 -0400 2f800fbd777b ("writeback: fix dirtied pages accounting on redirty") introduced account_page_redirty() which reverts stat updates for a redirtied page, making BDI_DIRTIED no longer monotonically increasing. bdi_update_write_bandwidth() uses the delta in BDI_DIRTIED as the basis for bandwidth calculation. While unlikely, since the above patch, the newer value may be lower than the recorded past value and underflow the bandwidth calculation leading to a wild result. Fix it by subtracing min of the old and new values when calculating delta. AFAIK, there hasn't been any report of it happening but the resulting erratic behavior would be non-critical and temporary, so it's possible that the issue is happening without being reported. The risk of the fix is very low, so tagged for -stable. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Jan Kara Cc: Wu Fengguang Cc: Greg Thelen Fixes: 2f800fbd777b ("writeback: fix dirtied pages accounting on redirty") Cc: stable@vger.kernel.org Signed-off-by: Jens Axboe --- mm/page-writeback.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index b4fd980a93eb..644bcb665773 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -857,8 +857,11 @@ static void bdi_update_write_bandwidth(struct backing_dev_info *bdi, * bw * elapsed + write_bandwidth * (period - elapsed) * write_bandwidth = --------------------------------------------------- * period + * + * @written may have decreased due to account_page_redirty(). + * Avoid underflowing @bw calculation. */ - bw = written - bdi->written_stamp; + bw = written - min(written, bdi->written_stamp); bw *= HZ; if (unlikely(elapsed > period)) { do_div(bw, elapsed); From c164c147c9a0a371c4710186972a02b6ee2eb984 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 21 Mar 2015 20:29:34 -0700 Subject: [PATCH 225/567] Input: ALPS - fix max coordinates for v5 and v7 protocols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 3296f71cd2fde7a2ad52e66a27eae419f6328066 ("Input: ALPS - consolidate setting protocol parameters") inadvertently moved call to alps_dolphin_get_device_area() from v5 to v7 protocol, causing both protocols report incorrect maximum values for X and Y axes which resulted in crash in Synaptics X driver. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=94801 Reported-by: Santiago Gala Reported-by: Pali Rohár Acked-by: Hans de Goede Acked-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 1bd15ebc01f2..33198b91bebf 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -2281,10 +2281,12 @@ static int alps_set_protocol(struct psmouse *psmouse, priv->set_abs_params = alps_set_abs_params_mt; priv->nibble_commands = alps_v3_nibble_commands; priv->addr_command = PSMOUSE_CMD_RESET_WRAP; - priv->x_max = 1360; - priv->y_max = 660; priv->x_bits = 23; priv->y_bits = 12; + + if (alps_dolphin_get_device_area(psmouse, priv)) + return -EIO; + break; case ALPS_PROTO_V6: @@ -2303,9 +2305,8 @@ static int alps_set_protocol(struct psmouse *psmouse, priv->set_abs_params = alps_set_abs_params_mt; priv->nibble_commands = alps_v3_nibble_commands; priv->addr_command = PSMOUSE_CMD_RESET_WRAP; - - if (alps_dolphin_get_device_area(psmouse, priv)) - return -EIO; + priv->x_max = 0xfff; + priv->y_max = 0x7ff; if (priv->fw_ver[1] != 0xba) priv->flags |= ALPS_BUTTONPAD; From 80b311d3118842eb681397233faa0d588df13f92 Mon Sep 17 00:00:00 2001 From: Sebastian Wicki Date: Mon, 23 Mar 2015 17:23:11 +0100 Subject: [PATCH 226/567] ALSA: hda - Add dock support for Thinkpad T450s (17aa:5036) This model uses the same dock port as the previous generation. Signed-off-by: Sebastian Wicki Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 526398a4a442..7b0f72c5c6f1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5036,6 +5036,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), From 98dc0703735d9cfc483522d5ffbce0c0b07c1f86 Mon Sep 17 00:00:00 2001 From: Ramiro Morales Date: Mon, 23 Mar 2015 10:33:07 -0700 Subject: [PATCH 227/567] Input: synaptics - add quirk for Thinkpad E440 Its ClickPad shares PNP ID "LEN2006" with the one in model E540 which is already handled by the driver (both are Haswell iterations of the Edge line, launched in 2014) but the dimensions it reports are different: $ sudo ./touchpad-edge-detector /dev/input/event3 Touchpad SynPS/2 Synaptics TouchPad on /dev/input/event3 Move one finger around the touchpad to detect the actual edges Kernel says: x [1472..5044], y [1408..3398] Touchpad sends: x [1024..5045], y [2457..4832] /^C Fortunately we can use the board ID, which is also different, to distinguish among them. $ dmesg | grep -i synaptics psmouse serio1: synaptics: Touchpad model: 1, fw: 8.1, id: 0x1e2b1, caps: 0xd001a3/0x940300/0x127c00, board id: 2691, fw id: 1494646 psmouse serio1: synaptics: serio: Synaptics pass-through port at isa0060/serio1/input0 input: SynPS/2 Synaptics TouchPad as /devices/platform/i8042/serio1/input/input4 Board ID in E540 is 2722: psmouse serio1: synaptics: Touchpad model: 1, fw: 8.1, id: 0x1e2b1, caps: 0xd001a3/0x940300/0x127c00, board id: 2722, fw id: 1484859 (from https://launchpadlibrarian.net/179702965/BootDmesg.txt) Signed-off-by: Ramiro Morales Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index dda605836546..f6a3a7b7d1ad 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -152,6 +152,11 @@ static const struct min_max_quirk min_max_pnpid_table[] = { {ANY_BOARD_ID, ANY_BOARD_ID}, 1024, 5022, 2508, 4832 }, + { + (const char * const []){"LEN2006", NULL}, + {2691, 2691}, + 1024, 5045, 2457, 4632 + }, { (const char * const []){"LEN2006", NULL}, {ANY_BOARD_ID, ANY_BOARD_ID}, @@ -189,7 +194,7 @@ static const char * const topbuttonpad_pnp_ids[] = { "LEN2003", "LEN2004", /* L440 */ "LEN2005", - "LEN2006", + "LEN2006", /* Edge E440/E540 */ "LEN2007", "LEN2008", "LEN2009", From e53f21bce4d35a93b23d8fa1a840860f6c74f59e Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 23 Mar 2015 15:06:50 +0000 Subject: [PATCH 228/567] arm64: Use the reserved TTBR0 if context switching to the init_mm The idle_task_exit() function may call switch_mm() with next == &init_mm. On arm64, init_mm.pgd cannot be used for user mappings, so this patch simply sets the reserved TTBR0. Cc: Reported-by: Jon Medhurst (Tixy) Tested-by: Jon Medhurst (Tixy) Signed-off-by: Catalin Marinas --- arch/arm64/include/asm/mmu_context.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index a9eee33dfa62..101a42bde728 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -151,6 +151,15 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, { unsigned int cpu = smp_processor_id(); + /* + * init_mm.pgd does not contain any user mappings and it is always + * active for kernel addresses in TTBR1. Just set the reserved TTBR0. + */ + if (next == &init_mm) { + cpu_set_reserved_ttbr0(); + return; + } + if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) check_and_switch_context(next, tsk); } From 9425183d177aa4a2f09d01a74925124f0778b595 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Mon, 23 Mar 2015 18:27:41 +0200 Subject: [PATCH 229/567] usb: xhci: handle Config Error Change (CEC) in xhci driver Linux xHCI driver doesn't report and handle port cofig error change. If Port Configure Error for root hub port occurs, CEC bit in PORTSC would be set by xHC and remains 1. This happends when the root port fails to configure its link partner, e.g. the port fails to exchange port capabilities information using Port Capability LMPs. Then the Port Status Change Events will be blocked until all status change bits(CEC is one of the change bits) are cleared('0') (refer to xHCI spec 4.19.2). Otherwise, the port status change event for this root port will not be generated anymore, then root port would look like dead for user and can't be recovered until a Host Controller Reset(HCRST). This patch is to check CEC bit in PORTSC in xhci_get_port_status() and set a Config Error in the return status if CEC is set. This will cause a ClearPortFeature request, where CEC bit is cleared in xhci_clear_port_change_bit(). [The commit log is based on initial Marvell patch posted at http://marc.info/?l=linux-kernel&m=142323612321434&w=2] Reported-by: Gregory CLEMENT Signed-off-by: Lu Baolu Cc: stable # v3.2+ Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a7865c4b0498..0827d7c96527 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -387,6 +387,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, status = PORT_PLC; port_change_bit = "link state"; break; + case USB_PORT_FEAT_C_PORT_CONFIG_ERROR: + status = PORT_CEC; + port_change_bit = "config error"; + break; default: /* Should never happen */ return; @@ -588,6 +592,8 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd, status |= USB_PORT_STAT_C_LINK_STATE << 16; if ((raw_port_status & PORT_WRC)) status |= USB_PORT_STAT_C_BH_RESET << 16; + if ((raw_port_status & PORT_CEC)) + status |= USB_PORT_STAT_C_CONFIG_ERROR << 16; } if (hcd->speed != HCD_USB3) { @@ -1005,6 +1011,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_PORT_LINK_STATE: + case USB_PORT_FEAT_C_PORT_CONFIG_ERROR: xhci_clear_port_change_bit(xhci, wValue, wIndex, port_array[wIndex], temp); break; @@ -1069,7 +1076,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) */ status = bus_state->resuming_ports; - mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC; + mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC; spin_lock_irqsave(&xhci->lock, flags); /* For each port, did anything change? If so, set that bit in buf. */ From 227a4fd801c8a9fa2c4700ab98ec1aec06e3b44d Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Mon, 23 Mar 2015 18:27:42 +0200 Subject: [PATCH 230/567] usb: xhci: apply XHCI_AVOID_BEI quirk to all Intel xHCI controllers When a device with an isochronous endpoint is plugged into the Intel xHCI host controller, and the driver submits multiple frames per URB, the xHCI driver will set the Block Event Interrupt (BEI) flag on all but the last TD for the URB. This causes the host controller to place an event on the event ring, but not send an interrupt. When the last TD for the URB completes, BEI is cleared, and we get an interrupt for the whole URB. However, under Intel xHCI host controllers, if the event ring is full of events from transfers with BEI set, an "Event Ring is Full" event will be posted to the last entry of the event ring, but no interrupt is generated. Host will cease all transfer and command executions and wait until software completes handling the pending events in the event ring. That means xHC stops, but event of "event ring is full" is not notified. As the result, the xHC looks like dead to user. This patch is to apply XHCI_AVOID_BEI quirk to Intel xHC devices. And it should be backported to kernels as old as 3.0, that contains the commit 69e848c2090a ("Intel xhci: Support EHCI/xHCI port switching."). Signed-off-by: Lu Baolu Tested-by: Alistair Grant Cc: stable@vger.kernel.org Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index fd53c9ebd662..2af32e26fafc 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -115,6 +115,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) if (pdev->vendor == PCI_VENDOR_ID_INTEL) { xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_INTEL_HOST; + xhci->quirks |= XHCI_AVOID_BEI; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { @@ -130,7 +131,6 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) * PPT chipsets. */ xhci->quirks |= XHCI_SPURIOUS_REBOOT; - xhci->quirks |= XHCI_AVOID_BEI; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) { From 63a4f065ece613b6d575b538234375b0e9c23bbc Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 23 Mar 2015 17:01:43 -0400 Subject: [PATCH 231/567] dm: fix add_disk() NULL pointer due to race with free_dev() Commit c4db59d31e39 ("fs: don't reassign dirty inodes to default_backing_dev_info") exposed DM to a latent race in free_dev() vs add_disk() in relation to management of the device's minor number. Fix this by refactoring free_dev() to match cleanup order of the alloc_dev() error path. Move cleanup of the gendisk, queue, and bdev to _before_ the cleanup of the idr managed minor number. Also, purely due to cleanup that fell out during the free_dev() audit: - adjust dm_blk_close() to access the gendisk's private_data under the _minor_lock spinlock. - move __dm_destroy()'s dm_get_live_table() call out from under the _minor_lock spinlock. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1202449 Reported-by: Zdenek Kabelac Reported-by: Jeff Moyer Signed-off-by: Mike Snitzer --- drivers/md/dm.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 9b641b38b857..8001fe9e3434 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -433,7 +433,6 @@ static int dm_blk_open(struct block_device *bdev, fmode_t mode) dm_get(md); atomic_inc(&md->open_count); - out: spin_unlock(&_minor_lock); @@ -442,16 +441,20 @@ out: static void dm_blk_close(struct gendisk *disk, fmode_t mode) { - struct mapped_device *md = disk->private_data; + struct mapped_device *md; spin_lock(&_minor_lock); + md = disk->private_data; + if (WARN_ON(!md)) + goto out; + if (atomic_dec_and_test(&md->open_count) && (test_bit(DMF_DEFERRED_REMOVE, &md->flags))) queue_work(deferred_remove_workqueue, &deferred_remove_work); dm_put(md); - +out: spin_unlock(&_minor_lock); } @@ -2241,7 +2244,6 @@ static void free_dev(struct mapped_device *md) int minor = MINOR(disk_devt(md->disk)); unlock_fs(md); - bdput(md->bdev); destroy_workqueue(md->wq); if (md->kworker_task) @@ -2252,19 +2254,22 @@ static void free_dev(struct mapped_device *md) mempool_destroy(md->rq_pool); if (md->bs) bioset_free(md->bs); - blk_integrity_unregister(md->disk); - del_gendisk(md->disk); + cleanup_srcu_struct(&md->io_barrier); free_table_devices(&md->table_devices); - free_minor(minor); + dm_stats_cleanup(&md->stats); spin_lock(&_minor_lock); md->disk->private_data = NULL; spin_unlock(&_minor_lock); - + if (blk_get_integrity(md->disk)) + blk_integrity_unregister(md->disk); + del_gendisk(md->disk); put_disk(md->disk); blk_cleanup_queue(md->queue); - dm_stats_cleanup(&md->stats); + bdput(md->bdev); + free_minor(minor); + module_put(THIS_MODULE); kfree(md); } @@ -2642,8 +2647,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait) might_sleep(); - spin_lock(&_minor_lock); map = dm_get_live_table(md, &srcu_idx); + + spin_lock(&_minor_lock); idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md)))); set_bit(DMF_FREEING, &md->flags); spin_unlock(&_minor_lock); From c806a6ad35bfa6c92249cd0ca4772d5ac3f8cb68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Date: Wed, 18 Mar 2015 19:38:22 +0100 Subject: [PATCH 232/567] KVM: x86: call irq notifiers with directed EOI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kvm_ioapic_update_eoi() wasn't called if directed EOI was enabled. We need to do that for irq notifiers. (Like with edge interrupts.) Fix it by skipping EOI broadcast only. Bug: https://bugzilla.kernel.org/show_bug.cgi?id=82211 Signed-off-by: Radim Krčmář Reviewed-by: Paolo Bonzini Tested-by: Bandan Das Signed-off-by: Marcelo Tosatti --- arch/x86/kvm/ioapic.c | 4 +++- arch/x86/kvm/lapic.c | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index b1947e0f3e10..46d4449772bc 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -422,6 +422,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, struct kvm_ioapic *ioapic, int vector, int trigger_mode) { int i; + struct kvm_lapic *apic = vcpu->arch.apic; for (i = 0; i < IOAPIC_NUM_PINS; i++) { union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i]; @@ -443,7 +444,8 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i); spin_lock(&ioapic->lock); - if (trigger_mode != IOAPIC_LEVEL_TRIG) + if (trigger_mode != IOAPIC_LEVEL_TRIG || + kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) continue; ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index bd4e34de24c7..4ee827d7bf36 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -833,8 +833,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2) static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector) { - if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) && - kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) { + if (kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) { int trigger_mode; if (apic_test_vector(vector, apic->regs + APIC_TMR)) trigger_mode = IOAPIC_LEVEL_TRIG; From 744961341d472db6272ed9b42319a90f5a2aa7c4 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 20 Mar 2015 12:21:37 +0000 Subject: [PATCH 233/567] kvm: avoid page allocation failure in kvm_set_memory_region() KVM guest can fail to startup with following trace on host: qemu-system-x86: page allocation failure: order:4, mode:0x40d0 Call Trace: dump_stack+0x47/0x67 warn_alloc_failed+0xee/0x150 __alloc_pages_direct_compact+0x14a/0x150 __alloc_pages_nodemask+0x776/0xb80 alloc_kmem_pages+0x3a/0x110 kmalloc_order+0x13/0x50 kmemdup+0x1b/0x40 __kvm_set_memory_region+0x24a/0x9f0 [kvm] kvm_set_ioapic+0x130/0x130 [kvm] kvm_set_memory_region+0x21/0x40 [kvm] kvm_vm_ioctl+0x43f/0x750 [kvm] Failure happens when attempting to allocate pages for 'struct kvm_memslots', however it doesn't have to be present in physically contiguous (kmalloc-ed) address space, change allocation to kvm_kvzalloc() so that it will be vmalloc-ed when its size is more then a page. Signed-off-by: Igor Mammedov Signed-off-by: Marcelo Tosatti --- virt/kvm/kvm_main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index a2214d9609bd..cc6a25d95fbf 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -471,7 +471,7 @@ static struct kvm *kvm_create_vm(unsigned long type) BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX); r = -ENOMEM; - kvm->memslots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL); + kvm->memslots = kvm_kvzalloc(sizeof(struct kvm_memslots)); if (!kvm->memslots) goto out_err_no_srcu; @@ -522,7 +522,7 @@ out_err_no_srcu: out_err_no_disable: for (i = 0; i < KVM_NR_BUSES; i++) kfree(kvm->buses[i]); - kfree(kvm->memslots); + kvfree(kvm->memslots); kvm_arch_free_vm(kvm); return ERR_PTR(r); } @@ -578,7 +578,7 @@ static void kvm_free_physmem(struct kvm *kvm) kvm_for_each_memslot(memslot, slots) kvm_free_physmem_slot(kvm, memslot, NULL); - kfree(kvm->memslots); + kvfree(kvm->memslots); } static void kvm_destroy_devices(struct kvm *kvm) @@ -871,10 +871,10 @@ int __kvm_set_memory_region(struct kvm *kvm, goto out_free; } - slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots), - GFP_KERNEL); + slots = kvm_kvzalloc(sizeof(struct kvm_memslots)); if (!slots) goto out_free; + memcpy(slots, kvm->memslots, sizeof(struct kvm_memslots)); if ((change == KVM_MR_DELETE) || (change == KVM_MR_MOVE)) { slot = id_to_memslot(slots, mem->slot); @@ -917,7 +917,7 @@ int __kvm_set_memory_region(struct kvm *kvm, kvm_arch_commit_memory_region(kvm, mem, &old, change); kvm_free_physmem_slot(kvm, &old, &new); - kfree(old_memslots); + kvfree(old_memslots); /* * IOMMU mapping: New slots need to be mapped. Old slots need to be @@ -936,7 +936,7 @@ int __kvm_set_memory_region(struct kvm *kvm, return 0; out_slots: - kfree(slots); + kvfree(slots); out_free: kvm_free_physmem_slot(kvm, &new, &old); out: From 8218c3f4df3bb1c637c17552405039a6dd3c1ee1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 27 Feb 2015 12:58:13 +0100 Subject: [PATCH 234/567] drm: Fixup racy refcounting in plane_force_disable Originally it was impossible to be dropping the last refcount in this function since there was always one around still from the idr. But in commit 83f45fc360c8e16a330474860ebda872d1384c8c Author: Daniel Vetter Date: Wed Aug 6 09:10:18 2014 +0200 drm: Don't grab an fb reference for the idr we've switched to weak references, broke that assumption but forgot to fix it up. Since we still force-disable planes it's only possible to hit this when racing multiple rmfb with fbdev restoring or similar evil things. As long as userspace is nice it's impossible to hit the BUG_ON. But the BUG_ON would most likely be hit from fbdev code, which usually invovles the console_lock besides all modeset locks. So very likely we'd never get the bug reports if this was hit in the wild, hence better be safe than sorry and backport. Spotted by Matt Roper while reviewing other patches. [airlied: pull this back into 4.0 - the oops happens there] Cc: stable@vger.kernel.org Cc: Matt Roper Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index f6d04c7b5115..679b10e34fb5 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -525,17 +525,6 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb) } EXPORT_SYMBOL(drm_framebuffer_reference); -static void drm_framebuffer_free_bug(struct kref *kref) -{ - BUG(); -} - -static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) -{ - DRM_DEBUG("%p: FB ID: %d (%d)\n", fb, fb->base.id, atomic_read(&fb->refcount.refcount)); - kref_put(&fb->refcount, drm_framebuffer_free_bug); -} - /** * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr * @fb: fb to unregister @@ -1320,7 +1309,7 @@ void drm_plane_force_disable(struct drm_plane *plane) return; } /* disconnect the plane from the fb and crtc: */ - __drm_framebuffer_unreference(plane->old_fb); + drm_framebuffer_unreference(plane->old_fb); plane->old_fb = NULL; plane->fb = NULL; plane->crtc = NULL; From dff173de84958a677ce0d24b1da3cdc3a32b4238 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Mon, 23 Mar 2015 10:56:14 +0200 Subject: [PATCH 235/567] bnx2x: Fix statistics locking scheme Statistics' state-machine in bnx2x driver must be synced with various driver flows, but its current locking scheme manages to be wasteful [using 2 locks + additional local variable] and prone to race-conditions at the same time, as the state-machine and 'action' are being accessed under different locks. In addition, current 'safe exec' isn't in fact safe, since the only guarantee it gives is that DMA transactions are over, but ramrods might still be running. This patch cleans up said logic, leaving us with a single lock for the entire flow and removing the possible races. Changes from v2: - Switched into mutex locking from semaphore locking. - Release locks on error flows. Changes from v1: Failure to acquire lock fails flow instead of printing a warning and allowing access to the critical section. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 7 +- .../net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_stats.c | 164 ++++++++---------- .../net/ethernet/broadcom/bnx2x/bnx2x_stats.h | 6 +- 5 files changed, 84 insertions(+), 101 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 756053c028be..4085c4b31047 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1811,7 +1811,7 @@ struct bnx2x { int stats_state; /* used for synchronization of concurrent threads statistics handling */ - spinlock_t stats_lock; + struct mutex stats_lock; /* used by dmae command loader */ struct dmae_command stats_dmae; @@ -1935,8 +1935,6 @@ struct bnx2x { int fp_array_size; u32 dump_preset_idx; - bool stats_started; - struct semaphore stats_sema; u8 phys_port_id[ETH_ALEN]; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 996e215fc324..ae571a199f2f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -12037,9 +12037,8 @@ static int bnx2x_init_bp(struct bnx2x *bp) mutex_init(&bp->port.phy_mutex); mutex_init(&bp->fw_mb_mutex); mutex_init(&bp->drv_info_mutex); + mutex_init(&bp->stats_lock); bp->drv_info_mng_owner = false; - spin_lock_init(&bp->stats_lock); - sema_init(&bp->stats_sema, 1); INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task); INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task); @@ -13668,9 +13667,9 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp) cancel_delayed_work_sync(&bp->sp_task); cancel_delayed_work_sync(&bp->period_task); - spin_lock_bh(&bp->stats_lock); + mutex_lock(&bp->stats_lock); bp->stats_state = STATS_STATE_DISABLED; - spin_unlock_bh(&bp->stats_lock); + mutex_unlock(&bp->stats_lock); bnx2x_save_statistics(bp); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index e5aca2de1871..cfe3c7695455 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -2238,7 +2238,9 @@ int bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf) cookie.vf = vf; cookie.state = VF_ACQUIRED; - bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie); + rc = bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie); + if (rc) + goto op_err; } DP(BNX2X_MSG_IOV, "set state to acquired\n"); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c index d1608297c773..800ab44a07ce 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c @@ -123,36 +123,28 @@ static void bnx2x_dp_stats(struct bnx2x *bp) */ static void bnx2x_storm_stats_post(struct bnx2x *bp) { - if (!bp->stats_pending) { - int rc; + int rc; - spin_lock_bh(&bp->stats_lock); + if (bp->stats_pending) + return; - if (bp->stats_pending) { - spin_unlock_bh(&bp->stats_lock); - return; - } + bp->fw_stats_req->hdr.drv_stats_counter = + cpu_to_le16(bp->stats_counter++); - bp->fw_stats_req->hdr.drv_stats_counter = - cpu_to_le16(bp->stats_counter++); + DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n", + le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter)); - DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n", - le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter)); + /* adjust the ramrod to include VF queues statistics */ + bnx2x_iov_adjust_stats_req(bp); + bnx2x_dp_stats(bp); - /* adjust the ramrod to include VF queues statistics */ - bnx2x_iov_adjust_stats_req(bp); - bnx2x_dp_stats(bp); - - /* send FW stats ramrod */ - rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0, - U64_HI(bp->fw_stats_req_mapping), - U64_LO(bp->fw_stats_req_mapping), - NONE_CONNECTION_TYPE); - if (rc == 0) - bp->stats_pending = 1; - - spin_unlock_bh(&bp->stats_lock); - } + /* send FW stats ramrod */ + rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0, + U64_HI(bp->fw_stats_req_mapping), + U64_LO(bp->fw_stats_req_mapping), + NONE_CONNECTION_TYPE); + if (rc == 0) + bp->stats_pending = 1; } static void bnx2x_hw_stats_post(struct bnx2x *bp) @@ -221,7 +213,7 @@ static void bnx2x_stats_comp(struct bnx2x *bp) */ /* should be called under stats_sema */ -static void __bnx2x_stats_pmf_update(struct bnx2x *bp) +static void bnx2x_stats_pmf_update(struct bnx2x *bp) { struct dmae_command *dmae; u32 opcode; @@ -519,7 +511,7 @@ static void bnx2x_func_stats_init(struct bnx2x *bp) } /* should be called under stats_sema */ -static void __bnx2x_stats_start(struct bnx2x *bp) +static void bnx2x_stats_start(struct bnx2x *bp) { if (IS_PF(bp)) { if (bp->port.pmf) @@ -531,34 +523,13 @@ static void __bnx2x_stats_start(struct bnx2x *bp) bnx2x_hw_stats_post(bp); bnx2x_storm_stats_post(bp); } - - bp->stats_started = true; -} - -static void bnx2x_stats_start(struct bnx2x *bp) -{ - if (down_timeout(&bp->stats_sema, HZ/10)) - BNX2X_ERR("Unable to acquire stats lock\n"); - __bnx2x_stats_start(bp); - up(&bp->stats_sema); } static void bnx2x_stats_pmf_start(struct bnx2x *bp) { - if (down_timeout(&bp->stats_sema, HZ/10)) - BNX2X_ERR("Unable to acquire stats lock\n"); bnx2x_stats_comp(bp); - __bnx2x_stats_pmf_update(bp); - __bnx2x_stats_start(bp); - up(&bp->stats_sema); -} - -static void bnx2x_stats_pmf_update(struct bnx2x *bp) -{ - if (down_timeout(&bp->stats_sema, HZ/10)) - BNX2X_ERR("Unable to acquire stats lock\n"); - __bnx2x_stats_pmf_update(bp); - up(&bp->stats_sema); + bnx2x_stats_pmf_update(bp); + bnx2x_stats_start(bp); } static void bnx2x_stats_restart(struct bnx2x *bp) @@ -568,11 +539,9 @@ static void bnx2x_stats_restart(struct bnx2x *bp) */ if (IS_VF(bp)) return; - if (down_timeout(&bp->stats_sema, HZ/10)) - BNX2X_ERR("Unable to acquire stats lock\n"); + bnx2x_stats_comp(bp); - __bnx2x_stats_start(bp); - up(&bp->stats_sema); + bnx2x_stats_start(bp); } static void bnx2x_bmac_stats_update(struct bnx2x *bp) @@ -1246,18 +1215,12 @@ static void bnx2x_stats_update(struct bnx2x *bp) { u32 *stats_comp = bnx2x_sp(bp, stats_comp); - /* we run update from timer context, so give up - * if somebody is in the middle of transition - */ - if (down_trylock(&bp->stats_sema)) + if (bnx2x_edebug_stats_stopped(bp)) return; - if (bnx2x_edebug_stats_stopped(bp) || !bp->stats_started) - goto out; - if (IS_PF(bp)) { if (*stats_comp != DMAE_COMP_VAL) - goto out; + return; if (bp->port.pmf) bnx2x_hw_stats_update(bp); @@ -1267,7 +1230,7 @@ static void bnx2x_stats_update(struct bnx2x *bp) BNX2X_ERR("storm stats were not updated for 3 times\n"); bnx2x_panic(); } - goto out; + return; } } else { /* vf doesn't collect HW statistics, and doesn't get completions @@ -1281,7 +1244,7 @@ static void bnx2x_stats_update(struct bnx2x *bp) /* vf is done */ if (IS_VF(bp)) - goto out; + return; if (netif_msg_timer(bp)) { struct bnx2x_eth_stats *estats = &bp->eth_stats; @@ -1292,9 +1255,6 @@ static void bnx2x_stats_update(struct bnx2x *bp) bnx2x_hw_stats_post(bp); bnx2x_storm_stats_post(bp); - -out: - up(&bp->stats_sema); } static void bnx2x_port_stats_stop(struct bnx2x *bp) @@ -1358,12 +1318,7 @@ static void bnx2x_port_stats_stop(struct bnx2x *bp) static void bnx2x_stats_stop(struct bnx2x *bp) { - int update = 0; - - if (down_timeout(&bp->stats_sema, HZ/10)) - BNX2X_ERR("Unable to acquire stats lock\n"); - - bp->stats_started = false; + bool update = false; bnx2x_stats_comp(bp); @@ -1381,8 +1336,6 @@ static void bnx2x_stats_stop(struct bnx2x *bp) bnx2x_hw_stats_post(bp); bnx2x_stats_comp(bp); } - - up(&bp->stats_sema); } static void bnx2x_stats_do_nothing(struct bnx2x *bp) @@ -1410,18 +1363,28 @@ static const struct { void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) { - enum bnx2x_stats_state state; - void (*action)(struct bnx2x *bp); + enum bnx2x_stats_state state = bp->stats_state; + if (unlikely(bp->panic)) return; - spin_lock_bh(&bp->stats_lock); - state = bp->stats_state; - bp->stats_state = bnx2x_stats_stm[state][event].next_state; - action = bnx2x_stats_stm[state][event].action; - spin_unlock_bh(&bp->stats_lock); + /* Statistics update run from timer context, and we don't want to stop + * that context in case someone is in the middle of a transition. + * For other events, wait a bit until lock is taken. + */ + if (!mutex_trylock(&bp->stats_lock)) { + if (event == STATS_EVENT_UPDATE) + return; - action(bp); + DP(BNX2X_MSG_STATS, + "Unlikely stats' lock contention [event %d]\n", event); + mutex_lock(&bp->stats_lock); + } + + bnx2x_stats_stm[state][event].action(bp); + bp->stats_state = bnx2x_stats_stm[state][event].next_state; + + mutex_unlock(&bp->stats_lock); if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp)) DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n", @@ -1998,13 +1961,34 @@ void bnx2x_afex_collect_stats(struct bnx2x *bp, void *void_afex_stats, } } -void bnx2x_stats_safe_exec(struct bnx2x *bp, - void (func_to_exec)(void *cookie), - void *cookie){ - if (down_timeout(&bp->stats_sema, HZ/10)) - BNX2X_ERR("Unable to acquire stats lock\n"); +int bnx2x_stats_safe_exec(struct bnx2x *bp, + void (func_to_exec)(void *cookie), + void *cookie) +{ + int cnt = 10, rc = 0; + + /* Wait for statistics to end [while blocking further requests], + * then run supplied function 'safely'. + */ + mutex_lock(&bp->stats_lock); + bnx2x_stats_comp(bp); + while (bp->stats_pending && cnt--) + if (bnx2x_storm_stats_update(bp)) + usleep_range(1000, 2000); + if (bp->stats_pending) { + BNX2X_ERR("Failed to wait for stats pending to clear [possibly FW is stuck]\n"); + rc = -EBUSY; + goto out; + } + func_to_exec(cookie); - __bnx2x_stats_start(bp); - up(&bp->stats_sema); + +out: + /* No need to restart statistics - if they're enabled, the timer + * will restart the statistics. + */ + mutex_unlock(&bp->stats_lock); + + return rc; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h index 2beceaefdeea..965539a9dabe 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h @@ -539,9 +539,9 @@ struct bnx2x; void bnx2x_memset_stats(struct bnx2x *bp); void bnx2x_stats_init(struct bnx2x *bp); void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event); -void bnx2x_stats_safe_exec(struct bnx2x *bp, - void (func_to_exec)(void *cookie), - void *cookie); +int bnx2x_stats_safe_exec(struct bnx2x *bp, + void (func_to_exec)(void *cookie), + void *cookie); /** * bnx2x_save_statistics - save statistics when unloading. From d0c294c53a771ae7e84506dfbd8c18c30f078735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kube=C4=8Dek?= Date: Mon, 23 Mar 2015 15:14:00 +0100 Subject: [PATCH 236/567] tcp: prevent fetching dst twice in early demux code On s390x, gcc 4.8 compiles this part of tcp_v6_early_demux() struct dst_entry *dst = sk->sk_rx_dst; if (dst) dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); to code reading sk->sk_rx_dst twice, once for the test and once for the argument of ip6_dst_check() (dst_check() is inline). This allows ip6_dst_check() to be called with null first argument, causing a crash. Protect sk->sk_rx_dst access by READ_ONCE() both in IPv4 and IPv6 TCP early demux code. Fixes: 41063e9dd119 ("ipv4: Early TCP socket demux.") Fixes: c7109986db3c ("ipv6: Early TCP socket demux") Signed-off-by: Michal Kubecek Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5a2dfed4783b..f1756ee02207 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1518,7 +1518,7 @@ void tcp_v4_early_demux(struct sk_buff *skb) skb->sk = sk; skb->destructor = sock_edemux; if (sk->sk_state != TCP_TIME_WAIT) { - struct dst_entry *dst = sk->sk_rx_dst; + struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst); if (dst) dst = dst_check(dst, 0); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5d46832c6f72..b283a498f7a4 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1585,7 +1585,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb) skb->sk = sk; skb->destructor = sock_edemux; if (sk->sk_state != TCP_TIME_WAIT) { - struct dst_entry *dst = sk->sk_rx_dst; + struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst); if (dst) dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); From a71aaf66725e8fc02253a3bbea15d27e656434fe Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 23 Mar 2015 14:07:57 -0500 Subject: [PATCH 237/567] iwlwifi: Fix memory leak in iwl_req_fw_callback() In this routine, kzalloc allocates a memory block. This allocation is freed in the error paths, but not in the normal exit, thus the allocation is leaked. The kmemleak facility was used to find the leak. Signed-off-by: Larry Finger Cc: Johannes Berg Cc: Emmanuel Grumbach Cc: Intel Linux Wireless --- drivers/net/wireless/iwlwifi/iwl-drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 996e7f16adf9..c7154ac42c8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1257,6 +1257,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) op->name, err); #endif } + kfree(pieces); return; try_again: From 509fca899d5682a6eee3d1fb70bba7c89439034b Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 23 Mar 2015 19:50:21 -0600 Subject: [PATCH 238/567] iommu/vt-d: Remove unused variable Unused after commit 71684406905f ("iommu/vt-d: Detach domain *only* from attached iommus"). Reported by 0-day builder. Signed-off-by: Alex Williamson Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index a83c965410e0..2d1e05bdbb53 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1742,7 +1742,6 @@ static int domain_init(struct dmar_domain *domain, int guest_width) static void domain_exit(struct dmar_domain *domain) { - struct dmar_drhd_unit *drhd; struct page *freelist = NULL; int i; From 65582a7f4ce5bd7a1fb61516d9c2476f4f166f4e Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Fri, 20 Mar 2015 11:42:17 +0000 Subject: [PATCH 239/567] usb: isp1760: fix spin unlock in the error path of isp1760_udc_start Commit a124820de5fd ("usb: isp1760: fix possible deadlock in isp1760_udc_irq") replaced spin_{un,}lock with spin_{un,}lock_irq{save,restore}. However it missed an error path resulting in the smatch warning as below: drivers/usb/isp1760/isp1760-udc.c:1230 isp1760_udc_start() warn: inconsistent returns 'irqsave:flags'. Locked on: line 1207 Unlocked on: line 1199 This patch fixes the spin unlock in the error path in isp1760_udc_start thereby removing the smatch warning mentioned above. Reported-by: Dan Carpenter Cc: Laurent Pinchart Cc: Felipe Balbi Signed-off-by: Sudeep Holla Signed-off-by: Felipe Balbi --- drivers/usb/isp1760/isp1760-udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index f32c292cc868..3fc4fe770253 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1203,7 +1203,7 @@ static int isp1760_udc_start(struct usb_gadget *gadget, if (udc->driver) { dev_err(udc->isp->dev, "UDC already has a gadget driver\n"); - spin_unlock(&udc->lock); + spin_unlock_irqrestore(&udc->lock, flags); return -EBUSY; } From d079535d5e1bf5e2e7c856bae2483414ea21e137 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Mon, 23 Mar 2015 16:31:09 -0700 Subject: [PATCH 240/567] net: use for_each_netdev_safe() in rtnl_group_changelink() In case we move the whole dev group to another netns, we should call for_each_netdev_safe(), otherwise we get a soft lockup: NMI watchdog: BUG: soft lockup - CPU#0 stuck for 22s! [ip:798] irq event stamp: 255424 hardirqs last enabled at (255423): [] restore_args+0x0/0x30 hardirqs last disabled at (255424): [] apic_timer_interrupt+0x6a/0x80 softirqs last enabled at (255422): [] __do_softirq+0x2c1/0x3a9 softirqs last disabled at (255417): [] irq_exit+0x41/0x95 CPU: 0 PID: 798 Comm: ip Not tainted 4.0.0-rc4+ #881 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff8800d1b88000 ti: ffff880119530000 task.ti: ffff880119530000 RIP: 0010:[] [] debug_lockdep_rcu_enabled+0x28/0x30 RSP: 0018:ffff880119533778 EFLAGS: 00000246 RAX: ffff8800d1b88000 RBX: 0000000000000002 RCX: 0000000000000038 RDX: 0000000000000000 RSI: ffff8800d1b888c8 RDI: ffff8800d1b888c8 RBP: ffff880119533778 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 000000000000b5c2 R12: 0000000000000246 R13: ffff880119533708 R14: 00000000001d5a40 R15: ffff88011a7d5a40 FS: 00007fc01315f740(0000) GS:ffff88011a600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00007f367a120988 CR3: 000000011849c000 CR4: 00000000000007f0 Stack: ffff880119533798 ffffffff811ac868 ffffffff811ac831 ffffffff811ac828 ffff8801195337c8 ffffffff811ac8c9 ffff8801195339b0 ffff8801197633e0 0000000000000000 ffff8801195339b0 ffff8801195337d8 ffffffff811ad2d7 Call Trace: [] rcu_read_lock+0x37/0x6e [] ? rcu_read_unlock+0x5f/0x5f [] ? rcu_read_unlock+0x56/0x5f [] __fget+0x2a/0x7a [] fget+0x13/0x15 [] proc_ns_fget+0xe/0x38 [] get_net_ns_by_fd+0x11/0x59 [] rtnl_link_get_net+0x33/0x3e [] do_setlink+0x73/0x87b [] ? trace_hardirqs_off+0xd/0xf [] ? retint_restore_args+0xe/0xe [] rtnl_newlink+0x40c/0x699 [] ? rtnl_newlink+0xeb/0x699 [] ? _raw_spin_unlock+0x28/0x33 [] ? security_capable+0x18/0x1a [] ? ns_capable+0x4d/0x65 [] rtnetlink_rcv_msg+0x181/0x194 [] ? rtnl_lock+0x17/0x19 [] ? rtnl_lock+0x17/0x19 [] ? __rtnl_unlock+0x17/0x17 [] netlink_rcv_skb+0x4d/0x93 [] rtnetlink_rcv+0x26/0x2d [] netlink_unicast+0xcb/0x150 [] netlink_sendmsg+0x501/0x523 [] ? might_fault+0x59/0xa9 [] ? copy_from_user+0x2a/0x2c [] sock_sendmsg+0x34/0x3c [] ___sys_sendmsg+0x1b8/0x255 [] ? handle_pte_fault+0xbd5/0xd4a [] ? native_sched_clock+0x35/0x37 [] ? sched_clock_local+0x12/0x72 [] ? sched_clock_cpu+0x9e/0xb7 [] ? rcu_read_lock_held+0x3b/0x3d [] ? __fcheck_files+0x4c/0x58 [] ? __fget_light+0x2d/0x52 [] __sys_sendmsg+0x42/0x60 [] SyS_sendmsg+0x12/0x1c [] system_call_fastpath+0x12/0x17 Fixes: e7ed828f10bd8 ("netlink: support setting devgroup parameters") Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index ee0608bb3bc0..7ebed55b5f7d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1932,10 +1932,10 @@ static int rtnl_group_changelink(const struct sk_buff *skb, struct ifinfomsg *ifm, struct nlattr **tb) { - struct net_device *dev; + struct net_device *dev, *aux; int err; - for_each_netdev(net, dev) { + for_each_netdev_safe(net, dev, aux) { if (dev->group == group) { err = do_setlink(skb, dev, ifm, tb, NULL, 0); if (err < 0) From f3eab7184ddcd4867cf42e3274ba24a66e1e093d Mon Sep 17 00:00:00 2001 From: Steve Capper Date: Sun, 22 Mar 2015 14:51:51 +0000 Subject: [PATCH 241/567] arm64: percpu: Make this_cpu accessors pre-empt safe this_cpu operations were implemented for arm64 in: 5284e1b arm64: xchg: Implement cmpxchg_double f97fc81 arm64: percpu: Implement this_cpu operations Unfortunately, it is possible for pre-emption to take place between address generation and data access. This can lead to cases where data is being manipulated by this_cpu for a different CPU than it was called on. Which effectively breaks the spec. This patch disables pre-emption for the this_cpu operations guaranteeing that address generation and data manipulation take place without a pre-emption in-between. Fixes: 5284e1b4bc8a ("arm64: xchg: Implement cmpxchg_double") Fixes: f97fc810798c ("arm64: percpu: Implement this_cpu operations") Reported-by: Mark Rutland Acked-by: Will Deacon Signed-off-by: Steve Capper [catalin.marinas@arm.com: remove space after type cast] Signed-off-by: Catalin Marinas --- arch/arm64/include/asm/cmpxchg.h | 30 ++++++++++++++++----- arch/arm64/include/asm/percpu.h | 46 +++++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index cb9593079f29..d8c25b7b18fb 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -246,14 +246,30 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, __ret; \ }) -#define this_cpu_cmpxchg_1(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n) -#define this_cpu_cmpxchg_2(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n) -#define this_cpu_cmpxchg_4(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n) -#define this_cpu_cmpxchg_8(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n) +#define _protect_cmpxchg_local(pcp, o, n) \ +({ \ + typeof(*raw_cpu_ptr(&(pcp))) __ret; \ + preempt_disable(); \ + __ret = cmpxchg_local(raw_cpu_ptr(&(pcp)), o, n); \ + preempt_enable(); \ + __ret; \ +}) -#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \ - cmpxchg_double_local(raw_cpu_ptr(&(ptr1)), raw_cpu_ptr(&(ptr2)), \ - o1, o2, n1, n2) +#define this_cpu_cmpxchg_1(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) +#define this_cpu_cmpxchg_2(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) +#define this_cpu_cmpxchg_4(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) +#define this_cpu_cmpxchg_8(ptr, o, n) _protect_cmpxchg_local(ptr, o, n) + +#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \ +({ \ + int __ret; \ + preempt_disable(); \ + __ret = cmpxchg_double_local( raw_cpu_ptr(&(ptr1)), \ + raw_cpu_ptr(&(ptr2)), \ + o1, o2, n1, n2); \ + preempt_enable(); \ + __ret; \ +}) #define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n)) #define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n)) diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 09da25bc596f..4fde8c1df97f 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -204,25 +204,47 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val, return ret; } -#define _percpu_add(pcp, val) \ - __percpu_add(raw_cpu_ptr(&(pcp)), val, sizeof(pcp)) +#define _percpu_read(pcp) \ +({ \ + typeof(pcp) __retval; \ + preempt_disable(); \ + __retval = (typeof(pcp))__percpu_read(raw_cpu_ptr(&(pcp)), \ + sizeof(pcp)); \ + preempt_enable(); \ + __retval; \ +}) -#define _percpu_add_return(pcp, val) (typeof(pcp)) (_percpu_add(pcp, val)) +#define _percpu_write(pcp, val) \ +do { \ + preempt_disable(); \ + __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val), \ + sizeof(pcp)); \ + preempt_enable(); \ +} while(0) \ + +#define _pcp_protect(operation, pcp, val) \ +({ \ + typeof(pcp) __retval; \ + preempt_disable(); \ + __retval = (typeof(pcp))operation(raw_cpu_ptr(&(pcp)), \ + (val), sizeof(pcp)); \ + preempt_enable(); \ + __retval; \ +}) + +#define _percpu_add(pcp, val) \ + _pcp_protect(__percpu_add, pcp, val) + +#define _percpu_add_return(pcp, val) _percpu_add(pcp, val) #define _percpu_and(pcp, val) \ - __percpu_and(raw_cpu_ptr(&(pcp)), val, sizeof(pcp)) + _pcp_protect(__percpu_and, pcp, val) #define _percpu_or(pcp, val) \ - __percpu_or(raw_cpu_ptr(&(pcp)), val, sizeof(pcp)) - -#define _percpu_read(pcp) (typeof(pcp)) \ - (__percpu_read(raw_cpu_ptr(&(pcp)), sizeof(pcp))) - -#define _percpu_write(pcp, val) \ - __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp)) + _pcp_protect(__percpu_or, pcp, val) #define _percpu_xchg(pcp, val) (typeof(pcp)) \ - (__percpu_xchg(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp))) + _pcp_protect(__percpu_xchg, pcp, (unsigned long)(val)) #define this_cpu_add_1(pcp, val) _percpu_add(pcp, val) #define this_cpu_add_2(pcp, val) _percpu_add(pcp, val) From a6e95cc718c8916a13f1e1e9d33cacbc5db56c0f Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 24 Mar 2015 09:31:40 +0900 Subject: [PATCH 242/567] rocker: handle non-bridge master change Master change notifications may occur other than when joining or leaving a bridge, for example when being added to or removed from a bond or Open vSwitch. Previously in those cases rocker_port_bridge_leave() was called which results in a null-pointer dereference as rocker_port->bridge_dev is NULL because there is no bridge device. This patch makes provision for doing nothing in such cases. Fixes: 6c7079450071f ("rocker: implement L2 bridge offloading") Acked-by: Jiri Pirko Acked-by: Scott Feldman Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 9fb6948e14c6..5cecec282aba 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4468,10 +4468,16 @@ static int rocker_port_master_changed(struct net_device *dev) struct net_device *master = netdev_master_upper_dev_get(dev); int err = 0; + /* There are currently three cases handled here: + * 1. Joining a bridge + * 2. Leaving a previously joined bridge + * 3. Other, e.g. being added to or removed from a bond or openvswitch, + * in which case nothing is done + */ if (master && master->rtnl_link_ops && !strcmp(master->rtnl_link_ops->kind, "bridge")) err = rocker_port_bridge_join(rocker_port, master); - else + else if (rocker_port_is_bridged(rocker_port)) err = rocker_port_bridge_leave(rocker_port); return err; From e5eda89d97ec256ba14e7e861387cc0468259c18 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Tue, 24 Mar 2015 15:18:38 +0200 Subject: [PATCH 243/567] net/mlx4_en: Call register_netdevice in the proper location Netdevice registration should be performed a the end of the driver initialization flow. If we don't do that, after calling register_netdevice, device callbacks may be issued by higher layers of the stack before final configuration of the device is done. For example (VXLAN configuration race), mlx4_SET_PORT_VXLAN was issued after the register_netdev command. System network scripts may configure the interface (UP) right after the registration, which also attach unicast VXLAN steering rule, before mlx4_SET_PORT_VXLAN was called, causing the firmware to fail the rule attachment. Fixes: 837052d0ccc5 ("net/mlx4_en: Add netdev support for TCP/IP offloads of vxlan tunneling") Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index ebce5bb24df9..3485acf03014 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2805,13 +2805,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, netif_carrier_off(dev); mlx4_en_set_default_moderation(priv); - err = register_netdev(dev); - if (err) { - en_err(priv, "Netdev registration failed for port %d\n", port); - goto out; - } - priv->registered = 1; - en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); @@ -2853,6 +2846,14 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap); + err = register_netdev(dev); + if (err) { + en_err(priv, "Netdev registration failed for port %d\n", port); + goto out; + } + + priv->registered = 1; + return 0; out: From bffb023ad2d44c0cfa8142ad8247391b32000998 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Tue, 24 Mar 2015 15:18:39 +0200 Subject: [PATCH 244/567] net/mlx4_core: Fix GEN_EQE accessing uninitialixed mutex We occasionally see in procedure mlx4_GEN_EQE that the driver tries to grab an uninitialized mutex. This can occur in only one of two ways: 1. We are trying to generate an async event on an uninitialized slave. 2. We are trying to generate an async event on an illegal slave number ( < 0 or > persist->num_vfs) or an inactive slave. To deal with #1: move the mutex initialization from specific slave init sequence in procedure mlx_master_do_cmd to mlx4_multi_func_init() (so that the mutex is always initialized for all slaves). To deal with #2: check in procedure mlx4_GEN_EQE that the slave number provided is in the proper range and that the slave is active. Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx4/eq.c | 18 +++++++----------- .../ethernet/mellanox/mlx4/resource_tracker.c | 6 ++++++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index a681d7c0bb9f..3350721bf515 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1993,7 +1993,6 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, goto reset_slave; slave_state[slave].vhcr_dma = ((u64) param) << 48; priv->mfunc.master.slave_state[slave].cookie = 0; - mutex_init(&priv->mfunc.master.gen_eqe_mutex[slave]); break; case MLX4_COMM_CMD_VHCR1: if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR0) @@ -2225,6 +2224,7 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) for (i = 0; i < dev->num_slaves; ++i) { s_state = &priv->mfunc.master.slave_state[i]; s_state->last_cmd = MLX4_COMM_CMD_RESET; + mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]); for (j = 0; j < MLX4_EVENT_TYPES_NUM; ++j) s_state->event_eq[j].eqn = -1; __raw_writel((__force u32) 0, diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index 264bc15c1ff2..6e70ffee8e87 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -153,12 +153,10 @@ void mlx4_gen_slave_eqe(struct work_struct *work) /* All active slaves need to receive the event */ if (slave == ALL_SLAVES) { - for (i = 0; i < dev->num_slaves; i++) { - if (i != dev->caps.function && - master->slave_state[i].active) - if (mlx4_GEN_EQE(dev, i, eqe)) - mlx4_warn(dev, "Failed to generate event for slave %d\n", - i); + for (i = 0; i <= dev->persist->num_vfs; i++) { + if (mlx4_GEN_EQE(dev, i, eqe)) + mlx4_warn(dev, "Failed to generate event for slave %d\n", + i); } } else { if (mlx4_GEN_EQE(dev, slave, eqe)) @@ -203,13 +201,11 @@ static void mlx4_slave_event(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) { struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *s_slave = - &priv->mfunc.master.slave_state[slave]; - if (!s_slave->active) { - /*mlx4_warn(dev, "Trying to pass event to inactive slave\n");*/ + if (slave < 0 || slave > dev->persist->num_vfs || + slave == dev->caps.function || + !priv->mfunc.master.slave_state[slave].active) return; - } slave_event(dev, slave, eqe); } diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index d97ca88c55b5..6e413ac4e940 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -3095,6 +3095,12 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) if (!priv->mfunc.master.slave_state) return -EINVAL; + /* check for slave valid, slave not PF, and slave active */ + if (slave < 0 || slave > dev->persist->num_vfs || + slave == dev->caps.function || + !priv->mfunc.master.slave_state[slave].active) + return 0; + event_eq = &priv->mfunc.master.slave_state[slave].event_eq[eqe->type]; /* Create the event only if the slave is registered */ From b3494a4ab20f6bdf74cdf2badf7918bb65ee8a00 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 23 Mar 2015 12:32:54 -0700 Subject: [PATCH 245/567] x86/asm/entry: Check for syscall exit work with IRQs disabled We currently have a race: if we're preempted during syscall exit, we can fail to process syscall return work that is queued up while we're preempted in ret_from_sys_call after checking ti.flags. Fix it by disabling interrupts before checking ti.flags. Reported-by: Stefan Seyfried Reported-by: Takashi Iwai Signed-off-by: Andy Lutomirski Acked-by: Denys Vlasenko Cc: Jiri Kosina Cc: Tejun Heo Fixes: 96b6352c1271 ("x86_64, entry: Remove the syscall exit audit") Link: http://lkml.kernel.org/r/189320d42b4d671df78c10555976bb10af1ffc75.1427137498.git.luto@kernel.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/entry_64.S | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 1d74d161687c..2babb393915e 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -364,12 +364,21 @@ system_call_fastpath: * Has incomplete stack frame and undefined top of stack. */ ret_from_sys_call: - testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) - jnz int_ret_from_sys_call_fixup /* Go the the slow path */ - LOCKDEP_SYS_EXIT DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF + + /* + * We must check ti flags with interrupts (or at least preemption) + * off because we must *never* return to userspace without + * processing exit work that is enqueued if we're preempted here. + * In particular, returning to userspace with any of the one-shot + * flags (TIF_NOTIFY_RESUME, TIF_USER_RETURN_NOTIFY, etc) set is + * very bad. + */ + testl $_TIF_ALLWORK_MASK,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET) + jnz int_ret_from_sys_call_fixup /* Go the the slow path */ + CFI_REMEMBER_STATE /* * sysretq will re-enable interrupts: @@ -386,7 +395,7 @@ ret_from_sys_call: int_ret_from_sys_call_fixup: FIXUP_TOP_OF_STACK %r11, -ARGOFFSET - jmp int_ret_from_sys_call + jmp int_ret_from_sys_call_irqs_off /* Do syscall tracing */ tracesys: @@ -432,6 +441,7 @@ tracesys_phase2: GLOBAL(int_ret_from_sys_call) DISABLE_INTERRUPTS(CLBR_NONE) TRACE_IRQS_OFF +int_ret_from_sys_call_irqs_off: movl $_TIF_ALLWORK_MASK,%edi /* edi: mask to check */ GLOBAL(int_with_check) From 977104e5606a6df8fe22c0dacd3620fc00b58d61 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 25 Mar 2015 00:53:26 +0800 Subject: [PATCH 246/567] ARM: dts: sun4i: a10-lime: Override and remove 1008MHz OPP setting The Olimex A10-Lime is known to be unstable when running at 1008MHz. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts index ab7891c43231..75742f8f96f3 100644 --- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts +++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts @@ -56,6 +56,22 @@ model = "Olimex A10-OLinuXino-LIME"; compatible = "olimex,a10-olinuxino-lime", "allwinner,sun4i-a10"; + cpus { + cpu0: cpu@0 { + /* + * The A10-Lime is known to be unstable + * when running at 1008 MHz + */ + operating-points = < + /* kHz uV */ + 912000 1350000 + 864000 1300000 + 624000 1250000 + >; + cooling-max-level = <2>; + }; + }; + soc@01c00000 { emac: ethernet@01c0b000 { pinctrl-names = "default"; From 370a9b5fb04a0d5cc7b7699c788616d6976f4476 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 25 Mar 2015 00:53:27 +0800 Subject: [PATCH 247/567] ARM: dts: sunxi: Remove overclocked/overvoltaged OPP Without proper regulator support for individual boards, it is dangerous to have overclocked/overvoltaged OPPs in the list. Cpufreq will increase the frequency without the accompanying voltage increase, resulting in an unstable system. Remove them for now. We can revisit them with the new version of OPP bindings, which support boost settings and frequency ranges, among other things. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun4i-a10.dtsi | 3 +-- arch/arm/boot/dts/sun5i-a13.dtsi | 3 +-- arch/arm/boot/dts/sun7i-a20.dtsi | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 5c2925831f20..eebb7853e00b 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -75,7 +75,6 @@ clock-latency = <244144>; /* 8 32k periods */ operating-points = < /* kHz uV */ - 1056000 1500000 1008000 1400000 912000 1350000 864000 1300000 @@ -83,7 +82,7 @@ >; #cooling-cells = <2>; cooling-min-level = <0>; - cooling-max-level = <4>; + cooling-max-level = <3>; }; }; diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi index f8818f1edbbe..883cb4873688 100644 --- a/arch/arm/boot/dts/sun5i-a13.dtsi +++ b/arch/arm/boot/dts/sun5i-a13.dtsi @@ -47,7 +47,6 @@ clock-latency = <244144>; /* 8 32k periods */ operating-points = < /* kHz uV */ - 1104000 1500000 1008000 1400000 912000 1350000 864000 1300000 @@ -57,7 +56,7 @@ >; #cooling-cells = <2>; cooling-min-level = <0>; - cooling-max-level = <6>; + cooling-max-level = <5>; }; }; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 3a8530b79f1c..fdd181792b4b 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -105,7 +105,6 @@ clock-latency = <244144>; /* 8 32k periods */ operating-points = < /* kHz uV */ - 1008000 1450000 960000 1400000 912000 1400000 864000 1300000 @@ -116,7 +115,7 @@ >; #cooling-cells = <2>; cooling-min-level = <0>; - cooling-max-level = <7>; + cooling-max-level = <6>; }; cpu@1 { From 1452db764c279f8b329f1b3b9469bd01d9e21afd Mon Sep 17 00:00:00 2001 From: Cliff Clark Date: Tue, 24 Mar 2015 14:07:26 -0700 Subject: [PATCH 248/567] ucc_geth: Intialize link state to down before register_netdev ucc_geth was indicating link up after a port is administratively enabled even when nothing is plugged in. This causes user-space tools to see a spurious link up the first time after boot. Signed-off-by: Cliff Clark Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/ucc_geth.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index 357e8b576905..56b774d3a13d 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -3893,6 +3893,9 @@ static int ucc_geth_probe(struct platform_device* ofdev) ugeth->phy_interface = phy_interface; ugeth->max_speed = max_speed; + /* Carrier starts down, phylib will bring it up */ + netif_carrier_off(dev); + err = register_netdev(dev); if (err) { if (netif_msg_probe(ugeth)) From 59a58cb34d3fe73e6c899cc5d9a87428ca662925 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 5 Feb 2015 18:30:20 +0000 Subject: [PATCH 249/567] drm/i915: Don't try to reference the fb in get_initial_plane_config() Tvrtko noticed a new warning on boot: WARNING: CPU: 1 PID: 353 at include/linux/kref.h:47 drm_framebuffer_reference+0x6c/0x80 [drm]() Call Trace: [] dump_stack+0x4f/0x7b [] warn_slowpath_common+0xaa/0xd0 [] warn_slowpath_null+0x1a/0x20 [] drm_framebuffer_reference+0x6c/0x80 [drm] [] update_state_fb.isra.54+0x47/0x50 [i915] [] skylake_get_initial_plane_config+0x93c/0x950 [i915] [] intel_modeset_init+0x1551/0x17c0 [i915] [] i915_driver_load+0xed0/0x11e0 [i915] [] ? _raw_spin_unlock_irqrestore+0x51/0x70 [] drm_dev_register+0x77/0x110 [drm] [] drm_get_pci_dev+0x11b/0x1f0 [drm] [] ? trace_hardirqs_on+0xd/0x10 [] ? _raw_spin_unlock_irqrestore+0x51/0x70 [] i915_pci_probe+0x56/0x60 [i915] [] pci_device_probe+0x7c/0x100 [] driver_probe_device+0x16d/0x380 We cannot take a reference at this point, not before intel_framebuffer_init() and the underlying drm_framebuffer_init(). Introduced in: commit 706dc7b549175e47f23e913b7f1e52874a7d0f56 Author: Matt Roper Date: Tue Feb 3 13:10:04 2015 -0800 drm/i915: Ensure plane->state->fb stays in sync with plane->fb v2: Don't move update_state_fb(). It was moved around because I originally put update_state_fb() in intel_alloc_plane_obj() before finding a better place. (Matt) Reviewed-by: Matt Roper Reported-by: Tvrtko Ursulin Cc: Matt Roper Cc: Tvrtko Ursulin Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter From drm-next: (cherry picked from commit f55548b5af87ebfc586ca75748947f1c1b1a4a52) Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_display.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6d22128d97b1..1c12262029fb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2438,8 +2438,10 @@ intel_find_plane_obj(struct intel_crtc *intel_crtc, if (!intel_crtc->base.primary->fb) return; - if (intel_alloc_plane_obj(intel_crtc, plane_config)) + if (intel_alloc_plane_obj(intel_crtc, plane_config)) { + update_state_fb(intel_crtc->base.primary); return; + } kfree(intel_crtc->base.primary->fb); intel_crtc->base.primary->fb = NULL; @@ -6663,7 +6665,6 @@ i9xx_get_initial_plane_config(struct intel_crtc *crtc, plane_config->size); crtc->base.primary->fb = fb; - update_state_fb(crtc->base.primary); } static void chv_crtc_clock_get(struct intel_crtc *crtc, @@ -7704,7 +7705,6 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc, plane_config->size); crtc->base.primary->fb = fb; - update_state_fb(crtc->base.primary); return; error: @@ -7798,7 +7798,6 @@ ironlake_get_initial_plane_config(struct intel_crtc *crtc, plane_config->size); crtc->base.primary->fb = fb; - update_state_fb(crtc->base.primary); } static bool ironlake_get_pipe_config(struct intel_crtc *crtc, From 1833c9f647e9bda1cd24653ff8f9c207b5f5b911 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Sat, 21 Mar 2015 12:43:08 +0100 Subject: [PATCH 250/567] s390/smp: reenable smt after resume After a suspend/resume cycle we missed to enable smt again, which leads to all sorts of bugs, since the kernel assumes smt is enabled, while the hardware thinks it is not. Reported-and-tested-by: Sebastian Ott Reported-by: Stefan Haberland Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/swsusp_asm64.S | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index 6b09fdffbd2f..ca6294645dd3 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S @@ -177,6 +177,17 @@ restart_entry: lhi %r1,1 sigp %r1,%r0,SIGP_SET_ARCHITECTURE sam64 +#ifdef CONFIG_SMP + larl %r1,smp_cpu_mt_shift + icm %r1,15,0(%r1) + jz smt_done + llgfr %r1,%r1 +smt_loop: + sigp %r1,%r0,SIGP_SET_MULTI_THREADING + brc 8,smt_done /* accepted */ + brc 2,smt_loop /* busy, try again */ +smt_done: +#endif larl %r1,.Lnew_pgm_check_psw lpswe 0(%r1) pgm_check_entry: From b229a0f840f774d29d8fedbf5deb344ca36b7f1a Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Mon, 23 Mar 2015 20:34:48 -0500 Subject: [PATCH 251/567] USB: ftdi_sio: Use jtag quirk for SNAP Connect E10 This patch uses the existing CALAO Systems ftdi_8u2232c_probe in order to avoid attaching a TTY to the JTAG port as this board is based on the CALAO Systems reference design and needs the same fix up. Signed-off-by: Doug Goldstein CC: stable [johan: clean up probe logic ] Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 130b354a8fd7..8eb68a31cab6 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1884,8 +1884,12 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) { struct usb_device *udev = serial->dev; - if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || - (udev->product && !strcmp(udev->product, "BeagleBone/XDS100V2"))) + if (udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) + return ftdi_jtag_probe(serial); + + if (udev->product && + (!strcmp(udev->product, "BeagleBone/XDS100V2") || + !strcmp(udev->product, "SNAP Connect E10"))) return ftdi_jtag_probe(serial); return 0; From 6fd99094de2b83d1d4c8457f2c83483b2828e75a Mon Sep 17 00:00:00 2001 From: "D.S. Ljungmark" Date: Wed, 25 Mar 2015 09:28:15 +0100 Subject: [PATCH 252/567] ipv6: Don't reduce hop limit for an interface A local route may have a lower hop_limit set than global routes do. RFC 3756, Section 4.2.7, "Parameter Spoofing" > 1. The attacker includes a Current Hop Limit of one or another small > number which the attacker knows will cause legitimate packets to > be dropped before they reach their destination. > As an example, one possible approach to mitigate this threat is to > ignore very small hop limits. The nodes could implement a > configurable minimum hop limit, and ignore attempts to set it below > said limit. Signed-off-by: D.S. Ljungmark Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 471ed24aabae..14ecdaf06bf7 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1218,7 +1218,14 @@ static void ndisc_router_discovery(struct sk_buff *skb) if (rt) rt6_set_expires(rt, jiffies + (HZ * lifetime)); if (ra_msg->icmph.icmp6_hop_limit) { - in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; + /* Only set hop_limit on the interface if it is higher than + * the current hop_limit. + */ + if (in6_dev->cnf.hop_limit < ra_msg->icmph.icmp6_hop_limit) { + in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; + } else { + ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than current\n"); + } if (rt) dst_metric_set(&rt->dst, RTAX_HOPLIMIT, ra_msg->icmph.icmp6_hop_limit); From dde93dfea53c72b07907d9e44a6e4b1545f6bdc4 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 25 Mar 2015 20:01:26 +0530 Subject: [PATCH 253/567] cxgb4: Fix frame size warning for 32 bit arch Fixes below warning by dynamically allocating memory All warnings: drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c: In function 'cctrl_tbl_show': >> drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c:689:1: warning: the >> frame >> size of 1028 bytes is larger than 1024 bytes [-Wframe-larger-than=] Reported-by: kbuild test robot Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 78854ceb0870..dcb047945290 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -670,9 +670,13 @@ static int cctrl_tbl_show(struct seq_file *seq, void *v) "0.9375" }; int i; - u16 incr[NMTUS][NCCTRL_WIN]; + u16 (*incr)[NCCTRL_WIN]; struct adapter *adap = seq->private; + incr = kmalloc(sizeof(*incr) * NMTUS, GFP_KERNEL); + if (!incr) + return -ENOMEM; + t4_read_cong_tbl(adap, incr); for (i = 0; i < NCCTRL_WIN; ++i) { @@ -685,6 +689,8 @@ static int cctrl_tbl_show(struct seq_file *seq, void *v) adap->params.a_wnd[i], dec_fac[adap->params.b_wnd[i]]); } + + kfree(incr); return 0; } From 6436a123a147db51a0b06024a8350f4c230e73ff Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 23 Mar 2015 18:01:35 -0700 Subject: [PATCH 254/567] selinux: fix sel_write_enforce broken return value Return a negative error value like the rest of the entries in this function. Cc: Signed-off-by: Joe Perches Acked-by: Stephen Smalley [PM: tweaked subject line] Signed-off-by: Paul Moore --- security/selinux/selinuxfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 33db1ad4fd10..138949a31eab 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -152,7 +152,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, goto out; /* No partial writes. */ - length = EINVAL; + length = -EINVAL; if (*ppos != 0) goto out; From fb903811c4e3bcd93ccc247235834e2632a3508d Mon Sep 17 00:00:00 2001 From: Ed Cashin Date: Wed, 25 Mar 2015 15:55:06 -0700 Subject: [PATCH 255/567] aoe: update aoe maintainer information The coraid.com email address is defunct. The old aoe support area hosted at coraid.com is no longer up. These changes update the email and website to current ones. Signed-off-by: Ed Cashin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 358eb0105e00..c6cd0f60635c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1675,8 +1675,8 @@ F: drivers/misc/eeprom/at24.c F: include/linux/platform_data/at24.h ATA OVER ETHERNET (AOE) DRIVER -M: "Ed L. Cashin" -W: http://support.coraid.com/support/linux +M: "Ed L. Cashin" +W: http://www.openaoe.org/ S: Supported F: Documentation/aoe/ F: drivers/block/aoe/ From ddd2a30d41a5bc578ab094f6dbf080697ea1a7dd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 25 Mar 2015 15:55:09 -0700 Subject: [PATCH 256/567] drivers/rtc/rtc-mrst: fix suspend/resume The Moorestown RTC driver implements suspend and resume callbacks and assigns them to the suspend and resume fields of the device_driver struct. These callbacks are never actually called by anything though. Modify the driver to properly use dev_pm_ops so that the suspend and resume functions are actually executed upon suspend/resume. [akpm@linux-foundation.org: device_driver.name is const char *] Signed-off-by: Lars-Peter Clausen Cc: Alessandro Zummo Cc: Feng Tang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mrst.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index e2436d140175..3a6fd3a8a2ec 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -413,8 +413,8 @@ static void rtc_mrst_do_remove(struct device *dev) mrst->dev = NULL; } -#ifdef CONFIG_PM -static int mrst_suspend(struct device *dev, pm_message_t mesg) +#ifdef CONFIG_PM_SLEEP +static int mrst_suspend(struct device *dev) { struct mrst_rtc *mrst = dev_get_drvdata(dev); unsigned char tmp; @@ -453,7 +453,7 @@ static int mrst_suspend(struct device *dev, pm_message_t mesg) */ static inline int mrst_poweroff(struct device *dev) { - return mrst_suspend(dev, PMSG_HIBERNATE); + return mrst_suspend(dev); } static int mrst_resume(struct device *dev) @@ -490,9 +490,11 @@ static int mrst_resume(struct device *dev) return 0; } +static SIMPLE_DEV_PM_OPS(mrst_pm_ops, mrst_suspend, mrst_resume); +#define MRST_PM_OPS (&mrst_pm_ops) + #else -#define mrst_suspend NULL -#define mrst_resume NULL +#define MRST_PM_OPS NULL static inline int mrst_poweroff(struct device *dev) { @@ -529,9 +531,8 @@ static struct platform_driver vrtc_mrst_platform_driver = { .remove = vrtc_mrst_platform_remove, .shutdown = vrtc_mrst_platform_shutdown, .driver = { - .name = (char *) driver_name, - .suspend = mrst_suspend, - .resume = mrst_resume, + .name = driver_name, + .pm = MRST_PM_OPS, } }; From 3fe89b3e2a7bbf3e97657104b9b33a9d81b950b3 Mon Sep 17 00:00:00 2001 From: Leon Yu Date: Wed, 25 Mar 2015 15:55:11 -0700 Subject: [PATCH 257/567] mm: fix anon_vma->degree underflow in anon_vma endless growing prevention I have constantly stumbled upon "kernel BUG at mm/rmap.c:399!" after upgrading to 3.19 and had no luck with 4.0-rc1 neither. So, after looking into new logic introduced by commit 7a3ef208e662 ("mm: prevent endless growth of anon_vma hierarchy"), I found chances are that unlink_anon_vmas() is called without incrementing dst->anon_vma->degree in anon_vma_clone() due to allocation failure. If dst->anon_vma is not NULL in error path, its degree will be incorrectly decremented in unlink_anon_vmas() and eventually underflow when exiting as a result of another call to unlink_anon_vmas(). That's how "kernel BUG at mm/rmap.c:399!" is triggered for me. This patch fixes the underflow by dropping dst->anon_vma when allocation fails. It's safe to do so regardless of original value of dst->anon_vma because dst->anon_vma doesn't have valid meaning if anon_vma_clone() fails. Besides, callers don't care dst->anon_vma in such case neither. Also suggested by Michal Hocko, we can clean up vma_adjust() a bit as anon_vma_clone() now does the work. [akpm@linux-foundation.org: tweak comment] Fixes: 7a3ef208e662 ("mm: prevent endless growth of anon_vma hierarchy") Signed-off-by: Leon Yu Signed-off-by: Konstantin Khlebnikov Reviewed-by: Michal Hocko Acked-by: Rik van Riel Acked-by: David Rientjes Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mmap.c | 4 +--- mm/rmap.c | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index da9990acc08b..9ec50a368634 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -774,10 +774,8 @@ again: remove_next = 1 + (end > next->vm_end); importer->anon_vma = exporter->anon_vma; error = anon_vma_clone(importer, exporter); - if (error) { - importer->anon_vma = NULL; + if (error) return error; - } } } diff --git a/mm/rmap.c b/mm/rmap.c index 5e3e09081164..c161a14b6a8f 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -287,6 +287,13 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src) return 0; enomem_failure: + /* + * dst->anon_vma is dropped here otherwise its degree can be incorrectly + * decremented in unlink_anon_vmas(). + * We can safely do this because callers of anon_vma_clone() don't care + * about dst->anon_vma if anon_vma_clone() failed. + */ + dst->anon_vma = NULL; unlink_anon_vmas(dst); return -ENOMEM; } From f683739539e819e9b821a197d80e52258510837b Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Wed, 25 Mar 2015 15:55:14 -0700 Subject: [PATCH 258/567] mm/pagewalk.c: prevent positive return value of walk_page_test() from being passed to callers walk_page_test() is purely pagewalk's internal stuff, and its positive return values are not intended to be passed to the callers of pagewalk. However, in the current code if the last vma in the do-while loop in walk_page_range() happens to return a positive value, it leaks outside walk_page_range(). So the user visible effect is invalid/unexpected return value (according to the reporter, mbind() causes it.) This patch fixes it simply by reinitializing the return value after checked. Another exposed interface, walk_page_vma(), already returns 0 for such cases so no problem. Fixes: fafaa4264eba ("pagewalk: improve vma handling") Signed-off-by: Naoya Horiguchi Signed-off-by: Kazutomo Yoshii Reported-by: Kazutomo Yoshii Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/pagewalk.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mm/pagewalk.c b/mm/pagewalk.c index 75c1f2878519..29f2f8b853ae 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -265,8 +265,15 @@ int walk_page_range(unsigned long start, unsigned long end, vma = vma->vm_next; err = walk_page_test(start, next, walk); - if (err > 0) + if (err > 0) { + /* + * positive return values are purely for + * controlling the pagewalk, so should never + * be passed to the callers. + */ + err = 0; continue; + } if (err < 0) break; } From 59ec96719f7521002804c0862888971410e288af Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 25 Mar 2015 15:55:17 -0700 Subject: [PATCH 259/567] MAINTAINERS: correct rtc armada38x pattern entry Commit c6a95dbee793 ("MAINTAINERS: add the RTC driver for the Armada38x") typoed the pattern, fix it. Signed-off-by: Joe Perches Acked-by: Gregory CLEMENT Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index c6cd0f60635c..12ebef95224d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1186,7 +1186,7 @@ M: Sebastian Hesselbarth L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-mvebu/ -F: drivers/rtc/armada38x-rtc +F: drivers/rtc/rtc-armada38x.c ARM/Marvell Berlin SoC support M: Sebastian Hesselbarth From b0dc3a342af36f95a68fe229b8f0f73552c5ca08 Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Wed, 25 Mar 2015 15:55:20 -0700 Subject: [PATCH 260/567] mm/memory hotplug: postpone the reset of obsolete pgdat Qiu Xishi reported the following BUG when testing hot-add/hot-remove node under stress condition: BUG: unable to handle kernel paging request at 0000000000025f60 IP: next_online_pgdat+0x1/0x50 PGD 0 Oops: 0000 [#1] SMP ACPI: Device does not support D3cold Modules linked in: fuse nls_iso8859_1 nls_cp437 vfat fat loop dm_mod coretemp mperf crc32c_intel ghash_clmulni_intel aesni_intel ablk_helper cryptd lrw gf128mul glue_helper aes_x86_64 pcspkr microcode igb dca i2c_algo_bit ipv6 megaraid_sas iTCO_wdt i2c_i801 i2c_core iTCO_vendor_support tg3 sg hwmon ptp lpc_ich pps_core mfd_core acpi_pad rtc_cmos button ext3 jbd mbcache sd_mod crc_t10dif scsi_dh_alua scsi_dh_rdac scsi_dh_hp_sw scsi_dh_emc scsi_dh ahci libahci libata scsi_mod [last unloaded: rasf] CPU: 23 PID: 238 Comm: kworker/23:1 Tainted: G O 3.10.15-5885-euler0302 #1 Hardware name: HUAWEI TECHNOLOGIES CO.,LTD. Huawei N1/Huawei N1, BIOS V100R001 03/02/2015 Workqueue: events vmstat_update task: ffffa800d32c0000 ti: ffffa800d32ae000 task.ti: ffffa800d32ae000 RIP: 0010: next_online_pgdat+0x1/0x50 RSP: 0018:ffffa800d32afce8 EFLAGS: 00010286 RAX: 0000000000001440 RBX: ffffffff81da53b8 RCX: 0000000000000082 RDX: 0000000000000000 RSI: 0000000000000082 RDI: 0000000000000000 RBP: ffffa800d32afd28 R08: ffffffff81c93bfc R09: ffffffff81cbdc96 R10: 00000000000040ec R11: 00000000000000a0 R12: ffffa800fffb3440 R13: ffffa800d32afd38 R14: 0000000000000017 R15: ffffa800e6616800 FS: 0000000000000000(0000) GS:ffffa800e6600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000025f60 CR3: 0000000001a0b000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: refresh_cpu_vm_stats+0xd0/0x140 vmstat_update+0x11/0x50 process_one_work+0x194/0x3d0 worker_thread+0x12b/0x410 kthread+0xc6/0xd0 ret_from_fork+0x7c/0xb0 The cause is the "memset(pgdat, 0, sizeof(*pgdat))" at the end of try_offline_node, which will reset all the content of pgdat to 0, as the pgdat is accessed lock-free, so that the users still using the pgdat will panic, such as the vmstat_update routine. process A: offline node XX: vmstat_updat() refresh_cpu_vm_stats() for_each_populated_zone() find online node XX cond_resched() offline cpu and memory, then try_offline_node() node_set_offline(nid), and memset(pgdat, 0, sizeof(*pgdat)) zone = next_zone(zone) pg_data_t *pgdat = zone->zone_pgdat; // here pgdat is NULL now next_online_pgdat(pgdat) next_online_node(pgdat->node_id); // NULL pointer access So the solution here is postponing the reset of obsolete pgdat from try_offline_node() to hotadd_new_pgdat(), and just resetting pgdat->nr_zones and pgdat->classzone_idx to be 0 rather than the memset 0 to avoid breaking pointer information in pgdat. Signed-off-by: Gu Zheng Reported-by: Xishi Qiu Suggested-by: KAMEZAWA Hiroyuki Cc: David Rientjes Cc: Yasuaki Ishimatsu Cc: Taku Izumi Cc: Tang Chen Cc: Xie XiuQi Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory_hotplug.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 9fab10795bea..65842d688b7c 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1092,6 +1092,10 @@ static pg_data_t __ref *hotadd_new_pgdat(int nid, u64 start) return NULL; arch_refresh_nodedata(nid, pgdat); + } else { + /* Reset the nr_zones and classzone_idx to 0 before reuse */ + pgdat->nr_zones = 0; + pgdat->classzone_idx = 0; } /* we can use NODE_DATA(nid) from here */ @@ -1977,15 +1981,6 @@ void try_offline_node(int nid) if (is_vmalloc_addr(zone->wait_table)) vfree(zone->wait_table); } - - /* - * Since there is no way to guarentee the address of pgdat/zone is not - * on stack of any kernel threads or used by other kernel objects - * without reference counting or other symchronizing method, do not - * reset node_data and free pgdat here. Just reset it to 0 and reuse - * the memory when the node is online again. - */ - memset(pgdat, 0, sizeof(*pgdat)); } EXPORT_SYMBOL(try_offline_node); From 859b7a0e89120505c304d7afbbe90325abaa0a6b Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 25 Mar 2015 15:55:23 -0700 Subject: [PATCH 261/567] mm/slub: fix lockups on PREEMPT && !SMP kernels Commit 9aabf810a67c ("mm/slub: optimize alloc/free fastpath by removing preemption on/off") introduced an occasional hang for kernels built with CONFIG_PREEMPT && !CONFIG_SMP. The problem is the following loop the patch introduced to slab_alloc_node and slab_free: do { tid = this_cpu_read(s->cpu_slab->tid); c = raw_cpu_ptr(s->cpu_slab); } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid)); GCC 4.9 has been observed to hoist the load of c and c->tid above the loop for !SMP kernels (as in this case raw_cpu_ptr(x) is compile-time constant and does not force a reload). On arm64 the generated assembly looks like: ldr x4, [x0,#8] loop: ldr x1, [x0,#8] cmp x1, x4 b.ne loop If the thread is preempted between the load of c->tid (into x1) and tid (into x4), and an allocation or free occurs in another thread (bumping the cpu_slab's tid), the thread will be stuck in the loop until s->cpu_slab->tid wraps, which may be forever in the absence of allocations/frees on the same CPU. This patch changes the loop condition to access c->tid with READ_ONCE. This ensures that the value is reloaded even when the compiler would otherwise assume it could cache the value, and also ensures that the load will not be torn. Signed-off-by: Mark Rutland Cc: Catalin Marinas Acked-by: Christoph Lameter Cc: David Rientjes Cc: Jesper Dangaard Brouer Cc: Joonsoo Kim Cc: Pekka Enberg Cc: Steve Capper Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 6832c4eab104..82c473780c91 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2449,7 +2449,8 @@ redo: do { tid = this_cpu_read(s->cpu_slab->tid); c = raw_cpu_ptr(s->cpu_slab); - } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid)); + } while (IS_ENABLED(CONFIG_PREEMPT) && + unlikely(tid != READ_ONCE(c->tid))); /* * Irqless object alloc/free algorithm used here depends on sequence @@ -2718,7 +2719,8 @@ redo: do { tid = this_cpu_read(s->cpu_slab->tid); c = raw_cpu_ptr(s->cpu_slab); - } while (IS_ENABLED(CONFIG_PREEMPT) && unlikely(tid != c->tid)); + } while (IS_ENABLED(CONFIG_PREEMPT) && + unlikely(tid != READ_ONCE(c->tid))); /* Same with comment on barrier() in slab_alloc_node() */ barrier(); From cfa869438282be84ad4110bba5027ef1fbbe71e4 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Wed, 25 Mar 2015 15:55:26 -0700 Subject: [PATCH 262/567] mm/page_alloc.c: call kernel_map_pages in unset_migrateype_isolate Commit 3c605096d315 ("mm/page_alloc: restrict max order of merging on isolated pageblock") changed the logic of unset_migratetype_isolate to check the buddy allocator and explicitly call __free_pages to merge. The page that is being freed in this path never had prep_new_page called so set_page_refcounted is called explicitly but there is no call to kernel_map_pages. With the default kernel_map_pages this is mostly harmless but if kernel_map_pages does any manipulation of the page tables (unmapping or setting pages to read only) this may trigger a fault: alloc_contig_range test_pages_isolated(ceb00, ced00) failed Unable to handle kernel paging request at virtual address ffffffc0cec00000 pgd = ffffffc045fc4000 [ffffffc0cec00000] *pgd=0000000000000000 Internal error: Oops: 9600004f [#1] PREEMPT SMP Modules linked in: exfatfs CPU: 1 PID: 23237 Comm: TimedEventQueue Not tainted 3.10.49-gc72ad36-dirty #1 task: ffffffc03de52100 ti: ffffffc015388000 task.ti: ffffffc015388000 PC is at memset+0xc8/0x1c0 LR is at kernel_map_pages+0x1ec/0x244 Fix this by calling kernel_map_pages to ensure the page is set in the page table properly Fixes: 3c605096d315 ("mm/page_alloc: restrict max order of merging on isolated pageblock") Signed-off-by: Laura Abbott Cc: Naoya Horiguchi Cc: Mel Gorman Acked-by: Rik van Riel Cc: Yasuaki Ishimatsu Cc: Zhang Yanfei Cc: Xishi Qiu Cc: Vladimir Davydov Acked-by: Joonsoo Kim Cc: Gioh Kim Cc: Michal Nazarewicz Cc: Marek Szyprowski Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_isolation.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/page_isolation.c b/mm/page_isolation.c index 72f5ac381ab3..755a42c76eb4 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -103,6 +103,7 @@ void unset_migratetype_isolate(struct page *page, unsigned migratetype) if (!is_migrate_isolate_page(buddy)) { __isolate_free_page(page, order); + kernel_map_pages(page, (1 << order), 1); set_page_refcounted(page); isolated_page = page; } From 3d5d472cf55d1be091e8a145f80602bf435ece85 Mon Sep 17 00:00:00 2001 From: Taesoo Kim Date: Wed, 25 Mar 2015 15:55:29 -0700 Subject: [PATCH 263/567] fs/affs/file.c: unlock/release page on error When affs_bread_ino() fails, correctly unlock the page and release the page cache with proper error value. All write_end() should unlock/release the page that was locked by write_beg(). Signed-off-by: Taesoo Kim Cc: Fabian Frederick Cc: Al Viro Cc: Geert Uytterhoeven Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/affs/file.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/fs/affs/file.c b/fs/affs/file.c index d2468bf95669..a91795e01a7f 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -699,8 +699,10 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping, boff = tmp % bsize; if (boff) { bh = affs_bread_ino(inode, bidx, 0); - if (IS_ERR(bh)) - return PTR_ERR(bh); + if (IS_ERR(bh)) { + written = PTR_ERR(bh); + goto err_first_bh; + } tmp = min(bsize - boff, to - from); BUG_ON(boff + tmp > bsize || tmp > bsize); memcpy(AFFS_DATA(bh) + boff, data + from, tmp); @@ -712,14 +714,16 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping, bidx++; } else if (bidx) { bh = affs_bread_ino(inode, bidx - 1, 0); - if (IS_ERR(bh)) - return PTR_ERR(bh); + if (IS_ERR(bh)) { + written = PTR_ERR(bh); + goto err_first_bh; + } } while (from + bsize <= to) { prev_bh = bh; bh = affs_getemptyblk_ino(inode, bidx); if (IS_ERR(bh)) - goto out; + goto err_bh; memcpy(AFFS_DATA(bh), data + from, bsize); if (buffer_new(bh)) { AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA); @@ -751,7 +755,7 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping, prev_bh = bh; bh = affs_bread_ino(inode, bidx, 1); if (IS_ERR(bh)) - goto out; + goto err_bh; tmp = min(bsize, to - from); BUG_ON(tmp > bsize); memcpy(AFFS_DATA(bh), data + from, tmp); @@ -790,12 +794,13 @@ done: if (tmp > inode->i_size) inode->i_size = AFFS_I(inode)->mmu_private = tmp; +err_first_bh: unlock_page(page); page_cache_release(page); return written; -out: +err_bh: bh = prev_bh; if (!written) written = PTR_ERR(bh); From 1f31e1b1963c240ced453489730bdfc9b0110ceb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 25 Mar 2015 15:55:31 -0700 Subject: [PATCH 264/567] MAINTAINERS: add Jan as DMI/SMBIOS support maintainer I am familiar with these drivers and I care about them so let me add myself as their maintainer. Signed-off-by: Jean Delvare Acked-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 12ebef95224d..88c09ca2584f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3252,6 +3252,13 @@ S: Maintained F: Documentation/hwmon/dme1737 F: drivers/hwmon/dme1737.c +DMI/SMBIOS SUPPORT +M: Jean Delvare +S: Maintained +F: drivers/firmware/dmi-id.c +F: drivers/firmware/dmi_scan.c +F: include/linux/dmi.h + DOCKING STATION DRIVER M: Shaohua Li L: linux-acpi@vger.kernel.org From 98cf21c61a7f5419d82f847c4d77bf6e96a76f5f Mon Sep 17 00:00:00 2001 From: Sergei Antonov Date: Wed, 25 Mar 2015 15:55:34 -0700 Subject: [PATCH 265/567] hfsplus: fix B-tree corruption after insertion at position 0 Fix B-tree corruption when a new record is inserted at position 0 in the node in hfs_brec_insert(). In this case a hfs_brec_update_parent() is called to update the parent index node (if exists) and it is passed hfs_find_data with a search_key containing a newly inserted key instead of the key to be updated. This results in an inconsistent index node. The bug reproduces on my machine after an extents overflow record for the catalog file (CNID=4) is inserted into the extents overflow B-tree. Because of a low (reserved) value of CNID=4, it has to become the first record in the first leaf node. The resulting first leaf node is correct: ---------------------------------------------------- | key0.CNID=4 | key1.CNID=123 | key2.CNID=456, ... | ---------------------------------------------------- But the parent index key0 still contains the previous key CNID=123: ----------------------- | key0.CNID=123 | ... | ----------------------- A change in hfs_brec_insert() makes hfs_brec_update_parent() work correctly by preventing it from getting fd->record=-1 value from __hfs_brec_find(). Along the way, I removed duplicate code with unification of the if condition. The resulting code is equivalent to the original code because node is never 0. Also hfs_brec_update_parent() will now return an error after getting a negative fd->record value. However, the return value of hfs_brec_update_parent() is not checked anywhere in the file and I'm leaving it unchanged by this patch. brec.c lacks error checking after some other calls too, but this issue is of less importance than the one being fixed by this patch. Signed-off-by: Sergei Antonov Cc: Joe Perches Reviewed-by: Vyacheslav Dubeyko Acked-by: Hin-Tak Leung Cc: Anton Altaparmakov Cc: Al Viro Cc: Christoph Hellwig Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hfsplus/brec.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index 6e560d56094b..754fdf8c6356 100644 --- a/fs/hfsplus/brec.c +++ b/fs/hfsplus/brec.c @@ -131,13 +131,16 @@ skip: hfs_bnode_write(node, entry, data_off + key_len, entry_len); hfs_bnode_dump(node); - if (new_node) { - /* update parent key if we inserted a key - * at the start of the first node - */ - if (!rec && new_node != node) - hfs_brec_update_parent(fd); + /* + * update parent key if we inserted a key + * at the start of the node and it is not the new node + */ + if (!rec && new_node != node) { + hfs_bnode_read_key(node, fd->search_key, data_off + size); + hfs_brec_update_parent(fd); + } + if (new_node) { hfs_bnode_put(fd->bnode); if (!new_node->parent) { hfs_btree_inc_height(tree); @@ -168,9 +171,6 @@ skip: goto again; } - if (!rec) - hfs_brec_update_parent(fd); - return 0; } @@ -370,6 +370,8 @@ again: if (IS_ERR(parent)) return PTR_ERR(parent); __hfs_brec_find(parent, fd, hfs_find_rec_by_key); + if (fd->record < 0) + return -ENOENT; hfs_bnode_dump(parent); rec = fd->record; From bea66fbd11af1ca98ae26855eea41eda8582923e Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 25 Mar 2015 15:55:37 -0700 Subject: [PATCH 266/567] mm: numa: group related processes based on VMA flags instead of page table flags These are three follow-on patches based on the xfsrepair workload Dave Chinner reported was problematic in 4.0-rc1 due to changes in page table management -- https://lkml.org/lkml/2015/3/1/226. Much of the problem was reduced by commit 53da3bc2ba9e ("mm: fix up numa read-only thread grouping logic") and commit ba68bc0115eb ("mm: thp: Return the correct value for change_huge_pmd"). It was known that the performance in 3.19 was still better even if is far less safe. This series aims to restore the performance without compromising on safety. For the test of this mail, I'm comparing 3.19 against 4.0-rc4 and the three patches applied on top autonumabench 3.19.0 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 vanilla vanilla vmwrite-v5r8 preserve-v5r8 slowscan-v5r8 Time System-NUMA01 124.00 ( 0.00%) 161.86 (-30.53%) 107.13 ( 13.60%) 103.13 ( 16.83%) 145.01 (-16.94%) Time System-NUMA01_THEADLOCAL 115.54 ( 0.00%) 107.64 ( 6.84%) 131.87 (-14.13%) 83.30 ( 27.90%) 92.35 ( 20.07%) Time System-NUMA02 9.35 ( 0.00%) 10.44 (-11.66%) 8.95 ( 4.28%) 10.72 (-14.65%) 8.16 ( 12.73%) Time System-NUMA02_SMT 3.87 ( 0.00%) 4.63 (-19.64%) 4.57 (-18.09%) 3.99 ( -3.10%) 3.36 ( 13.18%) Time Elapsed-NUMA01 570.06 ( 0.00%) 567.82 ( 0.39%) 515.78 ( 9.52%) 517.26 ( 9.26%) 543.80 ( 4.61%) Time Elapsed-NUMA01_THEADLOCAL 393.69 ( 0.00%) 384.83 ( 2.25%) 384.10 ( 2.44%) 384.31 ( 2.38%) 380.73 ( 3.29%) Time Elapsed-NUMA02 49.09 ( 0.00%) 49.33 ( -0.49%) 48.86 ( 0.47%) 48.78 ( 0.63%) 50.94 ( -3.77%) Time Elapsed-NUMA02_SMT 47.51 ( 0.00%) 47.15 ( 0.76%) 47.98 ( -0.99%) 48.12 ( -1.28%) 49.56 ( -4.31%) 3.19.0 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 vanilla vanillavmwrite-v5r8preserve-v5r8slowscan-v5r8 User 46334.60 46391.94 44383.95 43971.89 44372.12 System 252.84 284.66 252.61 201.24 249.00 Elapsed 1062.14 1050.96 998.68 1000.94 1026.78 Overall the system CPU usage is comparable and the test is naturally a bit variable. The slowing of the scanner hurts numa01 but on this machine it is an adverse workload and patches that dramatically help it often hurt absolutely everything else. Due to patch 2, the fault activity is interesting 3.19.0 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 vanilla vanillavmwrite-v5r8preserve-v5r8slowscan-v5r8 Minor Faults 2097811 2656646 2597249 1981230 1636841 Major Faults 362 450 365 364 365 Note the impact preserving the write bit across protection updates and fault reduces faults. NUMA alloc hit 1229008 1217015 1191660 1178322 1199681 NUMA alloc miss 0 0 0 0 0 NUMA interleave hit 0 0 0 0 0 NUMA alloc local 1228514 1216317 1190871 1177448 1199021 NUMA base PTE updates 245706197 240041607 238195516 244704842 115012800 NUMA huge PMD updates 479530 468448 464868 477573 224487 NUMA page range updates 491225557 479886983 476207932 489222218 229950144 NUMA hint faults 659753 656503 641678 656926 294842 NUMA hint local faults 381604 373963 360478 337585 186249 NUMA hint local percent 57 56 56 51 63 NUMA pages migrated 5412140 6374899 6266530 5277468 5755096 AutoNUMA cost 5121% 5083% 4994% 5097% 2388% Here the impact of slowing the PTE scanner on migratrion failures is obvious as "NUMA base PTE updates" and "NUMA huge PMD updates" are massively reduced even though the headline performance is very similar. As xfsrepair was the reported workload here is the impact of the series on it. xfsrepair 3.19.0 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 vanilla vanilla vmwrite-v5r8 preserve-v5r8 slowscan-v5r8 Min real-fsmark 1183.29 ( 0.00%) 1165.73 ( 1.48%) 1152.78 ( 2.58%) 1153.64 ( 2.51%) 1177.62 ( 0.48%) Min syst-fsmark 4107.85 ( 0.00%) 4027.75 ( 1.95%) 3986.74 ( 2.95%) 3979.16 ( 3.13%) 4048.76 ( 1.44%) Min real-xfsrepair 441.51 ( 0.00%) 463.96 ( -5.08%) 449.50 ( -1.81%) 440.08 ( 0.32%) 439.87 ( 0.37%) Min syst-xfsrepair 195.76 ( 0.00%) 278.47 (-42.25%) 262.34 (-34.01%) 203.70 ( -4.06%) 143.64 ( 26.62%) Amean real-fsmark 1188.30 ( 0.00%) 1177.34 ( 0.92%) 1157.97 ( 2.55%) 1158.21 ( 2.53%) 1182.22 ( 0.51%) Amean syst-fsmark 4111.37 ( 0.00%) 4055.70 ( 1.35%) 3987.19 ( 3.02%) 3998.72 ( 2.74%) 4061.69 ( 1.21%) Amean real-xfsrepair 450.88 ( 0.00%) 468.32 ( -3.87%) 454.14 ( -0.72%) 442.36 ( 1.89%) 440.59 ( 2.28%) Amean syst-xfsrepair 199.66 ( 0.00%) 290.60 (-45.55%) 277.20 (-38.84%) 204.68 ( -2.51%) 150.55 ( 24.60%) Stddev real-fsmark 4.12 ( 0.00%) 10.82 (-162.29%) 4.14 ( -0.28%) 5.98 (-45.05%) 4.60 (-11.53%) Stddev syst-fsmark 2.63 ( 0.00%) 20.32 (-671.82%) 0.37 ( 85.89%) 16.47 (-525.59%) 15.05 (-471.79%) Stddev real-xfsrepair 6.87 ( 0.00%) 4.55 ( 33.75%) 3.46 ( 49.58%) 1.78 ( 74.12%) 0.52 ( 92.50%) Stddev syst-xfsrepair 3.02 ( 0.00%) 10.30 (-241.37%) 13.17 (-336.37%) 0.71 ( 76.63%) 5.00 (-65.61%) CoeffVar real-fsmark 0.35 ( 0.00%) 0.92 (-164.73%) 0.36 ( -2.91%) 0.52 (-48.82%) 0.39 (-12.10%) CoeffVar syst-fsmark 0.06 ( 0.00%) 0.50 (-682.41%) 0.01 ( 85.45%) 0.41 (-543.22%) 0.37 (-478.78%) CoeffVar real-xfsrepair 1.52 ( 0.00%) 0.97 ( 36.21%) 0.76 ( 49.94%) 0.40 ( 73.62%) 0.12 ( 92.33%) CoeffVar syst-xfsrepair 1.51 ( 0.00%) 3.54 (-134.54%) 4.75 (-214.31%) 0.34 ( 77.20%) 3.32 (-119.63%) Max real-fsmark 1193.39 ( 0.00%) 1191.77 ( 0.14%) 1162.90 ( 2.55%) 1166.66 ( 2.24%) 1188.50 ( 0.41%) Max syst-fsmark 4114.18 ( 0.00%) 4075.45 ( 0.94%) 3987.65 ( 3.08%) 4019.45 ( 2.30%) 4082.80 ( 0.76%) Max real-xfsrepair 457.80 ( 0.00%) 474.60 ( -3.67%) 457.82 ( -0.00%) 444.42 ( 2.92%) 441.03 ( 3.66%) Max syst-xfsrepair 203.11 ( 0.00%) 303.65 (-49.50%) 294.35 (-44.92%) 205.33 ( -1.09%) 155.28 ( 23.55%) The really relevant lines as syst-xfsrepair which is the system CPU usage when running xfsrepair. Note that on my machine the overhead was 45% higher on 4.0-rc4 which may be part of what Dave is seeing. Once we preserve the write bit across faults, it's only 2.51% higher on average. With the full series applied, system CPU usage is 24.6% lower on average. Again, the impact of preserving the write bit on minor faults is obvious and the impact of slowing scanning after migration failures is obvious on the PTE updates. Note also that the number of pages migrated is much reduced even though the headline performance is comparable. 3.19.0 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 vanilla vanillavmwrite-v5r8preserve-v5r8slowscan-v5r8 Minor Faults 153466827 254507978 249163829 153501373 105737890 Major Faults 610 702 690 649 724 NUMA base PTE updates 217735049 210756527 217729596 216937111 144344993 NUMA huge PMD updates 129294 85044 106921 127246 79887 NUMA pages migrated 21938995 29705270 28594162 22687324 16258075 3.19.0 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 4.0.0-rc4 vanilla vanillavmwrite-v5r8preserve-v5r8slowscan-v5r8 Mean sdb-avgqusz 13.47 2.54 2.55 2.47 2.49 Mean sdb-avgrqsz 202.32 140.22 139.50 139.02 138.12 Mean sdb-await 25.92 5.09 5.33 5.02 5.22 Mean sdb-r_await 4.71 0.19 0.83 0.51 0.11 Mean sdb-w_await 104.13 5.21 5.38 5.05 5.32 Mean sdb-svctm 0.59 0.13 0.14 0.13 0.14 Mean sdb-rrqm 0.16 0.00 0.00 0.00 0.00 Mean sdb-wrqm 3.59 1799.43 1826.84 1812.21 1785.67 Max sdb-avgqusz 111.06 12.13 14.05 11.66 15.60 Max sdb-avgrqsz 255.60 190.34 190.01 187.33 191.78 Max sdb-await 168.24 39.28 49.22 44.64 65.62 Max sdb-r_await 660.00 52.00 280.00 76.00 12.00 Max sdb-w_await 7804.00 39.28 49.22 44.64 65.62 Max sdb-svctm 4.00 2.82 2.86 1.98 2.84 Max sdb-rrqm 8.30 0.00 0.00 0.00 0.00 Max sdb-wrqm 34.20 5372.80 5278.60 5386.60 5546.15 FWIW, I also checked SPECjbb in different configurations but it's similar observations -- minor faults lower, PTE update activity lower and performance is roughly comparable against 3.19. This patch (of 3): Threads that share writable data within pages are grouped together as related tasks. This decision is based on whether the PTE is marked dirty which is subject to timing races between the PTE scanner update and when the application writes the page. If the page is file-backed, then background flushes and sync also affect placement. This is unpredictable behaviour which is impossible to reason about so this patch makes grouping decisions based on the VMA flags. Signed-off-by: Mel Gorman Reported-by: Dave Chinner Tested-by: Dave Chinner Cc: Ingo Molnar Cc: Aneesh Kumar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 13 ++----------- mm/memory.c | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 626e93db28ba..2f12e9fcf1a2 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1291,17 +1291,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, flags |= TNF_FAULT_LOCAL; } - /* - * Avoid grouping on DSO/COW pages in specific and RO pages - * in general, RO pages shouldn't hurt as much anyway since - * they can be in shared cache state. - * - * FIXME! This checks "pmd_dirty()" as an approximation of - * "is this a read-only page", since checking "pmd_write()" - * is even more broken. We haven't actually turned this into - * a writable page, so pmd_write() will always be false. - */ - if (!pmd_dirty(pmd)) + /* See similar comment in do_numa_page for explanation */ + if (!(vma->vm_flags & VM_WRITE)) flags |= TNF_NO_GROUP; /* diff --git a/mm/memory.c b/mm/memory.c index 411144f977b1..20beb6647dba 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3069,16 +3069,19 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, } /* - * Avoid grouping on DSO/COW pages in specific and RO pages - * in general, RO pages shouldn't hurt as much anyway since - * they can be in shared cache state. + * Avoid grouping on RO pages in general. RO pages shouldn't hurt as + * much anyway since they can be in shared cache state. This misses + * the case where a mapping is writable but the process never writes + * to it but pte_write gets cleared during protection updates and + * pte_dirty has unpredictable behaviour between PTE scan updates, + * background writeback, dirty balancing and application behaviour. * - * FIXME! This checks "pmd_dirty()" as an approximation of - * "is this a read-only page", since checking "pmd_write()" - * is even more broken. We haven't actually turned this into - * a writable page, so pmd_write() will always be false. + * TODO: Note that the ideal here would be to avoid a situation where a + * NUMA fault is taken immediately followed by a write fault in + * some cases which would have lower overhead overall but would be + * invasive as the fault paths would need to be unified. */ - if (!pte_dirty(pte)) + if (!(vma->vm_flags & VM_WRITE)) flags |= TNF_NO_GROUP; /* From b191f9b106ea1a24a711dbebb2925d3313da5852 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 25 Mar 2015 15:55:40 -0700 Subject: [PATCH 267/567] mm: numa: preserve PTE write permissions across a NUMA hinting fault Protecting a PTE to trap a NUMA hinting fault clears the writable bit and further faults are needed after trapping a NUMA hinting fault to set the writable bit again. This patch preserves the writable bit when trapping NUMA hinting faults. The impact is obvious from the number of minor faults trapped during the basis balancing benchmark and the system CPU usage; autonumabench 4.0.0-rc4 4.0.0-rc4 baseline preserve Time System-NUMA01 107.13 ( 0.00%) 103.13 ( 3.73%) Time System-NUMA01_THEADLOCAL 131.87 ( 0.00%) 83.30 ( 36.83%) Time System-NUMA02 8.95 ( 0.00%) 10.72 (-19.78%) Time System-NUMA02_SMT 4.57 ( 0.00%) 3.99 ( 12.69%) Time Elapsed-NUMA01 515.78 ( 0.00%) 517.26 ( -0.29%) Time Elapsed-NUMA01_THEADLOCAL 384.10 ( 0.00%) 384.31 ( -0.05%) Time Elapsed-NUMA02 48.86 ( 0.00%) 48.78 ( 0.16%) Time Elapsed-NUMA02_SMT 47.98 ( 0.00%) 48.12 ( -0.29%) 4.0.0-rc4 4.0.0-rc4 baseline preserve User 44383.95 43971.89 System 252.61 201.24 Elapsed 998.68 1000.94 Minor Faults 2597249 1981230 Major Faults 365 364 There is a similar drop in system CPU usage using Dave Chinner's xfsrepair workload 4.0.0-rc4 4.0.0-rc4 baseline preserve Amean real-xfsrepair 454.14 ( 0.00%) 442.36 ( 2.60%) Amean syst-xfsrepair 277.20 ( 0.00%) 204.68 ( 26.16%) The patch looks hacky but the alternatives looked worse. The tidest was to rewalk the page tables after a hinting fault but it was more complex than this approach and the performance was worse. It's not generally safe to just mark the page writable during the fault if it's a write fault as it may have been read-only for COW so that approach was discarded. Signed-off-by: Mel Gorman Reported-by: Dave Chinner Tested-by: Dave Chinner Cc: Ingo Molnar Cc: Aneesh Kumar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 9 ++++++++- mm/memory.c | 8 +++----- mm/mprotect.c | 3 +++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 2f12e9fcf1a2..0a42d1521aa4 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1260,6 +1260,7 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, int target_nid, last_cpupid = -1; bool page_locked; bool migrated = false; + bool was_writable; int flags = 0; /* A PROT_NONE fault should not end up here */ @@ -1354,7 +1355,10 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, goto out; clear_pmdnuma: BUG_ON(!PageLocked(page)); + was_writable = pmd_write(pmd); pmd = pmd_modify(pmd, vma->vm_page_prot); + if (was_writable) + pmd = pmd_mkwrite(pmd); set_pmd_at(mm, haddr, pmdp, pmd); update_mmu_cache_pmd(vma, addr, pmdp); unlock_page(page); @@ -1478,6 +1482,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, if (__pmd_trans_huge_lock(pmd, vma, &ptl) == 1) { pmd_t entry; + bool preserve_write = prot_numa && pmd_write(*pmd); ret = 1; /* @@ -1493,9 +1498,11 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, if (!prot_numa || !pmd_protnone(*pmd)) { entry = pmdp_get_and_clear_notify(mm, addr, pmd); entry = pmd_modify(entry, newprot); + if (preserve_write) + entry = pmd_mkwrite(entry); ret = HPAGE_PMD_NR; set_pmd_at(mm, addr, pmd, entry); - BUG_ON(pmd_write(entry)); + BUG_ON(!preserve_write && pmd_write(entry)); } spin_unlock(ptl); } diff --git a/mm/memory.c b/mm/memory.c index 20beb6647dba..d20e12da3a3c 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3035,6 +3035,7 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, int last_cpupid; int target_nid; bool migrated = false; + bool was_writable = pte_write(pte); int flags = 0; /* A PROT_NONE fault should not end up here */ @@ -3059,6 +3060,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, /* Make it present again */ pte = pte_modify(pte, vma->vm_page_prot); pte = pte_mkyoung(pte); + if (was_writable) + pte = pte_mkwrite(pte); set_pte_at(mm, addr, ptep, pte); update_mmu_cache(vma, addr, ptep); @@ -3075,11 +3078,6 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, * to it but pte_write gets cleared during protection updates and * pte_dirty has unpredictable behaviour between PTE scan updates, * background writeback, dirty balancing and application behaviour. - * - * TODO: Note that the ideal here would be to avoid a situation where a - * NUMA fault is taken immediately followed by a write fault in - * some cases which would have lower overhead overall but would be - * invasive as the fault paths would need to be unified. */ if (!(vma->vm_flags & VM_WRITE)) flags |= TNF_NO_GROUP; diff --git a/mm/mprotect.c b/mm/mprotect.c index 44727811bf4c..88584838e704 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -75,6 +75,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, oldpte = *pte; if (pte_present(oldpte)) { pte_t ptent; + bool preserve_write = prot_numa && pte_write(oldpte); /* * Avoid trapping faults against the zero or KSM @@ -94,6 +95,8 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, ptent = ptep_modify_prot_start(mm, addr, pte); ptent = pte_modify(ptent, newprot); + if (preserve_write) + ptent = pte_mkwrite(ptent); /* Avoid taking write faults for known dirty pages */ if (dirty_accountable && pte_dirty(ptent) && From 074c238177a75f5e79af3b2cb6a84e54823ef950 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 25 Mar 2015 15:55:42 -0700 Subject: [PATCH 268/567] mm: numa: slow PTE scan rate if migration failures occur Dave Chinner reported the following on https://lkml.org/lkml/2015/3/1/226 Across the board the 4.0-rc1 numbers are much slower, and the degradation is far worse when using the large memory footprint configs. Perf points straight at the cause - this is from 4.0-rc1 on the "-o bhash=101073" config: - 56.07% 56.07% [kernel] [k] default_send_IPI_mask_sequence_phys - default_send_IPI_mask_sequence_phys - 99.99% physflat_send_IPI_mask - 99.37% native_send_call_func_ipi smp_call_function_many - native_flush_tlb_others - 99.85% flush_tlb_page ptep_clear_flush try_to_unmap_one rmap_walk try_to_unmap migrate_pages migrate_misplaced_page - handle_mm_fault - 99.73% __do_page_fault trace_do_page_fault do_async_page_fault + async_page_fault 0.63% native_send_call_func_single_ipi generic_exec_single smp_call_function_single This is showing excessive migration activity even though excessive migrations are meant to get throttled. Normally, the scan rate is tuned on a per-task basis depending on the locality of faults. However, if migrations fail for any reason then the PTE scanner may scan faster if the faults continue to be remote. This means there is higher system CPU overhead and fault trapping at exactly the time we know that migrations cannot happen. This patch tracks when migration failures occur and slows the PTE scanner. Signed-off-by: Mel Gorman Reported-by: Dave Chinner Tested-by: Dave Chinner Cc: Ingo Molnar Cc: Aneesh Kumar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 9 +++++---- kernel/sched/fair.c | 8 ++++++-- mm/huge_memory.c | 3 ++- mm/memory.c | 3 ++- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 6d77432e14ff..a419b65770d6 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1625,11 +1625,11 @@ struct task_struct { /* * numa_faults_locality tracks if faults recorded during the last - * scan window were remote/local. The task scan period is adapted - * based on the locality of the faults with different weights - * depending on whether they were shared or private faults + * scan window were remote/local or failed to migrate. The task scan + * period is adapted based on the locality of the faults with different + * weights depending on whether they were shared or private faults */ - unsigned long numa_faults_locality[2]; + unsigned long numa_faults_locality[3]; unsigned long numa_pages_migrated; #endif /* CONFIG_NUMA_BALANCING */ @@ -1719,6 +1719,7 @@ struct task_struct { #define TNF_NO_GROUP 0x02 #define TNF_SHARED 0x04 #define TNF_FAULT_LOCAL 0x08 +#define TNF_MIGRATE_FAIL 0x10 #ifdef CONFIG_NUMA_BALANCING extern void task_numa_fault(int last_node, int node, int pages, int flags); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 7ce18f3c097a..bcfe32088b37 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1609,9 +1609,11 @@ static void update_task_scan_period(struct task_struct *p, /* * If there were no record hinting faults then either the task is * completely idle or all activity is areas that are not of interest - * to automatic numa balancing. Scan slower + * to automatic numa balancing. Related to that, if there were failed + * migration then it implies we are migrating too quickly or the local + * node is overloaded. In either case, scan slower */ - if (local + shared == 0) { + if (local + shared == 0 || p->numa_faults_locality[2]) { p->numa_scan_period = min(p->numa_scan_period_max, p->numa_scan_period << 1); @@ -2080,6 +2082,8 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags) if (migrated) p->numa_pages_migrated += pages; + if (flags & TNF_MIGRATE_FAIL) + p->numa_faults_locality[2] += pages; p->numa_faults[task_faults_idx(NUMA_MEMBUF, mem_node, priv)] += pages; p->numa_faults[task_faults_idx(NUMA_CPUBUF, cpu_node, priv)] += pages; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 0a42d1521aa4..51b3e7c64622 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1350,7 +1350,8 @@ int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, if (migrated) { flags |= TNF_MIGRATED; page_nid = target_nid; - } + } else + flags |= TNF_MIGRATE_FAIL; goto out; clear_pmdnuma: diff --git a/mm/memory.c b/mm/memory.c index d20e12da3a3c..97839f5c8c30 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3103,7 +3103,8 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma, if (migrated) { page_nid = target_nid; flags |= TNF_MIGRATED; - } + } else + flags |= TNF_MIGRATE_FAIL; out: if (page_nid != -1) From b7b04004ecd9e58cdc6c6ff92f251d5ac5c0adb2 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 25 Mar 2015 15:55:45 -0700 Subject: [PATCH 269/567] mm: numa: mark huge PTEs young when clearing NUMA hinting faults Base PTEs are marked young when the NUMA hinting information is cleared but the same does not happen for huge pages which this patch addresses. Note that migrated pages are not marked young as the base page migration code does not assume that migrated pages have been referenced. This could be addressed but beyond the scope of this series which is aimed at Dave Chinners shrink workload that is unlikely to be affected by this issue. Signed-off-by: Mel Gorman Cc: Dave Chinner Cc: Ingo Molnar Cc: Aneesh Kumar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 51b3e7c64622..6817b0350c71 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1358,6 +1358,7 @@ clear_pmdnuma: BUG_ON(!PageLocked(page)); was_writable = pmd_write(pmd); pmd = pmd_modify(pmd, vma->vm_page_prot); + pmd = pmd_mkyoung(pmd); if (was_writable) pmd = pmd_mkwrite(pmd); set_pmd_at(mm, haddr, pmdp, pmd); From c5952338bfc234e54deda45b7228f610a545e28a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 23 Mar 2015 10:53:42 -0400 Subject: [PATCH 270/567] nfsd: return correct openowner when there is a race to put one in the hash alloc_init_open_stateowner can return an already freed entry if there is a race to put openowners in the hashtable. In commit 7ffb588086e9, we changed it so that we allocate and initialize an openowner, and then check to see if a matching one got stuffed into the hashtable in the meantime. If it did, then we free the one we just allocated and take a reference on the one already there. There is a bug here though. The code will then return the pointer to the one that was allocated (and has now been freed). This wasn't evident before as this race almost never occurred. The Linux kernel client used to serialize requests for a single openowner. That has changed now with v4.0 kernels, and this race can now easily occur. Fixes: 7ffb588086e9 Cc: # v3.17+ Cc: Trond Myklebust Reported-by: Christoph Hellwig Reviewed-by: Christoph Hellwig Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d2f2c37dc2db..cf29d1a698b3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3221,7 +3221,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, } else nfs4_free_openowner(&oo->oo_owner); spin_unlock(&clp->cl_lock); - return oo; + return ret; } static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { From 340f0ba1c6c8412aa35fd6476044836b84361ea6 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 23 Mar 2015 11:02:30 -0400 Subject: [PATCH 271/567] nfsd: return correct lockowner when there is a race on hash insert alloc_init_lock_stateowner can return an already freed entry if there is a race to put openowners in the hashtable. Noticed by inspection after Jeff Layton fixed the same bug for open owners. Depending on client behavior, this one may be trickier to trigger in practice. Fixes: c58c6610ec24 "nfsd: Protect adding/removing lock owners using client_lock" Cc: Cc: Trond Myklebust Acked-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index cf29d1a698b3..8ba1d888f1e6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5062,7 +5062,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, } else nfs4_free_lockowner(&lo->lo_owner); spin_unlock(&clp->cl_lock); - return lo; + return ret; } static void From 853695230e9847445ad42c330d023fca2324fd56 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Sun, 22 Mar 2015 22:16:40 +0800 Subject: [PATCH 272/567] NFSD: Printk blocklayout length and offset as format 0x%llx When testing pnfs with nfsd_debug on, nfsd print a negative number of layout length and foff in nfsd4_block_proc_layoutget as, "GET: -xxxx:-xxx 2" Signed-off-by: Kinglong Mee Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/blocklayout.c | 2 +- fs/nfsd/blocklayoutxdr.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c index cdbc78c72542..03d647bf195d 100644 --- a/fs/nfsd/blocklayout.c +++ b/fs/nfsd/blocklayout.c @@ -137,7 +137,7 @@ nfsd4_block_proc_layoutget(struct inode *inode, const struct svc_fh *fhp, seg->offset = iomap.offset; seg->length = iomap.length; - dprintk("GET: %lld:%lld %d\n", bex->foff, bex->len, bex->es); + dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es); return 0; out_error: diff --git a/fs/nfsd/blocklayoutxdr.c b/fs/nfsd/blocklayoutxdr.c index 9da89fddab33..9aa2796da90d 100644 --- a/fs/nfsd/blocklayoutxdr.c +++ b/fs/nfsd/blocklayoutxdr.c @@ -122,19 +122,19 @@ nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, p = xdr_decode_hyper(p, &bex.foff); if (bex.foff & (block_size - 1)) { - dprintk("%s: unaligned offset %lld\n", + dprintk("%s: unaligned offset 0x%llx\n", __func__, bex.foff); goto fail; } p = xdr_decode_hyper(p, &bex.len); if (bex.len & (block_size - 1)) { - dprintk("%s: unaligned length %lld\n", + dprintk("%s: unaligned length 0x%llx\n", __func__, bex.foff); goto fail; } p = xdr_decode_hyper(p, &bex.soff); if (bex.soff & (block_size - 1)) { - dprintk("%s: unaligned disk offset %lld\n", + dprintk("%s: unaligned disk offset 0x%llx\n", __func__, bex.soff); goto fail; } From 376675daeac3dc0e39b84ca90f0bdc41a9d44d46 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Sun, 22 Mar 2015 22:17:10 +0800 Subject: [PATCH 273/567] NFSD: Take care the return value from nfsd4_encode_stateid Signed-off-by: Kinglong Mee Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c76654c3605f..5fb7e78169a6 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4135,7 +4135,7 @@ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, return nfserr_resource; *p++ = cpu_to_be32(lrp->lrs_present); if (lrp->lrs_present) - nfsd4_encode_stateid(xdr, &lrp->lr_sid); + return nfsd4_encode_stateid(xdr, &lrp->lr_sid); return nfs_ok; } #endif /* CONFIG_NFSD_PNFS */ From 7890203da2cb9b861dae9bdb88f882f3e03baec9 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Sun, 22 Mar 2015 22:17:20 +0800 Subject: [PATCH 274/567] NFSD: Fix bad update of layout in nfsd4_return_file_layout With return layout as, (seg is return layout, lo is record layout) seg->offset <= lo->offset and layout_end(seg) < layout_end(lo), nfsd should update lo's offset to seg's end, and, seg->offset > lo->offset and layout_end(seg) >= layout_end(lo), nfsd should update lo's end to seg's offset. Fixes: 9cf514ccfa ("nfsd: implement pNFS operations") Signed-off-by: Kinglong Mee Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4layouts.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 6964613bad90..80e236bf79fc 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -440,15 +440,14 @@ nfsd4_return_file_layout(struct nfs4_layout *lp, struct nfsd4_layout_seg *seg, list_move_tail(&lp->lo_perstate, reaplist); return; } - end = seg->offset; + lo->offset = layout_end(seg); } else { /* retain the whole layout segment on a split. */ if (layout_end(seg) < end) { dprintk("%s: split not supported\n", __func__); return; } - - lo->offset = layout_end(seg); + end = seg->offset; } layout_update_len(lo, end); From 6914e1e3f63caa829431160f0f7093292daef2d5 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 26 Mar 2015 09:25:44 +0530 Subject: [PATCH 275/567] ARC: SA_SIGINFO ucontext regs off-by-one The regfile provided to SA_SIGINFO signal handler as ucontext was off by one due to pt_regs gutter cleanups in 2013. Before handling signal, user pt_regs are copied onto user_regs_struct and copied back later. Both structs are binary compatible. This was all fine until commit 2fa919045b72 (ARC: pt_regs update #2) which removed the empty stack slot at top of pt_regs (corresponding to first pad) and made the corresponding fixup in struct user_regs_struct (the pad in there was moved out of @scratch - not removed altogether as it is part of ptrace ABI) struct user_regs_struct { + long pad; struct { - long pad; long bta, lp_start, lp_end,.... } scratch; ... } This meant that now user_regs_struct was off by 1 reg w.r.t pt_regs and signal code needs to user_regs_struct.scratch to reflect it as pt_regs, which is what this commit does. This problem was hidden for 2 years, because both save/restore, despite using wrong location, were using the same location. Only an interim inspection (reproducer below) exposed the issue. void handle_segv(int signo, siginfo_t *info, void *context) { ucontext_t *uc = context; struct user_regs_struct *regs = &(uc->uc_mcontext.regs); printf("regs %x %x\n", <=== prints 7 8 (vs. 8 9) regs->scratch.r8, regs->scratch.r9); } int main() { struct sigaction sa; sa.sa_sigaction = handle_segv; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); sigaction(SIGSEGV, &sa, NULL); asm volatile( "mov r7, 7 \n" "mov r8, 8 \n" "mov r9, 9 \n" "mov r10, 10 \n" :::"r7","r8","r9","r10"); *((unsigned int*)0x10) = 0; } Fixes: 2fa919045b72ec892e "ARC: pt_regs update #2: Remove unused gutter at start of pt_regs" CC: Signed-off-by: Vineet Gupta --- arch/arc/kernel/signal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c index 114234e83caa..fdd3c98dfb0f 100644 --- a/arch/arc/kernel/signal.c +++ b/arch/arc/kernel/signal.c @@ -67,7 +67,7 @@ stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { int err; - err = __copy_to_user(&(sf->uc.uc_mcontext.regs), regs, + err = __copy_to_user(&(sf->uc.uc_mcontext.regs.scratch), regs, sizeof(sf->uc.uc_mcontext.regs.scratch)); err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t)); @@ -83,7 +83,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf) if (!err) set_current_blocked(&set); - err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs), + err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs.scratch), sizeof(sf->uc.uc_mcontext.regs.scratch)); return err; From e4140819dadc3624accac8294881bca8a3cba4ed Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 26 Mar 2015 11:14:41 +0530 Subject: [PATCH 276/567] ARC: signal handling robustify A malicious signal handler / restorer can DOS the system by fudging the user regs saved on stack, causing weird things such as sigreturn returning to user mode PC but cpu state still being kernel mode.... Ensure that in sigreturn path status32 always has U bit; any other bogosity (gargbage PC etc) will be taken care of by normal user mode exceptions mechanisms. Reproducer signal handler: void handle_sig(int signo, siginfo_t *info, void *context) { ucontext_t *uc = context; struct user_regs_struct *regs = &(uc->uc_mcontext.regs); regs->scratch.status32 = 0; } Before the fix, kernel would go off to weeds like below: --------->8----------- [ARCLinux]$ ./signal-test Path: /signal-test CPU: 0 PID: 61 Comm: signal-test Not tainted 4.0.0-rc5+ #65 task: 8f177880 ti: 5ffe6000 task.ti: 8f15c000 [ECR ]: 0x00220200 => Invalid Write @ 0x00000010 by insn @ 0x00010698 [EFA ]: 0x00000010 [BLINK ]: 0x2007c1ee [ERET ]: 0x10698 [STAT32]: 0x00000000 : <-------- BTA: 0x00010680 SP: 0x5ffe7e48 FP: 0x00000000 LPS: 0x20003c6c LPE: 0x20003c70 LPC: 0x00000000 ... --------->8----------- Reported-by: Alexey Brodkin Cc: Signed-off-by: Vineet Gupta --- arch/arc/kernel/signal.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c index fdd3c98dfb0f..edda76fae83f 100644 --- a/arch/arc/kernel/signal.c +++ b/arch/arc/kernel/signal.c @@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn) /* Don't restart from sigreturn */ syscall_wont_restart(regs); + /* + * Ensure that sigreturn always returns to user mode (in case the + * regs saved on user stack got fudged between save and sigreturn) + * Otherwise it is easy to panic the kernel with a custom + * signal handler and/or restorer which clobberes the status32/ret + * to return to a bogus location in kernel mode. + */ + regs->status32 |= STATUS_U_MASK; + return regs->r0; badframe: @@ -229,8 +238,11 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) /* * handler returns using sigreturn stub provided already by userpsace + * If not, nuke the process right away */ - BUG_ON(!(ksig->ka.sa.sa_flags & SA_RESTORER)); + if(!(ksig->ka.sa.sa_flags & SA_RESTORER)) + return 1; + regs->blink = (unsigned long)ksig->ka.sa.sa_restorer; /* User Stack for signal handler will be above the frame just carved */ @@ -296,12 +308,12 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) { sigset_t *oldset = sigmask_to_save(); - int ret; + int failed; /* Set up the stack frame */ - ret = setup_rt_frame(ksig, oldset, regs); + failed = setup_rt_frame(ksig, oldset, regs); - signal_setup_done(ret, ksig, 0); + signal_setup_done(failed, ksig, 0); } void do_signal(struct pt_regs *regs) From db48abf4367cb1f9e118defee0a37238638c2752 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 26 Mar 2015 13:28:39 +0800 Subject: [PATCH 277/567] ALSA: hda_intel: apply the Seperate stream_tag for Sunrise Point The total stream number of Sunrise Point's input and output stream exceeds 15, which will cause some streams do not work because of the overflow on SDxCTL.STRM field if using the legacy stream tag allocation method. This patch uses the new stream tag allocation method by add the flag AZX_DCAPS_SEPARATE_STREAM_TAG for Skylake platform. Signed-off-by: Libin Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4ca3d5d02436..a8a1e14272a1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1989,7 +1989,7 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Sunrise Point */ { PCI_DEVICE(0x8086, 0xa170), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, From 832a3aad1e2927b1684e7369c9f36a370e0b95da Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 18 Mar 2015 18:19:22 +0000 Subject: [PATCH 278/567] drm/i915: Keep ring->active_list and ring->requests_list consistent If we retire requests last, we may use a later seqno and so clear the requests lists without clearing the active list, leading to confusion. Hence we should retire requests first for consistency with the early return. The order used to be important as the lifecycle for the object on the active list was determined by request->seqno. However, the requests themselves are now reference counted removing the constraint from the order of retirement. Fixes regression from commit 1b5a433a4dd967b125131da42b89b5cc0d5b1f57 Author: John Harrison Date: Mon Nov 24 18:49:42 2014 +0000 drm/i915: Convert 'i915_seqno_passed' calls into 'i915_gem_request_completed ' and a WARNING: CPU: 0 PID: 1383 at drivers/gpu/drm/i915/i915_gem_evict.c:279 i915_gem_evict_vm+0x10c/0x140() WARN_ON(!list_empty(&vm->active_list)) Identified by updating WATCH_LISTS: [drm:i915_verify_lists] *ERROR* blitter ring: active list not empty, but no requests WARNING: CPU: 0 PID: 681 at drivers/gpu/drm/i915/i915_gem.c:2751 i915_gem_retire_requests_ring+0x149/0x230() WARN_ON(i915_verify_lists(ring->dev)) Note that this is only a problem in evict_vm where the following happens after a retire_request has cleaned out all requests, but not all active bo: - intel_ring_idle called from i915_gpu_idle notices that no requests are outstanding and immediately returns. - i915_gem_retire_requests_ring called from i915_gem_retire_requests also immediately returns when there's no request, still leaving the bo on the active list. - evict_vm hits the WARN_ON(!list_empty(&vm->active_list)) after evicting all active objects that there's still stuff left that shouldn't be there. Signed-off-by: Chris Wilson Cc: John Harrison Cc: Daniel Vetter Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem.c | 38 ++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5b205863b659..27ea6bdebce7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2737,24 +2737,11 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) WARN_ON(i915_verify_lists(ring->dev)); - /* Move any buffers on the active list that are no longer referenced - * by the ringbuffer to the flushing/inactive lists as appropriate, - * before we free the context associated with the requests. + /* Retire requests first as we use it above for the early return. + * If we retire requests last, we may use a later seqno and so clear + * the requests lists without clearing the active list, leading to + * confusion. */ - while (!list_empty(&ring->active_list)) { - struct drm_i915_gem_object *obj; - - obj = list_first_entry(&ring->active_list, - struct drm_i915_gem_object, - ring_list); - - if (!i915_gem_request_completed(obj->last_read_req, true)) - break; - - i915_gem_object_move_to_inactive(obj); - } - - while (!list_empty(&ring->request_list)) { struct drm_i915_gem_request *request; struct intel_ringbuffer *ringbuf; @@ -2789,6 +2776,23 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) i915_gem_free_request(request); } + /* Move any buffers on the active list that are no longer referenced + * by the ringbuffer to the flushing/inactive lists as appropriate, + * before we free the context associated with the requests. + */ + while (!list_empty(&ring->active_list)) { + struct drm_i915_gem_object *obj; + + obj = list_first_entry(&ring->active_list, + struct drm_i915_gem_object, + ring_list); + + if (!i915_gem_request_completed(obj->last_read_req, true)) + break; + + i915_gem_object_move_to_inactive(obj); + } + if (unlikely(ring->trace_irq_req && i915_gem_request_completed(ring->trace_irq_req, true))) { ring->irq_put(ring); From 11bc26fe372fa6da81c82c68f755d2795838a640 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Thu, 26 Mar 2015 10:27:06 +0100 Subject: [PATCH 279/567] clocksource/drivers: Fix various !CONFIG_HAS_IOMEM build errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix !CONFIG_HAS_IOMEM related build failures in three clocksource drivers. The build failures have the pattern of: drivers/clocksource/sh_cmt.c: In function ‘sh_cmt_map_memory’: drivers/clocksource/sh_cmt.c:920:2: error: implicit declaration of function ‘ioremap_nocache’ [-Werror=implicit-function-declaration] cmt->mapbase = ioremap_nocache(mem->start, resource_size(mem)); Signed-off-by: Richard Weinberger Signed-off-by: Daniel Lezcano Acked-by: Geert Uytterhoeven Cc: maxime.ripard@free-electrons.com Link: http://lkml.kernel.org/r/1427362029-6511-1-git-send-email-daniel.lezcano@linaro.org Signed-off-by: Ingo Molnar --- drivers/clocksource/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 68161f7a07d6..a0b036ccb118 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -192,6 +192,7 @@ config SYS_SUPPORTS_EM_STI config SH_TIMER_CMT bool "Renesas CMT timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS + depends on HAS_IOMEM default SYS_SUPPORTS_SH_CMT help This enables build of a clocksource and clockevent driver for @@ -201,6 +202,7 @@ config SH_TIMER_CMT config SH_TIMER_MTU2 bool "Renesas MTU2 timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS + depends on HAS_IOMEM default SYS_SUPPORTS_SH_MTU2 help This enables build of a clockevent driver for the Multi-Function @@ -210,6 +212,7 @@ config SH_TIMER_MTU2 config SH_TIMER_TMU bool "Renesas TMU timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS + depends on HAS_IOMEM default SYS_SUPPORTS_SH_TMU help This enables build of a clocksource and clockevent driver for From 6e206020324c50a95486f6b279a53512febed92d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 26 Mar 2015 10:27:09 +0100 Subject: [PATCH 280/567] clocksource/drivers/sun5i: Fix cpufreq interaction with sched_clock() The sun5i timer is used as the sched-clock on certain systems, and ever since we started using cpufreq, the cpu clock (that is one of the timer's clock indirect parent) now changes as well, along with the actual sched_clock() rate. This is not accurate and not desirable. We can safely remove the sun5i sched-clock on those systems, since we have other reliable sched_clock() sources in the system. Tested-by: Hans de Goede Signed-off-by: Maxime Ripard Signed-off-by: Daniel Lezcano [ Improved the changelog. ] Cc: richard@nod.at Link: http://lkml.kernel.org/r/1427362029-6511-4-git-send-email-daniel.lezcano@linaro.org Signed-off-by: Ingo Molnar --- drivers/clocksource/timer-sun5i.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 5dcbf90b8015..58597fbcc046 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -137,11 +136,6 @@ static struct irqaction sun5i_timer_irq = { .dev_id = &sun5i_clockevent, }; -static u64 sun5i_timer_sched_read(void) -{ - return ~readl(timer_base + TIMER_CNTVAL_LO_REG(1)); -} - static void __init sun5i_timer_init(struct device_node *node) { struct reset_control *rstc; @@ -172,7 +166,6 @@ static void __init sun5i_timer_init(struct device_node *node) writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD, timer_base + TIMER_CTL_REG(1)); - sched_clock_register(sun5i_timer_sched_read, 32, rate); clocksource_mmio_init(timer_base + TIMER_CNTVAL_LO_REG(1), node->name, rate, 340, 32, clocksource_mmio_readl_down); From af95b41426e0b58279f8ff0ebe420df49a4e96b8 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 26 Mar 2015 17:14:55 +0800 Subject: [PATCH 281/567] ALSA: hda - Add one more node in the EAPD supporting candidate list We have a HP machine which use the codec node 0x17 connecting the internal speaker, and from the node capability, we saw the EAPD, if we don't set the EAPD on for this node, the internal speaker can't output any sound. Cc: BugLink: https://bugs.launchpad.net/bugs/1436745 Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7b0f72c5c6f1..74382137b9f5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -396,7 +396,7 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) { /* We currently only handle front, HP */ static hda_nid_t pins[] = { - 0x0f, 0x10, 0x14, 0x15, 0 + 0x0f, 0x10, 0x14, 0x15, 0x17, 0 }; hda_nid_t *p; for (p = pins; *p; p++) From 3164a803416832d61268b758112e8dfd7e35cdf7 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 5 Feb 2015 19:24:25 +0000 Subject: [PATCH 282/567] drm/i915: Fix atomic state when reusing the firmware fb Right now, we get a warning when taking over the firmware fb: [drm:drm_atomic_plane_check] FB set but no CRTC with the following backtrace: [] drm_atomic_check_only+0x35d/0x510 [drm] [] drm_atomic_commit+0x17/0x60 [drm] [] drm_atomic_helper_plane_set_property+0x8d/0xd0 [drm_kms_helper] [] drm_mode_plane_set_obj_prop+0x2d/0x90 [drm] [] restore_fbdev_mode+0x6b/0xf0 [drm_kms_helper] [] drm_fb_helper_restore_fbdev_mode_unlocked+0x29/0x80 [drm_kms_helper] [] drm_fb_helper_set_par+0x22/0x50 [drm_kms_helper] [] intel_fbdev_set_par+0x1a/0x60 [i915] [] fbcon_init+0x4f4/0x580 That's because we update the plane state with the fb from the firmware, but we never associate the plane to that CRTC. We don't quite have the full DRM take over from HW state just yet, so fake enough of the plane atomic state to pass the checks. v2: Fix the state on which we set the CRTC in the case we're sharing the initial fb with another pipe. (Matt) Signed-off-by: Damien Lespiau Reviewed-by: Matt Roper Signed-off-by: Daniel Vetter [Jani: backported to drm-intel-fixes for v4.0-rc] Reference: http://mid.gmane.org/CA+5PVA7yXH=U757w8V=Zj2U1URG4nYNav20NpjtQ4svVueyPNw@mail.gmail.com Reference: http://lkml.kernel.org/r/CA+55aFweWR=nDzc2Y=rCtL_H8JfdprQiCimN5dwc+TgyD4Bjsg@mail.gmail.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1c12262029fb..30faf6c262e5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2439,7 +2439,11 @@ intel_find_plane_obj(struct intel_crtc *intel_crtc, return; if (intel_alloc_plane_obj(intel_crtc, plane_config)) { - update_state_fb(intel_crtc->base.primary); + struct drm_plane *primary = intel_crtc->base.primary; + + primary->state->crtc = &intel_crtc->base; + update_state_fb(primary); + return; } @@ -2464,11 +2468,14 @@ intel_find_plane_obj(struct intel_crtc *intel_crtc, continue; if (i915_gem_obj_ggtt_offset(obj) == plane_config->base) { + struct drm_plane *primary = intel_crtc->base.primary; + if (obj->tiling_mode != I915_TILING_NONE) dev_priv->preserve_bios_swizzle = true; drm_framebuffer_reference(c->primary->fb); - intel_crtc->base.primary->fb = c->primary->fb; + primary->fb = c->primary->fb; + primary->state->crtc = &intel_crtc->base; obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); break; } From 5f407751b0ca9bd876fe8f15ff28153661c6ba0a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 25 Mar 2015 18:30:38 +0100 Subject: [PATCH 283/567] drm/i915: Fixup legacy plane->crtc link for initial fb config This is a very similar bug in the load detect code fixed in commit 9128b040eb774e04bc23777b005ace2b66ab2a85 Author: Daniel Vetter Date: Tue Mar 3 17:31:21 2015 +0100 drm/i915: Fix modeset state confusion in the load detect code But this time around it was the initial fb code that forgot to update the plane->crtc pointer. Otherwise it's the exact same bug, with the exact same restrains (any set_config call/ioctl that doesn't disable the pipe papers over the bug for free, so fairly hard to hit in normal testing). So if you want the full explanation just go read that one over there - it's rather long ... Cc: Matt Roper Cc: Linus Torvalds Cc: Chris Wilson Cc: Josh Boyer Cc: Jani Nikula Reported-and-tested-by: Josh Boyer Signed-off-by: Daniel Vetter [Jani: backported to drm-intel-fixes for v4.0-rc] Reference: http://mid.gmane.org/CA+5PVA7ChbtJrknqws1qvZcbrg1CW2pQAFkSMURWWgyASRyGXg@mail.gmail.com Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 30faf6c262e5..f75173c20f47 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2442,6 +2442,7 @@ intel_find_plane_obj(struct intel_crtc *intel_crtc, struct drm_plane *primary = intel_crtc->base.primary; primary->state->crtc = &intel_crtc->base; + primary->crtc = &intel_crtc->base; update_state_fb(primary); return; @@ -2476,6 +2477,7 @@ intel_find_plane_obj(struct intel_crtc *intel_crtc, drm_framebuffer_reference(c->primary->fb); primary->fb = c->primary->fb; primary->state->crtc = &intel_crtc->base; + primary->crtc = &intel_crtc->base; obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); break; } From e91d863d1aaeda0349aed42dfbd75c98e042a2c9 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 13 Mar 2015 12:38:51 +0100 Subject: [PATCH 284/567] serial: samsung: Clear operation mode on UART shutdown Exynos serial ports operate either in a DMA-based or interrupt-based modes. In DMA-based mode, the UART generates a transfer data request and a Transmission (Tx) interrupt in interrupt-based mode. The Tx IRQ is only unmasked in interrupt-based mode and it was done in s3c24xx_serial_start_tx(). Commit ba019a3e2ad5 ("serial: samsung: remove redundant interrupt enabling") removed the IRQ enable on that function since it is enabled when the mode is set in enable_tx_pio(). The problem is that enable_tx_pio() is only called if the port mode has not been set before but the mode was not cleared on .shutdown(). So if the UART was shutdown and then started up again, the mode set will remain and the Tx IRQ won't be unmasked. This caused a hang on at least Exynos5250, Exynos5420 and Exynos5800 when the system is rebooted or powered off. Fixes: ba019a3e2ad5 ("serial: samsung: remove redundant interrupt enabling") Signed-off-by: Javier Martinez Canillas Reviewed-by: Sylwester Nawrocki Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index af821a908720..cf08876922f1 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -963,6 +963,7 @@ static void s3c24xx_serial_shutdown(struct uart_port *port) free_irq(ourport->tx_irq, ourport); tx_enabled(port) = 0; ourport->tx_claimed = 0; + ourport->tx_mode = 0; } if (ourport->rx_claimed) { From 4e8f245937091b2c9eebf3d4909c9ceda4f0a78e Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 13 Mar 2015 14:51:50 +0100 Subject: [PATCH 285/567] tty: serial: fsl_lpuart: specify transmit FIFO size Specify transmit FIFO size which might be different depending on LPUART instance. This makes sure uart_wait_until_sent in serial core getting called, which in turn waits and checks if the FIFO is really empty on shutdown by using the tx_empty callback. Without the call of this callback, the last several characters might not yet be transmitted when closing the serial port. This can be reproduced by simply using echo and redirect the output to a ttyLP device. Signed-off-by: Stefan Agner Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index b1893f3f88f1..7ec911000ec2 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1076,6 +1076,8 @@ static int lpuart_startup(struct uart_port *port) sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK) + 1); + sport->port.fifosize = sport->txfifo_size; + sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) & UARTPFIFO_FIFOSIZE_MASK) + 1); From 8e4934c6d6c659e22b1b746af4196683e77ce6ca Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 13 Mar 2015 14:51:51 +0100 Subject: [PATCH 286/567] tty: serial: fsl_lpuart: clear receive flag on FIFO flush When the receiver was enabled during startup, a character could have been in the FIFO when the UART get initially used. The driver configures the (receive) watermark level, and flushes the FIFO. However, the receive flag (RDRF) could still be set at that stage (as mentioned in the register description of UARTx_RWFIFO). This leads to an interrupt which won't be handled properly in interrupt mode: The receive interrupt function lpuart_rxint checks the FIFO count, which is 0 at that point (due to the flush during initialization). The problem does not manifest when using DMA to receive characters. Fix this situation by explicitly read the status register, which leads to clearing of the RDRF flag. Due to the flush just after the status flag read, a explicit data read is not to required. Signed-off-by: Stefan Agner Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 7ec911000ec2..3ad1458bfeb0 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -921,6 +921,9 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE, sport->port.membase + UARTPFIFO); + /* explicitly clear RDRF */ + readb(sport->port.membase + UARTSR1); + /* flush Tx and Rx FIFO */ writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO); From 9ffd906d9a6e50c958bd99971d762a426a12a36a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Feb 2015 13:26:21 +0300 Subject: [PATCH 287/567] watchdog: mtk_wdt: signedness bug in mtk_wdt_start() "ret" should be signed for the error handling to work correctly. This doesn't matter much in real life since mtk_wdt_set_timeout() always succeeds. Signed-off-by: Dan Carpenter Reviewed-by: Matthias Brugger Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mtk_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index a87f6df6e85f..938b987de551 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c @@ -133,7 +133,7 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev) u32 reg; struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev); void __iomem *wdt_base = mtk_wdt->wdt_base; - u32 ret; + int ret; ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout); if (ret < 0) From a629c08fdb98ebb184d745553af9dda4f05941bf Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 20 Feb 2015 23:45:44 +0000 Subject: [PATCH 288/567] watchdog: imgpdc: Fix probe NULL pointer dereference The IMG PDC watchdog probe function calls pdc_wdt_stop() prior to watchdog_set_drvdata(), causing a NULL pointer dereference when pdc_wdt_stop() retrieves the struct pdc_wdt_dev pointer using watchdog_get_drvdata() and reads the register base address through it. Fix by moving the watchdog_set_drvdata() call earlier, to where various other pdc_wdt->wdt_dev fields are initialised. Fixes: 93937669e9b5 ("watchdog: ImgTec PDC Watchdog Timer Driver") Signed-off-by: James Hogan Cc: Ezequiel Garcia Cc: Naidu Tellapati Cc: Jude Abraham Cc: linux-watchdog@vger.kernel.org Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/imgpdc_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c index c8def68d9e4c..32c35eb31e65 100644 --- a/drivers/watchdog/imgpdc_wdt.c +++ b/drivers/watchdog/imgpdc_wdt.c @@ -191,6 +191,7 @@ static int pdc_wdt_probe(struct platform_device *pdev) pdc_wdt->wdt_dev.ops = &pdc_wdt_ops; pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK; pdc_wdt->wdt_dev.parent = &pdev->dev; + watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt); ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev); if (ret < 0) { @@ -232,7 +233,6 @@ static int pdc_wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout); platform_set_drvdata(pdev, pdc_wdt); - watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt); ret = watchdog_register_device(&pdc_wdt->wdt_dev); if (ret) From ae6ee2fd47f76db5a1cd02c23378057bd21c2c8d Mon Sep 17 00:00:00 2001 From: James Hogan Date: Fri, 20 Feb 2015 23:45:45 +0000 Subject: [PATCH 289/567] watchdog: imgpdc: Fix default heartbeat The IMG PDC watchdog driver heartbeat module parameter has no default so it is initialised to zero. This results in the following warning during probe: imgpdc-wdt 2006000.wdt: Initial timeout out of range! setting max timeout The module parameter description implies that the default value should be PDC_WDT_DEF_TIMEOUT, which isn't yet used, so initialise it to that. Also tweak the heartbeat module parameter description for consistency. Fixes: 93937669e9b5 ("watchdog: ImgTec PDC Watchdog Timer Driver") Signed-off-by: James Hogan Cc: Ezequiel Garcia Cc: Naidu Tellapati Cc: Jude Abraham Cc: linux-watchdog@vger.kernel.org Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/imgpdc_wdt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c index 32c35eb31e65..0deaa4f971f5 100644 --- a/drivers/watchdog/imgpdc_wdt.c +++ b/drivers/watchdog/imgpdc_wdt.c @@ -42,10 +42,10 @@ #define PDC_WDT_MIN_TIMEOUT 1 #define PDC_WDT_DEF_TIMEOUT 64 -static int heartbeat; +static int heartbeat = PDC_WDT_DEF_TIMEOUT; module_param(heartbeat, int, 0); -MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. " - "(default = " __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")"); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds " + "(default=" __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")"); static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); From c6ac19dac2683a8b06aebcc10cb1c711b555a949 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 24 Mar 2015 20:42:42 +0200 Subject: [PATCH 290/567] gpio: syscon: reduce message level when direction reg offset not in dt Now GPIO syscon driver produces bunch of warnings during the boot of Kesytone 2 SoCs: gpio-syscon soc:keystone_dsp_gpio@02620240: can't read the dir register offset! gpio-syscon soc:keystone_dsp_gpio@2620244: can't read the dir register offset! This message unintentionally was added using dev_err(), but its actual log level is debug, because third cell of "ti,syscon-dev" is optional. Hence change it to dev_dbg() as it should be. This patch fixes commit: 5a3e3f8 ("gpio: syscon: retriave syscon node and regs offsets from dt") Reported-by: Russell King Tested-by: Murali Karicheri Acked-by: Santosh Shilimkar Signed-off-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-syscon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c index 257e2989215c..045a952576c7 100644 --- a/drivers/gpio/gpio-syscon.c +++ b/drivers/gpio/gpio-syscon.c @@ -219,7 +219,7 @@ static int syscon_gpio_probe(struct platform_device *pdev) ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2, &priv->dir_reg_offset); if (ret) - dev_err(dev, "can't read the dir register offset!\n"); + dev_dbg(dev, "can't read the dir register offset!\n"); priv->dir_reg_offset <<= 3; } From bfbaafae8519d82d10da6abe75f5766dd5b20475 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 20 Mar 2015 09:59:47 +0100 Subject: [PATCH 291/567] firmware: dmi_scan: Prevent dmi_num integer overflow dmi_num is a u16, dmi_len is a u32, so this construct: dmi_num = dmi_len / 4; would result in an integer overflow for a DMI table larger than 256 kB. I've never see such a large table so far, but SMBIOS 3.0 makes it possible so maybe we'll see such tables in the future. So instead of faking a structure count when the entry point does not provide it, adjust the loop condition in dmi_table() to properly deal with the case where dmi_num is not set. This bug was introduced with the initial SMBIOS 3.0 support in commit fc43026278b2 ("dmi: add support for SMBIOS 3.0 64-bit entry point"). Signed-off-by: Jean Delvare Cc: Matt Fleming Cc: Ivan Khoronzhuk Cc: Acked-by: Ard Biesheuvel Signed-off-by: Matt Fleming --- drivers/firmware/dmi_scan.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 69fac068669f..2eebd28b4c40 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -86,10 +86,13 @@ static void dmi_table(u8 *buf, u32 len, int num, int i = 0; /* - * Stop when we see all the items the table claimed to have - * OR we run off the end of the table (also happens) + * Stop when we have seen all the items the table claimed to have + * (SMBIOS < 3.0 only) OR we reach an end-of-table marker OR we run + * off the end of the table (should never happen but sometimes does + * on bogus implementations.) */ - while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { + while ((!num || i < num) && + (data - buf + sizeof(struct dmi_header)) <= len) { const struct dmi_header *dm = (const struct dmi_header *)data; /* @@ -529,21 +532,10 @@ static int __init dmi_smbios3_present(const u8 *buf) if (memcmp(buf, "_SM3_", 5) == 0 && buf[6] < 32 && dmi_checksum(buf, buf[6])) { dmi_ver = get_unaligned_be16(buf + 7); + dmi_num = 0; /* No longer specified */ dmi_len = get_unaligned_le32(buf + 12); dmi_base = get_unaligned_le64(buf + 16); - /* - * The 64-bit SMBIOS 3.0 entry point no longer has a field - * containing the number of structures present in the table. - * Instead, it defines the table size as a maximum size, and - * relies on the end-of-table structure type (#127) to be used - * to signal the end of the table. - * So let's define dmi_num as an upper bound as well: each - * structure has a 4 byte header, so dmi_len / 4 is an upper - * bound for the number of structures in the table. - */ - dmi_num = dmi_len / 4; - if (dmi_walk_early(dmi_decode) == 0) { pr_info("SMBIOS %d.%d present.\n", dmi_ver >> 8, dmi_ver & 0xFF); From a901125c65544aa05c52e1a7388c3900e8af105f Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Fri, 27 Mar 2015 10:34:20 +0800 Subject: [PATCH 292/567] locks: fix file_lock deletion inside loop locks_delete_lock_ctx() is called inside the loop, so we should use list_for_each_entry_safe. Fixes: 8634b51f6ca2 (locks: convert lease handling to file_lock_context) Signed-off-by: "Yan, Zheng" Signed-off-by: Jeff Layton --- fs/locks.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index 528fedfda15e..40bc384728c0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1388,9 +1388,8 @@ any_leases_conflict(struct inode *inode, struct file_lock *breaker) int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) { int error = 0; - struct file_lock *new_fl; struct file_lock_context *ctx = inode->i_flctx; - struct file_lock *fl; + struct file_lock *new_fl, *fl, *tmp; unsigned long break_time; int want_write = (mode & O_ACCMODE) != O_RDONLY; LIST_HEAD(dispose); @@ -1420,7 +1419,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) break_time++; /* so that 0 means no break time */ } - list_for_each_entry(fl, &ctx->flc_lease, fl_list) { + list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) { if (!leases_conflict(fl, new_fl)) continue; if (want_write) { From ad692b46dbf122ef90aadce3b389ef64c90e861d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 26 Mar 2015 10:42:00 +0200 Subject: [PATCH 293/567] drm/edid: set ELD for firmware and debugfs override EDIDs If the user supplies EDID through firmware or debugfs override, the driver callbacks are bypassed and the connector ELD does not get updated, and audio fails. Set ELD for firmware and debugfs EDIDs too. There should be no harm in gratuitously doing this for non HDMI/DP connectors, as it's still up to the driver to use the ELD, if any. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=82349 Reference: https://bugs.freedesktop.org/show_bug.cgi?id=80691 Reported-by: Emil Reported-by: Rob Engle Tested-by: Jolan Luff Reviewed-by: Daniel Vetter Cc: stable@vger.kernel.org Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_edid_load.c | 1 + drivers/gpu/drm/drm_probe_helper.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 732cb6f8e653..4c0aa97aaf03 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -287,6 +287,7 @@ int drm_load_edid_firmware(struct drm_connector *connector) drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); + drm_edid_to_eld(connector, edid); kfree(edid); return ret; diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 6591d48c1b9d..3fee587bc284 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -174,6 +174,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect struct edid *edid = (struct edid *) connector->edid_blob_ptr->data; count = drm_add_edid_modes(connector, edid); + drm_edid_to_eld(connector, edid); } else count = (*connector_funcs->get_modes)(connector); } From 3899ca844b82fb201fb764f56eec483acb59a29c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 18 Mar 2015 17:05:10 -0400 Subject: [PATCH 294/567] drm/radeon/dpm: fix 120hz handling harder Need to expand the check to handle short circuiting if the selected state is the same as current state. bug: https://bugs.freedesktop.org/show_bug.cgi?id=87796 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_pm.c | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5587603b4a89..33d5a4f4eebd 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1565,6 +1565,7 @@ struct radeon_dpm { int new_active_crtc_count; u32 current_active_crtcs; int current_active_crtc_count; + bool single_display; struct radeon_dpm_dynamic_state dyn_state; struct radeon_dpm_fan fan; u32 tdp_limit; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 33cf4108386d..c1ba83a8dd8c 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -837,12 +837,8 @@ static void radeon_dpm_thermal_work_handler(struct work_struct *work) radeon_pm_compute_clocks(rdev); } -static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, - enum radeon_pm_state_type dpm_state) +static bool radeon_dpm_single_display(struct radeon_device *rdev) { - int i; - struct radeon_ps *ps; - u32 ui_class; bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ? true : false; @@ -858,6 +854,17 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, if (single_display && (r600_dpm_get_vrefresh(rdev) >= 120)) single_display = false; + return single_display; +} + +static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev, + enum radeon_pm_state_type dpm_state) +{ + int i; + struct radeon_ps *ps; + u32 ui_class; + bool single_display = radeon_dpm_single_display(rdev); + /* certain older asics have a separare 3D performance state, * so try that first if the user selected performance */ @@ -983,6 +990,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev) struct radeon_ps *ps; enum radeon_pm_state_type dpm_state; int ret; + bool single_display = radeon_dpm_single_display(rdev); /* if dpm init failed */ if (!rdev->pm.dpm_enabled) @@ -1007,6 +1015,9 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev) /* vce just modifies an existing state so force a change */ if (ps->vce_active != rdev->pm.dpm.vce_active) goto force; + /* user has made a display change (such as timing) */ + if (rdev->pm.dpm.single_display != single_display) + goto force; if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) { /* for pre-BTC and APUs if the num crtcs changed but state is the same, * all we need to do is update the display configuration. @@ -1069,6 +1080,7 @@ force: rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; + rdev->pm.dpm.single_display = single_display; /* wait for the rings to drain */ for (i = 0; i < RADEON_NUM_RINGS; i++) { From f2c9e560b406f2f6b14b345c7da33467dee9cdf2 Mon Sep 17 00:00:00 2001 From: David Miller Date: Wed, 18 Mar 2015 23:18:40 -0400 Subject: [PATCH 295/567] radeon: Do not directly dereference pointers to BIOS area. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use readb() and memcpy_fromio() accessors instead. Reviewed-by: Christian König Signed-off-by: David S. Miller Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_bios.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 63ccb8fa799c..d27e4ccb848c 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -76,7 +76,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev) static bool radeon_read_bios(struct radeon_device *rdev) { - uint8_t __iomem *bios; + uint8_t __iomem *bios, val1, val2; size_t size; rdev->bios = NULL; @@ -86,15 +86,19 @@ static bool radeon_read_bios(struct radeon_device *rdev) return false; } - if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) { + val1 = readb(&bios[0]); + val2 = readb(&bios[1]); + + if (size == 0 || val1 != 0x55 || val2 != 0xaa) { pci_unmap_rom(rdev->pdev, bios); return false; } - rdev->bios = kmemdup(bios, size, GFP_KERNEL); + rdev->bios = kzalloc(size, GFP_KERNEL); if (rdev->bios == NULL) { pci_unmap_rom(rdev->pdev, bios); return false; } + memcpy_fromio(rdev->bios, bios, size); pci_unmap_rom(rdev->pdev, bios); return true; } From 1b01fc347ae7d2b76ac849f7040a32582cb5aee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 23 Mar 2015 11:32:59 +0100 Subject: [PATCH 296/567] drm/radeon: always dump the ring content if it's available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dumping is still possible if a ring isn't ready, only when it isn't allocated at all we need to abort here. Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 2456f69efd23..8c7872339c2a 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -495,7 +495,7 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data) seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); seq_printf(m, "%u dwords in ring\n", count); - if (!ring->ready) + if (!ring->ring) return 0; /* print 8 dw before current rptr as often it's the last executed From 88f9eae4d74c1b5c35adb026d7f0d4d44d2fdf70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 23 Mar 2015 11:33:00 +0100 Subject: [PATCH 297/567] drm/radeon: programm the VCE fw BAR as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise the VCE firmware needs to be in the first 256MB of VRAM. Signed-off-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/cikd.h | 1 + drivers/gpu/drm/radeon/vce_v2_0.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index c648e1996dab..243a36c93b8f 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -2129,6 +2129,7 @@ #define VCE_UENC_REG_CLOCK_GATING 0x207c0 #define VCE_SYS_INT_EN 0x21300 # define VCE_SYS_INT_TRAP_INTERRUPT_EN (1 << 3) +#define VCE_LMI_VCPU_CACHE_40BIT_BAR 0x2145c #define VCE_LMI_CTRL2 0x21474 #define VCE_LMI_CTRL 0x21498 #define VCE_LMI_VM_CTRL 0x214a0 diff --git a/drivers/gpu/drm/radeon/vce_v2_0.c b/drivers/gpu/drm/radeon/vce_v2_0.c index 1ac7bb825a1b..fbbe78fbd087 100644 --- a/drivers/gpu/drm/radeon/vce_v2_0.c +++ b/drivers/gpu/drm/radeon/vce_v2_0.c @@ -156,6 +156,9 @@ int vce_v2_0_resume(struct radeon_device *rdev) WREG32(VCE_LMI_SWAP_CNTL1, 0); WREG32(VCE_LMI_VM_CTRL, 0); + WREG32(VCE_LMI_VCPU_CACHE_40BIT_BAR, addr >> 8); + + addr &= 0xff; size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size); WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff); WREG32(VCE_VCPU_CACHE_SIZE0, size); From ff7f53fb82a7801a778e5902bdbbc5e195ab0de0 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 27 Mar 2015 15:17:20 -0400 Subject: [PATCH 298/567] libata: Update Crucial/Micron blacklist Micron has released an updated firmware (MU02) for M510/M550/MX100 drives to fix the issues with queued TRIM. Queued TRIM remains broken on M500 but is working fine on later drives such as M600 and MX200. Tweak our blacklist to reflect the above. Link: https://bugzilla.kernel.org/show_bug.cgi?id=71371 Signed-off-by: Martin K. Petersen Cc: stable@vger.kernel.org Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ef150ebb4c30..86374df28b10 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4204,9 +4204,16 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, /* devices that don't properly handle queued TRIM commands */ - { "Micron_M[56]*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Crucial_CT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Micron_M5[15]0*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Crucial_CT*M550*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, - { "Crucial_CT*SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, /* * As defined, the DRAT (Deterministic Read After Trim) and RZAT @@ -4226,6 +4233,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { */ { "INTEL*SSDSC2MH*", NULL, 0, }, + { "Micron*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Crucial*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "INTEL*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "SSD*INTEL*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Samsung*SSD*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM, }, From 6fc4d97a4987c5d247655a157a9377996626221a Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Fri, 27 Mar 2015 15:17:21 -0400 Subject: [PATCH 299/567] libata: Blacklist queued TRIM on Samsung SSD 850 Pro Blacklist queued TRIM on this drive for now. Reported-by: Stefan Keller Signed-off-by: Martin K. Petersen CC: stable@vger.kernel.org Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 86374df28b10..23dac3babfe3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4214,6 +4214,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Samsung SSD 850 PRO*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, /* * As defined, the DRAT (Deterministic Read After Trim) and RZAT From 41d9489319f28f06cf51731131bc353d5a6bce59 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 23 Mar 2015 14:16:38 +1100 Subject: [PATCH 300/567] drivers/of: Add empty ranges quirk for PA-Semi The "sdc" node is missing the ranges property, it needs to be treated as having an empty one otherwise translation fails for its children. Fixes 746c9e9f92dd, "of/base: Fix PowerPC address parsing hack" Tested-by: Steven Rostedt Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Grant Likely Cc: Stable # v3.18+ --- drivers/of/address.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/of/address.c b/drivers/of/address.c index ad2906919d45..78a7dcbec7d8 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -450,12 +450,17 @@ static struct of_bus *of_match_bus(struct device_node *np) return NULL; } -static int of_empty_ranges_quirk(void) +static int of_empty_ranges_quirk(struct device_node *np) { if (IS_ENABLED(CONFIG_PPC)) { - /* To save cycles, we cache the result */ + /* To save cycles, we cache the result for global "Mac" setting */ static int quirk_state = -1; + /* PA-SEMI sdc DT bug */ + if (of_device_is_compatible(np, "1682m-sdc")) + return true; + + /* Make quirk cached */ if (quirk_state < 0) quirk_state = of_machine_is_compatible("Power Macintosh") || @@ -490,7 +495,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, * This code is only enabled on powerpc. --gcl */ ranges = of_get_property(parent, rprop, &rlen); - if (ranges == NULL && !of_empty_ranges_quirk()) { + if (ranges == NULL && !of_empty_ranges_quirk(parent)) { pr_debug("OF: no ranges; cannot translate\n"); return 1; } From 6331c686e664909988ecc35b040e1e96c137f5e0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 27 Mar 2015 15:11:41 -0700 Subject: [PATCH 301/567] Bluetooth: btusb: Consolidate Broadcom based device entries For all modern Bluetooth USB devices from Broadcom it makes a lot more sense to use USB_VENDOR_AND_INTERFACE_INFO instead of manually adding USB_DEVICE for each one of them. There are already interface entries for these vendors and so just remove the duplicate device entries. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 9bf4d6ae6c6b..6e4ff16e487b 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -111,13 +111,7 @@ static const struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0c10, 0x0000) }, /* Broadcom BCM20702A0 */ - { USB_DEVICE(0x0489, 0xe042) }, - { USB_DEVICE(0x04ca, 0x2003) }, - { USB_DEVICE(0x0b05, 0x17b5) }, - { USB_DEVICE(0x0b05, 0x17cb) }, { USB_DEVICE(0x413c, 0x8197) }, - { USB_DEVICE(0x13d3, 0x3404), - .driver_info = BTUSB_BCM_PATCHRAM }, /* Broadcom BCM20702B0 (Dynex/Insignia) */ { USB_DEVICE(0x19ff, 0x0239), .driver_info = BTUSB_BCM_PATCHRAM }, @@ -139,10 +133,12 @@ static const struct usb_device_id btusb_table[] = { .driver_info = BTUSB_BCM_PATCHRAM }, /* Belkin F8065bf - Broadcom based */ - { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01), + .driver_info = BTUSB_BCM_PATCHRAM }, /* IMC Networks - Broadcom based */ - { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01), + .driver_info = BTUSB_BCM_PATCHRAM }, /* Intel Bluetooth USB Bootloader (RAM module) */ { USB_DEVICE(0x8087, 0x0a5a), From bbc45f3ab78edb8c97e563ddd351f851da47dab1 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Mon, 16 Mar 2015 22:27:10 +0100 Subject: [PATCH 302/567] iio/adc/cc10001_adc.c: Fix !HAS_IOMEM build Fixes: drivers/built-in.o: In function `cc10001_adc_probe': cc10001_adc.c:(.text+0x412e92): undefined reference to `devm_ioremap_resource' Signed-off-by: Richard Weinberger Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 202daf889be2..46379b1fb25b 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -137,7 +137,8 @@ config AXP288_ADC config CC10001_ADC tristate "Cosmic Circuits 10001 ADC driver" - depends on HAS_IOMEM || HAVE_CLK || REGULATOR + depends on HAVE_CLK || REGULATOR + depends on HAS_IOMEM select IIO_BUFFER select IIO_TRIGGERED_BUFFER help From f54e9f2be312a4e71b54aea865b2e33ccb95ef0c Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Tue, 24 Mar 2015 13:47:47 +0100 Subject: [PATCH 303/567] iio: adc: vf610: use ADC clock within specification Depending on conversion mode used, the ADC clock (ADCK) needs to be below a maximum frequency. According to Vybrid's data sheet this is 20MHz for the low power conversion mode. The ADC clock is depending on input clock, which is the bus clock by default. Vybrid SoC are typically clocked at at 400MHz or 500MHz, which leads to 66MHz or 83MHz bus clock respectively. Hence, a divider of 8 is required to stay below the specified maximum clock of 20MHz. Due to the different bus clock speeds, the resulting sampling frequency is not static. Hence use the ADC clock and calculate the actual available sampling frequency dynamically. This fixes bogous values observed on some 500MHz clocked Vybrid SoC. The resulting value usually showed Bit 9 being stuck at 1, or 0, which lead to a value of +/-512. Signed-off-by: Stefan Agner Acked-by: Fugang Duan Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/vf610_adc.c | 91 +++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 8ec353c01d98..e63b8e76d4c3 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -141,9 +141,13 @@ struct vf610_adc { struct regulator *vref; struct vf610_adc_feature adc_feature; + u32 sample_freq_avail[5]; + struct completion completion; }; +static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; + #define VF610_ADC_CHAN(_idx, _chan_type) { \ .type = (_chan_type), \ .indexed = 1, \ @@ -180,35 +184,47 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = { /* sentinel */ }; -/* - * ADC sample frequency, unit is ADCK cycles. - * ADC clk source is ipg clock, which is the same as bus clock. - * - * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder) - * SFCAdder: fixed to 6 ADCK cycles - * AverageNum: 1, 4, 8, 16, 32 samples for hardware average. - * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode - * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles - * - * By default, enable 12 bit resolution mode, clock source - * set to ipg clock, So get below frequency group: - */ -static const u32 vf610_sample_freq_avail[5] = -{1941176, 559332, 286957, 145374, 73171}; +static inline void vf610_adc_calculate_rates(struct vf610_adc *info) +{ + unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk); + int i; + + /* + * Calculate ADC sample frequencies + * Sample time unit is ADCK cycles. ADCK clk source is ipg clock, + * which is the same as bus clock. + * + * ADC conversion time = SFCAdder + AverageNum x (BCT + LSTAdder) + * SFCAdder: fixed to 6 ADCK cycles + * AverageNum: 1, 4, 8, 16, 32 samples for hardware average. + * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode + * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles + */ + adck_rate = ipg_rate / info->adc_feature.clk_div; + for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++) + info->sample_freq_avail[i] = + adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3)); +} static inline void vf610_adc_cfg_init(struct vf610_adc *info) { + struct vf610_adc_feature *adc_feature = &info->adc_feature; + /* set default Configuration for ADC controller */ - info->adc_feature.clk_sel = VF610_ADCIOC_BUSCLK_SET; - info->adc_feature.vol_ref = VF610_ADCIOC_VR_VREF_SET; + adc_feature->clk_sel = VF610_ADCIOC_BUSCLK_SET; + adc_feature->vol_ref = VF610_ADCIOC_VR_VREF_SET; - info->adc_feature.calibration = true; - info->adc_feature.ovwren = true; + adc_feature->calibration = true; + adc_feature->ovwren = true; - info->adc_feature.clk_div = 1; - info->adc_feature.res_mode = 12; - info->adc_feature.sample_rate = 1; - info->adc_feature.lpm = true; + adc_feature->res_mode = 12; + adc_feature->sample_rate = 1; + adc_feature->lpm = true; + + /* Use a save ADCK which is below 20MHz on all devices */ + adc_feature->clk_div = 8; + + vf610_adc_calculate_rates(info); } static void vf610_adc_cfg_post_set(struct vf610_adc *info) @@ -290,12 +306,10 @@ static void vf610_adc_cfg_set(struct vf610_adc *info) cfg_data = readl(info->regs + VF610_REG_ADC_CFG); - /* low power configuration */ cfg_data &= ~VF610_ADC_ADLPC_EN; if (adc_feature->lpm) cfg_data |= VF610_ADC_ADLPC_EN; - /* disable high speed */ cfg_data &= ~VF610_ADC_ADHSC_EN; writel(cfg_data, info->regs + VF610_REG_ADC_CFG); @@ -435,10 +449,27 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1941176, 559332, 286957, 145374, 73171"); +static ssize_t vf610_show_samp_freq_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vf610_adc *info = iio_priv(dev_to_iio_dev(dev)); + size_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(info->sample_freq_avail); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, + "%u ", info->sample_freq_avail[i]); + + /* replace trailing space by newline */ + buf[len - 1] = '\n'; + + return len; +} + +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(vf610_show_samp_freq_avail); static struct attribute *vf610_attributes[] = { - &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, NULL }; @@ -502,7 +533,7 @@ static int vf610_read_raw(struct iio_dev *indio_dev, return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_SAMP_FREQ: - *val = vf610_sample_freq_avail[info->adc_feature.sample_rate]; + *val = info->sample_freq_avail[info->adc_feature.sample_rate]; *val2 = 0; return IIO_VAL_INT; @@ -525,9 +556,9 @@ static int vf610_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: for (i = 0; - i < ARRAY_SIZE(vf610_sample_freq_avail); + i < ARRAY_SIZE(info->sample_freq_avail); i++) - if (val == vf610_sample_freq_avail[i]) { + if (val == info->sample_freq_avail[i]) { info->adc_feature.sample_rate = i; vf610_adc_sample_set(info); return 0; From 4ce7ca89d6e8eae9e201cd0e972ba323f33e2fb4 Mon Sep 17 00:00:00 2001 From: Darshana Padmadas Date: Sat, 28 Mar 2015 12:07:14 +0530 Subject: [PATCH 304/567] iio: imu: Use iio_trigger_get for indio_dev->trig assignment This patch uses iio_trigger_get to increment the reference count of trigger device, to avoid incorrect assignment. Can result in a null pointer dereference during removal if the trigger has been changed before removal. This patch refers to a similar situation encountered through the following discussion: http://www.spinics.net/lists/linux-iio/msg13669.html Signed-off-by: Darshana Padmadas Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis_trigger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index e0017c22bb9c..f53e9a803a0e 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -60,7 +60,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) iio_trigger_set_drvdata(adis->trig, adis); ret = iio_trigger_register(adis->trig); - indio_dev->trig = adis->trig; + indio_dev->trig = iio_trigger_get(adis->trig); if (ret) goto error_free_irq; From 600b21507eb64bcd85bb87d06c2c2c451b565f02 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sat, 28 Mar 2015 11:17:36 +0200 Subject: [PATCH 305/567] Bluetooth: Fix race condition with HCI_RESET flag During the HCI init phase a completed request might be the last part of the setup procedure after which the actual init procedure starts. The init procedure begins with a call to hci_reset_req() which sets the HCI_RESET flag. The purpose of this flag is to make us ignore any updates to ncmd/cmd_cnt as long as we haven't received the command complete event for the HCI_Reset. There's a potential race with this however: hci_req_cmd_complete(hdev, opcode, status); if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) queue_work(hdev->workqueue, &hdev->cmd_work); } Since the hci_req_cmd_complete() will trigger the completion of the setup stage, it's possible that hci_reset_req() gets called before we try to read ev->ncmd and the HCI_RESET flag. Because of this the cmd_cnt would never be updated and the hci_reset_req() in practice ends up blocking itself. This patch fixes the issue by updating cmd_cnt before notifying the request completion, and then reading it again to determine whether the cmd_work should be queued or not. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 62f92a508961..3ac23964e108 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3027,13 +3027,13 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) if (opcode != HCI_OP_NOP) cancel_delayed_work(&hdev->cmd_timer); + if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) + atomic_set(&hdev->cmd_cnt, 1); + hci_req_cmd_complete(hdev, opcode, status); - if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { - atomic_set(&hdev->cmd_cnt, 1); - if (!skb_queue_empty(&hdev->cmd_q)) - queue_work(hdev->workqueue, &hdev->cmd_work); - } + if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q)) + queue_work(hdev->workqueue, &hdev->cmd_work); } static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) @@ -3122,15 +3122,15 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) if (opcode != HCI_OP_NOP) cancel_delayed_work(&hdev->cmd_timer); + if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) + atomic_set(&hdev->cmd_cnt, 1); + if (ev->status || (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req_event)) hci_req_cmd_complete(hdev, opcode, ev->status); - if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { - atomic_set(&hdev->cmd_cnt, 1); - if (!skb_queue_empty(&hdev->cmd_q)) - queue_work(hdev->workqueue, &hdev->cmd_work); - } + if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q)) + queue_work(hdev->workqueue, &hdev->cmd_work); } static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb) From faccb950f7170c37c9c2e1f82a6e33cd7a23a5c9 Mon Sep 17 00:00:00 2001 From: Arman Uguray Date: Sat, 28 Mar 2015 12:38:58 -0700 Subject: [PATCH 306/567] Bluetooth: Fix using global connectable settings for adv This patch fixes a bug where ADV_NONCONN_IND was being used for advertising instances >0 while the global connectable setting was set to "on". Signed-off-by: Arman Uguray Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index fb2e764c6211..d998ec360598 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -985,9 +985,10 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance) /* Instance 0 always manages the "Tx Power" and "Flags" fields */ flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS; - /* For instance 0, assemble the flags from global settings */ - if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE) || - get_connectable(hdev)) + /* For instance 0, the HCI_ADVERTISING_CONNECTABLE setting corresponds + * to the "connectable" instance flag. + */ + if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) flags |= MGMT_ADV_FLAG_CONNECTABLE; return flags; @@ -1242,7 +1243,12 @@ static void enable_advertising(struct hci_request *req) instance = get_current_adv_instance(hdev); flags = get_adv_instance_flags(hdev, instance); - connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE); + + /* If the "connectable" instance flag was not set, then choose between + * ADV_IND and ADV_NONCONN_IND based on the global connectable setting. + */ + connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) || + get_connectable(hdev); /* Set require_privacy to true only when non-connectable * advertising is used. In that case it is fine to use a From c7d4883b0684a732af779f88768c57ab006ce3a1 Mon Sep 17 00:00:00 2001 From: Arman Uguray Date: Sat, 28 Mar 2015 12:38:59 -0700 Subject: [PATCH 307/567] Bluetooth: Use ADV_SCAN_IND for adv. instances With this patch, ADV_SCAN_IND will be used for advertising instances that have non-zero scan response data while the global "connectable" setting is "off". Signed-off-by: Arman Uguray Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d998ec360598..2d84fc16e108 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -994,6 +994,18 @@ static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance) return flags; } +static u8 get_adv_instance_scan_rsp_len(struct hci_dev *hdev, u8 instance) +{ + /* Ignore instance 0 and other unsupported instances */ + if (instance != 0x01) + return 0; + + /* TODO: Take into account the "appearance" and "local-name" flags here. + * These are currently being ignored as they are not supported. + */ + return hdev->adv_instance.scan_rsp_len; +} + static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) { u8 ad_len = 0, flags = 0; @@ -1260,7 +1272,14 @@ static void enable_advertising(struct hci_request *req) memset(&cp, 0, sizeof(cp)); cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval); cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval); - cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND; + + if (connectable) + cp.type = LE_ADV_IND; + else if (get_adv_instance_scan_rsp_len(hdev, instance)) + cp.type = LE_ADV_SCAN_IND; + else + cp.type = LE_ADV_NONCONN_IND; + cp.own_address_type = own_addr_type; cp.channel_map = hdev->le_adv_channel_map; From 880897d4c9eedd69b33b9905a6919e3e4f58eae8 Mon Sep 17 00:00:00 2001 From: Arman Uguray Date: Sat, 28 Mar 2015 12:39:00 -0700 Subject: [PATCH 308/567] Bluetooth: Update adv. parameters when conn. setting changes This patch fixes a bug where the advertising parameters weren't updated after a call to "Set Connectable" if the HCI_ADVERTISING_INSTANCE setting was set. Signed-off-by: Arman Uguray Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2d84fc16e108..29cbd98f4649 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2113,7 +2113,8 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, no_scan_update: /* Update the advertising parameters if necessary */ - if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) + if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || + hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) enable_advertising(&req); err = hci_req_run(&req, set_connectable_complete); From efcd8c98e0d195c09fd9141a7af32dd83e62a5cb Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 28 Mar 2015 15:18:58 -0700 Subject: [PATCH 309/567] Bluetooth: Move memory location outside of hci_dev lock Taking the hci_dev lock for just a memory allocation seems a bit too much and not really needed. So instead try to allocate the memory first and then take the lock. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 29cbd98f4649..a9a0036ff0a7 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6446,14 +6446,12 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, &cp->type, sizeof(cp->type)); } - hci_dev_lock(hdev); - rp_len = sizeof(*rp) + eir_len; rp = kmalloc(rp_len, GFP_ATOMIC); - if (!rp) { - hci_dev_unlock(hdev); + if (!rp) return -ENOMEM; - } + + hci_dev_lock(hdev); eir_len = 0; switch (cp->type) { @@ -6517,13 +6515,13 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, break; } - rp->type = cp->type; - rp->eir_len = cpu_to_le16(eir_len); - hci_dev_unlock(hdev); hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS); + rp->type = cp->type; + rp->eir_len = cpu_to_le16(eir_len); + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, MGMT_STATUS_SUCCESS, rp, sizeof(*rp) + eir_len); if (err < 0) From 57b0d3e8e7d570b693a1a253c637308130134a23 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 28 Mar 2015 15:18:59 -0700 Subject: [PATCH 310/567] Bluetooth: Fix error returns for Read Local OOB Extended Data commands The Read Local OOB Extended Data commands are required to return the address type and the data length at least. However currently the error returns only the address type. To fix this and avoid any extra allocations or stack memory, rearrange the code so that the same path can be used for error returns. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 71 +++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a9a0036ff0a7..3048092b1264 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6414,36 +6414,30 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, BT_DBG("%s", hdev->name); - if (!hdev_is_powered(hdev)) - return mgmt_cmd_complete(sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - MGMT_STATUS_NOT_POWERED, - &cp->type, sizeof(cp->type)); - - switch (cp->type) { - case BIT(BDADDR_BREDR): - status = mgmt_bredr_support(hdev); - if (status) - return mgmt_cmd_complete(sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - status, &cp->type, - sizeof(cp->type)); - eir_len = 5; - break; - case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)): - status = mgmt_le_support(hdev); - if (status) - return mgmt_cmd_complete(sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - status, &cp->type, - sizeof(cp->type)); - eir_len = 9 + 3 + 18 + 18 + 3; - break; - default: - return mgmt_cmd_complete(sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - MGMT_STATUS_INVALID_PARAMS, - &cp->type, sizeof(cp->type)); + if (hdev_is_powered(hdev)) { + switch (cp->type) { + case BIT(BDADDR_BREDR): + status = mgmt_bredr_support(hdev); + if (status) + eir_len = 0; + else + eir_len = 5; + break; + case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)): + status = mgmt_le_support(hdev); + if (status) + eir_len = 0; + else + eir_len = 9 + 3 + 18 + 18 + 3; + break; + default: + status = MGMT_STATUS_INVALID_PARAMS; + eir_len = 0; + break; + } + } else { + status = MGMT_STATUS_NOT_POWERED; + eir_len = 0; } rp_len = sizeof(*rp) + eir_len; @@ -6451,6 +6445,9 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, if (!rp) return -ENOMEM; + if (status) + goto complete; + hci_dev_lock(hdev); eir_len = 0; @@ -6463,11 +6460,8 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) && smp_generate_oob(hdev, hash, rand) < 0) { hci_dev_unlock(hdev); - err = mgmt_cmd_complete(sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - MGMT_STATUS_FAILED, - &cp->type, sizeof(cp->type)); - goto done; + status = MGMT_STATUS_FAILED; + goto complete; } if (hci_dev_test_flag(hdev, HCI_PRIVACY)) { @@ -6519,12 +6513,15 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS); + status = MGMT_STATUS_SUCCESS; + +complete: rp->type = cp->type; rp->eir_len = cpu_to_le16(eir_len); err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, - MGMT_STATUS_SUCCESS, rp, sizeof(*rp) + eir_len); - if (err < 0) + status, rp, sizeof(*rp) + eir_len); + if (err < 0 || status) goto done; err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev, From 20fa110a54d8070a7d68fb44a6c0ea2d8b09fddc Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 28 Mar 2015 15:32:52 -0700 Subject: [PATCH 311/567] Bluetooth: Remove superfluous extra empty line between functions Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_event.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3ac23964e108..20f34b861426 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1066,7 +1066,6 @@ static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev, hci_dev_unlock(hdev); } - static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); From 1e9e39f4a29857a396ac7b669d109f697f66695e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 26 Feb 2015 19:34:37 +0000 Subject: [PATCH 312/567] usbnet: Fix tx_packets stat for FLAG_MULTI_FRAME drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the usbnet core does not update the tx_packets statistic for drivers with FLAG_MULTI_PACKET and there is no hook in the TX completion path where they could do this. cdc_ncm and dependent drivers are bumping tx_packets stat on the transmit path while asix and sr9800 aren't updating it at all. Add a packet count in struct skb_data so these drivers can fill it in, initialise it to 1 for other drivers, and add the packet count to the tx_packets statistic on completion. Signed-off-by: Ben Hutchings Tested-by: Bjørn Mork Signed-off-by: David S. Miller --- drivers/net/usb/asix_common.c | 2 ++ drivers/net/usb/cdc_ncm.c | 3 ++- drivers/net/usb/sr9800.c | 1 + drivers/net/usb/usbnet.c | 5 +++-- include/linux/usb/usbnet.h | 12 ++++++++++++ 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 5c55f11572ba..724a9b50df7a 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -188,6 +188,8 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); skb_put(skb, sizeof(padbytes)); } + + usbnet_set_skb_tx_stats(skb, 1); return skb; } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 80a844e0ae03..70cbea551139 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1172,7 +1172,6 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) /* return skb */ ctx->tx_curr_skb = NULL; - dev->net->stats.tx_packets += ctx->tx_curr_frame_num; /* keep private stats: framing overhead and number of NTBs */ ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload; @@ -1184,6 +1183,8 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) */ dev->net->stats.tx_bytes -= skb_out->len - ctx->tx_curr_frame_payload; + usbnet_set_skb_tx_stats(skb_out, n); + return skb_out; exit_no_skb: diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c index b94a0fbb8b3b..7650cdc8fe6b 100644 --- a/drivers/net/usb/sr9800.c +++ b/drivers/net/usb/sr9800.c @@ -144,6 +144,7 @@ static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb, skb_put(skb, sizeof(padbytes)); } + usbnet_set_skb_tx_stats(skb, 1); return skb; } diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 449835f4331e..0f3ff285f6a1 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1188,8 +1188,7 @@ static void tx_complete (struct urb *urb) struct usbnet *dev = entry->dev; if (urb->status == 0) { - if (!(dev->driver_info->flags & FLAG_MULTI_PACKET)) - dev->net->stats.tx_packets++; + dev->net->stats.tx_packets += entry->packets; dev->net->stats.tx_bytes += entry->length; } else { dev->net->stats.tx_errors++; @@ -1348,6 +1347,8 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, urb->transfer_flags |= URB_ZERO_PACKET; } entry->length = urb->transfer_buffer_length = length; + if (!(info->flags & FLAG_MULTI_PACKET)) + usbnet_set_skb_tx_stats(skb, 1); spin_lock_irqsave(&dev->txq.lock, flags); retval = usb_autopm_get_interface_async(dev->intf); diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index d9a4905e01d0..ff3fb2bd0e90 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -228,8 +228,20 @@ struct skb_data { /* skb->cb is one of these */ struct usbnet *dev; enum skb_state state; size_t length; + unsigned long packets; }; +/* Drivers that set FLAG_MULTI_PACKET must call this in their + * tx_fixup method before returning an skb. + */ +static inline void +usbnet_set_skb_tx_stats(struct sk_buff *skb, unsigned long packets) +{ + struct skb_data *entry = (struct skb_data *) skb->cb; + + entry->packets = packets; +} + extern int usbnet_open(struct net_device *net); extern int usbnet_stop(struct net_device *net); extern netdev_tx_t usbnet_start_xmit(struct sk_buff *skb, From 7a1e890e2168e33fb62d84528e996b8b4b478fea Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 25 Mar 2015 21:41:33 +0100 Subject: [PATCH 313/567] usbnet: Fix tx_bytes statistic running backward in cdc_ncm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cdc_ncm disagrees with usbnet about how much framing overhead should be counted in the tx_bytes statistics, and tries 'fix' this by decrementing tx_bytes on the transmit path. But statistics must never be decremented except due to roll-over; this will thoroughly confuse user-space. Also, tx_bytes is only incremented by usbnet in the completion path. Fix this by requiring drivers that set FLAG_MULTI_FRAME to set a tx_bytes delta along with the tx_packets count. Fixes: beeecd42c3b4 ("net: cdc_ncm/cdc_mbim: adding NCM protocol statistics") Signed-off-by: Ben Hutchings Signed-off-by: Bjørn Mork --- drivers/net/usb/asix_common.c | 2 +- drivers/net/usb/cdc_ncm.c | 7 +++---- drivers/net/usb/sr9800.c | 2 +- drivers/net/usb/usbnet.c | 16 +++++++++++++--- include/linux/usb/usbnet.h | 6 ++++-- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 724a9b50df7a..75d6f26729a3 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -189,7 +189,7 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, skb_put(skb, sizeof(padbytes)); } - usbnet_set_skb_tx_stats(skb, 1); + usbnet_set_skb_tx_stats(skb, 1, 0); return skb; } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 70cbea551139..c3e4da9e79ca 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1177,13 +1177,12 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload; ctx->tx_ntbs++; - /* usbnet has already counted all the framing overhead. + /* usbnet will count all the framing overhead by default. * Adjust the stats so that the tx_bytes counter show real * payload data instead. */ - dev->net->stats.tx_bytes -= skb_out->len - ctx->tx_curr_frame_payload; - - usbnet_set_skb_tx_stats(skb_out, n); + usbnet_set_skb_tx_stats(skb_out, n, + ctx->tx_curr_frame_payload - skb_out->len); return skb_out; diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c index 7650cdc8fe6b..953de13267df 100644 --- a/drivers/net/usb/sr9800.c +++ b/drivers/net/usb/sr9800.c @@ -144,7 +144,7 @@ static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb, skb_put(skb, sizeof(padbytes)); } - usbnet_set_skb_tx_stats(skb, 1); + usbnet_set_skb_tx_stats(skb, 1, 0); return skb; } diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 0f3ff285f6a1..777757ae1973 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1346,9 +1346,19 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, } else urb->transfer_flags |= URB_ZERO_PACKET; } - entry->length = urb->transfer_buffer_length = length; - if (!(info->flags & FLAG_MULTI_PACKET)) - usbnet_set_skb_tx_stats(skb, 1); + urb->transfer_buffer_length = length; + + if (info->flags & FLAG_MULTI_PACKET) { + /* Driver has set number of packets and a length delta. + * Calculate the complete length and ensure that it's + * positive. + */ + entry->length += length; + if (WARN_ON_ONCE(entry->length <= 0)) + entry->length = length; + } else { + usbnet_set_skb_tx_stats(skb, 1, length); + } spin_lock_irqsave(&dev->txq.lock, flags); retval = usb_autopm_get_interface_async(dev->intf); diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index ff3fb2bd0e90..6e0ce8c7b8cb 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -227,7 +227,7 @@ struct skb_data { /* skb->cb is one of these */ struct urb *urb; struct usbnet *dev; enum skb_state state; - size_t length; + long length; unsigned long packets; }; @@ -235,11 +235,13 @@ struct skb_data { /* skb->cb is one of these */ * tx_fixup method before returning an skb. */ static inline void -usbnet_set_skb_tx_stats(struct sk_buff *skb, unsigned long packets) +usbnet_set_skb_tx_stats(struct sk_buff *skb, + unsigned long packets, long bytes_delta) { struct skb_data *entry = (struct skb_data *) skb->cb; entry->packets = packets; + entry->length = bytes_delta; } extern int usbnet_open(struct net_device *net); From f243e5a7859a24d10975afb9a1708cac624ba6f1 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Wed, 25 Mar 2015 14:45:03 -0700 Subject: [PATCH 314/567] ipmr,ip6mr: call ip6mr_free_table() on failure path Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 2 +- net/ipv6/ip6mr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 9d78427652d2..92825443fad6 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -268,7 +268,7 @@ static int __net_init ipmr_rules_init(struct net *net) return 0; err2: - kfree(mrt); + ipmr_free_table(mrt); err1: fib_rules_unregister(ops); return err; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 34b682617f50..52028f449a89 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -252,7 +252,7 @@ static int __net_init ip6mr_rules_init(struct net *net) return 0; err2: - kfree(mrt); + ip6mr_free_table(mrt); err1: fib_rules_unregister(ops); return err; From 4b8e27a86d209063d8aacfb918668bbb75e56019 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 26 Mar 2015 10:04:25 +0530 Subject: [PATCH 315/567] cxgb4: Allocate dynamic mem. for egress and ingress queue maps QIDs (egress/ingress) from firmware in FW_*_CMD.alloc command can be anywhere in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END. For eg, in the first load eqid can be from 100 to 300. In the next load it can be from 301 to 500 (assume eq_start is 100 and eq_end is 1000). The driver was assuming them to always start from EQ(IQFLINT)_START till MAX_EGRQ(INGQ). This was causing stack overflow and subsequent crash. Fixed it by dynamically allocating memory (of qsize (x_END - x_START + 1)) for these structures. Based on original work by Santosh Rastapur Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 12 +-- .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 79 +++++++++++++++++-- drivers/net/ethernet/chelsio/cxgb4/sge.c | 7 +- 3 files changed, 83 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 97842d03675b..8816c645de7d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -376,8 +376,6 @@ enum { enum { INGQ_EXTRAS = 2, /* firmware event queue and */ /* forwarded interrupts */ - MAX_EGRQ = MAX_ETH_QSETS*2 + MAX_OFLD_QSETS*2 - + MAX_CTRL_QUEUES + MAX_RDMA_QUEUES + MAX_ISCSI_QUEUES, MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES + MAX_RDMA_CIQS + MAX_ISCSI_QUEUES + INGQ_EXTRAS, }; @@ -616,11 +614,13 @@ struct sge { unsigned int idma_qid[2]; /* SGE IDMA Hung Ingress Queue ID */ unsigned int egr_start; + unsigned int egr_sz; unsigned int ingr_start; - void *egr_map[MAX_EGRQ]; /* qid->queue egress queue map */ - struct sge_rspq *ingr_map[MAX_INGQ]; /* qid->queue ingress queue map */ - DECLARE_BITMAP(starving_fl, MAX_EGRQ); - DECLARE_BITMAP(txq_maperr, MAX_EGRQ); + unsigned int ingr_sz; + void **egr_map; /* qid->queue egress queue map */ + struct sge_rspq **ingr_map; /* qid->queue ingress queue map */ + unsigned long *starving_fl; + unsigned long *txq_maperr; struct timer_list rx_timer; /* refills starving FLs */ struct timer_list tx_timer; /* checks Tx queues */ }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index a22cf932ca35..b9b5a7b1a116 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -920,7 +920,7 @@ static void quiesce_rx(struct adapter *adap) { int i; - for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { + for (i = 0; i < adap->sge.ingr_sz; i++) { struct sge_rspq *q = adap->sge.ingr_map[i]; if (q && q->handler) { @@ -941,7 +941,7 @@ static void enable_rx(struct adapter *adap) { int i; - for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) { + for (i = 0; i < adap->sge.ingr_sz; i++) { struct sge_rspq *q = adap->sge.ingr_map[i]; if (!q) @@ -970,8 +970,8 @@ static int setup_sge_queues(struct adapter *adap) int err, msi_idx, i, j; struct sge *s = &adap->sge; - bitmap_zero(s->starving_fl, MAX_EGRQ); - bitmap_zero(s->txq_maperr, MAX_EGRQ); + bitmap_zero(s->starving_fl, s->egr_sz); + bitmap_zero(s->txq_maperr, s->egr_sz); if (adap->flags & USING_MSIX) msi_idx = 1; /* vector 0 is for non-queue interrupts */ @@ -983,6 +983,19 @@ static int setup_sge_queues(struct adapter *adap) msi_idx = -((int)s->intrq.abs_id + 1); } + /* NOTE: If you add/delete any Ingress/Egress Queue allocations in here, + * don't forget to update the following which need to be + * synchronized to and changes here. + * + * 1. The calculations of MAX_INGQ in cxgb4.h. + * + * 2. Update enable_msix/name_msix_vecs/request_msix_queue_irqs + * to accommodate any new/deleted Ingress Queues + * which need MSI-X Vectors. + * + * 3. Update sge_qinfo_show() to include information on the + * new/deleted queues. + */ err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], msi_idx, NULL, fwevtq_handler); if (err) { @@ -4733,8 +4746,9 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c) if (ret < 0) return ret; - ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, MAX_EGRQ, 64, MAX_INGQ, - 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, FW_CMD_CAP_PF); + ret = t4_cfg_pfvf(adap, adap->fn, adap->fn, 0, adap->sge.egr_sz, 64, + MAX_INGQ, 0, 0, 4, 0xf, 0xf, 16, FW_CMD_CAP_PF, + FW_CMD_CAP_PF); if (ret < 0) return ret; @@ -5293,6 +5307,51 @@ static int adap_init0(struct adapter *adap) adap->tids.nftids = val[4] - val[3] + 1; adap->sge.ingr_start = val[5]; + /* qids (ingress/egress) returned from firmware can be anywhere + * in the range from EQ(IQFLINT)_START to EQ(IQFLINT)_END. + * Hence driver needs to allocate memory for this range to + * store the queue info. Get the highest IQFLINT/EQ index returned + * in FW_EQ_*_CMD.alloc command. + */ + params[0] = FW_PARAM_PFVF(EQ_END); + params[1] = FW_PARAM_PFVF(IQFLINT_END); + ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val); + if (ret < 0) + goto bye; + adap->sge.egr_sz = val[0] - adap->sge.egr_start + 1; + adap->sge.ingr_sz = val[1] - adap->sge.ingr_start + 1; + + adap->sge.egr_map = kcalloc(adap->sge.egr_sz, + sizeof(*adap->sge.egr_map), GFP_KERNEL); + if (!adap->sge.egr_map) { + ret = -ENOMEM; + goto bye; + } + + adap->sge.ingr_map = kcalloc(adap->sge.ingr_sz, + sizeof(*adap->sge.ingr_map), GFP_KERNEL); + if (!adap->sge.ingr_map) { + ret = -ENOMEM; + goto bye; + } + + /* Allocate the memory for the vaious egress queue bitmaps + * ie starving_fl and txq_maperr. + */ + adap->sge.starving_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz), + sizeof(long), GFP_KERNEL); + if (!adap->sge.starving_fl) { + ret = -ENOMEM; + goto bye; + } + + adap->sge.txq_maperr = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz), + sizeof(long), GFP_KERNEL); + if (!adap->sge.txq_maperr) { + ret = -ENOMEM; + goto bye; + } + params[0] = FW_PARAM_PFVF(CLIP_START); params[1] = FW_PARAM_PFVF(CLIP_END); ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val); @@ -5501,6 +5560,10 @@ static int adap_init0(struct adapter *adap) * happened to HW/FW, stop issuing commands. */ bye: + kfree(adap->sge.egr_map); + kfree(adap->sge.ingr_map); + kfree(adap->sge.starving_fl); + kfree(adap->sge.txq_maperr); if (ret != -ETIMEDOUT && ret != -EIO) t4_fw_bye(adap, adap->mbox); return ret; @@ -5912,6 +5975,10 @@ static void free_some_resources(struct adapter *adapter) t4_free_mem(adapter->l2t); t4_free_mem(adapter->tids.tid_tab); + kfree(adapter->sge.egr_map); + kfree(adapter->sge.ingr_map); + kfree(adapter->sge.starving_fl); + kfree(adapter->sge.txq_maperr); disable_msi(adapter); for_each_port(adapter, i) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index b4b9f6048fe7..b688b32c21fe 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2171,7 +2171,7 @@ static void sge_rx_timer_cb(unsigned long data) struct adapter *adap = (struct adapter *)data; struct sge *s = &adap->sge; - for (i = 0; i < ARRAY_SIZE(s->starving_fl); i++) + for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++) for (m = s->starving_fl[i]; m; m &= m - 1) { struct sge_eth_rxq *rxq; unsigned int id = __ffs(m) + i * BITS_PER_LONG; @@ -2259,7 +2259,7 @@ static void sge_tx_timer_cb(unsigned long data) struct adapter *adap = (struct adapter *)data; struct sge *s = &adap->sge; - for (i = 0; i < ARRAY_SIZE(s->txq_maperr); i++) + for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++) for (m = s->txq_maperr[i]; m; m &= m - 1) { unsigned long id = __ffs(m) + i * BITS_PER_LONG; struct sge_ofld_txq *txq = s->egr_map[id]; @@ -2741,7 +2741,8 @@ void t4_free_sge_resources(struct adapter *adap) free_rspq_fl(adap, &adap->sge.intrq, NULL); /* clear the reverse egress queue map */ - memset(adap->sge.egr_map, 0, sizeof(adap->sge.egr_map)); + memset(adap->sge.egr_map, 0, + adap->sge.egr_sz * sizeof(*adap->sge.egr_map)); } void t4_sge_start(struct adapter *adap) From b37987e8db5faee3fc12baecc4699f9d92bc0695 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 26 Mar 2015 10:04:26 +0530 Subject: [PATCH 316/567] cxgb4: Disable interrupts and napi before unregistering netdev Disable interrupts and quiesce rx before unregistering net device to avoid crash while unloading driver when traffic is flowing through. Based on original work by Shameem Khalid Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index b9b5a7b1a116..826de7a7f83c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -934,6 +934,21 @@ static void quiesce_rx(struct adapter *adap) } } +/* Disable interrupt and napi handler */ +static void disable_interrupts(struct adapter *adap) +{ + if (adap->flags & FULL_INIT_DONE) { + t4_intr_disable(adap); + if (adap->flags & USING_MSIX) { + free_msix_queue_irqs(adap); + free_irq(adap->msix_info[0].vec, adap); + } else { + free_irq(adap->pdev->irq, adap); + } + quiesce_rx(adap); + } +} + /* * Enable NAPI scheduling and interrupt generation for all Rx queues. */ @@ -4257,19 +4272,12 @@ static int cxgb_up(struct adapter *adap) static void cxgb_down(struct adapter *adapter) { - t4_intr_disable(adapter); cancel_work_sync(&adapter->tid_release_task); cancel_work_sync(&adapter->db_full_task); cancel_work_sync(&adapter->db_drop_task); adapter->tid_release_task_busy = false; adapter->tid_release_head = NULL; - if (adapter->flags & USING_MSIX) { - free_msix_queue_irqs(adapter); - free_irq(adapter->msix_info[0].vec, adapter); - } else - free_irq(adapter->pdev->irq, adapter); - quiesce_rx(adapter); t4_sge_stop(adapter); t4_free_sge_resources(adapter); adapter->flags &= ~FULL_INIT_DONE; @@ -5591,6 +5599,7 @@ static pci_ers_result_t eeh_err_detected(struct pci_dev *pdev, netif_carrier_off(dev); } spin_unlock(&adap->stats_lock); + disable_interrupts(adap); if (adap->flags & FULL_INIT_DONE) cxgb_down(adap); rtnl_unlock(); @@ -6304,6 +6313,8 @@ static void remove_one(struct pci_dev *pdev) if (is_offload(adapter)) detach_ulds(adapter); + disable_interrupts(adapter); + for_each_port(adapter, i) if (adapter->port[i]->reg_state == NETREG_REGISTERED) unregister_netdev(adapter->port[i]); From 263fcd312deffb9bf10f007f958dccfa64a807f5 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Mar 2015 14:15:02 +0000 Subject: [PATCH 317/567] irqchip: gicv3-its: Fix encoding of collection's target redistributor With a monolithic GICv3, redistributors are addressed using a linear number, while a distributed implementation uses physical addresses. When encoding a target address into a command, we strip the lower 16 bits, as redistributors are always 64kB aligned. This works perfectly well with a distributed implementation, but has the silly effect of always encoding target 0 in the monolithic case (unless you have more than 64k CPUs, of course). The obvious fix is to shift the linear target number by 16 when computing the target address, so that we don't loose any precious bit. Reported-by: Andre Przywara Tested-by: Andre Przywara Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1427465705-17126-2-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- drivers/irqchip/irq-gic-v3-its.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 596b0a9eee99..7318dba11957 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1026,7 +1026,7 @@ static void its_cpu_init_collection(void) * This ITS wants a linear CPU number. */ target = readq_relaxed(gic_data_rdist_rd_base() + GICR_TYPER); - target = GICR_TYPER_CPU_NUMBER(target); + target = GICR_TYPER_CPU_NUMBER(target) << 16; } /* Perform collection mapping */ From 7e195ba03738dec72fe337dcd3cb3c3c2bd66c30 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 27 Mar 2015 14:15:03 +0000 Subject: [PATCH 318/567] irqchip: gicv3-its: Fix device ID encoding When building ITS commands which have the device ID in it, we should mask off the whole upper 32 bits of the first command word before inserting the new value in there. Signed-off-by: Andre Przywara Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1427465705-17126-3-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- drivers/irqchip/irq-gic-v3-its.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 7318dba11957..fa0c43660c8b 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -169,7 +169,7 @@ static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr) static void its_encode_devid(struct its_cmd_block *cmd, u32 devid) { - cmd->raw_cmd[0] &= ~(0xffffUL << 32); + cmd->raw_cmd[0] &= BIT_ULL(32) - 1; cmd->raw_cmd[0] |= ((u64)devid) << 32; } From 4ad3e3634a6cbe916722c7113c5b488d52c7a3dc Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Mar 2015 14:15:04 +0000 Subject: [PATCH 319/567] irqchip: gicv3-its: Fix PROP/PEND and BASE/CBASE confusion The ITS driver sometime mixes up the use of GICR_PROPBASE bitfields for the GICR_PENDBASE register, and GITS_BASER for GICR_CBASE. This does not lead to any observable bug because similar bits are at the same location, but this just make the code even harder to understand... This patch provides the required #defines and fixes the mixup. Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1427465705-17126-4-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- drivers/irqchip/irq-gic-v3-its.c | 6 +++--- include/linux/irqchip/arm-gic-v3.h | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index fa0c43660c8b..56353f6b5952 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -986,8 +986,8 @@ static void its_cpu_init_lpis(void) /* set PENDBASE */ val = (page_to_phys(pend_page) | - GICR_PROPBASER_InnerShareable | - GICR_PROPBASER_WaWb); + GICR_PENDBASER_InnerShareable | + GICR_PENDBASER_WaWb); writeq_relaxed(val, rbase + GICR_PENDBASER); @@ -1425,7 +1425,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) writeq_relaxed(0, its->base + GITS_CWRITER); writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); - if ((tmp ^ baser) & GITS_BASER_SHAREABILITY_MASK) { + if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) { pr_info("ITS: using cache flushing for cmd queue\n"); its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING; } diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 781974afff9f..826a4bd63d4a 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -128,6 +128,19 @@ #define GICR_PROPBASER_RaWaWb (7U << 7) #define GICR_PROPBASER_IDBITS_MASK (0x1f) +#define GICR_PENDBASER_NonShareable (0U << 10) +#define GICR_PENDBASER_InnerShareable (1U << 10) +#define GICR_PENDBASER_OuterShareable (2U << 10) +#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10) +#define GICR_PENDBASER_nCnB (0U << 7) +#define GICR_PENDBASER_nC (1U << 7) +#define GICR_PENDBASER_RaWt (2U << 7) +#define GICR_PENDBASER_RaWb (3U << 7) +#define GICR_PENDBASER_WaWt (4U << 7) +#define GICR_PENDBASER_WaWb (5U << 7) +#define GICR_PENDBASER_RaWaWt (6U << 7) +#define GICR_PENDBASER_RaWaWb (7U << 7) + /* * Re-Distributor registers, offsets from SGI_base */ From 241a386c7dbb8b0db400a1f92f2ebe3b10eb661d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 27 Mar 2015 14:15:05 +0000 Subject: [PATCH 320/567] irqchip: gicv3-its: Use non-cacheable accesses when no shareability If the ITS or the redistributors report their shareability as zero, then it is important to make sure they will no generate any cacheable traffic, as this is unlikely to produce the expected result. Signed-off-by: Marc Zyngier Link: https://lkml.kernel.org/r/1427465705-17126-5-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper --- drivers/irqchip/irq-gic-v3-its.c | 47 +++++++++++++++++++++++++++--- include/linux/irqchip/arm-gic-v3.h | 4 +++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 56353f6b5952..9687f8afebff 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -802,6 +802,7 @@ static int its_alloc_tables(struct its_node *its) int i; int psz = SZ_64K; u64 shr = GITS_BASER_InnerShareable; + u64 cache = GITS_BASER_WaWb; for (i = 0; i < GITS_BASER_NR_REGS; i++) { u64 val = readq_relaxed(its->base + GITS_BASER + i * 8); @@ -848,7 +849,7 @@ retry_baser: val = (virt_to_phys(base) | (type << GITS_BASER_TYPE_SHIFT) | ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) | - GITS_BASER_WaWb | + cache | shr | GITS_BASER_VALID); @@ -874,9 +875,12 @@ retry_baser: * Shareability didn't stick. Just use * whatever the read reported, which is likely * to be the only thing this redistributor - * supports. + * supports. If that's zero, make it + * non-cacheable as well. */ shr = tmp & GITS_BASER_SHAREABILITY_MASK; + if (!shr) + cache = GITS_BASER_nC; goto retry_baser; } @@ -980,6 +984,17 @@ static void its_cpu_init_lpis(void) tmp = readq_relaxed(rbase + GICR_PROPBASER); if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { + if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) { + /* + * The HW reports non-shareable, we must + * remove the cacheability attributes as + * well. + */ + val &= ~(GICR_PROPBASER_SHAREABILITY_MASK | + GICR_PROPBASER_CACHEABILITY_MASK); + val |= GICR_PROPBASER_nC; + writeq_relaxed(val, rbase + GICR_PROPBASER); + } pr_info_once("GIC: using cache flushing for LPI property table\n"); gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING; } @@ -990,6 +1005,18 @@ static void its_cpu_init_lpis(void) GICR_PENDBASER_WaWb); writeq_relaxed(val, rbase + GICR_PENDBASER); + tmp = readq_relaxed(rbase + GICR_PENDBASER); + + if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { + /* + * The HW reports non-shareable, we must remove the + * cacheability attributes as well. + */ + val &= ~(GICR_PENDBASER_SHAREABILITY_MASK | + GICR_PENDBASER_CACHEABILITY_MASK); + val |= GICR_PENDBASER_nC; + writeq_relaxed(val, rbase + GICR_PENDBASER); + } /* Enable LPIs */ val = readl_relaxed(rbase + GICR_CTLR); @@ -1422,14 +1449,26 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) writeq_relaxed(baser, its->base + GITS_CBASER); tmp = readq_relaxed(its->base + GITS_CBASER); - writeq_relaxed(0, its->base + GITS_CWRITER); - writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) { + if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) { + /* + * The HW reports non-shareable, we must + * remove the cacheability attributes as + * well. + */ + baser &= ~(GITS_CBASER_SHAREABILITY_MASK | + GITS_CBASER_CACHEABILITY_MASK); + baser |= GITS_CBASER_nC; + writeq_relaxed(baser, its->base + GITS_CBASER); + } pr_info("ITS: using cache flushing for cmd queue\n"); its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING; } + writeq_relaxed(0, its->base + GITS_CWRITER); + writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); + if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) { its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its); if (!its->domain) { diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 826a4bd63d4a..ffbc034c8810 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -126,6 +126,7 @@ #define GICR_PROPBASER_WaWb (5U << 7) #define GICR_PROPBASER_RaWaWt (6U << 7) #define GICR_PROPBASER_RaWaWb (7U << 7) +#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7) #define GICR_PROPBASER_IDBITS_MASK (0x1f) #define GICR_PENDBASER_NonShareable (0U << 10) @@ -140,6 +141,7 @@ #define GICR_PENDBASER_WaWb (5U << 7) #define GICR_PENDBASER_RaWaWt (6U << 7) #define GICR_PENDBASER_RaWaWb (7U << 7) +#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7) /* * Re-Distributor registers, offsets from SGI_base @@ -195,6 +197,7 @@ #define GITS_CBASER_WaWb (5UL << 59) #define GITS_CBASER_RaWaWt (6UL << 59) #define GITS_CBASER_RaWaWb (7UL << 59) +#define GITS_CBASER_CACHEABILITY_MASK (7UL << 59) #define GITS_CBASER_NonShareable (0UL << 10) #define GITS_CBASER_InnerShareable (1UL << 10) #define GITS_CBASER_OuterShareable (2UL << 10) @@ -211,6 +214,7 @@ #define GITS_BASER_WaWb (5UL << 59) #define GITS_BASER_RaWaWt (6UL << 59) #define GITS_BASER_RaWaWb (7UL << 59) +#define GITS_BASER_CACHEABILITY_MASK (7UL << 59) #define GITS_BASER_TYPE_SHIFT (56) #define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7) #define GITS_BASER_ENTRY_SIZE_SHIFT (48) From 4217291e592da0e4258b652e82e5428639d29acc Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 26 Mar 2015 17:56:38 +0100 Subject: [PATCH 321/567] netns: don't clear nsid too early on removal With the current code, ids are removed too early. Suppose you have an ipip interface that stands in the netns foo and its link part in the netns bar (so the netns bar has an nsid into the netns foo). Now, you remove the netns bar: - the bar nsid into the netns foo is removed - the netns exit method of ipip is called, thus our ipip iface is removed: => a netlink message is sent in the netns foo to advertise this deletion => this netlink message requests an nsid for bar, thus a new nsid is allocated for bar and never removed. We must remove nsids when we are sure that nobody will refer to netns currently cleaned. Fixes: 0c7aecd4bde4 ("netns: add rtnl cmd to add and get peer netns ids") Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/net_namespace.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index cb5290b8c428..5221f975a4cc 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -349,7 +349,7 @@ static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */ static void cleanup_net(struct work_struct *work) { const struct pernet_operations *ops; - struct net *net, *tmp; + struct net *net, *tmp, *peer; struct list_head net_kill_list; LIST_HEAD(net_exit_list); @@ -365,14 +365,6 @@ static void cleanup_net(struct work_struct *work) list_for_each_entry(net, &net_kill_list, cleanup_list) { list_del_rcu(&net->list); list_add_tail(&net->exit_list, &net_exit_list); - for_each_net(tmp) { - int id = __peernet2id(tmp, net, false); - - if (id >= 0) - idr_remove(&tmp->netns_ids, id); - } - idr_destroy(&net->netns_ids); - } rtnl_unlock(); @@ -398,12 +390,26 @@ static void cleanup_net(struct work_struct *work) */ rcu_barrier(); + rtnl_lock(); /* Finally it is safe to free my network namespace structure */ list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { + /* Unreference net from all peers (no need to loop over + * net_exit_list because idr_destroy() will be called for each + * element of this list. + */ + for_each_net(peer) { + int id = __peernet2id(peer, net, false); + + if (id >= 0) + idr_remove(&peer->netns_ids, id); + } + idr_destroy(&net->netns_ids); + list_del_init(&net->exit_list); put_user_ns(net->user_ns); net_drop_ns(net); } + rtnl_unlock(); } static DECLARE_WORK(net_cleanup_work, cleanup_net); From 2ff2acf1fb65f1c83c41b67aba990c6d49a2274c Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 27 Mar 2015 11:01:18 +0530 Subject: [PATCH 322/567] cxgb4vf: Fix sparse warnings Fixes sparse warnings introduced in commit e85c9a7abfa407ed ("cxgb4/cxgb4vf: Add code to calculate T5 BAR2 Offsets for SGE Queue Registers") and df64e4d38c904dd3 ("cxgb4/cxgb4vf: Use new interfaces to calculate BAR2 SGE Queue Register addresses") and few old ones sparse warnings: >> drivers/net/ethernet/chelsio/cxgb4vf/sge.c:1006:48: sparse: cast removes >> address space of expression >> drivers/net/ethernet/chelsio/cxgb4vf/sge.c:1006:48: sparse: incorrect type in >> initializer (different address space) >> drivers/net/ethernet/chelsio/cxgb4vf/sge.c:1020:40: sparse: incorrect type in >> argument 1 (different base types) Reported-by: Dan Carpenter Reported-by: kbuild test robot Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 12 ++++++++---- drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index 0545f0de1c52..e0d711071afb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -1004,7 +1004,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, ? (tq->pidx - 1) : (tq->size - 1)); __be64 *src = (__be64 *)&tq->desc[index]; - __be64 __iomem *dst = (__be64 *)(tq->bar2_addr + + __be64 __iomem *dst = (__be64 __iomem *)(tq->bar2_addr + SGE_UDB_WCDOORBELL); unsigned int count = EQ_UNIT / sizeof(__be64); @@ -1018,7 +1018,11 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq, * DMA. */ while (count) { - writeq(*src, dst); + /* the (__force u64) is because the compiler + * doesn't understand the endian swizzling + * going on + */ + writeq((__force u64)*src, dst); src++; dst++; count--; @@ -1252,8 +1256,8 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(DIV_ROUND_UP(ETHTXQ_MAX_HDR, TXD_PER_EQ_UNIT) > 1); wr = (void *)&txq->q.desc[txq->q.pidx]; wr->equiq_to_len16 = cpu_to_be32(wr_mid); - wr->r3[0] = cpu_to_be64(0); - wr->r3[1] = cpu_to_be64(0); + wr->r3[0] = cpu_to_be32(0); + wr->r3[1] = cpu_to_be32(0); skb_copy_from_linear_data(skb, (void *)wr->ethmacdst, fw_hdr_copy_len); end = (u64 *)wr + flits; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 1b5506df35b1..280b4a215849 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -210,10 +210,10 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, if (rpl) { /* request bit in high-order BE word */ - WARN_ON((be32_to_cpu(*(const u32 *)cmd) + WARN_ON((be32_to_cpu(*(const __be32 *)cmd) & FW_CMD_REQUEST_F) == 0); get_mbox_rpl(adapter, rpl, size, mbox_data); - WARN_ON((be32_to_cpu(*(u32 *)rpl) + WARN_ON((be32_to_cpu(*(__be32 *)rpl) & FW_CMD_REQUEST_F) != 0); } t4_write_reg(adapter, mbox_ctl, @@ -484,7 +484,7 @@ int t4_bar2_sge_qregs(struct adapter *adapter, * o The BAR2 Queue ID. * o The BAR2 Queue ID Offset into the BAR2 page. */ - bar2_page_offset = ((qid >> qpp_shift) << page_shift); + bar2_page_offset = ((u64)(qid >> qpp_shift) << page_shift); bar2_qid = qid & qpp_mask; bar2_qid_offset = bar2_qid * SGE_UDB_SIZE; From 4ad19de8774e2a7b075b3e8ea48db85adcf33fa6 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Fri, 27 Mar 2015 12:24:22 +0300 Subject: [PATCH 323/567] net: tcp6: fix double call of tcp_v6_fill_cb() tcp_v6_fill_cb() will be called twice if socket's state changes from TCP_TIME_WAIT to TCP_LISTEN. That can result in control buffer data corruption because in the second tcp_v6_fill_cb() call it's not copying IP6CB(skb) anymore, but 'seq', 'end_seq', etc., so we can get weird and unpredictable results. Performance loss of up to 1200% has been observed in LTP/vxlan03 test. This can be fixed by copying inet6_skb_parm to the beginning of 'cb' only if xfrm6_policy_check() and tcp_v6_fill_cb() are going to be called again. Fixes: 2dc49d1680b53 ("tcp6: don't move IP6CB before xfrm6_policy_check()") Signed-off-by: Alexey Kodanev Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/tcp_ipv6.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index b283a498f7a4..1f5e62229aaa 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1411,6 +1411,15 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, TCP_SKB_CB(skb)->sacked = 0; } +static void tcp_v6_restore_cb(struct sk_buff *skb) +{ + /* We need to move header back to the beginning if xfrm6_policy_check() + * and tcp_v6_fill_cb() are going to be called again. + */ + memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, + sizeof(struct inet6_skb_parm)); +} + static int tcp_v6_rcv(struct sk_buff *skb) { const struct tcphdr *th; @@ -1543,6 +1552,7 @@ do_time_wait: inet_twsk_deschedule(tw, &tcp_death_row); inet_twsk_put(tw); sk = sk2; + tcp_v6_restore_cb(skb); goto process; } /* Fall through to ACK */ @@ -1551,6 +1561,7 @@ do_time_wait: tcp_v6_timewait_ack(sk, skb); break; case TCP_TW_RST: + tcp_v6_restore_cb(skb); goto no_tcp_socket; case TCP_TW_SUCCESS: ; From 63c607321492c5efc7a31bc4ea734b877f8e7f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 27 Mar 2015 11:08:32 +0100 Subject: [PATCH 324/567] net: fec: setup right value for mdio hold time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The FEC modules used on i.MX28 and newer have a register to tune the MDIO output hold time that should be at least 10 ns. Up to now this value was not explicitly set and so resulted in less hold time if the fec clock was faster than 100 MHz. This was noticed on an i.MX28 machine that uses an input clock of ~150 Mhz which resulted in unreliable communication with a Marvell switch. Signed-off-by: Uwe Kleine-König Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 30 ++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 78e1ce09b1ab..f6a3a7abd468 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1954,6 +1954,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) struct fec_enet_private *fep = netdev_priv(ndev); struct device_node *node; int err = -ENXIO, i; + u32 mii_speed, holdtime; /* * The i.MX28 dual fec interfaces are not equal. @@ -1991,10 +1992,33 @@ static int fec_enet_mii_init(struct platform_device *pdev) * Reference Manual has an error on this, and gets fixed on i.MX6Q * document. */ - fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000); + mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 5000000); if (fep->quirks & FEC_QUIRK_ENET_MAC) - fep->phy_speed--; - fep->phy_speed <<= 1; + mii_speed--; + if (mii_speed > 63) { + dev_err(&pdev->dev, + "fec clock (%lu) to fast to get right mii speed\n", + clk_get_rate(fep->clk_ipg)); + err = -EINVAL; + goto err_out; + } + + /* + * The i.MX28 and i.MX6 types have another filed in the MSCR (aka + * MII_SPEED) register that defines the MDIO output hold time. Earlier + * versions are RAZ there, so just ignore the difference and write the + * register always. + * The minimal hold time according to IEE802.3 (clause 22) is 10 ns. + * HOLDTIME + 1 is the number of clk cycles the fec is holding the + * output. + * The HOLDTIME bitfield takes values between 0 and 7 (inclusive). + * Given that ceil(clkrate / 5000000) <= 64, the calculation for + * holdtime cannot result in a value greater than 3. + */ + holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1; + + fep->phy_speed = mii_speed << 1 | holdtime << 8; + writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); fep->mii_bus = mdiobus_alloc(); From 78d84bc3734c2566dbba09baae2414734661ed6a Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Tue, 17 Mar 2015 12:35:41 +0000 Subject: [PATCH 325/567] arm64: juno: Fix misleading name of UART reference clock The UART reference clock speed is 7273.8 kHz, not 72738 kHz. Dots aren't usually used in node names even though ePAPR permits them. However, this can easily be avoided by expressing the frequency in Hz, not kHz. This patch changes the name to refclk7273800hz, reflecting the actual clock speed. Signed-off-by: Dave Martin Acked-by: Liviu Dudau Signed-off-by: Olof Johansson --- arch/arm64/boot/dts/arm/juno-clocks.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/arm/juno-clocks.dtsi b/arch/arm64/boot/dts/arm/juno-clocks.dtsi index ea2b5666a16f..c9b89efe0f56 100644 --- a/arch/arm64/boot/dts/arm/juno-clocks.dtsi +++ b/arch/arm64/boot/dts/arm/juno-clocks.dtsi @@ -8,7 +8,7 @@ */ /* SoC fixed clocks */ - soc_uartclk: refclk72738khz { + soc_uartclk: refclk7273800hz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <7273800>; From e42391cd048809d903291d07f86ed3934ce138e9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 29 Mar 2015 15:26:31 -0700 Subject: [PATCH 326/567] Linux 4.0-rc6 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 14c722f96877..da36a3be7969 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 0 SUBLEVEL = 0 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = Hurr durr I'ma sheep # *DOCUMENTATION* From 01fbd4ecff4f8dc8ca9614778326cc159705623e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 19 Mar 2015 15:32:49 +0100 Subject: [PATCH 327/567] rt2800usb: check Autorun mode on FW load only once Seems H/W report correctly firmware Autorun value only at initialization stage. When we close interface and open it again, Autorun value is 0 and we try to load firmware what kills the device. To fix clear REQUIRE_FIRMWARE firmware flag, to do not load firmware again, once we discover Autorun mode. Reported-and-tested-by: Sebastian Andrzej Siewior Signed-off-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/rt2x00/rt2800usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 41b6fb16c661..6ec2466b52b6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -293,6 +293,7 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev, if (retval) { rt2x00_info(rt2x00dev, "Firmware loading not required - NIC in AutoRun mode\n"); + __clear_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags); } else { rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, data + offset, length); From e480e1344873b6a715d06a003e603d86a11a4033 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Fri, 20 Mar 2015 19:31:33 +0900 Subject: [PATCH 328/567] rtlwifi: Change REG_CR+2 to MSR I changed REG_CR+2 and (MSR) to MSR because MSR is defined as (REG_CR + 2). Signed-off-by: Taehee Yoo Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8188ee/hw.c | 4 ++-- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192de/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192ee/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192se/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8723be/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8821ae/hw.c | 4 ++-- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c index bb9f5382da17..86ce5b1930e6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c @@ -886,7 +886,7 @@ static bool _rtl88ee_init_mac(struct ieee80211_hw *hw) rtl_write_word(rtlpriv, REG_CR, 0x2ff); rtl_write_byte(rtlpriv, REG_CR+1, 0x06); - rtl_write_byte(rtlpriv, REG_CR+2, 0x00); + rtl_write_byte(rtlpriv, MSR, 0x00); if (!rtlhal->mac_func_enable) { if (_rtl88ee_llt_table_init(hw) == false) { @@ -1278,7 +1278,7 @@ static int _rtl88ee_set_media_status(struct ieee80211_hw *hw, mode); } - rtl_write_byte(rtlpriv, (MSR), bt_msr | mode); + rtl_write_byte(rtlpriv, MSR, bt_msr | mode); rtlpriv->cfg->ops->led_control(hw, ledaction); if (mode == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 43b2b20e3fcf..d310d55d800e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1364,7 +1364,7 @@ static int _rtl92cu_set_media_status(struct ieee80211_hw *hw, "Network type %d not supported!\n", type); goto error_out; } - rtl_write_byte(rtlpriv, (MSR), bt_msr); + rtl_write_byte(rtlpriv, MSR, bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 133e395b7401..adb810794eef 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -497,7 +497,7 @@ int rtl92c_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) "Network type %d not supported!\n", type); return -EOPNOTSUPP; } - rtl_write_byte(rtlpriv, (REG_CR + 2), value); + rtl_write_byte(rtlpriv, MSR, value); return 0; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index 01bcc2d218dc..f49b60d31450 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -1126,7 +1126,7 @@ static int _rtl92de_set_media_status(struct ieee80211_hw *hw, break; } - rtl_write_byte(rtlpriv, REG_CR + 2, bt_msr); + rtl_write_byte(rtlpriv, MSR, bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c index db230a3f0137..da0a6125f314 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c @@ -1510,7 +1510,7 @@ static int _rtl92ee_set_media_status(struct ieee80211_hw *hw, mode); } - rtl_write_byte(rtlpriv, (MSR), bt_msr | mode); + rtl_write_byte(rtlpriv, MSR, bt_msr | mode); rtlpriv->cfg->ops->led_control(hw, ledaction); if (mode == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index dee88a80bee1..12b0978ba4fa 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -1204,7 +1204,7 @@ static int _rtl92se_set_media_status(struct ieee80211_hw *hw, if (type != NL80211_IFTYPE_AP && rtlpriv->mac80211.link_state < MAC80211_LINKED) bt_msr = rtl_read_byte(rtlpriv, MSR) & ~MSR_LINK_MASK; - rtl_write_byte(rtlpriv, (MSR), bt_msr); + rtl_write_byte(rtlpriv, MSR, bt_msr); temp = rtl_read_dword(rtlpriv, TCR); rtl_write_dword(rtlpriv, TCR, temp & (~BIT(8))); diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index b3b094759f6d..67bb47d77b68 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c @@ -1183,7 +1183,7 @@ static int _rtl8723e_set_media_status(struct ieee80211_hw *hw, mode); } - rtl_write_byte(rtlpriv, (MSR), bt_msr | mode); + rtl_write_byte(rtlpriv, MSR, bt_msr | mode); rtlpriv->cfg->ops->led_control(hw, ledaction); if (mode == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c index b46998341c40..b681af3c7a35 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723be/hw.c @@ -1558,7 +1558,7 @@ static int _rtl8723be_set_media_status(struct ieee80211_hw *hw, mode); } - rtl_write_byte(rtlpriv, (MSR), bt_msr | mode); + rtl_write_byte(rtlpriv, MSR, bt_msr | mode); rtlpriv->cfg->ops->led_control(hw, ledaction); if (mode == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c index 2a0a71bac00c..8704eee9f3a4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c @@ -423,7 +423,7 @@ void rtl8821ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) *((u16 *)(val+4)) = rtl_read_word(rtlpriv, REG_BSSID+4); break; case HW_VAR_MEDIA_STATUS: - val[0] = rtl_read_byte(rtlpriv, REG_CR+2) & 0x3; + val[0] = rtl_read_byte(rtlpriv, MSR) & 0x3; break; case HW_VAR_SLOT_TIME: *((u8 *)(val)) = mac->slot_time; @@ -2178,7 +2178,7 @@ static int _rtl8821ae_set_media_status(struct ieee80211_hw *hw, return 1; } - rtl_write_byte(rtlpriv, (MSR), bt_msr); + rtl_write_byte(rtlpriv, MSR, bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); if ((bt_msr & 0xfc) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); From 8badb50cfab6d433622dbfd5a90b6adf27333107 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:46 +0100 Subject: [PATCH 329/567] ath9k_htc: add new WMI_REG_RMW_CMDID command Since usb bus add extra delay on each request, a command with read + write requests is too expensive. We can dramtically reduce usb load by moving this command to firmware. In my tests, this patch will reduce channel scan time for about 5-10 seconds. Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath.h | 3 + drivers/net/wireless/ath/ath9k/htc.h | 5 + drivers/net/wireless/ath/ath9k/htc_drv_init.c | 142 +++++++++++++++++- drivers/net/wireless/ath/ath9k/hw.h | 12 ++ drivers/net/wireless/ath/ath9k/wmi.c | 3 + drivers/net/wireless/ath/ath9k/wmi.h | 16 ++ 6 files changed, 175 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 1eebe2ea3dfb..7e9481099a8e 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -131,6 +131,9 @@ struct ath_ops { void (*enable_write_buffer)(void *); void (*write_flush) (void *); u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr); + void (*enable_rmw_buffer)(void *); + void (*rmw_flush) (void *); + }; struct ath_common; diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 300d3671d0ef..e82a0d4ce23f 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -444,6 +444,10 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) #define OP_BT_SCAN BIT(4) #define OP_TSF_RESET BIT(6) +enum htc_op_flags { + HTC_FWFLAG_NO_RMW, +}; + struct ath9k_htc_priv { struct device *dev; struct ieee80211_hw *hw; @@ -482,6 +486,7 @@ struct ath9k_htc_priv { bool reconfig_beacon; unsigned int rxfilter; unsigned long op_flags; + unsigned long fw_flags; struct ath9k_hw_cal_data caldata; struct ath_spec_scan_priv spec_priv; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index fd229409f676..d7beefe60683 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -376,15 +376,137 @@ static void ath9k_regwrite_flush(void *hw_priv) mutex_unlock(&priv->wmi->multi_write_mutex); } +static void ath9k_reg_rmw_buffer(void *hw_priv, + u32 reg_offset, u32 set, u32 clr) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + u32 rsp_status; + int r; + + mutex_lock(&priv->wmi->multi_rmw_mutex); + + /* Store the register/value */ + priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].reg = + cpu_to_be32(reg_offset); + priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].set = + cpu_to_be32(set); + priv->wmi->multi_rmw[priv->wmi->multi_rmw_idx].clr = + cpu_to_be32(clr); + + priv->wmi->multi_rmw_idx++; + + /* If the buffer is full, send it out. */ + if (priv->wmi->multi_rmw_idx == MAX_RMW_CMD_NUMBER) { + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID, + (u8 *) &priv->wmi->multi_rmw, + sizeof(struct register_write) * priv->wmi->multi_rmw_idx, + (u8 *) &rsp_status, sizeof(rsp_status), + 100); + if (unlikely(r)) { + ath_dbg(common, WMI, + "REGISTER RMW FAILED, multi len: %d\n", + priv->wmi->multi_rmw_idx); + } + priv->wmi->multi_rmw_idx = 0; + } + + mutex_unlock(&priv->wmi->multi_rmw_mutex); +} + +static void ath9k_reg_rmw_flush(void *hw_priv) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + u32 rsp_status; + int r; + + if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) + return; + + atomic_dec(&priv->wmi->m_rmw_cnt); + + mutex_lock(&priv->wmi->multi_rmw_mutex); + + if (priv->wmi->multi_rmw_idx) { + r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID, + (u8 *) &priv->wmi->multi_rmw, + sizeof(struct register_rmw) * priv->wmi->multi_rmw_idx, + (u8 *) &rsp_status, sizeof(rsp_status), + 100); + if (unlikely(r)) { + ath_dbg(common, WMI, + "REGISTER RMW FAILED, multi len: %d\n", + priv->wmi->multi_rmw_idx); + } + priv->wmi->multi_rmw_idx = 0; + } + + mutex_unlock(&priv->wmi->multi_rmw_mutex); +} + +static void ath9k_enable_rmw_buffer(void *hw_priv) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + + if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) + return; + + atomic_inc(&priv->wmi->m_rmw_cnt); +} + +static u32 ath9k_reg_rmw_single(void *hw_priv, + u32 reg_offset, u32 set, u32 clr) +{ + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; + struct register_rmw buf, buf_ret; + int ret; + u32 val = 0; + + buf.reg = cpu_to_be32(reg_offset); + buf.set = cpu_to_be32(set); + buf.clr = cpu_to_be32(clr); + + ret = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID, + (u8 *) &buf, sizeof(buf), + (u8 *) &buf_ret, sizeof(buf_ret), + 100); + if (unlikely(ret)) { + ath_dbg(common, WMI, "REGISTER RMW FAILED:(0x%04x, %d)\n", + reg_offset, ret); + } + return val; +} + static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) { - u32 val; + struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; - val = ath9k_regread(hw_priv, reg_offset); - val &= ~clr; - val |= set; - ath9k_regwrite(hw_priv, val, reg_offset); - return val; + if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) { + u32 val; + + val = REG_READ(ah, reg_offset); + val &= ~clr; + val |= set; + REG_WRITE(ah, reg_offset, val); + + return 0; + } + + if (atomic_read(&priv->wmi->m_rmw_cnt)) + ath9k_reg_rmw_buffer(hw_priv, reg_offset, set, clr); + else + ath9k_reg_rmw_single(hw_priv, reg_offset, set, clr); + + return 0; } static void ath_usb_read_cachesize(struct ath_common *common, int *csz) @@ -501,6 +623,8 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, ah->reg_ops.write = ath9k_regwrite; ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer; ah->reg_ops.write_flush = ath9k_regwrite_flush; + ah->reg_ops.enable_rmw_buffer = ath9k_enable_rmw_buffer; + ah->reg_ops.rmw_flush = ath9k_reg_rmw_flush; ah->reg_ops.rmw = ath9k_reg_rmw; priv->ah = ah; @@ -686,6 +810,12 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) return -EINVAL; } + if (priv->fw_version_major == 1 && priv->fw_version_minor < 4) + set_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags); + + dev_info(priv->dev, "FW RMW support: %s\n", + test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags) ? "Off" : "On"); + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index aaec9451de49..7b51d8e3696f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -100,6 +100,18 @@ (_ah)->reg_ops.write_flush((_ah)); \ } while (0) +#define ENABLE_REG_RMW_BUFFER(_ah) \ + do { \ + if ((_ah)->reg_ops.enable_rmw_buffer) \ + (_ah)->reg_ops.enable_rmw_buffer((_ah)); \ + } while (0) + +#define REG_RMW_BUFFER_FLUSH(_ah) \ + do { \ + if ((_ah)->reg_ops.rmw_flush) \ + (_ah)->reg_ops.rmw_flush((_ah)); \ + } while (0) + #define PR_EEP(_s, _val) \ do { \ len += scnprintf(buf + len, size - len, "%20s : %10d\n",\ diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 65c8894c5f81..67a2f8c88829 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -61,6 +61,8 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_REG_READ_CMDID"; case WMI_REG_WRITE_CMDID: return "WMI_REG_WRITE_CMDID"; + case WMI_REG_RMW_CMDID: + return "WMI_REG_RMW_CMDID"; case WMI_RC_STATE_CHANGE_CMDID: return "WMI_RC_STATE_CHANGE_CMDID"; case WMI_RC_RATE_UPDATE_CMDID: @@ -101,6 +103,7 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv) spin_lock_init(&wmi->event_lock); mutex_init(&wmi->op_mutex); mutex_init(&wmi->multi_write_mutex); + mutex_init(&wmi->multi_rmw_mutex); init_completion(&wmi->cmd_wait); INIT_LIST_HEAD(&wmi->pending_tx_events); tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet, diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 0db37f230018..aa84a335289a 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -112,6 +112,7 @@ enum wmi_cmd_id { WMI_TX_STATS_CMDID, WMI_RX_STATS_CMDID, WMI_BITRATE_MASK_CMDID, + WMI_REG_RMW_CMDID, }; enum wmi_event_id { @@ -125,12 +126,19 @@ enum wmi_event_id { }; #define MAX_CMD_NUMBER 62 +#define MAX_RMW_CMD_NUMBER 15 struct register_write { __be32 reg; __be32 val; }; +struct register_rmw { + __be32 reg; + __be32 set; + __be32 clr; +} __packed; + struct ath9k_htc_tx_event { int count; struct __wmi_event_txstatus txs; @@ -156,10 +164,18 @@ struct wmi { spinlock_t wmi_lock; + /* multi write section */ atomic_t mwrite_cnt; struct register_write multi_write[MAX_CMD_NUMBER]; u32 multi_write_idx; struct mutex multi_write_mutex; + + /* multi rmw section */ + atomic_t m_rmw_cnt; + struct register_rmw multi_rmw[MAX_RMW_CMD_NUMBER]; + u32 multi_rmw_idx; + struct mutex multi_rmw_mutex; + }; struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv); From 8d1cbdef8a640536d0af1ee57930f671127329d5 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:47 +0100 Subject: [PATCH 330/567] ath9k: ar9271_hw_pa_cal - use defs instead of magin numbers This function uses mixed styles for register names/numbers which is make harder reading and optimisation. Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 42190b67c671..4576b99dd0cc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -430,22 +430,22 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) u32 regVal; unsigned int i; u32 regList[][2] = { - { 0x786c, 0 }, - { 0x7854, 0 }, - { 0x7820, 0 }, - { 0x7824, 0 }, - { 0x7868, 0 }, - { 0x783c, 0 }, - { 0x7838, 0 } , - { 0x7828, 0 } , + { AR9285_AN_TOP3, 0 }, + { AR9285_AN_RXTXBB1, 0 }, + { AR9285_AN_RF2G1, 0 }, + { AR9285_AN_RF2G2, 0 }, + { AR9285_AN_TOP2, 0 }, + { AR9285_AN_RF2G8, 0 }, + { AR9285_AN_RF2G7, 0 } , + { AR9285_AN_RF2G3, 0 } , }; for (i = 0; i < ARRAY_SIZE(regList); i++) regList[i][1] = REG_READ(ah, regList[i][0]); - regVal = REG_READ(ah, 0x7834); + regVal = REG_READ(ah, AR9285_AN_RF2G6); regVal &= (~(0x1)); - REG_WRITE(ah, 0x7834, regVal); + REG_WRITE(ah, AR9285_AN_RF2G6, regVal); regVal = REG_READ(ah, 0x9808); regVal |= (0x1 << 27); REG_WRITE(ah, 0x9808, regVal); @@ -477,7 +477,7 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) * does not matter since we turn it off */ REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); - + /* 7828, b0-11, ccom=fff */ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); /* Set: @@ -490,15 +490,16 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) /* find off_6_1; */ for (i = 6; i > 0; i--) { - regVal = REG_READ(ah, 0x7834); + regVal = REG_READ(ah, AR9285_AN_RF2G6); regVal |= (1 << (20 + i)); - REG_WRITE(ah, 0x7834, regVal); + REG_WRITE(ah, AR9285_AN_RF2G6, regVal); udelay(1); /* regVal = REG_READ(ah, 0x7834); */ regVal &= (~(0x1 << (20 + i))); - regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9) + regVal |= (MS(REG_READ(ah, AR9285_AN_RF2G9), + AR9285_AN_RXTXBB1_SPARE9) << (20 + i)); - REG_WRITE(ah, 0x7834, regVal); + REG_WRITE(ah, AR9285_AN_RF2G6, regVal); } regVal = (regVal >> 20) & 0x7f; @@ -517,9 +518,9 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) ENABLE_REGWRITE_BUFFER(ah); - regVal = REG_READ(ah, 0x7834); + regVal = REG_READ(ah, AR_AN_RF2G1_CH1); regVal |= 0x1; - REG_WRITE(ah, 0x7834, regVal); + REG_WRITE(ah, AR_AN_RF2G1_CH1, regVal); regVal = REG_READ(ah, 0x9808); regVal &= (~(0x1 << 27)); REG_WRITE(ah, 0x9808, regVal); From 0202a553f59b7d0df4db56d0ce64c702afea64d0 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:48 +0100 Subject: [PATCH 331/567] ath9k: ar9271_hw_pa_cal: use proper makroses. Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 4576b99dd0cc..8d24a73ca9f2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -443,33 +443,30 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) for (i = 0; i < ARRAY_SIZE(regList); i++) regList[i][1] = REG_READ(ah, regList[i][0]); - regVal = REG_READ(ah, AR9285_AN_RF2G6); - regVal &= (~(0x1)); - REG_WRITE(ah, AR9285_AN_RF2G6, regVal); - regVal = REG_READ(ah, 0x9808); - regVal |= (0x1 << 27); - REG_WRITE(ah, 0x9808, regVal); - + /* 7834, b1=0 */ + REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0); + /* 9808, b27=1 */ + REG_SET_BIT(ah, 0x9808, 1 << 27); /* 786c,b23,1, pwddac=1 */ - REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + REG_SET_BIT(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC); /* 7854, b5,1, pdrxtxbb=1 */ - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1); /* 7854, b7,1, pdv2i=1 */ - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I); /* 7854, b8,1, pddacinterface=1 */ - REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF); /* 7824,b12,0, offcal=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL); /* 7838, b1,0, pwddb=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB); /* 7820,b11,0, enpacal=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL); /* 7820,b25,1, pdpadrv1=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1); /* 7820,b24,0, pdpadrv2=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2); /* 7820,b23,0, pdpaout=0 */ - REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT); /* 783c,b14-16,7, padrvgn2tab_0=7 */ REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); /* @@ -516,15 +513,13 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) ah->pacal_info.prev_offset = regVal; } + + /* 7834, b1=1 */ + REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0); + /* 9808, b27=0 */ + REG_CLR_BIT(ah, 0x9808, 1 << 27); + ENABLE_REGWRITE_BUFFER(ah); - - regVal = REG_READ(ah, AR_AN_RF2G1_CH1); - regVal |= 0x1; - REG_WRITE(ah, AR_AN_RF2G1_CH1, regVal); - regVal = REG_READ(ah, 0x9808); - regVal &= (~(0x1 << 27)); - REG_WRITE(ah, 0x9808, regVal); - for (i = 0; i < ARRAY_SIZE(regList); i++) REG_WRITE(ah, regList[i][0], regList[i][1]); From 93442c85d23a1e86c693de4b00915168a4a99d92 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:49 +0100 Subject: [PATCH 332/567] ath9k: ar9271_hw_pa_cal: use RMW buffer Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 8d24a73ca9f2..62a23149556d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -436,13 +436,14 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) { AR9285_AN_RF2G2, 0 }, { AR9285_AN_TOP2, 0 }, { AR9285_AN_RF2G8, 0 }, - { AR9285_AN_RF2G7, 0 } , - { AR9285_AN_RF2G3, 0 } , + { AR9285_AN_RF2G7, 0 }, + { AR9285_AN_RF2G3, 0 }, }; for (i = 0; i < ARRAY_SIZE(regList); i++) regList[i][1] = REG_READ(ah, regList[i][0]); + ENABLE_REG_RMW_BUFFER(ah); /* 7834, b1=0 */ REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0); /* 9808, b27=1 */ @@ -476,6 +477,7 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); /* 7828, b0-11, ccom=fff */ REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); + REG_RMW_BUFFER_FLUSH(ah); /* Set: * localmode=1,bmode=1,bmoderxtx=1,synthon=1, @@ -514,10 +516,12 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) } + ENABLE_REG_RMW_BUFFER(ah); /* 7834, b1=1 */ REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0); /* 9808, b27=0 */ REG_CLR_BIT(ah, 0x9808, 1 << 27); + REG_RMW_BUFFER_FLUSH(ah); ENABLE_REGWRITE_BUFFER(ah); for (i = 0; i < ARRAY_SIZE(regList); i++) From d55ce0a6f98305c75c4581d7a19be622bb95179a Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:50 +0100 Subject: [PATCH 333/567] ath9k: add multi_read to be compatible with ath9k_htc Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index b889a8fc1982..f8d11efa7b0f 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -141,6 +141,16 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) return val; } +static void ath9k_multi_ioread32(void *hw_priv, u32 *addr, + u32 *val, u16 count) +{ + int i; + + for (i = 0; i < count; i++) + val[i] = ath9k_ioread32(hw_priv, addr[i]); +} + + static unsigned int __ath9k_reg_rmw(struct ath_softc *sc, u32 reg_offset, u32 set, u32 clr) { @@ -537,6 +547,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ah->hw = sc->hw; ah->hw_version.devid = devid; ah->reg_ops.read = ath9k_ioread32; + ah->reg_ops.multi_read = ath9k_multi_ioread32; ah->reg_ops.write = ath9k_iowrite32; ah->reg_ops.rmw = ath9k_reg_rmw; pCap = &ah->caps; From a57cb45a0a051601e14f81436b62750cc4f478c3 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:51 +0100 Subject: [PATCH 334/567] ath9k: add new function ath9k_hw_read_array REG_READ generate most overhead on usb bus. It send and read micro packages and reduce usb bandwidth. To reduce this overhead we should read in batches. Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 30 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 3 +++ 2 files changed, 33 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index cc8bea8a957f..6d5b4bc8ab48 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -121,6 +121,36 @@ void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array, REGWRITE_BUFFER_FLUSH(ah); } +void ath9k_hw_read_array(struct ath_hw *ah, u32 array[][2], int size) +{ + u32 *tmp_reg_list, *tmp_data; + int i; + + tmp_reg_list = kmalloc(size * sizeof(u32), GFP_KERNEL); + if (!tmp_reg_list) { + dev_err(ah->dev, "%s: tmp_reg_list: alloc filed\n", __func__); + return; + } + + tmp_data = kmalloc(size * sizeof(u32), GFP_KERNEL); + if (!tmp_data) { + dev_err(ah->dev, "%s tmp_data: alloc filed\n", __func__); + goto error_tmp_data; + } + + for (i = 0; i < size; i++) + tmp_reg_list[i] = array[i][0]; + + REG_READ_MULTI(ah, tmp_reg_list, tmp_data, size); + + for (i = 0; i < size; i++) + array[i][1] = tmp_data[i]; + + kfree(tmp_data); +error_tmp_data: + kfree(tmp_reg_list); +} + u32 ath9k_hw_reverse_bits(u32 val, u32 n) { u32 retval; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 7b51d8e3696f..92fab1a54697 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -138,6 +138,8 @@ #define REG_WRITE_ARRAY(iniarray, column, regWr) \ ath9k_hw_write_array(ah, iniarray, column, &(regWr)) +#define REG_READ_ARRAY(ah, array, size) \ + ath9k_hw_read_array(ah, array, size) #define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 #define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 @@ -1030,6 +1032,7 @@ void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan, bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); void ath9k_hw_write_array(struct ath_hw *ah, const struct ar5416IniArray *array, int column, unsigned int *writecnt); +void ath9k_hw_read_array(struct ath_hw *ah, u32 array[][2], int size); u32 ath9k_hw_reverse_bits(u32 val, u32 n); u16 ath9k_hw_computetxtime(struct ath_hw *ah, u8 phy, int kbps, From 03822782e8293db08f28507b85588656ff02f354 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:52 +0100 Subject: [PATCH 335/567] ath9k: ar9271_hw_pa_cal: use REG_READ_ARRAY insted of reading each register separatly and waste 4ms on each operation, we can use one shot read. Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 62a23149556d..50fcd343c41a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -440,8 +440,7 @@ static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) { AR9285_AN_RF2G3, 0 }, }; - for (i = 0; i < ARRAY_SIZE(regList); i++) - regList[i][1] = REG_READ(ah, regList[i][0]); + REG_READ_ARRAY(ah, regList, ARRAY_SIZE(regList)); ENABLE_REG_RMW_BUFFER(ah); /* 7834, b1=0 */ From 9c05babd933e1c4a811867c4d5aa170d788eeaf9 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:53 +0100 Subject: [PATCH 336/567] ath9k: use one shot read in ath9k_hw_update_mibstats this will reduce some overhead on usb bus. Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ani.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index ca01d17d130f..25e45e4d1a60 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -107,11 +107,21 @@ static const struct ani_cck_level_entry cck_level_table[] = { static void ath9k_hw_update_mibstats(struct ath_hw *ah, struct ath9k_mib_stats *stats) { - stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); - stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); - stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); - stats->rts_good += REG_READ(ah, AR_RTS_OK); - stats->beacons += REG_READ(ah, AR_BEACON_CNT); + u32 addr[5] = {AR_RTS_OK, AR_RTS_FAIL, AR_ACK_FAIL, + AR_FCS_FAIL, AR_BEACON_CNT}; + u32 data[5]; + + REG_READ_MULTI(ah, &addr[0], &data[0], 5); + /* AR_RTS_OK */ + stats->rts_good += data[0]; + /* AR_RTS_FAIL */ + stats->rts_bad += data[1]; + /* AR_ACK_FAIL */ + stats->ackrcv_bad += data[2]; + /* AR_FCS_FAIL */ + stats->fcs_bad += data[3]; + /* AR_BEACON_CNT */ + stats->beacons += data[4]; } static void ath9k_ani_restart(struct ath_hw *ah) From 9830ba6c9ad0165f4aa1025bcfc8e75d76083907 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:54 +0100 Subject: [PATCH 337/567] ath9k: ath9k_hw_loadnf: use REG_RMW Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/calib.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index e200a6e3aca5..3e2e24e4843f 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -238,7 +238,6 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath9k_nfcal_hist *h = NULL; unsigned i, j; - int32_t val; u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; struct ath_common *common = ath9k_hw_common(ah); s16 default_nf = ath9k_hw_get_default_nf(ah, chan); @@ -246,6 +245,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) if (ah->caldata) h = ah->caldata->nfCalHist; + ENABLE_REG_RMW_BUFFER(ah); for (i = 0; i < NUM_NF_READINGS; i++) { if (chainmask & (1 << i)) { s16 nfval; @@ -258,10 +258,8 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) else nfval = default_nf; - val = REG_READ(ah, ah->nf_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) nfval << 1) & 0x1ff); - REG_WRITE(ah, ah->nf_regs[i], val); + REG_RMW(ah, ah->nf_regs[i], + (((u32) nfval << 1) & 0x1ff), 0x1ff); } } @@ -274,6 +272,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + REG_RMW_BUFFER_FLUSH(ah); /* * Wait for load to complete, should be fast, a few 10s of us. @@ -309,19 +308,17 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) * by the median we just loaded. This will be initial (and max) value * of next noise floor calibration the baseband does. */ - ENABLE_REGWRITE_BUFFER(ah); + ENABLE_REG_RMW_BUFFER(ah); for (i = 0; i < NUM_NF_READINGS; i++) { if (chainmask & (1 << i)) { if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan)) continue; - val = REG_READ(ah, ah->nf_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (-50) << 1) & 0x1ff); - REG_WRITE(ah, ah->nf_regs[i], val); + REG_RMW(ah, ah->nf_regs[i], + (((u32) (-50) << 1) & 0x1ff), 0x1ff); } } - REGWRITE_BUFFER_FLUSH(ah); + REG_RMW_BUFFER_FLUSH(ah); return 0; } From 3df5dd901d1a4eddcb386d6a5321ef8a61edf376 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:55 +0100 Subject: [PATCH 338/567] ath9k: write buffer related optimisation in ar5008_hw_set_channel_regs Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index f273427fdd29..6c23d279525f 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -681,12 +681,13 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah, phymode |= AR_PHY_FC_DYN2040_PRI_CH; } + ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_PHY_TURBO, phymode); + /* This function do only REG_WRITE, so + * we can include it to REGWRITE_BUFFER. */ ath9k_hw_set11nmac2040(ah, chan); - ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); From 10e03ef6b4669c56d5d6858d80866bfa9bb2dc57 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:56 +0100 Subject: [PATCH 339/567] ath9k: ath9k_hw_set_4k_power_cal_tabl: use rmw buffer Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index e5a78d4fd66e..fc54fc71a2d3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -389,6 +389,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, } } + ENABLE_REG_RMW_BUFFER(ah); REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, (numXpdGain - 1) & 0x3); REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, @@ -396,6 +397,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, xpdGainValues[1]); REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0); + REG_RMW_BUFFER_FLUSH(ah); for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { regChainOffset = i * 0x1000; From 7b37e0d4db038d37bbb88a4c8ea2b828707cbd12 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:57 +0100 Subject: [PATCH 340/567] ath9k: use rmw buffer in ath9k_hw_set_operating_mode and ath9k_hw_reset Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/hw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6d5b4bc8ab48..1d9ad5bfe0c8 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1230,6 +1230,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC; u32 set = AR_STA_ID1_KSRCH_MODE; + ENABLE_REG_RMW_BUFFER(ah); switch (opmode) { case NL80211_IFTYPE_ADHOC: if (!AR_SREV_9340_13(ah)) { @@ -1251,6 +1252,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) break; } REG_RMW(ah, AR_STA_ID1, set, mask); + REG_RMW_BUFFER_FLUSH(ah); } void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, @@ -1963,6 +1965,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (!ath9k_hw_mci_is_enabled(ah)) REG_WRITE(ah, AR_OBS, 8); + ENABLE_REG_RMW_BUFFER(ah); if (ah->config.rx_intr_mitigation) { REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, ah->config.rimt_last); REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, ah->config.rimt_first); @@ -1972,6 +1975,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300); REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750); } + REG_RMW_BUFFER_FLUSH(ah); ath9k_hw_init_bb(ah, chan); From 18d6616f1bb14a29b14c6b0d4cde7fd527579b72 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:58 +0100 Subject: [PATCH 341/567] ath9k: ath9k_hw_4k_set_board_values: use rmw buffer Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index fc54fc71a2d3..060056262410 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -1082,6 +1082,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25); pwrctrl = mask * bb_desired_scale; clr = mask * 0x1f; + ENABLE_REG_RMW_BUFFER(ah); REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr); REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr); REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr); @@ -1096,6 +1097,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, clr = mask * 0x1f; REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr); REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr); + REG_RMW_BUFFER_FLUSH(ah); } } From 2028523b6dcead43ddbbe4dc14f59f07b6238d34 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:29:59 +0100 Subject: [PATCH 342/567] ath9k: ath9k_hw_analog_shift_rmw: use REG_RMW use REG_RMW in ath9k_hw_analog_shift_rmw. It will double execution speed on usb bus. Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index 971d770722cf..cc81482c934d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -27,12 +27,7 @@ void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, u32 shift, u32 val) { - u32 regVal; - - regVal = REG_READ(ah, reg) & ~mask; - regVal |= (val << shift) & mask; - - REG_WRITE(ah, reg, regVal); + REG_RMW(ah, reg, ((val << shift) & mask), mask); if (ah->config.analog_shiftreg) udelay(100); From ad10e0d65030d39c218e96f7e5269b301913b477 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:30:00 +0100 Subject: [PATCH 343/567] ath9k: ath9k_hw_4k_set_board_values: use rmw buffer it will reduce exution time from 14ms to 2ms on ar9271 Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 060056262410..291c1d14403c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -930,6 +930,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, } } + ENABLE_REG_RMW_BUFFER(ah); if (AR_SREV_9271(ah)) { ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, @@ -1034,6 +1035,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, AR9285_AN_RF2G4_DB2_4_S, db2[4]); } + REG_RMW_BUFFER_FLUSH(ah); REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, From 2dfc0247f0ff755296ab72ab3ddb8309fb35c660 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:30:01 +0100 Subject: [PATCH 344/567] ath9k: use REG_RMW and rmw buffer in ath9k_hw_4k_set_gain it is possible to reduce time needed for this function by rplacing REG_WRITE with REG_RMW (plus dummy 0) and putt all commands in same buffer. Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 291c1d14403c..38dc965605d8 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -772,15 +772,14 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, struct ar5416_eeprom_4k *eep, u8 txRxAttenLocal) { - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, - pModal->antCtrlChain[0]); + ENABLE_REG_RMW_BUFFER(ah); + REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, + pModal->antCtrlChain[0], 0); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), - (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + REG_RMW(ah, AR_PHY_TIMING_CTRL4(0), + SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF), + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF); if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= AR5416_EEP_MINOR_VER_3) { @@ -819,6 +818,7 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + REG_RMW_BUFFER_FLUSH(ah); } /* From b1c1a26461a79a289e08d0c04bf8520e305bf05d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:30:02 +0100 Subject: [PATCH 345/567] ath9k: use REG_RMW and rmw buffer in ath9k_hw_4k_set_board_values replace REG_WRITE to REG_RMW and place every thing in one RMW buffer. Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 38dc965605d8..4773da6dc6f2 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -1037,17 +1037,17 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, } REG_RMW_BUFFER_FLUSH(ah); - + ENABLE_REG_RMW_BUFFER(ah); REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, pModal->switchSettling); REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | - SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + REG_RMW(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON), 0); REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); @@ -1076,6 +1076,8 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, pModal->swSettleHt40); } + REG_RMW_BUFFER_FLUSH(ah); + bb_desired_scale = (pModal->bb_scale_smrt_antenna & EEP_4K_BB_DESIRED_SCALE_MASK); if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) { From eaa4059d56fdbeb1633c94e82d54849688d96777 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 22 Mar 2015 19:30:03 +0100 Subject: [PATCH 346/567] ath9k: use REG_RMW and rmw buffer in ath9k_hw_def_set_gain Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/eeprom_def.c | 34 +++++++++------------ 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 098059039351..056f516bf017 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -466,6 +466,7 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah, struct ar5416_eeprom_def *eep, u8 txRxAttenLocal, int regChainOffset, int i) { + ENABLE_REG_RMW_BUFFER(ah); if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { txRxAttenLocal = pModal->txRxAttenCh[i]; @@ -483,16 +484,12 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah, AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[i]); } else { - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) - | SM(pModal-> bswMargin[i], - AR_PHY_GAIN_2GHZ_BSW_MARGIN)); - REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) - | SM(pModal->bswAtten[i], - AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + SM(pModal-> bswMargin[i], AR_PHY_GAIN_2GHZ_BSW_MARGIN), + AR_PHY_GAIN_2GHZ_BSW_MARGIN); + REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + SM(pModal->bswAtten[i], AR_PHY_GAIN_2GHZ_BSW_ATTEN), + AR_PHY_GAIN_2GHZ_BSW_ATTEN); } } @@ -504,17 +501,14 @@ static void ath9k_hw_def_set_gain(struct ath_hw *ah, AR_PHY_RXGAIN + regChainOffset, AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); } else { - REG_WRITE(ah, - AR_PHY_RXGAIN + regChainOffset, - (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & - ~AR_PHY_RXGAIN_TXRX_ATTEN) - | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + regChainOffset, - (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & - ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | - SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + REG_RMW(ah, AR_PHY_RXGAIN + regChainOffset, + SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN), + AR_PHY_RXGAIN_TXRX_ATTEN); + REG_RMW(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN), + AR_PHY_GAIN_2GHZ_RXTX_MARGIN); } + REG_RMW_BUFFER_FLUSH(ah); } static void ath9k_hw_def_set_board_values(struct ath_hw *ah, From 2f5872b60146eadf74b8d349a3596f5aaf687401 Mon Sep 17 00:00:00 2001 From: Maithili Hinge Date: Sun, 22 Mar 2015 23:01:25 -0700 Subject: [PATCH 347/567] mwifiex: Fix issue in the SDIO reset path of mwifiex. SDIO reset was not happening properly on mwifiex as cancel_work_sync in mwifiex_sdio_remove used to kill the calling work function itself. Due to this, the interface was not getting removed and card was not getting added again. Reset work function has been made independent of adapter variable and cancel_work_sync has been moved to cleanup function. Signed-off-by: Maithili Hinge Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.c | 3 --- drivers/net/wireless/mwifiex/main.h | 2 -- drivers/net/wireless/mwifiex/pcie.c | 21 ++++++++-------- drivers/net/wireless/mwifiex/sdio.c | 38 ++++++++++++++--------------- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index eaaacecbdef6..a3c2bb122c09 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -1149,9 +1149,6 @@ mwifiex_add_card(void *card, struct semaphore *sem, INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue); } - if (adapter->if_ops.iface_work) - INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work); - /* Register the device. Fill up the private data structure with relevant information from the card. */ if (adapter->if_ops.register_dev(adapter)) { diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 842fa0beb188..b97b85b7f2a1 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -898,8 +898,6 @@ struct mwifiex_adapter { bool ext_scan; u8 fw_api_ver; u8 key_api_major_ver, key_api_minor_ver; - struct work_struct iface_work; - unsigned long iface_work_flags; struct memory_type_mapping *mem_type_mapping_tbl; u8 num_mem_types; u8 curr_mem_idx; diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index b31c9a70ffaa..bcc7751d883c 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -234,8 +234,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev) if (!adapter || !adapter->priv_num) return; - cancel_work_sync(&adapter->iface_work); - if (user_rmmod) { #ifdef CONFIG_PM_SLEEP if (adapter->is_suspended) @@ -2373,25 +2371,26 @@ done: adapter->curr_mem_idx = 0; } +static unsigned long iface_work_flags; +static struct mwifiex_adapter *save_adapter; static void mwifiex_pcie_work(struct work_struct *work) { - struct mwifiex_adapter *adapter = - container_of(work, struct mwifiex_adapter, iface_work); - if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP, - &adapter->iface_work_flags)) - mwifiex_pcie_fw_dump_work(adapter); + &iface_work_flags)) + mwifiex_pcie_fw_dump_work(save_adapter); } +static DECLARE_WORK(pcie_work, mwifiex_pcie_work); /* This function dumps FW information */ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) { - if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags)) + save_adapter = adapter; + if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags)) return; - set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags); + set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags); - schedule_work(&adapter->iface_work); + schedule_work(&pcie_work); } /* @@ -2619,7 +2618,6 @@ static struct mwifiex_if_ops pcie_ops = { .init_fw_port = mwifiex_pcie_init_fw_port, .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, .fw_dump = mwifiex_pcie_fw_dump, - .iface_work = mwifiex_pcie_work, }; /* @@ -2665,6 +2663,7 @@ static void mwifiex_pcie_cleanup_module(void) /* Set the flag as user is removing this module. */ user_rmmod = 1; + cancel_work_sync(&pcie_work); pci_unregister_driver(&mwifiex_pcie); } diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 4f08c58989af..6af7a08253f2 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -47,6 +47,7 @@ static u8 user_rmmod; static struct mwifiex_if_ops sdio_ops; +static unsigned long iface_work_flags; static struct semaphore add_remove_card_sem; @@ -200,8 +201,6 @@ mwifiex_sdio_remove(struct sdio_func *func) if (!adapter || !adapter->priv_num) return; - cancel_work_sync(&adapter->iface_work); - if (user_rmmod) { if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); @@ -2040,6 +2039,7 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) port, card->mp_data_port_mask); } +static struct mwifiex_adapter *save_adapter; static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; @@ -2108,10 +2108,8 @@ rdwr_status mwifiex_sdio_rdwr_firmware(struct mwifiex_adapter *adapter, } /* This function dump firmware memory to file */ -static void mwifiex_sdio_fw_dump_work(struct work_struct *work) +static void mwifiex_sdio_fw_dump_work(struct mwifiex_adapter *adapter) { - struct mwifiex_adapter *adapter = - container_of(work, struct mwifiex_adapter, iface_work); struct sdio_mmc_card *card = adapter->card; int ret = 0; unsigned int reg, reg_start, reg_end; @@ -2233,36 +2231,36 @@ done: static void mwifiex_sdio_work(struct work_struct *work) { - struct mwifiex_adapter *adapter = - container_of(work, struct mwifiex_adapter, iface_work); - - if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, - &adapter->iface_work_flags)) - mwifiex_sdio_card_reset_work(adapter); if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP, - &adapter->iface_work_flags)) - mwifiex_sdio_fw_dump_work(work); + &iface_work_flags)) + mwifiex_sdio_fw_dump_work(save_adapter); + if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, + &iface_work_flags)) + mwifiex_sdio_card_reset_work(save_adapter); } +static DECLARE_WORK(sdio_work, mwifiex_sdio_work); /* This function resets the card */ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) { - if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags)) + save_adapter = adapter; + if (test_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &iface_work_flags)) return; - set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &adapter->iface_work_flags); + set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &iface_work_flags); - schedule_work(&adapter->iface_work); + schedule_work(&sdio_work); } /* This function dumps FW information */ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter) { - if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags)) + save_adapter = adapter; + if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags)) return; - set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags); - schedule_work(&adapter->iface_work); + set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &iface_work_flags); + schedule_work(&sdio_work); } /* Function to dump SDIO function registers and SDIO scratch registers in case @@ -2378,7 +2376,6 @@ static struct mwifiex_if_ops sdio_ops = { .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, .event_complete = mwifiex_sdio_event_complete, .card_reset = mwifiex_sdio_card_reset, - .iface_work = mwifiex_sdio_work, .fw_dump = mwifiex_sdio_fw_dump, .reg_dump = mwifiex_sdio_reg_dump, .deaggr_pkt = mwifiex_deaggr_sdio_pkt, @@ -2418,6 +2415,7 @@ mwifiex_sdio_cleanup_module(void) /* Set the flag as user is removing this module. */ user_rmmod = 1; + cancel_work_sync(&sdio_work); sdio_unregister_driver(&mwifiex_sdio); } From 2d7defb07bbee286537457e5eab534bac01d126a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 23 Mar 2015 12:35:51 +0300 Subject: [PATCH 348/567] mwifiex: remove an unneede NULL check in mwifiex_init_adapter() "adapter->sleep_cfm" is always non-NULL at this point. Static checkers complain that we already dereference it at the start of the function when we do: skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm)); Signed-off-by: Dan Carpenter Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 6936de8c8a94..e12192f5cfad 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -266,18 +266,15 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) mwifiex_wmm_init(adapter); - if (adapter->sleep_cfm) { - sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *) - adapter->sleep_cfm->data; - memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len); - sleep_cfm_buf->command = - cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); - sleep_cfm_buf->size = - cpu_to_le16(adapter->sleep_cfm->len); - sleep_cfm_buf->result = 0; - sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM); - sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED); - } + sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *) + adapter->sleep_cfm->data; + memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len); + sleep_cfm_buf->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH); + sleep_cfm_buf->size = cpu_to_le16(adapter->sleep_cfm->len); + sleep_cfm_buf->result = 0; + sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM); + sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED); + memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params)); memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period)); adapter->tx_lock_flag = false; From 5ff46f7923b87f6cc5d5d66df08c9b6379a0461e Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 23 Mar 2015 19:50:55 +0530 Subject: [PATCH 349/567] mwifiex: stop command path in suspend handler Cancel all pending commands including scan commands and stop CAC during cfg80211 suspend handler. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index fc3bbe77eb18..eab110b1f97b 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2942,15 +2942,23 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_ds_hs_cfg hs_cfg; - int ret = 0; - struct mwifiex_private *priv = - mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + int i, ret = 0; + struct mwifiex_private *priv; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + mwifiex_abort_cac(priv); + } + + mwifiex_cancel_all_pending_cmd(adapter); if (!wowlan) { dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n"); return 0; } + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + if (!priv->media_connected) { dev_warn(adapter->dev, "Can not configure WOWLAN in disconnected state\n"); From 4acaf048b1d27cb6e1b214d370ed993bb2aac664 Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Mon, 23 Mar 2015 19:50:56 +0530 Subject: [PATCH 350/567] mwifiex: recover from skb allocation failures during RX This patch adds recovery mechanism for SDIO RX during SKB allocation failures. For allocation failures during multiport aggregation, we skip and drop RX packets. For single port read case, we will use preallocated card->mpa_rx.buf to complete cmd53 read. Now we terminate SDIO operations only upon cmd53 failures. CC: James Cameron Signed-off-by: Zhaoyang Liu Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 42 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 6af7a08253f2..d10320f89bc1 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -1317,10 +1317,14 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, skb_deaggr = mwifiex_alloc_dma_align_buf(len_arr[pind], GFP_KERNEL | GFP_DMA); - if (!skb_deaggr) - goto error; + if (!skb_deaggr) { + dev_err(adapter->dev, "skb allocation failure drop pkt len=%d type=%d\n", + pkt_len, pkt_type); + curr_ptr += len_arr[pind]; + continue; + } + skb_put(skb_deaggr, len_arr[pind]); - card->mpa_rx.skb_arr[pind] = skb_deaggr; if ((pkt_type == MWIFIEX_TYPE_DATA || (pkt_type == MWIFIEX_TYPE_AGGR_DATA && @@ -1335,7 +1339,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, mwifiex_decode_rx_packet(adapter, skb_deaggr, pkt_type); } else { - dev_err(adapter->dev, "wrong aggr pkt:\t" + dev_err(adapter->dev, " drop wrong aggr pkt:\t" "sdio_single_port_rx_aggr=%d\t" "type=%d len=%d max_len=%d\n", adapter->sdio_rx_aggr_enable, @@ -1352,9 +1356,18 @@ rx_curr_single: if (f_do_rx_cur) { dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", port, rx_len); + skb = mwifiex_alloc_dma_align_buf(rx_len, GFP_KERNEL | GFP_DMA); - if (!skb) - goto error; + if (!skb) { + dev_err(adapter->dev, "single skb allocated fail,\t" + "drop pkt port=%d len=%d\n", port, rx_len); + if (mwifiex_sdio_card_to_host(adapter, &pkt_type, + card->mpa_rx.buf, rx_len, + adapter->ioport + port)) + goto error; + return 0; + } + skb_put(skb, rx_len); if (mwifiex_sdio_card_to_host(adapter, &pkt_type, @@ -1363,10 +1376,11 @@ rx_curr_single: goto error; if (!adapter->sdio_rx_aggr_enable && pkt_type == MWIFIEX_TYPE_AGGR_DATA) { - dev_err(adapter->dev, "Wrong pkt type %d\t" - "Current SDIO RX Aggr not enabled\n", + dev_err(adapter->dev, "drop wrong pkt type %d\t" + "current SDIO RX Aggr not enabled\n", pkt_type); - goto error; + dev_kfree_skb_any(skb); + return 0; } mwifiex_decode_rx_packet(adapter, skb, pkt_type); @@ -1379,16 +1393,8 @@ rx_curr_single: return 0; error: - if (MP_RX_AGGR_IN_PROGRESS(card)) { - /* Multiport-aggregation transfer failed - cleanup */ - for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { - /* copy pkt to deaggr buf */ - skb_deaggr = card->mpa_rx.skb_arr[pind]; - if (skb_deaggr) - dev_kfree_skb_any(skb_deaggr); - } + if (MP_RX_AGGR_IN_PROGRESS(card)) MP_RX_AGGR_BUF_RESET(card); - } if (f_do_rx_cur && skb) /* Single transfer pending. Free curr buff also */ From 2f92b314f4daff2117847ac5343c54d3d041bf78 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 23 Mar 2015 18:14:10 -0500 Subject: [PATCH 351/567] rtlwifi: rtl8192cu: Add new USB ID USB ID 2001:330d is used for a D-Link DWA-131. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 90a714c189a8..6fde2507c7aa 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -377,6 +377,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/ {RTL_USB_DEVICE(0x2001, 0x3309, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/ {RTL_USB_DEVICE(0x2001, 0x330a, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/ + {RTL_USB_DEVICE(0x2001, 0x330d, rtl92cu_hal_cfg)}, /*D-Link DWA-131 */ {RTL_USB_DEVICE(0x2019, 0xab2b, rtl92cu_hal_cfg)}, /*Planex -Abocom*/ {RTL_USB_DEVICE(0x20f4, 0x624d, rtl92cu_hal_cfg)}, /*TRENDNet*/ {RTL_USB_DEVICE(0x2357, 0x0100, rtl92cu_hal_cfg)}, /*TP-Link WN8200ND*/ From 9374e7d2fdcad3c36dafc8d3effd554bc702c4b6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 26 Mar 2015 02:16:06 +0100 Subject: [PATCH 352/567] rtlwifi: rtl8192cu: Add new device ID Add new ID for ASUS N10 WiFi dongle. Signed-off-by: Marek Vasut Tested-by: Marek Vasut Cc: Larry Finger Cc: John W. Linville Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 6fde2507c7aa..23806c243a53 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -321,6 +321,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ + {RTL_USB_DEVICE(0x0b05, 0x17ba, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/ {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/ {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ From ee73c61c0af590ff2c03fb83e68a5664bd8b38d0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 27 Mar 2015 11:02:10 +0000 Subject: [PATCH 353/567] drm/i915: Skip allocating shadow batch for 0-length batches Since commit 17cabf571e50677d980e9ab2a43c5f11213003ae Author: Chris Wilson Date: Wed Jan 14 11:20:57 2015 +0000 drm/i915: Trim the command parser allocations we may then try to allocate a zero-sized object and attempt to extract its pages. Understandably this fails. Note that the real offender seems to be commit b9ffd80ed659c559152c042e74741f4f60cac691 Author: Brad Volkin Date: Thu Dec 11 12:13:10 2014 -0800 drm/i915: Use batch length instead of object size in command parser Testcase: igt/gem_exec_nop #ivb,byt,hsw Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter [cherry picked from commit 743e78c1d726d875b98ff9689cc77c4d3d5d9ae2 from drm-intel-next because 4.0 seems to be affected by this too, despite that the obvious culprit is definitely not in 4.0. Whatever, if fixes a bug. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index b773368fc62c..38a742532c4f 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1487,7 +1487,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } - if (i915_needs_cmd_parser(ring)) { + if (i915_needs_cmd_parser(ring) && args->batch_len) { batch_obj = i915_gem_execbuffer_parse(ring, &shadow_exec_entry, eb, From ca76683930a1c6acb8dd22867eca2bedaab998e3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 28 Mar 2015 18:05:44 +0100 Subject: [PATCH 354/567] dmaengine: jz4740: Define capabilities Setup the capabilities of the device/driver, so that users of the DMAengine API can query them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- drivers/dma/dma-jz4740.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c index 4527a3ebeac4..84884418fd30 100644 --- a/drivers/dma/dma-jz4740.c +++ b/drivers/dma/dma-jz4740.c @@ -511,6 +511,9 @@ static void jz4740_dma_desc_free(struct virt_dma_desc *vdesc) kfree(container_of(vdesc, struct jz4740_dma_desc, vdesc)); } +#define JZ4740_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) + static int jz4740_dma_probe(struct platform_device *pdev) { struct jz4740_dmaengine_chan *chan; @@ -548,6 +551,10 @@ static int jz4740_dma_probe(struct platform_device *pdev) dd->device_prep_dma_cyclic = jz4740_dma_prep_dma_cyclic; dd->device_config = jz4740_dma_slave_config; dd->device_terminate_all = jz4740_dma_terminate_all; + dd->src_addr_widths = JZ4740_DMA_BUSWIDTHS; + dd->dst_addr_widths = JZ4740_DMA_BUSWIDTHS; + dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; dd->dev = &pdev->dev; INIT_LIST_HEAD(&dd->channels); From 5ca9e7ce6eebec53362ff779264143860ccf68cd Mon Sep 17 00:00:00 2001 From: Petr Kulhavy Date: Fri, 27 Mar 2015 13:35:51 +0200 Subject: [PATCH 355/567] dmaengine: edma: fix memory leak when terminating running transfers If edma_terminate_all() was called while a transfer was running (i.e. after edma_execute() but before edma_callback()) the echan->edesc was not freed. This was due to the fact that a running transfer is on none of the vchan lists: desc_submitted, desc_issued, desc_completed (edma_execute() removes it from the desc_issued list), so the vchan_dma_desc_free_list() called at the end of edma_terminate_all() didn't find it and didn't free it. This bug was found on an AM1808 based hardware (very similar to da850evm, however using the second MMC/SD controller), where intense operations on the SD card wasted the device 128MB RAM within a couple of days. Peter Ujfalusi: The issue is even more severe since it affects cyclic (audio) transfers as well. In this case starting/stopping audio will results memory leak. Signed-off-by: Petr Kulhavy Signed-off-by: Peter Ujfalusi CC: CC: Signed-off-by: Vinod Koul --- drivers/dma/edma.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 276157f22612..53dbd3b3384c 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -260,6 +260,13 @@ static int edma_terminate_all(struct dma_chan *chan) */ if (echan->edesc) { int cyclic = echan->edesc->cyclic; + + /* + * free the running request descriptor + * since it is not in any of the vdesc lists + */ + edma_desc_free(&echan->edesc->vdesc); + echan->edesc = NULL; edma_stop(echan->ch_num); /* Move the cyclic channel back to default queue */ From 02d88b735f5a60f04dbf6d051b76e1877a0d0844 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 27 Mar 2015 13:35:52 +0200 Subject: [PATCH 356/567] dmaengine: omap-dma: Fix memory leak when terminating running transfer In omap_dma_start_desc the vdesc->node is removed from the virt-dma framework managed lists (to be precise from the desc_issued list). If a terminate_all comes before the transfer finishes the omap_desc will not be freed up because it is not in any of the lists and we stopped the DMA channel so the transfer will not going to complete. There is no special sequence for leaking memory when using cyclic (audio) transfer: with every start and stop of a cyclic transfer the driver leaks struct omap_desc worth of memory. Free up the allocated memory directly in omap_dma_terminate_all() since the framework will not going to do that for us. Signed-off-by: Peter Ujfalusi CC: CC: Signed-off-by: Vinod Koul --- drivers/dma/omap-dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 7dd6dd121681..167dbaf65742 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -981,6 +981,7 @@ static int omap_dma_terminate_all(struct dma_chan *chan) * c->desc is NULL and exit.) */ if (c->desc) { + omap_dma_desc_free(&c->desc->vd); c->desc = NULL; /* Avoid stopping the dma twice */ if (!c->paused) From f93178291712772983845700b12fc1c8b32f2eb1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 27 Mar 2015 13:35:53 +0200 Subject: [PATCH 357/567] dmaengine: bcm2835-dma: Fix memory leak when stopping a running transfer The vd->node is removed from the lists when the transfer started so the vchan_get_all_descriptors() will not find it. This results memory leak. Signed-off-by: Peter Ujfalusi Acked-by: Stephen Warren Signed-off-by: Vinod Koul --- drivers/dma/bcm2835-dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 0723096fb50a..c92d6a70ccf3 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -475,6 +475,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) * c->desc is NULL and exit.) */ if (c->desc) { + bcm2835_dma_desc_free(&c->desc->vd); c->desc = NULL; bcm2835_dma_abort(c->chan_base); From fbef403aa7b377eb238dc6cade21213c315bc1a7 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 27 Mar 2015 13:35:55 +0200 Subject: [PATCH 358/567] dmaengine: moxart-dma: Fix memory leak when stopping a running transfer The vd->node is removed from the lists when the transfer started so the vchan_get_all_descriptors() will not find it. This results memory leak. Signed-off-by: Peter Ujfalusi Signed-off-by: Vinod Koul --- drivers/dma/moxart-dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c index 15cab7d79525..b4634109e010 100644 --- a/drivers/dma/moxart-dma.c +++ b/drivers/dma/moxart-dma.c @@ -193,8 +193,10 @@ static int moxart_terminate_all(struct dma_chan *chan) spin_lock_irqsave(&ch->vc.lock, flags); - if (ch->desc) + if (ch->desc) { + moxart_dma_desc_free(&ch->desc->vd); ch->desc = NULL; + } ctrl = readl(ch->base + REG_OFF_CTRL); ctrl &= ~(APB_DMA_ENABLE | APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN); From f3f03330dee0526d82f2a0fd1a79d207ed1ac439 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 30 Mar 2015 18:46:29 +0200 Subject: [PATCH 359/567] nfsd: require an explicit option to enable pNFS Turns out sending out layouts to any client is a bad idea if they can't get at the storage device, so require explicit admin action to enable pNFS. Signed-off-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4layouts.c | 2 +- include/uapi/linux/nfsd/export.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index 80e236bf79fc..6904213a4363 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c @@ -118,7 +118,7 @@ void nfsd4_setup_layout_type(struct svc_export *exp) { struct super_block *sb = exp->ex_path.mnt->mnt_sb; - if (exp->ex_flags & NFSEXP_NOPNFS) + if (!(exp->ex_flags & NFSEXP_PNFS)) return; if (sb->s_export_op->get_uuid && diff --git a/include/uapi/linux/nfsd/export.h b/include/uapi/linux/nfsd/export.h index 4742f2cb42f2..d3bd6ffec041 100644 --- a/include/uapi/linux/nfsd/export.h +++ b/include/uapi/linux/nfsd/export.h @@ -47,7 +47,7 @@ * exported filesystem. */ #define NFSEXP_V4ROOT 0x10000 -#define NFSEXP_NOPNFS 0x20000 +#define NFSEXP_PNFS 0x20000 /* All flags that we claim to support. (Note we don't support NOACL.) */ #define NFSEXP_ALLFLAGS 0x3FE7F From a4368ff3ed3b57e4b5e36d83b75604f68bbcdaad Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 30 Mar 2015 23:21:01 +0300 Subject: [PATCH 360/567] Bluetooth: Refactor L2CAP variables into l2cap_ctrl We're getting very close to the maximum possible size of bt_skb_cb. To prepare to shrink the struct with the help of a union this patch moves all L2CAP related variables into the l2cap_ctrl struct. To later add other 'ctrl' structs the L2CAP one is renamed simple 'l2cap' instead of 'control'. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 8 +++--- net/bluetooth/l2cap_core.c | 48 +++++++++++++++---------------- net/bluetooth/l2cap_sock.c | 6 ++-- net/bluetooth/smp.c | 2 +- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 33a5e00025aa..d8367cc7c76e 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -269,6 +269,9 @@ struct l2cap_ctrl { __u16 reqseq; __u16 txseq; __u8 retries; + __le16 psm; + bdaddr_t bdaddr; + struct l2cap_chan *chan; }; struct hci_dev; @@ -284,10 +287,7 @@ struct bt_skb_cb { __u8 req_start:1; u8 req_event; hci_req_complete_t req_complete; - struct l2cap_chan *chan; - struct l2cap_ctrl control; - bdaddr_t bdaddr; - __le16 psm; + struct l2cap_ctrl l2cap; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d69861c89bb5..dad419782a12 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -292,7 +292,7 @@ static struct sk_buff *l2cap_ertm_seq_in_queue(struct sk_buff_head *head, struct sk_buff *skb; skb_queue_walk(head, skb) { - if (bt_cb(skb)->control.txseq == seq) + if (bt_cb(skb)->l2cap.txseq == seq) return skb; } @@ -954,11 +954,11 @@ static inline void __unpack_control(struct l2cap_chan *chan, { if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { __unpack_extended_control(get_unaligned_le32(skb->data), - &bt_cb(skb)->control); + &bt_cb(skb)->l2cap); skb_pull(skb, L2CAP_EXT_CTRL_SIZE); } else { __unpack_enhanced_control(get_unaligned_le16(skb->data), - &bt_cb(skb)->control); + &bt_cb(skb)->l2cap); skb_pull(skb, L2CAP_ENH_CTRL_SIZE); } } @@ -1200,8 +1200,8 @@ static void l2cap_move_setup(struct l2cap_chan *chan) chan->retry_count = 0; skb_queue_walk(&chan->tx_q, skb) { - if (bt_cb(skb)->control.retries) - bt_cb(skb)->control.retries = 1; + if (bt_cb(skb)->l2cap.retries) + bt_cb(skb)->l2cap.retries = 1; else break; } @@ -1846,8 +1846,8 @@ static void l2cap_streaming_send(struct l2cap_chan *chan, skb = skb_dequeue(&chan->tx_q); - bt_cb(skb)->control.retries = 1; - control = &bt_cb(skb)->control; + bt_cb(skb)->l2cap.retries = 1; + control = &bt_cb(skb)->l2cap; control->reqseq = 0; control->txseq = chan->next_tx_seq; @@ -1891,8 +1891,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) skb = chan->tx_send_head; - bt_cb(skb)->control.retries = 1; - control = &bt_cb(skb)->control; + bt_cb(skb)->l2cap.retries = 1; + control = &bt_cb(skb)->l2cap; if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) control->final = 1; @@ -1963,11 +1963,11 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan) continue; } - bt_cb(skb)->control.retries++; - control = bt_cb(skb)->control; + bt_cb(skb)->l2cap.retries++; + control = bt_cb(skb)->l2cap; if (chan->max_tx != 0 && - bt_cb(skb)->control.retries > chan->max_tx) { + bt_cb(skb)->l2cap.retries > chan->max_tx) { BT_DBG("Retry limit exceeded (%d)", chan->max_tx); l2cap_send_disconn_req(chan, ECONNRESET); l2cap_seq_list_clear(&chan->retrans_list); @@ -2045,7 +2045,7 @@ static void l2cap_retransmit_all(struct l2cap_chan *chan, if (chan->unacked_frames) { skb_queue_walk(&chan->tx_q, skb) { - if (bt_cb(skb)->control.txseq == control->reqseq || + if (bt_cb(skb)->l2cap.txseq == control->reqseq || skb == chan->tx_send_head) break; } @@ -2055,7 +2055,7 @@ static void l2cap_retransmit_all(struct l2cap_chan *chan, break; l2cap_seq_list_append(&chan->retrans_list, - bt_cb(skb)->control.txseq); + bt_cb(skb)->l2cap.txseq); } l2cap_ertm_resend(chan); @@ -2267,8 +2267,8 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, return ERR_PTR(err); } - bt_cb(skb)->control.fcs = chan->fcs; - bt_cb(skb)->control.retries = 0; + bt_cb(skb)->l2cap.fcs = chan->fcs; + bt_cb(skb)->l2cap.retries = 0; return skb; } @@ -2321,7 +2321,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, return PTR_ERR(skb); } - bt_cb(skb)->control.sar = sar; + bt_cb(skb)->l2cap.sar = sar; __skb_queue_tail(seg_queue, skb); len -= pdu_len; @@ -2856,7 +2856,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) continue; /* Don't send frame to the channel it came from */ - if (bt_cb(skb)->chan == chan) + if (bt_cb(skb)->l2cap.chan == chan) continue; nskb = skb_clone(skb, GFP_KERNEL); @@ -5918,7 +5918,7 @@ static int l2cap_rx_queued_iframes(struct l2cap_chan *chan) skb_unlink(skb, &chan->srej_q); chan->buffer_seq = __next_seq(chan, chan->buffer_seq); - err = l2cap_reassemble_sdu(chan, skb, &bt_cb(skb)->control); + err = l2cap_reassemble_sdu(chan, skb, &bt_cb(skb)->l2cap); if (err) break; } @@ -5952,7 +5952,7 @@ static void l2cap_handle_srej(struct l2cap_chan *chan, return; } - if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) { + if (chan->max_tx != 0 && bt_cb(skb)->l2cap.retries >= chan->max_tx) { BT_DBG("Retry limit exceeded (%d)", chan->max_tx); l2cap_send_disconn_req(chan, ECONNRESET); return; @@ -6005,7 +6005,7 @@ static void l2cap_handle_rej(struct l2cap_chan *chan, skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq); if (chan->max_tx && skb && - bt_cb(skb)->control.retries >= chan->max_tx) { + bt_cb(skb)->l2cap.retries >= chan->max_tx) { BT_DBG("Retry limit exceeded (%d)", chan->max_tx); l2cap_send_disconn_req(chan, ECONNRESET); return; @@ -6565,7 +6565,7 @@ static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) { - struct l2cap_ctrl *control = &bt_cb(skb)->control; + struct l2cap_ctrl *control = &bt_cb(skb)->l2cap; u16 len; u8 event; @@ -6864,8 +6864,8 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, goto drop; /* Store remote BD_ADDR and PSM for msg_name */ - bacpy(&bt_cb(skb)->bdaddr, &hcon->dst); - bt_cb(skb)->psm = psm; + bacpy(&bt_cb(skb)->l2cap.bdaddr, &hcon->dst); + bt_cb(skb)->l2cap.psm = psm; if (!chan->ops->recv(chan, skb)) { l2cap_chan_put(chan); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 9070720eedc8..a7278f05eafb 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1330,7 +1330,7 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, skb->priority = sk->sk_priority; - bt_cb(skb)->chan = chan; + bt_cb(skb)->l2cap.chan = chan; return skb; } @@ -1444,8 +1444,8 @@ static void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name, memset(la, 0, sizeof(struct sockaddr_l2)); la->l2_family = AF_BLUETOOTH; - la->l2_psm = bt_cb(skb)->psm; - bacpy(&la->l2_bdaddr, &bt_cb(skb)->bdaddr); + la->l2_psm = bt_cb(skb)->l2cap.psm; + bacpy(&la->l2_bdaddr, &bt_cb(skb)->l2cap.bdaddr); *msg_namelen = sizeof(struct sockaddr_l2); } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1ec3f66b5a74..1910c5806974 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -3017,7 +3017,7 @@ static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan, return ERR_PTR(-ENOMEM); skb->priority = HCI_PRIO_MAX; - bt_cb(skb)->chan = chan; + bt_cb(skb)->l2cap.chan = chan; return skb; } From db6e3e8d016823c6b0f773c70a69ce65807d8a44 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 30 Mar 2015 23:21:02 +0300 Subject: [PATCH 361/567] Bluetooth: Refactor HCI request variables into own struct In order to shrink the size of bt_skb_cb, this patch moves the HCI request related variables into their own req_ctrl struct. Additionall the L2CAP and HCI request structs are placed inside the same union since they will never be used at the same time for the same skb. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 14 ++++++++++---- net/bluetooth/hci_core.c | 12 ++++++------ net/bluetooth/hci_event.c | 4 ++-- net/bluetooth/hci_request.c | 6 +++--- net/bluetooth/hci_sock.c | 2 +- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index d8367cc7c76e..eeaff4b5cb62 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -278,16 +278,22 @@ struct hci_dev; typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status, u16 opcode); +struct req_ctrl { + bool start; + u8 event; + hci_req_complete_t complete; +}; + struct bt_skb_cb { __u8 pkt_type; __u8 force_active; __u16 opcode; __u16 expect; __u8 incoming:1; - __u8 req_start:1; - u8 req_event; - hci_req_complete_t req_complete; - struct l2cap_ctrl l2cap; + union { + struct l2cap_ctrl l2cap; + struct req_ctrl req; + }; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e6bfeb7b4415..246d7eca5d29 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3585,7 +3585,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, /* Stand-alone HCI commands must be flagged as * single-command requests. */ - bt_cb(skb)->req_start = 1; + bt_cb(skb)->req.start = true; skb_queue_tail(&hdev->cmd_q, skb); queue_work(hdev->workqueue, &hdev->cmd_work); @@ -4263,7 +4263,7 @@ static bool hci_req_is_complete(struct hci_dev *hdev) if (!skb) return true; - return bt_cb(skb)->req_start; + return bt_cb(skb)->req.start; } static void hci_resend_last(struct hci_dev *hdev) @@ -4323,14 +4323,14 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status) * command queue (hdev->cmd_q). */ if (hdev->sent_cmd) { - req_complete = bt_cb(hdev->sent_cmd)->req_complete; + req_complete = bt_cb(hdev->sent_cmd)->req.complete; if (req_complete) { /* We must set the complete callback to NULL to * avoid calling the callback more than once if * this function gets called again. */ - bt_cb(hdev->sent_cmd)->req_complete = NULL; + bt_cb(hdev->sent_cmd)->req.complete = NULL; goto call_complete; } @@ -4339,12 +4339,12 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status) /* Remove all pending commands belonging to this request */ spin_lock_irqsave(&hdev->cmd_q.lock, flags); while ((skb = __skb_dequeue(&hdev->cmd_q))) { - if (bt_cb(skb)->req_start) { + if (bt_cb(skb)->req.start) { __skb_queue_head(&hdev->cmd_q, skb); break; } - req_complete = bt_cb(skb)->req_complete; + req_complete = bt_cb(skb)->req.complete; kfree_skb(skb); } spin_unlock_irqrestore(&hdev->cmd_q.lock, flags); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 20f34b861426..7c0f992602f5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3125,7 +3125,7 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) atomic_set(&hdev->cmd_cnt, 1); if (ev->status || - (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req_event)) + (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event)) hci_req_cmd_complete(hdev, opcode, ev->status); if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q)) @@ -5049,7 +5049,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) skb_pull(skb, HCI_EVENT_HDR_SIZE); - if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req_event == event) { + if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) { struct hci_command_hdr *cmd_hdr = (void *) hdev->sent_cmd->data; u16 opcode = __le16_to_cpu(cmd_hdr->opcode); diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 55e096d20a0f..7e17907effb3 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -55,7 +55,7 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete) return -ENODATA; skb = skb_peek_tail(&req->cmd_q); - bt_cb(skb)->req_complete = complete; + bt_cb(skb)->req.complete = complete; spin_lock_irqsave(&hdev->cmd_q.lock, flags); skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q); @@ -116,9 +116,9 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, } if (skb_queue_empty(&req->cmd_q)) - bt_cb(skb)->req_start = 1; + bt_cb(skb)->req.start = true; - bt_cb(skb)->req_event = event; + bt_cb(skb)->req.event = event; skb_queue_tail(&req->cmd_q, skb); } diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 85a44a7dc150..56f9edbf3d05 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -1164,7 +1164,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, /* Stand-alone HCI commands must be flagged as * single-command requests. */ - bt_cb(skb)->req_start = 1; + bt_cb(skb)->req.start = true; skb_queue_tail(&hdev->cmd_q, skb); queue_work(hdev->workqueue, &hdev->cmd_work); From ca68a525ff6b62e77dc8a8c3020a63321bfb864f Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 29 Mar 2015 15:54:13 +0200 Subject: [PATCH 362/567] MAINTAINERS: Change the x86 microcode loader maintainer Let's make it official - I've been doing this for a while now anyway. Signed-off-by: Borislav Petkov Cc: Andreas Herrmann Cc: Andrew Morton Cc: Greg KH Cc: H. Peter Anvin Cc: Thomas Gleixner Cc: Tigran Aivazian Signed-off-by: Ingo Molnar --- MAINTAINERS | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1de6afa8ee51..e04362883ea3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -637,8 +637,7 @@ F: drivers/gpu/drm/radeon/radeon_kfd.h F: include/uapi/linux/kfd_ioctl.h AMD MICROCODE UPDATE SUPPORT -M: Andreas Herrmann -L: amd64-microcode@amd64.org +M: Borislav Petkov S: Maintained F: arch/x86/kernel/cpu/microcode/amd* @@ -5095,7 +5094,7 @@ S: Supported F: drivers/platform/x86/intel_menlow.c INTEL IA32 MICROCODE UPDATE SUPPORT -M: Tigran Aivazian +M: Borislav Petkov S: Maintained F: arch/x86/kernel/cpu/microcode/core* F: arch/x86/kernel/cpu/microcode/intel* From e9637415a92cf25ad800b7fdeddcd30cce7b44ab Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 30 Mar 2015 13:39:09 -0400 Subject: [PATCH 363/567] block: fix blk_stack_limits() regression due to lcm() change Linux 3.19 commit 69c953c ("lib/lcm.c: lcm(n,0)=lcm(0,n) is 0, not n") caused blk_stack_limits() to not properly stack queue_limits for stacked devices (e.g. DM). Fix this regression by establishing lcm_not_zero() and switching blk_stack_limits() over to using it. DM uses blk_set_stacking_limits() to establish the initial top-level queue_limits that are then built up based on underlying devices' limits using blk_stack_limits(). In the case of optimal_io_size (io_opt) blk_set_stacking_limits() establishes a default value of 0. With commit 69c953c, lcm(0, n) is no longer n, which compromises proper stacking of the underlying devices' io_opt. Test: $ modprobe scsi_debug dev_size_mb=10 num_tgts=1 opt_blks=1536 $ cat /sys/block/sde/queue/optimal_io_size 786432 $ dmsetup create node --table "0 100 linear /dev/sde 0" Before this fix: $ cat /sys/block/dm-5/queue/optimal_io_size 0 After this fix: $ cat /sys/block/dm-5/queue/optimal_io_size 786432 Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org # 3.19+ Acked-by: Martin K. Petersen Signed-off-by: Jens Axboe --- block/blk-settings.c | 6 +++--- include/linux/lcm.h | 1 + lib/lcm.c | 11 +++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/block/blk-settings.c b/block/blk-settings.c index 6ed2cbe5e8c9..12600bfffca9 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -585,7 +585,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, b->physical_block_size); t->io_min = max(t->io_min, b->io_min); - t->io_opt = lcm(t->io_opt, b->io_opt); + t->io_opt = lcm_not_zero(t->io_opt, b->io_opt); t->cluster &= b->cluster; t->discard_zeroes_data &= b->discard_zeroes_data; @@ -616,7 +616,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, b->raid_partial_stripes_expensive); /* Find lowest common alignment_offset */ - t->alignment_offset = lcm(t->alignment_offset, alignment) + t->alignment_offset = lcm_not_zero(t->alignment_offset, alignment) % max(t->physical_block_size, t->io_min); /* Verify that new alignment_offset is on a logical block boundary */ @@ -643,7 +643,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, b->max_discard_sectors); t->discard_granularity = max(t->discard_granularity, b->discard_granularity); - t->discard_alignment = lcm(t->discard_alignment, alignment) % + t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) % t->discard_granularity; } diff --git a/include/linux/lcm.h b/include/linux/lcm.h index 7bf01d779b45..1ce79a7f1daa 100644 --- a/include/linux/lcm.h +++ b/include/linux/lcm.h @@ -4,5 +4,6 @@ #include unsigned long lcm(unsigned long a, unsigned long b) __attribute_const__; +unsigned long lcm_not_zero(unsigned long a, unsigned long b) __attribute_const__; #endif /* _LCM_H */ diff --git a/lib/lcm.c b/lib/lcm.c index e97dbd51e756..03d7fcb420b5 100644 --- a/lib/lcm.c +++ b/lib/lcm.c @@ -12,3 +12,14 @@ unsigned long lcm(unsigned long a, unsigned long b) return 0; } EXPORT_SYMBOL_GPL(lcm); + +unsigned long lcm_not_zero(unsigned long a, unsigned long b) +{ + unsigned long l = lcm(a, b); + + if (l) + return l; + + return (b ? : a); +} +EXPORT_SYMBOL_GPL(lcm_not_zero); From 27705f7085ce2e124fac4c280ce824962cc90bb6 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Sat, 28 Mar 2015 19:13:22 +0100 Subject: [PATCH 364/567] ipvlan: fix addr hash list corruption When ipvlan interface with IP addresses attached is brought down and then deleted, the assigned addresses are deleted twice from the address hash list, first on the interface down and second on the link deletion. Similarly, when an address is added while the interface is down, it is added second time once the interface is brought up. When the interface is down, the addresses should be kept off the hash list for performance reasons. Ensure this is true, which also fixes the double add problem. To fix the double free, check whether the address is hashed before removing it. Reported-by: Dan Williams Signed-off-by: Jiri Benc Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_core.c | 5 +++-- drivers/net/ipvlan/ipvlan_main.c | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 2a175006028b..8a542b9340c4 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -81,12 +81,13 @@ void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr) hash = (addr->atype == IPVL_IPV6) ? ipvlan_get_v6_hash(&addr->ip6addr) : ipvlan_get_v4_hash(&addr->ip4addr); - hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]); + if (hlist_unhashed(&addr->hlnode)) + hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]); } void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync) { - hlist_del_rcu(&addr->hlnode); + hlist_del_init_rcu(&addr->hlnode); if (sync) synchronize_rcu(); } diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 4f4099d5603d..1eb3f33e11cc 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -622,7 +622,11 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) addr->atype = IPVL_IPV6; list_add_tail_rcu(&addr->anode, &ipvlan->addrs); ipvlan->ipv6cnt++; - ipvlan_ht_addr_add(ipvlan, addr); + /* If the interface is not up, the address will be added to the hash + * list by ipvlan_open. + */ + if (netif_running(ipvlan->dev)) + ipvlan_ht_addr_add(ipvlan, addr); return 0; } @@ -690,7 +694,11 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) addr->atype = IPVL_IPV4; list_add_tail_rcu(&addr->anode, &ipvlan->addrs); ipvlan->ipv4cnt++; - ipvlan_ht_addr_add(ipvlan, addr); + /* If the interface is not up, the address will be added to the hash + * list by ipvlan_open. + */ + if (netif_running(ipvlan->dev)) + ipvlan_ht_addr_add(ipvlan, addr); ipvlan_set_broadcast_mac_filter(ipvlan, true); return 0; From 2afa650ce297bc2048bc3d059774be9c39734565 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Sat, 28 Mar 2015 19:13:23 +0100 Subject: [PATCH 365/567] ipvlan: protect against concurrent link removal Adding and removing to the 'ipvlans' list is already done using _rcu list operations. Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 8a542b9340c4..568628f95aa2 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -193,7 +193,8 @@ static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb, if (skb->protocol == htons(ETH_P_PAUSE)) return; - list_for_each_entry(ipvlan, &port->ipvlans, pnode) { + rcu_read_lock(); + list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) { if (local && (ipvlan == in_dev)) continue; @@ -220,6 +221,7 @@ static void ipvlan_multicast_frame(struct ipvl_port *port, struct sk_buff *skb, mcast_acct: ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true); } + rcu_read_unlock(); /* Locally generated? ...Forward a copy to the main-device as * well. On the RX side we'll ignore it (wont give it to any From 40891e8ad630558caae26788d37bf50137b6d5d2 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Sat, 28 Mar 2015 19:13:24 +0100 Subject: [PATCH 366/567] ipvlan: do not use rcu operations for address list All accesses to ipvlan->addrs are under rtnl. Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 1eb3f33e11cc..aaa005bd21ce 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -505,7 +505,7 @@ static void ipvlan_link_delete(struct net_device *dev, struct list_head *head) if (ipvlan->ipv6cnt > 0 || ipvlan->ipv4cnt > 0) { list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) { ipvlan_ht_addr_del(addr, !dev->dismantle); - list_del_rcu(&addr->anode); + list_del(&addr->anode); } } list_del_rcu(&ipvlan->pnode); @@ -620,7 +620,7 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) addr->master = ipvlan; memcpy(&addr->ip6addr, ip6_addr, sizeof(struct in6_addr)); addr->atype = IPVL_IPV6; - list_add_tail_rcu(&addr->anode, &ipvlan->addrs); + list_add_tail(&addr->anode, &ipvlan->addrs); ipvlan->ipv6cnt++; /* If the interface is not up, the address will be added to the hash * list by ipvlan_open. @@ -640,7 +640,7 @@ static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) return; ipvlan_ht_addr_del(addr, true); - list_del_rcu(&addr->anode); + list_del(&addr->anode); ipvlan->ipv6cnt--; WARN_ON(ipvlan->ipv6cnt < 0); kfree_rcu(addr, rcu); @@ -692,7 +692,7 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) addr->master = ipvlan; memcpy(&addr->ip4addr, ip4_addr, sizeof(struct in_addr)); addr->atype = IPVL_IPV4; - list_add_tail_rcu(&addr->anode, &ipvlan->addrs); + list_add_tail(&addr->anode, &ipvlan->addrs); ipvlan->ipv4cnt++; /* If the interface is not up, the address will be added to the hash * list by ipvlan_open. @@ -713,7 +713,7 @@ static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) return; ipvlan_ht_addr_del(addr, true); - list_del_rcu(&addr->anode); + list_del(&addr->anode); ipvlan->ipv4cnt--; WARN_ON(ipvlan->ipv4cnt < 0); if (!ipvlan->ipv4cnt) From e9997c2938b23d792528da1597b3aea9b0f2a324 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Sat, 28 Mar 2015 19:13:25 +0100 Subject: [PATCH 367/567] ipvlan: fix check for IP addresses in control path When an ipvlan interface is down, its addresses are not on the hash list. Fix checks for existence of addresses not to depend on the hash list, walk through all interface addresses instead. Signed-off-by: Jiri Benc Acked-by: Mahesh Bandewar Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan.h | 4 +++- drivers/net/ipvlan/ipvlan_core.c | 21 +++++++++++++++------ drivers/net/ipvlan/ipvlan_main.c | 8 ++++---- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index 924ea98bd531..54549a6223dd 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h @@ -114,7 +114,9 @@ unsigned int ipvlan_mac_hash(const unsigned char *addr); rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb); int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev); void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr); -bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6); +struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan, + const void *iaddr, bool is_v6); +bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6); struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, const void *iaddr, bool is_v6); void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync); diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 568628f95aa2..b7877a194cfe 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -92,9 +92,9 @@ void ipvlan_ht_addr_del(struct ipvl_addr *addr, bool sync) synchronize_rcu(); } -bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6) +struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan, + const void *iaddr, bool is_v6) { - struct ipvl_port *port = ipvlan->port; struct ipvl_addr *addr; list_for_each_entry(addr, &ipvlan->addrs, anode) { @@ -102,12 +102,21 @@ bool ipvlan_addr_busy(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6) ipv6_addr_equal(&addr->ip6addr, iaddr)) || (!is_v6 && addr->atype == IPVL_IPV4 && addr->ip4addr.s_addr == ((struct in_addr *)iaddr)->s_addr)) + return addr; + } + return NULL; +} + +bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6) +{ + struct ipvl_dev *ipvlan; + + ASSERT_RTNL(); + + list_for_each_entry(ipvlan, &port->ipvlans, pnode) { + if (ipvlan_find_addr(ipvlan, iaddr, is_v6)) return true; } - - if (ipvlan_ht_addr_lookup(port, iaddr, is_v6)) - return true; - return false; } diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index aaa005bd21ce..4fa14208d799 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -607,7 +607,7 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) { struct ipvl_addr *addr; - if (ipvlan_addr_busy(ipvlan, ip6_addr, true)) { + if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) { netif_err(ipvlan, ifup, ipvlan->dev, "Failed to add IPv6=%pI6c addr for %s intf\n", ip6_addr, ipvlan->dev->name); @@ -635,7 +635,7 @@ static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) { struct ipvl_addr *addr; - addr = ipvlan_ht_addr_lookup(ipvlan->port, ip6_addr, true); + addr = ipvlan_find_addr(ipvlan, ip6_addr, true); if (!addr) return; @@ -679,7 +679,7 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) { struct ipvl_addr *addr; - if (ipvlan_addr_busy(ipvlan, ip4_addr, false)) { + if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) { netif_err(ipvlan, ifup, ipvlan->dev, "Failed to add IPv4=%pI4 on %s intf.\n", ip4_addr, ipvlan->dev->name); @@ -708,7 +708,7 @@ static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) { struct ipvl_addr *addr; - addr = ipvlan_ht_addr_lookup(ipvlan->port, ip4_addr, false); + addr = ipvlan_find_addr(ipvlan, ip4_addr, false); if (!addr) return; From f5e2dc5d7fe78fe4d8748d217338f4f7b6a5d7ea Mon Sep 17 00:00:00 2001 From: Anton Nayshtut Date: Sun, 29 Mar 2015 14:20:25 +0300 Subject: [PATCH 368/567] bonding: Bonding Overriding Configuration logic restored. Before commit 3900f29021f0bc7fe9815aa32f1a993b7dfdd402 ("bonding: slight optimizztion for bond_slave_override()") the override logic was to send packets with non-zero queue_id through the slave with corresponding queue_id, under two conditions only - if the slave can transmit and it's up. The above mentioned commit changed this logic by introducing an additional condition - whether the bond is active (indirectly, using the slave_can_tx and later - bond_is_active_slave), that prevents the user from implementing more complex policies according to the Documentation/networking/bonding.txt. Signed-off-by: Anton Nayshtut Signed-off-by: Alexey Bogoslavsky Signed-off-by: Andy Gospodarek Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b979c265fc51..089a4028859d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3850,7 +3850,8 @@ static inline int bond_slave_override(struct bonding *bond, /* Find out if any slaves have the same mapping as this skb. */ bond_for_each_slave_rcu(bond, slave, iter) { if (slave->queue_id == skb->queue_mapping) { - if (bond_slave_can_tx(slave)) { + if (bond_slave_is_up(slave) && + slave->link == BOND_LINK_UP) { bond_dev_queue_xmit(bond, skb, slave->dev); return 0; } From 5899f0478528b59ea9ced201eacb3e56ca406c39 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Sun, 29 Mar 2015 16:05:28 +0200 Subject: [PATCH 369/567] netlink: pad nla_memcpy dest buffer with zeroes This is especially important in cases where the kernel allocs a new structure and expects a field to be set from a netlink attribute. If such attribute is shorter than expected, the rest of the field is left containing previous data. When such field is read back by the user space, kernel memory content is leaked. Signed-off-by: Jiri Benc Acked-by: Thomas Graf Signed-off-by: David S. Miller --- lib/nlattr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/nlattr.c b/lib/nlattr.c index 76a1b59523ab..f5907d23272d 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -279,6 +279,8 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count) int minlen = min_t(int, count, nla_len(src)); memcpy(dest, nla_data(src), minlen); + if (count > minlen) + memset(dest + minlen, 0, count - minlen); return minlen; } From f9c72d10d6fbf949558cd088389a42213ed7b12d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 31 Mar 2015 12:03:28 -0400 Subject: [PATCH 370/567] sunrpc: make debugfs file creation failure non-fatal We currently have a problem that SELinux policy is being enforced when creating debugfs files. If a debugfs file is created as a side effect of doing some syscall, then that creation can fail if the SELinux policy for that process prevents it. This seems wrong. We don't do that for files under /proc, for instance, so Bruce has proposed a patch to fix that. While discussing that patch however, Greg K.H. stated: "No kernel code should care / fail if a debugfs function fails, so please fix up the sunrpc code first." This patch converts all of the sunrpc debugfs setup code to be void return functins, and the callers to not look for errors from those functions. This should allow rpc_clnt and rpc_xprt creation to work, even if the kernel fails to create debugfs files for some reason. Symptoms were failing krb5 mounts on systems using gss-proxy and selinux. Fixes: 388f0c776781 "sunrpc: add a debugfs rpc_xprt directory..." Cc: stable@vger.kernel.org Signed-off-by: Jeff Layton Acked-by: Greg Kroah-Hartman Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/debug.h | 18 ++++++------- net/sunrpc/clnt.c | 4 +-- net/sunrpc/debugfs.c | 52 ++++++++++++++++++++---------------- net/sunrpc/sunrpc_syms.c | 7 +---- net/sunrpc/xprt.c | 7 +---- 5 files changed, 41 insertions(+), 47 deletions(-) diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index c57d8ea0716c..59a7889e15db 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h @@ -60,17 +60,17 @@ struct rpc_xprt; #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) void rpc_register_sysctl(void); void rpc_unregister_sysctl(void); -int sunrpc_debugfs_init(void); +void sunrpc_debugfs_init(void); void sunrpc_debugfs_exit(void); -int rpc_clnt_debugfs_register(struct rpc_clnt *); +void rpc_clnt_debugfs_register(struct rpc_clnt *); void rpc_clnt_debugfs_unregister(struct rpc_clnt *); -int rpc_xprt_debugfs_register(struct rpc_xprt *); +void rpc_xprt_debugfs_register(struct rpc_xprt *); void rpc_xprt_debugfs_unregister(struct rpc_xprt *); #else -static inline int +static inline void sunrpc_debugfs_init(void) { - return 0; + return; } static inline void @@ -79,10 +79,10 @@ sunrpc_debugfs_exit(void) return; } -static inline int +static inline void rpc_clnt_debugfs_register(struct rpc_clnt *clnt) { - return 0; + return; } static inline void @@ -91,10 +91,10 @@ rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt) return; } -static inline int +static inline void rpc_xprt_debugfs_register(struct rpc_xprt *xprt) { - return 0; + return; } static inline void diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 612aa73bbc60..e6ce1517367f 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -303,9 +303,7 @@ static int rpc_client_register(struct rpc_clnt *clnt, struct super_block *pipefs_sb; int err; - err = rpc_clnt_debugfs_register(clnt); - if (err) - return err; + rpc_clnt_debugfs_register(clnt); pipefs_sb = rpc_get_sb_net(net); if (pipefs_sb) { diff --git a/net/sunrpc/debugfs.c b/net/sunrpc/debugfs.c index e811f390f9f6..82962f7e6e88 100644 --- a/net/sunrpc/debugfs.c +++ b/net/sunrpc/debugfs.c @@ -129,48 +129,52 @@ static const struct file_operations tasks_fops = { .release = tasks_release, }; -int +void rpc_clnt_debugfs_register(struct rpc_clnt *clnt) { - int len, err; + int len; char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */ + struct rpc_xprt *xprt; /* Already registered? */ - if (clnt->cl_debugfs) - return 0; + if (clnt->cl_debugfs || !rpc_clnt_dir) + return; len = snprintf(name, sizeof(name), "%x", clnt->cl_clid); if (len >= sizeof(name)) - return -EINVAL; + return; /* make the per-client dir */ clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir); if (!clnt->cl_debugfs) - return -ENOMEM; + return; /* make tasks file */ - err = -ENOMEM; if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs, clnt, &tasks_fops)) goto out_err; - err = -EINVAL; rcu_read_lock(); + xprt = rcu_dereference(clnt->cl_xprt); + /* no "debugfs" dentry? Don't bother with the symlink. */ + if (!xprt->debugfs) { + rcu_read_unlock(); + return; + } len = snprintf(name, sizeof(name), "../../rpc_xprt/%s", - rcu_dereference(clnt->cl_xprt)->debugfs->d_name.name); + xprt->debugfs->d_name.name); rcu_read_unlock(); + if (len >= sizeof(name)) goto out_err; - err = -ENOMEM; if (!debugfs_create_symlink("xprt", clnt->cl_debugfs, name)) goto out_err; - return 0; + return; out_err: debugfs_remove_recursive(clnt->cl_debugfs); clnt->cl_debugfs = NULL; - return err; } void @@ -226,33 +230,33 @@ static const struct file_operations xprt_info_fops = { .release = xprt_info_release, }; -int +void rpc_xprt_debugfs_register(struct rpc_xprt *xprt) { int len, id; static atomic_t cur_id; char name[9]; /* 8 hex digits + NULL term */ + if (!rpc_xprt_dir) + return; + id = (unsigned int)atomic_inc_return(&cur_id); len = snprintf(name, sizeof(name), "%x", id); if (len >= sizeof(name)) - return -EINVAL; + return; /* make the per-client dir */ xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir); if (!xprt->debugfs) - return -ENOMEM; + return; /* make tasks file */ if (!debugfs_create_file("info", S_IFREG | S_IRUSR, xprt->debugfs, xprt, &xprt_info_fops)) { debugfs_remove_recursive(xprt->debugfs); xprt->debugfs = NULL; - return -ENOMEM; } - - return 0; } void @@ -266,14 +270,17 @@ void __exit sunrpc_debugfs_exit(void) { debugfs_remove_recursive(topdir); + topdir = NULL; + rpc_clnt_dir = NULL; + rpc_xprt_dir = NULL; } -int __init +void __init sunrpc_debugfs_init(void) { topdir = debugfs_create_dir("sunrpc", NULL); if (!topdir) - goto out; + return; rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir); if (!rpc_clnt_dir) @@ -283,10 +290,9 @@ sunrpc_debugfs_init(void) if (!rpc_xprt_dir) goto out_remove; - return 0; + return; out_remove: debugfs_remove_recursive(topdir); topdir = NULL; -out: - return -ENOMEM; + rpc_clnt_dir = NULL; } diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index e37fbed87956..ee5d3d253102 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -98,10 +98,7 @@ init_sunrpc(void) if (err) goto out4; - err = sunrpc_debugfs_init(); - if (err) - goto out5; - + sunrpc_debugfs_init(); #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) rpc_register_sysctl(); #endif @@ -109,8 +106,6 @@ init_sunrpc(void) init_socket_xprt(); /* clnt sock transport */ return 0; -out5: - unregister_rpc_pipefs(); out4: unregister_pernet_subsys(&sunrpc_net_ops); out3: diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index e3015aede0d9..9949722d99ce 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1331,7 +1331,6 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net) */ struct rpc_xprt *xprt_create_transport(struct xprt_create *args) { - int err; struct rpc_xprt *xprt; struct xprt_class *t; @@ -1372,11 +1371,7 @@ found: return ERR_PTR(-ENOMEM); } - err = rpc_xprt_debugfs_register(xprt); - if (err) { - xprt_destroy(xprt); - return ERR_PTR(err); - } + rpc_xprt_debugfs_register(xprt); dprintk("RPC: created transport %p with %u slots\n", xprt, xprt->max_reqs); From fa2d8ff4e3522b4e05f590575d3eb8087f3a8cdc Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 30 Mar 2015 13:57:41 +0200 Subject: [PATCH 371/567] openvswitch: Return vport module ref before destruction Return module reference before invoking the respective vport ->destroy() function. This is needed as ovs_vport_del() is not invoked inside an RCU read side critical section so the kfree can occur immediately before returning to ovs_vport_del(). Returning the module reference before ->destroy() is safe because the module unregistration is blocked on ovs_lock which we hold while destroying the datapath. Fixes: 62b9c8d0372d ("ovs: Turn vports with dependencies into separate modules") Reported-by: Pravin Shelar Signed-off-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/vport.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index ec2954ffc690..067a3fff1d2c 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -274,10 +274,8 @@ void ovs_vport_del(struct vport *vport) ASSERT_OVSL(); hlist_del_rcu(&vport->hash_node); - - vport->ops->destroy(vport); - module_put(vport->ops->owner); + vport->ops->destroy(vport); } /** From ed4ac4221776a5103faf71a4032ca00178d6e66b Mon Sep 17 00:00:00 2001 From: Eugene Crosser Date: Mon, 30 Mar 2015 15:40:42 +0200 Subject: [PATCH 372/567] af_iucv: fix AF_IUCV sendmsg() errno When sending over AF_IUCV socket, errno was incorrectly set to ENOMEM even when other values where appropriate, notably EAGAIN. With this patch, error indicator returned by sock_alloc_send_skb() is passed to the caller, rather than being overwritten with ENOMEM. Signed-off-by: Eugene Crosser Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 2e9953b2db84..53d931172088 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1114,10 +1114,8 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, noblock, &err); else skb = sock_alloc_send_skb(sk, len, noblock, &err); - if (!skb) { - err = -ENOMEM; + if (!skb) goto out; - } if (iucv->transport == AF_IUCV_TRANS_HIPER) skb_reserve(skb, sizeof(struct af_iucv_trans_hdr) + ETH_HLEN); if (memcpy_from_msg(skb_put(skb, len), msg, len)) { From 347eec348a9b0ba6968145cc7b1995d2475ae31b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 31 Mar 2015 14:10:07 +0200 Subject: [PATCH 373/567] net/usb/r8152: add device id for Lenovo TP USB 3.0 Ethernet This device is sold as 'Lenovo Tinkpad USB 3.0 Ethernet 4X90E51405'. Chipset is RTL8153 and works with r8152. Signed-off-by: Christian Hesse Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ether.c | 8 ++++++++ drivers/net/usb/r8152.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 9311a08565be..4545e78840b0 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -522,6 +522,7 @@ static const struct driver_info wwan_info = { #define DELL_VENDOR_ID 0x413C #define REALTEK_VENDOR_ID 0x0bda #define SAMSUNG_VENDOR_ID 0x04e8 +#define LENOVO_VENDOR_ID 0x17ef static const struct usb_device_id products[] = { /* BLACKLIST !! @@ -702,6 +703,13 @@ static const struct usb_device_id products[] = { .driver_info = 0, }, +/* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */ +{ + USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = 0, +}, + /* WHITELIST!!! * * CDC Ether uses two interfaces, not necessarily consecutive. diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 438fc6bcaef1..9f7c0ab3b349 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -492,6 +492,7 @@ enum rtl8152_flags { /* Define these values to match your device */ #define VENDOR_ID_REALTEK 0x0bda #define VENDOR_ID_SAMSUNG 0x04e8 +#define VENDOR_ID_LENOVO 0x17ef #define MCU_TYPE_PLA 0x0100 #define MCU_TYPE_USB 0x0000 @@ -4037,6 +4038,7 @@ static struct usb_device_id rtl8152_table[] = { {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)}, {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)}, {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, + {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)}, {} }; From 85734b1a5de80341d7d01cd29bbea9cf6f77094b Mon Sep 17 00:00:00 2001 From: Filip Ayazi Date: Wed, 25 Mar 2015 15:53:04 -0700 Subject: [PATCH 374/567] Input: synaptics - fix min-max quirk value for E440 Commit 98dc070373 ("Input: synaptics - add quirk for Thinkpad E440") had a typo in ymax, this changes the value to the one reported by touchpad-edge-detector and mentioned in the commit. Signed-off-by: Filip Ayazi Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index f6a3a7b7d1ad..3b06c8a360b6 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -155,7 +155,7 @@ static const struct min_max_quirk min_max_pnpid_table[] = { { (const char * const []){"LEN2006", NULL}, {2691, 2691}, - 1024, 5045, 2457, 4632 + 1024, 5045, 2457, 4832 }, { (const char * const []){"LEN2006", NULL}, From 33096777519a66e632fed7f1e54e6480b4228827 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 27 Mar 2015 09:59:55 -0700 Subject: [PATCH 375/567] Input: define INPUT_PROP_ACCELEROMETER behavior Spell out what this property means to userspace. If the property is set, all directional axes must be accelerometer axes, any other axes are left as-is. This allows an accelerometer device to e.g. have an ABS_WHEEL. It is not permitted to mix normal directional axes and accelerometer axes on the same device node. Signed-off-by: Peter Hutterer Acked-by: Jiri Kosina Reviewed-by: Bastien Nocera Signed-off-by: Dmitry Torokhov --- Documentation/input/event-codes.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/input/event-codes.txt b/Documentation/input/event-codes.txt index c587a966413e..96705616f582 100644 --- a/Documentation/input/event-codes.txt +++ b/Documentation/input/event-codes.txt @@ -294,6 +294,12 @@ accordingly. This property does not affect kernel behavior. The kernel does not provide button emulation for such devices but treats them as any other INPUT_PROP_BUTTONPAD device. +INPUT_PROP_ACCELEROMETER +------------------------- +Directional axes on this device (absolute and/or relative x, y, z) represent +accelerometer data. All other axes retain their meaning. A device must not mix +regular directional axes and accelerometer axes on the same event node. + Guidelines: ========== The guidelines below ensure proper single-touch and multi-finger functionality. From d52356e7f48e400ca258c6763a232a92fa82ff68 Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Tue, 31 Mar 2015 18:11:46 +0200 Subject: [PATCH 376/567] powerpc: fix memory corruption by pnv_alloc_idle_core_states Space allocated for paca is based off nr_cpu_ids, but pnv_alloc_idle_core_states() iterates paca with cpu_nr_cores()*threads_per_core, which is using NR_CPUS. This causes pnv_alloc_idle_core_states() to write over memory, which is outside of paca array and may later lead to various panics. Fixes: 7cba160ad789 (powernv/cpuidle: Redesign idle states management) Signed-off-by: Jan Stancek Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/cputhreads.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h index 2bf8e9307be9..4c8ad592ae33 100644 --- a/arch/powerpc/include/asm/cputhreads.h +++ b/arch/powerpc/include/asm/cputhreads.h @@ -55,7 +55,7 @@ static inline cpumask_t cpu_thread_mask_to_cores(const struct cpumask *threads) static inline int cpu_nr_cores(void) { - return NR_CPUS >> threads_shift; + return nr_cpu_ids >> threads_shift; } static inline cpumask_t cpu_online_cores_map(void) From 7e436905780659d6dc12d0581944934bf91a9919 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Wed, 1 Apr 2015 09:42:50 +0800 Subject: [PATCH 377/567] tipc: fix a slab object leak When remove TIPC module, there is a warning to remind us that a slab object is leaked like: root@localhost:~# rmmod tipc [ 19.056226] ============================================================================= [ 19.057549] BUG TIPC (Not tainted): Objects remaining in TIPC on kmem_cache_close() [ 19.058736] ----------------------------------------------------------------------------- [ 19.058736] [ 19.060287] INFO: Slab 0xffffea0000519a00 objects=23 used=1 fp=0xffff880014668b00 flags=0x100000000004080 [ 19.061915] INFO: Object 0xffff880014668000 @offset=0 [ 19.062717] kmem_cache_destroy TIPC: Slab cache still has objects This is because the listening socket of TIPC topology server is not closed before TIPC proto handler is unregistered with proto_unregister(). However, as the socket is closed in tipc_exit_net() which is called by unregister_pernet_subsys() during unregistering TIPC namespace operation, the warning can be eliminated if calling unregister_pernet_subsys() is moved before calling proto_unregister(). Fixes: e05b31f4bf89 ("tipc: make tipc socket support net namespace") Reviewed-by: Erik Hugne Signed-off-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/core.c b/net/tipc/core.c index 935205e6bcfe..be1c9fa60b09 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -152,11 +152,11 @@ out_netlink: static void __exit tipc_exit(void) { tipc_bearer_cleanup(); + unregister_pernet_subsys(&tipc_net_ops); tipc_netlink_stop(); tipc_netlink_compat_stop(); tipc_socket_stop(); tipc_unregister_sysctl(); - unregister_pernet_subsys(&tipc_net_ops); pr_info("Deactivated\n"); } From 2f30232481ef39aa1657ac76b16c47d0c0241a69 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 25 Mar 2015 17:01:03 -0700 Subject: [PATCH 378/567] MAINTAINERS: Update Intel Wired Ethernet Driver info Update the git tree info with a recent change in tree names. Also add our new mailing list created solely for Linux kernel patches and kernel development, as well as the new patchwork project for tracking patches. Lastly update the list of "reviewers" since a couple of developers have moved on to different projects. Made an update to the section header so that it is more manageable going forward as we add new drivers. Signed-off-by: Jeff Kirsher --- MAINTAINERS | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 358eb0105e00..9508870ce2e0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5128,22 +5128,21 @@ M: Deepak Saxena S: Maintained F: drivers/char/hw_random/ixp4xx-rng.c -INTEL ETHERNET DRIVERS (e100/e1000/e1000e/fm10k/igb/igbvf/ixgb/ixgbe/ixgbevf/i40e/i40evf) +INTEL ETHERNET DRIVERS M: Jeff Kirsher -M: Jesse Brandeburg -M: Bruce Allan -M: Carolyn Wyborny -M: Don Skidmore -M: Greg Rose -M: Matthew Vick -M: John Ronciak -M: Mitch Williams -M: Linux NICS -L: e1000-devel@lists.sourceforge.net +R: Jesse Brandeburg +R: Shannon Nelson +R: Carolyn Wyborny +R: Don Skidmore +R: Matthew Vick +R: John Ronciak +R: Mitch Williams +L: intel-wired-lan@lists.osuosl.org W: http://www.intel.com/support/feedback.htm W: http://e1000.sourceforge.net/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net.git -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next.git +Q: http://patchwork.ozlabs.org/project/intel-wired-lan/list/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git S: Supported F: Documentation/networking/e100.txt F: Documentation/networking/e1000.txt From 75fdfc849ae0636853add4b7dbdc5753160ad0cb Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 25 Mar 2015 18:51:57 -0500 Subject: [PATCH 379/567] Fix warning on uninitialized buftype Pointed out by coverity analyzer. resp_buftype is not initialized in one path which can rarely log a spurious warning (buf is null so there will not be a problem with freeing data, but if buf_type were randomly set to wrong value could log a warning) Reported by Coverity (CID 1269144) Signed-off-by: Steve French Acked-by: Shirish Pargaonkar Acked-by: Sachin Prabhu Reviewed-by: Jeff Layton --- fs/cifs/smb2pdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 3417340bf89e..1b906debe11d 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2114,7 +2114,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, struct kvec iov[2]; int rc = 0; int len; - int resp_buftype; + int resp_buftype = CIFS_NO_BUFFER; unsigned char *bufptr; struct TCP_Server_Info *server; struct cifs_ses *ses = tcon->ses; From f3a31a2bbbfe22db0313a4e270c7ba91baa7b630 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 26 Mar 2015 19:23:20 -0500 Subject: [PATCH 380/567] Don't ignore errors on encrypting password in SMBTcon Although unlikely to fail (and tree connect does not commonly send a password since SECMODE_USER is the default for most servers) do not ignore errors on SMBNTEncrypt in SMB Tree Connect. Reported by Coverity (CID 1226853) Signed-off-by: Steve French Acked-by: Shirish Pargaonkar Acked-by: Sachin Prabhu Reviewed-by: Jeff Layton --- fs/cifs/connect.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 4cb8450e081b..cdb1aaf295b1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3696,6 +3696,12 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, #endif /* CIFS_WEAK_PW_HASH */ rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr, nls_codepage); + if (rc) { + cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n", + __func__, rc); + cifs_buf_release(smb_buffer); + return rc; + } bcc_ptr += CIFS_AUTH_RESP_SIZE; if (ses->capabilities & CAP_UNICODE) { From 8e3531060556bf5e09444acd2aa5c78bce9c9f70 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 26 Mar 2015 19:47:02 -0500 Subject: [PATCH 381/567] Fix dereference before null check warning null tcon is not likely in these paths in current code, but obviously it does clarify the code to check for null (if at all) before derefrencing rather than after. Reported by Coverity (CID 1042666) Signed-off-by: Steve French Acked-by: Shirish Pargaonkar Acked-by: Sachin Prabhu --- fs/cifs/smb2pdu.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 1b906debe11d..78b329f07b3b 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1218,7 +1218,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, struct smb2_ioctl_req *req; struct smb2_ioctl_rsp *rsp; struct TCP_Server_Info *server; - struct cifs_ses *ses = tcon->ses; + struct cifs_ses *ses; struct kvec iov[2]; int resp_buftype; int num_iovecs; @@ -1233,6 +1233,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, if (plen) *plen = 0; + if (tcon) + ses = tcon->ses; + else + return -EIO; + if (ses && (ses->server)) server = ses->server; else @@ -1296,14 +1301,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base; if ((rc != 0) && (rc != -EINVAL)) { - if (tcon) - cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); + cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); goto ioctl_exit; } else if (rc == -EINVAL) { if ((opcode != FSCTL_SRV_COPYCHUNK_WRITE) && (opcode != FSCTL_SRV_COPYCHUNK)) { - if (tcon) - cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); + cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); goto ioctl_exit; } } From 064bcc0702a83aed29220bee3b3db3f968c5d8ae Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 26 Mar 2015 22:41:59 -0500 Subject: [PATCH 382/567] Fix coverity warning Coverity reports a warning for referencing the beginning of the SMB2/SMB3 frame using the ProtocolId field as an array. Although it works the same either way, this patch should quiet the warning and might be a little clearer. Reported by Coverity (CID 741269) Signed-off-by: Steve French Acked-by: Shirish Pargaonkar Acked-by: Sachin Prabhu Reviewed-by: Jeff Layton --- fs/cifs/smb2misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 689f035915cf..22dfdf17d065 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -322,7 +322,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr) /* return pointer to beginning of data area, ie offset from SMB start */ if ((*off != 0) && (*len != 0)) - return hdr->ProtocolId + *off; + return (char *)(&hdr->ProtocolId[0]) + *off; else return NULL; } From c85c35f8fc1d3f5ca60cd713f10af387de73cb94 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 27 Mar 2015 01:15:02 -0500 Subject: [PATCH 383/567] Fix warning on impossible comparison workstation_RFC1001_name is part of the struct and can't be null, remove impossible comparison (array vs. null) Pointed out by Coverity (CID 140095) Signed-off-by: Steve French Reviewed-by: Jeff Layton --- fs/cifs/connect.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index cdb1aaf295b1..480cf9c81d50 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2917,8 +2917,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) * calling name ends in null (byte 16) from old smb * convention. */ - if (server->workstation_RFC1001_name && - server->workstation_RFC1001_name[0] != 0) + if (server->workstation_RFC1001_name[0] != 0) rfc1002mangle(ses_init_buf->trailer. session_req.calling_name, server->workstation_RFC1001_name, From 8b7a454443bdb73df4fd200af7f013f3319a3855 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 30 Mar 2015 16:58:17 -0500 Subject: [PATCH 384/567] CIFS: session servername can't be null remove impossible check Pointed out by Coverity (CID 115422) Signed-off-by: Steve French Reviewed-by: Jeff Layton --- fs/cifs/cifsencrypt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 4ac7445e6ec7..aa0dc2573374 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -1,6 +1,9 @@ /* * fs/cifs/cifsencrypt.c * + * Encryption and hashing operations relating to NTLM, NTLMv2. See MS-NLMP + * for more detailed information + * * Copyright (C) International Business Machines Corp., 2005,2013 * Author(s): Steve French (sfrench@us.ibm.com) * @@ -515,7 +518,8 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, __func__); return rc; } - } else if (ses->serverName) { + } else { + /* We use ses->serverName if no domain name available */ len = strlen(ses->serverName); server = kmalloc(2 + (len * 2), GFP_KERNEL); From dfebe40076f3b4966e818eaf94021a7ff788df04 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 27 Mar 2015 01:00:06 -0500 Subject: [PATCH 385/567] Fix another dereference before null check warning null tcon is not possible in these paths so remove confusing null check Reported by Coverity (CID 728519) Signed-off-by: Steve French Reviewed-by: Jeff Layton --- fs/cifs/smb2pdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 78b329f07b3b..65cd7a84c8bc 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1632,7 +1632,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0); - if ((rc != 0) && tcon) + if (rc != 0) cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE); free_rsp_buf(resp_buftype, iov[0].iov_base); From 4c5930e8056127e9a89bb7836bfa34318a89ab14 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 30 Mar 2015 22:03:06 -0500 Subject: [PATCH 386/567] Fix warning Coverity reports a warning due to unitialized attr structure in one code path. Reported by Coverity (CID 728535) Signed-off-by: Steve French Reviewed-by: Jeff Layton --- fs/cifs/inode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 2d4f37235ed0..3e126d7bb2ea 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -771,6 +771,8 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, cifs_buf_release(srchinf->ntwrk_buf_start); } kfree(srchinf); + if (rc) + goto cgii_exit; } else goto cgii_exit; From 8a4b5b0fb765947ff8d254e6078ca64ac0439a66 Mon Sep 17 00:00:00 2001 From: Gerhard Uttenthaler Date: Tue, 24 Mar 2015 19:02:29 +0100 Subject: [PATCH 387/567] can: ems_usb: fix endianess of CAN ID The device expects the CAN ID in little endian format. Signed-off-by: Gerhard Uttenthaler Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/ems_usb.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 9376f5e5b94e..481f5392970a 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -123,7 +123,7 @@ MODULE_LICENSE("GPL v2"); * CPC_MSG_TYPE_EXT_CAN_FRAME or CPC_MSG_TYPE_EXT_RTR_FRAME. */ struct cpc_can_msg { - u32 id; + __le32 id; u8 length; u8 msg[8]; }; @@ -765,7 +765,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne msg = (struct ems_cpc_msg *)&buf[CPC_HEADER_SIZE]; - msg->msg.can_msg.id = cf->can_id & CAN_ERR_MASK; + msg->msg.can_msg.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK); msg->msg.can_msg.length = cf->can_dlc; if (cf->can_id & CAN_RTR_FLAG) { @@ -783,9 +783,6 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne msg->length = CPC_CAN_MSG_MIN_SIZE + cf->can_dlc; } - /* Respect byte order */ - msg->msg.can_msg.id = cpu_to_le32(msg->msg.can_msg.id); - for (i = 0; i < MAX_TX_URBS; i++) { if (dev->tx_contexts[i].echo_index == MAX_TX_URBS) { context = &dev->tx_contexts[i]; From a0bc163a7cf2ceb413a76cfd7149c6591db829ea Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 25 Mar 2015 10:36:17 +0100 Subject: [PATCH 388/567] can: ems_usb: mark timestamp as little endian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct ems_cpc_msg describes the a message received from the USB device, which uses little endian byte order. This patch marks the timestamp in struct ems_cpc_msg accordingly. Acked-by: Gerhard Uttenthaler Acked-by: Uwe Kleine-König Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/ems_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 481f5392970a..866bac0ae7e9 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -200,8 +200,8 @@ struct __packed ems_cpc_msg { u8 type; /* type of message */ u8 length; /* length of data within union 'msg' */ u8 msgid; /* confirmation handle */ - u32 ts_sec; /* timestamp in seconds */ - u32 ts_nsec; /* timestamp in nano seconds */ + __le32 ts_sec; /* timestamp in seconds */ + __le32 ts_nsec; /* timestamp in nano seconds */ union { u8 generic[64]; From 514ac99c64b22d83b52dfee3b8becaa69a92bc4a Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 1 Apr 2015 07:50:28 +0200 Subject: [PATCH 389/567] can: fix multiple delivery of a single CAN frame for overlapping CAN filters The CAN_RAW socket can set multiple CAN identifier specific filters that lead to multiple filters in the af_can.c filter processing. These filters are indenpendent from each other which leads to logical OR'ed filters when applied. This patch makes sure that every CAN frame which is filtered for a specific socket is only delivered once to the user space. This is independent from the number of matching CAN filters of this socket. As the raw_rcv() function is executed from NET_RX softirq the introduced variables are implemented as per-CPU variables to avoid extensive locking at CAN frame reception time. Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- net/can/raw.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/net/can/raw.c b/net/can/raw.c index 63ffdb0f3a23..0c8d537b59b8 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -74,6 +74,11 @@ MODULE_ALIAS("can-proto-1"); * storing the single filter in dfilter, to avoid using dynamic memory. */ +struct uniqframe { + ktime_t tstamp; + const struct sk_buff *skb; +}; + struct raw_sock { struct sock sk; int bound; @@ -86,6 +91,7 @@ struct raw_sock { struct can_filter dfilter; /* default/single filter */ struct can_filter *filter; /* pointer to filter(s) */ can_err_mask_t err_mask; + struct uniqframe __percpu *uniq; }; /* @@ -123,6 +129,15 @@ static void raw_rcv(struct sk_buff *oskb, void *data) if (!ro->fd_frames && oskb->len != CAN_MTU) return; + /* eliminate multiple filter matches for the same skb */ + if (this_cpu_ptr(ro->uniq)->skb == oskb && + ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) { + return; + } else { + this_cpu_ptr(ro->uniq)->skb = oskb; + this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp; + } + /* clone the given skb to be able to enqueue it into the rcv queue */ skb = skb_clone(oskb, GFP_ATOMIC); if (!skb) @@ -297,6 +312,11 @@ static int raw_init(struct sock *sk) ro->recv_own_msgs = 0; ro->fd_frames = 0; + /* alloc_percpu provides zero'ed memory */ + ro->uniq = alloc_percpu(struct uniqframe); + if (unlikely(!ro->uniq)) + return -ENOMEM; + /* set notifier */ ro->notifier.notifier_call = raw_notifier; @@ -339,6 +359,7 @@ static int raw_release(struct socket *sock) ro->ifindex = 0; ro->bound = 0; ro->count = 0; + free_percpu(ro->uniq); sock_orphan(sk); sock->sk = NULL; From a5581ef4c2eac6449188862e903eb46c7233582a Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 1 Apr 2015 07:50:29 +0200 Subject: [PATCH 390/567] can: introduce new raw socket option to join the given CAN filters The CAN_RAW socket can set multiple CAN identifier specific filters that lead to multiple filters in the af_can.c filter processing. These filters are indenpendent from each other which leads to logical OR'ed filters when applied. This socket option joines the given CAN filters in the way that only CAN frames are passed to user space that matched *all* given CAN filters. The semantic for the applied filters is therefore changed to a logical AND. This is useful especially when the filterset is a combination of filters where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or CAN ID ranges from the incoming traffic. As the raw_rcv() function is executed from NET_RX softirq the introduced variables are implemented as per-CPU variables to avoid extensive locking at CAN frame reception time. Signed-off-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde --- Documentation/networking/can.txt | 20 ++++++++++++++++++-- include/uapi/linux/can/raw.h | 1 + net/can/raw.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index 0a2859a8ee7e..5abad1e921ca 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -22,7 +22,8 @@ This file contains 4.1.3 RAW socket option CAN_RAW_LOOPBACK 4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS 4.1.5 RAW socket option CAN_RAW_FD_FRAMES - 4.1.6 RAW socket returned message flags + 4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS + 4.1.7 RAW socket returned message flags 4.2 Broadcast Manager protocol sockets (SOCK_DGRAM) 4.2.1 Broadcast Manager operations 4.2.2 Broadcast Manager message flags @@ -601,7 +602,22 @@ solution for a couple of reasons: CAN FD frames by checking if the device maximum transfer unit is CANFD_MTU. The CAN device MTU can be retrieved e.g. with a SIOCGIFMTU ioctl() syscall. - 4.1.6 RAW socket returned message flags + 4.1.6 RAW socket option CAN_RAW_JOIN_FILTERS + + The CAN_RAW socket can set multiple CAN identifier specific filters that + lead to multiple filters in the af_can.c filter processing. These filters + are indenpendent from each other which leads to logical OR'ed filters when + applied (see 4.1.1). + + This socket option joines the given CAN filters in the way that only CAN + frames are passed to user space that matched *all* given CAN filters. The + semantic for the applied filters is therefore changed to a logical AND. + + This is useful especially when the filterset is a combination of filters + where the CAN_INV_FILTER flag is set in order to notch single CAN IDs or + CAN ID ranges from the incoming traffic. + + 4.1.7 RAW socket returned message flags When using recvmsg() call, the msg->msg_flags may contain following flags: diff --git a/include/uapi/linux/can/raw.h b/include/uapi/linux/can/raw.h index 78ec76fd89a6..8735f1080385 100644 --- a/include/uapi/linux/can/raw.h +++ b/include/uapi/linux/can/raw.h @@ -57,6 +57,7 @@ enum { CAN_RAW_LOOPBACK, /* local loopback (default:on) */ CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */ CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */ + CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */ }; #endif /* !_UAPI_CAN_RAW_H */ diff --git a/net/can/raw.c b/net/can/raw.c index 0c8d537b59b8..31b9748cbb4e 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -77,6 +77,7 @@ MODULE_ALIAS("can-proto-1"); struct uniqframe { ktime_t tstamp; const struct sk_buff *skb; + unsigned int join_rx_count; }; struct raw_sock { @@ -87,6 +88,7 @@ struct raw_sock { int loopback; int recv_own_msgs; int fd_frames; + int join_filters; int count; /* number of active filters */ struct can_filter dfilter; /* default/single filter */ struct can_filter *filter; /* pointer to filter(s) */ @@ -132,10 +134,21 @@ static void raw_rcv(struct sk_buff *oskb, void *data) /* eliminate multiple filter matches for the same skb */ if (this_cpu_ptr(ro->uniq)->skb == oskb && ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) { - return; + if (ro->join_filters) { + this_cpu_inc(ro->uniq->join_rx_count); + /* drop frame until all enabled filters matched */ + if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count) + return; + } else { + return; + } } else { this_cpu_ptr(ro->uniq)->skb = oskb; this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp; + this_cpu_ptr(ro->uniq)->join_rx_count = 1; + /* drop first frame to check all enabled filters? */ + if (ro->join_filters && ro->count > 1) + return; } /* clone the given skb to be able to enqueue it into the rcv queue */ @@ -311,6 +324,7 @@ static int raw_init(struct sock *sk) ro->loopback = 1; ro->recv_own_msgs = 0; ro->fd_frames = 0; + ro->join_filters = 0; /* alloc_percpu provides zero'ed memory */ ro->uniq = alloc_percpu(struct uniqframe); @@ -604,6 +618,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, break; + case CAN_RAW_JOIN_FILTERS: + if (optlen != sizeof(ro->join_filters)) + return -EINVAL; + + if (copy_from_user(&ro->join_filters, optval, optlen)) + return -EFAULT; + + break; + default: return -ENOPROTOOPT; } @@ -668,6 +691,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname, val = &ro->fd_frames; break; + case CAN_RAW_JOIN_FILTERS: + if (len > sizeof(int)) + len = sizeof(int); + val = &ro->join_filters; + break; + default: return -ENOPROTOOPT; } From 79d5eeddd7d23bd4588e370072977928b7075911 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 1 Apr 2015 11:49:59 +0200 Subject: [PATCH 391/567] can: pcan_usb: pcan_usb_fd_send_cmd(): silence compiler warning about uninitialized var This patch silences the compiler warning: drivers/net/can/usb/peak_usb/pcan_usb_fd.c: In function 'pcan_usb_fd_send_cmd': drivers/net/can/usb/peak_usb/pcan_usb_fd.c:185:6: warning: 'err' may be used uninitialized in this function [-Wuninitialized] by initialising the variable as 0. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 0bac0f14edc3..00481eeb9924 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -182,7 +182,7 @@ static inline void *pcan_usb_fd_cmd_buffer(struct peak_usb_device *dev) static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail) { void *cmd_head = pcan_usb_fd_cmd_buffer(dev); - int err; + int err = 0; u8 *packet_ptr; int i, n = 1, packet_len; ptrdiff_t cmd_len; From 80313b3078fcd2ca51970880d90757f05879a193 Mon Sep 17 00:00:00 2001 From: Stefan Lippers-Hollmann Date: Mon, 30 Mar 2015 22:44:27 +0200 Subject: [PATCH 392/567] x86/reboot: Add ASRock Q1900DC-ITX mainboard reboot quirk The ASRock Q1900DC-ITX mainboard (Baytrail-D) hangs randomly in both BIOS and UEFI mode while rebooting unless reboot=pci is used. Add a quirk to reboot via the pci method. The problem is very intermittent and hard to debug, it might succeed rebooting just fine 40 times in a row - but fails half a dozen times the next day. It seems to be slightly less common in BIOS CSM mode than native UEFI (with the CSM disabled), but it does happen in either mode. Since I've started testing this patch in late january, rebooting has been 100% reliable. Most of the time it already hangs during POST, but occasionally it might even make it through the bootloader and the kernel might even start booting, but then hangs before the mode switch. The same symptoms occur with grub-efi, gummiboot and grub-pc, just as well as (at least) kernel 3.16-3.19 and 4.0-rc6 (I haven't tried older kernels than 3.16). Upgrading to the most current mainboard firmware of the ASRock Q1900DC-ITX, version 1.20, does not improve the situation. ( Searching the web seems to suggest that other Bay Trail-D mainboards might be affected as well. ) -- Signed-off-by: Stefan Lippers-Hollmann Cc: Cc: Matt Fleming Link: http://lkml.kernel.org/r/20150330224427.0fb58e42@mir Signed-off-by: Ingo Molnar --- arch/x86/kernel/reboot.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index bae6c609888e..86db4bcd7ce5 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -183,6 +183,16 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { }, }, + /* ASRock */ + { /* Handle problems with rebooting on ASRock Q1900DC-ITX */ + .callback = set_pci_reboot, + .ident = "ASRock Q1900DC-ITX", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASRock"), + DMI_MATCH(DMI_BOARD_NAME, "Q1900DC-ITX"), + }, + }, + /* ASUS */ { /* Handle problems with rebooting on ASUS P4S800 */ .callback = set_bios_reboot, From 788211d81bfdf9b6a547d0530f206ba6ee76b107 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 1 Apr 2015 14:20:42 +0200 Subject: [PATCH 393/567] mac80211: fix RX A-MPDU session reorder timer deletion There's an issue with the way the RX A-MPDU reorder timer is deleted that can cause a kernel crash like this: * tid_rx is removed - call_rcu(ieee80211_free_tid_rx) * station is destroyed * reorder timer fires before ieee80211_free_tid_rx() runs, accessing the station, thus potentially crashing due to the use-after-free The station deletion is protected by synchronize_net(), but that isn't enough -- ieee80211_free_tid_rx() need not have run when that returns (it deletes the timer.) We could use rcu_barrier() instead of synchronize_net(), but that's much more expensive. Instead, to fix this, add a field tracking that the session is being deleted. In this case, the only re-arming of the timer happens with the reorder spinlock held, so make that code not rearm it if the session is being deleted and also delete the timer after setting that field. This ensures the timer cannot fire after ___ieee80211_stop_rx_ba_session() returns, which fixes the problem. Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg --- net/mac80211/agg-rx.c | 8 ++++++-- net/mac80211/rx.c | 7 ++++--- net/mac80211/sta_info.h | 2 ++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index a48bad468880..7702978a4c99 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -49,8 +49,6 @@ static void ieee80211_free_tid_rx(struct rcu_head *h) container_of(h, struct tid_ampdu_rx, rcu_head); int i; - del_timer_sync(&tid_rx->reorder_timer); - for (i = 0; i < tid_rx->buf_size; i++) __skb_queue_purge(&tid_rx->reorder_buf[i]); kfree(tid_rx->reorder_buf); @@ -93,6 +91,12 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, del_timer_sync(&tid_rx->session_timer); + /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */ + spin_lock_bh(&tid_rx->reorder_lock); + tid_rx->removed = true; + spin_unlock_bh(&tid_rx->reorder_lock); + del_timer_sync(&tid_rx->reorder_timer); + call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 944bdc04e913..1eb730bf8752 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -873,9 +873,10 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, set_release_timer: - mod_timer(&tid_agg_rx->reorder_timer, - tid_agg_rx->reorder_time[j] + 1 + - HT_RX_REORDER_BUF_TIMEOUT); + if (!tid_agg_rx->removed) + mod_timer(&tid_agg_rx->reorder_timer, + tid_agg_rx->reorder_time[j] + 1 + + HT_RX_REORDER_BUF_TIMEOUT); } else { del_timer(&tid_agg_rx->reorder_timer); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 925e68fe64c7..fb0fc1302a58 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -175,6 +175,7 @@ struct tid_ampdu_tx { * @reorder_lock: serializes access to reorder buffer, see below. * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and * and ssn. + * @removed: this session is removed (but might have been found due to RCU) * * This structure's lifetime is managed by RCU, assignments to * the array holding it must hold the aggregation mutex. @@ -199,6 +200,7 @@ struct tid_ampdu_rx { u16 timeout; u8 dialog_token; bool auto_seq; + bool removed; }; /** From 3d6b72534a109be4353b161a09a5683b441d0941 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 1 Apr 2015 10:02:19 +0300 Subject: [PATCH 394/567] bnx2x: Fix kdump on 4-port device When running in a kdump kernel, it's very likely that due to sync. loss with management firmware the first PCI function to probe and reach the previous unload flow would decide it can reset the chip and continue onward. While doing so, it will only close its own Rx port. On a 4-port device where 2nd port on engine is a 1g-port, the 2nd port would allow ingress traffic after the chip is reset [assuming it was active on the first kernel]. This would later cause a HW attention. This changes driver flow to close both ports' 1g capabilities during the previous driver unload flow prior to the chip reset. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index ae571a199f2f..e6dec47fec68 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -129,8 +129,8 @@ struct bnx2x_mac_vals { u32 xmac_val; u32 emac_addr; u32 emac_val; - u32 umac_addr; - u32 umac_val; + u32 umac_addr[2]; + u32 umac_val[2]; u32 bmac_addr; u32 bmac_val[2]; }; @@ -10141,6 +10141,25 @@ static u32 bnx2x_get_pretend_reg(struct bnx2x *bp) return base + (BP_ABS_FUNC(bp)) * stride; } +static bool bnx2x_prev_unload_close_umac(struct bnx2x *bp, + u8 port, u32 reset_reg, + struct bnx2x_mac_vals *vals) +{ + u32 mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port; + u32 base_addr; + + if (!(mask & reset_reg)) + return false; + + BNX2X_DEV_INFO("Disable umac Rx %02x\n", port); + base_addr = port ? GRCBASE_UMAC1 : GRCBASE_UMAC0; + vals->umac_addr[port] = base_addr + UMAC_REG_COMMAND_CONFIG; + vals->umac_val[port] = REG_RD(bp, vals->umac_addr[port]); + REG_WR(bp, vals->umac_addr[port], 0); + + return true; +} + static void bnx2x_prev_unload_close_mac(struct bnx2x *bp, struct bnx2x_mac_vals *vals) { @@ -10149,10 +10168,7 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp, u8 port = BP_PORT(bp); /* reset addresses as they also mark which values were changed */ - vals->bmac_addr = 0; - vals->umac_addr = 0; - vals->xmac_addr = 0; - vals->emac_addr = 0; + memset(vals, 0, sizeof(*vals)); reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2); @@ -10201,15 +10217,11 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp, REG_WR(bp, vals->xmac_addr, 0); mac_stopped = true; } - mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port; - if (mask & reset_reg) { - BNX2X_DEV_INFO("Disable umac Rx\n"); - base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0; - vals->umac_addr = base_addr + UMAC_REG_COMMAND_CONFIG; - vals->umac_val = REG_RD(bp, vals->umac_addr); - REG_WR(bp, vals->umac_addr, 0); - mac_stopped = true; - } + + mac_stopped |= bnx2x_prev_unload_close_umac(bp, 0, + reset_reg, vals); + mac_stopped |= bnx2x_prev_unload_close_umac(bp, 1, + reset_reg, vals); } if (mac_stopped) @@ -10505,8 +10517,11 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) /* Close the MAC Rx to prevent BRB from filling up */ bnx2x_prev_unload_close_mac(bp, &mac_vals); - /* close LLH filters towards the BRB */ + /* close LLH filters for both ports towards the BRB */ bnx2x_set_rx_filter(&bp->link_params, 0); + bp->link_params.port ^= 1; + bnx2x_set_rx_filter(&bp->link_params, 0); + bp->link_params.port ^= 1; /* Check if the UNDI driver was previously loaded */ if (bnx2x_prev_is_after_undi(bp)) { @@ -10553,8 +10568,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) if (mac_vals.xmac_addr) REG_WR(bp, mac_vals.xmac_addr, mac_vals.xmac_val); - if (mac_vals.umac_addr) - REG_WR(bp, mac_vals.umac_addr, mac_vals.umac_val); + if (mac_vals.umac_addr[0]) + REG_WR(bp, mac_vals.umac_addr[0], mac_vals.umac_val[0]); + if (mac_vals.umac_addr[1]) + REG_WR(bp, mac_vals.umac_addr[1], mac_vals.umac_val[1]); if (mac_vals.emac_addr) REG_WR(bp, mac_vals.emac_addr, mac_vals.emac_val); if (mac_vals.bmac_addr) { From da254fbc6357a66a127e4e4e234b4f9c555d5ed1 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 1 Apr 2015 10:02:20 +0300 Subject: [PATCH 395/567] bnx2x: Fix kdump when iommu=on When IOMM-vtd is active, once main kernel crashes unfinished DMAE transactions will be blocked, putting the HW in an error state which will cause further transactions to timeout. Current employed logic uses wrong macros, causing the first function to be the only function that cleanups that error state during its probe/load. This patch allows all the functions to successfully re-load in kdump kernel. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index e6dec47fec68..1ec635f54994 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -7866,6 +7866,20 @@ int bnx2x_init_hw_func_cnic(struct bnx2x *bp) return 0; } +/* previous driver DMAE transaction may have occurred when pre-boot stage ended + * and boot began, or when kdump kernel was loaded. Either case would invalidate + * the addresses of the transaction, resulting in was-error bit set in the pci + * causing all hw-to-host pcie transactions to timeout. If this happened we want + * to clear the interrupt which detected this from the pglueb and the was done + * bit + */ +static void bnx2x_clean_pglue_errors(struct bnx2x *bp) +{ + if (!CHIP_IS_E1x(bp)) + REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, + 1 << BP_ABS_FUNC(bp)); +} + static int bnx2x_init_hw_func(struct bnx2x *bp) { int port = BP_PORT(bp); @@ -7958,8 +7972,7 @@ static int bnx2x_init_hw_func(struct bnx2x *bp) bnx2x_init_block(bp, BLOCK_PGLUE_B, init_phase); - if (!CHIP_IS_E1x(bp)) - REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, func); + bnx2x_clean_pglue_errors(bp); bnx2x_init_block(bp, BLOCK_ATC, init_phase); bnx2x_init_block(bp, BLOCK_DMAE, init_phase); @@ -10588,26 +10601,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) return bnx2x_prev_mcp_done(bp); } -/* previous driver DMAE transaction may have occurred when pre-boot stage ended - * and boot began, or when kdump kernel was loaded. Either case would invalidate - * the addresses of the transaction, resulting in was-error bit set in the pci - * causing all hw-to-host pcie transactions to timeout. If this happened we want - * to clear the interrupt which detected this from the pglueb and the was done - * bit - */ -static void bnx2x_prev_interrupted_dmae(struct bnx2x *bp) -{ - if (!CHIP_IS_E1x(bp)) { - u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); - if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { - DP(BNX2X_MSG_SP, - "'was error' bit was found to be set in pglueb upon startup. Clearing\n"); - REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, - 1 << BP_FUNC(bp)); - } - } -} - static int bnx2x_prev_unload(struct bnx2x *bp) { int time_counter = 10; @@ -10617,7 +10610,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp) /* clear hw from errors which may have resulted from an interrupted * dmae transaction. */ - bnx2x_prev_interrupted_dmae(bp); + bnx2x_clean_pglue_errors(bp); /* Release previously held locks */ hw_lock_reg = (BP_FUNC(bp) <= 5) ? From 906a7985f72ee2f28433e2dd847a013da0e4cdea Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 31 Mar 2015 16:05:23 +0200 Subject: [PATCH 396/567] caif: remove unused struct member The tty_name member of struct ser_device is never set or used, so it can be removed. (The definition of struct ser_device is private to this .c file, and the identifier tty_name only occurs in this one place.) Signed-off-by: Rasmus Villemoes Signed-off-by: David S. Miller --- drivers/net/caif/caif_serial.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 27bbc56de15f..9da06537237f 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -70,7 +70,6 @@ struct ser_device { struct tty_struct *tty; bool tx_started; unsigned long state; - char *tty_name; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_tty_dir; struct debugfs_blob_wrapper tx_blob; From 687908c2b6498130172286f3387ec0eb0a20080e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 31 Mar 2015 22:08:45 +0200 Subject: [PATCH 397/567] net: phy: at803x: simplify using devm_gpiod_get_optional and its 4th argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Moreover use devm_gpiod_get_optional instead of ignoring all errors returned by devm_gpiod_get and simplify accordingly. The result is more strict error handling which is good. Signed-off-by: Uwe Kleine-König Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index f80e19ac6704..fabf11d32d27 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -192,16 +192,17 @@ static int at803x_probe(struct phy_device *phydev) { struct device *dev = &phydev->dev; struct at803x_priv *priv; + struct gpio_desc *gpiod_reset; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->gpiod_reset = devm_gpiod_get(dev, "reset"); - if (IS_ERR(priv->gpiod_reset)) - priv->gpiod_reset = NULL; - else - gpiod_direction_output(priv->gpiod_reset, 1); + gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod_reset)) + return PTR_ERR(gpiod_reset); + + priv->gpiod_reset = gpiod_reset; phydev->priv = priv; From e1b7c029a31a26e42c76f763b7cd566ecf62cbd2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 1 Apr 2015 17:03:30 +1030 Subject: [PATCH 398/567] lguest: now needs PCI_DIRECT. Since commit 8e7094694396 ("lguest: add a dummy PCI host bridge.") lguest uses PCI, but it needs you to frob the ports directly. Signed-off-by: Rusty Russell Acked-by: Ingo Molnar Signed-off-by: Linus Torvalds --- drivers/lguest/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig index ee035ec4526b..169172d2ba05 100644 --- a/drivers/lguest/Kconfig +++ b/drivers/lguest/Kconfig @@ -1,6 +1,6 @@ config LGUEST tristate "Linux hypervisor example code" - depends on X86_32 && EVENTFD && TTY + depends on X86_32 && EVENTFD && TTY && PCI_DIRECT select HVC_DRIVER ---help--- This is a very simple module which allows you to run From 8d88c6ebb34c3e54debe81e9b0d81b60411f8179 Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Wed, 1 Apr 2015 00:40:00 -0700 Subject: [PATCH 399/567] net: bcmgenet: enable MoCA link state change detection Currently, MoCA fixed PHYs are always in link-up state, regardless of whether the link is actually up or not. Add code to properly detect MoCA link state changes and to reflect the new state in MoCA fixed PHY. Only GENET V3 and V4 MACs are capable of detecting MoCA link state changes. The code works as follows: 1. GENET MAC detects MoCA link state change and issues UMAC_IRQ_LINK_UP or UMAC_IRQ_LINK_DOWN interrupt. 2. Link up/down interrupt is processed in bcmgenet_irq_task(), which calls phy_mac_interrupt(). 3. phy_mac_interrupt() updates the fixed PHY phydev->link and kicks the PHY state machine. 4. PHY state machine proceeds to read the fixed PHY link status register. 5. When the fixed PHY link status register is being read, the new function bcmgenet_fixed_phy_link_update() gets called. It copies the fixed PHY phydev->link value to the fixed PHY status->link. 6. PHY state machine receives the new link state of the fixed PHY. 7. MoCA fixed PHY link state now correctly reflects the real MoCA hardware link state. Signed-off-by: Petri Gynther Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 +++++++-- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 + drivers/net/ethernet/broadcom/genet/bcmmii.c | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index f7855a61e7ad..6043734ea613 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1734,6 +1734,9 @@ static int init_umac(struct bcmgenet_priv *priv) } else if (priv->ext_phy) { int0_enable |= UMAC_IRQ_LINK_EVENT; } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { + if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) + int0_enable |= UMAC_IRQ_LINK_EVENT; + reg = bcmgenet_bp_mc_get(priv); reg |= BIT(priv->hw_params->bp_in_en_shift); @@ -2926,7 +2929,8 @@ static struct bcmgenet_hw_params bcmgenet_hw_params[] = { .rdma_offset = 0x10000, .tdma_offset = 0x11000, .words_per_bd = 2, - .flags = GENET_HAS_EXT | GENET_HAS_MDIO_INTR, + .flags = GENET_HAS_EXT | GENET_HAS_MDIO_INTR | + GENET_HAS_MOCA_LINK_DET, }, [GENET_V4] = { .tx_queues = 4, @@ -2944,7 +2948,8 @@ static struct bcmgenet_hw_params bcmgenet_hw_params[] = { .rdma_offset = 0x2000, .tdma_offset = 0x4000, .words_per_bd = 3, - .flags = GENET_HAS_40BITS | GENET_HAS_EXT | GENET_HAS_MDIO_INTR, + .flags = GENET_HAS_40BITS | GENET_HAS_EXT | + GENET_HAS_MDIO_INTR | GENET_HAS_MOCA_LINK_DET, }, }; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index ddaa40cb0f21..6f2887a5e0be 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -508,6 +508,7 @@ enum bcmgenet_version { #define GENET_HAS_40BITS (1 << 0) #define GENET_HAS_EXT (1 << 1) #define GENET_HAS_MDIO_INTR (1 << 2) +#define GENET_HAS_MOCA_LINK_DET (1 << 3) /* BCMGENET hardware parameters, keep this structure nicely aligned * since it is going to be used in hot paths diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 6d3b66a103cc..e7651b3c6c57 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -462,6 +462,15 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) return 0; } +static int bcmgenet_fixed_phy_link_update(struct net_device *dev, + struct fixed_phy_status *status) +{ + if (dev && dev->phydev && status) + status->link = dev->phydev->link; + + return 0; +} + static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv) { struct device *kdev = &priv->pdev->dev; @@ -513,6 +522,13 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv) dev_err(kdev, "failed to register fixed PHY device\n"); return -ENODEV; } + + if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) { + ret = fixed_phy_set_link_update( + phydev, bcmgenet_fixed_phy_link_update); + if (!ret) + phydev->link = 0; + } } priv->phydev = phydev; From 9ca683c6d1482714a12170632afb74d43f0ece5a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 1 Apr 2015 08:49:24 -0700 Subject: [PATCH 400/567] chelsio cxgb/cxgb3: Make stats_strings arrays const Move ~2KB of strings in each driver from data to text. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb/cxgb2.c | 2 +- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c index 186566bfdbc8..f5f1b0b51ebd 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c +++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c @@ -354,7 +354,7 @@ static void set_msglevel(struct net_device *dev, u32 val) adapter->msg_enable = val; } -static char stats_strings[][ETH_GSTRING_LEN] = { +static const char stats_strings[][ETH_GSTRING_LEN] = { "TxOctetsOK", "TxOctetsBad", "TxUnicastFramesOK", diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index db76f7040455..b96e4bfcac41 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -1537,7 +1537,7 @@ static void set_msglevel(struct net_device *dev, u32 val) adapter->msg_enable = val; } -static char stats_strings[][ETH_GSTRING_LEN] = { +static const char stats_strings[][ETH_GSTRING_LEN] = { "TxOctetsOK ", "TxFramesOK ", "TxMulticastFramesOK", From 7ef65a42111270f343b26673c10e48180871326b Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 1 Apr 2015 21:41:15 +0530 Subject: [PATCH 401/567] cxgb4: Firmware macro changes for fw verison 1.13.32.0 Adds new macro and few macro changes for fw version 1.13.32.0 also changes version string in driver to match 1.13.32.0 Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 39 ++++++++++++++++++- .../net/ethernet/chelsio/cxgb4/t4fw_version.h | 8 ++-- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 9b353a88cbda..a4a19e0ec7f5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -101,7 +101,7 @@ enum fw_wr_opcodes { FW_RI_BIND_MW_WR = 0x18, FW_RI_FR_NSMR_WR = 0x19, FW_RI_INV_LSTAG_WR = 0x1a, - FW_LASTC2E_WR = 0x40 + FW_LASTC2E_WR = 0x70 }; struct fw_wr_hdr { @@ -993,6 +993,7 @@ enum fw_memtype_cf { FW_MEMTYPE_CF_EXTMEM = 0x2, FW_MEMTYPE_CF_FLASH = 0x4, FW_MEMTYPE_CF_INTERNAL = 0x5, + FW_MEMTYPE_CF_EXTMEM1 = 0x6, }; struct fw_caps_config_cmd { @@ -1035,6 +1036,7 @@ enum fw_params_mnem { FW_PARAMS_MNEM_PFVF = 2, /* function params */ FW_PARAMS_MNEM_REG = 3, /* limited register access */ FW_PARAMS_MNEM_DMAQ = 4, /* dma queue params */ + FW_PARAMS_MNEM_CHNET = 5, /* chnet params */ FW_PARAMS_MNEM_LAST }; @@ -3102,7 +3104,8 @@ enum fw_devlog_facility { FW_DEVLOG_FACILITY_FCOE = 0x2E, FW_DEVLOG_FACILITY_FOISCSI = 0x30, FW_DEVLOG_FACILITY_FOFCOE = 0x32, - FW_DEVLOG_FACILITY_MAX = 0x32, + FW_DEVLOG_FACILITY_CHNET = 0x34, + FW_DEVLOG_FACILITY_MAX = 0x34, }; /* log message format */ @@ -3139,4 +3142,36 @@ struct fw_devlog_cmd { (((x) >> FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S) & \ FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M) +/* P C I E F W P F 7 R E G I S T E R */ + +/* PF7 stores the Firmware Device Log parameters which allows Host Drivers to + * access the "devlog" which needing to contact firmware. The encoding is + * mostly the same as that returned by the DEVLOG command except for the size + * which is encoded as the number of entries in multiples-1 of 128 here rather + * than the memory size as is done in the DEVLOG command. Thus, 0 means 128 + * and 15 means 2048. This of course in turn constrains the allowed values + * for the devlog size ... + */ +#define PCIE_FW_PF_DEVLOG 7 + +#define PCIE_FW_PF_DEVLOG_NENTRIES128_S 28 +#define PCIE_FW_PF_DEVLOG_NENTRIES128_M 0xf +#define PCIE_FW_PF_DEVLOG_NENTRIES128_V(x) \ + ((x) << PCIE_FW_PF_DEVLOG_NENTRIES128_S) +#define PCIE_FW_PF_DEVLOG_NENTRIES128_G(x) \ + (((x) >> PCIE_FW_PF_DEVLOG_NENTRIES128_S) & \ + PCIE_FW_PF_DEVLOG_NENTRIES128_M) + +#define PCIE_FW_PF_DEVLOG_ADDR16_S 4 +#define PCIE_FW_PF_DEVLOG_ADDR16_M 0xffffff +#define PCIE_FW_PF_DEVLOG_ADDR16_V(x) ((x) << PCIE_FW_PF_DEVLOG_ADDR16_S) +#define PCIE_FW_PF_DEVLOG_ADDR16_G(x) \ + (((x) >> PCIE_FW_PF_DEVLOG_ADDR16_S) & PCIE_FW_PF_DEVLOG_ADDR16_M) + +#define PCIE_FW_PF_DEVLOG_MEMTYPE_S 0 +#define PCIE_FW_PF_DEVLOG_MEMTYPE_M 0xf +#define PCIE_FW_PF_DEVLOG_MEMTYPE_V(x) ((x) << PCIE_FW_PF_DEVLOG_MEMTYPE_S) +#define PCIE_FW_PF_DEVLOG_MEMTYPE_G(x) \ + (((x) >> PCIE_FW_PF_DEVLOG_MEMTYPE_S) & PCIE_FW_PF_DEVLOG_MEMTYPE_M) + #endif /* _T4FW_INTERFACE_H_ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h index e2bd3f747858..b9d1cbac0eee 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h @@ -36,13 +36,13 @@ #define __T4FW_VERSION_H__ #define T4FW_VERSION_MAJOR 0x01 -#define T4FW_VERSION_MINOR 0x0C -#define T4FW_VERSION_MICRO 0x19 +#define T4FW_VERSION_MINOR 0x0D +#define T4FW_VERSION_MICRO 0x20 #define T4FW_VERSION_BUILD 0x00 #define T5FW_VERSION_MAJOR 0x01 -#define T5FW_VERSION_MINOR 0x0C -#define T5FW_VERSION_MICRO 0x19 +#define T5FW_VERSION_MINOR 0x0D +#define T5FW_VERSION_MICRO 0x20 #define T5FW_VERSION_BUILD 0x00 #endif From ae469b68a557d1bd538c9122eaf99cf09fc242f2 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 1 Apr 2015 21:41:16 +0530 Subject: [PATCH 402/567] cxgb4: Fix to dump devlog, even if FW is crashed Add new Common Code routines to retrieve Firmware Device Log parameters from PCIE_FW_PF[7]. The firmware initializes its Device Log very early on and stores the parameters for its location/size in that register. Using the parameters from the register allows us to access the Firmware Device Log even when the firmware crashes very early on or we're not attached to the firmware Based on original work by Casey Leedom Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 + .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 33 +++--------- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 53 +++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 3 ++ 4 files changed, 65 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 8816c645de7d..c6ff4890d171 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1136,6 +1136,8 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter, unsigned int qtimer_val(const struct adapter *adap, const struct sge_rspq *q); + +int t4_init_devlog_params(struct adapter *adapter); int t4_init_sge_params(struct adapter *adapter); int t4_init_tp_params(struct adapter *adap); int t4_filter_field_shift(const struct adapter *adap, int filter_sel); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 826de7a7f83c..d92995138f7e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -5110,10 +5110,15 @@ static int adap_init0(struct adapter *adap) enum dev_state state; u32 params[7], val[7]; struct fw_caps_config_cmd caps_cmd; - struct fw_devlog_cmd devlog_cmd; - u32 devlog_meminfo; int reset = 1; + /* Grab Firmware Device Log parameters as early as possible so we have + * access to it for debugging, etc. + */ + ret = t4_init_devlog_params(adap); + if (ret < 0) + return ret; + /* Contact FW, advertising Master capability */ ret = t4_fw_hello(adap, adap->mbox, adap->mbox, MASTER_MAY, &state); if (ret < 0) { @@ -5191,30 +5196,6 @@ static int adap_init0(struct adapter *adap) if (ret < 0) goto bye; - /* Read firmware device log parameters. We really need to find a way - * to get these parameters initialized with some default values (which - * are likely to be correct) for the case where we either don't - * attache to the firmware or it's crashed when we probe the adapter. - * That way we'll still be able to perform early firmware startup - * debugging ... If the request to get the Firmware's Device Log - * parameters fails, we'll live so we don't make that a fatal error. - */ - memset(&devlog_cmd, 0, sizeof(devlog_cmd)); - devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) | - FW_CMD_REQUEST_F | FW_CMD_READ_F); - devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd)); - ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd), - &devlog_cmd); - if (ret == 0) { - devlog_meminfo = - ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog); - adap->params.devlog.memtype = - FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo); - adap->params.devlog.start = - FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4; - adap->params.devlog.size = ntohl(devlog_cmd.memsize_devlog); - } - /* * Find out what ports are available to us. Note that we need to do * this before calling adap_init0_no_config() since it needs nports diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 1abdfa123c6c..ee394dc68303 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -4458,6 +4458,59 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter, return 0; } +/** + * t4_init_devlog_params - initialize adapter->params.devlog + * @adap: the adapter + * + * Initialize various fields of the adapter's Firmware Device Log + * Parameters structure. + */ +int t4_init_devlog_params(struct adapter *adap) +{ + struct devlog_params *dparams = &adap->params.devlog; + u32 pf_dparams; + unsigned int devlog_meminfo; + struct fw_devlog_cmd devlog_cmd; + int ret; + + /* If we're dealing with newer firmware, the Device Log Paramerters + * are stored in a designated register which allows us to access the + * Device Log even if we can't talk to the firmware. + */ + pf_dparams = + t4_read_reg(adap, PCIE_FW_REG(PCIE_FW_PF_A, PCIE_FW_PF_DEVLOG)); + if (pf_dparams) { + unsigned int nentries, nentries128; + + dparams->memtype = PCIE_FW_PF_DEVLOG_MEMTYPE_G(pf_dparams); + dparams->start = PCIE_FW_PF_DEVLOG_ADDR16_G(pf_dparams) << 4; + + nentries128 = PCIE_FW_PF_DEVLOG_NENTRIES128_G(pf_dparams); + nentries = (nentries128 + 1) * 128; + dparams->size = nentries * sizeof(struct fw_devlog_e); + + return 0; + } + + /* Otherwise, ask the firmware for it's Device Log Parameters. + */ + memset(&devlog_cmd, 0, sizeof(devlog_cmd)); + devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) | + FW_CMD_REQUEST_F | FW_CMD_READ_F); + devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd)); + ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd), + &devlog_cmd); + if (ret) + return ret; + + devlog_meminfo = ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog); + dparams->memtype = FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo); + dparams->start = FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4; + dparams->size = ntohl(devlog_cmd.memsize_devlog); + + return 0; +} + /** * t4_init_sge_params - initialize adap->params.sge * @adapter: the adapter diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 231a725f6d5d..326674b19983 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -63,6 +63,8 @@ #define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) #define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) +#define PCIE_FW_REG(reg_addr, idx) ((reg_addr) + (idx) * 4) + #define SGE_PF_KDOORBELL_A 0x0 #define QID_S 15 @@ -707,6 +709,7 @@ #define PFNUM_V(x) ((x) << PFNUM_S) #define PCIE_FW_A 0x30b8 +#define PCIE_FW_PF_A 0x30bc #define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A 0x5908 From bd50752034e4c4847d413e812f554f1bde1e668c Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Mon, 30 Mar 2015 14:25:43 -0700 Subject: [PATCH 403/567] crypto: af_alg - make exports consistant Use EXPORT_SYMBOL_GPL instead of EXPORT_SYMBOL. Signed-off-by: Tadeusz Struk Signed-off-by: David S. Miller --- crypto/af_alg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 26089d182cb7..f22cc56fd1b3 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -381,7 +381,7 @@ void af_alg_link_sg(struct af_alg_sgl *sgl_prev, struct af_alg_sgl *sgl_new) sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); sg_chain(sgl_prev->sg, sgl_prev->npages + 1, sgl_new->sg); } -EXPORT_SYMBOL(af_alg_link_sg); +EXPORT_SYMBOL_GPL(af_alg_link_sg); void af_alg_free_sg(struct af_alg_sgl *sgl) { From 82d929207a11402f9cfe2131013a94939967828a Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Mon, 30 Mar 2015 14:25:44 -0700 Subject: [PATCH 404/567] crypto: algif - use kmalloc instead of kzalloc No need to use kzalloc to allocate sgls as the structure is initialized anyway. Signed-off-by: Tadeusz Struk Signed-off-by: David S. Miller --- crypto/algif_skcipher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 60496d405ebf..2db1eb776932 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -583,7 +583,7 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, rsgl = &sreq->first_sgl; list_add_tail(&rsgl->list, &sreq->list); } else { - rsgl = kzalloc(sizeof(*rsgl), GFP_KERNEL); + rsgl = kmalloc(sizeof(*rsgl), GFP_KERNEL); if (!rsgl) { err = -ENOMEM; goto free; From f1a8ff21d083c6b37bba9e4ad2c1d899ae41f75d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 1 Apr 2015 12:29:13 -0700 Subject: [PATCH 405/567] vxge: Add const to ethtool_driver_stats_keys Move about half a KB of data to text. Miscellanea: o Move strings out of the .h file into the .c file in case the .h file is ever #included twice Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- .../net/ethernet/neterion/vxge/vxge-ethtool.c | 19 +++++++++++++++++++ .../net/ethernet/neterion/vxge/vxge-ethtool.h | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c index b07d552a27d4..be916eb2f2e7 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c @@ -18,6 +18,25 @@ #include "vxge-ethtool.h" +static const char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { + {"\n DRIVER STATISTICS"}, + {"vpaths_opened"}, + {"vpath_open_fail_cnt"}, + {"link_up_cnt"}, + {"link_down_cnt"}, + {"tx_frms"}, + {"tx_errors"}, + {"tx_bytes"}, + {"txd_not_free"}, + {"txd_out_of_desc"}, + {"rx_frms"}, + {"rx_errors"}, + {"rx_bytes"}, + {"rx_mcast"}, + {"pci_map_fail_cnt"}, + {"skb_alloc_fail_cnt"} +}; + /** * vxge_ethtool_sset - Sets different link parameters. * @dev: device pointer. diff --git a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.h b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.h index 6cf3044d7f43..065a2c0429a4 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.h +++ b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.h @@ -19,25 +19,6 @@ /* Ethtool related variables and Macros. */ static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset); -static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { - {"\n DRIVER STATISTICS"}, - {"vpaths_opened"}, - {"vpath_open_fail_cnt"}, - {"link_up_cnt"}, - {"link_down_cnt"}, - {"tx_frms"}, - {"tx_errors"}, - {"tx_bytes"}, - {"txd_not_free"}, - {"txd_out_of_desc"}, - {"rx_frms"}, - {"rx_errors"}, - {"rx_bytes"}, - {"rx_mcast"}, - {"pci_map_fail_cnt"}, - {"skb_alloc_fail_cnt"} -}; - #define VXGE_TITLE_LEN 5 #define VXGE_HW_VPATH_STATS_LEN 27 #define VXGE_HW_AGGR_STATS_LEN 13 From 7887456e9da0fc57e8cc5ab50743539440e50750 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 1 Apr 2015 15:33:08 -0700 Subject: [PATCH 406/567] vmxnet3: spelling fixes Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 4c8a944d58b4..c1d0e7a9da04 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -104,7 +104,7 @@ vmxnet3_rq_driver_stats[] = { rx_buf_alloc_failure) }, }; -/* gloabl stats maintained by the driver */ +/* global stats maintained by the driver */ static const struct vmxnet3_stat_desc vmxnet3_global_stats[] = { /* description, offset */ @@ -272,7 +272,7 @@ int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features) adapter->shared->devRead.misc.uptFeatures &= ~UPT1_F_RXCSUM; - /* update harware LRO capability accordingly */ + /* update hardware LRO capability accordingly */ if (features & NETIF_F_LRO) adapter->shared->devRead.misc.uptFeatures |= UPT1_F_LRO; From c4b495128c5d941607179f18ec07c36bd2a3fc38 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 2 Apr 2015 11:17:58 +0900 Subject: [PATCH 407/567] vxlan: correct spelling in comments Fix some spelling / typos: * droppped -> dropped * asddress -> address * compatbility -> compatibility Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index a8d345054d23..b5fecb49a0c6 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -989,7 +989,7 @@ out: /* Watch incoming packets to learn mapping between Ethernet address * and Tunnel endpoint. - * Return true if packet is bogus and should be droppped. + * Return true if packet is bogus and should be dropped. */ static bool vxlan_snoop(struct net_device *dev, union vxlan_addr *src_ip, const u8 *src_mac) @@ -1085,7 +1085,7 @@ void vxlan_sock_release(struct vxlan_sock *vs) EXPORT_SYMBOL_GPL(vxlan_sock_release); /* Update multicast group membership when first VNI on - * multicast asddress is brought up + * multicast address is brought up */ static int vxlan_igmp_join(struct vxlan_dev *vxlan) { @@ -1229,7 +1229,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) * this as a malformed packet. This behavior diverges from * VXLAN RFC (RFC7348) which stipulates that bits in reserved * in reserved fields are to be ignored. The approach here - * maintains compatbility with previous stack code, and also + * maintains compatibility with previous stack code, and also * is more robust and provides a little more security in * adding extensions to VXLAN. */ From 05e8bb860b55acc2646b59cd5746c6b4189fa29e Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 2 Apr 2015 11:20:23 +0900 Subject: [PATCH 408/567] pkt_sched: fq: correct spelling of locally Correct spelling of locally. Also remove extra space before tab character in struct fq_flow. Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- net/sched/sch_fq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index dfcea20e3171..f377702d4b91 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Meant to be mostly used for localy generated traffic : + * Meant to be mostly used for locally generated traffic : * Fast classification depends on skb->sk being set before reaching us. * If not, (router workload), we use rxhash as fallback, with 32 bits wide hash. * All packets belonging to a socket are considered as a 'flow'. @@ -63,7 +63,7 @@ struct fq_flow { struct sk_buff *tail; /* last skb in the list */ unsigned long age; /* jiffies when flow was emptied, for gc */ }; - struct rb_node fq_node; /* anchor in fq_root[] trees */ + struct rb_node fq_node; /* anchor in fq_root[] trees */ struct sock *sk; int qlen; /* number of packets in flow queue */ int credit; From 0d65da4a238d3e9fc358b8e1540a193d63f92e20 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 2 Apr 2015 04:06:29 +0200 Subject: [PATCH 409/567] net: dsa: mv88e6131: Use common initialization functions Common initialization functions will be needed to enable HW bridging support. Signed-off-by: Guenter Roeck Reviewed-by: Andrew Lunn Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6131.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 2540ef0142af..0252d51c0a74 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -208,28 +208,6 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) val |= 0x0100; REG_WRITE(addr, 0x04, val); - /* Port Control 1: disable trunking. Also, if this is the - * CPU port, enable learn messages to be sent to this port. - */ - REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000); - - /* Port based VLAN map: give each port its own address - * database, allow the CPU port to talk to each of the 'real' - * ports, and allow each of the 'real' ports to only talk to - * the upstream port. - */ - val = (p & 0xf) << 12; - if (dsa_is_cpu_port(ds, p)) - val |= ds->phys_port_mask; - else - val |= 1 << dsa_upstream_port(ds); - REG_WRITE(addr, 0x06, val); - - /* Default VLAN ID and priority: don't set a default VLAN - * ID, and set the default packet priority to zero. - */ - REG_WRITE(addr, 0x07, 0x0000); - /* Port Control 2: don't force a good FCS, don't use * VLAN-based, source address-based or destination * address-based priority overrides, don't let the switch @@ -278,20 +256,19 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) */ REG_WRITE(addr, 0x19, 0x7654); - return 0; + return mv88e6xxx_setup_port_common(ds, p); } static int mv88e6131_setup(struct dsa_switch *ds) { - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int i; int ret; - mutex_init(&ps->smi_mutex); - mv88e6xxx_ppu_state_init(ds); - mutex_init(&ps->stats_mutex); + ret = mv88e6xxx_setup_common(ds); + if (ret < 0) + return ret; - ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0; + mv88e6xxx_ppu_state_init(ds); ret = mv88e6131_switch_reset(ds); if (ret < 0) From b2eb06627718836f7d133141693ec9685b4c4ef5 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 2 Apr 2015 04:06:30 +0200 Subject: [PATCH 410/567] net: dsa: mv88e6xxx: Move switch product IDs into common include file This will let us use the switch product IDs in the common source code. Signed-off-by: Guenter Roeck Reviewed-by: Andrew Lunn Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6131.c | 6 ------ drivers/net/dsa/mv88e6171.c | 4 ---- drivers/net/dsa/mv88e6xxx.h | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 0252d51c0a74..f0dea2d1581e 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -17,12 +17,6 @@ #include #include "mv88e6xxx.h" -/* Switch product IDs */ -#define ID_6085 0x04a0 -#define ID_6095 0x0950 -#define ID_6131 0x1060 -#define ID_6131_B2 0x1066 - static char *mv88e6131_probe(struct device *host_dev, int sw_addr) { struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev); diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 18cfead83dc9..639bd83b76c7 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -17,10 +17,6 @@ #include #include "mv88e6xxx.h" -/* Switch product IDs */ -#define ID_6171 0x1710 -#define ID_6172 0x1720 - static char *mv88e6171_probe(struct device *host_dev, int sw_addr) { struct mii_bus *bus = dsa_host_dev_to_mii_bus(host_dev); diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index aaf239aba726..aca48792db4b 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -11,6 +11,42 @@ #ifndef __MV88E6XXX_H #define __MV88E6XXX_H +/* switch product IDs */ + +#define ID_6085 0x04a0 +#define ID_6095 0x0950 + +#define ID_6123 0x1210 +#define ID_6123_A1 0x1212 +#define ID_6123_A2 0x1213 + +#define ID_6131 0x1060 +#define ID_6131_B2 0x1066 + +#define ID_6152 0x1a40 +#define ID_6155 0x1a50 + +#define ID_6161 0x1610 +#define ID_6161_A1 0x1612 +#define ID_6161_A2 0x1613 + +#define ID_6165 0x1650 +#define ID_6165_A1 0x1652 +#define ID_6165_A2 0x1653 + +#define ID_6171 0x1710 +#define ID_6172 0x1720 +#define ID_6176 0x1760 + +#define ID_6182 0x1a60 +#define ID_6185 0x1a70 + +#define ID_6352 0x3520 +#define ID_6352_A0 0x3521 +#define ID_6352_A1 0x3522 + +/* Registers */ + #define REG_PORT(p) (0x10 + (p)) #define REG_GLOBAL 0x1b #define REG_GLOBAL2 0x1c From d198893e73c66ceb36cc1b1c3f261e82b7cc5700 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 2 Apr 2015 04:06:31 +0200 Subject: [PATCH 411/567] net: dsa: mv88e6131: Determine and use number of switch ports Determine and use number of switch ports from chip ID instead of always using the maximum, and return error when an attempt is made to access a non-existing port. Signed-off-by: Guenter Roeck Reviewed-by: Andrew Lunn Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6131.c | 42 ++++++++++++++++++++++++++++++------- drivers/net/dsa/mv88e6xxx.h | 1 + 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index f0dea2d1581e..6b818fde2216 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -44,12 +44,13 @@ static char *mv88e6131_probe(struct device *host_dev, int sw_addr) static int mv88e6131_switch_reset(struct dsa_switch *ds) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int i; int ret; unsigned long timeout; /* Set all ports to the disabled state. */ - for (i = 0; i < 11; i++) { + for (i = 0; i < ps->num_ports; i++) { ret = REG_READ(REG_PORT(i), 0x04); REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); } @@ -255,6 +256,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) static int mv88e6131_setup(struct dsa_switch *ds) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int i; int ret; @@ -264,6 +266,21 @@ static int mv88e6131_setup(struct dsa_switch *ds) mv88e6xxx_ppu_state_init(ds); + switch (ps->id) { + case ID_6085: + ps->num_ports = 10; + break; + case ID_6095: + ps->num_ports = 11; + break; + case ID_6131: + case ID_6131_B2: + ps->num_ports = 8; + break; + default: + return -ENODEV; + } + ret = mv88e6131_switch_reset(ds); if (ret < 0) return ret; @@ -274,7 +291,7 @@ static int mv88e6131_setup(struct dsa_switch *ds) if (ret < 0) return ret; - for (i = 0; i < 11; i++) { + for (i = 0; i < ps->num_ports; i++) { ret = mv88e6131_setup_port(ds, i); if (ret < 0) return ret; @@ -283,17 +300,24 @@ static int mv88e6131_setup(struct dsa_switch *ds) return 0; } -static int mv88e6131_port_to_phy_addr(int port) +static int mv88e6131_port_to_phy_addr(struct dsa_switch *ds, int port) { - if (port >= 0 && port <= 11) + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + if (port >= 0 && port < ps->num_ports) return port; - return -1; + + return -EINVAL; } static int mv88e6131_phy_read(struct dsa_switch *ds, int port, int regnum) { - int addr = mv88e6131_port_to_phy_addr(port); + int addr = mv88e6131_port_to_phy_addr(ds, port); + + if (addr < 0) + return addr; + return mv88e6xxx_phy_read_ppu(ds, addr, regnum); } @@ -301,7 +325,11 @@ static int mv88e6131_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) { - int addr = mv88e6131_port_to_phy_addr(port); + int addr = mv88e6131_port_to_phy_addr(ds, port); + + if (addr < 0) + return addr; + return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val); } diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index aca48792db4b..ef058444bdb7 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -109,6 +109,7 @@ struct mv88e6xxx_priv_state { struct mutex eeprom_mutex; int id; /* switch product id */ + int num_ports; /* number of switch ports */ /* hw bridging */ From 14ef6ad22a2db28021e8ea8cd068fe5fcd88de7b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 2 Apr 2015 04:06:32 +0200 Subject: [PATCH 412/567] net: dsa: mv88e6123_61_65: Determine and use number of switch ports Determine and use number of switch ports from chip ID instead of always using the maximum, and return error when an attempt is made to access a non-existing port. Signed-off-by: Guenter Roeck Reviewed-by: Andrew Lunn Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6123_61_65.c | 54 ++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c index 2d7e1ffe9fdc..6480f77829ef 100644 --- a/drivers/net/dsa/mv88e6123_61_65.c +++ b/drivers/net/dsa/mv88e6123_61_65.c @@ -27,25 +27,25 @@ static char *mv88e6123_61_65_probe(struct device *host_dev, int sw_addr) ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); if (ret >= 0) { - if (ret == 0x1212) + if (ret == ID_6123_A1) return "Marvell 88E6123 (A1)"; - if (ret == 0x1213) + if (ret == ID_6123_A2) return "Marvell 88E6123 (A2)"; - if ((ret & 0xfff0) == 0x1210) + if ((ret & 0xfff0) == ID_6123) return "Marvell 88E6123"; - if (ret == 0x1612) + if (ret == ID_6161_A1) return "Marvell 88E6161 (A1)"; - if (ret == 0x1613) + if (ret == ID_6161_A2) return "Marvell 88E6161 (A2)"; - if ((ret & 0xfff0) == 0x1610) + if ((ret & 0xfff0) == ID_6161) return "Marvell 88E6161"; - if (ret == 0x1652) + if (ret == ID_6165_A1) return "Marvell 88E6165 (A1)"; - if (ret == 0x1653) + if (ret == ID_6165_A2) return "Marvell 88e6165 (A2)"; - if ((ret & 0xfff0) == 0x1650) + if ((ret & 0xfff0) == ID_6165) return "Marvell 88E6165"; } @@ -54,12 +54,13 @@ static char *mv88e6123_61_65_probe(struct device *host_dev, int sw_addr) static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int i; int ret; unsigned long timeout; /* Set all ports to the disabled state. */ - for (i = 0; i < 8; i++) { + for (i = 0; i < ps->num_ports; i++) { ret = REG_READ(REG_PORT(i), 0x04); REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); } @@ -271,6 +272,7 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p) static int mv88e6123_61_65_setup(struct dsa_switch *ds) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int i; int ret; @@ -278,6 +280,18 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) if (ret < 0) return ret; + switch (ps->id) { + case ID_6123: + ps->num_ports = 3; + break; + case ID_6161: + case ID_6165: + ps->num_ports = 6; + break; + default: + return -ENODEV; + } + ret = mv88e6123_61_65_switch_reset(ds); if (ret < 0) return ret; @@ -288,7 +302,7 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) if (ret < 0) return ret; - for (i = 0; i < 6; i++) { + for (i = 0; i < ps->num_ports; i++) { ret = mv88e6123_61_65_setup_port(ds, i); if (ret < 0) return ret; @@ -297,20 +311,25 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) return 0; } -static int mv88e6123_61_65_port_to_phy_addr(int port) +static int mv88e6123_61_65_port_to_phy_addr(struct dsa_switch *ds, int port) { - if (port >= 0 && port <= 4) + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + if (port >= 0 && port < ps->num_ports) return port; - return -1; + return -EINVAL; } static int mv88e6123_61_65_phy_read(struct dsa_switch *ds, int port, int regnum) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6123_61_65_port_to_phy_addr(port); + int addr = mv88e6123_61_65_port_to_phy_addr(ds, port); int ret; + if (addr < 0) + return addr; + mutex_lock(&ps->phy_mutex); ret = mv88e6xxx_phy_read(ds, addr, regnum); mutex_unlock(&ps->phy_mutex); @@ -322,9 +341,12 @@ mv88e6123_61_65_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6123_61_65_port_to_phy_addr(port); + int addr = mv88e6123_61_65_port_to_phy_addr(ds, port); int ret; + if (addr < 0) + return addr; + mutex_lock(&ps->phy_mutex); ret = mv88e6xxx_phy_write(ds, addr, regnum, val); mutex_unlock(&ps->phy_mutex); From 44e50ddbc74a4bd6a862be9e6de22bce8c0b4150 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 2 Apr 2015 04:06:33 +0200 Subject: [PATCH 413/567] net: dsa: Consistently set and use ps->num_ports As a step towards consolidating code, consistently set the number of ports in the private state structure, and make use of it in loops. Signed-off-by: Andrew Lunn Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6171.c | 23 +++++++++++++++-------- drivers/net/dsa/mv88e6352.c | 10 +++++++--- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 639bd83b76c7..5a295533ff20 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -38,12 +38,13 @@ static char *mv88e6171_probe(struct device *host_dev, int sw_addr) static int mv88e6171_switch_reset(struct dsa_switch *ds) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int i; int ret; unsigned long timeout; /* Set all ports to the disabled state. */ - for (i = 0; i < 8; i++) { + for (i = 0; i < ps->num_ports; i++) { ret = REG_READ(REG_PORT(i), 0x04); REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); } @@ -70,7 +71,7 @@ static int mv88e6171_switch_reset(struct dsa_switch *ds) return -ETIMEDOUT; /* Enable ports not under DSA, e.g. WAN port */ - for (i = 0; i < 8; i++) { + for (i = 0; i < ps->num_ports; i++) { if (dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i)) continue; @@ -83,6 +84,7 @@ static int mv88e6171_switch_reset(struct dsa_switch *ds) static int mv88e6171_setup_global(struct dsa_switch *ds) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; int i; @@ -147,7 +149,7 @@ static int mv88e6171_setup_global(struct dsa_switch *ds) } /* Clear all trunk masks. */ - for (i = 0; i < 8; i++) + for (i = 0; i < ps->num_ports; i++) REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff); /* Clear all trunk mappings. */ @@ -270,6 +272,7 @@ static int mv88e6171_setup_port(struct dsa_switch *ds, int p) static int mv88e6171_setup(struct dsa_switch *ds) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int i; int ret; @@ -277,6 +280,8 @@ static int mv88e6171_setup(struct dsa_switch *ds) if (ret < 0) return ret; + ps->num_ports = 7; + ret = mv88e6171_switch_reset(ds); if (ret < 0) return ret; @@ -287,7 +292,7 @@ static int mv88e6171_setup(struct dsa_switch *ds) if (ret < 0) return ret; - for (i = 0; i < 8; i++) { + for (i = 0; i < ps->num_ports; i++) { if (!(dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i))) continue; @@ -299,9 +304,11 @@ static int mv88e6171_setup(struct dsa_switch *ds) return 0; } -static int mv88e6171_port_to_phy_addr(int port) +static int mv88e6171_port_to_phy_addr(struct dsa_switch *ds, int port) { - if (port >= 0 && port <= 4) + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + if (port >= 0 && port < ps->num_ports) return port; return -1; } @@ -310,7 +317,7 @@ static int mv88e6171_phy_read(struct dsa_switch *ds, int port, int regnum) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6171_port_to_phy_addr(port); + int addr = mv88e6171_port_to_phy_addr(ds, port); int ret; mutex_lock(&ps->phy_mutex); @@ -324,7 +331,7 @@ mv88e6171_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6171_port_to_phy_addr(port); + int addr = mv88e6171_port_to_phy_addr(ds, port); int ret; mutex_lock(&ps->phy_mutex); diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 41fe3a6a72d1..040027fcd013 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -47,12 +47,13 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr) static int mv88e6352_switch_reset(struct dsa_switch *ds) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); unsigned long timeout; int ret; int i; /* Set all ports to the disabled state. */ - for (i = 0; i < 7; i++) { + for (i = 0; i < ps->num_ports; i++) { ret = REG_READ(REG_PORT(i), 0x04); REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); } @@ -82,6 +83,7 @@ static int mv88e6352_switch_reset(struct dsa_switch *ds) static int mv88e6352_setup_global(struct dsa_switch *ds) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; int i; @@ -152,7 +154,7 @@ static int mv88e6352_setup_global(struct dsa_switch *ds) /* Disable ingress rate limiting by resetting all ingress * rate limit registers to their initial state. */ - for (i = 0; i < 7; i++) + for (i = 0; i < ps->num_ports; i++) REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8)); /* Initialise cross-chip port VLAN table to reset defaults. */ @@ -367,6 +369,8 @@ static int mv88e6352_setup(struct dsa_switch *ds) if (ret < 0) return ret; + ps->num_ports = 7; + mutex_init(&ps->eeprom_mutex); ret = mv88e6352_switch_reset(ds); @@ -379,7 +383,7 @@ static int mv88e6352_setup(struct dsa_switch *ds) if (ret < 0) return ret; - for (i = 0; i < 7; i++) { + for (i = 0; i < ps->num_ports; i++) { ret = mv88e6352_setup_port(ds, i); if (ret < 0) return ret; From 143a83073aaea145aa050cd0ebb80454c9362608 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 2 Apr 2015 04:06:34 +0200 Subject: [PATCH 414/567] net: dsa: Centralize Marvell switch reset Marvell switches are all reset in nearly the same way. The only difference is if the PPU should be enabled or not. Move this code into the shared mv88x6xxx.c. Signed-off-by: Andrew Lunn Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6123_61_65.c | 36 +---------------------- drivers/net/dsa/mv88e6131.c | 36 +---------------------- drivers/net/dsa/mv88e6171.c | 48 +------------------------------ drivers/net/dsa/mv88e6352.c | 38 +----------------------- drivers/net/dsa/mv88e6xxx.c | 40 ++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx.h | 1 + 6 files changed, 45 insertions(+), 154 deletions(-) diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c index 6480f77829ef..10228ad48151 100644 --- a/drivers/net/dsa/mv88e6123_61_65.c +++ b/drivers/net/dsa/mv88e6123_61_65.c @@ -52,40 +52,6 @@ static char *mv88e6123_61_65_probe(struct device *host_dev, int sw_addr) return NULL; } -static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int i; - int ret; - unsigned long timeout; - - /* Set all ports to the disabled state. */ - for (i = 0; i < ps->num_ports; i++) { - ret = REG_READ(REG_PORT(i), 0x04); - REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); - } - - /* Wait for transmit queues to drain. */ - usleep_range(2000, 4000); - - /* Reset the switch. */ - REG_WRITE(REG_GLOBAL, 0x04, 0xc400); - - /* Wait up to one second for reset to complete. */ - timeout = jiffies + 1 * HZ; - while (time_before(jiffies, timeout)) { - ret = REG_READ(REG_GLOBAL, 0x00); - if ((ret & 0xc800) == 0xc800) - break; - - usleep_range(1000, 2000); - } - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - - return 0; -} - static int mv88e6123_61_65_setup_global(struct dsa_switch *ds) { int ret; @@ -292,7 +258,7 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) return -ENODEV; } - ret = mv88e6123_61_65_switch_reset(ds); + ret = mv88e6xxx_switch_reset(ds, false); if (ret < 0) return ret; diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 6b818fde2216..534a8f0b1c28 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -42,40 +42,6 @@ static char *mv88e6131_probe(struct device *host_dev, int sw_addr) return NULL; } -static int mv88e6131_switch_reset(struct dsa_switch *ds) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int i; - int ret; - unsigned long timeout; - - /* Set all ports to the disabled state. */ - for (i = 0; i < ps->num_ports; i++) { - ret = REG_READ(REG_PORT(i), 0x04); - REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); - } - - /* Wait for transmit queues to drain. */ - usleep_range(2000, 4000); - - /* Reset the switch. */ - REG_WRITE(REG_GLOBAL, 0x04, 0xc400); - - /* Wait up to one second for reset to complete. */ - timeout = jiffies + 1 * HZ; - while (time_before(jiffies, timeout)) { - ret = REG_READ(REG_GLOBAL, 0x00); - if ((ret & 0xc800) == 0xc800) - break; - - usleep_range(1000, 2000); - } - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - - return 0; -} - static int mv88e6131_setup_global(struct dsa_switch *ds) { int ret; @@ -281,7 +247,7 @@ static int mv88e6131_setup(struct dsa_switch *ds) return -ENODEV; } - ret = mv88e6131_switch_reset(ds); + ret = mv88e6xxx_switch_reset(ds, false); if (ret < 0) return ret; diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 5a295533ff20..69b35d124de5 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -36,52 +36,6 @@ static char *mv88e6171_probe(struct device *host_dev, int sw_addr) return NULL; } -static int mv88e6171_switch_reset(struct dsa_switch *ds) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int i; - int ret; - unsigned long timeout; - - /* Set all ports to the disabled state. */ - for (i = 0; i < ps->num_ports; i++) { - ret = REG_READ(REG_PORT(i), 0x04); - REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); - } - - /* Wait for transmit queues to drain. */ - usleep_range(2000, 4000); - - /* Reset the switch. Keep PPU active. The PPU needs to be - * active to support indirect phy register accesses through - * global registers 0x18 and 0x19. - */ - REG_WRITE(REG_GLOBAL, 0x04, 0xc000); - - /* Wait up to one second for reset to complete. */ - timeout = jiffies + 1 * HZ; - while (time_before(jiffies, timeout)) { - ret = REG_READ(REG_GLOBAL, 0x00); - if ((ret & 0xc800) == 0xc800) - break; - - usleep_range(1000, 2000); - } - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - - /* Enable ports not under DSA, e.g. WAN port */ - for (i = 0; i < ps->num_ports; i++) { - if (dsa_is_cpu_port(ds, i) || ds->phys_port_mask & (1 << i)) - continue; - - ret = REG_READ(REG_PORT(i), 0x04); - REG_WRITE(REG_PORT(i), 0x04, ret | 0x03); - } - - return 0; -} - static int mv88e6171_setup_global(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -282,7 +236,7 @@ static int mv88e6171_setup(struct dsa_switch *ds) ps->num_ports = 7; - ret = mv88e6171_switch_reset(ds); + ret = mv88e6xxx_switch_reset(ds, true); if (ret < 0) return ret; diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 040027fcd013..214bdbc8a5b1 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -45,42 +45,6 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr) return NULL; } -static int mv88e6352_switch_reset(struct dsa_switch *ds) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - unsigned long timeout; - int ret; - int i; - - /* Set all ports to the disabled state. */ - for (i = 0; i < ps->num_ports; i++) { - ret = REG_READ(REG_PORT(i), 0x04); - REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); - } - - /* Wait for transmit queues to drain. */ - usleep_range(2000, 4000); - - /* Reset the switch. Keep PPU active (bit 14, undocumented). - * The PPU needs to be active to support indirect phy register - * accesses through global registers 0x18 and 0x19. - */ - REG_WRITE(REG_GLOBAL, 0x04, 0xc000); - - /* Wait up to one second for reset to complete. */ - timeout = jiffies + 1 * HZ; - while (time_before(jiffies, timeout)) { - ret = REG_READ(REG_GLOBAL, 0x00); - if ((ret & 0x8800) == 0x8800) - break; - usleep_range(1000, 2000); - } - if (time_after(jiffies, timeout)) - return -ETIMEDOUT; - - return 0; -} - static int mv88e6352_setup_global(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -373,7 +337,7 @@ static int mv88e6352_setup(struct dsa_switch *ds) mutex_init(&ps->eeprom_mutex); - ret = mv88e6352_switch_reset(ds); + ret = mv88e6xxx_switch_reset(ds, true); if (ret < 0) return ret; diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 13572cc24c6d..9db5b40d78ea 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1161,6 +1161,46 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) return 0; } +int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + u16 is_reset = (ppu_active ? 0x8800 : 0xc800); + unsigned long timeout; + int ret; + int i; + + /* Set all ports to the disabled state. */ + for (i = 0; i < ps->num_ports; i++) { + ret = REG_READ(REG_PORT(i), 0x04); + REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); + } + + /* Wait for transmit queues to drain. */ + usleep_range(2000, 4000); + + /* Reset the switch. Keep the PPU active if requested. The PPU + * needs to be active to support indirect phy register access + * through global registers 0x18 and 0x19. + */ + if (ppu_active) + REG_WRITE(REG_GLOBAL, 0x04, 0xc000); + else + REG_WRITE(REG_GLOBAL, 0x04, 0xc400); + + /* Wait up to one second for reset to complete. */ + timeout = jiffies + 1 * HZ; + while (time_before(jiffies, timeout)) { + ret = REG_READ(REG_GLOBAL, 0x00); + if ((ret & is_reset) == is_reset) + break; + usleep_range(1000, 2000); + } + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + return 0; +} + static int __init mv88e6xxx_init(void) { #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index ef058444bdb7..f84d3d5178b9 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -129,6 +129,7 @@ struct mv88e6xxx_hw_stat { int reg; }; +int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active); int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port); int mv88e6xxx_setup_common(struct dsa_switch *ds); int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg); From 4914358567d81d6f1d95f7809c77658c55555f1c Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 2 Apr 2015 04:06:35 +0200 Subject: [PATCH 415/567] net: dsa: Move phy page access functions into shared code These functions could in future be used by other drivers. Move them into the shared area. Signed-off-by: Andrew Lunn Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6352.c | 45 +++++-------------------------------- drivers/net/dsa/mv88e6xxx.c | 34 ++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx.h | 4 +++- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 214bdbc8a5b1..fb16671c5f92 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -230,48 +230,13 @@ static int mv88e6352_setup_port(struct dsa_switch *ds, int p) #ifdef CONFIG_NET_DSA_HWMON -static int mv88e6352_phy_page_read(struct dsa_switch *ds, - int port, int page, int reg) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int ret; - - mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); - if (ret < 0) - goto error; - ret = mv88e6xxx_phy_read_indirect(ds, port, reg); -error: - mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); - mutex_unlock(&ps->phy_mutex); - return ret; -} - -static int mv88e6352_phy_page_write(struct dsa_switch *ds, - int port, int page, int reg, int val) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int ret; - - mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); - if (ret < 0) - goto error; - - ret = mv88e6xxx_phy_write_indirect(ds, port, reg, val); -error: - mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); - mutex_unlock(&ps->phy_mutex); - return ret; -} - static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp) { int ret; *temp = 0; - ret = mv88e6352_phy_page_read(ds, 0, 6, 27); + ret = mv88e6xxx_phy_page_read(ds, 0, 6, 27); if (ret < 0) return ret; @@ -286,7 +251,7 @@ static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp) *temp = 0; - ret = mv88e6352_phy_page_read(ds, 0, 6, 26); + ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); if (ret < 0) return ret; @@ -299,11 +264,11 @@ static int mv88e6352_set_temp_limit(struct dsa_switch *ds, int temp) { int ret; - ret = mv88e6352_phy_page_read(ds, 0, 6, 26); + ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); if (ret < 0) return ret; temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); - return mv88e6352_phy_page_write(ds, 0, 6, 26, + return mv88e6xxx_phy_page_write(ds, 0, 6, 26, (ret & 0xe0ff) | (temp << 8)); } @@ -313,7 +278,7 @@ static int mv88e6352_get_temp_alarm(struct dsa_switch *ds, bool *alarm) *alarm = false; - ret = mv88e6352_phy_page_read(ds, 0, 6, 26); + ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); if (ret < 0) return ret; diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 9db5b40d78ea..df727e1db18d 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1201,6 +1201,40 @@ int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active) return 0; } +int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; + + mutex_lock(&ps->phy_mutex); + ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); + if (ret < 0) + goto error; + ret = mv88e6xxx_phy_read_indirect(ds, port, reg); +error: + mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); + mutex_unlock(&ps->phy_mutex); + return ret; +} + +int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, + int reg, int val) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; + + mutex_lock(&ps->phy_mutex); + ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); + if (ret < 0) + goto error; + + ret = mv88e6xxx_phy_write_indirect(ds, port, reg, val); +error: + mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); + mutex_unlock(&ps->phy_mutex); + return ret; +} + static int __init mv88e6xxx_init(void) { #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index f84d3d5178b9..49614765760f 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -175,7 +175,9 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid); int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, unsigned char *addr, bool *is_static); - +int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg); +int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, + int reg, int val); extern struct dsa_switch_driver mv88e6131_switch_driver; extern struct dsa_switch_driver mv88e6123_61_65_switch_driver; extern struct dsa_switch_driver mv88e6352_switch_driver; From fd3a0ee4063e4f44d915df8f117d9e0d8b05950a Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 2 Apr 2015 04:06:36 +0200 Subject: [PATCH 416/567] net: dsa: Consolidate phy read and write functions Move the common code for reading and writing phy registers into the shared mv88e6xxx. Signed-off-by: Andrew Lunn Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6123_61_65.c | 46 +----------- drivers/net/dsa/mv88e6171.c | 40 +--------- drivers/net/dsa/mv88e6352.c | 45 +----------- drivers/net/dsa/mv88e6xxx.c | 118 +++++++++++++++++++++++++----- drivers/net/dsa/mv88e6xxx.h | 7 +- 5 files changed, 110 insertions(+), 146 deletions(-) diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c index 10228ad48151..5f536722f7c7 100644 --- a/drivers/net/dsa/mv88e6123_61_65.c +++ b/drivers/net/dsa/mv88e6123_61_65.c @@ -277,48 +277,6 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) return 0; } -static int mv88e6123_61_65_port_to_phy_addr(struct dsa_switch *ds, int port) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - - if (port >= 0 && port < ps->num_ports) - return port; - return -EINVAL; -} - -static int -mv88e6123_61_65_phy_read(struct dsa_switch *ds, int port, int regnum) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6123_61_65_port_to_phy_addr(ds, port); - int ret; - - if (addr < 0) - return addr; - - mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_read(ds, addr, regnum); - mutex_unlock(&ps->phy_mutex); - return ret; -} - -static int -mv88e6123_61_65_phy_write(struct dsa_switch *ds, - int port, int regnum, u16 val) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6123_61_65_port_to_phy_addr(ds, port); - int ret; - - if (addr < 0) - return addr; - - mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_write(ds, addr, regnum, val); - mutex_unlock(&ps->phy_mutex); - return ret; -} - static struct mv88e6xxx_hw_stat mv88e6123_61_65_hw_stats[] = { { "in_good_octets", 8, 0x00, }, { "in_bad_octets", 4, 0x02, }, @@ -381,8 +339,8 @@ struct dsa_switch_driver mv88e6123_61_65_switch_driver = { .probe = mv88e6123_61_65_probe, .setup = mv88e6123_61_65_setup, .set_addr = mv88e6xxx_set_addr_indirect, - .phy_read = mv88e6123_61_65_phy_read, - .phy_write = mv88e6123_61_65_phy_write, + .phy_read = mv88e6xxx_phy_read, + .phy_write = mv88e6xxx_phy_write, .poll_link = mv88e6xxx_poll_link, .get_strings = mv88e6123_61_65_get_strings, .get_ethtool_stats = mv88e6123_61_65_get_ethtool_stats, diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 69b35d124de5..4d6038991a59 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -258,42 +258,6 @@ static int mv88e6171_setup(struct dsa_switch *ds) return 0; } -static int mv88e6171_port_to_phy_addr(struct dsa_switch *ds, int port) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - - if (port >= 0 && port < ps->num_ports) - return port; - return -1; -} - -static int -mv88e6171_phy_read(struct dsa_switch *ds, int port, int regnum) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6171_port_to_phy_addr(ds, port); - int ret; - - mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_read_indirect(ds, addr, regnum); - mutex_unlock(&ps->phy_mutex); - return ret; -} - -static int -mv88e6171_phy_write(struct dsa_switch *ds, - int port, int regnum, u16 val) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6171_port_to_phy_addr(ds, port); - int ret; - - mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_write_indirect(ds, addr, regnum, val); - mutex_unlock(&ps->phy_mutex); - return ret; -} - static struct mv88e6xxx_hw_stat mv88e6171_hw_stats[] = { { "in_good_octets", 8, 0x00, }, { "in_bad_octets", 4, 0x02, }, @@ -375,8 +339,8 @@ struct dsa_switch_driver mv88e6171_switch_driver = { .probe = mv88e6171_probe, .setup = mv88e6171_setup, .set_addr = mv88e6xxx_set_addr_indirect, - .phy_read = mv88e6171_phy_read, - .phy_write = mv88e6171_phy_write, + .phy_read = mv88e6xxx_phy_read_indirect, + .phy_write = mv88e6xxx_phy_write_indirect, .poll_link = mv88e6xxx_poll_link, .get_strings = mv88e6171_get_strings, .get_ethtool_stats = mv88e6171_get_ethtool_stats, diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index fb16671c5f92..3806ff1aaa9c 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -321,47 +321,6 @@ static int mv88e6352_setup(struct dsa_switch *ds) return 0; } -static int mv88e6352_port_to_phy_addr(int port) -{ - if (port >= 0 && port <= 4) - return port; - return -EINVAL; -} - -static int -mv88e6352_phy_read(struct dsa_switch *ds, int port, int regnum) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6352_port_to_phy_addr(port); - int ret; - - if (addr < 0) - return addr; - - mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_read_indirect(ds, addr, regnum); - mutex_unlock(&ps->phy_mutex); - - return ret; -} - -static int -mv88e6352_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int addr = mv88e6352_port_to_phy_addr(port); - int ret; - - if (addr < 0) - return addr; - - mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_write_indirect(ds, addr, regnum, val); - mutex_unlock(&ps->phy_mutex); - - return ret; -} - static struct mv88e6xxx_hw_stat mv88e6352_hw_stats[] = { { "in_good_octets", 8, 0x00, }, { "in_bad_octets", 4, 0x02, }, @@ -621,8 +580,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .probe = mv88e6352_probe, .setup = mv88e6352_setup, .set_addr = mv88e6xxx_set_addr_indirect, - .phy_read = mv88e6352_phy_read, - .phy_write = mv88e6352_phy_write, + .phy_read = mv88e6xxx_phy_read_indirect, + .phy_write = mv88e6xxx_phy_write_indirect, .poll_link = mv88e6xxx_poll_link, .get_strings = mv88e6352_get_strings, .get_ethtool_stats = mv88e6352_get_ethtool_stats, diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index df727e1db18d..7c4c04bb0cb0 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -214,14 +214,17 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) return 0; } -int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum) +/* Must be called with phy mutex held */ +static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum) { if (addr >= 0) return mv88e6xxx_reg_read(ds, addr, regnum); return 0xffff; } -int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val) +/* Must be called with phy mutex held */ +static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, + u16 val) { if (addr >= 0) return mv88e6xxx_reg_write(ds, addr, regnum, val); @@ -579,37 +582,37 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); + ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); if (ret < 0) goto error; /* Enable temperature sensor */ - ret = mv88e6xxx_phy_read(ds, 0x0, 0x1a); + ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); if (ret < 0) goto error; - ret = mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); + ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); if (ret < 0) goto error; /* Wait for temperature to stabilize */ usleep_range(10000, 12000); - val = mv88e6xxx_phy_read(ds, 0x0, 0x1a); + val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); if (val < 0) { ret = val; goto error; } /* Disable temperature sensor */ - ret = mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); + ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); if (ret < 0) goto error; *temp = ((val & 0x1f) - 5) * 5; error: - mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); + _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); mutex_unlock(&ps->phy_mutex); return ret; } @@ -671,7 +674,9 @@ static int _mv88e6xxx_atu_wait(struct dsa_switch *ds) return _mv88e6xxx_wait(ds, REG_GLOBAL, 0x0b, ATU_BUSY); } -int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum) +/* Must be called with phy mutex held */ +static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, + int regnum) { int ret; @@ -684,8 +689,9 @@ int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum) return REG_READ(REG_GLOBAL2, 0x19); } -int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum, - u16 val) +/* Must be called with phy mutex held */ +static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, + int regnum, u16 val) { REG_WRITE(REG_GLOBAL2, 0x19, val); REG_WRITE(REG_GLOBAL2, 0x18, 0x9400 | (addr << 5) | regnum); @@ -715,7 +721,7 @@ static int mv88e6xxx_eee_enable_set(struct dsa_switch *ds, int port, { int reg, nreg; - reg = mv88e6xxx_phy_read_indirect(ds, port, 16); + reg = _mv88e6xxx_phy_read_indirect(ds, port, 16); if (reg < 0) return reg; @@ -726,7 +732,7 @@ static int mv88e6xxx_eee_enable_set(struct dsa_switch *ds, int port, nreg |= 0x0100; if (nreg != reg) - return mv88e6xxx_phy_write_indirect(ds, port, 16, nreg); + return _mv88e6xxx_phy_write_indirect(ds, port, 16, nreg); return 0; } @@ -1207,12 +1213,12 @@ int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg) int ret; mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); + ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); if (ret < 0) goto error; - ret = mv88e6xxx_phy_read_indirect(ds, port, reg); + ret = _mv88e6xxx_phy_read_indirect(ds, port, reg); error: - mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); + _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); mutex_unlock(&ps->phy_mutex); return ret; } @@ -1224,13 +1230,87 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, int ret; mutex_lock(&ps->phy_mutex); - ret = mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); + ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page); if (ret < 0) goto error; - ret = mv88e6xxx_phy_write_indirect(ds, port, reg, val); + ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val); error: - mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); + _mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0); + mutex_unlock(&ps->phy_mutex); + return ret; +} + +static int mv88e6xxx_port_to_phy_addr(struct dsa_switch *ds, int port) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + if (port >= 0 && port < ps->num_ports) + return port; + return -EINVAL; +} + +int +mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int addr = mv88e6xxx_port_to_phy_addr(ds, port); + int ret; + + if (addr < 0) + return addr; + + mutex_lock(&ps->phy_mutex); + ret = _mv88e6xxx_phy_read(ds, addr, regnum); + mutex_unlock(&ps->phy_mutex); + return ret; +} + +int +mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int addr = mv88e6xxx_port_to_phy_addr(ds, port); + int ret; + + if (addr < 0) + return addr; + + mutex_lock(&ps->phy_mutex); + ret = _mv88e6xxx_phy_write(ds, addr, regnum, val); + mutex_unlock(&ps->phy_mutex); + return ret; +} + +int +mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int addr = mv88e6xxx_port_to_phy_addr(ds, port); + int ret; + + if (addr < 0) + return addr; + + mutex_lock(&ps->phy_mutex); + ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum); + mutex_unlock(&ps->phy_mutex); + return ret; +} + +int +mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum, + u16 val) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int addr = mv88e6xxx_port_to_phy_addr(ds, port); + int ret; + + if (addr < 0) + return addr; + + mutex_lock(&ps->phy_mutex); + ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val); mutex_unlock(&ps->phy_mutex); return ret; } diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 49614765760f..44b0ec79cc6b 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -140,8 +140,11 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val); int mv88e6xxx_config_prio(struct dsa_switch *ds); int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr); int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr); -int mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum); -int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val); +int mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum); +int mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val); +int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum); +int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum, + u16 val); void mv88e6xxx_ppu_state_init(struct dsa_switch *ds); int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum); int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr, From 2f40c6981ac0adcaa2b3fc64e6ae81f80809aec8 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 2 Apr 2015 04:06:37 +0200 Subject: [PATCH 417/567] net: dsa: mv88e6xxx: Add missing mutex's in EEE operations. The phy_mutex should be held while reading and writing to the phy. Signed-off-by: Andrew Lunn Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 59 +++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 7c4c04bb0cb0..d9a78c71a4bb 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -701,53 +701,54 @@ static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int reg; - reg = mv88e6xxx_phy_read_indirect(ds, port, 16); + mutex_lock(&ps->phy_mutex); + + reg = _mv88e6xxx_phy_read_indirect(ds, port, 16); if (reg < 0) - return -EOPNOTSUPP; + goto out; e->eee_enabled = !!(reg & 0x0200); e->tx_lpi_enabled = !!(reg & 0x0100); - reg = REG_READ(REG_PORT(port), 0); - e->eee_active = !!(reg & 0x0040); - - return 0; -} - -static int mv88e6xxx_eee_enable_set(struct dsa_switch *ds, int port, - bool eee_enabled, bool tx_lpi_enabled) -{ - int reg, nreg; - - reg = _mv88e6xxx_phy_read_indirect(ds, port, 16); + reg = mv88e6xxx_reg_read(ds, REG_PORT(port), 0); if (reg < 0) - return reg; + goto out; - nreg = reg & ~0x0300; - if (eee_enabled) - nreg |= 0x0200; - if (tx_lpi_enabled) - nreg |= 0x0100; + e->eee_active = !!(reg & 0x0040); + reg = 0; - if (nreg != reg) - return _mv88e6xxx_phy_write_indirect(ds, port, 16, nreg); - - return 0; +out: + mutex_unlock(&ps->phy_mutex); + return reg; } int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, struct phy_device *phydev, struct ethtool_eee *e) { + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int reg; int ret; - ret = mv88e6xxx_eee_enable_set(ds, port, e->eee_enabled, - e->tx_lpi_enabled); - if (ret) - return -EOPNOTSUPP; + mutex_lock(&ps->phy_mutex); - return 0; + ret = _mv88e6xxx_phy_read_indirect(ds, port, 16); + if (ret < 0) + goto out; + + reg = ret & ~0x0300; + if (e->eee_enabled) + reg |= 0x0200; + if (e->tx_lpi_enabled) + reg |= 0x0100; + + ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg); +out: + mutex_unlock(&ps->phy_mutex); + + return ret; } static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd) From e413e7e1f7493910274c552d7f70ae396c93199a Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 2 Apr 2015 04:06:38 +0200 Subject: [PATCH 418/567] net: dsa: Consolidate getting the statistics Reading the statistics from the hardware is the same for all chips. What differs is the number of available statistics. Have just one copy of the code in the shared mv88e6xxx. Signed-off-by: Andrew Lunn Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6123_61_65.c | 62 +------------------ drivers/net/dsa/mv88e6131.c | 59 +----------------- drivers/net/dsa/mv88e6171.c | 59 +----------------- drivers/net/dsa/mv88e6352.c | 61 +------------------ drivers/net/dsa/mv88e6xxx.c | 99 +++++++++++++++++++++++++++++-- drivers/net/dsa/mv88e6xxx.h | 11 ++-- 6 files changed, 110 insertions(+), 241 deletions(-) diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c index 5f536722f7c7..81cc24448164 100644 --- a/drivers/net/dsa/mv88e6123_61_65.c +++ b/drivers/net/dsa/mv88e6123_61_65.c @@ -277,62 +277,6 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) return 0; } -static struct mv88e6xxx_hw_stat mv88e6123_61_65_hw_stats[] = { - { "in_good_octets", 8, 0x00, }, - { "in_bad_octets", 4, 0x02, }, - { "in_unicast", 4, 0x04, }, - { "in_broadcasts", 4, 0x06, }, - { "in_multicasts", 4, 0x07, }, - { "in_pause", 4, 0x16, }, - { "in_undersize", 4, 0x18, }, - { "in_fragments", 4, 0x19, }, - { "in_oversize", 4, 0x1a, }, - { "in_jabber", 4, 0x1b, }, - { "in_rx_error", 4, 0x1c, }, - { "in_fcs_error", 4, 0x1d, }, - { "out_octets", 8, 0x0e, }, - { "out_unicast", 4, 0x10, }, - { "out_broadcasts", 4, 0x13, }, - { "out_multicasts", 4, 0x12, }, - { "out_pause", 4, 0x15, }, - { "excessive", 4, 0x11, }, - { "collisions", 4, 0x1e, }, - { "deferred", 4, 0x05, }, - { "single", 4, 0x14, }, - { "multiple", 4, 0x17, }, - { "out_fcs_error", 4, 0x03, }, - { "late", 4, 0x1f, }, - { "hist_64bytes", 4, 0x08, }, - { "hist_65_127bytes", 4, 0x09, }, - { "hist_128_255bytes", 4, 0x0a, }, - { "hist_256_511bytes", 4, 0x0b, }, - { "hist_512_1023bytes", 4, 0x0c, }, - { "hist_1024_max_bytes", 4, 0x0d, }, - { "sw_in_discards", 4, 0x110, }, - { "sw_in_filtered", 2, 0x112, }, - { "sw_out_filtered", 2, 0x113, }, -}; - -static void -mv88e6123_61_65_get_strings(struct dsa_switch *ds, int port, uint8_t *data) -{ - mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats), - mv88e6123_61_65_hw_stats, port, data); -} - -static void -mv88e6123_61_65_get_ethtool_stats(struct dsa_switch *ds, - int port, uint64_t *data) -{ - mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6123_61_65_hw_stats), - mv88e6123_61_65_hw_stats, port, data); -} - -static int mv88e6123_61_65_get_sset_count(struct dsa_switch *ds) -{ - return ARRAY_SIZE(mv88e6123_61_65_hw_stats); -} - struct dsa_switch_driver mv88e6123_61_65_switch_driver = { .tag_protocol = DSA_TAG_PROTO_EDSA, .priv_size = sizeof(struct mv88e6xxx_priv_state), @@ -342,9 +286,9 @@ struct dsa_switch_driver mv88e6123_61_65_switch_driver = { .phy_read = mv88e6xxx_phy_read, .phy_write = mv88e6xxx_phy_write, .poll_link = mv88e6xxx_poll_link, - .get_strings = mv88e6123_61_65_get_strings, - .get_ethtool_stats = mv88e6123_61_65_get_ethtool_stats, - .get_sset_count = mv88e6123_61_65_get_sset_count, + .get_strings = mv88e6xxx_get_strings, + .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, + .get_sset_count = mv88e6xxx_get_sset_count, #ifdef CONFIG_NET_DSA_HWMON .get_temp = mv88e6xxx_get_temp, #endif diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 534a8f0b1c28..5bec7a60b476 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -299,59 +299,6 @@ mv88e6131_phy_write(struct dsa_switch *ds, return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val); } -static struct mv88e6xxx_hw_stat mv88e6131_hw_stats[] = { - { "in_good_octets", 8, 0x00, }, - { "in_bad_octets", 4, 0x02, }, - { "in_unicast", 4, 0x04, }, - { "in_broadcasts", 4, 0x06, }, - { "in_multicasts", 4, 0x07, }, - { "in_pause", 4, 0x16, }, - { "in_undersize", 4, 0x18, }, - { "in_fragments", 4, 0x19, }, - { "in_oversize", 4, 0x1a, }, - { "in_jabber", 4, 0x1b, }, - { "in_rx_error", 4, 0x1c, }, - { "in_fcs_error", 4, 0x1d, }, - { "out_octets", 8, 0x0e, }, - { "out_unicast", 4, 0x10, }, - { "out_broadcasts", 4, 0x13, }, - { "out_multicasts", 4, 0x12, }, - { "out_pause", 4, 0x15, }, - { "excessive", 4, 0x11, }, - { "collisions", 4, 0x1e, }, - { "deferred", 4, 0x05, }, - { "single", 4, 0x14, }, - { "multiple", 4, 0x17, }, - { "out_fcs_error", 4, 0x03, }, - { "late", 4, 0x1f, }, - { "hist_64bytes", 4, 0x08, }, - { "hist_65_127bytes", 4, 0x09, }, - { "hist_128_255bytes", 4, 0x0a, }, - { "hist_256_511bytes", 4, 0x0b, }, - { "hist_512_1023bytes", 4, 0x0c, }, - { "hist_1024_max_bytes", 4, 0x0d, }, -}; - -static void -mv88e6131_get_strings(struct dsa_switch *ds, int port, uint8_t *data) -{ - mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6131_hw_stats), - mv88e6131_hw_stats, port, data); -} - -static void -mv88e6131_get_ethtool_stats(struct dsa_switch *ds, - int port, uint64_t *data) -{ - mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6131_hw_stats), - mv88e6131_hw_stats, port, data); -} - -static int mv88e6131_get_sset_count(struct dsa_switch *ds) -{ - return ARRAY_SIZE(mv88e6131_hw_stats); -} - struct dsa_switch_driver mv88e6131_switch_driver = { .tag_protocol = DSA_TAG_PROTO_DSA, .priv_size = sizeof(struct mv88e6xxx_priv_state), @@ -361,9 +308,9 @@ struct dsa_switch_driver mv88e6131_switch_driver = { .phy_read = mv88e6131_phy_read, .phy_write = mv88e6131_phy_write, .poll_link = mv88e6xxx_poll_link, - .get_strings = mv88e6131_get_strings, - .get_ethtool_stats = mv88e6131_get_ethtool_stats, - .get_sset_count = mv88e6131_get_sset_count, + .get_strings = mv88e6xxx_get_strings, + .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, + .get_sset_count = mv88e6xxx_get_sset_count, }; MODULE_ALIAS("platform:mv88e6085"); diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 4d6038991a59..7314e7d71a67 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -258,59 +258,6 @@ static int mv88e6171_setup(struct dsa_switch *ds) return 0; } -static struct mv88e6xxx_hw_stat mv88e6171_hw_stats[] = { - { "in_good_octets", 8, 0x00, }, - { "in_bad_octets", 4, 0x02, }, - { "in_unicast", 4, 0x04, }, - { "in_broadcasts", 4, 0x06, }, - { "in_multicasts", 4, 0x07, }, - { "in_pause", 4, 0x16, }, - { "in_undersize", 4, 0x18, }, - { "in_fragments", 4, 0x19, }, - { "in_oversize", 4, 0x1a, }, - { "in_jabber", 4, 0x1b, }, - { "in_rx_error", 4, 0x1c, }, - { "in_fcs_error", 4, 0x1d, }, - { "out_octets", 8, 0x0e, }, - { "out_unicast", 4, 0x10, }, - { "out_broadcasts", 4, 0x13, }, - { "out_multicasts", 4, 0x12, }, - { "out_pause", 4, 0x15, }, - { "excessive", 4, 0x11, }, - { "collisions", 4, 0x1e, }, - { "deferred", 4, 0x05, }, - { "single", 4, 0x14, }, - { "multiple", 4, 0x17, }, - { "out_fcs_error", 4, 0x03, }, - { "late", 4, 0x1f, }, - { "hist_64bytes", 4, 0x08, }, - { "hist_65_127bytes", 4, 0x09, }, - { "hist_128_255bytes", 4, 0x0a, }, - { "hist_256_511bytes", 4, 0x0b, }, - { "hist_512_1023bytes", 4, 0x0c, }, - { "hist_1024_max_bytes", 4, 0x0d, }, -}; - -static void -mv88e6171_get_strings(struct dsa_switch *ds, int port, uint8_t *data) -{ - mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6171_hw_stats), - mv88e6171_hw_stats, port, data); -} - -static void -mv88e6171_get_ethtool_stats(struct dsa_switch *ds, - int port, uint64_t *data) -{ - mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6171_hw_stats), - mv88e6171_hw_stats, port, data); -} - -static int mv88e6171_get_sset_count(struct dsa_switch *ds) -{ - return ARRAY_SIZE(mv88e6171_hw_stats); -} - static int mv88e6171_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) { @@ -342,9 +289,9 @@ struct dsa_switch_driver mv88e6171_switch_driver = { .phy_read = mv88e6xxx_phy_read_indirect, .phy_write = mv88e6xxx_phy_write_indirect, .poll_link = mv88e6xxx_poll_link, - .get_strings = mv88e6171_get_strings, - .get_ethtool_stats = mv88e6171_get_ethtool_stats, - .get_sset_count = mv88e6171_get_sset_count, + .get_strings = mv88e6xxx_get_strings, + .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, + .get_sset_count = mv88e6xxx_get_sset_count, .set_eee = mv88e6171_set_eee, .get_eee = mv88e6171_get_eee, #ifdef CONFIG_NET_DSA_HWMON diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 3806ff1aaa9c..a1be6e3c0351 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -321,42 +321,6 @@ static int mv88e6352_setup(struct dsa_switch *ds) return 0; } -static struct mv88e6xxx_hw_stat mv88e6352_hw_stats[] = { - { "in_good_octets", 8, 0x00, }, - { "in_bad_octets", 4, 0x02, }, - { "in_unicast", 4, 0x04, }, - { "in_broadcasts", 4, 0x06, }, - { "in_multicasts", 4, 0x07, }, - { "in_pause", 4, 0x16, }, - { "in_undersize", 4, 0x18, }, - { "in_fragments", 4, 0x19, }, - { "in_oversize", 4, 0x1a, }, - { "in_jabber", 4, 0x1b, }, - { "in_rx_error", 4, 0x1c, }, - { "in_fcs_error", 4, 0x1d, }, - { "out_octets", 8, 0x0e, }, - { "out_unicast", 4, 0x10, }, - { "out_broadcasts", 4, 0x13, }, - { "out_multicasts", 4, 0x12, }, - { "out_pause", 4, 0x15, }, - { "excessive", 4, 0x11, }, - { "collisions", 4, 0x1e, }, - { "deferred", 4, 0x05, }, - { "single", 4, 0x14, }, - { "multiple", 4, 0x17, }, - { "out_fcs_error", 4, 0x03, }, - { "late", 4, 0x1f, }, - { "hist_64bytes", 4, 0x08, }, - { "hist_65_127bytes", 4, 0x09, }, - { "hist_128_255bytes", 4, 0x0a, }, - { "hist_256_511bytes", 4, 0x0b, }, - { "hist_512_1023bytes", 4, 0x0c, }, - { "hist_1024_max_bytes", 4, 0x0d, }, - { "sw_in_discards", 4, 0x110, }, - { "sw_in_filtered", 2, 0x112, }, - { "sw_out_filtered", 2, 0x113, }, -}; - static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -555,25 +519,6 @@ static int mv88e6352_set_eeprom(struct dsa_switch *ds, return 0; } -static void -mv88e6352_get_strings(struct dsa_switch *ds, int port, uint8_t *data) -{ - mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6352_hw_stats), - mv88e6352_hw_stats, port, data); -} - -static void -mv88e6352_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) -{ - mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6352_hw_stats), - mv88e6352_hw_stats, port, data); -} - -static int mv88e6352_get_sset_count(struct dsa_switch *ds) -{ - return ARRAY_SIZE(mv88e6352_hw_stats); -} - struct dsa_switch_driver mv88e6352_switch_driver = { .tag_protocol = DSA_TAG_PROTO_EDSA, .priv_size = sizeof(struct mv88e6xxx_priv_state), @@ -583,9 +528,9 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .phy_read = mv88e6xxx_phy_read_indirect, .phy_write = mv88e6xxx_phy_write_indirect, .poll_link = mv88e6xxx_poll_link, - .get_strings = mv88e6352_get_strings, - .get_ethtool_stats = mv88e6352_get_ethtool_stats, - .get_sset_count = mv88e6352_get_sset_count, + .get_strings = mv88e6xxx_get_strings, + .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, + .get_sset_count = mv88e6xxx_get_sset_count, .set_eee = mv88e6xxx_set_eee, .get_eee = mv88e6xxx_get_eee, #ifdef CONFIG_NET_DSA_HWMON diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index d9a78c71a4bb..b360fe5346d3 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -484,9 +484,62 @@ static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val) *val = _val | ret; } -void mv88e6xxx_get_strings(struct dsa_switch *ds, - int nr_stats, struct mv88e6xxx_hw_stat *stats, - int port, uint8_t *data) +static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = { + { "in_good_octets", 8, 0x00, }, + { "in_bad_octets", 4, 0x02, }, + { "in_unicast", 4, 0x04, }, + { "in_broadcasts", 4, 0x06, }, + { "in_multicasts", 4, 0x07, }, + { "in_pause", 4, 0x16, }, + { "in_undersize", 4, 0x18, }, + { "in_fragments", 4, 0x19, }, + { "in_oversize", 4, 0x1a, }, + { "in_jabber", 4, 0x1b, }, + { "in_rx_error", 4, 0x1c, }, + { "in_fcs_error", 4, 0x1d, }, + { "out_octets", 8, 0x0e, }, + { "out_unicast", 4, 0x10, }, + { "out_broadcasts", 4, 0x13, }, + { "out_multicasts", 4, 0x12, }, + { "out_pause", 4, 0x15, }, + { "excessive", 4, 0x11, }, + { "collisions", 4, 0x1e, }, + { "deferred", 4, 0x05, }, + { "single", 4, 0x14, }, + { "multiple", 4, 0x17, }, + { "out_fcs_error", 4, 0x03, }, + { "late", 4, 0x1f, }, + { "hist_64bytes", 4, 0x08, }, + { "hist_65_127bytes", 4, 0x09, }, + { "hist_128_255bytes", 4, 0x0a, }, + { "hist_256_511bytes", 4, 0x0b, }, + { "hist_512_1023bytes", 4, 0x0c, }, + { "hist_1024_max_bytes", 4, 0x0d, }, + /* Not all devices have the following counters */ + { "sw_in_discards", 4, 0x110, }, + { "sw_in_filtered", 2, 0x112, }, + { "sw_out_filtered", 2, 0x113, }, + +}; + +static bool have_sw_in_discards(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case ID_6095: case ID_6161: case ID_6165: + case ID_6171: case ID_6172: case ID_6176: + case ID_6182: case ID_6185: case ID_6352: + return true; + default: + return false; + } +} + +static void _mv88e6xxx_get_strings(struct dsa_switch *ds, + int nr_stats, + struct mv88e6xxx_hw_stat *stats, + int port, uint8_t *data) { int i; @@ -496,9 +549,10 @@ void mv88e6xxx_get_strings(struct dsa_switch *ds, } } -void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, - int nr_stats, struct mv88e6xxx_hw_stat *stats, - int port, uint64_t *data) +static void _mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, + int nr_stats, + struct mv88e6xxx_hw_stat *stats, + int port, uint64_t *data) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; @@ -546,6 +600,39 @@ error: mutex_unlock(&ps->stats_mutex); } +/* All the statistics in the table */ +void +mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +{ + if (have_sw_in_discards(ds)) + _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats), + mv88e6xxx_hw_stats, port, data); + else + _mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3, + mv88e6xxx_hw_stats, port, data); +} + +int mv88e6xxx_get_sset_count(struct dsa_switch *ds) +{ + if (have_sw_in_discards(ds)) + return ARRAY_SIZE(mv88e6xxx_hw_stats); + return ARRAY_SIZE(mv88e6xxx_hw_stats) - 3; +} + +void +mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, + int port, uint64_t *data) +{ + if (have_sw_in_discards(ds)) + _mv88e6xxx_get_ethtool_stats( + ds, ARRAY_SIZE(mv88e6xxx_hw_stats), + mv88e6xxx_hw_stats, port, data); + else + _mv88e6xxx_get_ethtool_stats( + ds, ARRAY_SIZE(mv88e6xxx_hw_stats) - 3, + mv88e6xxx_hw_stats, port, data); +} + int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port) { return 32 * sizeof(u16); diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 44b0ec79cc6b..fbbedc07754f 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -150,12 +150,11 @@ int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum); int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr, int regnum, u16 val); void mv88e6xxx_poll_link(struct dsa_switch *ds); -void mv88e6xxx_get_strings(struct dsa_switch *ds, - int nr_stats, struct mv88e6xxx_hw_stat *stats, - int port, uint8_t *data); -void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, - int nr_stats, struct mv88e6xxx_hw_stat *stats, - int port, uint64_t *data); +void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, uint8_t *data); +void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, + uint64_t *data); +int mv88e6xxx_get_sset_count(struct dsa_switch *ds); +int mv88e6xxx_get_sset_count_basic(struct dsa_switch *ds); int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port); void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, struct ethtool_regs *regs, void *_p); From cca8b1337541253f0414f744919c09f8b10bd962 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 2 Apr 2015 04:06:39 +0200 Subject: [PATCH 419/567] net: dsa: Use mnemonics rather than register numbers Rather than refer to registers by number, define mnemonics. Also define mnemonics for the commonly used bits within the registers. Signed-off-by: Andrew Lunn Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6123_61_65.c | 26 ++-- drivers/net/dsa/mv88e6131.c | 24 +-- drivers/net/dsa/mv88e6171.c | 10 +- drivers/net/dsa/mv88e6352.c | 10 +- drivers/net/dsa/mv88e6xxx.c | 195 +++++++++++++---------- drivers/net/dsa/mv88e6xxx.h | 248 +++++++++++++++++++++++------- 6 files changed, 335 insertions(+), 178 deletions(-) diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c index 81cc24448164..b4af6d5aff7c 100644 --- a/drivers/net/dsa/mv88e6123_61_65.c +++ b/drivers/net/dsa/mv88e6123_61_65.c @@ -25,27 +25,27 @@ static char *mv88e6123_61_65_probe(struct device *host_dev, int sw_addr) if (bus == NULL) return NULL; - ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); + ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); if (ret >= 0) { - if (ret == ID_6123_A1) + if (ret == PORT_SWITCH_ID_6123_A1) return "Marvell 88E6123 (A1)"; - if (ret == ID_6123_A2) + if (ret == PORT_SWITCH_ID_6123_A2) return "Marvell 88E6123 (A2)"; - if ((ret & 0xfff0) == ID_6123) + if ((ret & 0xfff0) == PORT_SWITCH_ID_6123) return "Marvell 88E6123"; - if (ret == ID_6161_A1) + if (ret == PORT_SWITCH_ID_6161_A1) return "Marvell 88E6161 (A1)"; - if (ret == ID_6161_A2) + if (ret == PORT_SWITCH_ID_6161_A2) return "Marvell 88E6161 (A2)"; - if ((ret & 0xfff0) == ID_6161) + if ((ret & 0xfff0) == PORT_SWITCH_ID_6161) return "Marvell 88E6161"; - if (ret == ID_6165_A1) + if (ret == PORT_SWITCH_ID_6165_A1) return "Marvell 88E6165 (A1)"; - if (ret == ID_6165_A2) + if (ret == PORT_SWITCH_ID_6165_A2) return "Marvell 88e6165 (A2)"; - if ((ret & 0xfff0) == ID_6165) + if ((ret & 0xfff0) == PORT_SWITCH_ID_6165) return "Marvell 88E6165"; } @@ -247,11 +247,11 @@ static int mv88e6123_61_65_setup(struct dsa_switch *ds) return ret; switch (ps->id) { - case ID_6123: + case PORT_SWITCH_ID_6123: ps->num_ports = 3; break; - case ID_6161: - case ID_6165: + case PORT_SWITCH_ID_6161: + case PORT_SWITCH_ID_6165: ps->num_ports = 6; break; default: diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 5bec7a60b476..e54824fa0d95 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -25,17 +25,17 @@ static char *mv88e6131_probe(struct device *host_dev, int sw_addr) if (bus == NULL) return NULL; - ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); + ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); if (ret >= 0) { int ret_masked = ret & 0xfff0; - if (ret_masked == ID_6085) + if (ret_masked == PORT_SWITCH_ID_6085) return "Marvell 88E6085"; - if (ret_masked == ID_6095) + if (ret_masked == PORT_SWITCH_ID_6095) return "Marvell 88E6095/88E6095F"; - if (ret == ID_6131_B2) + if (ret == PORT_SWITCH_ID_6131_B2) return "Marvell 88E6131 (B2)"; - if (ret_masked == ID_6131) + if (ret_masked == PORT_SWITCH_ID_6131) return "Marvell 88E6131"; } @@ -135,7 +135,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) * (100 Mb/s on 6085) full duplex. */ if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p)) - if (ps->id == ID_6085) + if (ps->id == PORT_SWITCH_ID_6085) REG_WRITE(addr, 0x01, 0x003d); /* 100 Mb/s */ else REG_WRITE(addr, 0x01, 0x003e); /* 1000 Mb/s */ @@ -162,7 +162,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) /* On 6085, unknown multicast forward is controlled * here rather than in Port Control 2 register. */ - if (ps->id == ID_6085) + if (ps->id == PORT_SWITCH_ID_6085) val |= 0x0008; } if (ds->dsa_port_mask & (1 << p)) @@ -181,7 +181,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) * If this is the upstream port for this switch, enable * forwarding of unknown multicast addresses. */ - if (ps->id == ID_6085) + if (ps->id == PORT_SWITCH_ID_6085) /* on 6085, bits 3:0 are reserved, bit 6 control ARP * mirroring, and multicast forward is handled in * Port Control register. @@ -233,14 +233,14 @@ static int mv88e6131_setup(struct dsa_switch *ds) mv88e6xxx_ppu_state_init(ds); switch (ps->id) { - case ID_6085: + case PORT_SWITCH_ID_6085: ps->num_ports = 10; break; - case ID_6095: + case PORT_SWITCH_ID_6095: ps->num_ports = 11; break; - case ID_6131: - case ID_6131_B2: + case PORT_SWITCH_ID_6131: + case PORT_SWITCH_ID_6131_B2: ps->num_ports = 8; break; default: diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 7314e7d71a67..9104efea0e3e 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -25,11 +25,11 @@ static char *mv88e6171_probe(struct device *host_dev, int sw_addr) if (bus == NULL) return NULL; - ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); + ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); if (ret >= 0) { - if ((ret & 0xfff0) == ID_6171) + if ((ret & 0xfff0) == PORT_SWITCH_ID_6171) return "Marvell 88E6171"; - if ((ret & 0xfff0) == ID_6172) + if ((ret & 0xfff0) == PORT_SWITCH_ID_6172) return "Marvell 88E6172"; } @@ -263,7 +263,7 @@ static int mv88e6171_get_eee(struct dsa_switch *ds, int port, { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - if (ps->id == ID_6172) + if (ps->id == PORT_SWITCH_ID_6172) return mv88e6xxx_get_eee(ds, port, e); return -EOPNOTSUPP; @@ -274,7 +274,7 @@ static int mv88e6171_set_eee(struct dsa_switch *ds, int port, { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - if (ps->id == ID_6172) + if (ps->id == PORT_SWITCH_ID_6172) return mv88e6xxx_set_eee(ds, port, phydev, e); return -EOPNOTSUPP; diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index a1be6e3c0351..126c11b81e75 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -30,15 +30,15 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr) if (bus == NULL) return NULL; - ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); + ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), PORT_SWITCH_ID); if (ret >= 0) { - if ((ret & 0xfff0) == 0x1760) + if ((ret & 0xfff0) == PORT_SWITCH_ID_6176) return "Marvell 88E6176"; - if (ret == 0x3521) + if (ret == PORT_SWITCH_ID_6352_A0) return "Marvell 88E6352 (A0)"; - if (ret == 0x3522) + if (ret == PORT_SWITCH_ID_6352_A1) return "Marvell 88E6352 (A1)"; - if ((ret & 0xfff0) == 0x3520) + if ((ret & 0xfff0) == PORT_SWITCH_ID_6352) return "Marvell 88E6352"; } diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index b360fe5346d3..488b6545dfb5 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -33,11 +33,11 @@ static int mv88e6xxx_reg_wait_ready(struct mii_bus *bus, int sw_addr) int i; for (i = 0; i < 16; i++) { - ret = mdiobus_read(bus, sw_addr, 0); + ret = mdiobus_read(bus, sw_addr, SMI_CMD); if (ret < 0) return ret; - if ((ret & 0x8000) == 0) + if ((ret & SMI_CMD_BUSY) == 0) return 0; } @@ -57,7 +57,8 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg) return ret; /* Transmit the read command. */ - ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg); + ret = mdiobus_write(bus, sw_addr, SMI_CMD, + SMI_CMD_OP_22_READ | (addr << 5) | reg); if (ret < 0) return ret; @@ -67,7 +68,7 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg) return ret; /* Read the data. */ - ret = mdiobus_read(bus, sw_addr, 1); + ret = mdiobus_read(bus, sw_addr, SMI_DATA); if (ret < 0) return ret; @@ -119,12 +120,13 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr, return ret; /* Transmit the data to write. */ - ret = mdiobus_write(bus, sw_addr, 1, val); + ret = mdiobus_write(bus, sw_addr, SMI_DATA, val); if (ret < 0) return ret; /* Transmit the write command. */ - ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg); + ret = mdiobus_write(bus, sw_addr, SMI_CMD, + SMI_CMD_OP_22_WRITE | (addr << 5) | reg); if (ret < 0) return ret; @@ -166,26 +168,26 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val) int mv88e6xxx_config_prio(struct dsa_switch *ds) { /* Configure the IP ToS mapping registers. */ - REG_WRITE(REG_GLOBAL, 0x10, 0x0000); - REG_WRITE(REG_GLOBAL, 0x11, 0x0000); - REG_WRITE(REG_GLOBAL, 0x12, 0x5555); - REG_WRITE(REG_GLOBAL, 0x13, 0x5555); - REG_WRITE(REG_GLOBAL, 0x14, 0xaaaa); - REG_WRITE(REG_GLOBAL, 0x15, 0xaaaa); - REG_WRITE(REG_GLOBAL, 0x16, 0xffff); - REG_WRITE(REG_GLOBAL, 0x17, 0xffff); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_0, 0x0000); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_1, 0x0000); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_2, 0x5555); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_3, 0x5555); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_4, 0xaaaa); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_5, 0xaaaa); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_6, 0xffff); + REG_WRITE(REG_GLOBAL, GLOBAL_IP_PRI_7, 0xffff); /* Configure the IEEE 802.1p priority mapping register. */ - REG_WRITE(REG_GLOBAL, 0x18, 0xfa41); + REG_WRITE(REG_GLOBAL, GLOBAL_IEEE_PRI, 0xfa41); return 0; } int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr) { - REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]); - REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]); - REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]); + REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 8) | addr[1]); + REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]); + REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]); return 0; } @@ -199,12 +201,13 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr) int j; /* Write the MAC address byte. */ - REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]); + REG_WRITE(REG_GLOBAL2, GLOBAL2_SWITCH_MAC, + GLOBAL2_SWITCH_MAC_BUSY | (i << 8) | addr[i]); /* Wait for the write to complete. */ for (j = 0; j < 16; j++) { - ret = REG_READ(REG_GLOBAL2, 0x0d); - if ((ret & 0x8000) == 0) + ret = REG_READ(REG_GLOBAL2, GLOBAL2_SWITCH_MAC); + if ((ret & GLOBAL2_SWITCH_MAC_BUSY) == 0) break; } if (j == 16) @@ -237,14 +240,16 @@ static int mv88e6xxx_ppu_disable(struct dsa_switch *ds) int ret; unsigned long timeout; - ret = REG_READ(REG_GLOBAL, 0x04); - REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000); + ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL); + REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, + ret & ~GLOBAL_CONTROL_PPU_ENABLE); timeout = jiffies + 1 * HZ; while (time_before(jiffies, timeout)) { - ret = REG_READ(REG_GLOBAL, 0x00); + ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS); usleep_range(1000, 2000); - if ((ret & 0xc000) != 0xc000) + if ((ret & GLOBAL_STATUS_PPU_MASK) != + GLOBAL_STATUS_PPU_POLLING) return 0; } @@ -256,14 +261,15 @@ static int mv88e6xxx_ppu_enable(struct dsa_switch *ds) int ret; unsigned long timeout; - ret = REG_READ(REG_GLOBAL, 0x04); - REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000); + ret = REG_READ(REG_GLOBAL, GLOBAL_CONTROL); + REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, ret | GLOBAL_CONTROL_PPU_ENABLE); timeout = jiffies + 1 * HZ; while (time_before(jiffies, timeout)) { - ret = REG_READ(REG_GLOBAL, 0x00); + ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS); usleep_range(1000, 2000); - if ((ret & 0xc000) == 0xc000) + if ((ret & GLOBAL_STATUS_PPU_MASK) == + GLOBAL_STATUS_PPU_POLLING) return 0; } @@ -384,11 +390,12 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) link = 0; if (dev->flags & IFF_UP) { - port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), 0x00); + port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), + PORT_STATUS); if (port_status < 0) continue; - link = !!(port_status & 0x0800); + link = !!(port_status & PORT_STATUS_LINK); } if (!link) { @@ -399,22 +406,22 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) continue; } - switch (port_status & 0x0300) { - case 0x0000: + switch (port_status & PORT_STATUS_SPEED_MASK) { + case PORT_STATUS_SPEED_10: speed = 10; break; - case 0x0100: + case PORT_STATUS_SPEED_100: speed = 100; break; - case 0x0200: + case PORT_STATUS_SPEED_1000: speed = 1000; break; default: speed = -1; break; } - duplex = (port_status & 0x0400) ? 1 : 0; - fc = (port_status & 0x8000) ? 1 : 0; + duplex = (port_status & PORT_STATUS_DUPLEX) ? 1 : 0; + fc = (port_status & PORT_STATUS_PAUSE_EN) ? 1 : 0; if (!netif_carrier_ok(dev)) { netdev_info(dev, @@ -433,8 +440,8 @@ static int mv88e6xxx_stats_wait(struct dsa_switch *ds) int i; for (i = 0; i < 10; i++) { - ret = REG_READ(REG_GLOBAL, 0x1d); - if ((ret & 0x8000) == 0) + ret = REG_READ(REG_GLOBAL, GLOBAL_STATS_OP); + if ((ret & GLOBAL_STATS_OP_BUSY) == 0) return 0; } @@ -446,7 +453,9 @@ static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) int ret; /* Snapshot the hardware statistics counters for this port. */ - REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port); + REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, + GLOBAL_STATS_OP_CAPTURE_PORT | + GLOBAL_STATS_OP_HIST_RX_TX | port); /* Wait for the snapshotting to complete. */ ret = mv88e6xxx_stats_wait(ds); @@ -463,7 +472,9 @@ static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val) *val = 0; - ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x1d, 0xcc00 | stat); + ret = mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_STATS_OP, + GLOBAL_STATS_OP_READ_CAPTURED | + GLOBAL_STATS_OP_HIST_RX_TX | stat); if (ret < 0) return; @@ -471,13 +482,13 @@ static void mv88e6xxx_stats_read(struct dsa_switch *ds, int stat, u32 *val) if (ret < 0) return; - ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1e); + ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_32); if (ret < 0) return; _val = ret << 16; - ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x1f); + ret = mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_STATS_COUNTER_01); if (ret < 0) return; @@ -527,9 +538,11 @@ static bool have_sw_in_discards(struct dsa_switch *ds) struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); switch (ps->id) { - case ID_6095: case ID_6161: case ID_6165: - case ID_6171: case ID_6172: case ID_6176: - case ID_6182: case ID_6185: case ID_6352: + case PORT_SWITCH_ID_6095: case PORT_SWITCH_ID_6161: + case PORT_SWITCH_ID_6165: case PORT_SWITCH_ID_6171: + case PORT_SWITCH_ID_6172: case PORT_SWITCH_ID_6176: + case PORT_SWITCH_ID_6182: case PORT_SWITCH_ID_6185: + case PORT_SWITCH_ID_6352: return true; default: return false; @@ -723,17 +736,20 @@ static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) int mv88e6xxx_phy_wait(struct dsa_switch *ds) { - return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x18, 0x8000); + return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP, + GLOBAL2_SMI_OP_BUSY); } int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds) { - return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x14, 0x0800); + return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP, + GLOBAL2_EEPROM_OP_LOAD); } int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds) { - return mv88e6xxx_wait(ds, REG_GLOBAL2, 0x14, 0x8000); + return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP, + GLOBAL2_EEPROM_OP_BUSY); } /* Must be called with SMI lock held */ @@ -758,7 +774,8 @@ static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) /* Must be called with SMI lock held */ static int _mv88e6xxx_atu_wait(struct dsa_switch *ds) { - return _mv88e6xxx_wait(ds, REG_GLOBAL, 0x0b, ATU_BUSY); + return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP, + GLOBAL_ATU_OP_BUSY); } /* Must be called with phy mutex held */ @@ -767,21 +784,23 @@ static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, { int ret; - REG_WRITE(REG_GLOBAL2, 0x18, 0x9800 | (addr << 5) | regnum); + REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP, + GLOBAL2_SMI_OP_22_READ | (addr << 5) | regnum); ret = mv88e6xxx_phy_wait(ds); if (ret < 0) return ret; - return REG_READ(REG_GLOBAL2, 0x19); + return REG_READ(REG_GLOBAL2, GLOBAL2_SMI_DATA); } /* Must be called with phy mutex held */ static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum, u16 val) { - REG_WRITE(REG_GLOBAL2, 0x19, val); - REG_WRITE(REG_GLOBAL2, 0x18, 0x9400 | (addr << 5) | regnum); + REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_DATA, val); + REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP, + GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | regnum); return mv88e6xxx_phy_wait(ds); } @@ -800,11 +819,11 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) e->eee_enabled = !!(reg & 0x0200); e->tx_lpi_enabled = !!(reg & 0x0100); - reg = mv88e6xxx_reg_read(ds, REG_PORT(port), 0); + reg = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS); if (reg < 0) goto out; - e->eee_active = !!(reg & 0x0040); + e->eee_active = !!(reg & PORT_STATUS_EEE); reg = 0; out: @@ -846,7 +865,7 @@ static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd) if (ret < 0) return ret; - ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x0b, cmd); + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_OP, cmd); if (ret < 0) return ret; @@ -861,7 +880,7 @@ static int _mv88e6xxx_flush_fid(struct dsa_switch *ds, int fid) if (ret < 0) return ret; - return _mv88e6xxx_atu_cmd(ds, fid, ATU_CMD_FLUSH_NONSTATIC_FID); + return _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB); } static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state) @@ -872,23 +891,25 @@ static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state) mutex_lock(&ps->smi_mutex); - reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), 0x04); + reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL); if (reg < 0) goto abort; - oldstate = reg & PSTATE_MASK; + oldstate = reg & PORT_CONTROL_STATE_MASK; if (oldstate != state) { /* Flush forwarding database if we're moving a port * from Learning or Forwarding state to Disabled or * Blocking or Listening state. */ - if (oldstate >= PSTATE_LEARNING && state <= PSTATE_BLOCKING) { + if (oldstate >= PORT_CONTROL_STATE_LEARNING && + state <= PORT_CONTROL_STATE_BLOCKING) { ret = _mv88e6xxx_flush_fid(ds, ps->fid[port]); if (ret) goto abort; } - reg = (reg & ~PSTATE_MASK) | state; - ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), 0x04, reg); + reg = (reg & ~PORT_CONTROL_STATE_MASK) | state; + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL, + reg); } abort: @@ -909,7 +930,7 @@ static int _mv88e6xxx_update_port_config(struct dsa_switch *ds, int port) reg |= (ps->bridge_mask[fid] | (1 << dsa_upstream_port(ds))) & ~(1 << port); - return _mv88e6xxx_reg_write(ds, REG_PORT(port), 0x06, reg); + return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN, reg); } /* Must be called with smi lock held */ @@ -1021,18 +1042,18 @@ int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state) switch (state) { case BR_STATE_DISABLED: - stp_state = PSTATE_DISABLED; + stp_state = PORT_CONTROL_STATE_DISABLED; break; case BR_STATE_BLOCKING: case BR_STATE_LISTENING: - stp_state = PSTATE_BLOCKING; + stp_state = PORT_CONTROL_STATE_BLOCKING; break; case BR_STATE_LEARNING: - stp_state = PSTATE_LEARNING; + stp_state = PORT_CONTROL_STATE_LEARNING; break; case BR_STATE_FORWARDING: default: - stp_state = PSTATE_FORWARDING; + stp_state = PORT_CONTROL_STATE_FORWARDING; break; } @@ -1054,8 +1075,9 @@ static int __mv88e6xxx_write_addr(struct dsa_switch *ds, int i, ret; for (i = 0; i < 3; i++) { - ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x0d + i, - (addr[i * 2] << 8) | addr[i * 2 + 1]); + ret = _mv88e6xxx_reg_write( + ds, REG_GLOBAL, GLOBAL_ATU_MAC_01 + i, + (addr[i * 2] << 8) | addr[i * 2 + 1]); if (ret < 0) return ret; } @@ -1068,7 +1090,8 @@ static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr) int i, ret; for (i = 0; i < 3; i++) { - ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x0d + i); + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, + GLOBAL_ATU_MAC_01 + i); if (ret < 0) return ret; addr[i * 2] = ret >> 8; @@ -1093,12 +1116,12 @@ static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port, if (ret < 0) return ret; - ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x0c, + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, (0x10 << port) | state); if (ret) return ret; - ret = _mv88e6xxx_atu_cmd(ds, fid, ATU_CMD_LOAD_FID); + ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_LOAD_DB); return ret; } @@ -1107,7 +1130,8 @@ int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid) { int state = is_multicast_ether_addr(addr) ? - FDB_STATE_MC_STATIC : FDB_STATE_STATIC; + GLOBAL_ATU_DATA_STATE_MC_STATIC : + GLOBAL_ATU_DATA_STATE_UC_STATIC; struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); int ret; @@ -1125,7 +1149,8 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, int ret; mutex_lock(&ps->smi_mutex); - ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, FDB_STATE_UNUSED); + ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, + GLOBAL_ATU_DATA_STATE_UNUSED); mutex_unlock(&ps->smi_mutex); return ret; @@ -1147,15 +1172,15 @@ static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, return ret; do { - ret = _mv88e6xxx_atu_cmd(ds, fid, ATU_CMD_GETNEXT_FID); + ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB); if (ret < 0) return ret; - ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, 0x0c); + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA); if (ret < 0) return ret; - state = ret & FDB_STATE_MASK; - if (state == FDB_STATE_UNUSED) + state = ret & GLOBAL_ATU_DATA_STATE_MASK; + if (state == GLOBAL_ATU_DATA_STATE_UNUSED) return -ENOENT; } while (!(((ret >> 4) & 0xff) & (1 << port))); @@ -1164,7 +1189,8 @@ static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, return ret; *is_static = state == (is_multicast_ether_addr(addr) ? - FDB_STATE_MC_STATIC : FDB_STATE_STATIC); + GLOBAL_ATU_DATA_STATE_MC_STATIC : + GLOBAL_ATU_DATA_STATE_UC_STATIC); return 0; } @@ -1209,7 +1235,8 @@ int mv88e6xxx_setup_port_common(struct dsa_switch *ds, int port) /* Port Control 1: disable trunking, disable sending * learning messages to this port. */ - ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), 0x05, 0x0000); + ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN, + 0x0000); if (ret) goto abort; @@ -1246,7 +1273,7 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) mutex_init(&ps->stats_mutex); mutex_init(&ps->phy_mutex); - ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0; + ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0; ps->fid_mask = (1 << DSA_MAX_PORTS) - 1; @@ -1265,8 +1292,8 @@ int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active) /* Set all ports to the disabled state. */ for (i = 0; i < ps->num_ports; i++) { - ret = REG_READ(REG_PORT(i), 0x04); - REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc); + ret = REG_READ(REG_PORT(i), PORT_CONTROL); + REG_WRITE(REG_PORT(i), PORT_CONTROL, ret & 0xfffc); } /* Wait for transmit queues to drain. */ diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index fbbedc07754f..e045154f3364 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -11,69 +11,199 @@ #ifndef __MV88E6XXX_H #define __MV88E6XXX_H -/* switch product IDs */ - -#define ID_6085 0x04a0 -#define ID_6095 0x0950 - -#define ID_6123 0x1210 -#define ID_6123_A1 0x1212 -#define ID_6123_A2 0x1213 - -#define ID_6131 0x1060 -#define ID_6131_B2 0x1066 - -#define ID_6152 0x1a40 -#define ID_6155 0x1a50 - -#define ID_6161 0x1610 -#define ID_6161_A1 0x1612 -#define ID_6161_A2 0x1613 - -#define ID_6165 0x1650 -#define ID_6165_A1 0x1652 -#define ID_6165_A2 0x1653 - -#define ID_6171 0x1710 -#define ID_6172 0x1720 -#define ID_6176 0x1760 - -#define ID_6182 0x1a60 -#define ID_6185 0x1a70 - -#define ID_6352 0x3520 -#define ID_6352_A0 0x3521 -#define ID_6352_A1 0x3522 - -/* Registers */ +#define SMI_CMD 0x00 +#define SMI_CMD_BUSY BIT(15) +#define SMI_CMD_CLAUSE_22 BIT(12) +#define SMI_CMD_OP_22_WRITE ((1 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) +#define SMI_CMD_OP_22_READ ((2 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22) +#define SMI_CMD_OP_45_WRITE_ADDR ((0 << 10) | SMI_CMD_BUSY) +#define SMI_CMD_OP_45_WRITE_DATA ((1 << 10) | SMI_CMD_BUSY) +#define SMI_CMD_OP_45_READ_DATA ((2 << 10) | SMI_CMD_BUSY) +#define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY) +#define SMI_DATA 0x01 #define REG_PORT(p) (0x10 + (p)) +#define PORT_STATUS 0x00 +#define PORT_STATUS_PAUSE_EN BIT(15) +#define PORT_STATUS_MY_PAUSE BIT(14) +#define PORT_STATUS_HD_FLOW BIT(13) +#define PORT_STATUS_PHY_DETECT BIT(12) +#define PORT_STATUS_LINK BIT(11) +#define PORT_STATUS_DUPLEX BIT(10) +#define PORT_STATUS_SPEED_MASK 0x0300 +#define PORT_STATUS_SPEED_10 0x0000 +#define PORT_STATUS_SPEED_100 0x0100 +#define PORT_STATUS_SPEED_1000 0x0200 +#define PORT_STATUS_EEE BIT(6) /* 6352 */ +#define PORT_STATUS_AM_DIS BIT(6) /* 6165 */ +#define PORT_STATUS_MGMII BIT(6) /* 6185 */ +#define PORT_STATUS_TX_PAUSED BIT(5) +#define PORT_STATUS_FLOW_CTRL BIT(4) +#define PORT_PCS_CTRL 0x01 +#define PORT_SWITCH_ID 0x03 +#define PORT_SWITCH_ID_6085 0x04a0 +#define PORT_SWITCH_ID_6095 0x0950 +#define PORT_SWITCH_ID_6123 0x1210 +#define PORT_SWITCH_ID_6123_A1 0x1212 +#define PORT_SWITCH_ID_6123_A2 0x1213 +#define PORT_SWITCH_ID_6131 0x1060 +#define PORT_SWITCH_ID_6131_B2 0x1066 +#define PORT_SWITCH_ID_6152 0x1a40 +#define PORT_SWITCH_ID_6155 0x1a50 +#define PORT_SWITCH_ID_6161 0x1610 +#define PORT_SWITCH_ID_6161_A1 0x1612 +#define PORT_SWITCH_ID_6161_A2 0x1613 +#define PORT_SWITCH_ID_6165 0x1650 +#define PORT_SWITCH_ID_6165_A1 0x1652 +#define PORT_SWITCH_ID_6165_A2 0x1653 +#define PORT_SWITCH_ID_6171 0x1710 +#define PORT_SWITCH_ID_6172 0x1720 +#define PORT_SWITCH_ID_6176 0x1760 +#define PORT_SWITCH_ID_6182 0x1a60 +#define PORT_SWITCH_ID_6185 0x1a70 +#define PORT_SWITCH_ID_6352 0x3520 +#define PORT_SWITCH_ID_6352_A0 0x3521 +#define PORT_SWITCH_ID_6352_A1 0x3522 +#define PORT_CONTROL 0x04 +#define PORT_CONTROL_STATE_MASK 0x03 +#define PORT_CONTROL_STATE_DISABLED 0x00 +#define PORT_CONTROL_STATE_BLOCKING 0x01 +#define PORT_CONTROL_STATE_LEARNING 0x02 +#define PORT_CONTROL_STATE_FORWARDING 0x03 +#define PORT_CONTROL_1 0x05 +#define PORT_BASE_VLAN 0x06 +#define PORT_DEFAULT_VLAN 0x07 +#define PORT_CONTROL_2 0x08 +#define PORT_RATE_CONTROL 0x09 +#define PORT_RATE_CONTROL_2 0x0a +#define PORT_ASSOC_VECTOR 0x0b +#define PORT_IN_DISCARD_LO 0x10 +#define PORT_IN_DISCARD_HI 0x11 +#define PORT_IN_FILTERED 0x12 +#define PORT_OUT_FILTERED 0x13 +#define PORT_TAG_REGMAP_0123 0x19 +#define PORT_TAG_REGMAP_4567 0x1a + #define REG_GLOBAL 0x1b +#define GLOBAL_STATUS 0x00 +#define GLOBAL_STATUS_PPU_STATE BIT(15) /* 6351 and 6171 */ +/* Two bits for 6165, 6185 etc */ +#define GLOBAL_STATUS_PPU_MASK (0x3 << 14) +#define GLOBAL_STATUS_PPU_DISABLED_RST (0x0 << 14) +#define GLOBAL_STATUS_PPU_INITIALIZING (0x1 << 14) +#define GLOBAL_STATUS_PPU_DISABLED (0x2 << 14) +#define GLOBAL_STATUS_PPU_POLLING (0x3 << 14) +#define GLOBAL_MAC_01 0x01 +#define GLOBAL_MAC_23 0x02 +#define GLOBAL_MAC_45 0x03 +#define GLOBAL_CONTROL 0x04 +#define GLOBAL_CONTROL_SW_RESET BIT(15) +#define GLOBAL_CONTROL_PPU_ENABLE BIT(14) +#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13) /* 6352 */ +#define GLOBAL_CONTROL_SCHED_PRIO BIT(11) /* 6152 */ +#define GLOBAL_CONTROL_MAX_FRAME_1632 BIT(10) /* 6152 */ +#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9) /* 6152 */ +#define GLOBAL_CONTROL_DEVICE_EN BIT(7) +#define GLOBAL_CONTROL_STATS_DONE_EN BIT(6) +#define GLOBAL_CONTROL_VTU_PROBLEM_EN BIT(5) +#define GLOBAL_CONTROL_VTU_DONE_EN BIT(4) +#define GLOBAL_CONTROL_ATU_PROBLEM_EN BIT(3) +#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2) +#define GLOBAL_CONTROL_TCAM_EN BIT(1) +#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0) +#define GLOBAL_VTU_OP 0x05 +#define GLOBAL_VTU_VID 0x06 +#define GLOBAL_VTU_DATA_0_3 0x07 +#define GLOBAL_VTU_DATA_4_7 0x08 +#define GLOBAL_VTU_DATA_8_11 0x09 +#define GLOBAL_ATU_CONTROL 0x0a +#define GLOBAL_ATU_OP 0x0b +#define GLOBAL_ATU_OP_BUSY BIT(15) +#define GLOBAL_ATU_OP_NOP (0 << 12) +#define GLOBAL_ATU_OP_FLUSH_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_NON_STATIC ((2 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) +#define GLOBAL_ATU_DATA 0x0c +#define GLOBAL_ATU_DATA_STATE_MASK 0x0f +#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00 +#define GLOBAL_ATU_DATA_STATE_UC_MGMT 0x0d +#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e +#define GLOBAL_ATU_DATA_STATE_UC_PRIO_OVER 0x0f +#define GLOBAL_ATU_DATA_STATE_MC_NONE_RATE 0x05 +#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07 +#define GLOBAL_ATU_DATA_STATE_MC_MGMT 0x0e +#define GLOBAL_ATU_DATA_STATE_MC_PRIO_OVER 0x0f +#define GLOBAL_ATU_MAC_01 0x0d +#define GLOBAL_ATU_MAC_23 0x0e +#define GLOBAL_ATU_MAC_45 0x0f +#define GLOBAL_IP_PRI_0 0x10 +#define GLOBAL_IP_PRI_1 0x11 +#define GLOBAL_IP_PRI_2 0x12 +#define GLOBAL_IP_PRI_3 0x13 +#define GLOBAL_IP_PRI_4 0x14 +#define GLOBAL_IP_PRI_5 0x15 +#define GLOBAL_IP_PRI_6 0x16 +#define GLOBAL_IP_PRI_7 0x17 +#define GLOBAL_IEEE_PRI 0x18 +#define GLOBAL_CORE_TAG_TYPE 0x19 +#define GLOBAL_MONITOR_CONTROL 0x1a +#define GLOBAL_CONTROL_2 0x1c +#define GLOBAL_STATS_OP 0x1d +#define GLOBAL_STATS_OP_BUSY BIT(15) +#define GLOBAL_STATS_OP_NOP (0 << 12) +#define GLOBAL_STATS_OP_FLUSH_ALL ((1 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_FLUSH_PORT ((2 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_READ_CAPTURED ((4 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_CAPTURE_PORT ((5 << 12) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_RX ((1 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_TX ((2 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_OP_HIST_RX_TX ((3 << 10) | GLOBAL_STATS_OP_BUSY) +#define GLOBAL_STATS_COUNTER_32 0x1e +#define GLOBAL_STATS_COUNTER_01 0x1f + #define REG_GLOBAL2 0x1c - -/* ATU commands */ - -#define ATU_BUSY 0x8000 - -#define ATU_CMD_LOAD_FID (ATU_BUSY | 0x3000) -#define ATU_CMD_GETNEXT_FID (ATU_BUSY | 0x4000) -#define ATU_CMD_FLUSH_NONSTATIC_FID (ATU_BUSY | 0x6000) - -/* port states */ - -#define PSTATE_MASK 0x03 -#define PSTATE_DISABLED 0x00 -#define PSTATE_BLOCKING 0x01 -#define PSTATE_LEARNING 0x02 -#define PSTATE_FORWARDING 0x03 - -/* FDB states */ - -#define FDB_STATE_MASK 0x0f - -#define FDB_STATE_UNUSED 0x00 -#define FDB_STATE_MC_STATIC 0x07 /* static multicast */ -#define FDB_STATE_STATIC 0x0e /* static unicast */ +#define GLOBAL2_INT_SOURCE 0x00 +#define GLOBAL2_INT_MASK 0x01 +#define GLOBAL2_MGMT_EN_2X 0x02 +#define GLOBAL2_MGMT_EN_0X 0x03 +#define GLOBAL2_FLOW_CONTROL 0x04 +#define GLOBAL2_SWITCH_MGMT 0x05 +#define GLOBAL2_DEVICE_MAPPING 0x06 +#define GLOBAL2_TRUNK_MASK 0x07 +#define GLOBAL2_TRUNK_MAPPING 0x08 +#define GLOBAL2_INGRESS_OP 0x09 +#define GLOBAL2_INGRESS_DATA 0x0a +#define GLOBAL2_PVT_ADDR 0x0b +#define GLOBAL2_PVT_DATA 0x0c +#define GLOBAL2_SWITCH_MAC 0x0d +#define GLOBAL2_SWITCH_MAC_BUSY BIT(15) +#define GLOBAL2_ATU_STATS 0x0e +#define GLOBAL2_PRIO_OVERRIDE 0x0f +#define GLOBAL2_EEPROM_OP 0x14 +#define GLOBAL2_EEPROM_OP_BUSY BIT(15) +#define GLOBAL2_EEPROM_OP_LOAD BIT(11) +#define GLOBAL2_EEPROM_DATA 0x15 +#define GLOBAL2_PTP_AVB_OP 0x16 +#define GLOBAL2_PTP_AVB_DATA 0x17 +#define GLOBAL2_SMI_OP 0x18 +#define GLOBAL2_SMI_OP_BUSY BIT(15) +#define GLOBAL2_SMI_OP_CLAUSE_22 BIT(12) +#define GLOBAL2_SMI_OP_22_WRITE ((1 << 10) | GLOBAL2_SMI_OP_BUSY | \ + GLOBAL2_SMI_OP_CLAUSE_22) +#define GLOBAL2_SMI_OP_22_READ ((2 << 10) | GLOBAL2_SMI_OP_BUSY | \ + GLOBAL2_SMI_OP_CLAUSE_22) +#define GLOBAL2_SMI_OP_45_WRITE_ADDR ((0 << 10) | GLOBAL2_SMI_OP_BUSY) +#define GLOBAL2_SMI_OP_45_WRITE_DATA ((1 << 10) | GLOBAL2_SMI_OP_BUSY) +#define GLOBAL2_SMI_OP_45_READ_DATA ((2 << 10) | GLOBAL2_SMI_OP_BUSY) +#define GLOBAL2_SMI_DATA 0x19 +#define GLOBAL2_SCRATCH_MISC 0x1a +#define GLOBAL2_WDOG_CONTROL 0x1b +#define GLOBAL2_QOS_WEIGHT 0x1c +#define GLOBAL2_MISC 0x1d struct mv88e6xxx_priv_state { /* When using multi-chip addressing, this mutex protects From f3a8b6b6a155210dac1f2a6ec4eb1b9ad04219df Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 2 Apr 2015 04:06:40 +0200 Subject: [PATCH 420/567] net: dsa: mv88e6xxx: Fix stats counters for 6352 family The statistic counters for the mv88e6172 never worked. This device is a member of the 6352 family of chips, which has a slightly different layout of the register used for capturing statistics. Add support for detecting this family and poking the port in the right place in the register. Signed-off-by: Andrew Lunn Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 488b6545dfb5..fc8d3b6ffe8e 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -434,6 +434,19 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) } } +static bool mv88e6xxx_6352_family(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case PORT_SWITCH_ID_6352: + case PORT_SWITCH_ID_6172: + case PORT_SWITCH_ID_6176: + return true; + } + return false; +} + static int mv88e6xxx_stats_wait(struct dsa_switch *ds) { int ret; @@ -452,6 +465,9 @@ static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) { int ret; + if (mv88e6xxx_6352_family(ds)) + port = (port + 1) << 5; + /* Snapshot the hardware statistics counters for this port. */ REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, GLOBAL_STATS_OP_CAPTURE_PORT | From 033f46b3c13d4072d8ee6b26dd1e90fdd06895d0 Mon Sep 17 00:00:00 2001 From: "tadeusz.struk@intel.com" Date: Wed, 1 Apr 2015 13:53:06 -0700 Subject: [PATCH 421/567] crypto: algif - explicitly mark end of data After the TX sgl is expanded we need to explicitly mark end of data at the last buffer that contains data. Changes in v2 - use type 'bool' and true/false for 'mark'. Signed-off-by: Tadeusz Struk Signed-off-by: David S. Miller --- crypto/algif_skcipher.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 2db1eb776932..0aa02635ceda 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -509,11 +509,11 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, struct skcipher_async_req *sreq; struct ablkcipher_request *req; struct skcipher_async_rsgl *last_rsgl = NULL; - unsigned int len = 0, tx_nents = skcipher_all_sg_nents(ctx); + unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx); unsigned int reqlen = sizeof(struct skcipher_async_req) + GET_REQ_SIZE(ctx) + GET_IV_SIZE(ctx); - int i = 0; int err = -ENOMEM; + bool mark = false; lock_sock(sk); req = kmalloc(reqlen, GFP_KERNEL); @@ -555,7 +555,7 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, iov_iter_count(&msg->msg_iter)); used = min_t(unsigned long, used, sg->length); - if (i == tx_nents) { + if (txbufs == tx_nents) { struct scatterlist *tmp; int x; /* Ran out of tx slots in async request @@ -573,10 +573,11 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, kfree(sreq->tsg); sreq->tsg = tmp; tx_nents *= 2; + mark = true; } /* Need to take over the tx sgl from ctx * to the asynch req - these sgls will be freed later */ - sg_set_page(sreq->tsg + i++, sg_page(sg), sg->length, + sg_set_page(sreq->tsg + txbufs++, sg_page(sg), sg->length, sg->offset); if (list_empty(&sreq->list)) { @@ -604,6 +605,9 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, iov_iter_advance(&msg->msg_iter, used); } + if (mark) + sg_mark_end(sreq->tsg + txbufs - 1); + ablkcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg, len, sreq->iv); err = ctx->enc ? crypto_ablkcipher_encrypt(req) : From c3370de64d563fa0db5e773b97b77ea7a961d131 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 1 Apr 2015 13:21:37 -0700 Subject: [PATCH 422/567] Bluetooth: Expose current Device ID information via debugfs For debugging purposes it is good to be able to read the current configured Device ID details. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hci_debugfs.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index e6255833a258..7db4220941cc 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c @@ -114,6 +114,30 @@ static const struct file_operations features_fops = { .release = single_release, }; +static int device_id_show(struct seq_file *f, void *ptr) +{ + struct hci_dev *hdev = f->private; + + hci_dev_lock(hdev); + seq_printf(f, "%4.4x:%4.4x:%4.4x:%4.4x\n", hdev->devid_source, + hdev->devid_vendor, hdev->devid_product, hdev->devid_version); + hci_dev_unlock(hdev); + + return 0; +} + +static int device_id_open(struct inode *inode, struct file *file) +{ + return single_open(file, device_id_show, inode->i_private); +} + +static const struct file_operations device_id_fops = { + .open = device_id_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int device_list_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; @@ -335,6 +359,8 @@ void hci_debugfs_create_common(struct hci_dev *hdev) debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev); debugfs_create_u8("hardware_error", 0444, hdev->debugfs, &hdev->hw_error_code); + debugfs_create_file("device_id", 0444, hdev->debugfs, hdev, + &device_id_fops); debugfs_create_file("device_list", 0444, hdev->debugfs, hdev, &device_list_fops); From 41533fe5b4f92adb3c40f263b889dc6addff550e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 1 Apr 2015 13:51:51 -0700 Subject: [PATCH 423/567] Bluetooth: Remove unneeded extra ( ) in valid flags check Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 48a0c250d5b8..1363dc616ace 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -499,7 +499,7 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) BIT(HCI_UART_INIT_PENDING) | BIT(HCI_UART_EXT_CONFIG); - if ((flags & ~valid_flags)) + if (flags & ~valid_flags) return -EINVAL; hu->hdev_flags = flags; From 8bf17a3619250944957c732e71659787528131c3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 1 Apr 2015 13:51:52 -0700 Subject: [PATCH 424/567] Bluetooth: Restrict CMTP flags to only valid ones The CMTP flags should be clearly restricted to valid ones. So this puts extra checks in place to ensure this. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/cmtp/core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 278a194e6af4..ddbc348c9dff 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -75,10 +75,11 @@ static void __cmtp_unlink_session(struct cmtp_session *session) static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci) { + u32 valid_flags = BIT(CMTP_LOOPBACK); memset(ci, 0, sizeof(*ci)); bacpy(&ci->bdaddr, &session->bdaddr); - ci->flags = session->flags; + ci->flags = session->flags & valid_flags; ci->state = session->state; ci->num = session->num; @@ -329,6 +330,7 @@ static int cmtp_session(void *arg) int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) { + u32 valid_flags = BIT(CMTP_LOOPBACK); struct cmtp_session *session, *s; int i, err; @@ -337,6 +339,9 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) if (!l2cap_is_socket(sock)) return -EBADFD; + if (req->flags & ~valid_flags) + return -EINVAL; + session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL); if (!session) return -ENOMEM; @@ -409,11 +414,15 @@ failed: int cmtp_del_connection(struct cmtp_conndel_req *req) { + u32 valid_flags = 0; struct cmtp_session *session; int err = 0; BT_DBG(""); + if (req->flags & ~valid_flags) + return -EINVAL; + down_read(&cmtp_session_sem); session = __cmtp_get_session(&req->bdaddr); From 5f5da99f1da5b01c7c45473a500c7dbb77a00958 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 1 Apr 2015 13:51:53 -0700 Subject: [PATCH 425/567] Bluetooth: Restrict HIDP flags to only valid ones The HIDP flags should be clearly restricted to valid ones. So this puts extra checks in place to ensure this. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hidp/core.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 07348e142f16..926a0e8b7136 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -70,10 +70,11 @@ static void hidp_session_terminate(struct hidp_session *s); static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci) { + u32 valid_flags = 0; memset(ci, 0, sizeof(*ci)); bacpy(&ci->bdaddr, &session->bdaddr); - ci->flags = session->flags; + ci->flags = session->flags & valid_flags; ci->state = BT_CONNECTED; if (session->input) { @@ -1312,6 +1313,7 @@ int hidp_connection_add(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) { + u32 valid_flags = 0; struct hidp_session *session; struct l2cap_conn *conn; struct l2cap_chan *chan; @@ -1321,6 +1323,9 @@ int hidp_connection_add(struct hidp_connadd_req *req, if (ret) return ret; + if (req->flags & ~valid_flags) + return -EINVAL; + chan = l2cap_pi(ctrl_sock->sk)->chan; conn = NULL; l2cap_chan_lock(chan); @@ -1351,8 +1356,12 @@ out_conn: int hidp_connection_del(struct hidp_conndel_req *req) { + u32 valid_flags = BIT(HIDP_VIRTUAL_CABLE_UNPLUG); struct hidp_session *session; + if (req->flags & ~valid_flags) + return -EINVAL; + session = hidp_session_find(&req->bdaddr); if (!session) return -ENOENT; From 0151e426b150db17992b49fa9ce96b79dace2aed Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 1 Apr 2015 13:51:54 -0700 Subject: [PATCH 426/567] Bluetooth: Restrict BNEP flags to only valid ones The BNEP flags should be clearly restricted to valid ones. So this puts extra checks in place to ensure this. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/bnep/core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 05f57e491ccb..c05eccc1cf82 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -525,6 +525,7 @@ static struct device_type bnep_type = { int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) { + u32 valid_flags = 0; struct net_device *dev; struct bnep_session *s, *ss; u8 dst[ETH_ALEN], src[ETH_ALEN]; @@ -535,6 +536,9 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) if (!l2cap_is_socket(sock)) return -EBADFD; + if (req->flags & ~valid_flags) + return -EINVAL; + baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst); baswap((void *) src, &l2cap_pi(sock->sk)->chan->src); @@ -611,11 +615,15 @@ failed: int bnep_del_connection(struct bnep_conndel_req *req) { + u32 valid_flags = 0; struct bnep_session *s; int err = 0; BT_DBG(""); + if (req->flags & ~valid_flags) + return -EINVAL; + down_read(&bnep_session_sem); s = __bnep_get_session(req->dst); @@ -631,10 +639,12 @@ int bnep_del_connection(struct bnep_conndel_req *req) static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s) { + u32 valid_flags = 0; + memset(ci, 0, sizeof(*ci)); memcpy(ci->dst, s->eh.h_source, ETH_ALEN); strcpy(ci->device, s->dev->name); - ci->flags = s->flags; + ci->flags = s->flags & valid_flags; ci->state = s->state; ci->role = s->role; } From 6de50f9fdb60a8d4c1cd94556106200ab1592e2d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 1 Apr 2015 12:52:12 -0700 Subject: [PATCH 427/567] Bluetooth: Export ECDH selftest result in debugfs When ECDH selftest is enabled, then besides printing the result into the kernel message buffer, also create a debugfs file that allows retrieving the same information. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/selftest.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/selftest.c b/net/bluetooth/selftest.c index 378f4064952c..dc688f13e496 100644 --- a/net/bluetooth/selftest.c +++ b/net/bluetooth/selftest.c @@ -21,6 +21,8 @@ SOFTWARE IS DISCLAIMED. */ +#include + #include #include @@ -154,6 +156,21 @@ static int __init test_ecdh_sample(const u8 priv_a[32], const u8 priv_b[32], return 0; } +static char test_ecdh_buffer[32]; + +static ssize_t test_ecdh_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + return simple_read_from_buffer(user_buf, count, ppos, test_ecdh_buffer, + strlen(test_ecdh_buffer)); +} + +static const struct file_operations test_ecdh_fops = { + .open = simple_open, + .read = test_ecdh_read, + .llseek = default_llseek, +}; + static int __init test_ecdh(void) { ktime_t calltime, delta, rettime; @@ -165,19 +182,19 @@ static int __init test_ecdh(void) err = test_ecdh_sample(priv_a_1, priv_b_1, pub_a_1, pub_b_1, dhkey_1); if (err) { BT_ERR("ECDH sample 1 failed"); - return err; + goto done; } err = test_ecdh_sample(priv_a_2, priv_b_2, pub_a_2, pub_b_2, dhkey_2); if (err) { BT_ERR("ECDH sample 2 failed"); - return err; + goto done; } err = test_ecdh_sample(priv_a_3, priv_a_3, pub_a_3, pub_a_3, dhkey_3); if (err) { BT_ERR("ECDH sample 3 failed"); - return err; + goto done; } rettime = ktime_get(); @@ -186,7 +203,17 @@ static int __init test_ecdh(void) BT_INFO("ECDH test passed in %llu usecs", duration); - return 0; +done: + if (!err) + snprintf(test_ecdh_buffer, sizeof(test_ecdh_buffer), + "PASS (%llu usecs)\n", duration); + else + snprintf(test_ecdh_buffer, sizeof(test_ecdh_buffer), "FAIL\n"); + + debugfs_create_file("selftest_ecdh", 0444, bt_debugfs, NULL, + &test_ecdh_fops); + + return err; } #else From 64dd374eac154f747623b256c59ecaf5affba724 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 1 Apr 2015 12:52:13 -0700 Subject: [PATCH 428/567] Bluetooth: Export SMP selftest result in debugfs When SMP selftest is enabled, then besides printing the result into the kernel message buffer, also create a debugfs file that allows retrieving the same information. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1910c5806974..1ab3dc9c8f99 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -3549,6 +3549,21 @@ static int __init test_h6(struct crypto_hash *tfm_cmac) return 0; } +static char test_smp_buffer[32]; + +static ssize_t test_smp_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + return simple_read_from_buffer(user_buf, count, ppos, test_smp_buffer, + strlen(test_smp_buffer)); +} + +static const struct file_operations test_smp_fops = { + .open = simple_open, + .read = test_smp_read, + .llseek = default_llseek, +}; + static int __init run_selftests(struct crypto_blkcipher *tfm_aes, struct crypto_hash *tfm_cmac) { @@ -3561,49 +3576,49 @@ static int __init run_selftests(struct crypto_blkcipher *tfm_aes, err = test_ah(tfm_aes); if (err) { BT_ERR("smp_ah test failed"); - return err; + goto done; } err = test_c1(tfm_aes); if (err) { BT_ERR("smp_c1 test failed"); - return err; + goto done; } err = test_s1(tfm_aes); if (err) { BT_ERR("smp_s1 test failed"); - return err; + goto done; } err = test_f4(tfm_cmac); if (err) { BT_ERR("smp_f4 test failed"); - return err; + goto done; } err = test_f5(tfm_cmac); if (err) { BT_ERR("smp_f5 test failed"); - return err; + goto done; } err = test_f6(tfm_cmac); if (err) { BT_ERR("smp_f6 test failed"); - return err; + goto done; } err = test_g2(tfm_cmac); if (err) { BT_ERR("smp_g2 test failed"); - return err; + goto done; } err = test_h6(tfm_cmac); if (err) { BT_ERR("smp_h6 test failed"); - return err; + goto done; } rettime = ktime_get(); @@ -3612,7 +3627,17 @@ static int __init run_selftests(struct crypto_blkcipher *tfm_aes, BT_INFO("SMP test passed in %llu usecs", duration); - return 0; +done: + if (!err) + snprintf(test_smp_buffer, sizeof(test_smp_buffer), + "PASS (%llu usecs)\n", duration); + else + snprintf(test_smp_buffer, sizeof(test_smp_buffer), "FAIL\n"); + + debugfs_create_file("selftest_smp", 0444, bt_debugfs, NULL, + &test_smp_fops); + + return err; } int __init bt_selftest_smp(void) From 840a1cf0cd533f30da792527ca5ff6a023d4a727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 27 Mar 2015 19:59:40 +0200 Subject: [PATCH 429/567] drm/i915: Reject the colorkey ioctls for primary and cursor planes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The legcy colorkey ioctls are only implemented for sprite planes, so reject the ioctl for primary/cursor planes. If we want to support colorkeying with these planes (assuming we have hw support of course) we should just move ahead with the colorkey property conversion. Testcase: kms_legacy_colorkey Cc: Tommi Rantala Cc: stable@vger.kernel.org Reference: http://mid.gmane.org/CA+ydwtr+bCo7LJ44JFmUkVRx144UDFgOS+aJTfK6KHtvBDVuAw@mail.gmail.com Reported-and-tested-by: Tommi Rantala Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_sprite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 0a52c44ad03d..9c5451c97942 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1322,7 +1322,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, drm_modeset_lock_all(dev); plane = drm_plane_find(dev, set->plane_id); - if (!plane) { + if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) { ret = -ENOENT; goto out_unlock; } @@ -1349,7 +1349,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, drm_modeset_lock_all(dev); plane = drm_plane_find(dev, get->plane_id); - if (!plane) { + if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) { ret = -ENOENT; goto out_unlock; } From 7ea24169097d3d3a3eab2dcc5773bc43fd5593e7 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 1 Apr 2015 14:26:34 -0700 Subject: [PATCH 430/567] x86/asm/entry/64: Disable opportunistic SYSRET if regs->flags has TF set When I wrote the opportunistic SYSRET code, I missed an important difference between SYSRET and IRET. Both instructions are capable of setting EFLAGS.TF, but they behave differently when doing so: - IRET will not issue a #DB trap after execution when it sets TF. This is critical -- otherwise you'd never be able to make forward progress when returning to userspace. - SYSRET, on the other hand, will trap with #DB immediately after returning to CPL3, and the next instruction will never execute. This breaks anything that opportunistically SYSRETs to a user context with TF set. For example, running this code with TF set and a SIGTRAP handler loaded never gets past 'post_nop': extern unsigned char post_nop[]; asm volatile ("pushfq\n\t" "popq %%r11\n\t" "nop\n\t" "post_nop:" : : "c" (post_nop) : "r11"); In my defense, I can't find this documented in the AMD or Intel manual. Fix it by using IRET to restore TF. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Thomas Gleixner Fixes: 2a23c6b8a9c4 ("x86_64, entry: Use sysret to return to userspace when possible") Link: http://lkml.kernel.org/r/9472f1ca4c19a38ecda45bba9c91b7168135fcfa.1427923514.git.luto@kernel.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/entry_64.S | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index 2babb393915e..f0095a76c182 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -799,7 +799,21 @@ retint_swapgs: /* return to user-space */ cmpq %r11,(EFLAGS-ARGOFFSET)(%rsp) /* R11 == RFLAGS */ jne opportunistic_sysret_failed - testq $X86_EFLAGS_RF,%r11 /* sysret can't restore RF */ + /* + * SYSRET can't restore RF. SYSRET can restore TF, but unlike IRET, + * restoring TF results in a trap from userspace immediately after + * SYSRET. This would cause an infinite loop whenever #DB happens + * with register state that satisfies the opportunistic SYSRET + * conditions. For example, single-stepping this user code: + * + * movq $stuck_here,%rcx + * pushfq + * popq %r11 + * stuck_here: + * + * would never get past 'stuck_here'. + */ + testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11 jnz opportunistic_sysret_failed /* nothing to check for RSP */ From f59df35fc28167886a0caf9f15db2f4a1f5932da Mon Sep 17 00:00:00 2001 From: Steffen Liebergeld Date: Thu, 2 Apr 2015 11:01:59 +0200 Subject: [PATCH 431/567] kgdb/x86: Fix reporting of 'si' in kgdb on x86_64 This patch fixes an error in kgdb for x86_64 which would report the value of dx when asked to give the value of si. Signed-off-by: Steffen Liebergeld Cc: Jason Wessel Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/kgdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 7ec1d5f8d283..25ecd56cefa8 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -72,7 +72,7 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { "bx", 8, offsetof(struct pt_regs, bx) }, { "cx", 8, offsetof(struct pt_regs, cx) }, { "dx", 8, offsetof(struct pt_regs, dx) }, - { "si", 8, offsetof(struct pt_regs, dx) }, + { "si", 8, offsetof(struct pt_regs, si) }, { "di", 8, offsetof(struct pt_regs, di) }, { "bp", 8, offsetof(struct pt_regs, bp) }, { "sp", 8, offsetof(struct pt_regs, sp) }, From adacb228d72b9529f8de0769cc33414c3012054d Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 17 Mar 2015 13:24:58 +0000 Subject: [PATCH 432/567] drm: Exynos: Respect framebuffer pitch for FIMD/Mixer When performing a modeset, use the framebuffer pitch value to set FIMD IMG_SIZE and Mixer SPAN registers. These are both defined as pitch - the distance between contiguous lines (bytes for FIMD, pixels for mixer). Fixes display on Snow (1366x768). Signed-off-by: Daniel Stone Tested-by: Javier Martinez Canillas Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 8 +++++--- drivers/gpu/drm/exynos/exynos_mixer.c | 17 ++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index c300e22da8ac..33a10ce967ea 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -147,6 +147,7 @@ struct fimd_win_data { unsigned int ovl_height; unsigned int fb_width; unsigned int fb_height; + unsigned int fb_pitch; unsigned int bpp; unsigned int pixel_format; dma_addr_t dma_addr; @@ -532,13 +533,14 @@ static void fimd_win_mode_set(struct exynos_drm_crtc *crtc, win_data->offset_y = plane->crtc_y; win_data->ovl_width = plane->crtc_width; win_data->ovl_height = plane->crtc_height; + win_data->fb_pitch = plane->pitch; win_data->fb_width = plane->fb_width; win_data->fb_height = plane->fb_height; win_data->dma_addr = plane->dma_addr[0] + offset; win_data->bpp = plane->bpp; win_data->pixel_format = plane->pixel_format; - win_data->buf_offsize = (plane->fb_width - plane->crtc_width) * - (plane->bpp >> 3); + win_data->buf_offsize = + plane->pitch - (plane->crtc_width * (plane->bpp >> 3)); win_data->line_size = plane->crtc_width * (plane->bpp >> 3); DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n", @@ -704,7 +706,7 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos) writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); /* buffer end address */ - size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3); + size = win_data->fb_pitch * win_data->ovl_height * (win_data->bpp >> 3); val = (unsigned long)(win_data->dma_addr + size); writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 3518bc4654c5..2e3bc57ea50e 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -55,6 +55,7 @@ struct hdmi_win_data { unsigned int fb_x; unsigned int fb_y; unsigned int fb_width; + unsigned int fb_pitch; unsigned int fb_height; unsigned int src_width; unsigned int src_height; @@ -438,7 +439,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) } else { luma_addr[0] = win_data->dma_addr; chroma_addr[0] = win_data->dma_addr - + (win_data->fb_width * win_data->fb_height); + + (win_data->fb_pitch * win_data->fb_height); } if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) { @@ -447,8 +448,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) luma_addr[1] = luma_addr[0] + 0x40; chroma_addr[1] = chroma_addr[0] + 0x40; } else { - luma_addr[1] = luma_addr[0] + win_data->fb_width; - chroma_addr[1] = chroma_addr[0] + win_data->fb_width; + luma_addr[1] = luma_addr[0] + win_data->fb_pitch; + chroma_addr[1] = chroma_addr[0] + win_data->fb_pitch; } } else { ctx->interlace = false; @@ -469,10 +470,10 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); /* setting size of input image */ - vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) | + vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_pitch) | VP_IMG_VSIZE(win_data->fb_height)); /* chroma height has to reduced by 2 to avoid chroma distorions */ - vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) | + vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_pitch) | VP_IMG_VSIZE(win_data->fb_height / 2)); vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width); @@ -559,7 +560,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) /* converting dma address base and source offset */ dma_addr = win_data->dma_addr + (win_data->fb_x * win_data->bpp >> 3) - + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3); + + (win_data->fb_y * win_data->fb_pitch); src_x_offset = 0; src_y_offset = 0; @@ -576,7 +577,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK); /* setup geometry */ - mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width); + mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), + win_data->fb_pitch / (win_data->bpp >> 3)); /* setup display size */ if (ctx->mxr_ver == MXR_VER_128_0_0_184 && @@ -961,6 +963,7 @@ static void mixer_win_mode_set(struct exynos_drm_crtc *crtc, win_data->fb_y = plane->fb_y; win_data->fb_width = plane->fb_width; win_data->fb_height = plane->fb_height; + win_data->fb_pitch = plane->pitch; win_data->src_width = plane->src_width; win_data->src_height = plane->src_height; From 863653fed0f449fb738295255cc834b271cfa088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 31 Mar 2015 17:36:57 +0200 Subject: [PATCH 433/567] drm/radeon: add extra check in radeon_ttm_tt_unpin_userptr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We somehow try to free the SG table twice. Bugs: https://bugs.freedesktop.org/show_bug.cgi?id=89734 Signed-off-by: Christian König Cc: Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_ttm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index d02aa1d0f588..b292aca0f342 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -598,6 +598,10 @@ static void radeon_ttm_tt_unpin_userptr(struct ttm_tt *ttm) enum dma_data_direction direction = write ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE; + /* double check that we don't free the table twice */ + if (!ttm->sg->sgl) + return; + /* free the sg table and pages again */ dma_unmap_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction); From 22e2e86560c5fca6f9b9d078f221fcdab9947a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 31 Mar 2015 17:36:58 +0200 Subject: [PATCH 434/567] drm/radeon: fix wait in radeon_mn_invalidate_range_start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to wait for all fences, not just the exclusive one. Signed-off-by: Christian König Cc: Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_mn.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_mn.c b/drivers/gpu/drm/radeon/radeon_mn.c index a69bd441dd2d..572b4dbec186 100644 --- a/drivers/gpu/drm/radeon/radeon_mn.c +++ b/drivers/gpu/drm/radeon/radeon_mn.c @@ -122,7 +122,6 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn, it = interval_tree_iter_first(&rmn->objects, start, end); while (it) { struct radeon_bo *bo; - struct fence *fence; int r; bo = container_of(it, struct radeon_bo, mn_it); @@ -134,12 +133,10 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn, continue; } - fence = reservation_object_get_excl(bo->tbo.resv); - if (fence) { - r = radeon_fence_wait((struct radeon_fence *)fence, false); - if (r) - DRM_ERROR("(%d) failed to wait for user bo\n", r); - } + r = reservation_object_wait_timeout_rcu(bo->tbo.resv, true, + false, MAX_SCHEDULE_TIMEOUT); + if (r) + DRM_ERROR("(%d) failed to wait for user bo\n", r); radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU); r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); From 444c6dd54d81edf81c606f571cb52eff4d47fa99 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Apr 2015 13:41:07 +0300 Subject: [PATCH 435/567] Bluetooth: Add clarifying comment to command status handling When dealing with HCI command status events, the reasoning for trying to mark a request as complete if no specific event is being waited for and status was success is not self-evident. This patch adds a clarifying comment above the if-statement. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7c0f992602f5..87e5bee36408 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3124,6 +3124,12 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) atomic_set(&hdev->cmd_cnt, 1); + /* Indicate request completion if the command failed. Also, if + * we're not waiting for a special event and we get a success + * command status we should try to flag the request as completed + * (since for this kind of commands there will not be a command + * complete event). + */ if (ev->status || (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event)) hci_req_cmd_complete(hdev, opcode, ev->status); From e6214487492566b15ff24e97c6747bb2e5d9e040 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Apr 2015 13:41:08 +0300 Subject: [PATCH 436/567] Bluetooth: Add second hci_request callback option for full skb This patch adds a second possible callback for HCI requests where the callback will receive the full skb of the last successfully completed HCI command. This API is useful for cases where we want to use a request to read some data and the existing hci_event.c handlers do not store it e.g. in the hci_dev struct. The reason the patch is a bit bigger than just adding the new API is because the hci_req_cmd_complete() functions required some refactoring to enable it: now hci_req_cmd_complete() is simply used to request the callback pointers if any, and the actual calling of them happens from a single place at the end of hci_event_packet(). The reason for this is that we need to pass the original skb (without any skb_pull, etc modifications done to it) and it's simplest to keep track of it within the hci_event_packet() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 3 ++ net/bluetooth/hci_core.c | 30 +++++------- net/bluetooth/hci_event.c | 76 +++++++++++++++++++++---------- net/bluetooth/hci_request.c | 14 +++++- net/bluetooth/hci_request.h | 5 +- 5 files changed, 84 insertions(+), 44 deletions(-) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index eeaff4b5cb62..7dba80546f16 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -277,11 +277,14 @@ struct l2cap_ctrl { struct hci_dev; typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status, u16 opcode); +typedef void (*hci_req_complete_skb_t)(struct hci_dev *hdev, u8 status, + u16 opcode, struct sk_buff *skb); struct req_ctrl { bool start; u8 event; hci_req_complete_t complete; + hci_req_complete_skb_t complete_skb; }; struct bt_skb_cb { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 246d7eca5d29..8af3af324eee 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -4288,9 +4288,10 @@ static void hci_resend_last(struct hci_dev *hdev) queue_work(hdev->workqueue, &hdev->cmd_work); } -void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status) +void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status, + hci_req_complete_t *req_complete, + hci_req_complete_skb_t *req_complete_skb) { - hci_req_complete_t req_complete = NULL; struct sk_buff *skb; unsigned long flags; @@ -4322,18 +4323,14 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status) * callback would be found in hdev->sent_cmd instead of the * command queue (hdev->cmd_q). */ - if (hdev->sent_cmd) { - req_complete = bt_cb(hdev->sent_cmd)->req.complete; + if (bt_cb(hdev->sent_cmd)->req.complete) { + *req_complete = bt_cb(hdev->sent_cmd)->req.complete; + return; + } - if (req_complete) { - /* We must set the complete callback to NULL to - * avoid calling the callback more than once if - * this function gets called again. - */ - bt_cb(hdev->sent_cmd)->req.complete = NULL; - - goto call_complete; - } + if (bt_cb(hdev->sent_cmd)->req.complete_skb) { + *req_complete_skb = bt_cb(hdev->sent_cmd)->req.complete_skb; + return; } /* Remove all pending commands belonging to this request */ @@ -4344,14 +4341,11 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status) break; } - req_complete = bt_cb(skb)->req.complete; + *req_complete = bt_cb(skb)->req.complete; + *req_complete_skb = bt_cb(skb)->req.complete_skb; kfree_skb(skb); } spin_unlock_irqrestore(&hdev->cmd_q.lock, flags); - -call_complete: - if (req_complete) - req_complete(hdev, status, status ? opcode : HCI_OP_NOP); } static void hci_rx_work(struct work_struct *work) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 87e5bee36408..7c69eb3629b7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2731,17 +2731,19 @@ unlock: hci_dev_unlock(hdev); } -static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, + u16 *opcode, u8 *status, + hci_req_complete_t *req_complete, + hci_req_complete_skb_t *req_complete_skb) { struct hci_ev_cmd_complete *ev = (void *) skb->data; - u8 status = skb->data[sizeof(*ev)]; - __u16 opcode; + + *opcode = __le16_to_cpu(ev->opcode); + *status = skb->data[sizeof(*ev)]; skb_pull(skb, sizeof(*ev)); - opcode = __le16_to_cpu(ev->opcode); - - switch (opcode) { + switch (*opcode) { case HCI_OP_INQUIRY_CANCEL: hci_cc_inquiry_cancel(hdev, skb); break; @@ -3019,32 +3021,36 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) break; default: - BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); + BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode); break; } - if (opcode != HCI_OP_NOP) + if (*opcode != HCI_OP_NOP) cancel_delayed_work(&hdev->cmd_timer); if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) atomic_set(&hdev->cmd_cnt, 1); - hci_req_cmd_complete(hdev, opcode, status); + hci_req_cmd_complete(hdev, *opcode, *status, req_complete, + req_complete_skb); if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q)) queue_work(hdev->workqueue, &hdev->cmd_work); } -static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb, + u16 *opcode, u8 *status, + hci_req_complete_t *req_complete, + hci_req_complete_skb_t *req_complete_skb) { struct hci_ev_cmd_status *ev = (void *) skb->data; - __u16 opcode; skb_pull(skb, sizeof(*ev)); - opcode = __le16_to_cpu(ev->opcode); + *opcode = __le16_to_cpu(ev->opcode); + *status = ev->status; - switch (opcode) { + switch (*opcode) { case HCI_OP_INQUIRY: hci_cs_inquiry(hdev, ev->status); break; @@ -3114,11 +3120,11 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) break; default: - BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); + BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode); break; } - if (opcode != HCI_OP_NOP) + if (*opcode != HCI_OP_NOP) cancel_delayed_work(&hdev->cmd_timer); if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) @@ -3132,7 +3138,8 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) */ if (ev->status || (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event)) - hci_req_cmd_complete(hdev, opcode, ev->status); + hci_req_cmd_complete(hdev, *opcode, ev->status, req_complete, + req_complete_skb); if (atomic_read(&hdev->cmd_cnt) && !skb_queue_empty(&hdev->cmd_q)) queue_work(hdev->workqueue, &hdev->cmd_work); @@ -5039,7 +5046,11 @@ static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb) void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_event_hdr *hdr = (void *) skb->data; - __u8 event = hdr->evt; + hci_req_complete_t req_complete = NULL; + hci_req_complete_skb_t req_complete_skb = NULL; + struct sk_buff *orig_skb = NULL; + u8 status = 0, event = hdr->evt; + u16 opcode = HCI_OP_NOP; hci_dev_lock(hdev); @@ -5053,15 +5064,24 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); - skb_pull(skb, HCI_EVENT_HDR_SIZE); - if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) { struct hci_command_hdr *cmd_hdr = (void *) hdev->sent_cmd->data; - u16 opcode = __le16_to_cpu(cmd_hdr->opcode); - - hci_req_cmd_complete(hdev, opcode, 0); + opcode = __le16_to_cpu(cmd_hdr->opcode); + hci_req_cmd_complete(hdev, opcode, status, &req_complete, + &req_complete_skb); } + /* If it looks like we might end up having to call + * req_complete_skb, store a pristine copy of the skb since the + * various handlers may modify the original one through + * skb_pull() calls, etc. + */ + if (req_complete_skb || event == HCI_EV_CMD_STATUS || + event == HCI_EV_CMD_COMPLETE) + orig_skb = skb_clone(skb, GFP_KERNEL); + + skb_pull(skb, HCI_EVENT_HDR_SIZE); + switch (event) { case HCI_EV_INQUIRY_COMPLETE: hci_inquiry_complete_evt(hdev, skb); @@ -5104,11 +5124,13 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) break; case HCI_EV_CMD_COMPLETE: - hci_cmd_complete_evt(hdev, skb); + hci_cmd_complete_evt(hdev, skb, &opcode, &status, + &req_complete, &req_complete_skb); break; case HCI_EV_CMD_STATUS: - hci_cmd_status_evt(hdev, skb); + hci_cmd_status_evt(hdev, skb, &opcode, &status, &req_complete, + &req_complete_skb); break; case HCI_EV_HARDWARE_ERROR: @@ -5240,6 +5262,12 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) break; } + if (req_complete) + req_complete(hdev, status, opcode); + else if (req_complete_skb) + req_complete_skb(hdev, status, opcode, orig_skb); + + kfree_skb(orig_skb); kfree_skb(skb); hdev->stat.evt_rx++; } diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 7e17907effb3..d6025d6e6d59 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -34,7 +34,8 @@ void hci_req_init(struct hci_request *req, struct hci_dev *hdev) req->err = 0; } -int hci_req_run(struct hci_request *req, hci_req_complete_t complete) +static int req_run(struct hci_request *req, hci_req_complete_t complete, + hci_req_complete_skb_t complete_skb) { struct hci_dev *hdev = req->hdev; struct sk_buff *skb; @@ -56,6 +57,7 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete) skb = skb_peek_tail(&req->cmd_q); bt_cb(skb)->req.complete = complete; + bt_cb(skb)->req.complete_skb = complete_skb; spin_lock_irqsave(&hdev->cmd_q.lock, flags); skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q); @@ -66,6 +68,16 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete) return 0; } +int hci_req_run(struct hci_request *req, hci_req_complete_t complete) +{ + return req_run(req, complete, NULL); +} + +int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete) +{ + return req_run(req, NULL, complete); +} + struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param) { diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index adf074d33544..bf6df92f42db 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -32,11 +32,14 @@ struct hci_request { void hci_req_init(struct hci_request *req, struct hci_dev *hdev); int hci_req_run(struct hci_request *req, hci_req_complete_t complete); +int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete); void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, const void *param); void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, const void *param, u8 event); -void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status); +void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status, + hci_req_complete_t *req_complete, + hci_req_complete_skb_t *req_complete_skb); struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param); From f60cb30579d3401cab1ed36b42df5c0568ae0ba7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Apr 2015 13:41:09 +0300 Subject: [PATCH 437/567] Bluetooth: Convert hci_req_sync family of function to new request API Now that there's an API in place that allows passing the resulting skb to the request callback we can conveniently convert the hci_req_sync and related functions to use it. Since we still need to get the skb from the async callback into the sleeping _sync() function the patch adds another req_skb variable to hci_dev where the sync request state is tracked. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 540c07feece7..257ac04c00e1 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -334,6 +334,7 @@ struct hci_dev { wait_queue_head_t req_wait_q; __u32 req_status; __u32 req_result; + struct sk_buff *req_skb; void *smp_data; void *smp_bredr_data; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 8af3af324eee..5cbb0957edc7 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -141,13 +141,16 @@ static const struct file_operations dut_mode_fops = { /* ---- HCI requests ---- */ -static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode) +static void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode, + struct sk_buff *skb) { BT_DBG("%s result 0x%2.2x", hdev->name, result); if (hdev->req_status == HCI_REQ_PEND) { hdev->req_result = result; hdev->req_status = HCI_REQ_DONE; + if (skb) + hdev->req_skb = skb_get(skb); wake_up_interruptible(&hdev->req_wait_q); } } @@ -164,18 +167,10 @@ static void hci_req_cancel(struct hci_dev *hdev, int err) } static struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode, - u8 event) + u8 event, struct sk_buff *skb) { struct hci_ev_cmd_complete *ev; struct hci_event_hdr *hdr; - struct sk_buff *skb; - - hci_dev_lock(hdev); - - skb = hdev->recv_evt; - hdev->recv_evt = NULL; - - hci_dev_unlock(hdev); if (!skb) return ERR_PTR(-ENODATA); @@ -223,6 +218,7 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, { DECLARE_WAITQUEUE(wait, current); struct hci_request req; + struct sk_buff *skb; int err = 0; BT_DBG("%s", hdev->name); @@ -236,7 +232,7 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, add_wait_queue(&hdev->req_wait_q, &wait); set_current_state(TASK_INTERRUPTIBLE); - err = hci_req_run(&req, hci_req_sync_complete); + err = hci_req_run_skb(&req, hci_req_sync_complete); if (err < 0) { remove_wait_queue(&hdev->req_wait_q, &wait); set_current_state(TASK_RUNNING); @@ -265,13 +261,17 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, } hdev->req_status = hdev->req_result = 0; + skb = hdev->req_skb; + hdev->req_skb = NULL; BT_DBG("%s end: err %d", hdev->name, err); - if (err < 0) + if (err < 0) { + kfree_skb(skb); return ERR_PTR(err); + } - return hci_get_cmd_complete(hdev, opcode, event); + return hci_get_cmd_complete(hdev, opcode, event, skb); } EXPORT_SYMBOL(__hci_cmd_sync_ev); @@ -303,7 +303,7 @@ static int __hci_req_sync(struct hci_dev *hdev, add_wait_queue(&hdev->req_wait_q, &wait); set_current_state(TASK_INTERRUPTIBLE); - err = hci_req_run(&req, hci_req_sync_complete); + err = hci_req_run_skb(&req, hci_req_sync_complete); if (err < 0) { hdev->req_status = 0; From f7d9e97592aeb7742084814c5f37e25571b2d51d Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Apr 2015 13:41:10 +0300 Subject: [PATCH 438/567] Bluetooth: Remove unneeded recv_event variable Now that the synchronous HCI requests use the new API and a new private variable the recv_evt member of hci_dev is no-longer needed. This patch removes it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 - net/bluetooth/hci_core.c | 3 --- net/bluetooth/hci_event.c | 12 ------------ 3 files changed, 16 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 257ac04c00e1..4cefee0b6330 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -326,7 +326,6 @@ struct hci_dev { struct sk_buff_head raw_q; struct sk_buff_head cmd_q; - struct sk_buff *recv_evt; struct sk_buff *sent_cmd; struct sk_buff *reassembly[NUM_REASSEMBLY]; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5cbb0957edc7..6192f6e3242f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1690,9 +1690,6 @@ static int hci_dev_do_close(struct hci_dev *hdev) hdev->sent_cmd = NULL; } - kfree_skb(hdev->recv_evt); - hdev->recv_evt = NULL; - /* After this point our queues are empty * and no tasks are scheduled. */ hdev->close(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7c69eb3629b7..dc9547c11c45 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5052,18 +5052,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) u8 status = 0, event = hdr->evt; u16 opcode = HCI_OP_NOP; - hci_dev_lock(hdev); - - /* Received events are (currently) only needed when a request is - * ongoing so avoid unnecessary memory allocation. - */ - if (hci_req_pending(hdev)) { - kfree_skb(hdev->recv_evt); - hdev->recv_evt = skb_clone(skb, GFP_KERNEL); - } - - hci_dev_unlock(hdev); - if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) { struct hci_command_hdr *cmd_hdr = (void *) hdev->sent_cmd->data; opcode = __le16_to_cpu(cmd_hdr->opcode); From abe66a4d036933c7376b40b0d7bb5de0458331aa Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Apr 2015 13:41:11 +0300 Subject: [PATCH 439/567] Bluetooth: Remove unused hci_req_pending() function The hci_req_pending() function has no users anymore, so simply remove it. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 -- net/bluetooth/hci_core.c | 5 ----- 2 files changed, 7 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4cefee0b6330..12686e8e9343 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1284,8 +1284,6 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency, int hci_register_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb); -bool hci_req_pending(struct hci_dev *hdev); - struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param, u32 timeout); struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 6192f6e3242f..fda23720e7b8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3560,11 +3560,6 @@ static void hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) } } -bool hci_req_pending(struct hci_dev *hdev) -{ - return (hdev->req_status == HCI_REQ_PEND); -} - /* Send HCI command */ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, const void *param) From 757aa0b56da5d1089c55bf349fa15836dae22b6f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Apr 2015 13:41:12 +0300 Subject: [PATCH 440/567] Bluetooth: Move hci_get_cmd_complete() to hci_event.c To make the hci_req_run_skb() API consistent with hci_cmd_sync_ev() the callback should receive the cmd_complete parameters in the 'normal' case and the full HCI event if a special event was expected. This patch moves the hci_get_cmd_complete() function from hci_core.c to hci_event.c where it's used to strip the skb from the needed headers before passing it on to the callback. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 52 +++-------------------------------- net/bluetooth/hci_event.c | 57 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 51 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fda23720e7b8..46b114c0140b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -166,53 +166,6 @@ static void hci_req_cancel(struct hci_dev *hdev, int err) } } -static struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode, - u8 event, struct sk_buff *skb) -{ - struct hci_ev_cmd_complete *ev; - struct hci_event_hdr *hdr; - - if (!skb) - return ERR_PTR(-ENODATA); - - if (skb->len < sizeof(*hdr)) { - BT_ERR("Too short HCI event"); - goto failed; - } - - hdr = (void *) skb->data; - skb_pull(skb, HCI_EVENT_HDR_SIZE); - - if (event) { - if (hdr->evt != event) - goto failed; - return skb; - } - - if (hdr->evt != HCI_EV_CMD_COMPLETE) { - BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt); - goto failed; - } - - if (skb->len < sizeof(*ev)) { - BT_ERR("Too short cmd_complete event"); - goto failed; - } - - ev = (void *) skb->data; - skb_pull(skb, sizeof(*ev)); - - if (opcode == __le16_to_cpu(ev->opcode)) - return skb; - - BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode, - __le16_to_cpu(ev->opcode)); - -failed: - kfree_skb(skb); - return ERR_PTR(-ENODATA); -} - struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param, u8 event, u32 timeout) { @@ -271,7 +224,10 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, return ERR_PTR(err); } - return hci_get_cmd_complete(hdev, opcode, event, skb); + if (!skb) + return ERR_PTR(-ENODATA); + + return skb; } EXPORT_SYMBOL(__hci_cmd_sync_ev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index dc9547c11c45..c2483cb6ffbd 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5043,13 +5043,58 @@ static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb) amp_read_loc_assoc_final_data(hdev, hcon); } +static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode, + u8 event, struct sk_buff *skb) +{ + struct hci_ev_cmd_complete *ev; + struct hci_event_hdr *hdr; + + if (!skb) + return false; + + if (skb->len < sizeof(*hdr)) { + BT_ERR("Too short HCI event"); + return false; + } + + hdr = (void *) skb->data; + skb_pull(skb, HCI_EVENT_HDR_SIZE); + + if (event) { + if (hdr->evt != event) + return false; + return true; + } + + if (hdr->evt != HCI_EV_CMD_COMPLETE) { + BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt); + return false; + } + + if (skb->len < sizeof(*ev)) { + BT_ERR("Too short cmd_complete event"); + return false; + } + + ev = (void *) skb->data; + skb_pull(skb, sizeof(*ev)); + + if (opcode != __le16_to_cpu(ev->opcode)) { + BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode, + __le16_to_cpu(ev->opcode)); + return false; + } + + return true; +} + void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_event_hdr *hdr = (void *) skb->data; hci_req_complete_t req_complete = NULL; hci_req_complete_skb_t req_complete_skb = NULL; struct sk_buff *orig_skb = NULL; - u8 status = 0, event = hdr->evt; + u8 status = 0, event = hdr->evt, req_evt = 0; u16 opcode = HCI_OP_NOP; if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) { @@ -5057,6 +5102,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) opcode = __le16_to_cpu(cmd_hdr->opcode); hci_req_cmd_complete(hdev, opcode, status, &req_complete, &req_complete_skb); + req_evt = event; } /* If it looks like we might end up having to call @@ -5250,10 +5296,15 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) break; } - if (req_complete) + if (req_complete) { req_complete(hdev, status, opcode); - else if (req_complete_skb) + } else if (req_complete_skb) { + if (!hci_get_cmd_complete(hdev, opcode, req_evt, orig_skb)) { + kfree_skb(orig_skb); + orig_skb = NULL; + } req_complete_skb(hdev, status, opcode, orig_skb); + } kfree_skb(orig_skb); kfree_skb(skb); From 1b9441f8ec426223f6f54f2af10ee01c8b743e5b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 2 Apr 2015 13:41:13 +0300 Subject: [PATCH 441/567] Bluetooth: Convert local OOB data reading to use HCI request Now that there's a HCI request API available where the callback receives the resulting skb, we can convert the local OOB data reading to use this new API. This patch does the necessary update in mgmt.c (which also requires moving the callback higher up since it's now a static function) and removes the custom calls from hci_event.c that are no-longer necessary. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 3 - net/bluetooth/hci_event.c | 11 ---- net/bluetooth/mgmt.c | 109 +++++++++++++++++++------------ 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 12686e8e9343..93fd3e756b8a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1391,9 +1391,6 @@ void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status); void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, u8 status); void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); -void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, - u8 *rand192, u8 *hash256, u8 *rand256, - u8 status); void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c2483cb6ffbd..01031038eb0e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1045,11 +1045,6 @@ static void hci_cc_read_local_oob_data(struct hci_dev *hdev, struct hci_rp_read_local_oob_data *rp = (void *) skb->data; BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - - hci_dev_lock(hdev); - mgmt_read_local_oob_data_complete(hdev, rp->hash, rp->rand, NULL, NULL, - rp->status); - hci_dev_unlock(hdev); } static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev, @@ -1058,12 +1053,6 @@ static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev, struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data; BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); - - hci_dev_lock(hdev); - mgmt_read_local_oob_data_complete(hdev, rp->hash192, rp->rand192, - rp->hash256, rp->rand256, - rp->status); - hci_dev_unlock(hdev); } static void hci_cc_le_set_random_addr(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 3048092b1264..bb0c53ac4c66 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3783,10 +3783,70 @@ failed: return err; } +static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, + u16 opcode, struct sk_buff *skb) +{ + struct mgmt_rp_read_local_oob_data mgmt_rp; + size_t rp_size = sizeof(mgmt_rp); + struct mgmt_pending_cmd *cmd; + + BT_DBG("%s status %u", hdev->name, status); + + cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev); + if (!cmd) + return; + + if (status || !skb) { + mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, + status ? mgmt_status(status) : MGMT_STATUS_FAILED); + goto remove; + } + + memset(&mgmt_rp, 0, sizeof(mgmt_rp)); + + if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) { + struct hci_rp_read_local_oob_data *rp = (void *) skb->data; + + if (skb->len < sizeof(*rp)) { + mgmt_cmd_status(cmd->sk, hdev->id, + MGMT_OP_READ_LOCAL_OOB_DATA, + MGMT_STATUS_FAILED); + goto remove; + } + + memcpy(mgmt_rp.hash192, rp->hash, sizeof(rp->hash)); + memcpy(mgmt_rp.rand192, rp->rand, sizeof(rp->rand)); + + rp_size -= sizeof(mgmt_rp.hash256) + sizeof(mgmt_rp.rand256); + } else { + struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data; + + if (skb->len < sizeof(*rp)) { + mgmt_cmd_status(cmd->sk, hdev->id, + MGMT_OP_READ_LOCAL_OOB_DATA, + MGMT_STATUS_FAILED); + goto remove; + } + + memcpy(mgmt_rp.hash192, rp->hash192, sizeof(rp->hash192)); + memcpy(mgmt_rp.rand192, rp->rand192, sizeof(rp->rand192)); + + memcpy(mgmt_rp.hash256, rp->hash256, sizeof(rp->hash256)); + memcpy(mgmt_rp.rand256, rp->rand256, sizeof(rp->rand256)); + } + + mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, + MGMT_STATUS_SUCCESS, &mgmt_rp, rp_size); + +remove: + mgmt_pending_remove(cmd); +} + static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { struct mgmt_pending_cmd *cmd; + struct hci_request req; int err; BT_DBG("%s", hdev->name); @@ -3817,12 +3877,14 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev, goto unlock; } - if (bredr_sc_enabled(hdev)) - err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA, - 0, NULL); - else - err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + hci_req_init(&req, hdev); + if (bredr_sc_enabled(hdev)) + hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL); + else + hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + + err = hci_req_run_skb(&req, read_local_oob_data_complete); if (err < 0) mgmt_pending_remove(cmd); @@ -7920,43 +7982,6 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) cmd ? cmd->sk : NULL); } -void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192, - u8 *rand192, u8 *hash256, u8 *rand256, - u8 status) -{ - struct mgmt_pending_cmd *cmd; - - BT_DBG("%s status %u", hdev->name, status); - - cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev); - if (!cmd) - return; - - if (status) { - mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA, - mgmt_status(status)); - } else { - struct mgmt_rp_read_local_oob_data rp; - size_t rp_size = sizeof(rp); - - memcpy(rp.hash192, hash192, sizeof(rp.hash192)); - memcpy(rp.rand192, rand192, sizeof(rp.rand192)); - - if (bredr_sc_enabled(hdev) && hash256 && rand256) { - memcpy(rp.hash256, hash256, sizeof(rp.hash256)); - memcpy(rp.rand256, rand256, sizeof(rp.rand256)); - } else { - rp_size -= sizeof(rp.hash256) + sizeof(rp.rand256); - } - - mgmt_cmd_complete(cmd->sk, hdev->id, - MGMT_OP_READ_LOCAL_OOB_DATA, 0, - &rp, rp_size); - } - - mgmt_pending_remove(cmd); -} - static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16]) { int i; From 687805e4a60fe83a11556c041840161f8016a367 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 27 Mar 2015 10:38:25 -0400 Subject: [PATCH 442/567] perf/x86/intel: Filter branches for PEBS event For supporting Intel LBR branches filtering, Intel LBR sharing logic mechanism is introduced from commit b36817e88630 ("perf/x86: Add Intel LBR sharing logic"). It modifies __intel_shared_reg_get_constraints() to config lbr_sel, which is finally used to set LBR_SELECT. However, the intel_shared_regs_constraints() function is called after intel_pebs_constraints(). The PEBS event will return immediately after intel_pebs_constraints(). So it's impossible to filter branches for PEBS events. This patch moves intel_shared_regs_constraints() ahead of intel_pebs_constraints(). We can safely do that because the intel_shared_regs_constraints() function only returns empty constraint if its rejecting the event, otherwise it returns NULL such that we continue calling intel_pebs_constraints() and x86_get_event_constraint(). Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: eranian@google.com Link: http://lkml.kernel.org/r/1427467105-9260-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 498b6d967138..40898abdff20 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -1649,11 +1649,11 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event if (c) return c; - c = intel_pebs_constraints(event); + c = intel_shared_regs_constraints(cpuc, event); if (c) return c; - c = intel_shared_regs_constraints(cpuc, event); + c = intel_pebs_constraints(event); if (c) return c; From c420f19b9cdc59662dbb56677417487efc1729ec Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Mon, 9 Mar 2015 11:20:22 -0700 Subject: [PATCH 443/567] perf/x86/intel: Fix Haswell CYCLE_ACTIVITY.* counter constraints Some of the CYCLE_ACTIVITY.* events can only be scheduled on counter 2. Due to a typo Haswell matched those with INTEL_EVENT_CONSTRAINT, which lead to the events never matching as the comparison does not expect anything in the umask too. Fix the typo. Signed-off-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Link: http://lkml.kernel.org/r/1425925222-32361-1-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 40898abdff20..258990688a5e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -212,11 +212,11 @@ static struct event_constraint intel_hsw_event_constraints[] = { INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */ /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */ - INTEL_EVENT_CONSTRAINT(0x08a3, 0x4), + INTEL_UEVENT_CONSTRAINT(0x08a3, 0x4), /* CYCLE_ACTIVITY.STALLS_L1D_PENDING */ - INTEL_EVENT_CONSTRAINT(0x0ca3, 0x4), + INTEL_UEVENT_CONSTRAINT(0x0ca3, 0x4), /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */ - INTEL_EVENT_CONSTRAINT(0x04a3, 0xf), + INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), EVENT_CONSTRAINT_END }; From 8494057ab5e40df590ef6ef7d66324d3ae33356b Mon Sep 17 00:00:00 2001 From: Shachar Raindel Date: Wed, 18 Mar 2015 17:39:08 +0000 Subject: [PATCH 444/567] IB/uverbs: Prevent integer overflow in ib_umem_get address arithmetic Properly verify that the resulting page aligned end address is larger than both the start address and the length of the memory area requested. Both the start and length arguments for ib_umem_get are controlled by the user. A misbehaving user can provide values which will cause an integer overflow when calculating the page aligned end address. This overflow can cause also miscalculation of the number of pages mapped, and additional logic issues. Addresses: CVE-2014-8159 Cc: Signed-off-by: Shachar Raindel Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/core/umem.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index aec7a6aa2951..8c014b5dab4c 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -99,6 +99,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, if (dmasync) dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); + /* + * If the combination of the addr and size requested for this memory + * region causes an integer overflow, return error. + */ + if ((PAGE_ALIGN(addr + size) <= size) || + (PAGE_ALIGN(addr + size) <= addr)) + return ERR_PTR(-EINVAL); + if (!can_do_mlock()) return ERR_PTR(-EPERM); From a54acb3a6f853e8394c4cb7b6a4d93c88f13eefd Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:00 +0200 Subject: [PATCH 445/567] dev: introduce dev_get_iflink() The goal of this patch is to prepare the removal of the iflink field. It introduces a new ndo function, which will be implemented by virtual interfaces. There is no functional change into this patch. All readers of iflink field now call dev_get_iflink(). Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_core.c | 2 +- include/linux/netdevice.h | 4 ++++ net/batman-adv/hard-interface.c | 5 +++-- net/bridge/br_netlink.c | 4 ++-- net/core/dev.c | 21 +++++++++++++++++++-- net/core/link_watch.c | 4 ++-- net/core/net-sysfs.c | 10 +++++++++- net/core/rtnetlink.c | 8 ++++---- net/ipv4/ipmr.c | 2 +- net/ipv6/addrconf.c | 4 ++-- net/ipv6/ip6mr.c | 2 +- 11 files changed, 48 insertions(+), 18 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 2a175006028b..131bde98188d 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -330,7 +330,7 @@ static int ipvlan_process_v4_outbound(struct sk_buff *skb) struct rtable *rt; int err, ret = NET_XMIT_DROP; struct flowi4 fl4 = { - .flowi4_oif = dev->iflink, + .flowi4_oif = dev_get_iflink(dev), .flowi4_tos = RT_TOS(ip4h->tos), .flowi4_flags = FLOWI_FLAG_ANYSRC, .daddr = ip4h->daddr, diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 967bb4c8caf1..788eb7a622ad 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1030,6 +1030,8 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * int queue_index, u32 maxrate); * Called when a user wants to set a max-rate limitation of specific * TX queue. + * int (*ndo_get_iflink)(const struct net_device *dev); + * Called to get the iflink value of this device. */ struct net_device_ops { int (*ndo_init)(struct net_device *dev); @@ -1191,6 +1193,7 @@ struct net_device_ops { int (*ndo_set_tx_maxrate)(struct net_device *dev, int queue_index, u32 maxrate); + int (*ndo_get_iflink)(const struct net_device *dev); }; /** @@ -2149,6 +2152,7 @@ void __dev_remove_pack(struct packet_type *pt); void dev_add_offload(struct packet_offload *po); void dev_remove_offload(struct packet_offload *po); +int dev_get_iflink(const struct net_device *dev); struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags, unsigned short mask); struct net_device *dev_get_by_name(struct net *net, const char *name); diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index fbda6b54baff..baf1f9843f2c 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -83,11 +83,12 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) return true; /* no more parents..stop recursion */ - if (net_dev->iflink == 0 || net_dev->iflink == net_dev->ifindex) + if (dev_get_iflink(net_dev) == 0 || + dev_get_iflink(net_dev) == net_dev->ifindex) return false; /* recurse over the parent device */ - parent_dev = __dev_get_by_index(&init_net, net_dev->iflink); + parent_dev = __dev_get_by_index(&init_net, dev_get_iflink(net_dev)); /* if we got a NULL parent_dev there is something broken.. */ if (WARN(!parent_dev, "Cannot find parent device")) return false; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index e1115a224a95..0e4ddb81610d 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -305,8 +305,8 @@ static int br_fill_ifinfo(struct sk_buff *skb, nla_put_u8(skb, IFLA_OPERSTATE, operstate) || (dev->addr_len && nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || - (dev->ifindex != dev->iflink && - nla_put_u32(skb, IFLA_LINK, dev->iflink))) + (dev->ifindex != dev_get_iflink(dev) && + nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev)))) goto nla_put_failure; if (event == RTM_NEWLINK && port) { diff --git a/net/core/dev.c b/net/core/dev.c index 65492b0354c0..77172d085760 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -659,6 +659,23 @@ __setup("netdev=", netdev_boot_setup); *******************************************************************************/ +/** + * dev_get_iflink - get 'iflink' value of a interface + * @dev: targeted interface + * + * Indicates the ifindex the interface is linked to. + * Physical interfaces have the same 'ifindex' and 'iflink' values. + */ + +int dev_get_iflink(const struct net_device *dev) +{ + if (dev->netdev_ops && dev->netdev_ops->ndo_get_iflink) + return dev->netdev_ops->ndo_get_iflink(dev); + + return dev->iflink; +} +EXPORT_SYMBOL(dev_get_iflink); + /** * __dev_get_by_name - find a device by its name * @net: the applicable net namespace @@ -6345,7 +6362,7 @@ int register_netdevice(struct net_device *dev) else if (__dev_get_by_index(net, dev->ifindex)) goto err_uninit; - if (dev->iflink == -1) + if (dev_get_iflink(dev) == -1) dev->iflink = dev->ifindex; /* Transfer changeable features to wanted_features and enable @@ -7061,7 +7078,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* If there is an ifindex conflict assign a new one */ if (__dev_get_by_index(net, dev->ifindex)) { - int iflink = (dev->iflink == dev->ifindex); + int iflink = (dev_get_iflink(dev) == dev->ifindex); dev->ifindex = dev_new_index(net); if (iflink) dev->iflink = dev->ifindex; diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 49a9e3e06c08..982861607f88 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -40,7 +40,7 @@ static DEFINE_SPINLOCK(lweventlist_lock); static unsigned char default_operstate(const struct net_device *dev) { if (!netif_carrier_ok(dev)) - return (dev->ifindex != dev->iflink ? + return (dev->ifindex != dev_get_iflink(dev) ? IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN); if (netif_dormant(dev)) @@ -89,7 +89,7 @@ static bool linkwatch_urgent_event(struct net_device *dev) if (!netif_running(dev)) return false; - if (dev->ifindex != dev->iflink) + if (dev->ifindex != dev_get_iflink(dev)) return true; if (dev->priv_flags & IFF_TEAM_PORT) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index cc5cf689809c..4238d6da5c60 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -109,11 +109,19 @@ NETDEVICE_SHOW_RO(dev_id, fmt_hex); NETDEVICE_SHOW_RO(dev_port, fmt_dec); NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec); NETDEVICE_SHOW_RO(addr_len, fmt_dec); -NETDEVICE_SHOW_RO(iflink, fmt_dec); NETDEVICE_SHOW_RO(ifindex, fmt_dec); NETDEVICE_SHOW_RO(type, fmt_dec); NETDEVICE_SHOW_RO(link_mode, fmt_dec); +static ssize_t iflink_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct net_device *ndev = to_net_dev(dev); + + return sprintf(buf, fmt_dec, dev_get_iflink(ndev)); +} +static DEVICE_ATTR_RO(iflink); + static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) { return sprintf(buf, fmt_dec, dev->name_assign_type); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b96ac2109c82..ee0186cdd5cf 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1055,8 +1055,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, #ifdef CONFIG_RPS nla_put_u32(skb, IFLA_NUM_RX_QUEUES, dev->num_rx_queues) || #endif - (dev->ifindex != dev->iflink && - nla_put_u32(skb, IFLA_LINK, dev->iflink)) || + (dev->ifindex != dev_get_iflink(dev) && + nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev))) || (upper_dev && nla_put_u32(skb, IFLA_MASTER, upper_dev->ifindex)) || nla_put_u8(skb, IFLA_CARRIER, netif_carrier_ok(dev)) || @@ -2863,8 +2863,8 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, nla_put_u32(skb, IFLA_MASTER, br_dev->ifindex)) || (dev->addr_len && nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || - (dev->ifindex != dev->iflink && - nla_put_u32(skb, IFLA_LINK, dev->iflink))) + (dev->ifindex != dev_get_iflink(dev) && + nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev)))) goto nla_put_failure; br_afspec = nla_nest_start(skb, IFLA_AF_SPEC); diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index b4a545d24adb..eec68b0c3bc8 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -801,7 +801,7 @@ static int vif_add(struct net *net, struct mr_table *mrt, v->pkt_out = 0; v->link = dev->ifindex; if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER)) - v->link = dev->iflink; + v->link = dev_get_iflink(dev); /* And finish update writing critical data */ write_lock_bh(&mrt_lock); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 5c9e94cb1b2c..37b70e82bff8 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4858,8 +4858,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, (dev->addr_len && nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || nla_put_u32(skb, IFLA_MTU, dev->mtu) || - (dev->ifindex != dev->iflink && - nla_put_u32(skb, IFLA_LINK, dev->iflink))) + (dev->ifindex != dev_get_iflink(dev) && + nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev)))) goto nla_put_failure; protoinfo = nla_nest_start(skb, IFLA_PROTINFO); if (!protoinfo) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index caf6b99374e6..18a5ab286420 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -992,7 +992,7 @@ static int mif6_add(struct net *net, struct mr6_table *mrt, v->pkt_out = 0; v->link = dev->ifindex; if (v->flags & MIFF_REGISTER) - v->link = dev->iflink; + v->link = dev_get_iflink(dev); /* And finish update writing critical data */ write_lock_bh(&mrt_lock); From ecf2c06a88d2ed534a87b84b8c1a467ab23352dd Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:01 +0200 Subject: [PATCH 446/567] ip6tnl,gre6,vti6: implement ndo_get_iflink Don't use dev->iflink anymore. CC: Steffen Klassert Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- include/net/ip6_tunnel.h | 1 + net/ipv6/ip6_gre.c | 8 ++------ net/ipv6/ip6_tunnel.c | 10 ++++++++-- net/ipv6/ip6_vti.c | 3 +-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h index 76c091b53dae..1668be5937e6 100644 --- a/include/net/ip6_tunnel.h +++ b/include/net/ip6_tunnel.h @@ -71,6 +71,7 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw); __u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr, const struct in6_addr *raddr); struct net *ip6_tnl_get_link_net(const struct net_device *dev); +int ip6_tnl_get_iflink(const struct net_device *dev); static inline void ip6tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 0f4e73da14e4..f724329d7436 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -1216,6 +1216,7 @@ static const struct net_device_ops ip6gre_netdev_ops = { .ndo_do_ioctl = ip6gre_tunnel_ioctl, .ndo_change_mtu = ip6gre_tunnel_change_mtu, .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_get_iflink = ip6_tnl_get_iflink, }; static void ip6gre_dev_free(struct net_device *dev) @@ -1238,7 +1239,6 @@ static void ip6gre_tunnel_setup(struct net_device *dev) if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) dev->mtu -= 8; dev->flags |= IFF_NOARP; - dev->iflink = 0; dev->addr_len = sizeof(struct in6_addr); netif_keep_dst(dev); } @@ -1270,8 +1270,6 @@ static int ip6gre_tunnel_init(struct net_device *dev) u64_stats_init(&ip6gre_tunnel_stats->syncp); } - dev->iflink = tunnel->parms.link; - return 0; } @@ -1480,8 +1478,6 @@ static int ip6gre_tap_init(struct net_device *dev) if (!dev->tstats) return -ENOMEM; - dev->iflink = tunnel->parms.link; - return 0; } @@ -1493,6 +1489,7 @@ static const struct net_device_ops ip6gre_tap_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = ip6gre_tunnel_change_mtu, .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_get_iflink = ip6_tnl_get_iflink, }; static void ip6gre_tap_setup(struct net_device *dev) @@ -1503,7 +1500,6 @@ static void ip6gre_tap_setup(struct net_device *dev) dev->netdev_ops = &ip6gre_tap_netdev_ops; dev->destructor = ip6gre_dev_free; - dev->iflink = 0; dev->features |= NETIF_F_NETNS_LOCAL; } diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 9bd85f0dff69..b6a211a150b2 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1264,8 +1264,6 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) else dev->flags &= ~IFF_POINTOPOINT; - dev->iflink = p->link; - if (p->flags & IP6_TNL_F_CAP_XMIT) { int strict = (ipv6_addr_type(&p->raddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)); @@ -1517,6 +1515,13 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) return 0; } +int ip6_tnl_get_iflink(const struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + + return t->parms.link; +} +EXPORT_SYMBOL(ip6_tnl_get_iflink); static const struct net_device_ops ip6_tnl_netdev_ops = { .ndo_init = ip6_tnl_dev_init, @@ -1525,6 +1530,7 @@ static const struct net_device_ops ip6_tnl_netdev_ops = { .ndo_do_ioctl = ip6_tnl_ioctl, .ndo_change_mtu = ip6_tnl_change_mtu, .ndo_get_stats = ip6_get_stats, + .ndo_get_iflink = ip6_tnl_get_iflink, }; diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 53d90ed68905..b53148444e15 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -601,8 +601,6 @@ static void vti6_link_config(struct ip6_tnl *t) dev->flags |= IFF_POINTOPOINT; else dev->flags &= ~IFF_POINTOPOINT; - - dev->iflink = p->link; } /** @@ -808,6 +806,7 @@ static const struct net_device_ops vti6_netdev_ops = { .ndo_do_ioctl = vti6_ioctl, .ndo_change_mtu = vti6_change_mtu, .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_get_iflink = ip6_tnl_get_iflink, }; /** From 1e99584b911cb6f3d2a681e2532d8dc3f9339c9c Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:02 +0200 Subject: [PATCH 447/567] ipip,gre,vti,sit: implement ndo_get_iflink Don't use dev->iflink anymore. CC: Steffen Klassert Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- include/net/ip_tunnels.h | 1 + net/ipv4/ip_gre.c | 2 ++ net/ipv4/ip_tunnel.c | 9 ++++++++- net/ipv4/ip_vti.c | 2 +- net/ipv4/ipip.c | 2 +- net/ipv6/sit.c | 3 +-- 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 2c47061a6954..d8214cb88bbc 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -142,6 +142,7 @@ int ip_tunnel_init(struct net_device *dev); void ip_tunnel_uninit(struct net_device *dev); void ip_tunnel_dellink(struct net_device *dev, struct list_head *head); struct net *ip_tunnel_get_link_net(const struct net_device *dev); +int ip_tunnel_get_iflink(const struct net_device *dev); int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id, struct rtnl_link_ops *ops, char *devname); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 0eb2a040a830..1060ca0bc23a 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -456,6 +456,7 @@ static const struct net_device_ops ipgre_netdev_ops = { .ndo_do_ioctl = ipgre_tunnel_ioctl, .ndo_change_mtu = ip_tunnel_change_mtu, .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_get_iflink = ip_tunnel_get_iflink, }; #define GRE_FEATURES (NETIF_F_SG | \ @@ -686,6 +687,7 @@ static const struct net_device_ops gre_tap_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = ip_tunnel_change_mtu, .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_get_iflink = ip_tunnel_get_iflink, }; static void ipgre_tap_setup(struct net_device *dev) diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 2cd08280c77b..4bb7252110a6 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -389,7 +389,6 @@ static int ip_tunnel_bind_dev(struct net_device *dev) hlen = tdev->hard_header_len + tdev->needed_headroom; mtu = tdev->mtu; } - dev->iflink = tunnel->parms.link; dev->needed_headroom = t_hlen + hlen; mtu -= (dev->hard_header_len + t_hlen); @@ -980,6 +979,14 @@ struct net *ip_tunnel_get_link_net(const struct net_device *dev) } EXPORT_SYMBOL(ip_tunnel_get_link_net); +int ip_tunnel_get_iflink(const struct net_device *dev) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + + return tunnel->parms.link; +} +EXPORT_SYMBOL(ip_tunnel_get_iflink); + int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id, struct rtnl_link_ops *ops, char *devname) { diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 5a6e27054f0a..c4f93c0d1104 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -341,6 +341,7 @@ static const struct net_device_ops vti_netdev_ops = { .ndo_do_ioctl = vti_tunnel_ioctl, .ndo_change_mtu = ip_tunnel_change_mtu, .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_get_iflink = ip_tunnel_get_iflink, }; static void vti_tunnel_setup(struct net_device *dev) @@ -361,7 +362,6 @@ static int vti_tunnel_init(struct net_device *dev) dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); dev->mtu = ETH_DATA_LEN; dev->flags = IFF_NOARP; - dev->iflink = 0; dev->addr_len = 4; dev->features |= NETIF_F_LLTX; netif_keep_dst(dev); diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index bfbcc85c02ee..5c81f6e40842 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -272,6 +272,7 @@ static const struct net_device_ops ipip_netdev_ops = { .ndo_do_ioctl = ipip_tunnel_ioctl, .ndo_change_mtu = ip_tunnel_change_mtu, .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_get_iflink = ip_tunnel_get_iflink, }; #define IPIP_FEATURES (NETIF_F_SG | \ @@ -286,7 +287,6 @@ static void ipip_tunnel_setup(struct net_device *dev) dev->type = ARPHRD_TUNNEL; dev->flags = IFF_NOARP; - dev->iflink = 0; dev->addr_len = 4; dev->features |= NETIF_F_LLTX; netif_keep_dst(dev); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index e6b9f51b15e8..6cf2026a9cea 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1076,7 +1076,6 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) if (dev->mtu < IPV6_MIN_MTU) dev->mtu = IPV6_MIN_MTU; } - dev->iflink = tunnel->parms.link; } static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) @@ -1336,6 +1335,7 @@ static const struct net_device_ops ipip6_netdev_ops = { .ndo_do_ioctl = ipip6_tunnel_ioctl, .ndo_change_mtu = ipip6_tunnel_change_mtu, .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_get_iflink = ip_tunnel_get_iflink, }; static void ipip6_dev_free(struct net_device *dev) @@ -1366,7 +1366,6 @@ static void ipip6_tunnel_setup(struct net_device *dev) dev->mtu = ETH_DATA_LEN - t_hlen; dev->flags = IFF_NOARP; netif_keep_dst(dev); - dev->iflink = 0; dev->addr_len = 4; dev->features |= NETIF_F_LLTX; dev->features |= SIT_FEATURES; From ee9b9596a8dd90fc59a910f840a419321be5917b Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:03 +0200 Subject: [PATCH 448/567] ipmr,ip6mr: implement ndo_get_iflink Don't use dev->iflink anymore. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 7 ++++++- net/ipv6/ip6mr.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index eec68b0c3bc8..d2e3b3ef039e 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -473,8 +473,14 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +static int reg_vif_get_iflink(const struct net_device *dev) +{ + return 0; +} + static const struct net_device_ops reg_vif_netdev_ops = { .ndo_start_xmit = reg_vif_xmit, + .ndo_get_iflink = reg_vif_get_iflink, }; static void reg_vif_setup(struct net_device *dev) @@ -509,7 +515,6 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) free_netdev(dev); return NULL; } - dev->iflink = 0; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 18a5ab286420..003431f5b4b6 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -718,8 +718,14 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } +static int reg_vif_get_iflink(const struct net_device *dev) +{ + return 0; +} + static const struct net_device_ops reg_vif_netdev_ops = { .ndo_start_xmit = reg_vif_xmit, + .ndo_get_iflink = reg_vif_get_iflink, }; static void reg_vif_setup(struct net_device *dev) @@ -752,7 +758,6 @@ static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt) free_netdev(dev); return NULL; } - dev->iflink = 0; if (dev_open(dev)) goto failure; From 2dbf6b5058ace6b12e0674b07d59d47177741ae7 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:04 +0200 Subject: [PATCH 449/567] vlan: implement ndo_get_iflink Don't use dev->iflink anymore. CC: Patrick McHardy Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/8021q/vlan_dev.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 8b5ab9033b41..01d7ba840df8 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -538,7 +538,6 @@ static int vlan_dev_init(struct net_device *dev) /* IFF_BROADCAST|IFF_MULTICAST; ??? */ dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_MASTER | IFF_SLAVE); - dev->iflink = real_dev->ifindex; dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))) | (1<<__LINK_STATE_PRESENT); @@ -733,6 +732,13 @@ static void vlan_dev_netpoll_cleanup(struct net_device *dev) } #endif /* CONFIG_NET_POLL_CONTROLLER */ +static int vlan_dev_get_iflink(const struct net_device *dev) +{ + struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; + + return real_dev->ifindex; +} + static const struct ethtool_ops vlan_ethtool_ops = { .get_settings = vlan_ethtool_get_settings, .get_drvinfo = vlan_ethtool_get_drvinfo, @@ -769,6 +775,7 @@ static const struct net_device_ops vlan_netdev_ops = { #endif .ndo_fix_features = vlan_dev_fix_features, .ndo_get_lock_subclass = vlan_dev_get_lock_subclass, + .ndo_get_iflink = vlan_dev_get_iflink, }; static void vlan_dev_free(struct net_device *dev) From ef5fa6bc46ee516f732d1171323cf3b8524bb8c2 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:05 +0200 Subject: [PATCH 450/567] macvlan: implement ndo_get_iflink Don't use dev->iflink anymore. CC: Patrick McHardy Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index b5e3320ca506..b227a13f6473 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -786,7 +786,6 @@ static int macvlan_init(struct net_device *dev) dev->hw_features |= NETIF_F_LRO; dev->vlan_features = lowerdev->vlan_features & MACVLAN_FEATURES; dev->gso_max_size = lowerdev->gso_max_size; - dev->iflink = lowerdev->ifindex; dev->hard_header_len = lowerdev->hard_header_len; macvlan_set_lockdep_class(dev); @@ -995,6 +994,13 @@ static void macvlan_dev_netpoll_cleanup(struct net_device *dev) } #endif /* CONFIG_NET_POLL_CONTROLLER */ +static int macvlan_dev_get_iflink(const struct net_device *dev) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + + return vlan->lowerdev->ifindex; +} + static const struct ethtool_ops macvlan_ethtool_ops = { .get_link = ethtool_op_get_link, .get_settings = macvlan_ethtool_get_settings, @@ -1025,6 +1031,7 @@ static const struct net_device_ops macvlan_netdev_ops = { .ndo_netpoll_setup = macvlan_dev_netpoll_setup, .ndo_netpoll_cleanup = macvlan_dev_netpoll_cleanup, #endif + .ndo_get_iflink = macvlan_dev_get_iflink, }; void macvlan_common_setup(struct net_device *dev) From 7c4116588b2ad5f45c693e0f12b612b621604c92 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:06 +0200 Subject: [PATCH 451/567] ipvlan: implement ndo_get_iflink Don't use dev->iflink anymore. CC: Mahesh Bandewar Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 2950c3780230..1701ede2df89 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -114,7 +114,6 @@ static int ipvlan_init(struct net_device *dev) dev->features = phy_dev->features & IPVLAN_FEATURES; dev->features |= NETIF_F_LLTX; dev->gso_max_size = phy_dev->gso_max_size; - dev->iflink = phy_dev->ifindex; dev->hard_header_len = phy_dev->hard_header_len; ipvlan_set_lockdep_class(dev); @@ -305,6 +304,13 @@ static int ipvlan_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, return 0; } +static int ipvlan_get_iflink(const struct net_device *dev) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + + return ipvlan->phy_dev->ifindex; +} + static const struct net_device_ops ipvlan_netdev_ops = { .ndo_init = ipvlan_init, .ndo_uninit = ipvlan_uninit, @@ -317,6 +323,7 @@ static const struct net_device_ops ipvlan_netdev_ops = { .ndo_get_stats64 = ipvlan_get_stats64, .ndo_vlan_rx_add_vid = ipvlan_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = ipvlan_vlan_rx_kill_vid, + .ndo_get_iflink = ipvlan_get_iflink, }; static int ipvlan_hard_header(struct sk_buff *skb, struct net_device *dev, From 5aa7add8f14bc29105bca841c053f574c8d232dd Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:07 +0200 Subject: [PATCH 452/567] infiniband/ipoib: implement ndo_get_iflink Don't use dev->iflink anymore. CC: Roland Dreier Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 ++++++++ drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 58b5aa3b6f2d..657b89b1d291 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -842,6 +842,13 @@ static void ipoib_set_mcast_list(struct net_device *dev) queue_work(ipoib_workqueue, &priv->restart_task); } +static int ipoib_get_iflink(const struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + + return priv->parent->ifindex; +} + static u32 ipoib_addr_hash(struct ipoib_neigh_hash *htbl, u8 *daddr) { /* @@ -1341,6 +1348,7 @@ static const struct net_device_ops ipoib_netdev_ops = { .ndo_start_xmit = ipoib_start_xmit, .ndo_tx_timeout = ipoib_timeout, .ndo_set_rx_mode = ipoib_set_mcast_list, + .ndo_get_iflink = ipoib_get_iflink, }; void ipoib_setup(struct net_device *dev) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 9fad7b5ac8b9..4dd1313056a4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -102,7 +102,6 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, } priv->child_type = type; - priv->dev->iflink = ppriv->dev->ifindex; list_add_tail(&priv->list, &ppriv->child_intfs); return 0; From abd2be00d474956c542a1c2ec848af7196b7fd51 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:08 +0200 Subject: [PATCH 453/567] dsa: implement ndo_get_iflink Don't use dev->iflink anymore. CC: Florian Fainelli Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/dsa/slave.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 3597724ec3d8..827cda560a55 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -55,13 +55,11 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds) /* slave device handling ****************************************************/ -static int dsa_slave_init(struct net_device *dev) +static int dsa_slave_get_iflink(const struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); - dev->iflink = p->parent->dst->master_netdev->ifindex; - - return 0; + return p->parent->dst->master_netdev->ifindex; } static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p) @@ -664,7 +662,6 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { }; static const struct net_device_ops dsa_slave_netdev_ops = { - .ndo_init = dsa_slave_init, .ndo_open = dsa_slave_open, .ndo_stop = dsa_slave_close, .ndo_start_xmit = dsa_slave_xmit, @@ -675,6 +672,7 @@ static const struct net_device_ops dsa_slave_netdev_ops = { .ndo_fdb_del = dsa_slave_fdb_del, .ndo_fdb_dump = dsa_slave_fdb_dump, .ndo_do_ioctl = dsa_slave_ioctl, + .ndo_get_iflink = dsa_slave_get_iflink, }; static const struct swdev_ops dsa_slave_swdev_ops = { From 7a66bbc96ce9ad8261fa5f7f6ae65370eb6866ee Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:09 +0200 Subject: [PATCH 454/567] net: remove iflink field from struct net_device Now that all users of iflink have the ndo_get_iflink handler available, it's possible to remove this field. By default, dev_get_iflink() returns the ifindex of the interface. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +-- net/core/dev.c | 13 ++----------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 788eb7a622ad..846a1f5bc9db 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1538,7 +1538,7 @@ struct net_device { netdev_features_t mpls_features; int ifindex; - int iflink; + int group; struct net_device_stats stats; @@ -1741,7 +1741,6 @@ struct net_device { #endif struct phy_device *phydev; struct lock_class_key *qdisc_tx_busylock; - int group; struct pm_qos_request pm_qos_req; }; #define to_net_dev(d) container_of(d, struct net_device, dev) diff --git a/net/core/dev.c b/net/core/dev.c index 77172d085760..3be107e0bc93 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -672,7 +672,7 @@ int dev_get_iflink(const struct net_device *dev) if (dev->netdev_ops && dev->netdev_ops->ndo_get_iflink) return dev->netdev_ops->ndo_get_iflink(dev); - return dev->iflink; + return dev->ifindex; } EXPORT_SYMBOL(dev_get_iflink); @@ -6331,8 +6331,6 @@ int register_netdevice(struct net_device *dev) spin_lock_init(&dev->addr_list_lock); netdev_set_addr_lockdep_class(dev); - dev->iflink = -1; - ret = dev_get_valid_name(net, dev, dev->name); if (ret < 0) goto out; @@ -6362,9 +6360,6 @@ int register_netdevice(struct net_device *dev) else if (__dev_get_by_index(net, dev->ifindex)) goto err_uninit; - if (dev_get_iflink(dev) == -1) - dev->iflink = dev->ifindex; - /* Transfer changeable features to wanted_features and enable * software offloads (GSO and GRO). */ @@ -7077,12 +7072,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char dev_net_set(dev, net); /* If there is an ifindex conflict assign a new one */ - if (__dev_get_by_index(net, dev->ifindex)) { - int iflink = (dev_get_iflink(dev) == dev->ifindex); + if (__dev_get_by_index(net, dev->ifindex)) dev->ifindex = dev_new_index(net); - if (iflink) - dev->iflink = dev->ifindex; - } /* Send a netdev-add uevent to the new namespace */ kobject_uevent(&dev->dev.kobj, KOBJ_ADD); From e1622baf54df8cc958bf29d71de5ad545ea7d93c Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:10 +0200 Subject: [PATCH 455/567] dev: set iflink to 0 for virtual interfaces Virtual interfaces are supposed to set an iflink value != of their ifindex. It was not the case for some of them, like vxlan, bond or bridge. Let's set iflink to 0 when dev->rtnl_link_ops is set. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/dev.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 3be107e0bc93..26622d614f81 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -672,6 +672,10 @@ int dev_get_iflink(const struct net_device *dev) if (dev->netdev_ops && dev->netdev_ops->ndo_get_iflink) return dev->netdev_ops->ndo_get_iflink(dev); + /* If dev->rtnl_link_ops is set, it's a virtual interface. */ + if (dev->rtnl_link_ops) + return 0; + return dev->ifindex; } EXPORT_SYMBOL(dev_get_iflink); From a45253bf32bf49cdb2807bad212b84f5ab51ac26 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 2 Apr 2015 17:07:11 +0200 Subject: [PATCH 456/567] veth: set iflink to the peer veth Now that the peer netns is advertised in rtnl messages, we can set this property so that IFLA_LINK will advertise the peer ifindex. It allows the userland to get the full veth configuration. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- drivers/net/veth.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 4cca36ebc4fb..c8186ffda1a3 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -263,6 +263,20 @@ static void veth_poll_controller(struct net_device *dev) } #endif /* CONFIG_NET_POLL_CONTROLLER */ +static int veth_get_iflink(const struct net_device *dev) +{ + struct veth_priv *priv = netdev_priv(dev); + struct net_device *peer; + int iflink; + + rcu_read_lock(); + peer = rcu_dereference(priv->peer); + iflink = peer ? peer->ifindex : 0; + rcu_read_unlock(); + + return iflink; +} + static const struct net_device_ops veth_netdev_ops = { .ndo_init = veth_dev_init, .ndo_open = veth_open, @@ -275,6 +289,7 @@ static const struct net_device_ops veth_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = veth_poll_controller, #endif + .ndo_get_iflink = veth_get_iflink, }; #define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ From e213568ad6b06ac828fe2a050fe4ec7b69f09f37 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 2 Apr 2015 12:00:58 -0700 Subject: [PATCH 457/567] Bluetooth: Disallow LE local out-of-band data when LE privacy is used When the LE pivacy feature is used, then pairing has to happen based on resolvable random addresses (RPA), but currently there is no clean way to retrieve the correct RPA. So instead of returning an outdated RPA, just disallow this command when LE privacy is in use. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index bb0c53ac4c66..20a7765680df 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6526,13 +6526,26 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, goto complete; } + /* This should return the active RPA, but since the RPA + * is only programmed on demand, it is really hard to fill + * this in at the moment. For now disallow retrieving + * local out-of-band data when privacy is in use. + * + * Returning the identity address will not help here since + * pairing happens before the identity resolving key is + * known and thus the connection establishment happens + * based on the RPA and not the identity address. + */ if (hci_dev_test_flag(hdev, HCI_PRIVACY)) { - memcpy(addr, &hdev->rpa, 6); - addr[6] = 0x01; - } else if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) || - !bacmp(&hdev->bdaddr, BDADDR_ANY) || - (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) && - bacmp(&hdev->static_addr, BDADDR_ANY))) { + hci_dev_unlock(hdev); + status = MGMT_STATUS_REJECTED; + goto complete; + } + + if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) || + !bacmp(&hdev->bdaddr, BDADDR_ANY) || + (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) && + bacmp(&hdev->static_addr, BDADDR_ANY))) { memcpy(addr, &hdev->static_addr, 6); addr[6] = 0x01; } else { From 0c36820e2ab7d943ab1188230fdf2149826d33c0 Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Tue, 31 Mar 2015 11:05:15 +0100 Subject: [PATCH 458/567] xen-netfront: transmit fully GSO-sized packets xen-netfront limits transmitted skbs to be at most 44 segments in size. However, GSO permits up to 65536 bytes, which means a maximum of 45 segments of 1448 bytes each. This slight reduction in the size of packets means a slight loss in efficiency. Since c/s 9ecd1a75d, xen-netfront sets gso_max_size to XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER, where XEN_NETIF_MAX_TX_SIZE is 65535 bytes. The calculation used by tcp_tso_autosize (and also tcp_xmit_size_goal since c/s 6c09fa09d) in determining when to split an skb into two is sk->sk_gso_max_size - 1 - MAX_TCP_HEADER. So the maximum permitted size of an skb is calculated to be (XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER) - 1 - MAX_TCP_HEADER. Intuitively, this looks like the wrong formula -- we don't need two TCP headers. Instead, there is no need to deviate from the default gso_max_size of 65536 as this already accommodates the size of the header. Currently, the largest skb transmitted by netfront is 63712 bytes (44 segments of 1448 bytes each), as observed via tcpdump. This patch makes netfront send skbs of up to 65160 bytes (45 segments of 1448 bytes each). Similarly, the maximum allowable mtu does not need to subtract MAX_TCP_HEADER as it relates to the size of the whole packet, including the header. Fixes: 9ecd1a75d977 ("xen-netfront: reduce gso_max_size to account for max TCP header") Signed-off-by: Jonathan Davies Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index e9b960f0ff32..720aaf6313d2 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1008,8 +1008,7 @@ err: static int xennet_change_mtu(struct net_device *dev, int mtu) { - int max = xennet_can_sg(dev) ? - XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER : ETH_DATA_LEN; + int max = xennet_can_sg(dev) ? XEN_NETIF_MAX_TX_SIZE : ETH_DATA_LEN; if (mtu > max) return -EINVAL; @@ -1279,8 +1278,6 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) netdev->ethtool_ops = &xennet_ethtool_ops; SET_NETDEV_DEV(netdev, &dev->dev); - netif_set_gso_max_size(netdev, XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER); - np->netdev = netdev; netif_carrier_off(netdev); From 802f42a8d99254b8602bf65cc50e8333bf479f13 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:06 +0300 Subject: [PATCH 459/567] net/mlx4: Add RSS support for fragmented IP datagrams Enable RSS support for fragmented IP packets, when device supports it. Until now, fragmented IP packets were directed only to the default_qpn. Since IP fragments (datagram) have no upper protocols (L3 IP packets), hash is performed on 3-tuple - dst MAC, source IP and dest IP. The HW makes sure that this holds for the 1st fragment too, so all fragments go to the same QP. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 12 ++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw.h | 1 + drivers/net/ethernet/mellanox/mlx4/main.c | 2 ++ include/linux/mlx4/device.h | 1 + 4 files changed, 16 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 209a6171e59b..412e019e8b2e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -105,6 +105,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) [41] = "Unicast VEP steering support", [42] = "Multicast VEP steering support", [48] = "Counters support", + [52] = "RSS IP fragments support", [53] = "Port ETS Scheduler support", [55] = "Port link type sensing support", [59] = "Port management change event support", @@ -1138,6 +1139,9 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, } for (; slave_port < dev->caps.num_ports; ++slave_port) flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port); + + /* Not exposing RSS IP fragments to guests */ + flags &= ~MLX4_DEV_CAP_FLAG_RSS_IP_FRAG; MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VL_PORT_OFFSET); @@ -1701,6 +1705,10 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) if (dev->caps.flags & MLX4_DEV_CAP_FLAG_COUNTERS) *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 4); + /* Enable RSS spread to fragmented IP packets when supported */ + if (dev->caps.flags & MLX4_DEV_CAP_FLAG_RSS_IP_FRAG) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 13); + /* CX3 is capable of extending CQEs/EQEs from 32 to 64 bytes */ if (dev->caps.flags & MLX4_DEV_CAP_FLAG_64B_EQE) { *(inbox + INIT_HCA_EQE_CQE_OFFSETS / 4) |= cpu_to_be32(1 << 29); @@ -1889,6 +1897,10 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev, else param->steering_mode = MLX4_STEERING_MODE_A0; } + + if (dword_field & (1 << 13)) + param->rss_ip_frags = 1; + /* steering attributes */ if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) { MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h index 863655bd3947..07cb7c2461ad 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -203,6 +203,7 @@ struct mlx4_init_hca_param { u64 dev_cap_enabled; u16 cqe_size; /* For use only when CQE stride feature enabled */ u16 eqe_size; /* For use only when EQE stride feature enabled */ + u8 rss_ip_frags; }; struct mlx4_init_ib_param { diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 43aa76775b5f..ee0a67069b57 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -885,6 +885,8 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) mlx4_warn(dev, "Timestamping is not supported in slave mode\n"); slave_adjust_steering_mode(dev, &dev_cap, &hca_param); + mlx4_dbg(dev, "RSS support for IP fragments is %s\n", + hca_param.rss_ip_frags ? "on" : "off"); if (func_cap.extra_flags & MLX4_QUERY_FUNC_FLAGS_BF_RES_QP && dev->caps.bf_reg_size) diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index ab7ebec943b8..41eaafdfb1cd 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -174,6 +174,7 @@ enum { MLX4_DEV_CAP_FLAG_VEP_UC_STEER = 1LL << 41, MLX4_DEV_CAP_FLAG_VEP_MC_STEER = 1LL << 42, MLX4_DEV_CAP_FLAG_COUNTERS = 1LL << 48, + MLX4_DEV_CAP_FLAG_RSS_IP_FRAG = 1LL << 52, MLX4_DEV_CAP_FLAG_SET_ETH_SCHED = 1LL << 53, MLX4_DEV_CAP_FLAG_SENSE_SUPPORT = 1LL << 55, MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV = 1LL << 59, From 241a08c3a767ca2f6ab1c99c4db4c3ff867de8aa Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:07 +0300 Subject: [PATCH 460/567] net/mlx4_en: Change loopback only upon feature change Currently any change of netdev features results in a call to mlx4_en_update_loopback_state(). Those calls are unnecessary, and should be called only upon loopback feature change. Also moved some of the logic into mlx4_en_update_loopback_state(). Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_main.c | 5 +++++ drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 12 +++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index 58d5a07d0ff4..913b716ed2e1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -103,6 +103,11 @@ void mlx4_en_update_loopback_state(struct net_device *dev, { struct mlx4_en_priv *priv = netdev_priv(dev); + if (features & NETIF_F_LOOPBACK) + priv->ctrl_flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK); + else + priv->ctrl_flags &= cpu_to_be32(~MLX4_WQE_CTRL_FORCE_LOOPBACK); + priv->flags &= ~(MLX4_EN_FLAG_RX_FILTER_NEEDED| MLX4_EN_FLAG_ENABLE_HW_LOOPBACK); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 51b20663c2a6..d73ab1ba5a78 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2210,13 +2210,11 @@ static int mlx4_en_set_features(struct net_device *netdev, en_info(priv, "Turn %s TX vlan strip offload\n", (features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF"); - if (features & NETIF_F_LOOPBACK) - priv->ctrl_flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK); - else - priv->ctrl_flags &= - cpu_to_be32(~MLX4_WQE_CTRL_FORCE_LOOPBACK); - - mlx4_en_update_loopback_state(netdev, features); + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_LOOPBACK)) { + en_info(priv, "Turn %s loopback\n", + (features & NETIF_F_LOOPBACK) ? "ON" : "OFF"); + mlx4_en_update_loopback_state(netdev, features); + } return 0; From fccea6436a5bd16aed6f722efce13ec2c90427d7 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:08 +0300 Subject: [PATCH 461/567] net/mlx4: Make mlx4_is_eth visible inline funcion Currently implemented as static function in resource_tracker.c -- this change will allow other files in mlx4_core to use it as well. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 5 ----- include/linux/mlx4/device.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 11bcd27e218f..fd2520aa8a8c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -221,11 +221,6 @@ struct res_fs_rule { int qpn; }; -static int mlx4_is_eth(struct mlx4_dev *dev, int port) -{ - return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1; -} - static void *res_tracker_lookup(struct rb_root *root, u64 res_id) { struct rb_node *node = root->rb_node; diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 41eaafdfb1cd..0f7f13d6a03e 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -1002,6 +1002,11 @@ static inline int mlx4_is_slave(struct mlx4_dev *dev) return dev->flags & MLX4_FLAG_SLAVE; } +static inline int mlx4_is_eth(struct mlx4_dev *dev, int port) +{ + return dev->caps.port_type[port] == MLX4_PORT_TYPE_IB ? 0 : 1; +} + int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, struct mlx4_buf *buf, gfp_t gfp); void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf); From 4abccb61578694372dc9b245afd41f55b5f1e546 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:09 +0300 Subject: [PATCH 462/567] net/mlx4: Aesthetic code changes in multi_func_init Previous vf_oper and vf_admin code created very long lines, making it hard to read the code. Added relevant in-struct pointers to reduce code complexity and avoid code lines spread over 80 lines. Same logic is preserved. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 08ab90a70965..179ca2889434 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -2212,6 +2212,9 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) } if (mlx4_is_master(dev)) { + struct mlx4_vf_oper_state *vf_oper; + struct mlx4_vf_admin_state *vf_admin; + priv->mfunc.master.slave_state = kzalloc(dev->num_slaves * sizeof(struct mlx4_slave_state), GFP_KERNEL); @@ -2231,6 +2234,8 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) goto err_comm_oper; for (i = 0; i < dev->num_slaves; ++i) { + vf_admin = &priv->mfunc.master.vf_admin[i]; + vf_oper = &priv->mfunc.master.vf_oper[i]; s_state = &priv->mfunc.master.slave_state[i]; s_state->last_cmd = MLX4_COMM_CMD_RESET; mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]); @@ -2242,6 +2247,9 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) &priv->mfunc.comm[i].slave_read); mmiowb(); for (port = 1; port <= MLX4_MAX_PORTS; port++) { + struct mlx4_vport_state *admin_vport; + struct mlx4_vport_state *oper_vport; + s_state->vlan_filter[port] = kzalloc(sizeof(struct mlx4_vlan_fltr), GFP_KERNEL); @@ -2250,11 +2258,14 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) kfree(s_state->vlan_filter[port]); goto err_slaves; } + + admin_vport = &vf_admin->vport[port]; + oper_vport = &vf_oper->vport[port].state; INIT_LIST_HEAD(&s_state->mcast_filters[port]); - priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT; - priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT; - priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX; - priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX; + admin_vport->default_vlan = MLX4_VGT; + oper_vport->default_vlan = MLX4_VGT; + vf_oper->vport[port].vlan_idx = NO_INDX; + vf_oper->vport[port].mac_idx = NO_INDX; } spin_lock_init(&s_state->lock); } From 12a889c057504fbf307dd237aedb87263ef2848a Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:10 +0300 Subject: [PATCH 463/567] net/mlx4: New file for QoS related firmware commands Create two new files fw_qos.h and fw_qos.c in mlx4_core module. It gathers all relevant QoS firmware related commands etc, thus improving encapsulation of the mlx4_core module. For now it contains the QoS existing commands: mlx4_SET_PORT_SCHEDULER and mlx4_SET_PORT_PRIO2TC. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/Makefile | 5 +- .../net/ethernet/mellanox/mlx4/en_dcb_nl.c | 1 + drivers/net/ethernet/mellanox/mlx4/fw_qos.c | 125 ++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw_qos.h | 75 +++++++++++ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 15 --- drivers/net/ethernet/mellanox/mlx4/port.c | 71 ---------- include/linux/mlx4/device.h | 5 - 7 files changed, 204 insertions(+), 93 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx4/fw_qos.c create mode 100644 drivers/net/ethernet/mellanox/mlx4/fw_qos.h diff --git a/drivers/net/ethernet/mellanox/mlx4/Makefile b/drivers/net/ethernet/mellanox/mlx4/Makefile index 3e9c70f15b42..c82217e0d22d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/Makefile +++ b/drivers/net/ethernet/mellanox/mlx4/Makefile @@ -1,7 +1,8 @@ obj-$(CONFIG_MLX4_CORE) += mlx4_core.o -mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ - mr.o pd.o port.o profile.o qp.o reset.o sense.o srq.o resource_tracker.o +mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o fw_qos.o icm.o intf.o \ + main.o mcg.o mr.o pd.o port.o profile.o qp.o reset.o sense.o \ + srq.o resource_tracker.o obj-$(CONFIG_MLX4_EN) += mlx4_en.o diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index 8e3260c0eaa5..f01918c63f28 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -35,6 +35,7 @@ #include #include "mlx4_en.h" +#include "fw_qos.h" /* Definitions for QCN */ diff --git a/drivers/net/ethernet/mellanox/mlx4/fw_qos.c b/drivers/net/ethernet/mellanox/mlx4/fw_qos.c new file mode 100644 index 000000000000..0f5af7cf4547 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx4/fw_qos.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. + * All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "fw_qos.h" + +struct mlx4_set_port_prio2tc_context { + u8 prio2tc[4]; +}; + +struct mlx4_port_scheduler_tc_cfg_be { + __be16 pg; + __be16 bw_precentage; + __be16 max_bw_units; /* 3-100Mbps, 4-1Gbps, other values - reserved */ + __be16 max_bw_value; +}; + +struct mlx4_set_port_scheduler_context { + struct mlx4_port_scheduler_tc_cfg_be tc[MLX4_NUM_TC]; +}; + +int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_port_prio2tc_context *context; + int err; + u32 in_mod; + int i; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + context = mailbox->buf; + + for (i = 0; i < MLX4_NUM_UP; i += 2) + context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1]; + + in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC); + +int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, + u8 *pg, u16 *ratelimit) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_port_scheduler_context *context; + int err; + u32 in_mod; + int i; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + context = mailbox->buf; + + for (i = 0; i < MLX4_NUM_TC; i++) { + struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; + u16 r; + + if (ratelimit && ratelimit[i]) { + if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) { + r = ratelimit[i]; + tc->max_bw_units = + htons(MLX4_RATELIMIT_100M_UNITS); + } else { + r = ratelimit[i] / 10; + tc->max_bw_units = + htons(MLX4_RATELIMIT_1G_UNITS); + } + tc->max_bw_value = htons(r); + } else { + tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT); + tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS); + } + + tc->pg = htons(pg[i]); + tc->bw_precentage = htons(tc_tx_bw[i]); + } + + in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h new file mode 100644 index 000000000000..ab9be0fad9c8 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. + * All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_FW_QOS_H +#define MLX4_FW_QOS_H + +#include +#include + +#define MLX4_NUM_UP 8 +#define MLX4_NUM_TC 8 + +/** + * mlx4_SET_PORT_PRIO2TC - This routine maps user priorities to traffic + * classes of a given port and device. + * + * @dev: mlx4_dev. + * @port: Physical port number. + * @prio2tc: Array of TC associated with each priorities. + * + * Returns 0 on success or a negative mlx4_core errno code. + **/ +int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc); + +/** + * mlx4_SET_PORT_SCHEDULER - This routine configures the arbitration between + * traffic classes (ETS) and configured rate limit for traffic classes. + * tc_tx_bw, pg and ratelimit are arrays where each index represents a TC. + * The description for those parameters below refers to a single TC. + * + * @dev: mlx4_dev. + * @port: Physical port number. + * @tc_tx_bw: The percentage of the bandwidth allocated for traffic class + * within a TC group. The sum of the bw_percentage of all the traffic + * classes within a TC group must equal 100% for correct operation. + * @pg: The TC group the traffic class is associated with. + * @ratelimit: The maximal bandwidth allowed for the use by this traffic class. + * + * Returns 0 on success or a negative mlx4_core errno code. + **/ +int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, + u8 *pg, u16 *ratelimit); + +#endif /* MLX4_FW_QOS_H */ diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 0b16db015745..9e5236b1b5f8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -64,21 +64,6 @@ #define INIT_HCA_TPT_MW_ENABLE (1 << 7) -struct mlx4_set_port_prio2tc_context { - u8 prio2tc[4]; -}; - -struct mlx4_port_scheduler_tc_cfg_be { - __be16 pg; - __be16 bw_precentage; - __be16 max_bw_units; /* 3-100Mbps, 4-1Gbps, other values - reserved */ - __be16 max_bw_value; -}; - -struct mlx4_set_port_scheduler_context { - struct mlx4_port_scheduler_tc_cfg_be tc[MLX4_NUM_TC]; -}; - enum { MLX4_HCR_BASE = 0x80680, MLX4_HCR_SIZE = 0x0001c, diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index b97f173ab062..6a53d42db52f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -1016,77 +1016,6 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, } EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); -int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_prio2tc_context *context; - int err; - u32 in_mod; - int i; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - for (i = 0; i < MLX4_NUM_UP; i += 2) - context->prio2tc[i >> 1] = prio2tc[i] << 4 | prio2tc[i + 1]; - - in_mod = MLX4_SET_PORT_PRIO2TC << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_SET_PORT_PRIO2TC); - -int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, - u8 *pg, u16 *ratelimit) -{ - struct mlx4_cmd_mailbox *mailbox; - struct mlx4_set_port_scheduler_context *context; - int err; - u32 in_mod; - int i; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) - return PTR_ERR(mailbox); - context = mailbox->buf; - - for (i = 0; i < MLX4_NUM_TC; i++) { - struct mlx4_port_scheduler_tc_cfg_be *tc = &context->tc[i]; - u16 r; - - if (ratelimit && ratelimit[i]) { - if (ratelimit[i] <= MLX4_MAX_100M_UNITS_VAL) { - r = ratelimit[i]; - tc->max_bw_units = - htons(MLX4_RATELIMIT_100M_UNITS); - } else { - r = ratelimit[i]/10; - tc->max_bw_units = - htons(MLX4_RATELIMIT_1G_UNITS); - } - tc->max_bw_value = htons(r); - } else { - tc->max_bw_value = htons(MLX4_RATELIMIT_DEFAULT); - tc->max_bw_units = htons(MLX4_RATELIMIT_1G_UNITS); - } - - tc->pg = htons(pg[i]); - tc->bw_precentage = htons(tc_tx_bw[i]); - } - - in_mod = MLX4_SET_PORT_SCHEDULER << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); - - mlx4_free_cmd_mailbox(dev, mailbox); - return err; -} -EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); - enum { VXLAN_ENABLE_MODIFY = 1 << 7, VXLAN_STEERING_MODIFY = 1 << 6, diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 0f7f13d6a03e..b676d0c0111a 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -49,8 +49,6 @@ #define MSIX_LEGACY_SZ 4 #define MIN_MSIX_P_PORT 5 -#define MLX4_NUM_UP 8 -#define MLX4_NUM_TC 8 #define MLX4_MAX_100M_UNITS_VAL 255 /* * work around: can't set values * greater then this value when @@ -1311,9 +1309,6 @@ int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx); int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, u8 promisc); -int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc); -int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, - u8 *pg, u16 *ratelimit); int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable); int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx); int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); From 7e95bb99a8f969d4534867452793e44cc4731ca9 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:11 +0300 Subject: [PATCH 464/567] net/mlx4: Add mlx4_ALLOCATE_VPP implementation Implements device ALLOCATE_VPP command, to be used for granular QoS configuration of VFs by the PF device. Defines and queries the amount of VPPs assigned to each port, and the amount of VPPs assigned to each priority of each port. Once the total VPPs are split between the priorities of a port, they may be assigned with a share of the BW or a rate limit. Split into two functions (get/set) whoch are supplied with mlx4_alloc_vpp_context and physical port number. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 9 +++ drivers/net/ethernet/mellanox/mlx4/fw_qos.c | 75 +++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw_qos.h | 28 ++++++++ include/linux/mlx4/cmd.h | 1 + 4 files changed, 113 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 179ca2889434..79cc5ec57dca 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1454,6 +1454,15 @@ static struct mlx4_cmd_info cmd_info[] = { .verify = NULL, .wrapper = mlx4_CMD_EPERM_wrapper, }, + { + .opcode = MLX4_CMD_ALLOCATE_VPP, + .has_inbox = false, + .has_outbox = true, + .out_is_imm = false, + .encode_slave_id = false, + .verify = NULL, + .wrapper = mlx4_CMD_EPERM_wrapper, + }, { .opcode = MLX4_CMD_CONF_SPECIAL_QP, .has_inbox = false, diff --git a/drivers/net/ethernet/mellanox/mlx4/fw_qos.c b/drivers/net/ethernet/mellanox/mlx4/fw_qos.c index 0f5af7cf4547..5ce3440b99c7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw_qos.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw_qos.c @@ -34,6 +34,13 @@ #include #include "fw_qos.h" +#include "fw.h" + +enum { + /* allocate vpp opcode modifiers */ + MLX4_ALLOCATE_VPP_ALLOCATE = 0x0, + MLX4_ALLOCATE_VPP_QUERY = 0x1 +}; struct mlx4_set_port_prio2tc_context { u8 prio2tc[4]; @@ -50,6 +57,12 @@ struct mlx4_set_port_scheduler_context { struct mlx4_port_scheduler_tc_cfg_be tc[MLX4_NUM_TC]; }; +/* Granular Qos (per VF) section */ +struct mlx4_alloc_vpp_param { + __be32 availible_vpp; + __be32 vpp_p_up[MLX4_NUM_UP]; +}; + int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) { struct mlx4_cmd_mailbox *mailbox; @@ -123,3 +136,65 @@ int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, return err; } EXPORT_SYMBOL(mlx4_SET_PORT_SCHEDULER); + +int mlx4_ALLOCATE_VPP_get(struct mlx4_dev *dev, u8 port, + u16 *availible_vpp, u8 *vpp_p_up) +{ + int i; + int err; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_alloc_vpp_param *out_param; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + out_param = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma, port, + MLX4_ALLOCATE_VPP_QUERY, + MLX4_CMD_ALLOCATE_VPP, + MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_NATIVE); + if (err) + goto out; + + /* Total number of supported VPPs */ + *availible_vpp = (u16)be32_to_cpu(out_param->availible_vpp); + + for (i = 0; i < MLX4_NUM_UP; i++) + vpp_p_up[i] = (u8)be32_to_cpu(out_param->vpp_p_up[i]); + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + + return err; +} +EXPORT_SYMBOL(mlx4_ALLOCATE_VPP_get); + +int mlx4_ALLOCATE_VPP_set(struct mlx4_dev *dev, u8 port, u8 *vpp_p_up) +{ + int i; + int err; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_alloc_vpp_param *in_param; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + in_param = mailbox->buf; + + for (i = 0; i < MLX4_NUM_UP; i++) + in_param->vpp_p_up[i] = cpu_to_be32(vpp_p_up[i]); + + err = mlx4_cmd(dev, mailbox->dma, port, + MLX4_ALLOCATE_VPP_ALLOCATE, + MLX4_CMD_ALLOCATE_VPP, + MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL(mlx4_ALLOCATE_VPP_set); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h index ab9be0fad9c8..be79951c44ef 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h @@ -71,5 +71,33 @@ int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc); **/ int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw, u8 *pg, u16 *ratelimit); +/** + * mlx4_ALLOCATE_VPP_get - Query port VPP availible resources and allocation. + * Before distribution of VPPs to priorities, only availible_vpp is returned. + * After initialization it returns the distribution of VPPs among priorities. + * + * @dev: mlx4_dev. + * @port: Physical port number. + * @availible_vpp: Pointer to variable where number of availible VPPs is stored + * @vpp_p_up: Distribution of VPPs to priorities is stored in this array + * + * Returns 0 on success or a negative mlx4_core errno code. + **/ +int mlx4_ALLOCATE_VPP_get(struct mlx4_dev *dev, u8 port, + u16 *availible_vpp, u8 *vpp_p_up); +/** + * mlx4_ALLOCATE_VPP_set - Distribution of VPPs among differnt priorities. + * The total number of VPPs assigned to all for a port must not exceed + * the value reported by availible_vpp in mlx4_ALLOCATE_VPP_get. + * VPP allocation is allowed only after the port type has been set, + * and while no QPs are open for this port. + * + * @dev: mlx4_dev. + * @port: Physical port number. + * @vpp_p_up: Allocation of VPPs to different priorities. + * + * Returns 0 on success or a negative mlx4_core errno code. + **/ +int mlx4_ALLOCATE_VPP_set(struct mlx4_dev *dev, u8 port, u8 *vpp_p_up); #endif /* MLX4_FW_QOS_H */ diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h index 7299e9548906..e0f88a098fb8 100644 --- a/include/linux/mlx4/cmd.h +++ b/include/linux/mlx4/cmd.h @@ -68,6 +68,7 @@ enum { MLX4_CMD_UNMAP_ICM_AUX = 0xffb, MLX4_CMD_SET_ICM_SIZE = 0xffd, MLX4_CMD_ACCESS_REG = 0x3b, + MLX4_CMD_ALLOCATE_VPP = 0x80, /*master notify fw on finish for slave's flr*/ MLX4_CMD_INFORM_FLR_DONE = 0x5b, From 1c29146d3821be984030b49cf9509a269edc3b8b Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:12 +0300 Subject: [PATCH 465/567] net/mlx4: Add mlx4_SET_VPORT_QOS implementation Add the SET_VPORT_QOS device command, which is ntended for virtual granular QoS configuration per VF in SRIOV mode. The SET_VPORT_QOS command sets and queries QoS parameters of a VPort. Each priority allowed for a VPort is assigned with a share of the BW, and a BW limitation. QoS parameters can be modified at any time, but must be initialized before any QP is associated with the VPort. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 9 +++ drivers/net/ethernet/mellanox/mlx4/fw_qos.c | 89 +++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw_qos.h | 36 +++++++++ include/linux/mlx4/cmd.h | 1 + 4 files changed, 135 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 79cc5ec57dca..af95231ba3e2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1463,6 +1463,15 @@ static struct mlx4_cmd_info cmd_info[] = { .verify = NULL, .wrapper = mlx4_CMD_EPERM_wrapper, }, + { + .opcode = MLX4_CMD_SET_VPORT_QOS, + .has_inbox = false, + .has_outbox = true, + .out_is_imm = false, + .encode_slave_id = false, + .verify = NULL, + .wrapper = mlx4_CMD_EPERM_wrapper, + }, { .opcode = MLX4_CMD_CONF_SPECIAL_QP, .has_inbox = false, diff --git a/drivers/net/ethernet/mellanox/mlx4/fw_qos.c b/drivers/net/ethernet/mellanox/mlx4/fw_qos.c index 5ce3440b99c7..8f2fde0487c4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw_qos.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw_qos.c @@ -42,6 +42,12 @@ enum { MLX4_ALLOCATE_VPP_QUERY = 0x1 }; +enum { + /* set vport qos opcode modifiers */ + MLX4_SET_VPORT_QOS_SET = 0x0, + MLX4_SET_VPORT_QOS_QUERY = 0x1 +}; + struct mlx4_set_port_prio2tc_context { u8 prio2tc[4]; }; @@ -63,6 +69,19 @@ struct mlx4_alloc_vpp_param { __be32 vpp_p_up[MLX4_NUM_UP]; }; +struct mlx4_prio_qos_param { + __be32 bw_share; + __be32 max_avg_bw; + __be32 reserved; + __be32 enable; + __be32 reserved1[4]; +}; + +struct mlx4_set_vport_context { + __be32 reserved[8]; + struct mlx4_prio_qos_param qos_p_up[MLX4_NUM_UP]; +}; + int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc) { struct mlx4_cmd_mailbox *mailbox; @@ -198,3 +217,73 @@ int mlx4_ALLOCATE_VPP_set(struct mlx4_dev *dev, u8 port, u8 *vpp_p_up) return err; } EXPORT_SYMBOL(mlx4_ALLOCATE_VPP_set); + +int mlx4_SET_VPORT_QOS_get(struct mlx4_dev *dev, u8 port, u8 vport, + struct mlx4_vport_qos_param *out_param) +{ + int i; + int err; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_vport_context *ctx; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + ctx = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma, (vport << 8) | port, + MLX4_SET_VPORT_QOS_QUERY, + MLX4_CMD_SET_VPORT_QOS, + MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_NATIVE); + if (err) + goto out; + + for (i = 0; i < MLX4_NUM_UP; i++) { + out_param[i].bw_share = be32_to_cpu(ctx->qos_p_up[i].bw_share); + out_param[i].max_avg_bw = + be32_to_cpu(ctx->qos_p_up[i].max_avg_bw); + out_param[i].enable = + !!(be32_to_cpu(ctx->qos_p_up[i].enable) & 31); + } + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + + return err; +} +EXPORT_SYMBOL(mlx4_SET_VPORT_QOS_get); + +int mlx4_SET_VPORT_QOS_set(struct mlx4_dev *dev, u8 port, u8 vport, + struct mlx4_vport_qos_param *in_param) +{ + int i; + int err; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_vport_context *ctx; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + ctx = mailbox->buf; + + for (i = 0; i < MLX4_NUM_UP; i++) { + ctx->qos_p_up[i].bw_share = cpu_to_be32(in_param[i].bw_share); + ctx->qos_p_up[i].max_avg_bw = + cpu_to_be32(in_param[i].max_avg_bw); + ctx->qos_p_up[i].enable = + cpu_to_be32(in_param[i].enable << 31); + } + + err = mlx4_cmd(dev, mailbox->dma, (vport << 8) | port, + MLX4_SET_VPORT_QOS_SET, + MLX4_CMD_SET_VPORT_QOS, + MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL(mlx4_SET_VPORT_QOS_set); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h index be79951c44ef..b3fffafff062 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h @@ -41,6 +41,12 @@ #define MLX4_NUM_UP 8 #define MLX4_NUM_TC 8 +struct mlx4_vport_qos_param { + u32 bw_share; + u32 max_avg_bw; + u8 enable; +}; + /** * mlx4_SET_PORT_PRIO2TC - This routine maps user priorities to traffic * classes of a given port and device. @@ -100,4 +106,34 @@ int mlx4_ALLOCATE_VPP_get(struct mlx4_dev *dev, u8 port, **/ int mlx4_ALLOCATE_VPP_set(struct mlx4_dev *dev, u8 port, u8 *vpp_p_up); +/** + * mlx4_SET_VPORT_QOS_get - Query QoS proporties of a Vport. + * Each priority allowed for the Vport is assigned with a share of the BW, + * and a BW limitation. This commands query the current QoS values. + * + * @dev: mlx4_dev. + * @port: Physical port number. + * @vport: Vport id. + * @out_param: Array of mlx4_vport_qos_param that will contain the values. + * + * Returns 0 on success or a negative mlx4_core errno code. + **/ +int mlx4_SET_VPORT_QOS_get(struct mlx4_dev *dev, u8 port, u8 vport, + struct mlx4_vport_qos_param *out_param); + +/** + * mlx4_SET_VPORT_QOS_set - Set QoS proporties of a Vport. + * QoS parameters can be modified at any time, but must be initialized + * before any QP is associated with the VPort. + * + * @dev: mlx4_dev. + * @port: Physical port number. + * @vport: Vport id. + * @out_param: Array of mlx4_vport_qos_param which holds the requested values. + * + * Returns 0 on success or a negative mlx4_core errno code. + **/ +int mlx4_SET_VPORT_QOS_set(struct mlx4_dev *dev, u8 port, u8 vport, + struct mlx4_vport_qos_param *in_param); + #endif /* MLX4_FW_QOS_H */ diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h index e0f88a098fb8..88326ed0033a 100644 --- a/include/linux/mlx4/cmd.h +++ b/include/linux/mlx4/cmd.h @@ -69,6 +69,7 @@ enum { MLX4_CMD_SET_ICM_SIZE = 0xffd, MLX4_CMD_ACCESS_REG = 0x3b, MLX4_CMD_ALLOCATE_VPP = 0x80, + MLX4_CMD_SET_VPORT_QOS = 0x81, /*master notify fw on finish for slave's flr*/ MLX4_CMD_INFORM_FLR_DONE = 0x5b, From d019fcb2244519d453694bfce868f3e717bfcebb Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:13 +0300 Subject: [PATCH 466/567] net/mlx4: Query device for QoS per VF support Checks in QUERY_DEV_CAP if the granular QoS per VF feature is supported by the device. Disabled for guests. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 10 +++++++++- include/linux/mlx4/device.h | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 412e019e8b2e..94e857e39063 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -147,7 +147,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [21] = "Port Remap support", [22] = "QCN support", [23] = "QP rate limiting support", - [24] = "Ethernet Flow control statistics support" + [24] = "Ethernet Flow control statistics support", + [25] = "Granular QoS per VF support", }; int i; @@ -871,6 +872,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET); dev_cap->max_rq_desc_sz = size; MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE); + if (field & (1 << 4)) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QOS_VPP; if (field & (1 << 5)) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL; if (field & (1 << 6)) @@ -1199,6 +1202,11 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, field16 = 0; MLX4_PUT(outbox->buf, field16, QUERY_DEV_CAP_QP_RATE_LIMIT_NUM_OFFSET); + /* turn off QoS per VF support for guests */ + MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE); + field &= 0xef; + MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE); + return 0; } diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index b676d0c0111a..c37208f7869f 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -205,7 +205,8 @@ enum { MLX4_DEV_CAP_FLAG2_PORT_REMAP = 1LL << 21, MLX4_DEV_CAP_FLAG2_QCN = 1LL << 22, MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT = 1LL << 23, - MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN = 1LL << 24 + MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN = 1LL << 24, + MLX4_DEV_CAP_FLAG2_QOS_VPP = 1LL << 25, }; enum { From 666672d480fbae1af2e086f2bea200ed5607f967 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:14 +0300 Subject: [PATCH 467/567] net/mlx4: Allocate VPPs for each port on PF init Initialization of granular Qos per VF mechanism. Query the port availible VPPs and allocates those on all supported priorities in an equal share. Allocation is done only in SRIOV mode, when the feature is supported by the device and port type is Ethernet. Allocation currently is done only on the default priority 0. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 66 +++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw_qos.h | 3 + drivers/net/ethernet/mellanox/mlx4/mlx4.h | 7 +++ 3 files changed, 76 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index af95231ba3e2..7d3c64275b75 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -1883,6 +1883,63 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, return 0; } +static void mlx4_set_default_port_qos(struct mlx4_dev *dev, int port) +{ + struct mlx4_qos_manager *port_qos_ctl; + struct mlx4_priv *priv = mlx4_priv(dev); + + port_qos_ctl = &priv->mfunc.master.qos_ctl[port]; + bitmap_zero(port_qos_ctl->priority_bm, MLX4_NUM_UP); + + /* Enable only default prio at PF init routine */ + set_bit(MLX4_DEFAULT_QOS_PRIO, port_qos_ctl->priority_bm); +} + +static void mlx4_allocate_port_vpps(struct mlx4_dev *dev, int port) +{ + int i; + int err; + int num_vfs; + u16 availible_vpp; + u8 vpp_param[MLX4_NUM_UP]; + struct mlx4_qos_manager *port_qos; + struct mlx4_priv *priv = mlx4_priv(dev); + + err = mlx4_ALLOCATE_VPP_get(dev, port, &availible_vpp, vpp_param); + if (err) { + mlx4_info(dev, "Failed query availible VPPs\n"); + return; + } + + port_qos = &priv->mfunc.master.qos_ctl[port]; + num_vfs = (availible_vpp / + bitmap_weight(port_qos->priority_bm, MLX4_NUM_UP)); + + for (i = 0; i < MLX4_NUM_UP; i++) { + if (test_bit(i, port_qos->priority_bm)) + vpp_param[i] = num_vfs; + } + + err = mlx4_ALLOCATE_VPP_set(dev, port, vpp_param); + if (err) { + mlx4_info(dev, "Failed allocating VPPs\n"); + return; + } + + /* Query actual allocated VPP, just to make sure */ + err = mlx4_ALLOCATE_VPP_get(dev, port, &availible_vpp, vpp_param); + if (err) { + mlx4_info(dev, "Failed query availible VPPs\n"); + return; + } + + port_qos->num_of_qos_vfs = num_vfs; + mlx4_dbg(dev, "Port %d Availible VPPs %d\n", port, availible_vpp); + + for (i = 0; i < MLX4_NUM_UP; i++) + mlx4_dbg(dev, "Port %d UP %d Allocated %d VPPs\n", port, i, + vpp_param[i]); +} static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) { @@ -2288,6 +2345,15 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) spin_lock_init(&s_state->lock); } + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP) { + for (port = 1; port <= dev->caps.num_ports; port++) { + if (mlx4_is_eth(dev, port)) { + mlx4_set_default_port_qos(dev, port); + mlx4_allocate_port_vpps(dev, port); + } + } + } + memset(&priv->mfunc.master.cmd_eqe, 0, dev->caps.eqe_size); priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD; INIT_WORK(&priv->mfunc.master.comm_work, diff --git a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h index b3fffafff062..4a5320f79094 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h @@ -41,6 +41,9 @@ #define MLX4_NUM_UP 8 #define MLX4_NUM_TC 8 +/* Default supported priorities for VPP allocation */ +#define MLX4_DEFAULT_QOS_PRIO (0) + struct mlx4_vport_qos_param { u32 bw_share; u32 max_avg_bw; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 9e5236b1b5f8..1add698dba5b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -50,6 +50,7 @@ #include #include #include +#include "fw_qos.h" #define DRV_NAME "mlx4_core" #define PFX DRV_NAME ": " @@ -553,6 +554,11 @@ struct mlx4_slave_event_eq { struct mlx4_eqe event_eqe[SLAVE_EVENT_EQ_SIZE]; }; +struct mlx4_qos_manager { + int num_of_qos_vfs; + DECLARE_BITMAP(priority_bm, MLX4_NUM_UP); +}; + struct mlx4_master_qp0_state { int proxy_qp0_active; int qp0_active; @@ -577,6 +583,7 @@ struct mlx4_mfunc_master_ctx { struct mlx4_eqe cmd_eqe; struct mlx4_slave_event_eq slave_eq; struct mutex gen_eqe_mutex[MLX4_MFUNC_MAX]; + struct mlx4_qos_manager qos_ctl[MLX4_MAX_PORTS + 1]; }; struct mlx4_mfunc { From 08068cd5683f11e4505aa9c8cc6ed5942f8ad299 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:15 +0300 Subject: [PATCH 468/567] net/mlx4: Added qos_vport QP configuration in VST mode Granular QoS per VF feature introduce a new QP field, qos_vport. PF administrator can connect VF QPs to a certain QoS Vport, to inherit its proporties. Connecting QPs to the default QoS Vport (defined as 0) is always allowed, even when there are no allocated VPPs. At this point, only the default vport is connected to QPs. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 9 ++++++++- drivers/net/ethernet/mellanox/mlx4/fw_qos.h | 3 +++ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 2 ++ drivers/net/ethernet/mellanox/mlx4/qp.c | 5 +++++ drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 6 ++++++ include/linux/mlx4/qp.h | 8 ++++++-- 6 files changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 7d3c64275b75..4c0c6c7e63e7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -48,6 +48,7 @@ #include "mlx4.h" #include "fw.h" +#include "fw_qos.h" #define CMD_POLL_TOKEN 0xffff #define INBOX_MASK 0xffffffffffffff00ULL @@ -1808,7 +1809,8 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, if (vp_oper->state.default_vlan == vp_admin->default_vlan && vp_oper->state.default_qos == vp_admin->default_qos && - vp_oper->state.link_state == vp_admin->link_state) + vp_oper->state.link_state == vp_admin->link_state && + vp_oper->state.qos_vport == vp_admin->qos_vport) return 0; if (!(priv->mfunc.master.slave_state[slave].active && @@ -1866,6 +1868,7 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, vp_oper->state.default_vlan = vp_admin->default_vlan; vp_oper->state.default_qos = vp_admin->default_qos; vp_oper->state.link_state = vp_admin->link_state; + vp_oper->state.qos_vport = vp_admin->qos_vport; if (vp_admin->link_state == IFLA_VF_LINK_STATE_DISABLE) work->flags |= MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE; @@ -1874,6 +1877,7 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, work->port = port; work->slave = slave; work->qos = vp_oper->state.default_qos; + work->qos_vport = vp_oper->state.qos_vport; work->vlan_id = vp_oper->state.default_vlan; work->vlan_ix = vp_oper->vlan_idx; work->priv = priv; @@ -2339,6 +2343,9 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) INIT_LIST_HEAD(&s_state->mcast_filters[port]); admin_vport->default_vlan = MLX4_VGT; oper_vport->default_vlan = MLX4_VGT; + admin_vport->qos_vport = + MLX4_VPP_DEFAULT_VPORT; + oper_vport->qos_vport = MLX4_VPP_DEFAULT_VPORT; vf_oper->vport[port].vlan_idx = NO_INDX; vf_oper->vport[port].mac_idx = NO_INDX; } diff --git a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h index 4a5320f79094..ac1f331878e6 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw_qos.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw_qos.h @@ -44,6 +44,9 @@ /* Default supported priorities for VPP allocation */ #define MLX4_DEFAULT_QOS_PRIO (0) +/* Derived from FW feature definition, 0 is the default vport fo all QPs */ +#define MLX4_VPP_DEFAULT_VPORT (0) + struct mlx4_vport_qos_param { u32 bw_share; u32 max_avg_bw; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 1add698dba5b..32469c64d580 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -498,6 +498,7 @@ struct mlx4_vport_state { u32 tx_rate; bool spoofchk; u32 link_state; + u8 qos_vport; }; struct mlx4_vf_admin_state { @@ -636,6 +637,7 @@ struct mlx4_vf_immed_vlan_work { int orig_vlan_ix; u8 port; u8 qos; + u8 qos_vport; u16 vlan_id; u16 orig_vlan_id; }; diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 69e4462e4ee4..b75214a80d0e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -447,6 +447,11 @@ int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn, cmd->qp_context.rate_limit_params = cpu_to_be16((params->rate_unit << 14) | params->rate_val); } + if (attr & MLX4_UPDATE_QP_QOS_VPORT) { + qp_mask |= 1ULL << MLX4_UPD_QP_MASK_QOS_VPP; + cmd->qp_context.qos_vport = params->qos_vport; + } + cmd->primary_addr_path_mask = cpu_to_be64(pri_addr_path_mask); cmd->qp_mask = cpu_to_be64(qp_mask); diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index fd2520aa8a8c..c7f28bf4b8e2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -765,6 +765,7 @@ static int update_vport_qp_param(struct mlx4_dev *dev, qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN; qpc->pri_path.sched_queue &= 0xC7; qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3; + qpc->qos_vport = vp_oper->state.qos_vport; } if (vp_oper->state.spoofchk) { qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC; @@ -4917,6 +4918,11 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) qp->sched_queue & 0xC7; upd_context->qp_context.pri_path.sched_queue |= ((work->qos & 0x7) << 3); + upd_context->qp_mask |= + cpu_to_be64(1ULL << + MLX4_UPD_QP_MASK_QOS_VPP); + upd_context->qp_context.qos_vport = + work->qos_vport; } err = mlx4_cmd(dev, mailbox->dma, diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index 1023ebe035b7..6fed539e5456 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h @@ -209,7 +209,8 @@ struct mlx4_qp_context { __be16 sq_wqe_counter; u32 reserved3; __be16 rate_limit_params; - __be16 reserved4; + u8 reserved4; + u8 qos_vport; __be32 param3; __be32 nummmcpeers_basemkey; u8 log_page_size; @@ -231,6 +232,7 @@ struct mlx4_update_qp_context { enum { MLX4_UPD_QP_MASK_PM_STATE = 32, MLX4_UPD_QP_MASK_VSD = 33, + MLX4_UPD_QP_MASK_QOS_VPP = 34, MLX4_UPD_QP_MASK_RATE_LIMIT = 35, }; @@ -432,7 +434,8 @@ enum mlx4_update_qp_attr { MLX4_UPDATE_QP_SMAC = 1 << 0, MLX4_UPDATE_QP_VSD = 1 << 1, MLX4_UPDATE_QP_RATE_LIMIT = 1 << 2, - MLX4_UPDATE_QP_SUPPORTED_ATTRS = (1 << 3) - 1 + MLX4_UPDATE_QP_QOS_VPORT = 1 << 3, + MLX4_UPDATE_QP_SUPPORTED_ATTRS = (1 << 4) - 1 }; enum mlx4_update_qp_params_flags { @@ -441,6 +444,7 @@ enum mlx4_update_qp_params_flags { struct mlx4_update_qp_params { u8 smac_index; + u8 qos_vport; u32 flags; u16 rate_unit; u16 rate_val; From cda373f4849d5dd6fedceb4aeba35682a0e1a833 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:16 +0300 Subject: [PATCH 469/567] net/mlx4_en: Enable TX rate limit per VF Support granular QoS per VF, by implementing the ndo_set_vf_rate. Enforce a rate limit per VF when called, and enabled only for VFs in VST mode with user priority supported by the device. We don't enforce VFs to be in VST mode at the moment of configuration, but rather save the given rate limit and enforce it when the VF is moved to VST with user priority which is supported (currently 0). VST<->VGT or VST qos value state changes are disallowed when a rate limit is configured. Minimum BW share is not supported yet. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 177 +++++++++++++++++- .../net/ethernet/mellanox/mlx4/en_netdev.c | 11 ++ include/linux/mlx4/cmd.h | 2 + 3 files changed, 189 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 4c0c6c7e63e7..bc6e4c9b6bb5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -2781,6 +2781,103 @@ static int mlx4_slaves_closest_port(struct mlx4_dev *dev, int slave, int port) return port; } +static int mlx4_set_vport_qos(struct mlx4_priv *priv, int slave, int port, + int max_tx_rate) +{ + int i; + int err; + struct mlx4_qos_manager *port_qos; + struct mlx4_dev *dev = &priv->dev; + struct mlx4_vport_qos_param vpp_qos[MLX4_NUM_UP]; + + port_qos = &priv->mfunc.master.qos_ctl[port]; + memset(vpp_qos, 0, sizeof(struct mlx4_vport_qos_param) * MLX4_NUM_UP); + + if (slave > port_qos->num_of_qos_vfs) { + mlx4_info(dev, "No availible VPP resources for this VF\n"); + return -EINVAL; + } + + /* Query for default QoS values from Vport 0 is needed */ + err = mlx4_SET_VPORT_QOS_get(dev, port, 0, vpp_qos); + if (err) { + mlx4_info(dev, "Failed to query Vport 0 QoS values\n"); + return err; + } + + for (i = 0; i < MLX4_NUM_UP; i++) { + if (test_bit(i, port_qos->priority_bm) && max_tx_rate) { + vpp_qos[i].max_avg_bw = max_tx_rate; + vpp_qos[i].enable = 1; + } else { + /* if user supplied tx_rate == 0, meaning no rate limit + * configuration is required. so we are leaving the + * value of max_avg_bw as queried from Vport 0. + */ + vpp_qos[i].enable = 0; + } + } + + err = mlx4_SET_VPORT_QOS_set(dev, port, slave, vpp_qos); + if (err) { + mlx4_info(dev, "Failed to set Vport %d QoS values\n", slave); + return err; + } + + return 0; +} + +static bool mlx4_is_vf_vst_and_prio_qos(struct mlx4_dev *dev, int port, + struct mlx4_vport_state *vf_admin) +{ + struct mlx4_qos_manager *info; + struct mlx4_priv *priv = mlx4_priv(dev); + + if (!mlx4_is_master(dev) || + !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) + return false; + + info = &priv->mfunc.master.qos_ctl[port]; + + if (vf_admin->default_vlan != MLX4_VGT && + test_bit(vf_admin->default_qos, info->priority_bm)) + return true; + + return false; +} + +static bool mlx4_valid_vf_state_change(struct mlx4_dev *dev, int port, + struct mlx4_vport_state *vf_admin, + int vlan, int qos) +{ + struct mlx4_vport_state dummy_admin = {0}; + + if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) || + !vf_admin->tx_rate) + return true; + + dummy_admin.default_qos = qos; + dummy_admin.default_vlan = vlan; + + /* VF wants to move to other VST state which is valid with current + * rate limit. Either differnt default vlan in VST or other + * supported QoS priority. Otherwise we don't allow this change when + * the TX rate is still configured. + */ + if (mlx4_is_vf_vst_and_prio_qos(dev, port, &dummy_admin)) + return true; + + mlx4_info(dev, "Cannot change VF state to %s while rate is set\n", + (vlan == MLX4_VGT) ? "VGT" : "VST"); + + if (vlan != MLX4_VGT) + mlx4_info(dev, "VST priority %d not supported for QoS\n", qos); + + mlx4_info(dev, "Please set rate to 0 prior to this VF state change\n"); + + return false; +} + int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -2824,12 +2921,22 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) port = mlx4_slaves_closest_port(dev, slave, port); vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; + if (!mlx4_valid_vf_state_change(dev, port, vf_admin, vlan, qos)) + return -EPERM; + if ((0 == vlan) && (0 == qos)) vf_admin->default_vlan = MLX4_VGT; else vf_admin->default_vlan = vlan; vf_admin->default_qos = qos; + /* If rate was configured prior to VST, we saved the configured rate + * in vf_admin->rate and now, if priority supported we enforce the QoS + */ + if (mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) && + vf_admin->tx_rate) + vf_admin->qos_vport = slave; + if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port)) mlx4_info(dev, "updating vf %d port %d config will take effect on next VF restart\n", @@ -2838,6 +2945,69 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) } EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); +int mlx4_set_vf_rate(struct mlx4_dev *dev, int port, int vf, int min_tx_rate, + int max_tx_rate) +{ + int err; + int slave; + struct mlx4_vport_state *vf_admin; + struct mlx4_priv *priv = mlx4_priv(dev); + + if (!mlx4_is_master(dev) || + !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) + return -EPROTONOSUPPORT; + + if (min_tx_rate) { + mlx4_info(dev, "Minimum BW share not supported\n"); + return -EPROTONOSUPPORT; + } + + slave = mlx4_get_slave_indx(dev, vf); + if (slave < 0) + return -EINVAL; + + port = mlx4_slaves_closest_port(dev, slave, port); + vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; + + err = mlx4_set_vport_qos(priv, slave, port, max_tx_rate); + if (err) { + mlx4_info(dev, "vf %d failed to set rate %d\n", vf, + max_tx_rate); + return err; + } + + vf_admin->tx_rate = max_tx_rate; + /* if VF is not in supported mode (VST with supported prio), + * we do not change vport configuration for its QPs, but save + * the rate, so it will be enforced when it moves to supported + * mode next time. + */ + if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin)) { + mlx4_info(dev, + "rate set for VF %d when not in valid state\n", vf); + + if (vf_admin->default_vlan != MLX4_VGT) + mlx4_info(dev, "VST priority not supported by QoS\n"); + else + mlx4_info(dev, "VF in VGT mode (needed VST)\n"); + + mlx4_info(dev, + "rate %d take affect when VF moves to valid state\n", + max_tx_rate); + return 0; + } + + /* If user sets rate 0 assigning default vport for its QPs */ + vf_admin->qos_vport = max_tx_rate ? slave : MLX4_VPP_DEFAULT_VPORT; + + if (priv->mfunc.master.slave_state[slave].active && + dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) + mlx4_master_immediate_activate_vlan_qos(priv, slave, port); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_set_vf_rate); + /* mlx4_get_slave_default_vlan - * return true if VST ( default vlan) * if VST, will return vlan & qos (if not NULL) @@ -2911,7 +3081,12 @@ int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_in ivf->vlan = s_info->default_vlan; ivf->qos = s_info->default_qos; - ivf->max_tx_rate = s_info->tx_rate; + + if (mlx4_is_vf_vst_and_prio_qos(dev, port, s_info)) + ivf->max_tx_rate = s_info->tx_rate; + else + ivf->max_tx_rate = 0; + ivf->min_tx_rate = 0; ivf->spoofchk = s_info->spoofchk; ivf->linkstate = s_info->link_state; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index d73ab1ba5a78..2a5df0aa2228 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2240,6 +2240,16 @@ static int mlx4_en_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos) return mlx4_set_vf_vlan(mdev->dev, en_priv->port, vf, vlan, qos); } +static int mlx4_en_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate, + int max_tx_rate) +{ + struct mlx4_en_priv *en_priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = en_priv->mdev; + + return mlx4_set_vf_rate(mdev->dev, en_priv->port, vf, min_tx_rate, + max_tx_rate); +} + static int mlx4_en_set_vf_spoofchk(struct net_device *dev, int vf, bool setting) { struct mlx4_en_priv *en_priv = netdev_priv(dev); @@ -2458,6 +2468,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = { .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, .ndo_set_vf_mac = mlx4_en_set_vf_mac, .ndo_set_vf_vlan = mlx4_en_set_vf_vlan, + .ndo_set_vf_rate = mlx4_en_set_vf_rate, .ndo_set_vf_spoofchk = mlx4_en_set_vf_spoofchk, .ndo_set_vf_link_state = mlx4_en_set_vf_link_state, .ndo_get_vf_config = mlx4_en_get_vf_config, diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h index 88326ed0033a..a788839f54bb 100644 --- a/include/linux/mlx4/cmd.h +++ b/include/linux/mlx4/cmd.h @@ -296,6 +296,8 @@ void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbo u32 mlx4_comm_get_version(void); int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac); int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos); +int mlx4_set_vf_rate(struct mlx4_dev *dev, int port, int vf, int min_tx_rate, + int max_tx_rate); int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting); int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf); int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state); From 3742cc65512cd4897a63dce94104f9a6e74997a0 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:17 +0300 Subject: [PATCH 470/567] net/mlx4: Warn users of depracated QoS Firmware A new capability bit was introduced in the past to to differ devices using the QoS ETS feature. The old was deprecated since then. If driver sees device which set only the old capabilty, it will print warning to user suggesting to upgrade the FW. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 2 +- drivers/net/ethernet/mellanox/mlx4/fw.c | 7 +++++-- drivers/net/ethernet/mellanox/mlx4/main.c | 8 ++++++++ include/linux/mlx4/device.h | 1 + 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 2a5df0aa2228..be9e07a72193 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2814,7 +2814,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->msg_enable = MLX4_EN_MSG_LEVEL; #ifdef CONFIG_MLX4_EN_DCB if (!mlx4_is_slave(priv->mdev->dev)) { - if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_SET_ETH_SCHED) { + if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) { dev->dcbnl_ops = &mlx4_en_dcbnl_ops; } else { en_info(priv, "enabling only PFC DCB ops\n"); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 94e857e39063..16bbd6cdff6c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -149,6 +149,7 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [23] = "QP rate limiting support", [24] = "Ethernet Flow control statistics support", [25] = "Granular QoS per VF support", + [26] = "Port ETS Scheduler support", }; int i; @@ -900,6 +901,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN); if (field & 1<<3) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS; + if (field & (1 << 5)) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETS_CFG; MLX4_GET(dev_cap->max_icm_sz, outbox, QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET); if (dev_cap->flags & MLX4_DEV_CAP_FLAG_COUNTERS) @@ -1157,9 +1160,9 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, field &= 0x7f; MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET); - /* For guests, disable vxlan tunneling */ + /* For guests, disable vxlan tunneling and QoS support */ MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VXLAN); - field &= 0xf7; + field &= 0xd7; MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN); /* For guests, report Blueflame disabled */ diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index ee0a67069b57..3becad37aec8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -528,6 +528,14 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.alloc_res_qp_mask = (dev->caps.bf_reg_size ? MLX4_RESERVE_ETH_BF_QP : 0) | MLX4_RESERVE_A0_QP; + + if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) && + dev->caps.flags & MLX4_DEV_CAP_FLAG_SET_ETH_SCHED) { + mlx4_warn(dev, "Old device ETS support detected\n"); + mlx4_warn(dev, "Consider upgrading device FW.\n"); + dev->caps.flags2 |= MLX4_DEV_CAP_FLAG2_ETS_CFG; + } + } else { dev->caps.alloc_res_qp_mask = 0; } diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index c37208f7869f..15f46767342e 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -207,6 +207,7 @@ enum { MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT = 1LL << 23, MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN = 1LL << 24, MLX4_DEV_CAP_FLAG2_QOS_VPP = 1LL << 25, + MLX4_DEV_CAP_FLAG2_ETS_CFG = 1LL << 26, }; enum { From 38438f7c7e8cdbb0e9f55aae0e43da67c460639f Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:18 +0300 Subject: [PATCH 471/567] net/mlx4: Set enhanced QoS support by default when ETS supported If HCA supports ETS QoS feature, set enhanced QoS bit in init_hca as default. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 16bbd6cdff6c..b93e23bef6c9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -49,9 +49,9 @@ enum { extern void __buggy_use_of_MLX4_GET(void); extern void __buggy_use_of_MLX4_PUT(void); -static bool enable_qos; +static bool enable_qos = true; module_param(enable_qos, bool, 0444); -MODULE_PARM_DESC(enable_qos, "Enable Quality of Service support in the HCA (default: off)"); +MODULE_PARM_DESC(enable_qos, "Enable Enhanced QoS support (default: on)"); #define MLX4_GET(dest, source, offset) \ do { \ @@ -1709,7 +1709,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3); /* Enable QoS support if module parameter set */ - if (enable_qos) + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG && enable_qos) *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2); /* enable counters */ From a130b59057320192b4b00ed0ba4bc8a38f66f289 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:19 +0300 Subject: [PATCH 472/567] net/mlx4: Add SET_PORT opcode modifiers enumeration The calls to SET_PORT used hard-code numbers, when supplying command's opcode modifiers, fix that to use well defined constants. Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/main.c | 11 +++---- drivers/net/ethernet/mellanox/mlx4/cmd.c | 3 +- drivers/net/ethernet/mellanox/mlx4/port.c | 36 +++++++++++++---------- include/linux/mlx4/cmd.h | 8 ++++- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index b972c0b41799..976bea794b5f 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -587,8 +587,9 @@ static int mlx4_ib_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_vio ((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask); } - err = mlx4_cmd(dev->dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); + err = mlx4_cmd(dev->dev, mailbox->dma, port, MLX4_SET_PORT_IB_OPCODE, + MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_WRAPPED); mlx4_free_cmd_mailbox(dev->dev, mailbox); return err; @@ -1525,8 +1526,8 @@ static void update_gids_task(struct work_struct *work) memcpy(gids, gw->gids, sizeof gw->gids); err = mlx4_cmd(dev, mailbox->dma, MLX4_SET_PORT_GID_TABLE << 8 | gw->port, - 1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); + MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); if (err) pr_warn("set port command failed\n"); else @@ -1564,7 +1565,7 @@ static void reset_gids_task(struct work_struct *work) IB_LINK_LAYER_ETHERNET) { err = mlx4_cmd(dev, mailbox->dma, MLX4_SET_PORT_GID_TABLE << 8 | gw->port, - 1, MLX4_CMD_SET_PORT, + MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index bc6e4c9b6bb5..06993ea9e6ba 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -726,7 +726,8 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, * specific command/input_mod/opcode_mod/fw-status to be debug. */ if (op == MLX4_CMD_SET_PORT && in_modifier == 1 && - op_modifier == 0 && context->fw_status == CMD_STAT_BAD_SIZE) + op_modifier == MLX4_SET_PORT_IB_OPCODE && + context->fw_status == CMD_STAT_BAD_SIZE) mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n", op, context->fw_status); else diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 6a53d42db52f..ca4488ed561c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -123,8 +123,9 @@ static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, + MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_NATIVE); mlx4_free_cmd_mailbox(dev, mailbox); return err; @@ -337,8 +338,9 @@ static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, + MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_NATIVE); mlx4_free_cmd_mailbox(dev, mailbox); @@ -625,9 +627,9 @@ static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave, MLX4_ROCE_GID_ENTRY_SIZE); err = mlx4_cmd(dev, mailbox->dma, - ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 1, - MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_NATIVE); + ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), + MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); mutex_unlock(&(priv->port[port].gid_table.mutex)); return err; } @@ -941,8 +943,9 @@ int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz) (pkey_tbl_flag << MLX4_CHANGE_PORT_PKEY_TBL_SZ) | (dev->caps.port_ib_mtu[port] << MLX4_SET_PORT_MTU_CAP) | (vl_cap << MLX4_SET_PORT_VL_CAP)); - err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); + err = mlx4_cmd(dev, mailbox->dma, port, + MLX4_SET_PORT_IB_OPCODE, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); if (err != -ENOMEM) break; } @@ -971,8 +974,9 @@ int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, context->pfcrx = pfcrx; in_mod = MLX4_SET_PORT_GENERAL << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); + err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, + MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_WRAPPED); mlx4_free_cmd_mailbox(dev, mailbox); return err; @@ -1008,8 +1012,9 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, context->vlan_miss = MLX4_VLAN_MISS_IDX; in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); + err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, + MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_WRAPPED); mlx4_free_cmd_mailbox(dev, mailbox); return err; @@ -1050,8 +1055,9 @@ int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable) context->steering = steering; in_mod = MLX4_SET_PORT_VXLAN << 8 | port; - err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, + MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_NATIVE); mlx4_free_cmd_mailbox(dev, mailbox); return err; diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h index a788839f54bb..62c4d4def474 100644 --- a/include/linux/mlx4/cmd.h +++ b/include/linux/mlx4/cmd.h @@ -188,7 +188,13 @@ enum { }; enum { - /* set port opcode modifiers */ + /* Set port opcode modifiers */ + MLX4_SET_PORT_IB_OPCODE = 0x0, + MLX4_SET_PORT_ETH_OPCODE = 0x1, +}; + +enum { + /* Set port Ethernet input modifiers */ MLX4_SET_PORT_GENERAL = 0x0, MLX4_SET_PORT_RQP_CALC = 0x1, MLX4_SET_PORT_MAC_TABLE = 0x2, From 51af33cfed248dc8f36fa82df06b85e10038a01e Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Thu, 2 Apr 2015 16:31:20 +0300 Subject: [PATCH 473/567] net/mlx4_en: Add interface identify support Add support for the interface ethtool identify feature. Make the physical port LED to blink with green and yellow colors. The device handles the LED blink by itself (synchrous use of set_phys_id), by returning 0 to ETHTOOL_ID_ACTIVE command. Signed-off-by: Eyal Grossman Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx4/en_ethtool.c | 27 +++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw.c | 10 +++++++ drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 + drivers/net/ethernet/mellanox/mlx4/port.c | 26 ++++++++++++++++++ include/linux/mlx4/cmd.h | 1 + include/linux/mlx4/device.h | 2 ++ 6 files changed, 67 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index eba969b08dd1..3f44e2bbb982 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1939,6 +1939,32 @@ static int mlx4_en_get_module_eeprom(struct net_device *dev, return 0; } +static int mlx4_en_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) +{ + int err; + u16 beacon_duration; + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + + if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_BEACON)) + return -EOPNOTSUPP; + + switch (state) { + case ETHTOOL_ID_ACTIVE: + beacon_duration = PORT_BEACON_MAX_LIMIT; + break; + case ETHTOOL_ID_INACTIVE: + beacon_duration = 0; + break; + default: + return -EOPNOTSUPP; + } + + err = mlx4_SET_PORT_BEACON(mdev->dev, priv->port, beacon_duration); + return err; +} + const struct ethtool_ops mlx4_en_ethtool_ops = { .get_drvinfo = mlx4_en_get_drvinfo, .get_settings = mlx4_en_get_settings, @@ -1948,6 +1974,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .get_sset_count = mlx4_en_get_sset_count, .get_ethtool_stats = mlx4_en_get_ethtool_stats, .self_test = mlx4_en_self_test, + .set_phys_id = mlx4_en_set_phys_id, .get_wol = mlx4_en_get_wol, .set_wol = mlx4_en_set_wol, .get_msglevel = mlx4_en_get_msglevel, diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index b93e23bef6c9..6317844b291f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -150,6 +150,7 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [24] = "Ethernet Flow control statistics support", [25] = "Granular QoS per VF support", [26] = "Port ETS Scheduler support", + [27] = "Port beacon support", }; int i; @@ -647,6 +648,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) #define QUERY_DEV_CAP_RSS_OFFSET 0x2e #define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f #define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33 +#define QUERY_DEV_CAP_PORT_BEACON_OFFSET 0x34 #define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35 #define QUERY_DEV_CAP_MTU_WIDTH_OFFSET 0x36 #define QUERY_DEV_CAP_VL_PORT_OFFSET 0x37 @@ -786,6 +788,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) if (field & 0x80) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FS_EN; dev_cap->fs_log_max_ucast_qp_range_size = field & 0x1f; + MLX4_GET(field, outbox, QUERY_DEV_CAP_PORT_BEACON_OFFSET); + if (field & 0x80) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_BEACON; MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET); if (field & 0x80) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_IPOIB; @@ -1165,6 +1170,11 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, field &= 0xd7; MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN); + /* For guests, disable port BEACON */ + MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_PORT_BEACON_OFFSET); + field &= 0x7f; + MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_PORT_BEACON_OFFSET); + /* For guests, report Blueflame disabled */ MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_BF_OFFSET); field &= 0x7f; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 67eeea244eff..9de30216b146 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -482,6 +482,7 @@ enum { MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP = (1 << 5), }; +#define PORT_BEACON_MAX_LIMIT (65535) #define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE) #define MLX4_EN_MAC_HASH_IDX 5 diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index ca4488ed561c..e8d716dfd5cb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -835,6 +835,12 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, MLX4_CMD_NATIVE); } + /* Slaves are not allowed to SET_PORT beacon (LED) blink */ + if (op_mod == MLX4_SET_PORT_BEACON_OPCODE) { + mlx4_warn(dev, "denying SET_PORT Beacon slave:%d\n", slave); + return -EPERM; + } + /* For IB, we only consider: * - The capability mask, which is set to the aggregate of all * slave function capabilities @@ -1064,6 +1070,26 @@ int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable) } EXPORT_SYMBOL(mlx4_SET_PORT_VXLAN); +int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time) +{ + int err; + struct mlx4_cmd_mailbox *mailbox; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + *((__be32 *)mailbox->buf) = cpu_to_be32(time); + + err = mlx4_cmd(dev, mailbox->dma, port, MLX4_SET_PORT_BEACON_OPCODE, + MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL(mlx4_SET_PORT_BEACON); + int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h index 62c4d4def474..f62e7cf227c6 100644 --- a/include/linux/mlx4/cmd.h +++ b/include/linux/mlx4/cmd.h @@ -191,6 +191,7 @@ enum { /* Set port opcode modifiers */ MLX4_SET_PORT_IB_OPCODE = 0x0, MLX4_SET_PORT_ETH_OPCODE = 0x1, + MLX4_SET_PORT_BEACON_OPCODE = 0x4, }; enum { diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 15f46767342e..b761be7c88c8 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -208,6 +208,7 @@ enum { MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN = 1LL << 24, MLX4_DEV_CAP_FLAG2_QOS_VPP = 1LL << 25, MLX4_DEV_CAP_FLAG2_ETS_CFG = 1LL << 26, + MLX4_DEV_CAP_FLAG2_PORT_BEACON = 1LL << 27, }; enum { @@ -1311,6 +1312,7 @@ int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx); int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, u8 promisc); +int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time); int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable); int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx); int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); From f0df35037a0a0df902a31f79065222951888bbc9 Mon Sep 17 00:00:00 2001 From: Muhammad Mahajna Date: Thu, 2 Apr 2015 16:31:21 +0300 Subject: [PATCH 474/567] net/mlx4_en: Add RX-FCS support Enabled when device supports KEEP FCS. When the flag is set, Ethernet FCS is appended to the end of the frame, controlled by ethtool. Signed-off-by: Muhammad Mahajna Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx4/en_netdev.c | 33 +++++++++++++++---- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 5 ++- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index be9e07a72193..333af3405a80 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2195,15 +2195,19 @@ static int mlx4_en_set_features(struct net_device *netdev, netdev_features_t features) { struct mlx4_en_priv *priv = netdev_priv(netdev); + bool reset = false; int ret = 0; + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_RXFCS)) { + en_info(priv, "Turn %s RX-FCS\n", + (features & NETIF_F_RXFCS) ? "ON" : "OFF"); + reset = true; + } + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_RX)) { en_info(priv, "Turn %s RX vlan strip offload\n", (features & NETIF_F_HW_VLAN_CTAG_RX) ? "ON" : "OFF"); - ret = mlx4_en_reset_config(netdev, priv->hwtstamp_config, - features); - if (ret) - return ret; + reset = true; } if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_TX)) @@ -2216,8 +2220,14 @@ static int mlx4_en_set_features(struct net_device *netdev, mlx4_en_update_loopback_state(netdev, features); } - return 0; + if (reset) { + ret = mlx4_en_reset_config(netdev, priv->hwtstamp_config, + features); + if (ret) + return ret; + } + return 0; } static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac) @@ -2901,6 +2911,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, dev->hw_features |= NETIF_F_LOOPBACK | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; + if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) + dev->hw_features |= NETIF_F_RXFCS; + if (mdev->dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED && mdev->dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC) @@ -2997,7 +3010,8 @@ int mlx4_en_reset_config(struct net_device *dev, if (priv->hwtstamp_config.tx_type == ts_config.tx_type && priv->hwtstamp_config.rx_filter == ts_config.rx_filter && - !DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX)) + !DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX) && + !DEV_FEATURE_CHANGED(dev, features, NETIF_F_RXFCS)) return 0; /* Nothing to change */ if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX) && @@ -3036,6 +3050,13 @@ int mlx4_en_reset_config(struct net_device *dev, dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; } + if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_RXFCS)) { + if (features & NETIF_F_RXFCS) + dev->features |= NETIF_F_RXFCS; + else + dev->features &= ~NETIF_F_RXFCS; + } + /* RX vlan offload and RX time-stamping can't co-exist ! * Regardless of the caller's choice, * Turn Off RX vlan offload in case of time-stamping is ON diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 698d60de1255..79b1501e7951 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -1116,7 +1116,10 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, /* Cancel FCS removal if FW allows */ if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) { context->param3 |= cpu_to_be32(1 << 29); - ring->fcs_del = ETH_FCS_LEN; + if (priv->dev->features & NETIF_F_RXFCS) + ring->fcs_del = 0; + else + ring->fcs_del = ETH_FCS_LEN; } else ring->fcs_del = 0; From 78500b8c03236a18d454c9cc8a24cccca506b200 Mon Sep 17 00:00:00 2001 From: Muhammad Mahajna Date: Thu, 2 Apr 2015 16:31:22 +0300 Subject: [PATCH 475/567] net/mlx4_en: Add RX-ALL support Enabled when the device supports KEEP FCS and IGNORE FCS. When the flag is set, pass all received frames up the stack, even ones with invalid FCS, controlled by ethtool. Signed-off-by: Muhammad Mahajna Signed-off-by: Ido Shamay Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx4/en_netdev.c | 14 ++++++++ drivers/net/ethernet/mellanox/mlx4/fw.c | 8 +++++ drivers/net/ethernet/mellanox/mlx4/main.c | 21 ++++++++++++ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 6 ++-- drivers/net/ethernet/mellanox/mlx4/port.c | 34 +++++++++++++++++++ include/linux/mlx4/device.h | 3 ++ 6 files changed, 84 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 333af3405a80..0f1afc085d58 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2204,6 +2204,17 @@ static int mlx4_en_set_features(struct net_device *netdev, reset = true; } + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_RXALL)) { + u8 ignore_fcs_value = (features & NETIF_F_RXALL) ? 1 : 0; + + en_info(priv, "Turn %s RX-ALL\n", + ignore_fcs_value ? "ON" : "OFF"); + ret = mlx4_SET_PORT_fcs_check(priv->mdev->dev, + priv->port, ignore_fcs_value); + if (ret) + return ret; + } + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_RX)) { en_info(priv, "Turn %s RX vlan strip offload\n", (features & NETIF_F_HW_VLAN_CTAG_RX) ? "ON" : "OFF"); @@ -2914,6 +2925,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) dev->hw_features |= NETIF_F_RXFCS; + if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_IGNORE_FCS) + dev->hw_features |= NETIF_F_RXALL; + if (mdev->dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED && mdev->dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC) diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 6317844b291f..b9881fc1252f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -151,6 +151,7 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [25] = "Granular QoS per VF support", [26] = "Port ETS Scheduler support", [27] = "Port beacon support", + [28] = "RX-ALL support", }; int i; @@ -893,6 +894,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) MLX4_GET(field, outbox, QUERY_DEV_CAP_CONFIG_DEV_OFFSET); if (field & 0x20) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV; + if (field & (1 << 2)) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_IGNORE_FCS; MLX4_GET(dev_cap->reserved_lkey, outbox, QUERY_DEV_CAP_RSVD_LKEY_OFFSET); MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET); @@ -1220,6 +1223,11 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave, field &= 0xef; MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE); + /* turn off ignore FCS feature for guests */ + MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CONFIG_DEV_OFFSET); + field &= 0xfb; + MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CONFIG_DEV_OFFSET); + return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 3becad37aec8..acceb75e8c44 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -297,6 +297,25 @@ static int mlx4_dev_port(struct mlx4_dev *dev, int port, return err; } +static inline void mlx4_enable_ignore_fcs(struct mlx4_dev *dev) +{ + if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_IGNORE_FCS)) + return; + + if (mlx4_is_mfunc(dev)) { + mlx4_dbg(dev, "SRIOV mode - Disabling Ignore FCS"); + dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_IGNORE_FCS; + return; + } + + if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP)) { + mlx4_dbg(dev, + "Keep FCS is not supported - Disabling Ignore FCS"); + dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_IGNORE_FCS; + return; + } +} + #define MLX4_A0_STEERING_TABLE_SIZE 256 static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) { @@ -540,6 +559,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.alloc_res_qp_mask = 0; } + mlx4_enable_ignore_fcs(dev); + return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 32469c64d580..f30eeb730a86 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -763,9 +763,11 @@ enum { struct mlx4_set_port_general_context { - u8 reserved[3]; + u16 reserved1; + u8 v_ignore_fcs; u8 flags; - u16 reserved2; + u8 ignore_fcs; + u8 reserved2; __be16 mtu; u8 pptx; u8 pfctx; diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index e8d716dfd5cb..c2b21313dba7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -45,6 +45,14 @@ #define MLX4_VLAN_VALID (1u << 31) #define MLX4_VLAN_MASK 0xfff +#define MLX4_STATS_TRAFFIC_COUNTERS_MASK 0xfULL +#define MLX4_STATS_TRAFFIC_DROPS_MASK 0xc0ULL +#define MLX4_STATS_ERROR_COUNTERS_MASK 0x1ffc30ULL +#define MLX4_STATS_PORT_COUNTERS_MASK 0x1fe00000ULL + +#define MLX4_FLAG_V_IGNORE_FCS_MASK 0x2 +#define MLX4_IGNORE_FCS_MASK 0x1 + void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) { int i; @@ -1027,6 +1035,32 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, } EXPORT_SYMBOL(mlx4_SET_PORT_qpn_calc); +int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_port_general_context *context; + u32 in_mod; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + context = mailbox->buf; + context->v_ignore_fcs |= MLX4_FLAG_V_IGNORE_FCS_MASK; + if (ignore_fcs_value) + context->ignore_fcs |= MLX4_IGNORE_FCS_MASK; + else + context->ignore_fcs &= ~MLX4_IGNORE_FCS_MASK; + + in_mod = MLX4_SET_PORT_GENERAL << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL(mlx4_SET_PORT_fcs_check); + enum { VXLAN_ENABLE_MODIFY = 1 << 7, VXLAN_STEERING_MODIFY = 1 << 6, diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index b761be7c88c8..f9ce34bec45b 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -209,6 +209,7 @@ enum { MLX4_DEV_CAP_FLAG2_QOS_VPP = 1LL << 25, MLX4_DEV_CAP_FLAG2_ETS_CFG = 1LL << 26, MLX4_DEV_CAP_FLAG2_PORT_BEACON = 1LL << 27, + MLX4_DEV_CAP_FLAG2_IGNORE_FCS = 1LL << 28, }; enum { @@ -1313,6 +1314,8 @@ int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, u8 promisc); int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time); +int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, + u8 ignore_fcs_value); int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable); int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx); int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); From db60304718583f99162adabb7dd96e2f7073f8f3 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 2 Apr 2015 16:31:23 +0300 Subject: [PATCH 476/567] MAINTAINERS: Update mlx4_en entry Add Ido Shamay as co-maintainer for the mlx4 Ethernet driver. Signed-off-by: Amir Vadai Signed-off-by: Or Gerlitz Signed-off-by: David S. Miller --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0f0e582e98f7..7f2eb47f5246 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6323,6 +6323,7 @@ F: drivers/scsi/megaraid/ MELLANOX ETHERNET DRIVER (mlx4_en) M: Amir Vadai +M: Ido Shamay L: netdev@vger.kernel.org S: Supported W: http://www.mellanox.com From 2da7142516527a5213588f47ed302e79a5d9527a Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 2 Apr 2015 09:33:00 -0400 Subject: [PATCH 477/567] tipc: drop tunneled packet duplicates at reception In commit 8b4ed8634f8b3f9aacfc42b4a872d30c36b9e255 ("tipc: eliminate race condition at dual link establishment") we introduced a parallel link synchronization mechanism that guarentees sequential delivery even for users switching from an old to a newly established link. The new mechanism makes it unnecessary to deliver the tunneled duplicate packets back to the old link, as we are currently doing. It is now sufficient to use the last tunneled packet's inner sequence number as synchronization point between the two parallel links, whereafter it can be dropped. In this commit, we drop the duplicate packets arriving on the new link, after updating the synchronization point at each new arrival. Although it would now have been sufficient for the other endpoint to only tunnel the last packet in its send queue, and not the entire queue, we must still do this to maintain compatibility with older nodes. This commit makes it possible to get rid if some complex interaction between the two parallel links. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 134 +++++++++++++++++------------------------------- 1 file changed, 48 insertions(+), 86 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 514466efc25c..c697cf69da91 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -105,8 +105,6 @@ static void link_handle_out_of_seq_msg(struct tipc_link *link, struct sk_buff *skb); static void tipc_link_proto_rcv(struct tipc_link *link, struct sk_buff *skb); -static int tipc_link_tunnel_rcv(struct tipc_node *node, - struct sk_buff **skb); static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol); static void link_state_event(struct tipc_link *l_ptr, u32 event); static void link_reset_statistics(struct tipc_link *l_ptr); @@ -115,7 +113,8 @@ static void tipc_link_sync_xmit(struct tipc_link *l); static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); static void tipc_link_input(struct tipc_link *l, struct sk_buff *skb); static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb); - +static bool tipc_link_failover_rcv(struct tipc_node *node, + struct sk_buff **skb); /* * Simple link routines */ @@ -1274,8 +1273,10 @@ static void tipc_link_input(struct tipc_link *link, struct sk_buff *skb) if (msg_dup(msg)) { link->flags |= LINK_SYNCHING; link->synch_point = msg_seqno(msg_get_wrapped(msg)); + kfree_skb(skb); + break; } - if (!tipc_link_tunnel_rcv(node, &skb)) + if (!tipc_link_failover_rcv(node, &skb)) break; if (msg_user(buf_msg(skb)) != MSG_BUNDLER) { tipc_data_input(link, skb); @@ -1755,101 +1756,62 @@ tunnel_queue: goto tunnel_queue; } -/* tipc_link_dup_rcv(): Receive a tunnelled DUPLICATE_MSG packet. - * Owner node is locked. - */ -static void tipc_link_dup_rcv(struct tipc_link *link, - struct sk_buff *skb) -{ - struct sk_buff *iskb; - int pos = 0; - - if (!tipc_link_is_up(link)) - return; - - if (!tipc_msg_extract(skb, &iskb, &pos)) { - pr_warn("%sfailed to extract inner dup pkt\n", link_co_err); - return; - } - /* Append buffer to deferred queue, if applicable: */ - link_handle_out_of_seq_msg(link, iskb); -} - /* tipc_link_failover_rcv(): Receive a tunnelled ORIGINAL_MSG packet * Owner node is locked. */ -static struct sk_buff *tipc_link_failover_rcv(struct tipc_link *l_ptr, - struct sk_buff *t_buf) +static bool tipc_link_failover_rcv(struct tipc_node *node, + struct sk_buff **skb) { - struct tipc_msg *t_msg = buf_msg(t_buf); - struct sk_buff *buf = NULL; - struct tipc_msg *msg; + struct tipc_msg *msg = buf_msg(*skb); + struct sk_buff *iskb = NULL; + struct tipc_link *link = NULL; + int bearer_id = msg_bearer_id(msg); int pos = 0; - if (tipc_link_is_up(l_ptr)) - tipc_link_reset(l_ptr); - - /* First failover packet? */ - if (l_ptr->exp_msg_count == START_CHANGEOVER) - l_ptr->exp_msg_count = msg_msgcnt(t_msg); - - /* Should there be an inner packet? */ - if (l_ptr->exp_msg_count) { - l_ptr->exp_msg_count--; - if (!tipc_msg_extract(t_buf, &buf, &pos)) { - pr_warn("%sno inner failover pkt\n", link_co_err); - goto exit; - } - msg = buf_msg(buf); - - if (less(msg_seqno(msg), l_ptr->reset_checkpoint)) { - kfree_skb(buf); - buf = NULL; - goto exit; - } - if (msg_user(msg) == MSG_FRAGMENTER) { - l_ptr->stats.recv_fragments++; - tipc_buf_append(&l_ptr->reasm_buf, &buf); - } + if (msg_type(msg) != ORIGINAL_MSG) { + pr_warn("%sunknown tunnel pkt received\n", link_co_err); + goto exit; } -exit: - if ((!l_ptr->exp_msg_count) && (l_ptr->flags & LINK_STOPPED)) - tipc_link_delete(l_ptr); - return buf; -} - -/* tipc_link_tunnel_rcv(): Receive a tunnelled packet, sent - * via other link as result of a failover (ORIGINAL_MSG) or - * a new active link (DUPLICATE_MSG). Failover packets are - * returned to the active link for delivery upwards. - * Owner node is locked. - */ -static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr, - struct sk_buff **buf) -{ - struct sk_buff *t_buf = *buf; - struct tipc_link *l_ptr; - struct tipc_msg *t_msg = buf_msg(t_buf); - u32 bearer_id = msg_bearer_id(t_msg); - - *buf = NULL; - if (bearer_id >= MAX_BEARERS) goto exit; + link = node->links[bearer_id]; + if (!link) + goto exit; + if (tipc_link_is_up(link)) + tipc_link_reset(link); - l_ptr = n_ptr->links[bearer_id]; - if (!l_ptr) + /* First failover packet? */ + if (link->exp_msg_count == START_CHANGEOVER) + link->exp_msg_count = msg_msgcnt(msg); + + /* Should we expect an inner packet? */ + if (!link->exp_msg_count) goto exit; - if (msg_type(t_msg) == DUPLICATE_MSG) - tipc_link_dup_rcv(l_ptr, t_buf); - else if (msg_type(t_msg) == ORIGINAL_MSG) - *buf = tipc_link_failover_rcv(l_ptr, t_buf); - else - pr_warn("%sunknown tunnel pkt received\n", link_co_err); + if (!tipc_msg_extract(*skb, &iskb, &pos)) { + pr_warn("%sno inner failover pkt\n", link_co_err); + *skb = NULL; + goto exit; + } + link->exp_msg_count--; + *skb = NULL; + + /* Was packet already delivered? */ + if (less(buf_seqno(iskb), link->reset_checkpoint)) { + kfree_skb(iskb); + iskb = NULL; + goto exit; + } + if (msg_user(buf_msg(iskb)) == MSG_FRAGMENTER) { + link->stats.recv_fragments++; + tipc_buf_append(&link->reasm_buf, &iskb); + } exit: - kfree_skb(t_buf); - return *buf != NULL; + if (link && (!link->exp_msg_count) && (link->flags & LINK_STOPPED)) + tipc_link_delete(link); + kfree_skb(*skb); + *skb = iskb; + return *skb; } static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol) From dff29b1a88524fe6afe296d6c477c491d1e02af0 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 2 Apr 2015 09:33:01 -0400 Subject: [PATCH 478/567] tipc: eliminate delayed link deletion at link failover When a bearer is disabled manually, all its links have to be reset and deleted. However, if there is a remaining, parallel link ready to take over a deleted link's traffic, we currently delay the delete of the removed link until the failover procedure is finished. This is because the remaining link needs to access state from the reset link, such as the last received packet number, and any partially reassembled buffer, in order to perform a successful failover. In this commit, we do instead move the state data over to the new link, so that it can fulfill the procedure autonomously, without accessing any data on the old link. This means that we can now proceed and delete all pertaining links immediately when a bearer is disabled. This saves us from some unnecessary complexity in such situations. We also choose to change the confusing definitions CHANGEOVER_PROTOCOL, ORIGINAL_MSG and DUPLICATE_MSG to the more descriptive TUNNEL_PROTOCOL, FAILOVER_MSG and SYNCH_MSG respectively. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 126 ++++++++++++++++++++++-------------------------- net/tipc/link.h | 17 ++++--- net/tipc/msg.c | 4 +- net/tipc/msg.h | 10 ++-- net/tipc/node.c | 13 +++-- 5 files changed, 79 insertions(+), 91 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index c697cf69da91..b1e17953eeea 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -89,17 +89,9 @@ static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { #define TIMEOUT_EVT 560817u /* link timer expired */ /* - * The following two 'message types' is really just implementation - * data conveniently stored in the message header. - * They must not be considered part of the protocol + * State value stored in 'failover_pkts' */ -#define OPEN_MSG 0 -#define CLOSED_MSG 1 - -/* - * State value stored in 'exp_msg_count' - */ -#define START_CHANGEOVER 100000u +#define FIRST_FAILOVER 0xffffu static void link_handle_out_of_seq_msg(struct tipc_link *link, struct sk_buff *skb); @@ -113,8 +105,7 @@ static void tipc_link_sync_xmit(struct tipc_link *l); static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); static void tipc_link_input(struct tipc_link *l, struct sk_buff *skb); static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb); -static bool tipc_link_failover_rcv(struct tipc_node *node, - struct sk_buff **skb); +static bool tipc_link_failover_rcv(struct tipc_link *l, struct sk_buff **skb); /* * Simple link routines */ @@ -332,15 +323,19 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, } /** - * link_delete - Conditional deletion of link. - * If timer still running, real delete is done when it expires - * @link: link to be deleted + * tipc_link_delete - Delete a link + * @l: link to be deleted */ -void tipc_link_delete(struct tipc_link *link) +void tipc_link_delete(struct tipc_link *l) { - tipc_link_reset_fragments(link); - tipc_node_detach_link(link->owner, link); - tipc_link_put(link); + tipc_link_reset(l); + if (del_timer(&l->timer)) + tipc_link_put(l); + l->flags |= LINK_STOPPED; + /* Delete link now, or when timer is finished: */ + tipc_link_reset_fragments(l); + tipc_node_detach_link(l->owner, l); + tipc_link_put(l); } void tipc_link_delete_list(struct net *net, unsigned int bearer_id, @@ -349,23 +344,12 @@ void tipc_link_delete_list(struct net *net, unsigned int bearer_id, struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_link *link; struct tipc_node *node; - bool del_link; rcu_read_lock(); list_for_each_entry_rcu(node, &tn->node_list, list) { tipc_node_lock(node); link = node->links[bearer_id]; - if (!link) { - tipc_node_unlock(node); - continue; - } - del_link = !tipc_link_is_up(link) && !link->exp_msg_count; - tipc_link_reset(link); - if (del_timer(&link->timer)) - tipc_link_put(link); - link->flags |= LINK_STOPPED; - /* Delete link now, or when failover is finished: */ - if (shutting_down || !tipc_node_is_up(node) || del_link) + if (link) tipc_link_delete(link); tipc_node_unlock(node); } @@ -472,9 +456,9 @@ void tipc_link_purge_queues(struct tipc_link *l_ptr) void tipc_link_reset(struct tipc_link *l_ptr) { u32 prev_state = l_ptr->state; - u32 checkpoint = l_ptr->next_in_no; int was_active_link = tipc_link_is_active(l_ptr); struct tipc_node *owner = l_ptr->owner; + struct tipc_link *pl = tipc_parallel_link(l_ptr); msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff)); @@ -492,11 +476,15 @@ void tipc_link_reset(struct tipc_link *l_ptr) tipc_node_link_down(l_ptr->owner, l_ptr); tipc_bearer_remove_dest(owner->net, l_ptr->bearer_id, l_ptr->addr); - if (was_active_link && tipc_node_active_links(l_ptr->owner)) { - l_ptr->reset_checkpoint = checkpoint; - l_ptr->exp_msg_count = START_CHANGEOVER; + if (was_active_link && tipc_node_is_up(l_ptr->owner) && (pl != l_ptr)) { + l_ptr->flags |= LINK_FAILINGOVER; + l_ptr->failover_checkpt = l_ptr->next_in_no; + pl->failover_pkts = FIRST_FAILOVER; + pl->failover_checkpt = l_ptr->next_in_no; + pl->failover_skb = l_ptr->reasm_buf; + } else { + kfree_skb(l_ptr->reasm_buf); } - /* Clean up all queues, except inputq: */ __skb_queue_purge(&l_ptr->transmq); __skb_queue_purge(&l_ptr->deferdq); @@ -506,6 +494,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) if (!skb_queue_empty(owner->inputq)) owner->action_flags |= TIPC_MSG_EVT; tipc_link_purge_backlog(l_ptr); + l_ptr->reasm_buf = NULL; l_ptr->rcv_unacked = 0; l_ptr->checkpoint = 1; l_ptr->next_out_no = 1; @@ -557,8 +546,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) if (!(l_ptr->flags & LINK_STARTED) && (event != STARTING_EVT)) return; /* Not yet. */ - /* Check whether changeover is going on */ - if (l_ptr->exp_msg_count) { + if (l_ptr->flags & LINK_FAILINGOVER) { if (event == TIMEOUT_EVT) link_set_timer(l_ptr, cont_intv); return; @@ -1242,7 +1230,7 @@ static bool tipc_data_input(struct tipc_link *link, struct sk_buff *skb) node->action_flags |= TIPC_NAMED_MSG_EVT; return true; case MSG_BUNDLER: - case CHANGEOVER_PROTOCOL: + case TUNNEL_PROTOCOL: case MSG_FRAGMENTER: case BCAST_PROTOCOL: return false; @@ -1269,14 +1257,14 @@ static void tipc_link_input(struct tipc_link *link, struct sk_buff *skb) return; switch (msg_user(msg)) { - case CHANGEOVER_PROTOCOL: + case TUNNEL_PROTOCOL: if (msg_dup(msg)) { link->flags |= LINK_SYNCHING; link->synch_point = msg_seqno(msg_get_wrapped(msg)); kfree_skb(skb); break; } - if (!tipc_link_failover_rcv(node, &skb)) + if (!tipc_link_failover_rcv(link, &skb)) break; if (msg_user(buf_msg(skb)) != MSG_BUNDLER) { tipc_data_input(link, skb); @@ -1391,8 +1379,8 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, u32 msg_size = sizeof(l_ptr->proto_msg); int r_flag; - /* Don't send protocol message during link changeover */ - if (l_ptr->exp_msg_count) + /* Don't send protocol message during link failover */ + if (l_ptr->flags & LINK_FAILINGOVER) return; /* Abort non-RESET send if communication with node is prohibited */ @@ -1444,7 +1432,7 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, } l_ptr->stats.sent_states++; } else { /* RESET_MSG or ACTIVATE_MSG */ - msg_set_ack(msg, mod(l_ptr->reset_checkpoint - 1)); + msg_set_ack(msg, mod(l_ptr->failover_checkpt - 1)); msg_set_seq_gap(msg, 0); msg_set_next_sent(msg, 1); msg_set_probe(msg, 0); @@ -1486,8 +1474,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, u32 msg_tol; struct tipc_msg *msg = buf_msg(buf); - /* Discard protocol message during link changeover */ - if (l_ptr->exp_msg_count) + if (l_ptr->flags & LINK_FAILINGOVER) goto exit; if (l_ptr->net_plane != msg_net_plane(msg)) @@ -1659,8 +1646,8 @@ void tipc_link_failover_send_queue(struct tipc_link *l_ptr) if (!tunnel) return; - tipc_msg_init(link_own_addr(l_ptr), &tunnel_hdr, CHANGEOVER_PROTOCOL, - ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); + tipc_msg_init(link_own_addr(l_ptr), &tunnel_hdr, TUNNEL_PROTOCOL, + FAILOVER_MSG, INT_H_SIZE, l_ptr->addr); skb_queue_splice_tail_init(&l_ptr->backlogq, &l_ptr->transmq); tipc_link_purge_backlog(l_ptr); msgcount = skb_queue_len(&l_ptr->transmq); @@ -1722,8 +1709,8 @@ void tipc_link_dup_queue_xmit(struct tipc_link *link, struct sk_buff_head *queue = &link->transmq; int mcnt; - tipc_msg_init(link_own_addr(link), &tnl_hdr, CHANGEOVER_PROTOCOL, - DUPLICATE_MSG, INT_H_SIZE, link->addr); + tipc_msg_init(link_own_addr(link), &tnl_hdr, TUNNEL_PROTOCOL, + SYNCH_MSG, INT_H_SIZE, link->addr); mcnt = skb_queue_len(&link->transmq) + skb_queue_len(&link->backlogq); msg_set_msgcnt(&tnl_hdr, mcnt); msg_set_bearer_id(&tnl_hdr, link->peer_bearer_id); @@ -1756,36 +1743,37 @@ tunnel_queue: goto tunnel_queue; } -/* tipc_link_failover_rcv(): Receive a tunnelled ORIGINAL_MSG packet +/* tipc_link_failover_rcv(): Receive a tunnelled FAILOVER_MSG packet * Owner node is locked. */ -static bool tipc_link_failover_rcv(struct tipc_node *node, +static bool tipc_link_failover_rcv(struct tipc_link *link, struct sk_buff **skb) { struct tipc_msg *msg = buf_msg(*skb); struct sk_buff *iskb = NULL; - struct tipc_link *link = NULL; + struct tipc_link *pl = NULL; int bearer_id = msg_bearer_id(msg); int pos = 0; - if (msg_type(msg) != ORIGINAL_MSG) { + if (msg_type(msg) != FAILOVER_MSG) { pr_warn("%sunknown tunnel pkt received\n", link_co_err); goto exit; } if (bearer_id >= MAX_BEARERS) goto exit; - link = node->links[bearer_id]; - if (!link) - goto exit; - if (tipc_link_is_up(link)) - tipc_link_reset(link); - /* First failover packet? */ - if (link->exp_msg_count == START_CHANGEOVER) - link->exp_msg_count = msg_msgcnt(msg); + if (bearer_id == link->bearer_id) + goto exit; + + pl = link->owner->links[bearer_id]; + if (pl && tipc_link_is_up(pl)) + tipc_link_reset(pl); + + if (link->failover_pkts == FIRST_FAILOVER) + link->failover_pkts = msg_msgcnt(msg); /* Should we expect an inner packet? */ - if (!link->exp_msg_count) + if (!link->failover_pkts) goto exit; if (!tipc_msg_extract(*skb, &iskb, &pos)) { @@ -1793,22 +1781,22 @@ static bool tipc_link_failover_rcv(struct tipc_node *node, *skb = NULL; goto exit; } - link->exp_msg_count--; + link->failover_pkts--; *skb = NULL; - /* Was packet already delivered? */ - if (less(buf_seqno(iskb), link->reset_checkpoint)) { + /* Was this packet already delivered? */ + if (less(buf_seqno(iskb), link->failover_checkpt)) { kfree_skb(iskb); iskb = NULL; goto exit; } if (msg_user(buf_msg(iskb)) == MSG_FRAGMENTER) { link->stats.recv_fragments++; - tipc_buf_append(&link->reasm_buf, &iskb); + tipc_buf_append(&link->failover_skb, &iskb); } exit: - if (link && (!link->exp_msg_count) && (link->flags & LINK_STOPPED)) - tipc_link_delete(link); + if (!link->failover_pkts && pl) + pl->flags &= ~LINK_FAILINGOVER; kfree_skb(*skb); *skb = iskb; return *skb; diff --git a/net/tipc/link.h b/net/tipc/link.h index d2b5663643da..6e28f03c7905 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -58,9 +58,10 @@ /* Link endpoint execution states */ -#define LINK_STARTED 0x0001 -#define LINK_STOPPED 0x0002 -#define LINK_SYNCHING 0x0004 +#define LINK_STARTED 0x0001 +#define LINK_STOPPED 0x0002 +#define LINK_SYNCHING 0x0004 +#define LINK_FAILINGOVER 0x0008 /* Starting value for maximum packet size negotiation on unicast links * (unless bearer MTU is less) @@ -167,11 +168,12 @@ struct tipc_link { struct tipc_msg *pmsg; u32 priority; char net_plane; + u16 synch_point; - /* Changeover */ - u32 exp_msg_count; - u32 reset_checkpoint; - u32 synch_point; + /* Failover */ + u16 failover_pkts; + u16 failover_checkpt; + struct sk_buff *failover_skb; /* Max packet negotiation */ u32 max_pkt; @@ -201,7 +203,6 @@ struct tipc_link { struct sk_buff_head wakeupq; /* Fragmentation/reassembly */ - u32 long_msg_seq_no; struct sk_buff *reasm_buf; /* Statistics */ diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 3bb499c61918..c3e96e815418 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -355,7 +355,7 @@ bool tipc_msg_bundle(struct sk_buff *bskb, struct sk_buff *skb, u32 mtu) start = align(bsz); pad = start - bsz; - if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL)) + if (unlikely(msg_user(msg) == TUNNEL_PROTOCOL)) return false; if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) return false; @@ -433,7 +433,7 @@ bool tipc_msg_make_bundle(struct sk_buff **skb, u32 mtu, u32 dnode) if (msg_user(msg) == MSG_FRAGMENTER) return false; - if (msg_user(msg) == CHANGEOVER_PROTOCOL) + if (msg_user(msg) == TUNNEL_PROTOCOL) return false; if (msg_user(msg) == BCAST_PROTOCOL) return false; diff --git a/net/tipc/msg.h b/net/tipc/msg.h index d273207ede28..e1d3595e2ee9 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -72,7 +72,7 @@ struct plist; #define MSG_BUNDLER 6 #define LINK_PROTOCOL 7 #define CONN_MANAGER 8 -#define CHANGEOVER_PROTOCOL 10 +#define TUNNEL_PROTOCOL 10 #define NAME_DISTRIBUTOR 11 #define MSG_FRAGMENTER 12 #define LINK_CONFIG 13 @@ -512,8 +512,8 @@ static inline void msg_set_nameupper(struct tipc_msg *m, u32 n) /* * Changeover tunnel message types */ -#define DUPLICATE_MSG 0 -#define ORIGINAL_MSG 1 +#define SYNCH_MSG 0 +#define FAILOVER_MSG 1 /* * Config protocol message types @@ -556,9 +556,9 @@ static inline void msg_set_node_capabilities(struct tipc_msg *m, u32 n) static inline bool msg_dup(struct tipc_msg *m) { - if (likely(msg_user(m) != CHANGEOVER_PROTOCOL)) + if (likely(msg_user(m) != TUNNEL_PROTOCOL)) return false; - if (msg_type(m) != DUPLICATE_MSG) + if (msg_type(m) != SYNCH_MSG) return false; return true; } diff --git a/net/tipc/node.c b/net/tipc/node.c index 3e4f04897c03..f3d522c2881a 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -394,18 +394,17 @@ static void node_lost_contact(struct tipc_node *n_ptr) n_ptr->bclink.recv_permitted = false; } - /* Abort link changeover */ + /* Abort any ongoing link failover */ for (i = 0; i < MAX_BEARERS; i++) { struct tipc_link *l_ptr = n_ptr->links[i]; if (!l_ptr) continue; - l_ptr->reset_checkpoint = l_ptr->next_in_no; - l_ptr->exp_msg_count = 0; + l_ptr->flags &= ~LINK_FAILINGOVER; + l_ptr->failover_checkpt = 0; + l_ptr->failover_pkts = 0; + kfree_skb(l_ptr->failover_skb); + l_ptr->failover_skb = NULL; tipc_link_reset_fragments(l_ptr); - - /* Link marked for deletion after failover? => do it now */ - if (l_ptr->flags & LINK_STOPPED) - tipc_link_delete(l_ptr); } n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN; From ed193ece2649c194a87a9d8470195760d367c075 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 2 Apr 2015 09:33:02 -0400 Subject: [PATCH 479/567] tipc: simplify link mtu negotiation When a link is being established, the two endpoints advertise their respective interface MTU in the transmitted RESET and ACTIVATE messages. If there is any difference, the lower of the two MTUs will be selected for use by both endpoints. However, as a remnant of earlier attempts to introduce TIPC level routing. there also exists an MTU discovery mechanism. If an intermediate node has a lower MTU than the two endpoints, they will discover this through a bisectional approach, and finally adopt this MTU for common use. Since there is no TIPC level routing, and probably never will be, this mechanism doesn't make any sense, and only serves to make the link level protocol unecessarily complex. In this commit, we eliminate the MTU discovery algorithm,and fall back to the simple MTU advertising approach. This change is fully backwards compatible. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bcast.c | 4 +- net/tipc/link.c | 129 ++++++++++++----------------------------------- net/tipc/link.h | 12 ++--- net/tipc/node.c | 9 ++-- 4 files changed, 43 insertions(+), 111 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index ae558dd7f8ee..c5cbdcb1f0b5 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -413,7 +413,7 @@ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno) */ if (((seqno - tn->own_addr) % TIPC_MIN_LINK_WIN) == 0) { tipc_link_proto_xmit(node->active_links[node->addr & 1], - STATE_MSG, 0, 0, 0, 0, 0); + STATE_MSG, 0, 0, 0, 0); tn->bcl->stats.sent_acks++; } } @@ -899,7 +899,7 @@ int tipc_bclink_init(struct net *net) skb_queue_head_init(&bclink->inputq); bcl->owner = &bclink->node; bcl->owner->net = net; - bcl->max_pkt = MAX_PKT_DEFAULT_MCAST; + bcl->mtu = MAX_PKT_DEFAULT_MCAST; tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT); bcl->bearer_id = MAX_BEARERS; rcu_assign_pointer(tn->bearer_list[MAX_BEARERS], &bcbearer->bearer); diff --git a/net/tipc/link.c b/net/tipc/link.c index b1e17953eeea..a6b30df6ec02 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -136,34 +136,6 @@ static struct tipc_link *tipc_parallel_link(struct tipc_link *l) return l->owner->active_links[1]; } -static void link_init_max_pkt(struct tipc_link *l_ptr) -{ - struct tipc_node *node = l_ptr->owner; - struct tipc_net *tn = net_generic(node->net, tipc_net_id); - struct tipc_bearer *b_ptr; - u32 max_pkt; - - rcu_read_lock(); - b_ptr = rcu_dereference_rtnl(tn->bearer_list[l_ptr->bearer_id]); - if (!b_ptr) { - rcu_read_unlock(); - return; - } - max_pkt = (b_ptr->mtu & ~3); - rcu_read_unlock(); - - if (max_pkt > MAX_MSG_SIZE) - max_pkt = MAX_MSG_SIZE; - - l_ptr->max_pkt_target = max_pkt; - if (l_ptr->max_pkt_target < MAX_PKT_DEFAULT) - l_ptr->max_pkt = l_ptr->max_pkt_target; - else - l_ptr->max_pkt = MAX_PKT_DEFAULT; - - l_ptr->max_pkt_probes = 0; -} - /* * Simple non-static link routines (i.e. referenced outside this file) */ @@ -304,7 +276,8 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, msg_set_bearer_id(msg, b_ptr->identity); strcpy((char *)msg_data(msg), if_name); l_ptr->net_plane = b_ptr->net_plane; - link_init_max_pkt(l_ptr); + l_ptr->advertised_mtu = b_ptr->mtu; + l_ptr->mtu = l_ptr->advertised_mtu; l_ptr->priority = b_ptr->priority; tipc_link_set_queue_limits(l_ptr, b_ptr->window); l_ptr->next_out_no = 1; @@ -465,8 +438,8 @@ void tipc_link_reset(struct tipc_link *l_ptr) /* Link is down, accept any session */ l_ptr->peer_session = INVALID_SESSION; - /* Prepare for max packet size negotiation */ - link_init_max_pkt(l_ptr); + /* Prepare for renewed mtu size negotiation */ + l_ptr->mtu = l_ptr->advertised_mtu; l_ptr->state = RESET_UNKNOWN; @@ -563,11 +536,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) l_ptr->checkpoint = l_ptr->next_in_no; if (tipc_bclink_acks_missing(l_ptr->owner)) { tipc_link_proto_xmit(l_ptr, STATE_MSG, - 0, 0, 0, 0, 0); - l_ptr->fsm_msg_cnt++; - } else if (l_ptr->max_pkt < l_ptr->max_pkt_target) { - tipc_link_proto_xmit(l_ptr, STATE_MSG, - 1, 0, 0, 0, 0); + 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; } link_set_timer(l_ptr, cont_intv); @@ -575,7 +544,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) } l_ptr->state = WORKING_UNKNOWN; l_ptr->fsm_msg_cnt = 0; - tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); + tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv / 4); break; @@ -586,7 +555,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) l_ptr->state = RESET_RESET; l_ptr->fsm_msg_cnt = 0; tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG, - 0, 0, 0, 0, 0); + 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; @@ -609,7 +578,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) l_ptr->state = RESET_RESET; l_ptr->fsm_msg_cnt = 0; tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG, - 0, 0, 0, 0, 0); + 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; @@ -620,13 +589,13 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) l_ptr->checkpoint = l_ptr->next_in_no; if (tipc_bclink_acks_missing(l_ptr->owner)) { tipc_link_proto_xmit(l_ptr, STATE_MSG, - 0, 0, 0, 0, 0); + 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; } link_set_timer(l_ptr, cont_intv); } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) { tipc_link_proto_xmit(l_ptr, STATE_MSG, - 1, 0, 0, 0, 0); + 1, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv / 4); } else { /* Link has failed */ @@ -636,7 +605,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) l_ptr->state = RESET_UNKNOWN; l_ptr->fsm_msg_cnt = 0; tipc_link_proto_xmit(l_ptr, RESET_MSG, - 0, 0, 0, 0, 0); + 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); } @@ -656,7 +625,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) l_ptr->state = WORKING_WORKING; l_ptr->fsm_msg_cnt = 0; link_activate(l_ptr); - tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); + tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0); l_ptr->fsm_msg_cnt++; if (l_ptr->owner->working_links == 1) tipc_link_sync_xmit(l_ptr); @@ -666,7 +635,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) l_ptr->state = RESET_RESET; l_ptr->fsm_msg_cnt = 0; tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG, - 1, 0, 0, 0, 0); + 1, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; @@ -676,7 +645,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) link_set_timer(l_ptr, cont_intv); break; case TIMEOUT_EVT: - tipc_link_proto_xmit(l_ptr, RESET_MSG, 0, 0, 0, 0, 0); + tipc_link_proto_xmit(l_ptr, RESET_MSG, 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; @@ -694,7 +663,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) l_ptr->state = WORKING_WORKING; l_ptr->fsm_msg_cnt = 0; link_activate(l_ptr); - tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0, 0); + tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0); l_ptr->fsm_msg_cnt++; if (l_ptr->owner->working_links == 1) tipc_link_sync_xmit(l_ptr); @@ -704,7 +673,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) break; case TIMEOUT_EVT: tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG, - 0, 0, 0, 0, 0); + 0, 0, 0, 0); l_ptr->fsm_msg_cnt++; link_set_timer(l_ptr, cont_intv); break; @@ -733,7 +702,7 @@ int __tipc_link_xmit(struct net *net, struct tipc_link *link, struct tipc_msg *msg = buf_msg(skb_peek(list)); unsigned int maxwin = link->window; unsigned int imp = msg_importance(msg); - uint mtu = link->max_pkt; + uint mtu = link->mtu; uint ack = mod(link->next_in_no - 1); uint seqno = link->next_out_no; uint bc_last_in = link->owner->bclink.last_in; @@ -1187,7 +1156,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr) link_retrieve_defq(l_ptr, &head); if (unlikely(++l_ptr->rcv_unacked >= TIPC_MIN_LINK_WIN)) { l_ptr->stats.sent_acks++; - tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); + tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0); } tipc_link_input(l_ptr, skb); skb = NULL; @@ -1362,7 +1331,7 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, if (tipc_link_defer_pkt(&l_ptr->deferdq, buf)) { l_ptr->stats.deferred_recv++; if ((skb_queue_len(&l_ptr->deferdq) % TIPC_MIN_LINK_WIN) == 1) - tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); + tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0); } else { l_ptr->stats.duplicates++; } @@ -1372,7 +1341,7 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, * Send protocol message to the other endpoint. */ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, - u32 gap, u32 tolerance, u32 priority, u32 ack_mtu) + u32 gap, u32 tolerance, u32 priority) { struct sk_buff *buf = NULL; struct tipc_msg *msg = l_ptr->pmsg; @@ -1410,26 +1379,11 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, l_ptr->stats.sent_nacks++; msg_set_link_tolerance(msg, tolerance); msg_set_linkprio(msg, priority); - msg_set_max_pkt(msg, ack_mtu); + msg_set_max_pkt(msg, l_ptr->mtu); msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); msg_set_probe(msg, probe_msg != 0); - if (probe_msg) { - u32 mtu = l_ptr->max_pkt; - - if ((mtu < l_ptr->max_pkt_target) && - link_working_working(l_ptr) && - l_ptr->fsm_msg_cnt) { - msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3; - if (l_ptr->max_pkt_probes == 10) { - l_ptr->max_pkt_target = (msg_size - 4); - l_ptr->max_pkt_probes = 0; - msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3; - } - l_ptr->max_pkt_probes++; - } - + if (probe_msg) l_ptr->stats.sent_probes++; - } l_ptr->stats.sent_states++; } else { /* RESET_MSG or ACTIVATE_MSG */ msg_set_ack(msg, mod(l_ptr->failover_checkpt - 1)); @@ -1438,7 +1392,7 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, msg_set_probe(msg, 0); msg_set_link_tolerance(msg, l_ptr->tolerance); msg_set_linkprio(msg, l_ptr->priority); - msg_set_max_pkt(msg, l_ptr->max_pkt_target); + msg_set_max_pkt(msg, l_ptr->advertised_mtu); } r_flag = (l_ptr->owner->working_links > tipc_link_is_up(l_ptr)); @@ -1469,8 +1423,6 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf) { u32 rec_gap = 0; - u32 max_pkt_info; - u32 max_pkt_ack; u32 msg_tol; struct tipc_msg *msg = buf_msg(buf); @@ -1513,15 +1465,8 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, if (msg_linkprio(msg) > l_ptr->priority) l_ptr->priority = msg_linkprio(msg); - max_pkt_info = msg_max_pkt(msg); - if (max_pkt_info) { - if (max_pkt_info < l_ptr->max_pkt_target) - l_ptr->max_pkt_target = max_pkt_info; - if (l_ptr->max_pkt > l_ptr->max_pkt_target) - l_ptr->max_pkt = l_ptr->max_pkt_target; - } else { - l_ptr->max_pkt = l_ptr->max_pkt_target; - } + if (l_ptr->mtu > msg_max_pkt(msg)) + l_ptr->mtu = msg_max_pkt(msg); /* Synchronize broadcast link info, if not done previously */ if (!tipc_node_is_up(l_ptr->owner)) { @@ -1566,18 +1511,8 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, mod(l_ptr->next_in_no)); } - max_pkt_ack = msg_max_pkt(msg); - if (max_pkt_ack > l_ptr->max_pkt) { - l_ptr->max_pkt = max_pkt_ack; - l_ptr->max_pkt_probes = 0; - } - - max_pkt_ack = 0; - if (msg_probe(msg)) { + if (msg_probe(msg)) l_ptr->stats.recv_probes++; - if (msg_size(msg) > sizeof(l_ptr->proto_msg)) - max_pkt_ack = msg_size(msg); - } /* Protocol message before retransmits, reduce loss risk */ if (l_ptr->owner->bclink.recv_permitted) @@ -1585,8 +1520,8 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, msg_last_bcast(msg)); if (rec_gap || (msg_probe(msg))) { - tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, rec_gap, 0, - 0, max_pkt_ack); + tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, + rec_gap, 0, 0); } if (msg_seq_gap(msg)) { l_ptr->stats.recv_nacks++; @@ -1816,7 +1751,7 @@ static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol) void tipc_link_set_queue_limits(struct tipc_link *l, u32 win) { - int max_bulk = TIPC_MAX_PUBLICATIONS / (l->max_pkt / ITEM_SIZE); + int max_bulk = TIPC_MAX_PUBLICATIONS / (l->mtu / ITEM_SIZE); l->window = win; l->backlog[TIPC_LOW_IMPORTANCE].limit = win / 2; @@ -1988,14 +1923,14 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info) tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]); link_set_supervision_props(link, tol); - tipc_link_proto_xmit(link, STATE_MSG, 0, 0, tol, 0, 0); + tipc_link_proto_xmit(link, STATE_MSG, 0, 0, tol, 0); } if (props[TIPC_NLA_PROP_PRIO]) { u32 prio; prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); link->priority = prio; - tipc_link_proto_xmit(link, STATE_MSG, 0, 0, 0, prio, 0); + tipc_link_proto_xmit(link, STATE_MSG, 0, 0, 0, prio); } if (props[TIPC_NLA_PROP_WIN]) { u32 win; @@ -2100,7 +2035,7 @@ static int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg, if (nla_put_u32(msg->skb, TIPC_NLA_LINK_DEST, tipc_cluster_mask(tn->own_addr))) goto attr_msg_full; - if (nla_put_u32(msg->skb, TIPC_NLA_LINK_MTU, link->max_pkt)) + if (nla_put_u32(msg->skb, TIPC_NLA_LINK_MTU, link->mtu)) goto attr_msg_full; if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, link->next_in_no)) goto attr_msg_full; diff --git a/net/tipc/link.h b/net/tipc/link.h index 6e28f03c7905..b5b4e3554d4e 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -123,9 +123,8 @@ struct tipc_stats { * @backlog_limit: backlog queue congestion thresholds (indexed by importance) * @exp_msg_count: # of tunnelled messages expected during link changeover * @reset_checkpoint: seq # of last acknowledged message at time of link reset - * @max_pkt: current maximum packet size for this link - * @max_pkt_target: desired maximum packet size for this link - * @max_pkt_probes: # of probes based on current (max_pkt, max_pkt_target) + * @mtu: current maximum packet size for this link + * @advertised_mtu: advertised own mtu when link is being established * @transmitq: queue for sent, non-acked messages * @backlogq: queue for messages waiting to be sent * @next_out_no: next sequence number to use for outbound messages @@ -176,9 +175,8 @@ struct tipc_link { struct sk_buff *failover_skb; /* Max packet negotiation */ - u32 max_pkt; - u32 max_pkt_target; - u32 max_pkt_probes; + u16 mtu; + u16 advertised_mtu; /* Sending */ struct sk_buff_head transmq; @@ -233,7 +231,7 @@ int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dest, int __tipc_link_xmit(struct net *net, struct tipc_link *link, struct sk_buff_head *list); void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, - u32 gap, u32 tolerance, u32 priority, u32 acked_mtu); + u32 gap, u32 tolerance, u32 priority); void tipc_link_push_packets(struct tipc_link *l_ptr); u32 tipc_link_defer_pkt(struct sk_buff_head *list, struct sk_buff *buf); void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window); diff --git a/net/tipc/node.c b/net/tipc/node.c index f3d522c2881a..22c059ad2999 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -254,8 +254,8 @@ void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) active[0] = active[1] = l_ptr; exit: /* Leave room for changeover header when returning 'mtu' to users: */ - n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE; - n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE; + n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE; + n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE; } /** @@ -319,11 +319,10 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) /* Leave room for changeover header when returning 'mtu' to users: */ if (active[0]) { - n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE; - n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE; + n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE; + n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE; return; } - /* Loopback link went down? No fragmentation needed from now on. */ if (n_ptr->addr == tn->own_addr) { n_ptr->act_mtus[0] = MAX_MSG_SIZE; From ad1891062adcdacb5818e104707dca8c193c33d8 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 2 Apr 2015 17:07:19 +0300 Subject: [PATCH 480/567] net/mlx5_core: Allocate firmware pages from device's NUMA node Allocate firmware pages from the NUMA node which is close to the device. Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index 4fdaae9b54d9..cf8591a0c48d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -243,8 +243,9 @@ static int alloc_system_page(struct mlx5_core_dev *dev, u16 func_id) struct page *page; u64 addr; int err; + int nid = dev_to_node(&dev->pdev->dev); - page = alloc_page(GFP_HIGHUSER); + page = alloc_pages_node(nid, GFP_HIGHUSER, 0); if (!page) { mlx5_core_warn(dev, "failed to allocate page\n"); return -ENOMEM; From c3c6c9c810e100ab92c782e855f9ab9991065f4e Mon Sep 17 00:00:00 2001 From: Haggai Abramonvsky Date: Thu, 2 Apr 2015 17:07:20 +0300 Subject: [PATCH 481/567] net/mlx5_core: Fix call to mlx5_core_qp_modify Pass 0 in the sqd_event parameter. Signed-off-by: Haggai Abramovsky Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/qp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index be0cd358b080..2c0f142cd3ba 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1165,7 +1165,7 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) if (qp->state != IB_QPS_RESET) { mlx5_ib_qp_disable_pagefaults(qp); if (mlx5_core_qp_modify(dev->mdev, to_mlx5_state(qp->state), - MLX5_QP_STATE_RST, in, sizeof(*in), &qp->mqp)) + MLX5_QP_STATE_RST, in, 0, &qp->mqp)) mlx5_ib_warn(dev, "mlx5_ib: modify QP %06x to RESET failed\n", qp->mqp.qpn); } From 7bef7ad24b9aa15cb06870f78ba8bd84bb7e1407 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 2 Apr 2015 17:07:21 +0300 Subject: [PATCH 482/567] net/mlx5_core: Coding style fix Put a line of space before return and next statement. Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/qp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 2c0f142cd3ba..859c136911e0 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1162,6 +1162,7 @@ static void destroy_qp_common(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp) in = kzalloc(sizeof(*in), GFP_KERNEL); if (!in) return; + if (qp->state != IB_QPS_RESET) { mlx5_ib_qp_disable_pagefaults(qp); if (mlx5_core_qp_modify(dev->mdev, to_mlx5_state(qp->state), From 9ef9baa2acda077f3831f6e7cdf751bc8691f78f Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 2 Apr 2015 17:07:22 +0300 Subject: [PATCH 483/567] net/mlx5_core: Avoid setting DC requestor/responder resources PRM does not support setting these values so avoid setting them. Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 350c6297fe5d..f29fd5592305 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -288,8 +288,6 @@ static void copy_rw_fields(void *to, struct mlx5_caps *from) MLX5_SET(cmd_hca_cap, to, log_max_ra_req_qp, from->gen.log_max_ra_req_qp); MLX5_SET(cmd_hca_cap, to, log_max_ra_res_qp, from->gen.log_max_ra_res_qp); MLX5_SET(cmd_hca_cap, to, pkey_table_size, from->gen.pkey_table_size); - MLX5_SET(cmd_hca_cap, to, log_max_ra_req_dc, from->gen.log_max_ra_req_dc); - MLX5_SET(cmd_hca_cap, to, log_max_ra_res_dc, from->gen.log_max_ra_res_dc); MLX5_SET(cmd_hca_cap, to, pkey_table_size, to_fw_pkey_sz(from->gen.pkey_table_size)); MLX5_SET(cmd_hca_cap, to, log_uar_page_sz, PAGE_SHIFT - 12); v64 = from->gen.flags & MLX5_CAP_BITS_RW_MASK; From b812b5441e359adb9bd44108f7f91e5b0ba4a768 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 2 Apr 2015 17:07:23 +0300 Subject: [PATCH 484/567] net/mlx5_core: Clear doorbell record inside mlx5_db_alloc() Do it in one place instead of every where the function is invoked Signed-off-by: Achiad Shochat Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/cq.c | 2 -- drivers/infiniband/hw/mlx5/qp.c | 3 --- drivers/infiniband/hw/mlx5/srq.c | 2 -- drivers/net/ethernet/mellanox/mlx5/core/alloc.c | 3 +++ 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index c463e7bba5f4..f78249c48173 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -697,8 +697,6 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, cq->mcq.set_ci_db = cq->db.db; cq->mcq.arm_db = cq->db.db + 1; - *cq->mcq.set_ci_db = 0; - *cq->mcq.arm_db = 0; cq->mcq.cqe_sz = cqe_size; err = alloc_cq_buf(dev, &cq->buf, entries, cqe_size); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 859c136911e0..c2f43d378cb5 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -796,9 +796,6 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, goto err_free; } - qp->db.db[0] = 0; - qp->db.db[1] = 0; - qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wrid), GFP_KERNEL); qp->sq.wr_data = kmalloc(qp->sq.wqe_cnt * sizeof(*qp->sq.wr_data), GFP_KERNEL); qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof(*qp->rq.wrid), GFP_KERNEL); diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 41fec66217dd..90bc9ff62fe7 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -165,8 +165,6 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, return err; } - *srq->db.db = 0; - if (mlx5_buf_alloc(dev->mdev, buf_size, PAGE_SIZE * 2, &srq->buf)) { mlx5_ib_dbg(dev, "buf alloc failed\n"); err = -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index 201ca6d76ce5..63dd75485204 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -171,6 +171,9 @@ static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir, db->db = pgdir->db_page + offset / sizeof(*pgdir->db_page); db->dma = pgdir->db_dma + offset; + db->db[0] = 0; + db->db[1] = 0; + return 0; } From 60722c2ba02be052140998bc80ed77d74e3c03df Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 2 Apr 2015 17:07:24 +0300 Subject: [PATCH 485/567] net/mlx5_core: Use the right inbox struct in destroy mkey command struct mlx5_query_mkey_mbox_in rather than mlx5_destroy_mkey_mbox_in Signed-off-by: Achiad Shochat Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c index 184c3615f479..1a9b75139c2d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c @@ -141,7 +141,7 @@ EXPORT_SYMBOL(mlx5_core_destroy_mkey); int mlx5_core_query_mkey(struct mlx5_core_dev *dev, struct mlx5_core_mr *mr, struct mlx5_query_mkey_mbox_out *out, int outlen) { - struct mlx5_destroy_mkey_mbox_in in; + struct mlx5_query_mkey_mbox_in in; int err; memset(&in, 0, sizeof(in)); From 64599cca51de08cef94bc13a0f98351e5bb01f41 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 2 Apr 2015 17:07:25 +0300 Subject: [PATCH 486/567] net/mlx5_core: Use coherent memory for command interface page Use coherent memory for the commands descriptor page. Take measures to make sure the page is aligned to MLX5_ADAPTER_PAGE_SIZE as required by the hardware. Reported-by: Yevgeny Kliteynik Signed-off-by: Eli Cohen Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 72 +++++++++++++------ include/linux/mlx5/driver.h | 3 + 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index a2853057c779..43a73d36b01d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1319,6 +1319,45 @@ ex_err: return err; } +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); + if (!cmd->cmd_alloc_buf) + return -ENOMEM; + + /* make sure it is aligned to 4K */ + if (!((uintptr_t)cmd->cmd_alloc_buf & (MLX5_ADAPTER_PAGE_SIZE - 1))) { + cmd->cmd_buf = cmd->cmd_alloc_buf; + cmd->dma = cmd->alloc_dma; + cmd->alloc_size = MLX5_ADAPTER_PAGE_SIZE; + return 0; + } + + 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); + if (!cmd->cmd_alloc_buf) + return -ENOMEM; + + cmd->cmd_buf = PTR_ALIGN(cmd->cmd_alloc_buf, MLX5_ADAPTER_PAGE_SIZE); + cmd->dma = ALIGN(cmd->alloc_dma, MLX5_ADAPTER_PAGE_SIZE); + cmd->alloc_size = 2 * MLX5_ADAPTER_PAGE_SIZE - 1; + return 0; +} + +static void free_cmd_page(struct mlx5_core_dev *dev, struct mlx5_cmd *cmd) +{ + struct device *ddev = &dev->pdev->dev; + + dma_free_coherent(ddev, cmd->alloc_size, cmd->cmd_alloc_buf, + cmd->alloc_dma); +} + int mlx5_cmd_init(struct mlx5_core_dev *dev) { int size = sizeof(struct mlx5_cmd_prot_block); @@ -1341,17 +1380,9 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) if (!cmd->pool) return -ENOMEM; - cmd->cmd_buf = (void *)__get_free_pages(GFP_ATOMIC, 0); - if (!cmd->cmd_buf) { - err = -ENOMEM; + err = alloc_cmd_page(dev, cmd); + if (err) goto err_free_pool; - } - cmd->dma = dma_map_single(&dev->pdev->dev, cmd->cmd_buf, PAGE_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(&dev->pdev->dev, cmd->dma)) { - err = -ENOMEM; - goto err_free; - } cmd_l = ioread32be(&dev->iseg->cmdq_addr_l_sz) & 0xff; cmd->log_sz = cmd_l >> 4 & 0xf; @@ -1360,13 +1391,13 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) dev_err(&dev->pdev->dev, "firmware reports too many outstanding commands %d\n", 1 << cmd->log_sz); err = -EINVAL; - goto err_map; + goto err_free_page; } if (cmd->log_sz + cmd->log_stride > MLX5_ADAPTER_PAGE_SHIFT) { dev_err(&dev->pdev->dev, "command queue size overflow\n"); err = -EINVAL; - goto err_map; + goto err_free_page; } cmd->checksum_disabled = 1; @@ -1378,7 +1409,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) dev_err(&dev->pdev->dev, "driver does not support command interface version. driver %d, firmware %d\n", CMD_IF_REV, cmd->cmdif_rev); err = -ENOTSUPP; - goto err_map; + goto err_free_page; } spin_lock_init(&cmd->alloc_lock); @@ -1394,7 +1425,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) if (cmd_l & 0xfff) { dev_err(&dev->pdev->dev, "invalid command queue address\n"); err = -ENOMEM; - goto err_map; + goto err_free_page; } iowrite32be(cmd_h, &dev->iseg->cmdq_addr_h); @@ -1410,7 +1441,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) err = create_msg_cache(dev); if (err) { dev_err(&dev->pdev->dev, "failed to create command cache\n"); - goto err_map; + goto err_free_page; } set_wqname(dev); @@ -1435,11 +1466,8 @@ err_wq: err_cache: destroy_msg_cache(dev); -err_map: - dma_unmap_single(&dev->pdev->dev, cmd->dma, PAGE_SIZE, - DMA_BIDIRECTIONAL); -err_free: - free_pages((unsigned long)cmd->cmd_buf, 0); +err_free_page: + free_cmd_page(dev, cmd); err_free_pool: pci_pool_destroy(cmd->pool); @@ -1455,9 +1483,7 @@ void mlx5_cmd_cleanup(struct mlx5_core_dev *dev) clean_debug_files(dev); destroy_workqueue(cmd->wq); destroy_msg_cache(dev); - dma_unmap_single(&dev->pdev->dev, cmd->dma, PAGE_SIZE, - DMA_BIDIRECTIONAL); - free_pages((unsigned long)cmd->cmd_buf, 0); + free_cmd_page(dev, cmd); pci_pool_destroy(cmd->pool); } EXPORT_SYMBOL(mlx5_cmd_cleanup); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 166d9315fe4b..8d8ca6d9b03b 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -232,6 +232,9 @@ struct mlx5_cmd_stats { }; struct mlx5_cmd { + void *cmd_alloc_buf; + dma_addr_t alloc_dma; + int alloc_size; void *cmd_buf; dma_addr_t dma; u16 cmdif_rev; From 05e4ecd1dc8b085a9010f20dcb5409b25488480a Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 2 Apr 2015 17:07:26 +0300 Subject: [PATCH 487/567] net/mlx5_core: Avoid copying outbox in aysnc command completion Avoid copying to the output buffer in cmd_exec since this is done after the command is completed. Failure to do this may cause cases where the callback handler is called before the copy done by cmd_exec which then overwrites it. Reported-by: Tamer Hleihel Signed-off-by: Eli Cohen Signed-off-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 43a73d36b01d..290ae87fdef7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1236,7 +1236,8 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out, goto out_out; } - err = mlx5_copy_from_msg(out, outb, out_size); + if (!callback) + err = mlx5_copy_from_msg(out, outb, out_size); out_out: if (!callback) From 21db507439ec3a76a9587f2ad50ad3e4d13f4440 Mon Sep 17 00:00:00 2001 From: Ira Gusinsky Date: Thu, 2 Apr 2015 17:07:27 +0300 Subject: [PATCH 488/567] net/mlx5_core: Avoid usage command work entry after writing command doorbell Avoid usage of command work entry in cmd_work_handler since it can be released by mlx5_cmd_invoke before the work handler returns to running. Signed-off-by: Ira Gusinsky Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 290ae87fdef7..0d862696b876 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -515,10 +515,11 @@ static void cmd_work_handler(struct work_struct *work) ent->ts1 = ktime_get_ns(); /* ring doorbell after the descriptor is valid */ + mlx5_core_dbg(dev, "writing 0x%x to command doorbell\n", 1 << ent->idx); wmb(); iowrite32be(1 << ent->idx, &dev->iseg->cmd_dbell); - mlx5_core_dbg(dev, "write 0x%x to command doorbell\n", 1 << ent->idx); mmiowb(); + /* if not in polling don't use ent after this point */ if (cmd->mode == CMD_MODE_POLLING) { poll_timeout(ent); /* make sure we read the descriptor after ownership is SW */ From 4cbdd27c9c3abf87d6fe88cdd749218193ed3e12 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 2 Apr 2015 17:07:28 +0300 Subject: [PATCH 489/567] net/mlx5_core: Fix a bug in alloc_token In alloc_token(), the token '1' would be allocated twice consecutively. Signed-off-by: Achiad Shochat Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 0d862696b876..697d538163f2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -125,7 +125,10 @@ static u8 alloc_token(struct mlx5_cmd *cmd) u8 token; spin_lock(&cmd->token_lock); - token = cmd->token++ % 255 + 1; + cmd->token++; + if (cmd->token == 0) + cmd->token++; + token = cmd->token; spin_unlock(&cmd->token_lock); return token; From 302bdf68fc56a6330bc6b10ce435b4d466417537 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 2 Apr 2015 17:07:29 +0300 Subject: [PATCH 490/567] net/mlx5_core: Fix Mellanox copyright note Signed-off-by: Achiad Shochat Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/alloc.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/cq.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/debugfs.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eq.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/health.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/mad.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/mcg.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/mr.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/pd.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/port.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/qp.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/srq.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/uar.c | 2 +- include/linux/mlx5/cmd.h | 2 +- include/linux/mlx5/cq.h | 2 +- include/linux/mlx5/device.h | 2 +- include/linux/mlx5/doorbell.h | 2 +- include/linux/mlx5/driver.h | 2 +- include/linux/mlx5/mlx5_ifc.h | 2 +- include/linux/mlx5/qp.h | 2 +- include/linux/mlx5/srq.h | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index 63dd75485204..ac0f7bf4be95 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 697d538163f2..e3273faf4568 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c index 43c5f4809526..eb0cf81f5f45 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index 4878025e231c..5210d92e6bc7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index da82991239a8..dbf190d9b9ad 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 06f9036acd83..4b4cda3bcc5f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 3e6670c4a7cd..292d76f2a904 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mad.c b/drivers/net/ethernet/mellanox/mlx5/core/mad.c index fd80ecfa7195..ee1b0b965f34 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mad.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mad.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index f29fd5592305..78dfdab1ead4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mcg.c b/drivers/net/ethernet/mellanox/mlx5/core/mcg.c index 44837640bd7c..d79fd85d1dd5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mcg.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index f0c9f9a7a361..a051b906afdf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mr.c b/drivers/net/ethernet/mellanox/mlx5/core/mr.c index 1a9b75139c2d..1adb300dd850 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/mr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index cf8591a0c48d..df2238372ea7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pd.c b/drivers/net/ethernet/mellanox/mlx5/core/pd.c index 790da5c4ca4f..f2d3aee909e8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index 72c2d002c3b8..49e90f2612d8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 575d853dbe05..dc7dbf7e9d98 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/srq.c b/drivers/net/ethernet/mellanox/mlx5/core/srq.c index 38bce93f8314..f9d25dcd03c1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/srq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/srq.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c index 06801d6f595e..5a89bb1d678a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/include/linux/mlx5/cmd.h b/include/linux/mlx5/cmd.h index 2826a4b6071e..68cd08f02c2f 100644 --- a/include/linux/mlx5/cmd.h +++ b/include/linux/mlx5/cmd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h index f6b17ac601bd..72ee0d732a26 100644 --- a/include/linux/mlx5/cq.h +++ b/include/linux/mlx5/cq.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 4e5bd813bb9a..abf65c790421 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/include/linux/mlx5/doorbell.h b/include/linux/mlx5/doorbell.h index 163a818411e7..afc78a3f4462 100644 --- a/include/linux/mlx5/doorbell.h +++ b/include/linux/mlx5/doorbell.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 8d8ca6d9b03b..8fedd39a9a60 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 5f48b8f592c5..cb3ad17edd1f 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h index 61f7a342d1bf..310b5f7fd6ae 100644 --- a/include/linux/mlx5/qp.h +++ b/include/linux/mlx5/qp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/include/linux/mlx5/srq.h b/include/linux/mlx5/srq.h index e1a363a33663..f43ed054a3e0 100644 --- a/include/linux/mlx5/srq.h +++ b/include/linux/mlx5/srq.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU From 6cf0a15f07a5a4600beb72f3a246fcd9325e86aa Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 2 Apr 2015 17:07:30 +0300 Subject: [PATCH 491/567] IB/mlx5: Fix Mellanox copyright note Signed-off-by: Achiad Shochat Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/ah.c | 2 +- drivers/infiniband/hw/mlx5/cq.c | 2 +- drivers/infiniband/hw/mlx5/doorbell.c | 2 +- drivers/infiniband/hw/mlx5/mad.c | 2 +- drivers/infiniband/hw/mlx5/main.c | 2 +- drivers/infiniband/hw/mlx5/mem.c | 2 +- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 +- drivers/infiniband/hw/mlx5/mr.c | 2 +- drivers/infiniband/hw/mlx5/odp.c | 2 +- drivers/infiniband/hw/mlx5/qp.c | 2 +- drivers/infiniband/hw/mlx5/srq.c | 2 +- drivers/infiniband/hw/mlx5/user.h | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/ah.c b/drivers/infiniband/hw/mlx5/ah.c index 39ab0caefdf9..66080580e24d 100644 --- a/drivers/infiniband/hw/mlx5/ah.c +++ b/drivers/infiniband/hw/mlx5/ah.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index f78249c48173..6efd9f73ff60 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/doorbell.c b/drivers/infiniband/hw/mlx5/doorbell.c index ece028fc47d6..a0e4e6ddb71a 100644 --- a/drivers/infiniband/hw/mlx5/doorbell.c +++ b/drivers/infiniband/hw/mlx5/doorbell.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index 657af9a1167c..9cf9a37bb5ff 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index cc4ac1e583b2..45816b10af5e 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c index 611a9fdf2f38..40df2cca0609 100644 --- a/drivers/infiniband/hw/mlx5/mem.c +++ b/drivers/infiniband/hw/mlx5/mem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 83f22fe297c8..8f94f69fbea5 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index cd9822eeacae..71c593583864 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c index a2c541c4809a..5099db08afd2 100644 --- a/drivers/infiniband/hw/mlx5/odp.c +++ b/drivers/infiniband/hw/mlx5/odp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Mellanox Technologies. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index c2f43d378cb5..4d7024b899cb 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 90bc9ff62fe7..02d77a29764d 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/hw/mlx5/user.h b/drivers/infiniband/hw/mlx5/user.h index d0ba264ac1ed..76fb7b927d37 100644 --- a/drivers/infiniband/hw/mlx5/user.h +++ b/drivers/infiniband/hw/mlx5/user.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Mellanox Technologies inc. All rights reserved. + * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU From 4ae6c18c59f1419202ab5e2a918e551099d88f9f Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 2 Apr 2015 17:07:31 +0300 Subject: [PATCH 492/567] net/mlx5_core: Update module info macros for ConnectX4 Support Declare the support of new ConnectX4 HCA in module info Pump up the module version Signed-off-by: Achiad Shochat Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 78dfdab1ead4..fe41a7c2c629 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -48,11 +48,11 @@ #include "mlx5_core.h" #define DRIVER_NAME "mlx5_core" -#define DRIVER_VERSION "2.2-1" -#define DRIVER_RELDATE "Feb 2014" +#define DRIVER_VERSION "3.0" +#define DRIVER_RELDATE "January 2015" MODULE_AUTHOR("Eli Cohen "); -MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library"); +MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRIVER_VERSION); From 233d05d28ad942929b6b4fbc48aa8dd083c16484 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 2 Apr 2015 17:07:32 +0300 Subject: [PATCH 493/567] net/mlx5_core: Move completion eqs from mlx5_ib to mlx5_core Preparation for ethernet driver. These functions will be used in drivers other than mlx5_ib. Signed-off-by: Achiad Shochat Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/cq.c | 2 +- drivers/infiniband/hw/mlx5/main.c | 104 +----------------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 3 - .../net/ethernet/mellanox/mlx5/core/main.c | 91 +++++++++++++++ include/linux/mlx5/driver.h | 3 +- 5 files changed, 98 insertions(+), 105 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 6efd9f73ff60..c94e2651820d 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -780,7 +780,7 @@ struct ib_cq *mlx5_ib_create_cq(struct ib_device *ibdev, int entries, cq->cqe_size = cqe_size; cqb->ctx.cqe_sz_flags = cqe_sz_to_mlx_sz(cqe_size) << 5; cqb->ctx.log_sz_usr_page = cpu_to_be32((ilog2(entries) << 24) | index); - err = mlx5_vector2eqn(dev, vector, &eqn, &irqn); + err = mlx5_vector2eqn(dev->mdev, vector, &eqn, &irqn); if (err) goto err_cqb; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 45816b10af5e..e59e2a1f8726 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -62,95 +62,6 @@ static char mlx5_version[] = DRIVER_NAME ": Mellanox Connect-IB Infiniband driver v" DRIVER_VERSION " (" DRIVER_RELDATE ")\n"; -int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn) -{ - struct mlx5_eq_table *table = &dev->mdev->priv.eq_table; - struct mlx5_eq *eq, *n; - int err = -ENOENT; - - spin_lock(&table->lock); - list_for_each_entry_safe(eq, n, &dev->eqs_list, list) { - if (eq->index == vector) { - *eqn = eq->eqn; - *irqn = eq->irqn; - err = 0; - break; - } - } - spin_unlock(&table->lock); - - return err; -} - -static int alloc_comp_eqs(struct mlx5_ib_dev *dev) -{ - struct mlx5_eq_table *table = &dev->mdev->priv.eq_table; - char name[MLX5_MAX_EQ_NAME]; - struct mlx5_eq *eq, *n; - int ncomp_vec; - int nent; - int err; - int i; - - INIT_LIST_HEAD(&dev->eqs_list); - ncomp_vec = table->num_comp_vectors; - nent = MLX5_COMP_EQ_SIZE; - for (i = 0; i < ncomp_vec; i++) { - eq = kzalloc(sizeof(*eq), GFP_KERNEL); - if (!eq) { - err = -ENOMEM; - goto clean; - } - - snprintf(name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i); - err = mlx5_create_map_eq(dev->mdev, eq, - i + MLX5_EQ_VEC_COMP_BASE, nent, 0, - name, &dev->mdev->priv.uuari.uars[0]); - if (err) { - kfree(eq); - goto clean; - } - mlx5_ib_dbg(dev, "allocated completion EQN %d\n", eq->eqn); - eq->index = i; - spin_lock(&table->lock); - list_add_tail(&eq->list, &dev->eqs_list); - spin_unlock(&table->lock); - } - - dev->num_comp_vectors = ncomp_vec; - return 0; - -clean: - spin_lock(&table->lock); - list_for_each_entry_safe(eq, n, &dev->eqs_list, list) { - list_del(&eq->list); - spin_unlock(&table->lock); - if (mlx5_destroy_unmap_eq(dev->mdev, eq)) - mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn); - kfree(eq); - spin_lock(&table->lock); - } - spin_unlock(&table->lock); - return err; -} - -static void free_comp_eqs(struct mlx5_ib_dev *dev) -{ - struct mlx5_eq_table *table = &dev->mdev->priv.eq_table; - struct mlx5_eq *eq, *n; - - spin_lock(&table->lock); - list_for_each_entry_safe(eq, n, &dev->eqs_list, list) { - list_del(&eq->list); - spin_unlock(&table->lock); - if (mlx5_destroy_unmap_eq(dev->mdev, eq)) - mlx5_ib_warn(dev, "failed to destroy EQ 0x%x\n", eq->eqn); - kfree(eq); - spin_lock(&table->lock); - } - spin_unlock(&table->lock); -} - static int mlx5_ib_query_device(struct ib_device *ibdev, struct ib_device_attr *props) { @@ -1291,10 +1202,6 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) get_ext_port_caps(dev); - err = alloc_comp_eqs(dev); - if (err) - goto err_dealloc; - MLX5_INIT_DOORBELL_LOCK(&dev->uar_lock); strlcpy(dev->ib_dev.name, "mlx5_%d", IB_DEVICE_NAME_MAX); @@ -1303,7 +1210,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) dev->ib_dev.local_dma_lkey = mdev->caps.gen.reserved_lkey; dev->num_ports = mdev->caps.gen.num_ports; dev->ib_dev.phys_port_cnt = dev->num_ports; - dev->ib_dev.num_comp_vectors = dev->num_comp_vectors; + dev->ib_dev.num_comp_vectors = + dev->mdev->priv.eq_table.num_comp_vectors; dev->ib_dev.dma_device = &mdev->pdev->dev; dev->ib_dev.uverbs_abi_ver = MLX5_IB_UVERBS_ABI_VERSION; @@ -1390,13 +1298,13 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) err = init_node_data(dev); if (err) - goto err_eqs; + goto err_dealloc; mutex_init(&dev->cap_mask_mutex); err = create_dev_resources(&dev->devr); if (err) - goto err_eqs; + goto err_dealloc; err = mlx5_ib_odp_init_one(dev); if (err) @@ -1433,9 +1341,6 @@ err_odp: err_rsrc: destroy_dev_resources(&dev->devr); -err_eqs: - free_comp_eqs(dev); - err_dealloc: ib_dealloc_device((struct ib_device *)dev); @@ -1450,7 +1355,6 @@ static void mlx5_ib_remove(struct mlx5_core_dev *mdev, void *context) destroy_umrc_res(dev); mlx5_ib_odp_remove_one(dev); destroy_dev_resources(&dev->devr); - free_comp_eqs(dev); ib_dealloc_device(&dev->ib_dev); } diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 8f94f69fbea5..dff1cfcdf476 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -421,9 +421,7 @@ struct mlx5_ib_dev { struct ib_device ib_dev; struct mlx5_core_dev *mdev; MLX5_DECLARE_DOORBELL_LOCK(uar_lock); - struct list_head eqs_list; int num_ports; - int num_comp_vectors; /* serialize update of capability mask */ struct mutex cap_mask_mutex; @@ -594,7 +592,6 @@ struct ib_xrcd *mlx5_ib_alloc_xrcd(struct ib_device *ibdev, struct ib_ucontext *context, struct ib_udata *udata); int mlx5_ib_dealloc_xrcd(struct ib_xrcd *xrcd); -int mlx5_vector2eqn(struct mlx5_ib_dev *dev, int vector, int *eqn, int *irqn); int mlx5_ib_get_buf_offset(u64 addr, int page_shift, u32 *offset); int mlx5_query_ext_port_caps(struct mlx5_ib_dev *dev, u8 port); int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index fe41a7c2c629..cfc29027f07a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -507,6 +507,87 @@ static int mlx5_core_disable_hca(struct mlx5_core_dev *dev) return 0; } +int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, int *irqn) +{ + struct mlx5_eq_table *table = &dev->priv.eq_table; + struct mlx5_eq *eq, *n; + int err = -ENOENT; + + spin_lock(&table->lock); + list_for_each_entry_safe(eq, n, &table->comp_eqs_list, list) { + if (eq->index == vector) { + *eqn = eq->eqn; + *irqn = eq->irqn; + err = 0; + break; + } + } + spin_unlock(&table->lock); + + return err; +} +EXPORT_SYMBOL(mlx5_vector2eqn); + +static void free_comp_eqs(struct mlx5_core_dev *dev) +{ + struct mlx5_eq_table *table = &dev->priv.eq_table; + struct mlx5_eq *eq, *n; + + spin_lock(&table->lock); + list_for_each_entry_safe(eq, n, &table->comp_eqs_list, list) { + list_del(&eq->list); + spin_unlock(&table->lock); + if (mlx5_destroy_unmap_eq(dev, eq)) + mlx5_core_warn(dev, "failed to destroy EQ 0x%x\n", + eq->eqn); + kfree(eq); + spin_lock(&table->lock); + } + spin_unlock(&table->lock); +} + +static int alloc_comp_eqs(struct mlx5_core_dev *dev) +{ + struct mlx5_eq_table *table = &dev->priv.eq_table; + char name[MLX5_MAX_EQ_NAME]; + struct mlx5_eq *eq; + int ncomp_vec; + int nent; + int err; + int i; + + INIT_LIST_HEAD(&table->comp_eqs_list); + ncomp_vec = table->num_comp_vectors; + nent = MLX5_COMP_EQ_SIZE; + for (i = 0; i < ncomp_vec; i++) { + eq = kzalloc(sizeof(*eq), GFP_KERNEL); + if (!eq) { + err = -ENOMEM; + goto clean; + } + + snprintf(name, MLX5_MAX_EQ_NAME, "mlx5_comp%d", i); + err = mlx5_create_map_eq(dev, eq, + i + MLX5_EQ_VEC_COMP_BASE, nent, 0, + name, &dev->priv.uuari.uars[0]); + if (err) { + kfree(eq); + goto clean; + } + mlx5_core_dbg(dev, "allocated completion EQN %d\n", eq->eqn); + eq->index = i; + spin_lock(&table->lock); + list_add_tail(&eq->list, &table->comp_eqs_list); + spin_unlock(&table->lock); + } + + return 0; + +clean: + free_comp_eqs(dev); + return err; +} + static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) { struct mlx5_priv *priv = &dev->priv; @@ -643,6 +724,12 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) goto err_free_uar; } + err = alloc_comp_eqs(dev); + if (err) { + dev_err(&pdev->dev, "Failed to alloc completion EQs\n"); + goto err_stop_eqs; + } + MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock); mlx5_init_cq_table(dev); @@ -652,6 +739,9 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) return 0; +err_stop_eqs: + mlx5_stop_eqs(dev); + err_free_uar: mlx5_free_uuars(dev, &priv->uuari); @@ -703,6 +793,7 @@ static void mlx5_dev_cleanup(struct mlx5_core_dev *dev) mlx5_cleanup_srq_table(dev); mlx5_cleanup_qp_table(dev); mlx5_cleanup_cq_table(dev); + free_comp_eqs(dev); mlx5_stop_eqs(dev); mlx5_free_uuars(dev, &priv->uuari); mlx5_eq_cleanup(dev); diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 8fedd39a9a60..f250f6580dad 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -410,7 +410,7 @@ struct mlx5_core_srq { struct mlx5_eq_table { void __iomem *update_ci; void __iomem *update_arm_ci; - struct list_head *comp_eq_head; + struct list_head comp_eqs_list; struct mlx5_eq pages_eq; struct mlx5_eq async_eq; struct mlx5_eq cmd_eq; @@ -725,6 +725,7 @@ int mlx5_create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq, u8 vecidx, int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq); int mlx5_start_eqs(struct mlx5_core_dev *dev); int mlx5_stop_eqs(struct mlx5_core_dev *dev); +int mlx5_vector2eqn(struct mlx5_core_dev *dev, int vector, int *eqn, int *irqn); int mlx5_core_attach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn); int mlx5_core_detach_mcg(struct mlx5_core_dev *dev, union ib_gid *mgid, u32 qpn); From ce0f75093282c5dca1e79ae3e3e893deaea86166 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 2 Apr 2015 17:07:33 +0300 Subject: [PATCH 494/567] net/mlx5_core: Modify arm CQ in preparation for upcoming Ethernet driver Pass consumer index as a parameter to arm CQ Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/cq.c | 8 ++++++-- include/linux/mlx5/cq.h | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index c94e2651820d..2ee6b1051975 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -572,11 +572,15 @@ int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) { + struct mlx5_core_dev *mdev = to_mdev(ibcq->device)->mdev; + void __iomem *uar_page = mdev->priv.uuari.uars[0].map; + mlx5_cq_arm(&to_mcq(ibcq)->mcq, (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? MLX5_CQ_DB_REQ_NOT_SOL : MLX5_CQ_DB_REQ_NOT, - to_mdev(ibcq->device)->mdev->priv.uuari.uars[0].map, - MLX5_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->mdev->priv.cq_uar_lock)); + uar_page, + MLX5_GET_DOORBELL_LOCK(&mdev->priv.cq_uar_lock), + to_mcq(ibcq)->mcq.cons_index); return 0; } diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h index 72ee0d732a26..2695ced222df 100644 --- a/include/linux/mlx5/cq.h +++ b/include/linux/mlx5/cq.h @@ -137,14 +137,15 @@ enum { static inline void mlx5_cq_arm(struct mlx5_core_cq *cq, u32 cmd, void __iomem *uar_page, - spinlock_t *doorbell_lock) + spinlock_t *doorbell_lock, + u32 cons_index) { __be32 doorbell[2]; u32 sn; u32 ci; sn = cq->arm_sn & 3; - ci = cq->cons_index & 0xffffff; + ci = cons_index & 0xffffff; *cq->arm_db = cpu_to_be32(sn << 28 | cmd | ci); From 64613d9499c4887485d4350387919ea507330d90 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 2 Apr 2015 17:07:34 +0300 Subject: [PATCH 495/567] net/mlx5_core: Extend struct mlx5_interface to support multiple protocols Preparation for ethernet driver. Signed-off-by: Achiad Shochat Signed-off-by: Saeed Mahameed Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx5/main.c | 1 + .../net/ethernet/mellanox/mlx5/core/main.c | 22 +++++++++++++++++++ include/linux/mlx5/driver.h | 8 +++++++ 3 files changed, 31 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index e59e2a1f8726..57c9809e8b87 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1362,6 +1362,7 @@ static struct mlx5_interface mlx5_ib_interface = { .add = mlx5_ib_add, .remove = mlx5_ib_remove, .event = mlx5_ib_event, + .protocol = MLX5_INTERFACE_PROTOCOL_IB, }; static int __init mlx5_ib_init(void) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index cfc29027f07a..28425e5ea91f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -908,6 +908,28 @@ void mlx5_unregister_interface(struct mlx5_interface *intf) } EXPORT_SYMBOL(mlx5_unregister_interface); +void *mlx5_get_protocol_dev(struct mlx5_core_dev *mdev, int protocol) +{ + struct mlx5_priv *priv = &mdev->priv; + struct mlx5_device_context *dev_ctx; + unsigned long flags; + void *result = NULL; + + spin_lock_irqsave(&priv->ctx_lock, flags); + + list_for_each_entry(dev_ctx, &mdev->priv.ctx_list, list) + if ((dev_ctx->intf->protocol == protocol) && + dev_ctx->intf->get_dev) { + result = dev_ctx->intf->get_dev(dev_ctx->context); + break; + } + + spin_unlock_irqrestore(&priv->ctx_lock, flags); + + return result; +} +EXPORT_SYMBOL(mlx5_get_protocol_dev); + static void mlx5_core_event(struct mlx5_core_dev *dev, enum mlx5_dev_event event, unsigned long param) { diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index f250f6580dad..9a90e7523dc2 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -781,14 +781,22 @@ enum { MAX_MR_CACHE_ENTRIES = 16, }; +enum { + MLX5_INTERFACE_PROTOCOL_IB = 0, + MLX5_INTERFACE_PROTOCOL_ETH = 1, +}; + struct mlx5_interface { void * (*add)(struct mlx5_core_dev *dev); void (*remove)(struct mlx5_core_dev *dev, void *context); void (*event)(struct mlx5_core_dev *dev, void *context, enum mlx5_dev_event event, unsigned long param); + void * (*get_dev)(void *context); + int protocol; struct list_head list; }; +void *mlx5_get_protocol_dev(struct mlx5_core_dev *mdev, int protocol); int mlx5_register_interface(struct mlx5_interface *intf); void mlx5_unregister_interface(struct mlx5_interface *intf); From 666b805150efd62f05810ff0db08f44a2370c937 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Wed, 1 Apr 2015 20:26:46 -0400 Subject: [PATCH 496/567] tcp: fix FRTO undo on cumulative ACK of SACKed range On processing cumulative ACKs, the FRTO code was not checking the SACKed bit, meaning that there could be a spurious FRTO undo on a cumulative ACK of a previously SACKed skb. The FRTO code should only consider a cumulative ACK to indicate that an original/unretransmitted skb is newly ACKed if the skb was not yet SACKed. The effect of the spurious FRTO undo would typically be to make the connection think that all previously-sent packets were in flight when they really weren't, leading to a stall and an RTO. Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Fixes: e33099f96d99c ("tcp: implement RFC5682 F-RTO") Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index fb4cf8b8e121..f501ac048366 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3105,10 +3105,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, if (!first_ackt.v64) first_ackt = last_ackt; - if (!(sacked & TCPCB_SACKED_ACKED)) + if (!(sacked & TCPCB_SACKED_ACKED)) { reord = min(pkts_acked, reord); - if (!after(scb->end_seq, tp->high_seq)) - flag |= FLAG_ORIG_SACK_ACKED; + if (!after(scb->end_seq, tp->high_seq)) + flag |= FLAG_ORIG_SACK_ACKED; + } } if (sacked & TCPCB_SACKED_ACKED) From ed785309c94445dd90e242370e1f7bb034e008fd Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 31 Mar 2015 11:01:45 -0700 Subject: [PATCH 497/567] ipv4: take rtnl_lock and mark mrt table as freed on namespace cleanup This is the IPv4 part for commit 905a6f96a1b1 (ipv6: take rtnl_lock and mark mrt6 table as freed on namespace cleanup). Cc: Hannes Frederic Sowa Acked-by: Hannes Frederic Sowa Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 92825443fad6..bc40115bc394 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -278,10 +278,12 @@ static void __net_exit ipmr_rules_exit(struct net *net) { struct mr_table *mrt, *next; + rtnl_lock(); list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { list_del(&mrt->list); ipmr_free_table(mrt); } + rtnl_unlock(); fib_rules_unregister(net->ipv4.mr_rules_ops); } #else @@ -308,7 +310,10 @@ static int __net_init ipmr_rules_init(struct net *net) static void __net_exit ipmr_rules_exit(struct net *net) { + rtnl_lock(); ipmr_free_table(net->ipv4.mrt); + net->ipv4.mrt = NULL; + rtnl_unlock(); } #endif From 419df12fb5fa558451319276838c1842f2b11f8f Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 31 Mar 2015 11:01:46 -0700 Subject: [PATCH 498/567] net: move fib_rules_unregister() under rtnl lock We have to hold rtnl lock for fib_rules_unregister() otherwise the following race could happen: fib_rules_unregister(): fib_nl_delrule(): ... ... ... ops = lookup_rules_ops(); list_del_rcu(&ops->list); list_for_each_entry(ops->rules) { fib_rules_cleanup_ops(ops); ... list_del_rcu(); list_del_rcu(); } Note, net->rules_mod_lock is actually not needed at all, either upper layer netns code or rtnl lock guarantees we are safe. Cc: Alexander Duyck Cc: Thomas Graf Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/core/fib_rules.c | 2 +- net/decnet/dn_rules.c | 2 ++ net/ipv4/fib_frontend.c | 3 +-- net/ipv4/ipmr.c | 2 +- net/ipv6/fib6_rules.c | 2 ++ net/ipv6/ip6mr.c | 2 +- 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 44706e81b2e0..e4fdc9dfb2c7 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -175,9 +175,9 @@ void fib_rules_unregister(struct fib_rules_ops *ops) spin_lock(&net->rules_mod_lock); list_del_rcu(&ops->list); - fib_rules_cleanup_ops(ops); spin_unlock(&net->rules_mod_lock); + fib_rules_cleanup_ops(ops); call_rcu(&ops->rcu, fib_rules_put_rcu); } EXPORT_SYMBOL_GPL(fib_rules_unregister); diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index faf7cc3483fe..9d66a0f72f90 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -248,7 +248,9 @@ void __init dn_fib_rules_init(void) void __exit dn_fib_rules_cleanup(void) { + rtnl_lock(); fib_rules_unregister(dn_fib_rules_ops); + rtnl_unlock(); rcu_barrier(); } diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 57be71dd6a9e..23b9b3e86f4c 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -1111,11 +1111,10 @@ static void ip_fib_net_exit(struct net *net) { unsigned int i; + rtnl_lock(); #ifdef CONFIG_IP_MULTIPLE_TABLES fib4_rules_exit(net); #endif - - rtnl_lock(); for (i = 0; i < FIB_TABLE_HASHSZ; i++) { struct fib_table *tb; struct hlist_head *head; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index bc40115bc394..fe54eba6d00d 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -283,8 +283,8 @@ static void __net_exit ipmr_rules_exit(struct net *net) list_del(&mrt->list); ipmr_free_table(mrt); } - rtnl_unlock(); fib_rules_unregister(net->ipv4.mr_rules_ops); + rtnl_unlock(); } #else #define ipmr_for_each_table(mrt, net) \ diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 27ca79682efb..70bc6abc0639 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -322,7 +322,9 @@ out_fib6_rules_ops: static void __net_exit fib6_rules_net_exit(struct net *net) { + rtnl_lock(); fib_rules_unregister(net->ipv6.fib6_rules_ops); + rtnl_unlock(); } static struct pernet_operations fib6_rules_net_ops = { diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 52028f449a89..2f1fd9ffcb34 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -267,8 +267,8 @@ static void __net_exit ip6mr_rules_exit(struct net *net) list_del(&mrt->list); ip6mr_free_table(mrt); } - rtnl_unlock(); fib_rules_unregister(net->ipv6.mr6_rules_ops); + rtnl_unlock(); } #else #define ip6mr_for_each_table(mrt, net) \ From 7ba0c47c34a1ea5bc7a24ca67309996cce0569b5 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 31 Mar 2015 11:01:47 -0700 Subject: [PATCH 499/567] ip6mr: call del_timer_sync() in ip6mr_free_table() We need to wait for the flying timers, since we are going to free the mrtable right after it. Cc: Hannes Frederic Sowa Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/ipv6/ip6mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 2f1fd9ffcb34..312e0ff47339 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -336,7 +336,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id) static void ip6mr_free_table(struct mr6_table *mrt) { - del_timer(&mrt->ipmr_expire_timer); + del_timer_sync(&mrt->ipmr_expire_timer); mroute_clean_tables(mrt); kfree(mrt); } From 818f2e7b25ac3ae12b1a40690e3aa082ff5896ee Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 31 Mar 2015 00:44:59 -0700 Subject: [PATCH 500/567] i40evf: Fix Outer UDP RX checksum code Inner protocol being UDP should not stop us from verifying Outer UDP checksum correctness. If the Outer protocol is not UDP (NVGRE) we should not be doing a UDP checksum check. If the packet has zero checksum, skip checksum check. Change-ID: Ie7f153feb276a59f66a54a0938901b2c0a8100fa Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index f41da5d8047b..1b5ee4655b25 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -915,9 +915,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, * so the total length of IPv4 header is IHL*4 bytes * The UDP_0 bit *may* bet set if the *inner* header is UDP */ - if (ipv4_tunnel && - (decoded.inner_prot != I40E_RX_PTYPE_INNER_PROT_UDP) && - !(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) { + if (ipv4_tunnel) { skb->transport_header = skb->mac_header + sizeof(struct ethhdr) + (ip_hdr(skb)->ihl * 4); @@ -927,15 +925,19 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, skb->protocol == htons(ETH_P_8021AD)) ? VLAN_HLEN : 0; - rx_udp_csum = udp_csum(skb); - iph = ip_hdr(skb); - csum = csum_tcpudp_magic( - iph->saddr, iph->daddr, - (skb->len - skb_transport_offset(skb)), - IPPROTO_UDP, rx_udp_csum); + if ((ip_hdr(skb)->protocol == IPPROTO_UDP) && + (udp_hdr(skb)->check != 0)) { + rx_udp_csum = udp_csum(skb); + iph = ip_hdr(skb); + csum = csum_tcpudp_magic(iph->saddr, iph->daddr, + (skb->len - + skb_transport_offset(skb)), + IPPROTO_UDP, rx_udp_csum); - if (udp_hdr(skb)->check != csum) - goto checksum_fail; + if (udp_hdr(skb)->check != csum) + goto checksum_fail; + + } /* else its GRE and so no outer UDP header */ } skb->ip_summed = CHECKSUM_UNNECESSARY; From b57459e913afeca56b43b09f35588e3e8b2b0f26 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Tue, 31 Mar 2015 00:45:00 -0700 Subject: [PATCH 501/567] i40e: validate VSI param from VFs Validate that the VF has sent us a valid VSI index before actually using that index. Without this code, a malicious or buggy VF driver could panic the host by sending an invalid index into the VSI array. Change-ID: I66a177687a0dcc281ec83e714d3813d70d18c8b4 Reported-by: Nick Nunley Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 0a93684130b9..bb184122f563 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -57,6 +57,8 @@ static inline bool i40e_vc_isvalid_vsi_id(struct i40e_vf *vf, u8 vsi_id) { struct i40e_pf *pf = vf->pf; + if (vsi_id > pf->num_alloc_vsi) + return false; return pf->vsi[vsi_id]->vf_id == vf->vf_id; } From 25fc0e6590d7c18886cab667430c0da16f0586c4 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 31 Mar 2015 00:45:01 -0700 Subject: [PATCH 502/567] i40e: Print some more info to help figure out the cause of HMC error HMC_ERRORINFO and HMC_ERRORDATA helps explain the cause of HMC error. Change-ID: I053bbc175a5f4c5c3e9ec2ea7400d5c56aaa4ec1 Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 845bceeda645..77e3b84bc367 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3197,6 +3197,9 @@ static irqreturn_t i40e_intr(int irq, void *data) if (icr0 & I40E_PFINT_ICR0_HMC_ERR_MASK) { icr0 &= ~I40E_PFINT_ICR0_HMC_ERR_MASK; dev_info(&pf->pdev->dev, "HMC error interrupt\n"); + dev_info(&pf->pdev->dev, "HMC error info 0x%x, HMC error data 0x%x\n", + rd32(hw, I40E_PFHMC_ERRORINFO), + rd32(hw, I40E_PFHMC_ERRORDATA)); } if (icr0 & I40E_PFINT_ICR0_TIMESYNC_MASK) { From 1a2f62489b5dc15bd2aadb1de2e38f732e2c4553 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 31 Mar 2015 00:45:01 -0700 Subject: [PATCH 503/567] i40e: Change some memcpys to struct assignments Several memcpys are not necessary and can be changed to structure assignments. Struct assignments are always type safe so this is preferable. Change-ID: I7daf45a4b5e799c686b9d5c8ba9db047584ab82b Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 77e3b84bc367..9e19933277e6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1969,7 +1969,7 @@ void i40e_vlan_stripping_enable(struct i40e_vsi *vsi) I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; ctxt.seid = vsi->seid; - memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); + ctxt.info = vsi->info; ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, @@ -1998,7 +1998,7 @@ void i40e_vlan_stripping_disable(struct i40e_vsi *vsi) I40E_AQ_VSI_PVLAN_EMOD_NOTHING; ctxt.seid = vsi->seid; - memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); + ctxt.info = vsi->info; ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, @@ -2282,7 +2282,7 @@ int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid) I40E_AQ_VSI_PVLAN_EMOD_STR; ctxt.seid = vsi->seid; - memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); + ctxt.info = vsi->info; aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); if (aq_ret) { dev_info(&vsi->back->pdev->dev, @@ -4395,7 +4395,7 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc) ctxt.pf_num = vsi->back->hw.pf_id; ctxt.vf_num = 0; ctxt.uplink_seid = vsi->uplink_seid; - memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info)); + ctxt.info = vsi->info; i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, false); /* Update the VSI after updating the VSI queue-mapping information */ @@ -5223,9 +5223,8 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf, goto exit; } - memset(&tmp_dcbx_cfg, 0, sizeof(tmp_dcbx_cfg)); /* Store the old configuration */ - memcpy(&tmp_dcbx_cfg, &hw->local_dcbx_config, sizeof(tmp_dcbx_cfg)); + tmp_dcbx_cfg = hw->local_dcbx_config; /* Reset the old DCBx configuration data */ memset(&hw->local_dcbx_config, 0, sizeof(hw->local_dcbx_config)); @@ -5785,11 +5784,9 @@ static void i40e_handle_link_event(struct i40e_pf *pf, struct i40e_hw *hw = &pf->hw; struct i40e_aqc_get_link_status *status = (struct i40e_aqc_get_link_status *)&e->desc.params.raw; - struct i40e_link_status *hw_link_info = &hw->phy.link_info; /* save off old link status information */ - memcpy(&pf->hw.phy.link_info_old, hw_link_info, - sizeof(pf->hw.phy.link_info_old)); + hw->phy.link_info_old = hw->phy.link_info; /* Do a new status request to re-enable LSE reporting * and load new status information into the hw struct @@ -8272,7 +8269,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret, pf->hw.aq.asq_last_status); return -ENOENT; } - memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); + vsi->info = ctxt.info; vsi->info.valid_sections = 0; vsi->seid = ctxt.seid; @@ -8406,7 +8403,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret = -ENOENT; goto err; } - memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info)); + vsi->info = ctxt.info; vsi->info.valid_sections = 0; vsi->seid = ctxt.seid; vsi->id = ctxt.vsi_number; From 8b6ed9c202c0c7c179ab7a6cf8010ff0b63d2d4f Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 31 Mar 2015 00:45:01 -0700 Subject: [PATCH 504/567] i40e/i40evf: fix bug when skb allocation fails If the skb allocation fails we should not continue using the skb pointer. Breaking out at the point of failure means that at the next RX interrupt the driver will try the allocation again. Change-ID: Iefaad69856ced7418bfd92afe55322676341f82e Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 5 ++++- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 9b11f2e7e361..5a1a67733b88 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1565,8 +1565,11 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) if (likely(!skb)) { skb = netdev_alloc_skb_ip_align(rx_ring->netdev, rx_ring->rx_hdr_len); - if (!skb) + if (!skb) { rx_ring->rx_stats.alloc_buff_failed++; + break; + } + /* initialize queue mapping */ skb_record_rx_queue(skb, rx_ring->queue_index); /* we are reusing so sync this buffer for CPU use */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 1b5ee4655b25..2be50a8d3671 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1040,8 +1040,11 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) if (likely(!skb)) { skb = netdev_alloc_skb_ip_align(rx_ring->netdev, rx_ring->rx_hdr_len); - if (!skb) + if (!skb) { rx_ring->rx_stats.alloc_buff_failed++; + break; + } + /* initialize queue mapping */ skb_record_rx_queue(skb, rx_ring->queue_index); /* we are reusing so sync this buffer for CPU use */ From b38da40190a1f8a1a0edcc70f983f7838aabadd4 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 31 Mar 2015 00:45:02 -0700 Subject: [PATCH 505/567] i40e: fix invalid void return in FCoE code A function was calling i40e_tx_map with return, but tx_map returns void, and the caller returns void, so just drop the return, and everything is good. Change-ID: I53fc676d517864761e7cbb8ca83f1ef0c15b1f8f Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index 1ca48458e668..1803afeef23e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -1306,8 +1306,7 @@ static void i40e_fcoe_tx_map(struct i40e_ring *tx_ring, /* MACLEN is ether header length in words not bytes */ td_offset |= (maclen >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; - return i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len, - td_cmd, td_offset); + i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len, td_cmd, td_offset); } /** From 6d7b967db3b1607c789f62936d68ced6321482ed Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Tue, 31 Mar 2015 00:45:02 -0700 Subject: [PATCH 506/567] i40e: warn at the right time The call to pci_disable_sriov got moved, but the message about not disabling VFs didn't move. So move it. While we're at, reword the message a bit to make it more consistent with other driver messages. Change-ID: I17d3e15e4fcfd5c9431a96ecb0117d728d3da18b Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index bb184122f563..184b00390f57 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -734,6 +734,8 @@ void i40e_free_vfs(struct i40e_pf *pf) */ if (!pci_vfs_assigned(pf->pdev)) pci_disable_sriov(pf->pdev); + else + dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n"); msleep(20); /* let any messages in transit get finished up */ @@ -763,9 +765,6 @@ void i40e_free_vfs(struct i40e_pf *pf) bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32; wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx)); } - } else { - dev_warn(&pf->pdev->dev, - "unable to disable SR-IOV because VFs are assigned.\n"); } clear_bit(__I40E_VF_DISABLE, &pf->state); } From 31eaaccff0fedb7cf6b6716efa3a2b8b8315ec68 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Tue, 31 Mar 2015 00:45:03 -0700 Subject: [PATCH 507/567] i40e/i40evf: Set Ethernet protocol correctly when Tx VLAN offloads are disabled If transmit VLAN HW offloads are disabled then the network stack sends up an skb with the protocol set to 8021q. In that case to get the correct checksum offloads we have to reset the skb protocol to the encapsulated ethertype. Change-ID: I903d78533de09b1c5d3ec695ee1990dd0fa5dd0d Signed-off-by: Greg Rose Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 13 +++++++++++++ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 5a1a67733b88..d8989f9d1798 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2057,6 +2057,19 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, __be16 protocol = skb->protocol; u32 tx_flags = 0; + if (protocol == htons(ETH_P_8021Q) && + !(tx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) { + /* When HW VLAN acceleration is turned off by the user the + * stack sets the protocol to 8021q so that the driver + * can take any steps required to support the SW only + * VLAN handling. In our case the driver doesn't need + * to take any further steps so just set the protocol + * to the encapsulated ethertype. + */ + skb->protocol = vlan_get_protocol(skb); + goto out; + } + /* if we have a HW VLAN tag being added, default to the HW one */ if (skb_vlan_tag_present(skb)) { tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 2be50a8d3671..e2ddb30e96f5 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1370,6 +1370,19 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, __be16 protocol = skb->protocol; u32 tx_flags = 0; + if (protocol == htons(ETH_P_8021Q) && + !(tx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) { + /* When HW VLAN acceleration is turned off by the user the + * stack sets the protocol to 8021q so that the driver + * can take any steps required to support the SW only + * VLAN handling. In our case the driver doesn't need + * to take any further steps so just set the protocol + * to the encapsulated ethertype. + */ + skb->protocol = vlan_get_protocol(skb); + goto out; + } + /* if we have a HW VLAN tag being added, default to the HW one */ if (skb_vlan_tag_present(skb)) { tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT; @@ -1386,6 +1399,7 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb, tx_flags |= I40E_TX_FLAGS_SW_VLAN; } +out: *flags = tx_flags; return 0; } From c142b1dc898efd4702aeacc787bbef8918c401e7 Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Tue, 31 Mar 2015 00:45:03 -0700 Subject: [PATCH 508/567] i40e: Don't register/de-register apps on NIC partitions in MFP mode Do not register or try to de-register DCB applications with the DCBNL layer in case of NIC partitions when adapter is in MFP mode. Change-ID: I603d042a61983a6562be471c6a2b181572504118 Signed-off-by: Neerav Parikh Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c index 400fb28db576..bd5079d5c1b6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c @@ -178,6 +178,10 @@ void i40e_dcbnl_set_all(struct i40e_vsi *vsi) if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) return; + /* MFP mode but not an iSCSI PF so return */ + if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi)) + return; + dcbxcfg = &hw->local_dcbx_config; /* Set up all the App TLVs if DCBx is negotiated */ @@ -282,6 +286,10 @@ void i40e_dcbnl_flush_apps(struct i40e_pf *pf, struct i40e_dcb_app_priority_table app; int i; + /* MFP mode but not an iSCSI PF so return */ + if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi)) + return; + for (i = 0; i < old_cfg->numapps; i++) { app = old_cfg->app[i]; /* The APP is not available anymore delete it */ From c22c06c8d1b62cd2a42a8f276c7e72bc17067183 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Tue, 31 Mar 2015 00:45:04 -0700 Subject: [PATCH 509/567] i40e: fix up VXLAN messages When the VXLAN ports are added and removed, the messaging was giving some bogus index info, the port was always '0' for the delete, and the message text style didn't match other messages in the driver. Also, there was an over-use of the tertiary statement which made reading a little harder than necessary. Change-ID: Ie805182a697b8b4c12024403ada87fd4e4fa2358 Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 38 ++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 9e19933277e6..15cee4d7ecf8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6608,7 +6608,6 @@ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf) { struct i40e_hw *hw = &pf->hw; i40e_status ret; - u8 filter_index; __be16 port; int i; @@ -6621,22 +6620,20 @@ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf) if (pf->pending_vxlan_bitmap & (1 << i)) { pf->pending_vxlan_bitmap &= ~(1 << i); port = pf->vxlan_ports[i]; - ret = port ? - i40e_aq_add_udp_tunnel(hw, ntohs(port), + if (port) + ret = i40e_aq_add_udp_tunnel(hw, ntohs(port), I40E_AQC_TUNNEL_TYPE_VXLAN, - &filter_index, NULL) - : i40e_aq_del_udp_tunnel(hw, i, NULL); + NULL, NULL); + else + ret = i40e_aq_del_udp_tunnel(hw, i, NULL); if (ret) { - dev_info(&pf->pdev->dev, "Failed to execute AQ command for %s port %d with index %d\n", - port ? "adding" : "deleting", - ntohs(port), port ? i : i); - + dev_info(&pf->pdev->dev, + "%s vxlan port %d, index %d failed, err %d, aq_err %d\n", + port ? "add" : "delete", + ntohs(port), i, ret, + pf->hw.aq.asq_last_status); pf->vxlan_ports[i] = 0; - } else { - dev_info(&pf->pdev->dev, "%s port %d with AQ command with index %d\n", - port ? "Added" : "Deleted", - ntohs(port), port ? i : filter_index); } } } @@ -7829,7 +7826,8 @@ static void i40e_add_vxlan_port(struct net_device *netdev, /* Check if port already exists */ if (idx < I40E_MAX_PF_UDP_OFFLOAD_PORTS) { - netdev_info(netdev, "Port %d already offloaded\n", ntohs(port)); + netdev_info(netdev, "vxlan port %d already offloaded\n", + ntohs(port)); return; } @@ -7837,7 +7835,7 @@ static void i40e_add_vxlan_port(struct net_device *netdev, next_idx = i40e_get_vxlan_port_idx(pf, 0); if (next_idx == I40E_MAX_PF_UDP_OFFLOAD_PORTS) { - netdev_info(netdev, "Maximum number of UDP ports reached, not adding port %d\n", + netdev_info(netdev, "maximum number of vxlan UDP ports reached, not adding port %d\n", ntohs(port)); return; } @@ -7845,8 +7843,9 @@ static void i40e_add_vxlan_port(struct net_device *netdev, /* New port: add it and mark its index in the bitmap */ pf->vxlan_ports[next_idx] = port; pf->pending_vxlan_bitmap |= (1 << next_idx); - pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC; + + dev_info(&pf->pdev->dev, "adding vxlan port %d\n", ntohs(port)); } /** @@ -7874,12 +7873,13 @@ static void i40e_del_vxlan_port(struct net_device *netdev, * and make it pending */ pf->vxlan_ports[idx] = 0; - pf->pending_vxlan_bitmap |= (1 << idx); - pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC; + + dev_info(&pf->pdev->dev, "deleting vxlan port %d\n", + ntohs(port)); } else { - netdev_warn(netdev, "Port %d was not found, not deleting\n", + netdev_warn(netdev, "vxlan port %d was not found, not deleting\n", ntohs(port)); } } From 3932dbfe1ecdcf05578cc6aca7ca1b6c6dbd311e Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Tue, 31 Mar 2015 00:45:04 -0700 Subject: [PATCH 510/567] i40e: stop flow director on shutdown In some cases, the hardware would continue to try to access the FDIR ring after entering D3Hot state, which would cause either PCIe errors or NMIs, depending upon system configuration. Explicitly stop FDIR in our shutdown routine to eliminate this possibility. Change-ID: Ib98060d6352ec595ab9a78bfe252675a9fa5d8bc Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 15cee4d7ecf8..5e79054f2801 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -10210,6 +10210,8 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state) set_bit(__I40E_DOWN, &pf->state); del_timer_sync(&pf->service_timer); cancel_work_sync(&pf->service_task); + i40e_fdir_teardown(pf); + rtnl_lock(); i40e_prep_for_reset(pf); rtnl_unlock(); From fdf0e0bfc363a9b5380ecb5e9c46d6f5a39a9b75 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 31 Mar 2015 00:45:05 -0700 Subject: [PATCH 511/567] i40e: Communicate VSI id in place of VSI index to the VFs This does not affect the Virtual channel API as such but it changes the meaning of what is communicated to the VSI resource struct as vsi_id. Earlier vsi_idx was being passed in, which was the index in the PF's VSI array. Now we pass vsi_id as communicated by the FW to the driver. This will help with future expansion of VF and FW communication. With this in place now the VF and Virtual channel driver change to move over to VSI id use is complete and is validated. Change-ID: I14246ef82b3b3dc1fa76291d2dd0c05d12cedb7c Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 16 +++ .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 110 +++++++++--------- .../ethernet/intel/i40e/i40e_virtchnl_pf.h | 2 +- 4 files changed, 76 insertions(+), 53 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 1c8bd7c152c2..33c35d3b7420 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -628,6 +628,7 @@ extern const char i40e_driver_name[]; extern const char i40e_driver_version_str[]; void i40e_do_reset_safe(struct i40e_pf *pf, u32 reset_flags); void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags); +struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id); void i40e_update_stats(struct i40e_vsi *vsi); void i40e_update_eth_stats(struct i40e_vsi *vsi); struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5e79054f2801..89a2d76a1f69 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -249,6 +249,22 @@ static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id) return count; } +/** + * i40e_find_vsi_from_id - searches for the vsi with the given id + * @pf - the pf structure to search for the vsi + * @id - id of the vsi it is searching for + **/ +struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id) +{ + int i; + + for (i = 0; i < pf->num_alloc_vsi; i++) + if (pf->vsi[i] && (pf->vsi[i]->id == id)) + return pf->vsi[i]; + + return NULL; +} + /** * i40e_service_event_schedule - Schedule the service task to wake up * @pf: board private structure diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 184b00390f57..4d69e1f04901 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -53,13 +53,12 @@ static inline void i40e_vc_disable_vf(struct i40e_pf *pf, struct i40e_vf *vf) * * check for the valid VSI id **/ -static inline bool i40e_vc_isvalid_vsi_id(struct i40e_vf *vf, u8 vsi_id) +static inline bool i40e_vc_isvalid_vsi_id(struct i40e_vf *vf, u16 vsi_id) { struct i40e_pf *pf = vf->pf; + struct i40e_vsi *vsi = i40e_find_vsi_from_id(pf, vsi_id); - if (vsi_id > pf->num_alloc_vsi) - return false; - return pf->vsi[vsi_id]->vf_id == vf->vf_id; + return (vsi && (vsi->vf_id == vf->vf_id)); } /** @@ -70,12 +69,13 @@ static inline bool i40e_vc_isvalid_vsi_id(struct i40e_vf *vf, u8 vsi_id) * * check for the valid queue id **/ -static inline bool i40e_vc_isvalid_queue_id(struct i40e_vf *vf, u8 vsi_id, +static inline bool i40e_vc_isvalid_queue_id(struct i40e_vf *vf, u16 vsi_id, u8 qid) { struct i40e_pf *pf = vf->pf; + struct i40e_vsi *vsi = i40e_find_vsi_from_id(pf, vsi_id); - return qid < pf->vsi[vsi_id]->alloc_queue_pairs; + return (vsi && (qid < vsi->alloc_queue_pairs)); } /** @@ -97,18 +97,21 @@ static inline bool i40e_vc_isvalid_vector_id(struct i40e_vf *vf, u8 vector_id) /** * i40e_vc_get_pf_queue_id * @vf: pointer to the VF info - * @vsi_idx: index of VSI in PF struct + * @vsi_id: id of VSI as provided by the FW * @vsi_queue_id: vsi relative queue id * * return PF relative queue id **/ -static u16 i40e_vc_get_pf_queue_id(struct i40e_vf *vf, u8 vsi_idx, +static u16 i40e_vc_get_pf_queue_id(struct i40e_vf *vf, u16 vsi_id, u8 vsi_queue_id) { struct i40e_pf *pf = vf->pf; - struct i40e_vsi *vsi = pf->vsi[vsi_idx]; + struct i40e_vsi *vsi = i40e_find_vsi_from_id(pf, vsi_id); u16 pf_queue_id = I40E_QUEUE_END_OF_LIST; + if (!vsi) + return pf_queue_id; + if (le16_to_cpu(vsi->info.mapping_flags) & I40E_AQ_VSI_QUE_MAP_NONCONTIG) pf_queue_id = @@ -123,12 +126,12 @@ static u16 i40e_vc_get_pf_queue_id(struct i40e_vf *vf, u8 vsi_idx, /** * i40e_config_irq_link_list * @vf: pointer to the VF info - * @vsi_idx: index of VSI in PF struct + * @vsi_id: id of VSI as given by the FW * @vecmap: irq map info * * configure irq link list from the map **/ -static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_idx, +static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, struct i40e_virtchnl_vector_map *vecmap) { unsigned long linklistmap = 0, tempmap; @@ -173,7 +176,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_idx, I40E_VIRTCHNL_SUPPORTED_QTYPES)); vsi_queue_id = next_q/I40E_VIRTCHNL_SUPPORTED_QTYPES; qtype = next_q%I40E_VIRTCHNL_SUPPORTED_QTYPES; - pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx, vsi_queue_id); + pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id); reg = ((qtype << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) | pf_queue_id); wr32(hw, reg_idx, reg); @@ -200,7 +203,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_idx, (I40E_MAX_VSI_QP * I40E_VIRTCHNL_SUPPORTED_QTYPES)) { vsi_queue_id = next_q / I40E_VIRTCHNL_SUPPORTED_QTYPES; qtype = next_q % I40E_VIRTCHNL_SUPPORTED_QTYPES; - pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx, + pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id); } else { pf_queue_id = I40E_QUEUE_END_OF_LIST; @@ -223,24 +226,26 @@ irq_list_done: /** * i40e_config_vsi_tx_queue * @vf: pointer to the VF info - * @vsi_idx: index of VSI in PF struct + * @vsi_id: id of VSI as provided by the FW * @vsi_queue_id: vsi relative queue index * @info: config. info * * configure tx queue **/ -static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_idx, +static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id, u16 vsi_queue_id, struct i40e_virtchnl_txq_info *info) { struct i40e_pf *pf = vf->pf; struct i40e_hw *hw = &pf->hw; struct i40e_hmc_obj_txq tx_ctx; + struct i40e_vsi *vsi; u16 pf_queue_id; u32 qtx_ctl; int ret = 0; - pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx, vsi_queue_id); + pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id); + vsi = i40e_find_vsi_from_id(pf, vsi_id); /* clear the context structure first */ memset(&tx_ctx, 0, sizeof(struct i40e_hmc_obj_txq)); @@ -248,7 +253,7 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_idx, /* only set the required fields */ tx_ctx.base = info->dma_ring_addr / 128; tx_ctx.qlen = info->ring_len; - tx_ctx.rdylist = le16_to_cpu(pf->vsi[vsi_idx]->info.qs_handle[0]); + tx_ctx.rdylist = le16_to_cpu(vsi->info.qs_handle[0]); tx_ctx.rdylist_act = 0; tx_ctx.head_wb_ena = info->headwb_enabled; tx_ctx.head_wb_addr = info->dma_headwb_addr; @@ -290,13 +295,13 @@ error_context: /** * i40e_config_vsi_rx_queue * @vf: pointer to the VF info - * @vsi_idx: index of VSI in PF struct + * @vsi_id: id of VSI as provided by the FW * @vsi_queue_id: vsi relative queue index * @info: config. info * * configure rx queue **/ -static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_idx, +static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id, u16 vsi_queue_id, struct i40e_virtchnl_rxq_info *info) { @@ -306,7 +311,7 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_idx, u16 pf_queue_id; int ret = 0; - pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx, vsi_queue_id); + pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id); /* clear the context structure first */ memset(&rx_ctx, 0, sizeof(struct i40e_hmc_obj_rxq)); @@ -403,7 +408,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) } if (type == I40E_VSI_SRIOV) { u8 brdcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - vf->lan_vsi_index = vsi->idx; + vf->lan_vsi_idx = vsi->idx; vf->lan_vsi_id = vsi->id; /* If the port VLAN has been configured and then the * VF driver was removed then the VSI port VLAN @@ -468,8 +473,8 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf) wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), reg); /* map PF queues to VF queues */ - for (j = 0; j < pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs; j++) { - u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index, j); + for (j = 0; j < pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs; j++) { + u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id, j); reg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK); wr32(hw, I40E_VPLAN_QTABLE(total_queue_pairs, vf->vf_id), reg); total_queue_pairs++; @@ -477,13 +482,13 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf) /* map PF queues to VSI */ for (j = 0; j < 7; j++) { - if (j * 2 >= pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs) { + if (j * 2 >= pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs) { reg = 0x07FF07FF; /* unused */ } else { - u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index, + u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id, j * 2); reg = qid; - qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index, + qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id, (j * 2) + 1); reg |= qid << 16; } @@ -527,9 +532,9 @@ static void i40e_free_vf_res(struct i40e_vf *vf) int i, msix_vf; /* free vsi & disconnect it from the parent uplink */ - if (vf->lan_vsi_index) { - i40e_vsi_release(pf->vsi[vf->lan_vsi_index]); - vf->lan_vsi_index = 0; + if (vf->lan_vsi_idx) { + i40e_vsi_release(pf->vsi[vf->lan_vsi_idx]); + vf->lan_vsi_idx = 0; vf->lan_vsi_id = 0; } msix_vf = pf->hw.func_caps.num_msix_vectors_vf; @@ -584,7 +589,7 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf) ret = i40e_alloc_vsi_res(vf, I40E_VSI_SRIOV); if (ret) goto error_alloc; - total_queue_pairs += pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs; + total_queue_pairs += pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs; set_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps); /* store the total qps number for the runtime @@ -694,10 +699,10 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr) wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg); /* On initial reset, we won't have any queues */ - if (vf->lan_vsi_index == 0) + if (vf->lan_vsi_idx == 0) goto complete_reset; - i40e_vsi_control_rings(pf->vsi[vf->lan_vsi_index], false); + i40e_vsi_control_rings(pf->vsi[vf->lan_vsi_idx], false); complete_reset: /* reallocate VF resources to reset the VSI state */ i40e_free_vf_res(vf); @@ -1018,18 +1023,18 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf) } vfres->vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2; - vsi = pf->vsi[vf->lan_vsi_index]; + vsi = pf->vsi[vf->lan_vsi_idx]; if (!vsi->info.pvid) vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN; vfres->num_vsis = num_vsis; vfres->num_queue_pairs = vf->num_queue_pairs; vfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf; - if (vf->lan_vsi_index) { - vfres->vsi_res[i].vsi_id = vf->lan_vsi_index; + if (vf->lan_vsi_idx) { + vfres->vsi_res[i].vsi_id = vf->lan_vsi_id; vfres->vsi_res[i].vsi_type = I40E_VSI_SRIOV; vfres->vsi_res[i].num_queue_pairs = - pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs; + pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs; memcpy(vfres->vsi_res[i].default_mac_addr, vf->default_lan_addr.addr, ETH_ALEN); i++; @@ -1081,14 +1086,14 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, bool allmulti = false; i40e_status aq_ret; + vsi = i40e_find_vsi_from_id(pf, info->vsi_id); if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) || !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) || !i40e_vc_isvalid_vsi_id(vf, info->vsi_id) || - (pf->vsi[info->vsi_id]->type != I40E_VSI_FCOE)) { + (vsi->type != I40E_VSI_FCOE)) { aq_ret = I40E_ERR_PARAM; goto error_param; } - vsi = pf->vsi[info->vsi_id]; if (info->flags & I40E_FLAG_VF_MULTICAST_PROMISC) allmulti = true; aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, @@ -1150,7 +1155,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) } } /* set vsi num_queue_pairs in use to num configured by VF */ - pf->vsi[vf->lan_vsi_index]->num_queue_pairs = qci->num_queue_pairs; + pf->vsi[vf->lan_vsi_idx]->num_queue_pairs = qci->num_queue_pairs; error_param: /* send the response to the VF */ @@ -1251,7 +1256,8 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = I40E_ERR_PARAM; goto error_param; } - if (i40e_vsi_control_rings(pf->vsi[vsi_id], true)) + + if (i40e_vsi_control_rings(pf->vsi[vf->lan_vsi_idx], true)) aq_ret = I40E_ERR_TIMEOUT; error_param: /* send the response to the VF */ @@ -1273,7 +1279,6 @@ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) struct i40e_virtchnl_queue_select *vqs = (struct i40e_virtchnl_queue_select *)msg; struct i40e_pf *pf = vf->pf; - u16 vsi_id = vqs->vsi_id; i40e_status aq_ret = 0; if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) { @@ -1290,7 +1295,8 @@ static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) aq_ret = I40E_ERR_PARAM; goto error_param; } - if (i40e_vsi_control_rings(pf->vsi[vsi_id], false)) + + if (i40e_vsi_control_rings(pf->vsi[vf->lan_vsi_idx], false)) aq_ret = I40E_ERR_TIMEOUT; error_param: @@ -1328,7 +1334,7 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) goto error_param; } - vsi = pf->vsi[vqs->vsi_id]; + vsi = pf->vsi[vf->lan_vsi_idx]; if (!vsi) { aq_ret = I40E_ERR_PARAM; goto error_param; @@ -1406,7 +1412,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) if (ret) goto error_param; } - vsi = pf->vsi[vsi_id]; + vsi = pf->vsi[vf->lan_vsi_idx]; /* add new addresses to the list */ for (i = 0; i < al->num_elements; i++) { @@ -1474,7 +1480,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) goto error_param; } } - vsi = pf->vsi[vsi_id]; + vsi = pf->vsi[vf->lan_vsi_idx]; /* delete addresses from the list */ for (i = 0; i < al->num_elements; i++) @@ -1524,7 +1530,7 @@ static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) goto error_param; } } - vsi = pf->vsi[vsi_id]; + vsi = pf->vsi[vf->lan_vsi_idx]; if (vsi->info.pvid) { aq_ret = I40E_ERR_PARAM; goto error_param; @@ -1577,7 +1583,7 @@ static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) } } - vsi = pf->vsi[vsi_id]; + vsi = pf->vsi[vf->lan_vsi_idx]; if (vsi->info.pvid) { aq_ret = I40E_ERR_PARAM; goto error_param; @@ -1966,7 +1972,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) } vf = &(pf->vf[vf_id]); - vsi = pf->vsi[vf->lan_vsi_index]; + vsi = pf->vsi[vf->lan_vsi_idx]; if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) { dev_err(&pf->pdev->dev, "Uninitialized VF %d\n", vf_id); @@ -2040,7 +2046,7 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, } vf = &(pf->vf[vf_id]); - vsi = pf->vsi[vf->lan_vsi_index]; + vsi = pf->vsi[vf->lan_vsi_idx]; if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) { dev_err(&pf->pdev->dev, "Uninitialized VF %d\n", vf_id); ret = -EINVAL; @@ -2153,7 +2159,7 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate, } vf = &(pf->vf[vf_id]); - vsi = pf->vsi[vf->lan_vsi_index]; + vsi = pf->vsi[vf->lan_vsi_idx]; if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) { dev_err(&pf->pdev->dev, "Uninitialized VF %d.\n", vf_id); ret = -EINVAL; @@ -2227,7 +2233,7 @@ int i40e_ndo_get_vf_config(struct net_device *netdev, vf = &(pf->vf[vf_id]); /* first vsi is always the LAN vsi */ - vsi = pf->vsi[vf->lan_vsi_index]; + vsi = pf->vsi[vf->lan_vsi_idx]; if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) { dev_err(&pf->pdev->dev, "Uninitialized VF %d\n", vf_id); ret = -EINVAL; @@ -2351,7 +2357,7 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable) vf->spoofchk = enable; memset(&ctxt, 0, sizeof(ctxt)); - ctxt.seid = pf->vsi[vf->lan_vsi_index]->seid; + ctxt.seid = pf->vsi[vf->lan_vsi_idx]->seid; ctxt.pf_num = pf->hw.pf_id; ctxt.info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID); if (enable) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 9c3a41040835..09043c1aae54 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -88,7 +88,7 @@ struct i40e_vf { * When assigned, these will be non-zero, because VSI 0 is always * the main LAN VSI for the PF. */ - u8 lan_vsi_index; /* index into PF struct */ + u8 lan_vsi_idx; /* index into PF struct */ u8 lan_vsi_id; /* ID as used by firmware */ u8 num_queue_pairs; /* num of qps assigned to VF vsis */ From 13acb54683f834cb16baf7ad7fd6e15a97b0762f Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Tue, 31 Mar 2015 00:45:05 -0700 Subject: [PATCH 512/567] i40evf: protect VLAN filter list The MAC filter list is protected by a critical task bit, and the VLAN list should be protected as well. This prevents list corruption if the watchdog happens to run at the same time as a VLAN filter is being added or deleted. Change-ID: Ia4867cebbbb046a1f38012771b288a634ca5882b Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40evf/i40evf_main.c | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index b08efafee1ae..46aef2a45cbf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -664,13 +664,21 @@ i40evf_vlan_filter *i40evf_find_vlan(struct i40evf_adapter *adapter, u16 vlan) static struct i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan) { - struct i40evf_vlan_filter *f; + struct i40evf_vlan_filter *f = NULL; + int count = 50; + + while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + &adapter->crit_section)) { + udelay(1); + if (--count == 0) + goto out; + } f = i40evf_find_vlan(adapter, vlan); if (!f) { f = kzalloc(sizeof(*f), GFP_ATOMIC); if (!f) - return NULL; + goto clearout; f->vlan = vlan; @@ -680,6 +688,9 @@ i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan) adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; } +clearout: + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); +out: return f; } @@ -691,12 +702,21 @@ i40evf_vlan_filter *i40evf_add_vlan(struct i40evf_adapter *adapter, u16 vlan) static void i40evf_del_vlan(struct i40evf_adapter *adapter, u16 vlan) { struct i40evf_vlan_filter *f; + int count = 50; + + while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, + &adapter->crit_section)) { + udelay(1); + if (--count == 0) + return; + } f = i40evf_find_vlan(adapter, vlan); if (f) { f->remove = true; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; } + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); } /** From 9a9c8ae1c1b43e12a5ab786d3463b251fe2fd4aa Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 31 Mar 2015 00:45:06 -0700 Subject: [PATCH 513/567] i40evf: Refactor VF RSS code Refactor VF RSS code to allow RSS on a single queue and eliminate the need for the next_queue function. Change-ID: I9253bad96b7f542ee7036e15636db0e5d58d8ef2 Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40evf/i40evf_main.c | 43 +++++-------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 46aef2a45cbf..6d5f3b21c68a 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1435,41 +1435,22 @@ restart_watchdog: } /** - * next_queue - increment to next available tx queue - * @adapter: board private structure - * @j: queue counter - * - * Helper function for RSS programming to increment through available - * queus. Returns the next queue value. - **/ -static int next_queue(struct i40evf_adapter *adapter, int j) -{ - j += 1; - - return j >= adapter->num_active_queues ? 0 : j; -} - -/** - * i40evf_configure_rss - Prepare for RSS if used + * i40evf_configure_rss - Prepare for RSS * @adapter: board private structure **/ static void i40evf_configure_rss(struct i40evf_adapter *adapter) { u32 rss_key[I40E_VFQF_HKEY_MAX_INDEX + 1]; struct i40e_hw *hw = &adapter->hw; + u32 cqueue = 0; u32 lut = 0; int i, j; u64 hena; - /* No RSS for single queue. */ - if (adapter->num_active_queues == 1) { - wr32(hw, I40E_VFQF_HENA(0), 0); - wr32(hw, I40E_VFQF_HENA(1), 0); - return; - } - /* Hash type is configured by the PF - we just supply the key */ netdev_rss_key_fill(rss_key, sizeof(rss_key)); + + /* Fill out hash function seed */ for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) wr32(hw, I40E_VFQF_HKEY(i), rss_key[i]); @@ -1479,16 +1460,14 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter) wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32)); /* Populate the LUT with max no. of queues in round robin fashion */ - j = adapter->num_active_queues; for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) { - j = next_queue(adapter, j); - lut = j; - j = next_queue(adapter, j); - lut |= j << 8; - j = next_queue(adapter, j); - lut |= j << 16; - j = next_queue(adapter, j); - lut |= j << 24; + lut = 0; + for (j = 0; j < 4; j++) { + if (cqueue == adapter->vsi_res->num_queue_pairs) + cqueue = 0; + lut |= ((cqueue) << (8 * j)); + cqueue++; + } wr32(hw, I40E_VFQF_HLUT(i), lut); } i40e_flush(hw); From 42d255ce43e1dbe28b5907ec276cd88330952661 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Tue, 31 Mar 2015 00:45:06 -0700 Subject: [PATCH 514/567] i40e: Bump to version 1.3.1 Bump. Change-ID: I7dc88baa33264e5919bc938adf76706573209432 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 89a2d76a1f69..63de3f4b7a94 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -38,8 +38,8 @@ static const char i40e_driver_string[] = #define DRV_KERN "-k" #define DRV_VERSION_MAJOR 1 -#define DRV_VERSION_MINOR 2 -#define DRV_VERSION_BUILD 43 +#define DRV_VERSION_MINOR 3 +#define DRV_VERSION_BUILD 1 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN From 51456b2914a34d16b1255b7c55d5cbf6a681d306 Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Fri, 3 Apr 2015 09:17:26 +0100 Subject: [PATCH 515/567] ipv4: coding style: comparison for equality with NULL The ipv4 code uses a mixture of coding styles. In some instances check for NULL pointer is done as x == NULL and sometimes as !x. !x is preferred according to checkpatch and this patch makes the code consistent by adopting the latter form. No changes detected by objdiff. Signed-off-by: Ian Morris Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 6 ++--- net/ipv4/arp.c | 26 ++++++++++----------- net/ipv4/cipso_ipv4.c | 36 ++++++++++++++-------------- net/ipv4/devinet.c | 40 +++++++++++++++---------------- net/ipv4/esp4.c | 2 +- net/ipv4/fib_frontend.c | 26 ++++++++++----------- net/ipv4/fib_rules.c | 4 ++-- net/ipv4/fib_semantics.c | 24 +++++++++---------- net/ipv4/fib_trie.c | 12 +++++----- net/ipv4/geneve.c | 2 +- net/ipv4/gre_offload.c | 2 +- net/ipv4/icmp.c | 6 ++--- net/ipv4/igmp.c | 12 +++++----- net/ipv4/inet_fragment.c | 4 ++-- net/ipv4/ip_fragment.c | 11 +++++---- net/ipv4/ip_gre.c | 4 ++-- net/ipv4/ip_input.c | 5 ++-- net/ipv4/ip_output.c | 23 ++++++++++-------- net/ipv4/ip_sockglue.c | 4 ++-- net/ipv4/ip_tunnel.c | 8 +++---- net/ipv4/ipcomp.c | 2 +- net/ipv4/ipconfig.c | 6 +++-- net/ipv4/ipip.c | 2 +- net/ipv4/ipmr.c | 48 +++++++++++++++++++------------------- net/ipv4/ping.c | 2 +- net/ipv4/raw.c | 2 +- net/ipv4/route.c | 20 ++++++++-------- net/ipv4/sysctl_net_ipv4.c | 6 ++--- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_fastopen.c | 6 ++--- net/ipv4/tcp_input.c | 16 ++++++------- net/ipv4/tcp_ipv4.c | 6 ++--- net/ipv4/tcp_metrics.c | 2 +- net/ipv4/tcp_minisocks.c | 2 +- net/ipv4/tcp_output.c | 21 +++++++++-------- net/ipv4/udp.c | 6 ++--- net/ipv4/udp_diag.c | 2 +- net/ipv4/xfrm4_input.c | 2 +- net/ipv4/xfrm4_policy.c | 2 +- 39 files changed, 210 insertions(+), 202 deletions(-) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 64a9c0fdc4aa..7d3b00c01bc8 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -217,7 +217,7 @@ int inet_listen(struct socket *sock, int backlog) * shutdown() (rather than close()). */ if ((sysctl_tcp_fastopen & TFO_SERVER_ENABLE) != 0 && - inet_csk(sk)->icsk_accept_queue.fastopenq == NULL) { + !inet_csk(sk)->icsk_accept_queue.fastopenq) { if ((sysctl_tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) != 0) err = fastopen_init_queue(sk, backlog); else if ((sysctl_tcp_fastopen & @@ -314,11 +314,11 @@ lookup_protocol: answer_flags = answer->flags; rcu_read_unlock(); - WARN_ON(answer_prot->slab == NULL); + WARN_ON(!answer_prot->slab); err = -ENOBUFS; sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot); - if (sk == NULL) + if (!sk) goto out; err = 0; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 5f5c674e130a..ffe84226a2c8 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -228,7 +228,7 @@ static int arp_constructor(struct neighbour *neigh) rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); - if (in_dev == NULL) { + if (!in_dev) { rcu_read_unlock(); return -EINVAL; } @@ -475,7 +475,7 @@ static inline int arp_fwd_pvlan(struct in_device *in_dev, */ /* - * Create an arp packet. If (dest_hw == NULL), we create a broadcast + * Create an arp packet. If dest_hw is not set, we create a broadcast * message. */ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, @@ -495,7 +495,7 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, */ skb = alloc_skb(arp_hdr_len(dev) + hlen + tlen, GFP_ATOMIC); - if (skb == NULL) + if (!skb) return NULL; skb_reserve(skb, hlen); @@ -503,9 +503,9 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev)); skb->dev = dev; skb->protocol = htons(ETH_P_ARP); - if (src_hw == NULL) + if (!src_hw) src_hw = dev->dev_addr; - if (dest_hw == NULL) + if (!dest_hw) dest_hw = dev->broadcast; /* @@ -614,7 +614,7 @@ void arp_send(int type, int ptype, __be32 dest_ip, skb = arp_create(type, ptype, dest_ip, dev, src_ip, dest_hw, src_hw, target_hw); - if (skb == NULL) + if (!skb) return; arp_xmit(skb); @@ -644,7 +644,7 @@ static int arp_process(struct sk_buff *skb) * is ARP'able. */ - if (in_dev == NULL) + if (!in_dev) goto out; arp = arp_hdr(skb); @@ -808,7 +808,7 @@ static int arp_process(struct sk_buff *skb) is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip && inet_addr_type(net, sip) == RTN_UNICAST; - if (n == NULL && + if (!n && ((arp->ar_op == htons(ARPOP_REPLY) && inet_addr_type(net, sip) == RTN_UNICAST) || is_garp)) n = __neigh_lookup(&arp_tbl, &sip, dev, 1); @@ -900,7 +900,7 @@ out_of_mem: static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on) { - if (dev == NULL) { + if (!dev) { IPV4_DEVCONF_ALL(net, PROXY_ARP) = on; return 0; } @@ -926,7 +926,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r, return -ENODEV; } if (mask) { - if (pneigh_lookup(&arp_tbl, net, &ip, dev, 1) == NULL) + if (!pneigh_lookup(&arp_tbl, net, &ip, dev, 1)) return -ENOBUFS; return 0; } @@ -947,7 +947,7 @@ static int arp_req_set(struct net *net, struct arpreq *r, ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; if (r->arp_flags & ATF_PERM) r->arp_flags |= ATF_COM; - if (dev == NULL) { + if (!dev) { struct rtable *rt = ip_route_output(net, ip, 0, RTO_ONLINK, 0); if (IS_ERR(rt)) @@ -1067,7 +1067,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r, return arp_req_delete_public(net, r, dev); ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - if (dev == NULL) { + if (!dev) { struct rtable *rt = ip_route_output(net, ip, 0, RTO_ONLINK, 0); if (IS_ERR(rt)) return PTR_ERR(rt); @@ -1116,7 +1116,7 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) if (r.arp_dev[0]) { err = -ENODEV; dev = __dev_get_by_name(net, r.arp_dev); - if (dev == NULL) + if (!dev) goto out; /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index e361ea6f3fc8..1b28e1183c1b 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -255,7 +255,7 @@ static int __init cipso_v4_cache_init(void) cipso_v4_cache = kcalloc(CIPSO_V4_CACHE_BUCKETS, sizeof(struct cipso_v4_map_cache_bkt), GFP_KERNEL); - if (cipso_v4_cache == NULL) + if (!cipso_v4_cache) return -ENOMEM; for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) { @@ -339,7 +339,7 @@ static int cipso_v4_cache_check(const unsigned char *key, secattr->cache = entry->lsm_data; secattr->flags |= NETLBL_SECATTR_CACHE; secattr->type = NETLBL_NLTYPE_CIPSOV4; - if (prev_entry == NULL) { + if (!prev_entry) { spin_unlock_bh(&cipso_v4_cache[bkt].lock); return 0; } @@ -393,10 +393,10 @@ int cipso_v4_cache_add(const unsigned char *cipso_ptr, cipso_ptr_len = cipso_ptr[1]; entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (entry == NULL) + if (!entry) return -ENOMEM; entry->key = kmemdup(cipso_ptr, cipso_ptr_len, GFP_ATOMIC); - if (entry->key == NULL) { + if (!entry->key) { ret_val = -ENOMEM; goto cache_add_failure; } @@ -547,7 +547,7 @@ doi_add_return: */ void cipso_v4_doi_free(struct cipso_v4_doi *doi_def) { - if (doi_def == NULL) + if (!doi_def) return; switch (doi_def->type) { @@ -598,7 +598,7 @@ int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info) spin_lock(&cipso_v4_doi_list_lock); doi_def = cipso_v4_doi_search(doi); - if (doi_def == NULL) { + if (!doi_def) { spin_unlock(&cipso_v4_doi_list_lock); ret_val = -ENOENT; goto doi_remove_return; @@ -644,7 +644,7 @@ struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) rcu_read_lock(); doi_def = cipso_v4_doi_search(doi); - if (doi_def == NULL) + if (!doi_def) goto doi_getdef_return; if (!atomic_inc_not_zero(&doi_def->refcount)) doi_def = NULL; @@ -664,7 +664,7 @@ doi_getdef_return: */ void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def) { - if (doi_def == NULL) + if (!doi_def) return; if (!atomic_dec_and_test(&doi_def->refcount)) @@ -1642,7 +1642,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) rcu_read_lock(); doi_def = cipso_v4_doi_search(get_unaligned_be32(&opt[2])); - if (doi_def == NULL) { + if (!doi_def) { err_offset = 2; goto validate_return_locked; } @@ -1736,7 +1736,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) * not the loopback device drop the packet. Further, * there is no legitimate reason for setting this from * userspace so reject it if skb is NULL. */ - if (skb == NULL || !(skb->dev->flags & IFF_LOOPBACK)) { + if (!skb || !(skb->dev->flags & IFF_LOOPBACK)) { err_offset = opt_iter; goto validate_return_locked; } @@ -1897,7 +1897,7 @@ int cipso_v4_sock_setattr(struct sock *sk, * defined yet but it is not a problem as the only users of these * "lite" PF_INET sockets are functions which do an accept() call * afterwards so we will label the socket as part of the accept(). */ - if (sk == NULL) + if (!sk) return 0; /* We allocate the maximum CIPSO option size here so we are probably @@ -1905,7 +1905,7 @@ int cipso_v4_sock_setattr(struct sock *sk, * on and after all we are only talking about 40 bytes. */ buf_len = CIPSO_V4_OPT_LEN_MAX; buf = kmalloc(buf_len, GFP_ATOMIC); - if (buf == NULL) { + if (!buf) { ret_val = -ENOMEM; goto socket_setattr_failure; } @@ -1921,7 +1921,7 @@ int cipso_v4_sock_setattr(struct sock *sk, * set the IPOPT_CIPSO option. */ opt_len = (buf_len + 3) & ~3; opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); - if (opt == NULL) { + if (!opt) { ret_val = -ENOMEM; goto socket_setattr_failure; } @@ -1981,7 +1981,7 @@ int cipso_v4_req_setattr(struct request_sock *req, * on and after all we are only talking about 40 bytes. */ buf_len = CIPSO_V4_OPT_LEN_MAX; buf = kmalloc(buf_len, GFP_ATOMIC); - if (buf == NULL) { + if (!buf) { ret_val = -ENOMEM; goto req_setattr_failure; } @@ -1997,7 +1997,7 @@ int cipso_v4_req_setattr(struct request_sock *req, * set the IPOPT_CIPSO option. */ opt_len = (buf_len + 3) & ~3; opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC); - if (opt == NULL) { + if (!opt) { ret_val = -ENOMEM; goto req_setattr_failure; } @@ -2102,7 +2102,7 @@ void cipso_v4_sock_delattr(struct sock *sk) sk_inet = inet_sk(sk); opt = rcu_dereference_protected(sk_inet->inet_opt, 1); - if (opt == NULL || opt->opt.cipso == 0) + if (!opt || opt->opt.cipso == 0) return; hdr_delta = cipso_v4_delopt(&sk_inet->inet_opt); @@ -2128,7 +2128,7 @@ void cipso_v4_req_delattr(struct request_sock *req) req_inet = inet_rsk(req); opt = req_inet->opt; - if (opt == NULL || opt->opt.cipso == 0) + if (!opt || opt->opt.cipso == 0) return; cipso_v4_delopt(&req_inet->opt); @@ -2157,7 +2157,7 @@ int cipso_v4_getattr(const unsigned char *cipso, doi = get_unaligned_be32(&cipso[2]); rcu_read_lock(); doi_def = cipso_v4_doi_search(doi); - if (doi_def == NULL) + if (!doi_def) goto getattr_return; /* XXX - This code assumes only one tag per CIPSO option which isn't * really a good assumption to make but since we only support the MAC diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c6473f365ad1..0ee21689d37e 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -585,7 +585,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) ifm = nlmsg_data(nlh); in_dev = inetdev_by_index(net, ifm->ifa_index); - if (in_dev == NULL) { + if (!in_dev) { err = -ENODEV; goto errout; } @@ -755,21 +755,21 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, ifm = nlmsg_data(nlh); err = -EINVAL; - if (ifm->ifa_prefixlen > 32 || tb[IFA_LOCAL] == NULL) + if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL]) goto errout; dev = __dev_get_by_index(net, ifm->ifa_index); err = -ENODEV; - if (dev == NULL) + if (!dev) goto errout; in_dev = __in_dev_get_rtnl(dev); err = -ENOBUFS; - if (in_dev == NULL) + if (!in_dev) goto errout; ifa = inet_alloc_ifa(); - if (ifa == NULL) + if (!ifa) /* * A potential indev allocation can be left alive, it stays * assigned to its device and is destroy with it. @@ -780,7 +780,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, neigh_parms_data_state_setall(in_dev->arp_parms); in_dev_hold(in_dev); - if (tb[IFA_ADDRESS] == NULL) + if (!tb[IFA_ADDRESS]) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; INIT_HLIST_NODE(&ifa->hash); @@ -1340,7 +1340,7 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev) if (named++ == 0) goto skip; dot = strchr(old, ':'); - if (dot == NULL) { + if (!dot) { sprintf(old, ":%d", named); dot = old; } @@ -1509,7 +1509,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, u32 preferred, valid; nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags); - if (nlh == NULL) + if (!nlh) return -EMSGSIZE; ifm = nlmsg_data(nlh); @@ -1628,7 +1628,7 @@ static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, net = dev_net(ifa->ifa_dev->dev); skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL); - if (skb == NULL) + if (!skb) goto errout; err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0); @@ -1665,7 +1665,7 @@ static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev) return -ENODATA; nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4); - if (nla == NULL) + if (!nla) return -EMSGSIZE; for (i = 0; i < IPV4_DEVCONF_MAX; i++) @@ -1754,7 +1754,7 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg), flags); - if (nlh == NULL) + if (!nlh) return -EMSGSIZE; ncm = nlmsg_data(nlh); @@ -1796,7 +1796,7 @@ void inet_netconf_notify_devconf(struct net *net, int type, int ifindex, int err = -ENOBUFS; skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_ATOMIC); - if (skb == NULL) + if (!skb) goto errout; err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0, @@ -1853,10 +1853,10 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb, break; default: dev = __dev_get_by_index(net, ifindex); - if (dev == NULL) + if (!dev) goto errout; in_dev = __in_dev_get_rtnl(dev); - if (in_dev == NULL) + if (!in_dev) goto errout; devconf = &in_dev->cnf; break; @@ -1864,7 +1864,7 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb, err = -ENOBUFS; skb = nlmsg_new(inet_netconf_msgsize_devconf(-1), GFP_ATOMIC); - if (skb == NULL) + if (!skb) goto errout; err = inet_netconf_fill_devconf(skb, ifindex, devconf, @@ -2215,7 +2215,7 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf) { struct devinet_sysctl_table *t = cnf->sysctl; - if (t == NULL) + if (!t) return; cnf->sysctl = NULL; @@ -2276,16 +2276,16 @@ static __net_init int devinet_init_net(struct net *net) if (!net_eq(net, &init_net)) { all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL); - if (all == NULL) + if (!all) goto err_alloc_all; dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL); - if (dflt == NULL) + if (!dflt) goto err_alloc_dflt; #ifdef CONFIG_SYSCTL tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL); - if (tbl == NULL) + if (!tbl) goto err_alloc_ctl; tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1]; @@ -2305,7 +2305,7 @@ static __net_init int devinet_init_net(struct net *net) err = -ENOMEM; forw_hdr = register_net_sysctl(net, "net/ipv4", tbl); - if (forw_hdr == NULL) + if (!forw_hdr) goto err_reg_ctl; net->ipv4.forw_hdr = forw_hdr; #endif diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 60173d4d3a0e..421a80b09b62 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -553,7 +553,7 @@ static int esp_init_authenc(struct xfrm_state *x) int err; err = -EINVAL; - if (x->ealg == NULL) + if (!x->ealg) goto error; err = -ENAMETOOLONG; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 718b0a16ea40..2166d2bf1562 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -53,11 +53,11 @@ static int __net_init fib4_rules_init(struct net *net) struct fib_table *local_table, *main_table; main_table = fib_trie_table(RT_TABLE_MAIN, NULL); - if (main_table == NULL) + if (!main_table) return -ENOMEM; local_table = fib_trie_table(RT_TABLE_LOCAL, main_table); - if (local_table == NULL) + if (!local_table) goto fail; hlist_add_head_rcu(&local_table->tb_hlist, @@ -486,7 +486,7 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt, for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) if (strcmp(ifa->ifa_label, devname) == 0) break; - if (ifa == NULL) + if (!ifa) return -ENODEV; cfg->fc_prefsrc = ifa->ifa_local; } @@ -514,7 +514,7 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt, int len = 0; mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL); - if (mx == NULL) + if (!mx) return -ENOMEM; if (rt->rt_flags & RTF_MTU) @@ -676,7 +676,7 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) goto errout; tb = fib_get_table(net, cfg.fc_table); - if (tb == NULL) { + if (!tb) { err = -ESRCH; goto errout; } @@ -698,7 +698,7 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) goto errout; tb = fib_new_table(net, cfg.fc_table); - if (tb == NULL) { + if (!tb) { err = -ENOBUFS; goto errout; } @@ -779,7 +779,7 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad else tb = fib_new_table(net, RT_TABLE_LOCAL); - if (tb == NULL) + if (!tb) return; cfg.fc_table = tb->tb_id; @@ -806,7 +806,7 @@ void fib_add_ifaddr(struct in_ifaddr *ifa) if (ifa->ifa_flags & IFA_F_SECONDARY) { prim = inet_ifa_byprefix(in_dev, prefix, mask); - if (prim == NULL) { + if (!prim) { pr_warn("%s: bug: prim == NULL\n", __func__); return; } @@ -860,7 +860,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) if (ifa->ifa_flags & IFA_F_SECONDARY) { prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); - if (prim == NULL) { + if (!prim) { pr_warn("%s: bug: prim == NULL\n", __func__); return; } @@ -1030,7 +1030,7 @@ static void nl_fib_input(struct sk_buff *skb) return; skb = netlink_skb_clone(skb, GFP_KERNEL); - if (skb == NULL) + if (!skb) return; nlh = nlmsg_hdr(skb); @@ -1051,7 +1051,7 @@ static int __net_init nl_fib_lookup_init(struct net *net) }; sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, &cfg); - if (sk == NULL) + if (!sk) return -EAFNOSUPPORT; net->ipv4.fibnl = sk; return 0; @@ -1089,7 +1089,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, case NETDEV_DOWN: fib_del_ifaddr(ifa, NULL); atomic_inc(&net->ipv4.dev_addr_genid); - if (ifa->ifa_dev->ifa_list == NULL) { + if (!ifa->ifa_dev->ifa_list) { /* Last address was deleted from this interface. * Disable IP. */ @@ -1157,7 +1157,7 @@ static int __net_init ip_fib_net_init(struct net *net) size = max_t(size_t, size, L1_CACHE_BYTES); net->ipv4.fib_table_hash = kzalloc(size, GFP_KERNEL); - if (net->ipv4.fib_table_hash == NULL) + if (!net->ipv4.fib_table_hash) return -ENOMEM; err = fib4_rules_init(net); diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 8162dd8e86d7..56151982f74e 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -153,7 +153,7 @@ static struct fib_table *fib_empty_table(struct net *net) u32 id; for (id = 1; id <= RT_TABLE_MAX; id++) - if (fib_get_table(net, id) == NULL) + if (!fib_get_table(net, id)) return fib_new_table(net, id); return NULL; } @@ -184,7 +184,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, struct fib_table *table; table = fib_empty_table(net); - if (table == NULL) { + if (!table) { err = -ENOBUFS; goto errout; } diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index eac5aec7772a..8d695b6659c7 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -390,7 +390,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int err = -ENOBUFS; skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL); - if (skb == NULL) + if (!skb) goto errout; err = fib_dump_info(skb, info->portid, seq, event, tb_id, @@ -503,7 +503,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) } #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (cfg->fc_mp == NULL) + if (!cfg->fc_mp) return 0; rtnh = cfg->fc_mp; @@ -646,7 +646,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, rcu_read_lock(); err = -ENODEV; in_dev = inetdev_by_index(net, nh->nh_oif); - if (in_dev == NULL) + if (!in_dev) goto out; err = -ENETDOWN; if (!(in_dev->dev->flags & IFF_UP)) @@ -803,7 +803,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) } fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (fi == NULL) + if (!fi) goto failure; fib_info_cnt++; if (cfg->fc_mx) { @@ -921,7 +921,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) nh->nh_scope = RT_SCOPE_NOWHERE; nh->nh_dev = dev_get_by_index(net, fi->fib_nh->nh_oif); err = -ENODEV; - if (nh->nh_dev == NULL) + if (!nh->nh_dev) goto failure; } else { change_nexthops(fi) { @@ -995,7 +995,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, struct rtmsg *rtm; nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags); - if (nlh == NULL) + if (!nlh) return -EMSGSIZE; rtm = nlmsg_data(nlh); @@ -1045,12 +1045,12 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, struct nlattr *mp; mp = nla_nest_start(skb, RTA_MULTIPATH); - if (mp == NULL) + if (!mp) goto nla_put_failure; for_nexthops(fi) { rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh)); - if (rtnh == NULL) + if (!rtnh) goto nla_put_failure; rtnh->rtnh_flags = nh->nh_flags & 0xFF; @@ -1093,7 +1093,7 @@ int fib_sync_down_addr(struct net *net, __be32 local) struct hlist_head *head = &fib_info_laddrhash[hash]; struct fib_info *fi; - if (fib_info_laddrhash == NULL || local == 0) + if (!fib_info_laddrhash || local == 0) return 0; hlist_for_each_entry(fi, head, fib_lhash) { @@ -1182,7 +1182,7 @@ void fib_select_default(struct fib_result *res) fib_alias_accessed(fa); - if (fi == NULL) { + if (!fi) { if (next_fi != res->fi) break; } else if (!fib_detect_death(fi, order, &last_resort, @@ -1195,7 +1195,7 @@ void fib_select_default(struct fib_result *res) order++; } - if (order <= 0 || fi == NULL) { + if (order <= 0 || !fi) { tb->tb_default = -1; goto out; } @@ -1251,7 +1251,7 @@ int fib_sync_up(struct net_device *dev) alive++; continue; } - if (nexthop_nh->nh_dev == NULL || + if (!nexthop_nh->nh_dev || !(nexthop_nh->nh_dev->flags & IFF_UP)) continue; if (nexthop_nh->nh_dev != dev || diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 2c7c299ee2b9..9e4a3e3423b4 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -391,9 +391,9 @@ static void put_child(struct key_vector *tn, unsigned long i, BUG_ON(i >= child_length(tn)); /* update emptyChildren, overflow into fullChildren */ - if (n == NULL && chi != NULL) + if (!n && chi != NULL) empty_child_inc(tn); - if (n != NULL && chi == NULL) + if (n != NULL && !chi) empty_child_dec(tn); /* update fullChildren */ @@ -528,7 +528,7 @@ static struct key_vector *inflate(struct trie *t, unsigned long j, k; /* An empty child */ - if (inode == NULL) + if (!inode) continue; /* A leaf or an internal node with skipped bits */ @@ -1154,7 +1154,7 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) } err = -ENOBUFS; new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); - if (new_fa == NULL) + if (!new_fa) goto out; fi_drop = fa->fa_info; @@ -1204,7 +1204,7 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) err = -ENOBUFS; new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); - if (new_fa == NULL) + if (!new_fa) goto out; new_fa->fa_info = fi; @@ -1975,7 +1975,7 @@ struct fib_table *fib_trie_table(u32 id, struct fib_table *alias) sz += sizeof(struct trie); tb = kzalloc(sz, GFP_KERNEL); - if (tb == NULL) + if (!tb) return NULL; tb->tb_id = id; diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c index 5a4828ba05ad..a7d8be3dd3de 100644 --- a/net/ipv4/geneve.c +++ b/net/ipv4/geneve.c @@ -196,7 +196,7 @@ static struct sk_buff **geneve_gro_receive(struct sk_buff **head, rcu_read_lock(); ptype = gro_find_receive_by_type(type); - if (ptype == NULL) { + if (!ptype) { flush = 1; goto out_unlock; } diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 51973ddc05a6..9358f11aae40 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -149,7 +149,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head, rcu_read_lock(); ptype = gro_find_receive_by_type(type); - if (ptype == NULL) + if (!ptype) goto out_unlock; grehlen = GRE_HEADER_SECTION; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 5e564014a0b7..f5203fba6236 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -399,7 +399,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) return; sk = icmp_xmit_lock(net); - if (sk == NULL) + if (!sk) return; inet = inet_sk(sk); @@ -609,7 +609,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) skb_in->data, sizeof(_inner_type), &_inner_type); - if (itp == NULL) + if (!itp) goto out; /* @@ -627,7 +627,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) return; sk = icmp_xmit_lock(net); - if (sk == NULL) + if (!sk) goto out_free; /* diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index ad09213ac5b2..27d204b834f9 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -692,7 +692,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, hlen = LL_RESERVED_SPACE(dev); tlen = dev->needed_tailroom; skb = alloc_skb(IGMP_SIZE + hlen + tlen, GFP_ATOMIC); - if (skb == NULL) { + if (!skb) { ip_rt_put(rt); return -1; } @@ -981,7 +981,7 @@ int igmp_rcv(struct sk_buff *skb) int len = skb->len; bool dropped = true; - if (in_dev == NULL) + if (!in_dev) goto drop; if (!pskb_may_pull(skb, sizeof(struct igmphdr))) @@ -1888,7 +1888,7 @@ int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr) if (count >= sysctl_igmp_max_memberships) goto done; iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); - if (iml == NULL) + if (!iml) goto done; memcpy(&iml->multi, imr, sizeof(*imr)); @@ -1909,7 +1909,7 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, struct ip_sf_socklist *psf = rtnl_dereference(iml->sflist); int err; - if (psf == NULL) { + if (!psf) { /* any-source empty exclude case */ return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, iml->sfmode, 0, NULL, 0); @@ -2360,7 +2360,7 @@ void ip_mc_drop_socket(struct sock *sk) struct ip_mc_socklist *iml; struct net *net = sock_net(sk); - if (inet->mc_list == NULL) + if (!inet->mc_list) return; rtnl_lock(); @@ -2587,7 +2587,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) for_each_netdev_rcu(net, state->dev) { struct in_device *idev; idev = __in_dev_get_rcu(state->dev); - if (unlikely(idev == NULL)) + if (unlikely(!idev)) continue; im = rcu_dereference(idev->mc_list); if (likely(im != NULL)) { diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index e7920352646a..5e346a082e5f 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -385,7 +385,7 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, } q = kmem_cache_zalloc(f->frags_cachep, GFP_ATOMIC); - if (q == NULL) + if (!q) return NULL; q->net = nf; @@ -406,7 +406,7 @@ static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf, struct inet_frag_queue *q; q = inet_frag_alloc(nf, f, arg); - if (q == NULL) + if (!q) return NULL; return inet_frag_intern(nf, q, f, arg); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 145a50c4d566..5a6cf8667a9d 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -372,7 +372,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) goto err; err = -ENOMEM; - if (pskb_pull(skb, ihl) == NULL) + if (!pskb_pull(skb, ihl)) goto err; err = pskb_trim_rcsum(skb, end - offset); @@ -537,7 +537,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, qp->q.fragments = head; } - WARN_ON(head == NULL); + WARN_ON(!head); WARN_ON(FRAG_CB(head)->offset != 0); /* Allocate a new buffer for the datagram. */ @@ -559,7 +559,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, struct sk_buff *clone; int i, plen = 0; - if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) + clone = alloc_skb(0, GFP_ATOMIC); + if (!clone) goto out_nomem; clone->next = head->next; head->next = clone; @@ -754,7 +755,7 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net) table = ip4_frags_ns_ctl_table; if (!net_eq(net, &init_net)) { table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL); - if (table == NULL) + if (!table) goto err_alloc; table[0].data = &net->ipv4.frags.high_thresh; @@ -770,7 +771,7 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net) } hdr = register_net_sysctl(net, "net/ipv4", table); - if (hdr == NULL) + if (!hdr) goto err_reg; net->ipv4.frags_hdr = hdr; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 1060ca0bc23a..5fd706473c73 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -182,7 +182,7 @@ static int ipgre_err(struct sk_buff *skb, u32 info, t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, iph->daddr, iph->saddr, tpi->key); - if (t == NULL) + if (!t) return PACKET_REJECT; if (t->parms.iph.daddr == 0 || @@ -423,7 +423,7 @@ static int ipgre_open(struct net_device *dev) return -EADDRNOTAVAIL; dev = rt->dst.dev; ip_rt_put(rt); - if (__in_dev_get_rtnl(dev) == NULL) + if (!__in_dev_get_rtnl(dev)) return -EADDRNOTAVAIL; t->mlink = dev->ifindex; ip_mc_inc_group(__in_dev_get_rtnl(dev), t->parms.iph.daddr); diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 3d4da2c16b6a..00bed6fe3b66 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -314,7 +314,7 @@ static int ip_rcv_finish(struct sk_buff *skb) const struct iphdr *iph = ip_hdr(skb); struct rtable *rt; - if (sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) { + if (sysctl_ip_early_demux && !skb_dst(skb) && !skb->sk) { const struct net_protocol *ipprot; int protocol = iph->protocol; @@ -387,7 +387,8 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, IP_UPD_PO_STATS_BH(dev_net(dev), IPSTATS_MIB_IN, skb->len); - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) { IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); goto out; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8259e777b249..561d67b2ac74 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -182,7 +182,7 @@ static inline int ip_finish_output2(struct sk_buff *skb) struct sk_buff *skb2; skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev)); - if (skb2 == NULL) { + if (!skb2) { kfree_skb(skb); return -ENOMEM; } @@ -381,7 +381,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl) /* Make sure we can route this packet. */ rt = (struct rtable *)__sk_dst_check(sk, 0); - if (rt == NULL) { + if (!rt) { __be32 daddr; /* Use correct destination address if we have options. */ @@ -790,12 +790,13 @@ static inline int ip_ufo_append_data(struct sock *sk, * device, so create one single skb packet containing complete * udp datagram */ - if ((skb = skb_peek_tail(queue)) == NULL) { + skb = skb_peek_tail(queue); + if (!skb) { skb = sock_alloc_send_skb(sk, hh_len + fragheaderlen + transhdrlen + 20, (flags & MSG_DONTWAIT), &err); - if (skb == NULL) + if (!skb) return err; /* reserve space for Hardware header */ @@ -961,10 +962,10 @@ alloc_new_skb: skb = sock_wmalloc(sk, alloclen + hh_len + 15, 1, sk->sk_allocation); - if (unlikely(skb == NULL)) + if (unlikely(!skb)) err = -ENOBUFS; } - if (skb == NULL) + if (!skb) goto error; /* @@ -1088,10 +1089,10 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, */ opt = ipc->opt; if (opt) { - if (cork->opt == NULL) { + if (!cork->opt) { cork->opt = kmalloc(sizeof(struct ip_options) + 40, sk->sk_allocation); - if (unlikely(cork->opt == NULL)) + if (unlikely(!cork->opt)) return -ENOBUFS; } memcpy(cork->opt, &opt->opt, sizeof(struct ip_options) + opt->opt.optlen); @@ -1198,7 +1199,8 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, return -EMSGSIZE; } - if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) + skb = skb_peek_tail(&sk->sk_write_queue); + if (!skb) return -EINVAL; cork->length += size; @@ -1329,7 +1331,8 @@ struct sk_buff *__ip_make_skb(struct sock *sk, __be16 df = 0; __u8 ttl; - if ((skb = __skb_dequeue(queue)) == NULL) + skb = __skb_dequeue(queue); + if (!skb) goto out; tail_skb = &(skb_shinfo(skb)->frag_list); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index f6a0d54b308a..f64b1b24c64f 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -351,7 +351,7 @@ int ip_ra_control(struct sock *sk, unsigned char on, return 0; } } - if (new_ra == NULL) { + if (!new_ra) { spin_unlock_bh(&ip_ra_lock); return -ENOBUFS; } @@ -482,7 +482,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) err = -EAGAIN; skb = sock_dequeue_err_skb(sk); - if (skb == NULL) + if (!skb) goto out; copied = skb->len; diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 4bb7252110a6..31eaa9ba1803 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -654,7 +654,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, if (dst == 0) { /* NBMA tunnel */ - if (skb_dst(skb) == NULL) { + if (!skb_dst(skb)) { dev->stats.tx_fifo_errors++; goto tx_error; } @@ -672,7 +672,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, neigh = dst_neigh_lookup(skb_dst(skb), &ipv6_hdr(skb)->daddr); - if (neigh == NULL) + if (!neigh) goto tx_error; addr6 = (const struct in6_addr *)&neigh->primary_key; @@ -843,7 +843,7 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) case SIOCGETTUNNEL: if (dev == itn->fb_tunnel_dev) { t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); - if (t == NULL) + if (!t) t = netdev_priv(dev); } memcpy(p, &t->parms, sizeof(*p)); @@ -914,7 +914,7 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) if (dev == itn->fb_tunnel_dev) { err = -ENOENT; t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); - if (t == NULL) + if (!t) goto done; err = -EPERM; if (t == netdev_priv(itn->fb_tunnel_dev)) diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index c0855d50a3fa..d97f4f2787f5 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -63,7 +63,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) struct xfrm_state *t; t = xfrm_state_alloc(net); - if (t == NULL) + if (!t) goto out; t->id.proto = IPPROTO_IPIP; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index b26376ef87f6..8e7328c6a390 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -504,7 +504,8 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (!net_eq(dev_net(dev), &init_net)) goto drop; - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) return NET_RX_DROP; if (!pskb_may_pull(skb, sizeof(struct arphdr))) @@ -958,7 +959,8 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str if (skb->pkt_type == PACKET_OTHERHOST) goto drop; - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) return NET_RX_DROP; if (!pskb_may_pull(skb, diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 5c81f6e40842..ff96396ebec5 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -144,7 +144,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) err = -ENOENT; t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, iph->daddr, iph->saddr, 0); - if (t == NULL) + if (!t) goto out; if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 3ef30cf57f4a..a170e4bc9006 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -189,7 +189,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp, } mrt = ipmr_get_table(rule->fr_net, rule->table); - if (mrt == NULL) + if (!mrt) return -EAGAIN; res->mrt = mrt; return 0; @@ -253,7 +253,7 @@ static int __net_init ipmr_rules_init(struct net *net) INIT_LIST_HEAD(&net->ipv4.mr_tables); mrt = ipmr_new_table(net, RT_TABLE_DEFAULT); - if (mrt == NULL) { + if (!mrt) { err = -ENOMEM; goto err1; } @@ -320,7 +320,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) return mrt; mrt = kzalloc(sizeof(*mrt), GFP_KERNEL); - if (mrt == NULL) + if (!mrt) return NULL; write_pnet(&mrt->net, net); mrt->id = id; @@ -422,7 +422,7 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) dev->flags |= IFF_MULTICAST; in_dev = __in_dev_get_rtnl(dev); - if (in_dev == NULL) + if (!in_dev) goto failure; ipv4_devconf_setall(in_dev); @@ -506,7 +506,7 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup); - if (dev == NULL) + if (!dev) return NULL; dev_net_set(dev, net); @@ -762,7 +762,7 @@ static int vif_add(struct net *net, struct mr_table *mrt, case 0: if (vifc->vifc_flags == VIFF_USE_IFINDEX) { dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex); - if (dev && __in_dev_get_rtnl(dev) == NULL) { + if (dev && !__in_dev_get_rtnl(dev)) { dev_put(dev); return -EADDRNOTAVAIL; } @@ -1008,7 +1008,7 @@ static int ipmr_cache_report(struct mr_table *mrt, rcu_read_lock(); mroute_sk = rcu_dereference(mrt->mroute_sk); - if (mroute_sk == NULL) { + if (!mroute_sk) { rcu_read_unlock(); kfree_skb(skb); return -EINVAL; @@ -1161,7 +1161,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, return -EINVAL; c = ipmr_cache_alloc(); - if (c == NULL) + if (!c) return -ENOMEM; c->mfc_origin = mfc->mfcc_origin.s_addr; @@ -1283,7 +1283,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi return -EOPNOTSUPP; mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); - if (mrt == NULL) + if (!mrt) return -ENOENT; if (optname != MRT_INIT) { @@ -1446,7 +1446,7 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int return -EOPNOTSUPP; mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); - if (mrt == NULL) + if (!mrt) return -ENOENT; if (optname != MRT_VERSION && @@ -1492,7 +1492,7 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) struct mr_table *mrt; mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); - if (mrt == NULL) + if (!mrt) return -ENOENT; switch (cmd) { @@ -1566,7 +1566,7 @@ int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) struct mr_table *mrt; mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); - if (mrt == NULL) + if (!mrt) return -ENOENT; switch (cmd) { @@ -1701,7 +1701,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, struct flowi4 fl4; int encap = 0; - if (vif->dev == NULL) + if (!vif->dev) goto out_free; #ifdef CONFIG_IP_PIMSM @@ -1992,7 +1992,7 @@ int ip_mr_input(struct sk_buff *skb) /* already under rcu_read_lock() */ cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr); - if (cache == NULL) { + if (!cache) { int vif = ipmr_find_vif(mrt, skb->dev); if (vif >= 0) @@ -2003,13 +2003,13 @@ int ip_mr_input(struct sk_buff *skb) /* * No usable cache entry */ - if (cache == NULL) { + if (!cache) { int vif; if (local) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); ip_local_deliver(skb); - if (skb2 == NULL) + if (!skb2) return -ENOBUFS; skb = skb2; } @@ -2068,7 +2068,7 @@ static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb, reg_dev = mrt->vif_table[mrt->mroute_reg_vif_num].dev; read_unlock(&mrt_lock); - if (reg_dev == NULL) + if (!reg_dev) return 1; skb->mac_header = skb->network_header; @@ -2198,18 +2198,18 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb, int err; mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); - if (mrt == NULL) + if (!mrt) return -ENOENT; rcu_read_lock(); cache = ipmr_cache_find(mrt, saddr, daddr); - if (cache == NULL && skb->dev) { + if (!cache && skb->dev) { int vif = ipmr_find_vif(mrt, skb->dev); if (vif >= 0) cache = ipmr_cache_find_any(mrt, daddr, vif); } - if (cache == NULL) { + if (!cache) { struct sk_buff *skb2; struct iphdr *iph; struct net_device *dev; @@ -2267,7 +2267,7 @@ static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, int err; nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags); - if (nlh == NULL) + if (!nlh) return -EMSGSIZE; rtm = nlmsg_data(nlh); @@ -2332,7 +2332,7 @@ static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, skb = nlmsg_new(mroute_msgsize(mfc->mfc_parent >= MAXVIFS, mrt->maxvif), GFP_ATOMIC); - if (skb == NULL) + if (!skb) goto errout; err = ipmr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0); @@ -2447,7 +2447,7 @@ static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos) struct mr_table *mrt; mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); - if (mrt == NULL) + if (!mrt) return ERR_PTR(-ENOENT); iter->mrt = mrt; @@ -2566,7 +2566,7 @@ static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) struct mr_table *mrt; mrt = ipmr_get_table(net, RT_TABLE_DEFAULT); - if (mrt == NULL) + if (!mrt) return ERR_PTR(-ENOENT); it->mrt = mrt; diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 344e7cdfb8d4..2dcd2e60df64 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -516,7 +516,7 @@ void ping_err(struct sk_buff *skb, int offset, u32 info) ntohs(icmph->un.echo.sequence)); sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id)); - if (sk == NULL) { + if (!sk) { pr_debug("no socket, dropping\n"); return; /* No socket for error */ } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 56946f47d446..46a78204189d 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -363,7 +363,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, skb = sock_alloc_send_skb(sk, length + hlen + tlen + 15, flags & MSG_DONTWAIT, &err); - if (skb == NULL) + if (!skb) goto error; skb_reserve(skb, hlen); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 652b92ebd7ba..26a1cb348b3d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1056,7 +1056,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); rt = (struct rtable *)odst; - if (odst->obsolete && odst->ops->check(odst, 0) == NULL) { + if (odst->obsolete && !odst->ops->check(odst, 0)) { rt = ip_route_output_flow(sock_net(sk), &fl4, sk); if (IS_ERR(rt)) goto out; @@ -1450,7 +1450,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, /* Primary sanity checks. */ - if (in_dev == NULL) + if (!in_dev) return -EINVAL; if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || @@ -1553,7 +1553,7 @@ static int __mkroute_input(struct sk_buff *skb, /* get a working reference to the output device */ out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res)); - if (out_dev == NULL) { + if (!out_dev) { net_crit_ratelimited("Bug in ip_route_input_slow(). Please report.\n"); return -EINVAL; } @@ -2054,7 +2054,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4) ipv4_is_lbcast(fl4->daddr))) { /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ dev_out = __ip_dev_find(net, fl4->saddr, false); - if (dev_out == NULL) + if (!dev_out) goto out; /* Special hack: user can direct multicasts @@ -2087,7 +2087,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4) if (fl4->flowi4_oif) { dev_out = dev_get_by_index_rcu(net, fl4->flowi4_oif); rth = ERR_PTR(-ENODEV); - if (dev_out == NULL) + if (!dev_out) goto out; /* RACE: Check return value of inet_select_addr instead. */ @@ -2299,7 +2299,7 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 metrics[RTAX_MAX]; nlh = nlmsg_put(skb, portid, seq, event, sizeof(*r), flags); - if (nlh == NULL) + if (!nlh) return -EMSGSIZE; r = nlmsg_data(nlh); @@ -2421,7 +2421,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) rtm = nlmsg_data(nlh); skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); - if (skb == NULL) { + if (!skb) { err = -ENOBUFS; goto errout; } @@ -2452,7 +2452,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) struct net_device *dev; dev = __dev_get_by_index(net, iif); - if (dev == NULL) { + if (!dev) { err = -ENODEV; goto errout_free; } @@ -2651,7 +2651,7 @@ static __net_init int sysctl_route_net_init(struct net *net) tbl = ipv4_route_flush_table; if (!net_eq(net, &init_net)) { tbl = kmemdup(tbl, sizeof(ipv4_route_flush_table), GFP_KERNEL); - if (tbl == NULL) + if (!tbl) goto err_dup; /* Don't export sysctls to unprivileged users */ @@ -2661,7 +2661,7 @@ static __net_init int sysctl_route_net_init(struct net *net) tbl[0].extra1 = net; net->ipv4.route_hdr = register_net_sysctl(net, "net/ipv4/route", tbl); - if (net->ipv4.route_hdr == NULL) + if (!net->ipv4.route_hdr) goto err_reg; return 0; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index fdf899163d44..c3852a7ff3c7 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -909,7 +909,7 @@ static __net_init int ipv4_sysctl_init_net(struct net *net) int i; table = kmemdup(table, sizeof(ipv4_net_table), GFP_KERNEL); - if (table == NULL) + if (!table) goto err_alloc; /* Update the variables to point into the current struct net */ @@ -918,7 +918,7 @@ static __net_init int ipv4_sysctl_init_net(struct net *net) } net->ipv4.ipv4_hdr = register_net_sysctl(net, "net/ipv4", table); - if (net->ipv4.ipv4_hdr == NULL) + if (!net->ipv4.ipv4_hdr) goto err_reg; net->ipv4.sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL); @@ -956,7 +956,7 @@ static __init int sysctl_ipv4_init(void) struct ctl_table_header *hdr; hdr = register_net_sysctl(&init_net, "net/ipv4", ipv4_table); - if (hdr == NULL) + if (!hdr) return -ENOMEM; if (register_pernet_subsys(&ipv4_sysctl_ops)) { diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index dbd51cefaf02..5bd809bfd0aa 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1047,7 +1047,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, tp->fastopen_req = kzalloc(sizeof(struct tcp_fastopen_request), sk->sk_allocation); - if (unlikely(tp->fastopen_req == NULL)) + if (unlikely(!tp->fastopen_req)) return -ENOBUFS; tp->fastopen_req->data = msg; tp->fastopen_req->size = size; diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 2eb887ec0ce3..5da55e2b5cd2 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -141,7 +141,7 @@ static bool tcp_fastopen_create_child(struct sock *sk, req->sk = NULL; child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL); - if (child == NULL) + if (!child) return false; spin_lock(&queue->fastopenq->lock); @@ -214,7 +214,7 @@ static bool tcp_fastopen_create_child(struct sock *sk, sk->sk_data_ready(sk); bh_unlock_sock(child); sock_put(child); - WARN_ON(req->sk == NULL); + WARN_ON(!req->sk); return true; } @@ -233,7 +233,7 @@ static bool tcp_fastopen_queue_check(struct sock *sk) * temporarily vs a server not supporting Fast Open at all. */ fastopenq = inet_csk(sk)->icsk_accept_queue.fastopenq; - if (fastopenq == NULL || fastopenq->max_qlen == 0) + if (!fastopenq || fastopenq->max_qlen == 0) return false; if (fastopenq->qlen >= fastopenq->max_qlen) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 18b80e8bc533..1fd283684303 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -866,7 +866,7 @@ static void tcp_update_reordering(struct sock *sk, const int metric, /* This must be called before lost_out is incremented */ static void tcp_verify_retransmit_hint(struct tcp_sock *tp, struct sk_buff *skb) { - if ((tp->retransmit_skb_hint == NULL) || + if (!tp->retransmit_skb_hint || before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) tp->retransmit_skb_hint = skb; @@ -1614,7 +1614,7 @@ static struct sk_buff *tcp_maybe_skipping_dsack(struct sk_buff *skb, struct tcp_sacktag_state *state, u32 skip_to_seq) { - if (next_dup == NULL) + if (!next_dup) return skb; if (before(next_dup->start_seq, skip_to_seq)) { @@ -1783,7 +1783,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, if (tcp_highest_sack_seq(tp) == cache->end_seq) { /* ...but better entrypoint exists! */ skb = tcp_highest_sack(sk); - if (skb == NULL) + if (!skb) break; state.fack_count = tp->fackets_out; cache++; @@ -1798,7 +1798,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, if (!before(start_seq, tcp_highest_sack_seq(tp))) { skb = tcp_highest_sack(sk); - if (skb == NULL) + if (!skb) break; state.fack_count = tp->fackets_out; } @@ -3698,7 +3698,7 @@ void tcp_parse_options(const struct sk_buff *skb, */ if (opsize < TCPOLEN_EXP_FASTOPEN_BASE || get_unaligned_be16(ptr) != TCPOPT_FASTOPEN_MAGIC || - foc == NULL || !th->syn || (opsize & 1)) + !foc || !th->syn || (opsize & 1)) break; foc->len = opsize - TCPOLEN_EXP_FASTOPEN_BASE; if (foc->len >= TCP_FASTOPEN_COOKIE_MIN && @@ -4669,7 +4669,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) struct sk_buff *head; u32 start, end; - if (skb == NULL) + if (!skb) return; start = TCP_SKB_CB(skb)->seq; @@ -5124,7 +5124,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, { struct tcp_sock *tp = tcp_sk(sk); - if (unlikely(sk->sk_rx_dst == NULL)) + if (unlikely(!sk->sk_rx_dst)) inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb); /* * Header prediction. @@ -5694,7 +5694,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV && sk->sk_state != TCP_FIN_WAIT1); - if (tcp_check_req(sk, skb, req, true) == NULL) + if (!tcp_check_req(sk, skb, req, true)) goto discard; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 69f9cf684744..9ff311cf00f3 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -122,7 +122,7 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp) and use initial timestamp retrieved from peer table. */ if (tcptw->tw_ts_recent_stamp && - (twp == NULL || (sysctl_tcp_tw_reuse && + (!twp || (sysctl_tcp_tw_reuse && get_seconds() - tcptw->tw_ts_recent_stamp > 1))) { tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2; if (tp->write_seq == 0) @@ -494,7 +494,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) /* Only in fast or simultaneous open. If a fast open socket is * is already accepted it is treated as a connected one below. */ - if (fastopen && fastopen->sk == NULL) + if (fastopen && !fastopen->sk) break; if (!sock_owned_by_user(sk)) { @@ -1390,7 +1390,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) sk_mark_napi_id(sk, skb); if (dst) { if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif || - dst->ops->check(dst, 0) == NULL) { + !dst->ops->check(dst, 0)) { dst_release(dst); sk->sk_rx_dst = NULL; } diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 71ec14c87579..78ecc4a01712 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -505,7 +505,7 @@ void tcp_init_metrics(struct sock *sk) struct tcp_metrics_block *tm; u32 val, crtt = 0; /* cached RTT scaled by 8 */ - if (dst == NULL) + if (!dst) goto reset; dst_confirm(dst); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 274e96fb369b..f0db1599a09c 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -763,7 +763,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, * socket is created, wait for troubles. */ child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL); - if (child == NULL) + if (!child) goto listen_overflow; inet_csk_reqsk_queue_unlink(sk, req); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 2e69b8d16e68..bdc80734cd2c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -565,7 +565,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb, opts->mss = tcp_advertise_mss(sk); remaining -= TCPOLEN_MSS_ALIGNED; - if (likely(sysctl_tcp_timestamps && *md5 == NULL)) { + if (likely(sysctl_tcp_timestamps && !*md5)) { opts->options |= OPTION_TS; opts->tsval = tcp_skb_timestamp(skb) + tp->tsoffset; opts->tsecr = tp->rx_opt.ts_recent; @@ -1148,7 +1148,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, /* Get a new skb... force flag on. */ buff = sk_stream_alloc_skb(sk, nsize, gfp); - if (buff == NULL) + if (!buff) return -ENOMEM; /* We'll just try again later. */ sk->sk_wmem_queued += buff->truesize; @@ -1707,7 +1707,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, return tcp_fragment(sk, skb, len, mss_now, gfp); buff = sk_stream_alloc_skb(sk, 0, gfp); - if (unlikely(buff == NULL)) + if (unlikely(!buff)) return -ENOMEM; sk->sk_wmem_queued += buff->truesize; @@ -1925,7 +1925,8 @@ static int tcp_mtu_probe(struct sock *sk) } /* We're allowed to probe. Build it now. */ - if ((nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC)) == NULL) + nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC); + if (!nskb) return -1; sk->sk_wmem_queued += nskb->truesize; sk_mem_charge(sk, nskb->truesize); @@ -2733,7 +2734,7 @@ void tcp_xmit_retransmit_queue(struct sock *sk) if (skb == tcp_send_head(sk)) break; /* we could do better than to assign each time */ - if (hole == NULL) + if (!hole) tp->retransmit_skb_hint = skb; /* Assume this retransmit will generate @@ -2765,7 +2766,7 @@ begin_fwd: goto begin_fwd; } else if (!(sacked & TCPCB_LOST)) { - if (hole == NULL && !(sacked & (TCPCB_SACKED_RETRANS|TCPCB_SACKED_ACKED))) + if (!hole && !(sacked & (TCPCB_SACKED_RETRANS|TCPCB_SACKED_ACKED))) hole = skb; continue; @@ -2868,14 +2869,14 @@ int tcp_send_synack(struct sock *sk) struct sk_buff *skb; skb = tcp_write_queue_head(sk); - if (skb == NULL || !(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) { + if (!skb || !(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) { pr_debug("%s: wrong queue state\n", __func__); return -EFAULT; } if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_ACK)) { if (skb_cloned(skb)) { struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); - if (nskb == NULL) + if (!nskb) return -ENOMEM; tcp_unlink_write_queue(skb, sk); __skb_header_release(nskb); @@ -3300,7 +3301,7 @@ void tcp_send_ack(struct sock *sk) * sock. */ buff = alloc_skb(MAX_TCP_HEADER, sk_gfp_atomic(sk, GFP_ATOMIC)); - if (buff == NULL) { + if (!buff) { inet_csk_schedule_ack(sk); inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN; inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, @@ -3344,7 +3345,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent) /* We don't queue it, tcp_transmit_skb() sets ownership. */ skb = alloc_skb(MAX_TCP_HEADER, sk_gfp_atomic(sk, GFP_ATOMIC)); - if (skb == NULL) + if (!skb) return -1; /* Reserve space for headers and set control bits. */ diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 294af16633af..9f525a2a68df 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -633,7 +633,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) sk = __udp4_lib_lookup(net, iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex, udptable); - if (sk == NULL) { + if (!sk) { ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); return; /* No socket for error */ } @@ -1011,7 +1011,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) if (connected) rt = (struct rtable *)sk_dst_check(sk, 0); - if (rt == NULL) { + if (!rt) { struct net *net = sock_net(sk); fl4 = &fl4_stack; @@ -1619,7 +1619,7 @@ static void flush_stack(struct sock **stack, unsigned int count, for (i = 0; i < count; i++) { sk = stack[i]; - if (likely(skb1 == NULL)) + if (likely(!skb1)) skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC); if (!skb1) { diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index 2dbfc1f1f7b3..b763c39ae1d7 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c @@ -58,7 +58,7 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, goto out_nosk; err = -ENOENT; - if (sk == NULL) + if (!sk) goto out_nosk; err = sock_diag_check_cookie(sk, req->id.idiag_cookie); diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index aac6197b7a71..cac7468db0a1 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -24,7 +24,7 @@ int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb) static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb) { - if (skb_dst(skb) == NULL) { + if (!skb_dst(skb)) { const struct iphdr *iph = ip_hdr(skb); if (ip_route_input_noref(skb, iph->daddr, iph->saddr, diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index c224c856247b..bff69746e05f 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -298,7 +298,7 @@ static void __net_exit xfrm4_net_exit(struct net *net) { struct ctl_table *table; - if (net->ipv4.xfrm4_hdr == NULL) + if (!net->ipv4.xfrm4_hdr) return; table = net->ipv4.xfrm4_hdr->ctl_table_arg; From 00db41243e8d5032c2e0f5bf6063bb19324bfdb3 Mon Sep 17 00:00:00 2001 From: Ian Morris Date: Fri, 3 Apr 2015 09:17:27 +0100 Subject: [PATCH 516/567] ipv4: coding style: comparison for inequality with NULL The ipv4 code uses a mixture of coding styles. In some instances check for non-NULL pointer is done as x != NULL and sometimes as x. x is preferred according to checkpatch and this patch makes the code consistent by adopting the latter form. No changes detected by objdiff. Signed-off-by: Ian Morris Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 2 +- net/ipv4/arp.c | 2 +- net/ipv4/cipso_ipv4.c | 6 +++--- net/ipv4/devinet.c | 2 +- net/ipv4/fib_trie.c | 4 ++-- net/ipv4/geneve.c | 2 +- net/ipv4/gre_offload.c | 2 +- net/ipv4/igmp.c | 8 ++++---- net/ipv4/inet_connection_sock.c | 8 ++++---- net/ipv4/inet_hashtables.c | 2 +- net/ipv4/inet_timewait_sock.c | 2 +- net/ipv4/ip_fragment.c | 3 ++- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_options.c | 2 +- net/ipv4/ip_output.c | 6 +++--- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/ip_tunnel.c | 2 +- net/ipv4/ip_vti.c | 2 +- net/ipv4/ipmr.c | 2 +- net/ipv4/ping.c | 2 +- net/ipv4/raw.c | 4 ++-- net/ipv4/route.c | 2 +- net/ipv4/tcp.c | 12 ++++++------ net/ipv4/tcp_diag.c | 2 +- net/ipv4/tcp_input.c | 12 ++++++------ net/ipv4/tcp_ipv4.c | 4 ++-- net/ipv4/tcp_minisocks.c | 6 +++--- net/ipv4/tcp_output.c | 14 +++++++------- net/ipv4/udp.c | 4 ++-- net/ipv4/udp_offload.c | 4 ++-- 30 files changed, 64 insertions(+), 63 deletions(-) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 7d3b00c01bc8..8b47a4d79d04 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1269,7 +1269,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, if (udpfrag) { iph->id = htons(id); iph->frag_off = htons(offset >> 3); - if (skb->next != NULL) + if (skb->next) iph->frag_off |= htons(IP_MF); offset += skb->len - nhoff - ihl; } else { diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index ffe84226a2c8..c6e67aa46c32 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -569,7 +569,7 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, break; #endif default: - if (target_hw != NULL) + if (target_hw) memcpy(arp_ptr, target_hw, dev->addr_len); else memset(arp_ptr, 0, dev->addr_len); diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 1b28e1183c1b..bdb2a07ec363 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -502,7 +502,7 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def, atomic_set(&doi_def->refcount, 1); spin_lock(&cipso_v4_doi_list_lock); - if (cipso_v4_doi_search(doi_def->doi) != NULL) { + if (cipso_v4_doi_search(doi_def->doi)) { spin_unlock(&cipso_v4_doi_list_lock); ret_val = -EEXIST; goto doi_add_return; @@ -513,7 +513,7 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def, doi_add_return: audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_ADD, audit_info); - if (audit_buf != NULL) { + if (audit_buf) { const char *type_str; switch (doi_type) { case CIPSO_V4_MAP_TRANS: @@ -617,7 +617,7 @@ int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info) doi_remove_return: audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_DEL, audit_info); - if (audit_buf != NULL) { + if (audit_buf) { audit_log_format(audit_buf, " cipso_doi=%u res=%u", doi, ret_val == 0 ? 1 : 0); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 0ee21689d37e..419d23c53ec7 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1290,7 +1290,7 @@ __be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 addr = 0; struct net_device *dev; - if (in_dev != NULL) + if (in_dev) return confirm_addr_indev(in_dev, dst, local, scope); rcu_read_lock(); diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 9e4a3e3423b4..e13fcc602da2 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -391,9 +391,9 @@ static void put_child(struct key_vector *tn, unsigned long i, BUG_ON(i >= child_length(tn)); /* update emptyChildren, overflow into fullChildren */ - if (!n && chi != NULL) + if (!n && chi) empty_child_inc(tn); - if (n != NULL && !chi) + if (n && !chi) empty_child_dec(tn); /* update fullChildren */ diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c index a7d8be3dd3de..e64f8e9785d1 100644 --- a/net/ipv4/geneve.c +++ b/net/ipv4/geneve.c @@ -230,7 +230,7 @@ static int geneve_gro_complete(struct sk_buff *skb, int nhoff, rcu_read_lock(); ptype = gro_find_complete_by_type(type); - if (ptype != NULL) + if (ptype) err = ptype->callbacks.gro_complete(skb, nhoff + gh_len); rcu_read_unlock(); diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 9358f11aae40..5aa46d4b44ef 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -243,7 +243,7 @@ static int gre_gro_complete(struct sk_buff *skb, int nhoff) rcu_read_lock(); ptype = gro_find_complete_by_type(type); - if (ptype != NULL) + if (ptype) err = ptype->callbacks.gro_complete(skb, nhoff + grehlen); rcu_read_unlock(); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 27d204b834f9..a3a697f5ffba 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2370,7 +2370,7 @@ void ip_mc_drop_socket(struct sock *sk) inet->mc_list = iml->next_rcu; in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); (void) ip_mc_leave_src(sk, iml, in_dev); - if (in_dev != NULL) + if (in_dev) ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); /* decrease mem now to avoid the memleak warning */ atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); @@ -2590,10 +2590,10 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) if (unlikely(!idev)) continue; im = rcu_dereference(idev->mc_list); - if (likely(im != NULL)) { + if (likely(im)) { spin_lock_bh(&im->lock); psf = im->sources; - if (likely(psf != NULL)) { + if (likely(psf)) { state->im = im; state->idev = idev; break; @@ -2663,7 +2663,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) __releases(rcu) { struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); - if (likely(state->im != NULL)) { + if (likely(state->im)) { spin_unlock_bh(&state->im->lock); state->im = NULL; } diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 79c0c9439fdc..5c3dd6267ed3 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -673,7 +673,7 @@ struct sock *inet_csk_clone_lock(const struct sock *sk, { struct sock *newsk = sk_clone_lock(sk, priority); - if (newsk != NULL) { + if (newsk) { struct inet_connection_sock *newicsk = inet_csk(newsk); newsk->sk_state = TCP_SYN_RECV; @@ -843,7 +843,7 @@ void inet_csk_listen_stop(struct sock *sk) sk_acceptq_removed(sk); reqsk_put(req); } - if (queue->fastopenq != NULL) { + if (queue->fastopenq) { /* Free all the reqs queued in rskq_rst_head. */ spin_lock_bh(&queue->fastopenq->lock); acc_req = queue->fastopenq->rskq_rst_head; @@ -875,7 +875,7 @@ int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, { const struct inet_connection_sock *icsk = inet_csk(sk); - if (icsk->icsk_af_ops->compat_getsockopt != NULL) + if (icsk->icsk_af_ops->compat_getsockopt) return icsk->icsk_af_ops->compat_getsockopt(sk, level, optname, optval, optlen); return icsk->icsk_af_ops->getsockopt(sk, level, optname, @@ -888,7 +888,7 @@ int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, { const struct inet_connection_sock *icsk = inet_csk(sk); - if (icsk->icsk_af_ops->compat_setsockopt != NULL) + if (icsk->icsk_af_ops->compat_setsockopt) return icsk->icsk_af_ops->compat_setsockopt(sk, level, optname, optval, optlen); return icsk->icsk_af_ops->setsockopt(sk, level, optname, diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 0fb841b9d834..d4630bf2d9aa 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -64,7 +64,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, { struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC); - if (tb != NULL) { + if (tb) { write_pnet(&tb->ib_net, net); tb->port = snum; tb->fastreuse = 0; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index f38e387448fb..118f0f195820 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -173,7 +173,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat struct inet_timewait_sock *tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab, GFP_ATOMIC); - if (tw != NULL) { + if (tw) { const struct inet_sock *inet = inet_sk(sk); kmemcheck_annotate_bitfield(tw, flags); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 5a6cf8667a9d..cc1da6d9cb35 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -639,7 +639,8 @@ int ip_defrag(struct sk_buff *skb, u32 user) IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); /* Lookup (or create) queue header */ - if ((qp = ip_find(net, ip_hdr(skb), user)) != NULL) { + qp = ip_find(net, ip_hdr(skb), user); + if (qp) { int ret; spin_lock(&qp->q.lock); diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 00bed6fe3b66..2e0410ed8f16 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -203,7 +203,7 @@ static int ip_local_deliver_finish(struct sk_buff *skb) raw = raw_local_deliver(skb, protocol); ipprot = rcu_dereference(inet_protos[protocol]); - if (ipprot != NULL) { + if (ipprot) { int ret; if (!ipprot->no_policy) { diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 5b3d91be2db0..bd246792360b 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -264,7 +264,7 @@ int ip_options_compile(struct net *net, unsigned char *iph; int optlen, l; - if (skb != NULL) { + if (skb) { rt = skb_rtable(skb); optptr = (unsigned char *)&(ip_hdr(skb)[1]); } else diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 561d67b2ac74..26f6f7956168 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -257,7 +257,7 @@ static int ip_finish_output(struct sk_buff *skb) { #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) /* Policy lookup after SNAT yielded a new policy */ - if (skb_dst(skb)->xfrm != NULL) { + if (skb_dst(skb)->xfrm) { IPCB(skb)->flags |= IPSKB_REROUTED; return dst_output(skb); } @@ -376,7 +376,7 @@ int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl) inet_opt = rcu_dereference(inet->inet_opt); fl4 = &fl->u.ip4; rt = skb_rtable(skb); - if (rt != NULL) + if (rt) goto packet_routed; /* Make sure we can route this packet. */ @@ -587,7 +587,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) ip_options_fragment(frag); offset += skb->len - hlen; iph->frag_off = htons(offset>>3); - if (frag->next != NULL) + if (frag->next) iph->frag_off |= htons(IP_MF); /* Ready, complete checksum */ ip_send_check(iph); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index f64b1b24c64f..7cfb0893f263 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -387,7 +387,7 @@ void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, skb_network_header(skb); serr->port = port; - if (skb_pull(skb, payload - skb->data) != NULL) { + if (skb_pull(skb, payload - skb->data)) { skb_reset_transport_header(skb); if (sock_queue_err_skb(sk, skb) == 0) return; diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 31eaa9ba1803..6d364ab8e14e 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -876,7 +876,7 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) break; } if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { - if (t != NULL) { + if (t) { if (t->dev != dev) { err = -EEXIST; break; diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index c4f93c0d1104..9f7269f3c54a 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -60,7 +60,7 @@ static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi, tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, iph->saddr, iph->daddr, 0); - if (tunnel != NULL) { + if (tunnel) { if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) goto drop; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index a170e4bc9006..c204b728bbc1 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -316,7 +316,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) unsigned int i; mrt = ipmr_get_table(net, id); - if (mrt != NULL) + if (mrt) return mrt; mrt = kzalloc(sizeof(*mrt), GFP_KERNEL); diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 2dcd2e60df64..a93f260cf24c 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -971,7 +971,7 @@ bool ping_rcv(struct sk_buff *skb) skb_push(skb, skb->data - (u8 *)icmph); sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id)); - if (sk != NULL) { + if (sk) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); pr_debug("rcv on socket %p\n", sk); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 46a78204189d..6d0fa8fb8af0 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -293,7 +293,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) read_lock(&raw_v4_hashinfo.lock); raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); - if (raw_sk != NULL) { + if (raw_sk) { iph = (const struct iphdr *)skb->data; net = dev_net(skb->dev); @@ -872,7 +872,7 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); - if (skb != NULL) + if (skb) amount = skb->len; spin_unlock_bh(&sk->sk_receive_queue.lock); return put_user(amount, (int __user *)arg); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 26a1cb348b3d..a78540f28276 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1591,7 +1591,7 @@ static int __mkroute_input(struct sk_buff *skb, fnhe = find_exception(&FIB_RES_NH(*res), daddr); if (do_cache) { - if (fnhe != NULL) + if (fnhe) rth = rcu_dereference(fnhe->fnhe_rth_input); else rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 5bd809bfd0aa..094a6822c71d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -496,7 +496,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) /* Connected or passive Fast Open socket? */ if (sk->sk_state != TCP_SYN_SENT && - (sk->sk_state != TCP_SYN_RECV || tp->fastopen_rsk != NULL)) { + (sk->sk_state != TCP_SYN_RECV || tp->fastopen_rsk)) { int target = sock_rcvlowat(sk, 0, INT_MAX); if (tp->urg_seq == tp->copied_seq && @@ -1028,7 +1028,7 @@ static inline int select_size(const struct sock *sk, bool sg) void tcp_free_fastopen_req(struct tcp_sock *tp) { - if (tp->fastopen_req != NULL) { + if (tp->fastopen_req) { kfree(tp->fastopen_req); tp->fastopen_req = NULL; } @@ -1042,7 +1042,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE)) return -EOPNOTSUPP; - if (tp->fastopen_req != NULL) + if (tp->fastopen_req) return -EALREADY; /* Another Fast Open is in progress */ tp->fastopen_req = kzalloc(sizeof(struct tcp_fastopen_request), @@ -2138,7 +2138,7 @@ adjudge_to_death: * aborted (e.g., closed with unread data) before 3WHS * finishes. */ - if (req != NULL) + if (req) reqsk_fastopen_remove(sk, req, false); inet_csk_destroy_sock(sk); } @@ -2776,7 +2776,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level, break; case TCP_FASTOPEN: - if (icsk->icsk_accept_queue.fastopenq != NULL) + if (icsk->icsk_accept_queue.fastopenq) val = icsk->icsk_accept_queue.fastopenq->max_qlen; else val = 0; @@ -2960,7 +2960,7 @@ void tcp_done(struct sock *sk) tcp_set_state(sk, TCP_CLOSE); tcp_clear_xmit_timers(sk); - if (req != NULL) + if (req) reqsk_fastopen_remove(sk, req, false); sk->sk_shutdown = SHUTDOWN_MASK; diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 86dc119a3815..79b34a0f4a4a 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -29,7 +29,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, r->idiag_rqueue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0); r->idiag_wqueue = tp->write_seq - tp->snd_una; } - if (info != NULL) + if (info) tcp_get_info(sk, info); } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 1fd283684303..df7e7fa12733 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1256,7 +1256,7 @@ static u8 tcp_sacktag_one(struct sock *sk, fack_count += pcount; /* Lost marker hint past SACKed? Tweak RFC3517 cnt */ - if (!tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) && + if (!tcp_is_fack(tp) && tp->lost_skb_hint && before(start_seq, TCP_SKB_CB(tp->lost_skb_hint)->seq)) tp->lost_cnt_hint += pcount; @@ -1535,7 +1535,7 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk, if (!before(TCP_SKB_CB(skb)->seq, end_seq)) break; - if ((next_dup != NULL) && + if (next_dup && before(TCP_SKB_CB(skb)->seq, next_dup->end_seq)) { in_sack = tcp_match_skb_to_sack(sk, skb, next_dup->start_seq, @@ -1551,7 +1551,7 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk, if (in_sack <= 0) { tmp = tcp_shift_skb_data(sk, skb, state, start_seq, end_seq, dup_sack); - if (tmp != NULL) { + if (tmp) { if (tmp != skb) { skb = tmp; continue; @@ -5321,7 +5321,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) tcp_set_state(sk, TCP_ESTABLISHED); - if (skb != NULL) { + if (skb) { icsk->icsk_af_ops->sk_rx_dst_set(sk, skb); security_inet_conn_established(sk, skb); } @@ -5690,7 +5690,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, } req = tp->fastopen_rsk; - if (req != NULL) { + if (req) { WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV && sk->sk_state != TCP_FIN_WAIT1); @@ -5780,7 +5780,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, * ACK we have received, this would have acknowledged * our SYNACK so stop the SYNACK timer. */ - if (req != NULL) { + if (req) { /* Return RST if ack_seq is invalid. * Note that RFC793 only says to generate a * DUPACK for it but for TCP Fast Open it seems diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 9ff311cf00f3..560f9571f7c4 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1305,7 +1305,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, /* Copy over the MD5 key from the original socket */ key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&newinet->inet_daddr, AF_INET); - if (key != NULL) { + if (key) { /* * We're using one, so create a matching key * on the newsk structure. If we fail to get @@ -1797,7 +1797,7 @@ void tcp_v4_destroy_sock(struct sock *sk) if (inet_csk(sk)->icsk_bind_hash) inet_put_port(sk); - BUG_ON(tp->fastopen_rsk != NULL); + BUG_ON(tp->fastopen_rsk); /* If socket is aborted during connect operation */ tcp_free_fastopen_req(tp); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index f0db1599a09c..d7003911c894 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -294,7 +294,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets) tw = inet_twsk_alloc(sk, state); - if (tw != NULL) { + if (tw) { struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); struct inet_sock *inet = inet_sk(sk); @@ -332,7 +332,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) struct tcp_md5sig_key *key; tcptw->tw_md5_key = NULL; key = tp->af_specific->md5_lookup(sk, sk); - if (key != NULL) { + if (key) { tcptw->tw_md5_key = kmemdup(key, sizeof(*key), GFP_ATOMIC); if (tcptw->tw_md5_key && !tcp_alloc_md5sig_pool()) BUG(); @@ -454,7 +454,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, { struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC); - if (newsk != NULL) { + if (newsk) { const struct inet_request_sock *ireq = inet_rsk(req); struct tcp_request_sock *treq = tcp_rsk(req); struct inet_connection_sock *newicsk = inet_csk(newsk); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index bdc80734cd2c..7404e5238e00 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -641,7 +641,7 @@ static unsigned int tcp_synack_options(struct sock *sk, if (unlikely(!ireq->tstamp_ok)) remaining -= TCPOLEN_SACKPERM_ALIGNED; } - if (foc != NULL && foc->len >= 0) { + if (foc && foc->len >= 0) { u32 need = TCPOLEN_EXP_FASTOPEN_BASE + foc->len; need = (need + 3) & ~3U; /* Align to 32 bits */ if (remaining >= need) { @@ -2224,7 +2224,7 @@ void tcp_send_loss_probe(struct sock *sk) int mss = tcp_current_mss(sk); int err = -1; - if (tcp_send_head(sk) != NULL) { + if (tcp_send_head(sk)) { err = tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); goto rearm_timer; } @@ -2758,7 +2758,7 @@ begin_fwd: if (!tcp_can_forward_retransmit(sk)) break; /* Backtrack if necessary to non-L'ed skb */ - if (hole != NULL) { + if (hole) { skb = hole; hole = NULL; } @@ -2811,7 +2811,7 @@ void tcp_send_fin(struct sock *sk) */ mss_now = tcp_current_mss(sk); - if (tcp_send_head(sk) != NULL) { + if (tcp_send_head(sk)) { TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_FIN; TCP_SKB_CB(skb)->end_seq++; tp->write_seq++; @@ -3015,7 +3015,7 @@ static void tcp_connect_init(struct sock *sk) (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); #ifdef CONFIG_TCP_MD5SIG - if (tp->af_specific->md5_lookup(sk, sk) != NULL) + if (tp->af_specific->md5_lookup(sk, sk)) tp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; #endif @@ -3376,8 +3376,8 @@ int tcp_write_wakeup(struct sock *sk) if (sk->sk_state == TCP_CLOSE) return -1; - if ((skb = tcp_send_head(sk)) != NULL && - before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp))) { + skb = tcp_send_head(sk); + if (skb && before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp))) { int err; unsigned int mss = tcp_current_mss(sk); unsigned int seg_size = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9f525a2a68df..2162fc6ce1c1 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1522,7 +1522,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) /* if we're overly short, let UDP handle it */ encap_rcv = ACCESS_ONCE(up->encap_rcv); - if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) { + if (skb->len > sizeof(struct udphdr) && encap_rcv) { int ret; /* Verify checksum before giving to encap */ @@ -1802,7 +1802,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, saddr, daddr, udptable, proto); sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); - if (sk != NULL) { + if (sk) { int ret; if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk)) diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 4915d8284a86..f9386160cbee 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -285,7 +285,7 @@ void udp_del_offload(struct udp_offload *uo) pr_warn("udp_del_offload: didn't find offload for port %d\n", ntohs(uo->port)); unlock: spin_unlock(&udp_offload_lock); - if (uo_priv != NULL) + if (uo_priv) call_rcu(&uo_priv->rcu, udp_offload_free_routine); } EXPORT_SYMBOL(udp_del_offload); @@ -394,7 +394,7 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff) break; } - if (uo_priv != NULL) { + if (uo_priv) { NAPI_GRO_CB(skb)->proto = uo_priv->offload->ipproto; err = uo_priv->offload->callbacks.gro_complete(skb, nhoff + sizeof(struct udphdr), From 6d458f5b4ece8542a5c2281e40008823fec91814 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 3 Apr 2015 12:02:36 +0200 Subject: [PATCH 517/567] Revert "netns: don't clear nsid too early on removal" This reverts commit 4217291e592d ("netns: don't clear nsid too early on removal"). This is not the right fix, it introduces races. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/net_namespace.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 5221f975a4cc..cb5290b8c428 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -349,7 +349,7 @@ static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */ static void cleanup_net(struct work_struct *work) { const struct pernet_operations *ops; - struct net *net, *tmp, *peer; + struct net *net, *tmp; struct list_head net_kill_list; LIST_HEAD(net_exit_list); @@ -365,6 +365,14 @@ static void cleanup_net(struct work_struct *work) list_for_each_entry(net, &net_kill_list, cleanup_list) { list_del_rcu(&net->list); list_add_tail(&net->exit_list, &net_exit_list); + for_each_net(tmp) { + int id = __peernet2id(tmp, net, false); + + if (id >= 0) + idr_remove(&tmp->netns_ids, id); + } + idr_destroy(&net->netns_ids); + } rtnl_unlock(); @@ -390,26 +398,12 @@ static void cleanup_net(struct work_struct *work) */ rcu_barrier(); - rtnl_lock(); /* Finally it is safe to free my network namespace structure */ list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { - /* Unreference net from all peers (no need to loop over - * net_exit_list because idr_destroy() will be called for each - * element of this list. - */ - for_each_net(peer) { - int id = __peernet2id(peer, net, false); - - if (id >= 0) - idr_remove(&peer->netns_ids, id); - } - idr_destroy(&net->netns_ids); - list_del_init(&net->exit_list); put_user_ns(net->user_ns); net_drop_ns(net); } - rtnl_unlock(); } static DECLARE_WORK(net_cleanup_work, cleanup_net); From 576b7cd2f6ff1e90b3fc0a000d2fe74f8a50a4bb Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 3 Apr 2015 12:02:37 +0200 Subject: [PATCH 518/567] netns: don't allocate an id for dead netns First, let's explain the problem. Suppose you have an ipip interface that stands in the netns foo and its link part in the netns bar (so the netns bar has an nsid into the netns foo). Now, you remove the netns bar: - the bar nsid into the netns foo is removed - the netns exit method of ipip is called, thus our ipip iface is removed: => a netlink message is built in the netns foo to advertise this deletion => this netlink message requests an nsid for bar, thus a new nsid is allocated for bar and never removed. This patch adds a check in peernet2id() so that an id cannot be allocated for a netns which is currently destroyed. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/net_namespace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index cb5290b8c428..70d3450588b2 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -198,8 +198,10 @@ static int __peernet2id(struct net *net, struct net *peer, bool alloc) */ int peernet2id(struct net *net, struct net *peer) { - int id = __peernet2id(net, peer, true); + bool alloc = atomic_read(&peer->count) == 0 ? false : true; + int id; + id = __peernet2id(net, peer, alloc); return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED; } EXPORT_SYMBOL(peernet2id); From e79d8429aac95a5cbe4c235795c7cd554c91f924 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 3 Apr 2015 22:17:17 +1030 Subject: [PATCH 519/567] netdevice: document NETDEV_TX_BUSY deprecation. This paraphrases DaveM (and steals some of his words) explaining why a device shouldn't return NETDEV_TX_BUSY, even though it looks so inviting to driver authors. See http://www.spinics.net/lists/netdev/msg322350.html Inspired-by: David Miller Signed-off-by: Rusty Russell Signed-off-by: David S. Miller --- include/linux/netdevice.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 846a1f5bc9db..a710d22b174f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -795,7 +795,10 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, * struct net_device *dev); * Called when a packet needs to be transmitted. - * Must return NETDEV_TX_OK , NETDEV_TX_BUSY. + * Returns NETDEV_TX_OK. Can return NETDEV_TX_BUSY, but you should stop + * the queue before that can happen; it's for obsolete devices and weird + * corner cases, but the stack really does a non-trivial amount + * of useless work if you return NETDEV_TX_BUSY. * (can also return NETDEV_TX_LOCKED iff NETIF_F_LLTX) * Required can not be NULL. * From 2e7056c433216f406b90a003aa0ba42e19d3bdcf Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 31 Mar 2015 14:19:10 -0700 Subject: [PATCH 520/567] jhash: Update jhash_[321]words functions to use correct initval Looking over the implementation for jhash2 and comparing it to jhash_3words I realized that the two hashes were in fact very different. Doing a bit of digging led me to "The new jhash implementation" in which lookup2 was supposed to have been replaced with lookup3. In reviewing the patch I noticed that jhash2 had originally initialized a and b to JHASH_GOLDENRATIO and c to initval, but after the patch a, b, and c were initialized to initval + (length << 2) + JHASH_INITVAL. However the changes in jhash_3words simply replaced the initialization of a and b with JHASH_INITVAL. This change corrects what I believe was an oversight so that a, b, and c in jhash_3words all have the same value added consisting of initval + (length << 2) + JHASH_INITVAL so that jhash2 and jhash_3words will now produce the same hash result given the same inputs. Fixes: 60d509c823cca ("The new jhash implementation") Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- include/linux/jhash.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/jhash.h b/include/linux/jhash.h index 47cb09edec1a..348c6f47e4cc 100644 --- a/include/linux/jhash.h +++ b/include/linux/jhash.h @@ -145,11 +145,11 @@ static inline u32 jhash2(const u32 *k, u32 length, u32 initval) } -/* jhash_3words - hash exactly 3, 2 or 1 word(s) */ -static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) +/* __jhash_nwords - hash exactly 3, 2 or 1 word(s) */ +static inline u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) { - a += JHASH_INITVAL; - b += JHASH_INITVAL; + a += initval; + b += initval; c += initval; __jhash_final(a, b, c); @@ -157,14 +157,19 @@ static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) return c; } +static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) +{ + return __jhash_nwords(a, b, c, initval + JHASH_INITVAL + (3 << 2)); +} + static inline u32 jhash_2words(u32 a, u32 b, u32 initval) { - return jhash_3words(a, b, 0, initval); + return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); } static inline u32 jhash_1word(u32 a, u32 initval) { - return jhash_3words(a, 0, 0, initval); + return __jhash_nwords(a, 0, 0, initval + JHASH_INITVAL + (1 << 2)); } #endif /* _LINUX_JHASH_H */ From e0fdbab1699b89a9b0c192d4cb355f8ab43a8f17 Mon Sep 17 00:00:00 2001 From: Grzegorz Kolodziejczyk Date: Fri, 3 Apr 2015 12:14:52 +0200 Subject: [PATCH 521/567] Bluetooth: bnep: Return err value while sending cmd is not understood Send command not understood response should be verified if it was successfully sent, like all send responses. Signed-off-by: Grzegorz Kolodziejczyk Signed-off-by: Marcel Holtmann --- net/bluetooth/bnep/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index c05eccc1cf82..5cf5fbd2908d 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -239,7 +239,7 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) pkt[0] = BNEP_CONTROL; pkt[1] = BNEP_CMD_NOT_UNDERSTOOD; pkt[2] = cmd; - bnep_send(s, pkt, sizeof(pkt)); + err = bnep_send(s, pkt, sizeof(pkt)); } break; } From bcad57182425426dd4aa14deb27f97acb329f3cd Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 3 Apr 2015 20:52:24 +0200 Subject: [PATCH 522/567] ebpf: add skb->priority to offset map for usage in {cls, act}_bpf This adds the ability to read out the skb->priority from an eBPF program, so that it can be taken into account from a tc filter or action for the use-case where the priority is not being used to directly override the filter classification in a qdisc, but to tag traffic otherwise for the classifier; the priority can be assigned from various places incl. user space, in future we may also mangle it from an eBPF program. Signed-off-by: Daniel Borkmann Cc: Alexei Starovoitov Signed-off-by: David S. Miller --- include/uapi/linux/bpf.h | 1 + net/core/filter.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 74aab6e0d964..0db8580f3cca 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -184,6 +184,7 @@ struct __sk_buff { __u32 vlan_present; __u32 vlan_tci; __u32 vlan_proto; + __u32 priority; }; #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/net/core/filter.c b/net/core/filter.c index 444a07e4f68d..955a7d77decd 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1304,6 +1304,13 @@ static u32 sk_filter_convert_ctx_access(int dst_reg, int src_reg, int ctx_off, offsetof(struct sk_buff, vlan_proto)); break; + case offsetof(struct __sk_buff, priority): + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, priority) != 4); + + *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, + offsetof(struct sk_buff, priority)); + break; + case offsetof(struct __sk_buff, mark): return convert_skb_access(SKF_AD_MARK, dst_reg, src_reg, insn); From a3bebdce4135a44d09e96ba66c40797c8f9fa902 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Wed, 1 Apr 2015 20:30:31 +0300 Subject: [PATCH 523/567] add fixed_phy_update_state() - update state of fixed_phy Currently fixed_phy uses a callback to periodically poll the link state. This patch adds the fixed_phy_update_state() API. It solves the following problems: - On link state interrupt, MAC driver can't update status. Instead it needs to provide the callback to periodically query the HW about the link state. It is more efficient to update status after interrupt. - The callback needs to be unregistered before phy_disconnect(), or otherwise it will be called with net_dev==NULL. phy_disconnect() does not have enough info to unregister the callback automatically. - The callback needs to be registered before of_phy_connect() to avoid running with outdated state, but of_phy_connect() returns the phy_device pointer, which is needed to register the callback. Registering it before of_phy_connect() will therefore require a hack to get the pointer earlier. Overall, this addition makes the subsequent patch that implements SGMII link status for mvneta, much cleaner. CC: Florian Fainelli CC: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Stas Sergeev Signed-off-by: David S. Miller --- drivers/net/phy/fixed_phy.c | 29 +++++++++++++++++++++++++++++ include/linux/phy_fixed.h | 9 +++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index a08a3c78ba97..1960b46add65 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -183,6 +183,35 @@ int fixed_phy_set_link_update(struct phy_device *phydev, } EXPORT_SYMBOL_GPL(fixed_phy_set_link_update); +int fixed_phy_update_state(struct phy_device *phydev, + const struct fixed_phy_status *status, + const struct fixed_phy_status *changed) +{ + struct fixed_mdio_bus *fmb = &platform_fmb; + struct fixed_phy *fp; + + if (!phydev || !phydev->bus) + return -EINVAL; + + list_for_each_entry(fp, &fmb->phys, node) { + if (fp->addr == phydev->addr) { +#define _UPD(x) if (changed->x) \ + fp->status.x = status->x + _UPD(link); + _UPD(speed); + _UPD(duplex); + _UPD(pause); + _UPD(asym_pause); +#undef _UPD + fixed_phy_update_regs(fp); + return 0; + } + } + + return -ENOENT; +} +EXPORT_SYMBOL(fixed_phy_update_state); + int fixed_phy_add(unsigned int irq, int phy_addr, struct fixed_phy_status *status) { diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h index 7e75bfe37cc7..fe5732d53eda 100644 --- a/include/linux/phy_fixed.h +++ b/include/linux/phy_fixed.h @@ -21,6 +21,9 @@ extern void fixed_phy_del(int phy_addr); extern int fixed_phy_set_link_update(struct phy_device *phydev, int (*link_update)(struct net_device *, struct fixed_phy_status *)); +extern int fixed_phy_update_state(struct phy_device *phydev, + const struct fixed_phy_status *status, + const struct fixed_phy_status *changed); #else static inline int fixed_phy_add(unsigned int irq, int phy_id, struct fixed_phy_status *status) @@ -43,6 +46,12 @@ static inline int fixed_phy_set_link_update(struct phy_device *phydev, { return -ENODEV; } +static inline int fixed_phy_update_state(struct phy_device *phydev, + const struct fixed_phy_status *status, + const struct fixed_phy_status *changed) +{ + return -ENODEV; +} #endif /* CONFIG_FIXED_PHY */ #endif /* __PHY_FIXED_H */ From 898b2970e2c91e4543b579998922822894325866 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Wed, 1 Apr 2015 20:32:49 +0300 Subject: [PATCH 524/567] mvneta: implement SGMII-based in-band link state signaling When MDIO bus is unavailable (common setup for SGMII), the in-band signaling must be used to correctly track link state. This patch enables the in-band status delivery for link state changes, namely: - link up/down - link speed - duplex full/half fixed_phy_update_state() is used to update phy status. CC: Thomas Petazzoni CC: Florian Fainelli CC: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Stas Sergeev Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 106 +++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 96208f17bb53..a7a9271f64b1 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -100,6 +100,8 @@ #define MVNETA_TXQ_CMD 0x2448 #define MVNETA_TXQ_DISABLE_SHIFT 8 #define MVNETA_TXQ_ENABLE_MASK 0x000000ff +#define MVNETA_GMAC_CLOCK_DIVIDER 0x24f4 +#define MVNETA_GMAC_1MS_CLOCK_ENABLE BIT(31) #define MVNETA_ACC_MODE 0x2500 #define MVNETA_CPU_MAP(cpu) (0x2540 + ((cpu) << 2)) #define MVNETA_CPU_RXQ_ACCESS_ALL_MASK 0x000000ff @@ -122,6 +124,7 @@ #define MVNETA_TX_INTR_MASK_ALL (0xff << 0) #define MVNETA_RX_INTR_MASK(nr_rxqs) (((1 << nr_rxqs) - 1) << 8) #define MVNETA_RX_INTR_MASK_ALL (0xff << 8) +#define MVNETA_MISCINTR_INTR_MASK BIT(31) #define MVNETA_INTR_OLD_CAUSE 0x25a8 #define MVNETA_INTR_OLD_MASK 0x25ac @@ -165,6 +168,7 @@ #define MVNETA_GMAC_MAX_RX_SIZE_MASK 0x7ffc #define MVNETA_GMAC0_PORT_ENABLE BIT(0) #define MVNETA_GMAC_CTRL_2 0x2c08 +#define MVNETA_GMAC2_INBAND_AN_ENABLE BIT(0) #define MVNETA_GMAC2_PCS_ENABLE BIT(3) #define MVNETA_GMAC2_PORT_RGMII BIT(4) #define MVNETA_GMAC2_PORT_RESET BIT(6) @@ -180,9 +184,11 @@ #define MVNETA_GMAC_AUTONEG_CONFIG 0x2c0c #define MVNETA_GMAC_FORCE_LINK_DOWN BIT(0) #define MVNETA_GMAC_FORCE_LINK_PASS BIT(1) +#define MVNETA_GMAC_INBAND_AN_ENABLE BIT(2) #define MVNETA_GMAC_CONFIG_MII_SPEED BIT(5) #define MVNETA_GMAC_CONFIG_GMII_SPEED BIT(6) #define MVNETA_GMAC_AN_SPEED_EN BIT(7) +#define MVNETA_GMAC_AN_FLOW_CTRL_EN BIT(11) #define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12) #define MVNETA_GMAC_AN_DUPLEX_EN BIT(13) #define MVNETA_MIB_COUNTERS_BASE 0x3080 @@ -304,6 +310,7 @@ struct mvneta_port { unsigned int link; unsigned int duplex; unsigned int speed; + int use_inband_status:1; }; /* The mvneta_tx_desc and mvneta_rx_desc structures describe the @@ -994,6 +1001,20 @@ static void mvneta_defaults_set(struct mvneta_port *pp) val &= ~MVNETA_PHY_POLLING_ENABLE; mvreg_write(pp, MVNETA_UNIT_CONTROL, val); + if (pp->use_inband_status) { + val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); + val &= ~(MVNETA_GMAC_FORCE_LINK_PASS | + MVNETA_GMAC_FORCE_LINK_DOWN | + MVNETA_GMAC_AN_FLOW_CTRL_EN); + val |= MVNETA_GMAC_INBAND_AN_ENABLE | + MVNETA_GMAC_AN_SPEED_EN | + MVNETA_GMAC_AN_DUPLEX_EN; + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); + val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER); + val |= MVNETA_GMAC_1MS_CLOCK_ENABLE; + mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val); + } + mvneta_set_ucast_table(pp, -1); mvneta_set_special_mcast_table(pp, -1); mvneta_set_other_mcast_table(pp, -1); @@ -2043,6 +2064,28 @@ static irqreturn_t mvneta_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static int mvneta_fixed_link_update(struct mvneta_port *pp, + struct phy_device *phy) +{ + struct fixed_phy_status status; + struct fixed_phy_status changed = {}; + u32 gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS); + + status.link = !!(gmac_stat & MVNETA_GMAC_LINK_UP); + if (gmac_stat & MVNETA_GMAC_SPEED_1000) + status.speed = SPEED_1000; + else if (gmac_stat & MVNETA_GMAC_SPEED_100) + status.speed = SPEED_100; + else + status.speed = SPEED_10; + status.duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX); + changed.link = 1; + changed.speed = 1; + changed.duplex = 1; + fixed_phy_update_state(phy, &status, &changed); + return 0; +} + /* NAPI handler * Bits 0 - 7 of the causeRxTx register indicate that are transmitted * packets on the corresponding TXQ (Bit 0 is for TX queue 1). @@ -2063,8 +2106,18 @@ static int mvneta_poll(struct napi_struct *napi, int budget) } /* Read cause register */ - cause_rx_tx = mvreg_read(pp, MVNETA_INTR_NEW_CAUSE) & - (MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); + cause_rx_tx = mvreg_read(pp, MVNETA_INTR_NEW_CAUSE); + if (cause_rx_tx & MVNETA_MISCINTR_INTR_MASK) { + u32 cause_misc = mvreg_read(pp, MVNETA_INTR_MISC_CAUSE); + + mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0); + if (pp->use_inband_status && (cause_misc & + (MVNETA_CAUSE_PHY_STATUS_CHANGE | + MVNETA_CAUSE_LINK_CHANGE | + MVNETA_CAUSE_PSC_SYNC_CHANGE))) { + mvneta_fixed_link_update(pp, pp->phy_dev); + } + } /* Release Tx descriptors */ if (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL) { @@ -2109,7 +2162,9 @@ static int mvneta_poll(struct napi_struct *napi, int budget) napi_complete(napi); local_irq_save(flags); mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); + MVNETA_RX_INTR_MASK(rxq_number) | + MVNETA_TX_INTR_MASK(txq_number) | + MVNETA_MISCINTR_INTR_MASK); local_irq_restore(flags); } @@ -2373,7 +2428,13 @@ static void mvneta_start_dev(struct mvneta_port *pp) /* Unmask interrupts */ mvreg_write(pp, MVNETA_INTR_NEW_MASK, - MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number)); + MVNETA_RX_INTR_MASK(rxq_number) | + MVNETA_TX_INTR_MASK(txq_number) | + MVNETA_MISCINTR_INTR_MASK); + mvreg_write(pp, MVNETA_INTR_MISC_MASK, + MVNETA_CAUSE_PHY_STATUS_CHANGE | + MVNETA_CAUSE_LINK_CHANGE | + MVNETA_CAUSE_PSC_SYNC_CHANGE); phy_start(pp->phy_dev); netif_tx_start_all_queues(pp->dev); @@ -2523,9 +2584,7 @@ static void mvneta_adjust_link(struct net_device *ndev) val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED | MVNETA_GMAC_CONFIG_GMII_SPEED | - MVNETA_GMAC_CONFIG_FULL_DUPLEX | - MVNETA_GMAC_AN_SPEED_EN | - MVNETA_GMAC_AN_DUPLEX_EN); + MVNETA_GMAC_CONFIG_FULL_DUPLEX); if (phydev->duplex) val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX; @@ -2554,12 +2613,24 @@ static void mvneta_adjust_link(struct net_device *ndev) if (status_change) { if (phydev->link) { - u32 val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG); - val |= (MVNETA_GMAC_FORCE_LINK_PASS | - MVNETA_GMAC_FORCE_LINK_DOWN); - mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val); + if (!pp->use_inband_status) { + u32 val = mvreg_read(pp, + MVNETA_GMAC_AUTONEG_CONFIG); + val &= ~MVNETA_GMAC_FORCE_LINK_DOWN; + val |= MVNETA_GMAC_FORCE_LINK_PASS; + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, + val); + } mvneta_port_up(pp); } else { + if (!pp->use_inband_status) { + u32 val = mvreg_read(pp, + MVNETA_GMAC_AUTONEG_CONFIG); + val &= ~MVNETA_GMAC_FORCE_LINK_PASS; + val |= MVNETA_GMAC_FORCE_LINK_DOWN; + mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, + val); + } mvneta_port_down(pp); } phy_print_status(phydev); @@ -2910,6 +2981,9 @@ static int mvneta_port_power_up(struct mvneta_port *pp, int phy_mode) return -EINVAL; } + if (pp->use_inband_status) + ctrl |= MVNETA_GMAC2_INBAND_AN_ENABLE; + /* Cancel Port Reset */ ctrl &= ~MVNETA_GMAC2_PORT_RESET; mvreg_write(pp, MVNETA_GMAC_CTRL_2, ctrl); @@ -2934,6 +3008,7 @@ static int mvneta_probe(struct platform_device *pdev) char hw_mac_addr[ETH_ALEN]; const char *mac_from; int phy_mode; + int fixed_phy = 0; int err; /* Our multiqueue support is not complete, so for now, only @@ -2967,6 +3042,7 @@ static int mvneta_probe(struct platform_device *pdev) dev_err(&pdev->dev, "cannot register fixed PHY\n"); goto err_free_irq; } + fixed_phy = 1; /* In the case of a fixed PHY, the DT node associated * to the PHY is the Ethernet MAC DT node. @@ -2990,6 +3066,8 @@ static int mvneta_probe(struct platform_device *pdev) pp = netdev_priv(dev); pp->phy_node = phy_node; pp->phy_interface = phy_mode; + pp->use_inband_status = (phy_mode == PHY_INTERFACE_MODE_SGMII) && + fixed_phy; pp->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pp->clk)) { @@ -3067,6 +3145,12 @@ static int mvneta_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pp->dev); + if (pp->use_inband_status) { + struct phy_device *phy = of_phy_find_device(dn); + + mvneta_fixed_link_update(pp, phy); + } + return 0; err_free_stats: From b81b7be6ae830a507d15cf4fc626be02cc9ab79b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 2 Apr 2015 12:29:50 +0800 Subject: [PATCH 525/567] test_rhashtable: Remove bogus max_size setting Now that resizing is completely automatic, we need to remove the max_size setting or the test will fail. Reported-by: Fengguang Wu Signed-off-by: Herbert Xu Acked-by: Thomas Graf Signed-off-by: David S. Miller --- lib/test_rhashtable.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c index a42a0d44e818..b2957540d3c7 100644 --- a/lib/test_rhashtable.c +++ b/lib/test_rhashtable.c @@ -44,7 +44,6 @@ static const struct rhashtable_params test_rht_params = { .key_offset = offsetof(struct test_obj, value), .key_len = sizeof(int), .hashfn = jhash, - .max_size = 2, /* we expand/shrink manually here */ .nulls_base = (3U << RHT_BASE_SHIFT), }; From 0477e2e868ceead7fd96218e1a062e01631ce717 Mon Sep 17 00:00:00 2001 From: Grzegorz Kolodziejczyk Date: Fri, 3 Apr 2015 12:14:53 +0200 Subject: [PATCH 526/567] Bluetooth: bnep: Add support for get bnep features via ioctl This is needed if user space wants to know supported bnep features by kernel, e.g. if kernel supports sending response to bnep setup control message. By now there is no possibility to know supported features by kernel in case of bnep. Ioctls allows only to add connection, delete connection, get connection list, get connection info. Adding connection if it's possible (establishing network device connection) is equivalent to starting bnep session. Bnep session handles data queue of transmit, receive messages over bnep channel. It means that if we add connection the received/transmitted data will be parsed immediately. In case of get bnep features we want to know before session start, if we should leave setup data on socket queue and let kernel to handle with it, or in case of no setup handling support, if we should pull this message and handle setup response within user space. Signed-off-by: Grzegorz Kolodziejczyk Signed-off-by: Marcel Holtmann --- fs/compat_ioctl.c | 2 ++ net/bluetooth/bnep/bnep.h | 1 + net/bluetooth/bnep/sock.c | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index afec6450450f..6b8e2f091f5b 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -570,6 +570,7 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, void __user *argp) #define BNEPCONNDEL _IOW('B', 201, int) #define BNEPGETCONNLIST _IOR('B', 210, int) #define BNEPGETCONNINFO _IOR('B', 211, int) +#define BNEPGETSUPPFEAT _IOR('B', 212, int) #define CMTPCONNADD _IOW('C', 200, int) #define CMTPCONNDEL _IOW('C', 201, int) @@ -1247,6 +1248,7 @@ COMPATIBLE_IOCTL(BNEPCONNADD) COMPATIBLE_IOCTL(BNEPCONNDEL) COMPATIBLE_IOCTL(BNEPGETCONNLIST) COMPATIBLE_IOCTL(BNEPGETCONNINFO) +COMPATIBLE_IOCTL(BNEPGETSUPPFEAT) COMPATIBLE_IOCTL(CMTPCONNADD) COMPATIBLE_IOCTL(CMTPCONNDEL) COMPATIBLE_IOCTL(CMTPGETCONNLIST) diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index 5a5b16f365e9..8709733c12a7 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -111,6 +111,7 @@ struct bnep_ext_hdr { #define BNEPCONNDEL _IOW('B', 201, int) #define BNEPGETCONNLIST _IOR('B', 210, int) #define BNEPGETCONNINFO _IOR('B', 211, int) +#define BNEPGETSUPPFEAT _IOR('B', 212, int) struct bnep_connadd_req { int sock; /* Connected socket */ diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 5f051290daba..5766e6b66dbb 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -57,6 +57,7 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long struct bnep_conninfo ci; struct socket *nsock; void __user *argp = (void __user *)arg; + __u32 supp_feat = 0; int err; BT_DBG("cmd %x arg %lx", cmd, arg); @@ -120,6 +121,12 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return err; + case BNEPGETSUPPFEAT: + if (copy_to_user(argp, &supp_feat, sizeof(supp_feat))) + return -EFAULT; + + return 0; + default: return -EINVAL; } From bf8b9a9cb77b14e37a8bc925be5db7bfd54d69a8 Mon Sep 17 00:00:00 2001 From: Grzegorz Kolodziejczyk Date: Fri, 3 Apr 2015 12:14:54 +0200 Subject: [PATCH 527/567] Bluetooth: bnep: Add support to extended headers of control frames Handling extended headers of control frames is required BNEP functionality. This patch refractor bnep rx frame handling function. Extended header for control frames shouldn't be omitted as it was previously done. Every control frame should be checked if it contains extended header and then every extension should be parsed separately. Signed-off-by: Grzegorz Kolodziejczyk Signed-off-by: Marcel Holtmann --- net/bluetooth/bnep/core.c | 50 +++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 5cf5fbd2908d..0ee6f6d9d93e 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -292,30 +292,56 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) { struct net_device *dev = s->dev; struct sk_buff *nskb; - u8 type; + u8 type, ctrl_type; dev->stats.rx_bytes += skb->len; type = *(u8 *) skb->data; skb_pull(skb, 1); + ctrl_type = *(u8 *)skb->data; if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) goto badframe; if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { - bnep_rx_control(s, skb->data, skb->len); - kfree_skb(skb); - return 0; + if (bnep_rx_control(s, skb->data, skb->len) < 0) { + dev->stats.tx_errors++; + kfree_skb(skb); + return 0; + } + + if (!(type & BNEP_EXT_HEADER)) { + kfree_skb(skb); + return 0; + } + + /* Verify and pull ctrl message since it's already processed */ + switch (ctrl_type) { + case BNEP_SETUP_CONN_REQ: + /* Pull: ctrl type (1 b), len (1 b), data (len bytes) */ + if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2)) + goto badframe; + break; + case BNEP_FILTER_MULTI_ADDR_SET: + case BNEP_FILTER_NET_TYPE_SET: + /* Pull: ctrl type (1 b), len (2 b), data (len bytes) */ + if (!skb_pull(skb, 3 + *(u16 *)(skb->data + 1) * 2)) + goto badframe; + break; + default: + kfree_skb(skb); + return 0; + } + } else { + skb_reset_mac_header(skb); + + /* Verify and pull out header */ + if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK])) + goto badframe; + + s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2)); } - skb_reset_mac_header(skb); - - /* Verify and pull out header */ - if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK])) - goto badframe; - - s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2)); - if (type & BNEP_EXT_HEADER) { if (bnep_rx_extension(s, skb) < 0) goto badframe; From 836a061b19d7b4e2e5e05c2a87a366e33127cf88 Mon Sep 17 00:00:00 2001 From: Grzegorz Kolodziejczyk Date: Fri, 3 Apr 2015 12:14:55 +0200 Subject: [PATCH 528/567] Bluetooth: bnep: Handle BNEP connection setup request With this patch kernel will be able to handle setup request. This is needed if we would like to handle control mesages with extension headers. User space will be only resposible for reading setup data and checking if scenario is conformance to specification (dst and src device bnep role). In case of new user space, setup data must be leaved(peek msg) on queue. New bnep session will be responsible for handling this data. Signed-off-by: Grzegorz Kolodziejczyk Signed-off-by: Marcel Holtmann --- net/bluetooth/bnep/bnep.h | 3 +++ net/bluetooth/bnep/core.c | 14 +++++++++++--- net/bluetooth/bnep/sock.c | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index 8709733c12a7..40854c99bc1e 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -113,6 +113,9 @@ struct bnep_ext_hdr { #define BNEPGETCONNINFO _IOR('B', 211, int) #define BNEPGETSUPPFEAT _IOR('B', 212, int) +#define BNEP_SETUP_RESPONSE 0 +#define BNEP_SETUP_RSP_SENT 10 + struct bnep_connadd_req { int sock; /* Connected socket */ __u32 flags; diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 0ee6f6d9d93e..1641367e54ca 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -231,7 +231,14 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) break; case BNEP_SETUP_CONN_REQ: - err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, BNEP_CONN_NOT_ALLOWED); + /* Successful response should be sent only once */ + if (test_bit(BNEP_SETUP_RESPONSE, &s->flags) && + !test_and_set_bit(BNEP_SETUP_RSP_SENT, &s->flags)) + err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, + BNEP_SUCCESS); + else + err = bnep_send_rsp(s, BNEP_SETUP_CONN_RSP, + BNEP_CONN_NOT_ALLOWED); break; default: { @@ -551,7 +558,7 @@ static struct device_type bnep_type = { int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) { - u32 valid_flags = 0; + u32 valid_flags = BIT(BNEP_SETUP_RESPONSE); struct net_device *dev; struct bnep_session *s, *ss; u8 dst[ETH_ALEN], src[ETH_ALEN]; @@ -596,6 +603,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) s->sock = sock; s->role = req->role; s->state = BT_CONNECTED; + s->flags = req->flags; s->msg.msg_flags = MSG_NOSIGNAL; @@ -665,7 +673,7 @@ int bnep_del_connection(struct bnep_conndel_req *req) static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s) { - u32 valid_flags = 0; + u32 valid_flags = BIT(BNEP_SETUP_RESPONSE); memset(ci, 0, sizeof(*ci)); memcpy(ci->dst, s->eh.h_source, ETH_ALEN); diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 5766e6b66dbb..bde2bdd9e929 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -57,7 +57,7 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long struct bnep_conninfo ci; struct socket *nsock; void __user *argp = (void __user *)arg; - __u32 supp_feat = 0; + __u32 supp_feat = BIT(BNEP_SETUP_RESPONSE); int err; BT_DBG("cmd %x arg %lx", cmd, arg); From b2ddeb11738464ce8f75c15384a3b8132cb80357 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 3 Apr 2015 11:02:09 -0700 Subject: [PATCH 529/567] Bluetooth: cmtp: Use BIT(x) instead of (1 << x) Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/cmtp/capi.c | 2 +- net/bluetooth/cmtp/core.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 75bd2c42e3e7..b0c6c6af76ef 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -333,7 +333,7 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) return; } - if (session->flags & (1 << CMTP_LOOPBACK)) { + if (session->flags & BIT(CMTP_LOOPBACK)) { kfree_skb(skb); return; } diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index ddbc348c9dff..298ed37010e6 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -314,7 +314,7 @@ static int cmtp_session(void *arg) down_write(&cmtp_session_sem); - if (!(session->flags & (1 << CMTP_LOOPBACK))) + if (!(session->flags & BIT(CMTP_LOOPBACK))) cmtp_detach_device(session); fput(session->sock->file); @@ -390,7 +390,7 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) goto unlink; } - if (!(session->flags & (1 << CMTP_LOOPBACK))) { + if (!(session->flags & BIT(CMTP_LOOPBACK))) { err = cmtp_attach_device(session); if (err < 0) { atomic_inc(&session->terminate); From fd6413d882304ca66d99199db1561382e18396e4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 3 Apr 2015 11:02:10 -0700 Subject: [PATCH 530/567] Bluetooth: hidp: Use BIT(x) instead of (1 << x) Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/hidp/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 926a0e8b7136..a05b9dbf14c9 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -908,7 +908,7 @@ static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr, kref_init(&session->ref); atomic_set(&session->state, HIDP_SESSION_IDLING); init_waitqueue_head(&session->state_queue); - session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); + session->flags = req->flags & BIT(HIDP_BLUETOOTH_VENDOR_ID); /* connection management */ bacpy(&session->bdaddr, bdaddr); @@ -1366,7 +1366,7 @@ int hidp_connection_del(struct hidp_conndel_req *req) if (!session) return -ENOENT; - if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) + if (req->flags & BIT(HIDP_VIRTUAL_CABLE_UNPLUG)) hidp_send_ctrl_message(session, HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, From 38c8af60046edab4c9db5f26e79746b1bd52c837 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 3 Apr 2015 13:23:12 -0700 Subject: [PATCH 531/567] Bluetooth: Fix location of TX power field in LE advertising data The TX power field in the LE advertising data should be placed last since it needs to be possible to enable kernel controlled TX power, but still allow for userspace provided flags field. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/mgmt.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 20a7765680df..845dfcc43a20 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1043,6 +1043,14 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) } } + if (instance) { + memcpy(ptr, hdev->adv_instance.adv_data, + hdev->adv_instance.adv_data_len); + + ad_len += hdev->adv_instance.adv_data_len; + ptr += hdev->adv_instance.adv_data_len; + } + /* Provide Tx Power only if we can provide a valid value for it */ if (hdev->adv_tx_power != HCI_TX_POWER_INVALID && (instance_flags & MGMT_ADV_FLAG_TX_POWER)) { @@ -1054,12 +1062,6 @@ static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) ptr += 3; } - if (instance) { - memcpy(ptr, hdev->adv_instance.adv_data, - hdev->adv_instance.adv_data_len); - ad_len += hdev->adv_instance.adv_data_len; - } - return ad_len; } From cfdfab314647b1755afedc33ab66f3f247e161ae Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 3 Apr 2015 16:23:58 -0400 Subject: [PATCH 532/567] netfilter: Create and use nf_hook_state. Instead of passing a large number of arguments down into the nf_hook() entry points, create a structure which carries this state down through the hook processing layers. This makes is so that if we want to change the types or signatures of any of these pieces of state, there are less places that need to be changed. Signed-off-by: David S. Miller --- include/linux/netfilter.h | 28 +++++++++++++++++++++----- net/netfilter/core.c | 32 ++++++++++++------------------ net/netfilter/nf_internals.h | 11 +++-------- net/netfilter/nf_queue.c | 38 +++++++++++++++++++----------------- 4 files changed, 59 insertions(+), 50 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 2517ece98820..aee7ef1e23ed 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -44,6 +44,16 @@ int netfilter_init(void); struct sk_buff; struct nf_hook_ops; + +struct nf_hook_state { + unsigned int hook; + int thresh; + u_int8_t pf; + struct net_device *in; + struct net_device *out; + int (*okfn)(struct sk_buff *); +}; + typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, @@ -118,9 +128,7 @@ static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) } #endif -int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, - struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct sk_buff *), int thresh); +int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state); /** * nf_hook_thresh - call a netfilter hook @@ -135,8 +143,18 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, struct net_device *outdev, int (*okfn)(struct sk_buff *), int thresh) { - if (nf_hooks_active(pf, hook)) - return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh); + if (nf_hooks_active(pf, hook)) { + struct nf_hook_state state = { + .hook = hook, + .thresh = thresh, + .pf = pf, + .in = indev, + .out = outdev, + .okfn = okfn + }; + + return nf_hook_slow(skb, &state); + } return 1; } diff --git a/net/netfilter/core.c b/net/netfilter/core.c index fea9ef566427..11d04ebfc5e3 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -120,12 +120,8 @@ EXPORT_SYMBOL(nf_unregister_hooks); unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb, - unsigned int hook, - const struct net_device *indev, - const struct net_device *outdev, - struct nf_hook_ops **elemp, - int (*okfn)(struct sk_buff *), - int hook_thresh) + struct nf_hook_state *state, + struct nf_hook_ops **elemp) { unsigned int verdict; @@ -134,19 +130,20 @@ unsigned int nf_iterate(struct list_head *head, * function because of risk of continuing from deleted element. */ list_for_each_entry_continue_rcu((*elemp), head, list) { - if (hook_thresh > (*elemp)->priority) + if (state->thresh > (*elemp)->priority) continue; /* Optimization: we don't need to hold module reference here, since function can't sleep. --RR */ repeat: - verdict = (*elemp)->hook(*elemp, skb, indev, outdev, okfn); + verdict = (*elemp)->hook(*elemp, skb, state->in, state->out, + state->okfn); if (verdict != NF_ACCEPT) { #ifdef CONFIG_NETFILTER_DEBUG if (unlikely((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT)) { NFDEBUG("Evil return from %p(%u).\n", - (*elemp)->hook, hook); + (*elemp)->hook, state->hook); continue; } #endif @@ -161,11 +158,7 @@ repeat: /* Returns 1 if okfn() needs to be executed by the caller, * -EPERM for NF_DROP, 0 otherwise. */ -int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, - struct net_device *indev, - struct net_device *outdev, - int (*okfn)(struct sk_buff *), - int hook_thresh) +int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state) { struct nf_hook_ops *elem; unsigned int verdict; @@ -174,10 +167,11 @@ int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, /* We may already have this, but read-locks nest anyway */ rcu_read_lock(); - elem = list_entry_rcu(&nf_hooks[pf][hook], struct nf_hook_ops, list); + elem = list_entry_rcu(&nf_hooks[state->pf][state->hook], + struct nf_hook_ops, list); next_hook: - verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev, - outdev, &elem, okfn, hook_thresh); + verdict = nf_iterate(&nf_hooks[state->pf][state->hook], skb, state, + &elem); if (verdict == NF_ACCEPT || verdict == NF_STOP) { ret = 1; } else if ((verdict & NF_VERDICT_MASK) == NF_DROP) { @@ -186,8 +180,8 @@ next_hook: if (ret == 0) ret = -EPERM; } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { - int err = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, - verdict >> NF_VERDICT_QBITS); + int err = nf_queue(skb, elem, state, + verdict >> NF_VERDICT_QBITS); if (err < 0) { if (err == -ECANCELED) goto next_hook; diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h index 61a3c927e63c..ea7f36784b3d 100644 --- a/net/netfilter/nf_internals.h +++ b/net/netfilter/nf_internals.h @@ -14,16 +14,11 @@ /* core.c */ unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb, - unsigned int hook, const struct net_device *indev, - const struct net_device *outdev, - struct nf_hook_ops **elemp, - int (*okfn)(struct sk_buff *), int hook_thresh); + struct nf_hook_state *state, struct nf_hook_ops **elemp); /* nf_queue.c */ -int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem, u_int8_t pf, - unsigned int hook, struct net_device *indev, - struct net_device *outdev, int (*okfn)(struct sk_buff *), - unsigned int queuenum); +int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem, + struct nf_hook_state *state, unsigned int queuenum); int __init netfilter_queue_init(void); /* nf_log.c */ diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 4c8b68e5fa16..6f8e9485cc83 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -100,12 +100,9 @@ EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs); * through nf_reinject(). */ int nf_queue(struct sk_buff *skb, - struct nf_hook_ops *elem, - u_int8_t pf, unsigned int hook, - struct net_device *indev, - struct net_device *outdev, - int (*okfn)(struct sk_buff *), - unsigned int queuenum) + struct nf_hook_ops *elem, + struct nf_hook_state *state, + unsigned int queuenum) { int status = -ENOENT; struct nf_queue_entry *entry = NULL; @@ -121,7 +118,7 @@ int nf_queue(struct sk_buff *skb, goto err_unlock; } - afinfo = nf_get_afinfo(pf); + afinfo = nf_get_afinfo(state->pf); if (!afinfo) goto err_unlock; @@ -134,11 +131,11 @@ int nf_queue(struct sk_buff *skb, *entry = (struct nf_queue_entry) { .skb = skb, .elem = elem, - .pf = pf, - .hook = hook, - .indev = indev, - .outdev = outdev, - .okfn = okfn, + .pf = state->pf, + .hook = state->hook, + .indev = state->in, + .outdev = state->out, + .okfn = state->okfn, .size = sizeof(*entry) + afinfo->route_key_size, }; @@ -171,6 +168,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) struct sk_buff *skb = entry->skb; struct nf_hook_ops *elem = entry->elem; const struct nf_afinfo *afinfo; + struct nf_hook_state state; int err; rcu_read_lock(); @@ -189,12 +187,17 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) verdict = NF_DROP; } + state.hook = entry->hook; + state.thresh = INT_MIN; + state.pf = entry->pf; + state.in = entry->indev; + state.out = entry->outdev; + state.okfn = entry->okfn; + if (verdict == NF_ACCEPT) { next_hook: verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook], - skb, entry->hook, - entry->indev, entry->outdev, &elem, - entry->okfn, INT_MIN); + skb, &state, &elem); } switch (verdict & NF_VERDICT_MASK) { @@ -205,9 +208,8 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) local_bh_enable(); break; case NF_QUEUE: - err = nf_queue(skb, elem, entry->pf, entry->hook, - entry->indev, entry->outdev, entry->okfn, - verdict >> NF_VERDICT_QBITS); + err = nf_queue(skb, elem, &state, + verdict >> NF_VERDICT_QBITS); if (err < 0) { if (err == -ECANCELED) goto next_hook; From 1d1de89b9a4746f1dd055a3b8d073dd2f962a3b6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 3 Apr 2015 16:31:01 -0400 Subject: [PATCH 533/567] netfilter: Use nf_hook_state in nf_queue_entry. That way we don't have to reinstantiate another nf_hook_state on the stack of the nf_reinject() path. Signed-off-by: David S. Miller --- include/net/netfilter/nf_queue.h | 6 +--- net/ipv4/netfilter.c | 4 +-- net/ipv6/netfilter.c | 4 +-- net/netfilter/nf_queue.c | 44 ++++++++++++---------------- net/netfilter/nfnetlink_queue_core.c | 30 +++++++++---------- 5 files changed, 39 insertions(+), 49 deletions(-) diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index 84a53d780306..d81d584157e1 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h @@ -12,12 +12,8 @@ struct nf_queue_entry { unsigned int id; struct nf_hook_ops *elem; - u_int8_t pf; + struct nf_hook_state state; u16 size; /* sizeof(entry) + saved route keys */ - unsigned int hook; - struct net_device *indev; - struct net_device *outdev; - int (*okfn)(struct sk_buff *); /* extra space to store route keys */ }; diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 7ebd6e37875c..65de0684e22a 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -94,7 +94,7 @@ static void nf_ip_saveroute(const struct sk_buff *skb, { struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); - if (entry->hook == NF_INET_LOCAL_OUT) { + if (entry->state.hook == NF_INET_LOCAL_OUT) { const struct iphdr *iph = ip_hdr(skb); rt_info->tos = iph->tos; @@ -109,7 +109,7 @@ static int nf_ip_reroute(struct sk_buff *skb, { const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); - if (entry->hook == NF_INET_LOCAL_OUT) { + if (entry->state.hook == NF_INET_LOCAL_OUT) { const struct iphdr *iph = ip_hdr(skb); if (!(iph->tos == rt_info->tos && diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 398377a9d018..d958718b5031 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -84,7 +84,7 @@ static void nf_ip6_saveroute(const struct sk_buff *skb, { struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); - if (entry->hook == NF_INET_LOCAL_OUT) { + if (entry->state.hook == NF_INET_LOCAL_OUT) { const struct ipv6hdr *iph = ipv6_hdr(skb); rt_info->daddr = iph->daddr; @@ -98,7 +98,7 @@ static int nf_ip6_reroute(struct sk_buff *skb, { struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); - if (entry->hook == NF_INET_LOCAL_OUT) { + if (entry->state.hook == NF_INET_LOCAL_OUT) { const struct ipv6hdr *iph = ipv6_hdr(skb); if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) || diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 6f8e9485cc83..d3cd37edca18 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -47,11 +47,13 @@ EXPORT_SYMBOL(nf_unregister_queue_handler); void nf_queue_entry_release_refs(struct nf_queue_entry *entry) { + struct nf_hook_state *state = &entry->state; + /* Release those devices we held, or Alexey will kill me. */ - if (entry->indev) - dev_put(entry->indev); - if (entry->outdev) - dev_put(entry->outdev); + if (state->in) + dev_put(state->in); + if (state->out) + dev_put(state->out); #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (entry->skb->nf_bridge) { struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge; @@ -70,13 +72,15 @@ EXPORT_SYMBOL_GPL(nf_queue_entry_release_refs); /* Bump dev refs so they don't vanish while packet is out */ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry) { + struct nf_hook_state *state = &entry->state; + if (!try_module_get(entry->elem->owner)) return false; - if (entry->indev) - dev_hold(entry->indev); - if (entry->outdev) - dev_hold(entry->outdev); + if (state->in) + dev_hold(state->in); + if (state->out) + dev_hold(state->out); #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (entry->skb->nf_bridge) { struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge; @@ -131,11 +135,7 @@ int nf_queue(struct sk_buff *skb, *entry = (struct nf_queue_entry) { .skb = skb, .elem = elem, - .pf = state->pf, - .hook = state->hook, - .indev = state->in, - .outdev = state->out, - .okfn = state->okfn, + .state = *state, .size = sizeof(*entry) + afinfo->route_key_size, }; @@ -168,7 +168,6 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) struct sk_buff *skb = entry->skb; struct nf_hook_ops *elem = entry->elem; const struct nf_afinfo *afinfo; - struct nf_hook_state state; int err; rcu_read_lock(); @@ -182,33 +181,28 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) } if (verdict == NF_ACCEPT) { - afinfo = nf_get_afinfo(entry->pf); + afinfo = nf_get_afinfo(entry->state.pf); if (!afinfo || afinfo->reroute(skb, entry) < 0) verdict = NF_DROP; } - state.hook = entry->hook; - state.thresh = INT_MIN; - state.pf = entry->pf; - state.in = entry->indev; - state.out = entry->outdev; - state.okfn = entry->okfn; + entry->state.thresh = INT_MIN; if (verdict == NF_ACCEPT) { next_hook: - verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook], - skb, &state, &elem); + verdict = nf_iterate(&nf_hooks[entry->state.pf][entry->state.hook], + skb, &entry->state, &elem); } switch (verdict & NF_VERDICT_MASK) { case NF_ACCEPT: case NF_STOP: local_bh_disable(); - entry->okfn(skb); + entry->state.okfn(skb); local_bh_enable(); break; case NF_QUEUE: - err = nf_queue(skb, elem, &state, + err = nf_queue(skb, elem, &entry->state, verdict >> NF_VERDICT_QBITS); if (err < 0) { if (err == -ECANCELED) diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 86ee8b05adae..6e74655a8d4f 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c @@ -314,13 +314,13 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, if (entskb->tstamp.tv64) size += nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp)); - if (entry->hook <= NF_INET_FORWARD || - (entry->hook == NF_INET_POST_ROUTING && entskb->sk == NULL)) + if (entry->state.hook <= NF_INET_FORWARD || + (entry->state.hook == NF_INET_POST_ROUTING && entskb->sk == NULL)) csum_verify = !skb_csum_unnecessary(entskb); else csum_verify = false; - outdev = entry->outdev; + outdev = entry->state.out; switch ((enum nfqnl_config_mode)ACCESS_ONCE(queue->copy_mode)) { case NFQNL_COPY_META: @@ -368,23 +368,23 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, return NULL; } nfmsg = nlmsg_data(nlh); - nfmsg->nfgen_family = entry->pf; + nfmsg->nfgen_family = entry->state.pf; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = htons(queue->queue_num); nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg)); pmsg = nla_data(nla); pmsg->hw_protocol = entskb->protocol; - pmsg->hook = entry->hook; + pmsg->hook = entry->state.hook; *packet_id_ptr = &pmsg->packet_id; - indev = entry->indev; + indev = entry->state.in; if (indev) { #if !IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (nla_put_be32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex))) goto nla_put_failure; #else - if (entry->pf == PF_BRIDGE) { + if (entry->state.pf == PF_BRIDGE) { /* Case 1: indev is physical input device, we need to * look for bridge group (when called from * netfilter_bridge) */ @@ -414,7 +414,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex))) goto nla_put_failure; #else - if (entry->pf == PF_BRIDGE) { + if (entry->state.pf == PF_BRIDGE) { /* Case 1: outdev is physical output device, we need to * look for bridge group (when called from * netfilter_bridge) */ @@ -633,8 +633,8 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) struct nfqnl_instance *queue; struct sk_buff *skb, *segs; int err = -ENOBUFS; - struct net *net = dev_net(entry->indev ? - entry->indev : entry->outdev); + struct net *net = dev_net(entry->state.in ? + entry->state.in : entry->state.out); struct nfnl_queue_net *q = nfnl_queue_pernet(net); /* rcu_read_lock()ed by nf_hook_slow() */ @@ -647,7 +647,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) skb = entry->skb; - switch (entry->pf) { + switch (entry->state.pf) { case NFPROTO_IPV4: skb->protocol = htons(ETH_P_IP); break; @@ -757,11 +757,11 @@ nfqnl_set_mode(struct nfqnl_instance *queue, static int dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) { - if (entry->indev) - if (entry->indev->ifindex == ifindex) + if (entry->state.in) + if (entry->state.in->ifindex == ifindex) return 1; - if (entry->outdev) - if (entry->outdev->ifindex == ifindex) + if (entry->state.out) + if (entry->state.out->ifindex == ifindex) return 1; #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (entry->skb->nf_bridge) { From 238e54c9cb9385a1ba99e92801f3615a2fb398b6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 3 Apr 2015 20:32:56 -0400 Subject: [PATCH 534/567] netfilter: Make nf_hookfn use nf_hook_state. Pass the nf_hook_state all the way down into the hook functions themselves. Signed-off-by: David S. Miller --- include/linux/netfilter.h | 4 +- net/bridge/br_netfilter.c | 46 +++++++------------ net/bridge/netfilter/ebtable_filter.c | 14 +++--- net/bridge/netfilter/ebtable_nat.c | 14 +++--- net/bridge/netfilter/nf_tables_bridge.c | 10 ++-- net/decnet/netfilter/dn_rtmsg.c | 4 +- net/ipv4/netfilter/arptable_filter.c | 7 ++- net/ipv4/netfilter/ipt_CLUSTERIP.c | 10 ++-- net/ipv4/netfilter/ipt_SYNPROXY.c | 6 +-- net/ipv4/netfilter/iptable_filter.c | 7 ++- net/ipv4/netfilter/iptable_mangle.c | 14 +++--- net/ipv4/netfilter/iptable_nat.c | 28 +++++------ net/ipv4/netfilter/iptable_raw.c | 8 ++-- net/ipv4/netfilter/iptable_security.c | 8 ++-- .../netfilter/nf_conntrack_l3proto_ipv4.c | 20 +++----- net/ipv4/netfilter/nf_defrag_ipv4.c | 4 +- net/ipv4/netfilter/nf_tables_arp.c | 6 +-- net/ipv4/netfilter/nf_tables_ipv4.c | 12 ++--- net/ipv4/netfilter/nft_chain_nat_ipv4.c | 25 ++++------ net/ipv4/netfilter/nft_chain_route_ipv4.c | 6 +-- net/ipv6/netfilter/ip6t_SYNPROXY.c | 6 +-- net/ipv6/netfilter/ip6table_filter.c | 7 ++- net/ipv6/netfilter/ip6table_mangle.c | 13 +++--- net/ipv6/netfilter/ip6table_nat.c | 28 +++++------ net/ipv6/netfilter/ip6table_raw.c | 7 ++- net/ipv6/netfilter/ip6table_security.c | 8 ++-- .../netfilter/nf_conntrack_l3proto_ipv6.c | 20 +++----- net/ipv6/netfilter/nf_defrag_ipv6_hooks.c | 8 ++-- net/ipv6/netfilter/nf_tables_ipv6.c | 12 ++--- net/ipv6/netfilter/nft_chain_nat_ipv6.c | 24 ++++------ net/ipv6/netfilter/nft_chain_route_ipv6.c | 6 +-- net/netfilter/core.c | 3 +- net/netfilter/ipvs/ip_vs_core.c | 32 ++++--------- security/selinux/hooks.c | 28 ++++------- security/smack/smack_netfilter.c | 8 +--- 35 files changed, 169 insertions(+), 294 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index aee7ef1e23ed..c480c43ad8f7 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -56,9 +56,7 @@ struct nf_hook_state { typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)); + const struct nf_hook_state *state); struct nf_hook_ops { struct list_head list; diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index f3884a1b942f..7527e94dd5dc 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -562,9 +562,7 @@ bad: * to ip6tables, which doesn't support NAT, so things are fairly simple. */ static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { const struct ipv6hdr *hdr; u32 pkt_len; @@ -612,9 +610,7 @@ static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops, * address to be able to detect DNAT afterwards. */ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct net_bridge_port *p; struct net_bridge *br; @@ -623,7 +619,7 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops, if (unlikely(!pskb_may_pull(skb, len))) return NF_DROP; - p = br_port_get_rcu(in); + p = br_port_get_rcu(state->in); if (p == NULL) return NF_DROP; br = p->br; @@ -633,7 +629,7 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops, return NF_ACCEPT; nf_bridge_pull_encap_header_rcsum(skb); - return br_nf_pre_routing_ipv6(ops, skb, in, out, okfn); + return br_nf_pre_routing_ipv6(ops, skb, state); } if (!brnf_call_iptables && !br->nf_call_iptables) @@ -671,9 +667,7 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops, * prevent this from happening. */ static unsigned int br_nf_local_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { br_drop_fake_rtable(skb); return NF_ACCEPT; @@ -710,9 +704,7 @@ static int br_nf_forward_finish(struct sk_buff *skb) * bridge ports. */ static unsigned int br_nf_forward_ip(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nf_bridge_info *nf_bridge; struct net_device *parent; @@ -726,7 +718,7 @@ static unsigned int br_nf_forward_ip(const struct nf_hook_ops *ops, if (!nf_bridge_unshare(skb)) return NF_DROP; - parent = bridge_parent(out); + parent = bridge_parent(state->out); if (!parent) return NF_DROP; @@ -754,23 +746,21 @@ static unsigned int br_nf_forward_ip(const struct nf_hook_ops *ops, else skb->protocol = htons(ETH_P_IPV6); - NF_HOOK(pf, NF_INET_FORWARD, skb, brnf_get_logical_dev(skb, in), parent, - br_nf_forward_finish); + NF_HOOK(pf, NF_INET_FORWARD, skb, brnf_get_logical_dev(skb, state->in), + parent, br_nf_forward_finish); return NF_STOLEN; } static unsigned int br_nf_forward_arp(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct net_bridge_port *p; struct net_bridge *br; struct net_device **d = (struct net_device **)(skb->cb); - p = br_port_get_rcu(out); + p = br_port_get_rcu(state->out); if (p == NULL) return NF_ACCEPT; br = p->br; @@ -789,9 +779,9 @@ static unsigned int br_nf_forward_arp(const struct nf_hook_ops *ops, nf_bridge_push_encap_header(skb); return NF_ACCEPT; } - *d = (struct net_device *)in; - NF_HOOK(NFPROTO_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in, - (struct net_device *)out, br_nf_forward_finish); + *d = state->in; + NF_HOOK(NFPROTO_ARP, NF_ARP_FORWARD, skb, state->in, + state->out, br_nf_forward_finish); return NF_STOLEN; } @@ -859,9 +849,7 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb) /* PF_BRIDGE/POST_ROUTING ********************************************/ static unsigned int br_nf_post_routing(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; struct net_device *realoutdev = bridge_parent(skb->dev); @@ -910,9 +898,7 @@ static unsigned int br_nf_post_routing(const struct nf_hook_ops *ops, * for the second time. */ static unsigned int ip_sabotage_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { if (skb->nf_bridge && !(skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) { diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index ce205aabf9c5..8a3f63b2e807 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -58,20 +58,18 @@ static const struct ebt_table frame_filter = { static unsigned int ebt_in_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return ebt_do_table(ops->hooknum, skb, in, out, - dev_net(in)->xt.frame_filter); + return ebt_do_table(ops->hooknum, skb, state->in, state->out, + dev_net(state->in)->xt.frame_filter); } static unsigned int ebt_out_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return ebt_do_table(ops->hooknum, skb, in, out, - dev_net(out)->xt.frame_filter); + return ebt_do_table(ops->hooknum, skb, state->in, state->out, + dev_net(state->out)->xt.frame_filter); } static struct nf_hook_ops ebt_ops_filter[] __read_mostly = { diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index a0ac2984fb6c..c5ef5b1ab678 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c @@ -58,20 +58,18 @@ static struct ebt_table frame_nat = { static unsigned int ebt_nat_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return ebt_do_table(ops->hooknum, skb, in, out, - dev_net(in)->xt.frame_nat); + return ebt_do_table(ops->hooknum, skb, state->in, state->out, + dev_net(state->in)->xt.frame_nat); } static unsigned int ebt_nat_out(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return ebt_do_table(ops->hooknum, skb, in, out, - dev_net(out)->xt.frame_nat); + return ebt_do_table(ops->hooknum, skb, state->in, state->out, + dev_net(state->out)->xt.frame_nat); } static struct nf_hook_ops ebt_ops_nat[] __read_mostly = { diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c index 19473a9371b8..2c46a47160a8 100644 --- a/net/bridge/netfilter/nf_tables_bridge.c +++ b/net/bridge/netfilter/nf_tables_bridge.c @@ -93,21 +93,19 @@ static inline void nft_bridge_set_pktinfo_ipv6(struct nft_pktinfo *pkt, static unsigned int nft_do_chain_bridge(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nft_pktinfo pkt; switch (eth_hdr(skb)->h_proto) { case htons(ETH_P_IP): - nft_bridge_set_pktinfo_ipv4(&pkt, ops, skb, in, out); + nft_bridge_set_pktinfo_ipv4(&pkt, ops, skb, state->in, state->out); break; case htons(ETH_P_IPV6): - nft_bridge_set_pktinfo_ipv6(&pkt, ops, skb, in, out); + nft_bridge_set_pktinfo_ipv6(&pkt, ops, skb, state->in, state->out); break; default: - nft_set_pktinfo(&pkt, ops, skb, in, out); + nft_set_pktinfo(&pkt, ops, skb, state->in, state->out); break; } diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index e4d9560a910b..af34fc9bdf69 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -89,9 +89,7 @@ static void dnrmg_send_peer(struct sk_buff *skb) static unsigned int dnrmg_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { dnrmg_send_peer(skb); return NF_ACCEPT; diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 802ddecb30b8..6a641cb41062 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -28,12 +28,11 @@ static const struct xt_table packet_filter = { /* The work comes in here from netfilter.c */ static unsigned int arptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - const struct net *net = dev_net((in != NULL) ? in : out); + const struct net *net = dev_net(state->in ? state->in : state->out); - return arpt_do_table(skb, ops->hooknum, in, out, + return arpt_do_table(skb, ops->hooknum, state->in, state->out, net->ipv4.arptable_filter); } diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index f75e9df5e017..771ab3d01ad3 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -504,14 +504,12 @@ static void arp_print(struct arp_payload *payload) static unsigned int arp_mangle(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct arphdr *arp = arp_hdr(skb); struct arp_payload *payload; struct clusterip_config *c; - struct net *net = dev_net(in ? in : out); + struct net *net = dev_net(state->in ? state->in : state->out); /* we don't care about non-ethernet and non-ipv4 ARP */ if (arp->ar_hrd != htons(ARPHRD_ETHER) || @@ -536,10 +534,10 @@ arp_mangle(const struct nf_hook_ops *ops, * addresses on different interfacs. However, in the CLUSTERIP case * this wouldn't work, since we didn't subscribe the mcast group on * other interfaces */ - if (c->dev != out) { + if (c->dev != state->out) { pr_debug("not mangling arp reply on different " "interface: cip'%s'-skb'%s'\n", - c->dev->name, out->name); + c->dev->name, state->out->name); clusterip_config_put(c); return NF_ACCEPT; } diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c index a313c3fbeb46..e9e67793055f 100644 --- a/net/ipv4/netfilter/ipt_SYNPROXY.c +++ b/net/ipv4/netfilter/ipt_SYNPROXY.c @@ -300,11 +300,9 @@ synproxy_tg4(struct sk_buff *skb, const struct xt_action_param *par) static unsigned int ipv4_synproxy_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *nhs) { - struct synproxy_net *snet = synproxy_pernet(dev_net(in ? : out)); + struct synproxy_net *snet = synproxy_pernet(dev_net(nhs->in ? : nhs->out)); enum ip_conntrack_info ctinfo; struct nf_conn *ct; struct nf_conn_synproxy *synproxy; diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index e08a74a243a8..1df0d42bfd39 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -34,8 +34,7 @@ static const struct xt_table packet_filter = { static unsigned int iptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { const struct net *net; @@ -45,8 +44,8 @@ iptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, /* root is playing with raw sockets. */ return NF_ACCEPT; - net = dev_net((in != NULL) ? in : out); - return ipt_do_table(skb, ops->hooknum, in, out, + net = dev_net(state->in ? state->in : state->out); + return ipt_do_table(skb, ops->hooknum, state->in, state->out, net->ipv4.iptable_filter); } diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 6a5079c34bb3..7a825e740045 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -81,18 +81,16 @@ ipt_mangle_out(struct sk_buff *skb, const struct net_device *out) static unsigned int iptable_mangle_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { if (ops->hooknum == NF_INET_LOCAL_OUT) - return ipt_mangle_out(skb, out); + return ipt_mangle_out(skb, state->out); if (ops->hooknum == NF_INET_POST_ROUTING) - return ipt_do_table(skb, ops->hooknum, in, out, - dev_net(out)->ipv4.iptable_mangle); + return ipt_do_table(skb, ops->hooknum, state->in, state->out, + dev_net(state->out)->ipv4.iptable_mangle); /* PREROUTING/INPUT/FORWARD: */ - return ipt_do_table(skb, ops->hooknum, in, out, - dev_net(in)->ipv4.iptable_mangle); + return ipt_do_table(skb, ops->hooknum, state->in, state->out, + dev_net(state->in)->ipv4.iptable_mangle); } static struct nf_hook_ops *mangle_ops __read_mostly; diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c index 6b67d7e9a75d..7a7fea4711e5 100644 --- a/net/ipv4/netfilter/iptable_nat.c +++ b/net/ipv4/netfilter/iptable_nat.c @@ -41,38 +41,34 @@ static unsigned int iptable_nat_do_chain(const struct nf_hook_ops *ops, static unsigned int iptable_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv4_fn(ops, skb, in, out, iptable_nat_do_chain); + return nf_nat_ipv4_fn(ops, skb, state->in, state->out, + iptable_nat_do_chain); } static unsigned int iptable_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv4_in(ops, skb, in, out, iptable_nat_do_chain); + return nf_nat_ipv4_in(ops, skb, state->in, state->out, + iptable_nat_do_chain); } static unsigned int iptable_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv4_out(ops, skb, in, out, iptable_nat_do_chain); + return nf_nat_ipv4_out(ops, skb, state->in, state->out, + iptable_nat_do_chain); } static unsigned int iptable_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv4_local_fn(ops, skb, in, out, iptable_nat_do_chain); + return nf_nat_ipv4_local_fn(ops, skb, state->in, state->out, + iptable_nat_do_chain); } static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = { diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index b2f7e8f98316..fac8f607c70b 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -21,8 +21,7 @@ static const struct xt_table packet_raw = { /* The work comes in here from netfilter.c. */ static unsigned int iptable_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { const struct net *net; @@ -32,8 +31,9 @@ iptable_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, /* root is playing with raw sockets. */ return NF_ACCEPT; - net = dev_net((in != NULL) ? in : out); - return ipt_do_table(skb, ops->hooknum, in, out, net->ipv4.iptable_raw); + net = dev_net(state->in ? state->in : state->out); + return ipt_do_table(skb, ops->hooknum, state->in, state->out, + net->ipv4.iptable_raw); } static struct nf_hook_ops *rawtable_ops __read_mostly; diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index c86647ed2078..d9ad60a57413 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -38,9 +38,7 @@ static const struct xt_table security_table = { static unsigned int iptable_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { const struct net *net; @@ -50,8 +48,8 @@ iptable_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, /* Somebody is playing with raw sockets. */ return NF_ACCEPT; - net = dev_net((in != NULL) ? in : out); - return ipt_do_table(skb, ops->hooknum, in, out, + net = dev_net(state->in ? state->in : state->out); + return ipt_do_table(skb, ops->hooknum, state->in, state->out, net->ipv4.iptable_security); } diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 8c8d6642cbb0..30ad9554b5e9 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -94,9 +94,7 @@ static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, static unsigned int ipv4_helper(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; @@ -123,9 +121,7 @@ static unsigned int ipv4_helper(const struct nf_hook_ops *ops, static unsigned int ipv4_confirm(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; @@ -149,24 +145,20 @@ out: static unsigned int ipv4_conntrack_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_conntrack_in(dev_net(in), PF_INET, ops->hooknum, skb); + return nf_conntrack_in(dev_net(state->in), PF_INET, ops->hooknum, skb); } static unsigned int ipv4_conntrack_local(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { /* root is playing with raw sockets. */ if (skb->len < sizeof(struct iphdr) || ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; - return nf_conntrack_in(dev_net(out), PF_INET, ops->hooknum, skb); + return nf_conntrack_in(dev_net(state->out), PF_INET, ops->hooknum, skb); } /* Connection tracking may drop packets, but never alters them, so diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index 7e5ca6f2d0cd..c88b7d434718 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c @@ -63,9 +63,7 @@ static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum, static unsigned int ipv4_conntrack_defrag(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(skb->sk); diff --git a/net/ipv4/netfilter/nf_tables_arp.c b/net/ipv4/netfilter/nf_tables_arp.c index 19412a4063fb..fceb50e1e87d 100644 --- a/net/ipv4/netfilter/nf_tables_arp.c +++ b/net/ipv4/netfilter/nf_tables_arp.c @@ -17,13 +17,11 @@ static unsigned int nft_do_chain_arp(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nft_pktinfo pkt; - nft_set_pktinfo(&pkt, ops, skb, in, out); + nft_set_pktinfo(&pkt, ops, skb, state->in, state->out); return nft_do_chain(&pkt, ops); } diff --git a/net/ipv4/netfilter/nf_tables_ipv4.c b/net/ipv4/netfilter/nf_tables_ipv4.c index 6820c8c40842..708e388e3dbe 100644 --- a/net/ipv4/netfilter/nf_tables_ipv4.c +++ b/net/ipv4/netfilter/nf_tables_ipv4.c @@ -20,22 +20,18 @@ static unsigned int nft_do_chain_ipv4(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nft_pktinfo pkt; - nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); + nft_set_pktinfo_ipv4(&pkt, ops, skb, state->in, state->out); return nft_do_chain(&pkt, ops); } static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { if (unlikely(skb->len < sizeof(struct iphdr) || ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) { @@ -45,7 +41,7 @@ static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, return NF_ACCEPT; } - return nft_do_chain_ipv4(ops, skb, in, out, okfn); + return nft_do_chain_ipv4(ops, skb, state); } struct nft_af_info nft_af_ipv4 __read_mostly = { diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c index df547bf50078..d08db6b0fcc3 100644 --- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c @@ -41,38 +41,31 @@ static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, static unsigned int nft_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv4_fn(ops, skb, in, out, nft_nat_do_chain); + return nf_nat_ipv4_fn(ops, skb, state->in, state->out, nft_nat_do_chain); } static unsigned int nft_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv4_in(ops, skb, in, out, nft_nat_do_chain); + return nf_nat_ipv4_in(ops, skb, state->in, state->out, nft_nat_do_chain); } static unsigned int nft_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv4_out(ops, skb, in, out, nft_nat_do_chain); + return nf_nat_ipv4_out(ops, skb, state->in, state->out, nft_nat_do_chain); } static unsigned int nft_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv4_local_fn(ops, skb, in, out, nft_nat_do_chain); + return nf_nat_ipv4_local_fn(ops, skb, state->in, state->out, + nft_nat_do_chain); } static const struct nf_chain_type nft_chain_nat_ipv4 = { diff --git a/net/ipv4/netfilter/nft_chain_route_ipv4.c b/net/ipv4/netfilter/nft_chain_route_ipv4.c index 125b66766c0a..073d0776ae7f 100644 --- a/net/ipv4/netfilter/nft_chain_route_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_route_ipv4.c @@ -23,9 +23,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { unsigned int ret; struct nft_pktinfo pkt; @@ -39,7 +37,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; - nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); + nft_set_pktinfo_ipv4(&pkt, ops, skb, state->in, state->out); mark = skb->mark; iph = ip_hdr(skb); diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c index a0d17270117c..6edb7b106de7 100644 --- a/net/ipv6/netfilter/ip6t_SYNPROXY.c +++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c @@ -315,11 +315,9 @@ synproxy_tg6(struct sk_buff *skb, const struct xt_action_param *par) static unsigned int ipv6_synproxy_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *nhs) { - struct synproxy_net *snet = synproxy_pernet(dev_net(in ? : out)); + struct synproxy_net *snet = synproxy_pernet(dev_net(nhs->in ? : nhs->out)); enum ip_conntrack_info ctinfo; struct nf_conn *ct; struct nf_conn_synproxy *synproxy; diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index ca7f6c128086..eb9ef093454f 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -33,12 +33,11 @@ static const struct xt_table packet_filter = { /* The work comes in here from netfilter.c. */ static unsigned int ip6table_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - const struct net *net = dev_net((in != NULL) ? in : out); + const struct net *net = dev_net(state->in ? state->in : state->out); - return ip6t_do_table(skb, ops->hooknum, in, out, + return ip6t_do_table(skb, ops->hooknum, state->in, state->out, net->ipv6.ip6table_filter); } diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 307bbb782d14..e713b8d3dbbc 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -77,17 +77,16 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) /* The work comes in here from netfilter.c. */ static unsigned int ip6table_mangle_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { if (ops->hooknum == NF_INET_LOCAL_OUT) - return ip6t_mangle_out(skb, out); + return ip6t_mangle_out(skb, state->out); if (ops->hooknum == NF_INET_POST_ROUTING) - return ip6t_do_table(skb, ops->hooknum, in, out, - dev_net(out)->ipv6.ip6table_mangle); + return ip6t_do_table(skb, ops->hooknum, state->in, state->out, + dev_net(state->out)->ipv6.ip6table_mangle); /* INPUT/FORWARD */ - return ip6t_do_table(skb, ops->hooknum, in, out, - dev_net(in)->ipv6.ip6table_mangle); + return ip6t_do_table(skb, ops->hooknum, state->in, state->out, + dev_net(state->in)->ipv6.ip6table_mangle); } static struct nf_hook_ops *mangle_ops __read_mostly; diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index b0634ac996b7..e32b0d0315e6 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c @@ -43,38 +43,34 @@ static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops, static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv6_fn(ops, skb, in, out, ip6table_nat_do_chain); + return nf_nat_ipv6_fn(ops, skb, state->in, state->out, + ip6table_nat_do_chain); } static unsigned int ip6table_nat_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv6_in(ops, skb, in, out, ip6table_nat_do_chain); + return nf_nat_ipv6_in(ops, skb, state->in, state->out, + ip6table_nat_do_chain); } static unsigned int ip6table_nat_out(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv6_out(ops, skb, in, out, ip6table_nat_do_chain); + return nf_nat_ipv6_out(ops, skb, state->in, state->out, + ip6table_nat_do_chain); } static unsigned int ip6table_nat_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv6_local_fn(ops, skb, in, out, ip6table_nat_do_chain); + return nf_nat_ipv6_local_fn(ops, skb, state->in, state->out, + ip6table_nat_do_chain); } static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 5274740acecc..937908e25862 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -20,12 +20,11 @@ static const struct xt_table packet_raw = { /* The work comes in here from netfilter.c. */ static unsigned int ip6table_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - const struct net *net = dev_net((in != NULL) ? in : out); + const struct net *net = dev_net(state->in ? state->in : state->out); - return ip6t_do_table(skb, ops->hooknum, in, out, + return ip6t_do_table(skb, ops->hooknum, state->in, state->out, net->ipv6.ip6table_raw); } diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index ab3b0219ecfa..f33b41e8e294 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -37,13 +37,11 @@ static const struct xt_table security_table = { static unsigned int ip6table_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - const struct net *net = dev_net((in != NULL) ? in : out); + const struct net *net = dev_net(state->in ? state->in : state->out); - return ip6t_do_table(skb, ops->hooknum, in, out, + return ip6t_do_table(skb, ops->hooknum, state->in, state->out, net->ipv6.ip6table_security); } diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index fba91c6fc7ca..4ba0c34c627b 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -97,9 +97,7 @@ static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, static unsigned int ipv6_helper(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nf_conn *ct; const struct nf_conn_help *help; @@ -135,9 +133,7 @@ static unsigned int ipv6_helper(const struct nf_hook_ops *ops, static unsigned int ipv6_confirm(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; @@ -171,25 +167,21 @@ out: static unsigned int ipv6_conntrack_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_conntrack_in(dev_net(in), PF_INET6, ops->hooknum, skb); + return nf_conntrack_in(dev_net(state->in), PF_INET6, ops->hooknum, skb); } static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { /* root is playing with raw sockets. */ if (skb->len < sizeof(struct ipv6hdr)) { net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); return NF_ACCEPT; } - return nf_conntrack_in(dev_net(out), PF_INET6, ops->hooknum, skb); + return nf_conntrack_in(dev_net(state->out), PF_INET6, ops->hooknum, skb); } static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c index e70382e4dfb5..e2b882056751 100644 --- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c @@ -54,9 +54,7 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, static unsigned int ipv6_defrag(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct sk_buff *reasm; @@ -78,8 +76,8 @@ static unsigned int ipv6_defrag(const struct nf_hook_ops *ops, nf_ct_frag6_consume_orig(reasm); NF_HOOK_THRESH(NFPROTO_IPV6, ops->hooknum, reasm, - (struct net_device *) in, (struct net_device *) out, - okfn, NF_IP6_PRI_CONNTRACK_DEFRAG + 1); + state->in, state->out, + state->okfn, NF_IP6_PRI_CONNTRACK_DEFRAG + 1); return NF_STOLEN; } diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c index 0d812b31277d..224bc8971a0b 100644 --- a/net/ipv6/netfilter/nf_tables_ipv6.c +++ b/net/ipv6/netfilter/nf_tables_ipv6.c @@ -18,14 +18,12 @@ static unsigned int nft_do_chain_ipv6(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct nft_pktinfo pkt; /* malformed packet, drop it */ - if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) + if (nft_set_pktinfo_ipv6(&pkt, ops, skb, state->in, state->out) < 0) return NF_DROP; return nft_do_chain(&pkt, ops); @@ -33,9 +31,7 @@ static unsigned int nft_do_chain_ipv6(const struct nf_hook_ops *ops, static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { if (unlikely(skb->len < sizeof(struct ipv6hdr))) { if (net_ratelimit()) @@ -44,7 +40,7 @@ static unsigned int nft_ipv6_output(const struct nf_hook_ops *ops, return NF_ACCEPT; } - return nft_do_chain_ipv6(ops, skb, in, out, okfn); + return nft_do_chain_ipv6(ops, skb, state); } struct nft_af_info nft_af_ipv6 __read_mostly = { diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c index 1c4b75dd425b..f73f4ae25bc2 100644 --- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c @@ -39,38 +39,30 @@ static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, static unsigned int nft_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv6_fn(ops, skb, in, out, nft_nat_do_chain); + return nf_nat_ipv6_fn(ops, skb, state->in, state->out, nft_nat_do_chain); } static unsigned int nft_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv6_in(ops, skb, in, out, nft_nat_do_chain); + return nf_nat_ipv6_in(ops, skb, state->in, state->out, nft_nat_do_chain); } static unsigned int nft_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv6_out(ops, skb, in, out, nft_nat_do_chain); + return nf_nat_ipv6_out(ops, skb, state->in, state->out, nft_nat_do_chain); } static unsigned int nft_nat_ipv6_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return nf_nat_ipv6_local_fn(ops, skb, in, out, nft_nat_do_chain); + return nf_nat_ipv6_local_fn(ops, skb, state->in, state->out, nft_nat_do_chain); } static const struct nf_chain_type nft_chain_nat_ipv6 = { diff --git a/net/ipv6/netfilter/nft_chain_route_ipv6.c b/net/ipv6/netfilter/nft_chain_route_ipv6.c index 42031299585e..c826c3c854b2 100644 --- a/net/ipv6/netfilter/nft_chain_route_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_route_ipv6.c @@ -24,9 +24,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { unsigned int ret; struct nft_pktinfo pkt; @@ -35,7 +33,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, u32 mark, flowlabel; /* malformed packet, drop it */ - if (nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out) < 0) + if (nft_set_pktinfo_ipv6(&pkt, ops, skb, state->in, state->out) < 0) return NF_DROP; /* save source/dest address, mark, hoplimit, flowlabel, priority */ diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 11d04ebfc5e3..e6163017c42d 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -136,8 +136,7 @@ unsigned int nf_iterate(struct list_head *head, /* Optimization: we don't need to hold module reference here, since function can't sleep. --RR */ repeat: - verdict = (*elemp)->hook(*elemp, skb, state->in, state->out, - state->okfn); + verdict = (*elemp)->hook(*elemp, skb, state); if (verdict != NF_ACCEPT) { #ifdef CONFIG_NETFILTER_DEBUG if (unlikely((verdict & NF_VERDICT_MASK) diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 04dbd9c7213f..5d2b806a862e 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1272,8 +1272,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af) */ static unsigned int ip_vs_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { return ip_vs_out(ops->hooknum, skb, AF_INET); } @@ -1284,8 +1283,7 @@ ip_vs_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb, */ static unsigned int ip_vs_local_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { return ip_vs_out(ops->hooknum, skb, AF_INET); } @@ -1299,8 +1297,7 @@ ip_vs_local_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb, */ static unsigned int ip_vs_reply6(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { return ip_vs_out(ops->hooknum, skb, AF_INET6); } @@ -1311,8 +1308,7 @@ ip_vs_reply6(const struct nf_hook_ops *ops, struct sk_buff *skb, */ static unsigned int ip_vs_local_reply6(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { return ip_vs_out(ops->hooknum, skb, AF_INET6); } @@ -1769,9 +1765,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) */ static unsigned int ip_vs_remote_request4(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { return ip_vs_in(ops->hooknum, skb, AF_INET); } @@ -1782,8 +1776,7 @@ ip_vs_remote_request4(const struct nf_hook_ops *ops, struct sk_buff *skb, */ static unsigned int ip_vs_local_request4(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { return ip_vs_in(ops->hooknum, skb, AF_INET); } @@ -1796,9 +1789,7 @@ ip_vs_local_request4(const struct nf_hook_ops *ops, struct sk_buff *skb, */ static unsigned int ip_vs_remote_request6(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { return ip_vs_in(ops->hooknum, skb, AF_INET6); } @@ -1809,8 +1800,7 @@ ip_vs_remote_request6(const struct nf_hook_ops *ops, struct sk_buff *skb, */ static unsigned int ip_vs_local_request6(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { return ip_vs_in(ops->hooknum, skb, AF_INET6); } @@ -1829,8 +1819,7 @@ ip_vs_local_request6(const struct nf_hook_ops *ops, struct sk_buff *skb, */ static unsigned int ip_vs_forward_icmp(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { int r; struct net *net; @@ -1851,8 +1840,7 @@ ip_vs_forward_icmp(const struct nf_hook_ops *ops, struct sk_buff *skb, #ifdef CONFIG_IP_VS_IPV6 static unsigned int ip_vs_forward_icmp_v6(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { int r; struct net *net; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index edc66de39f2e..7e392edaab97 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4852,21 +4852,17 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return selinux_ip_forward(skb, in, PF_INET); + return selinux_ip_forward(skb, state->in, PF_INET); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return selinux_ip_forward(skb, in, PF_INET6); + return selinux_ip_forward(skb, state->in, PF_INET6); } #endif /* IPV6 */ @@ -4914,9 +4910,7 @@ static unsigned int selinux_ip_output(struct sk_buff *skb, static unsigned int selinux_ipv4_output(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { return selinux_ip_output(skb, PF_INET); } @@ -5091,21 +5085,17 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return selinux_ip_postroute(skb, out, PF_INET); + return selinux_ip_postroute(skb, state->out, PF_INET); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { - return selinux_ip_postroute(skb, out, PF_INET6); + return selinux_ip_postroute(skb, state->out, PF_INET6); } #endif /* IPV6 */ diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c index c952632afb0d..a455cfc9ec1f 100644 --- a/security/smack/smack_netfilter.c +++ b/security/smack/smack_netfilter.c @@ -23,9 +23,7 @@ static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct socket_smack *ssp; struct smack_known *skp; @@ -42,9 +40,7 @@ static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops, static unsigned int smack_ipv4_output(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) + const struct nf_hook_state *state) { struct socket_smack *ssp; struct smack_known *skp; From d7cf4081ed454dba02cb632e492ecf5e29d1ee44 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 3 Apr 2015 20:51:13 -0400 Subject: [PATCH 535/567] netfilter: Pass nf_hook_state through nf_nat_ipv4_{in,out,fn,local_fn}(). Signed-off-by: David S. Miller --- include/net/netfilter/nf_nat_l3proto.h | 24 ++++++----------- net/ipv4/netfilter/iptable_nat.c | 18 +++++-------- net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | 33 +++++++++++------------- net/ipv4/netfilter/nft_chain_nat_ipv4.c | 14 +++++----- 4 files changed, 36 insertions(+), 53 deletions(-) diff --git a/include/net/netfilter/nf_nat_l3proto.h b/include/net/netfilter/nf_nat_l3proto.h index 340c013795a4..e596f35f14c9 100644 --- a/include/net/netfilter/nf_nat_l3proto.h +++ b/include/net/netfilter/nf_nat_l3proto.h @@ -44,40 +44,32 @@ int nf_nat_icmp_reply_translation(struct sk_buff *skb, struct nf_conn *ct, unsigned int hooknum); unsigned int nf_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)); unsigned int nf_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)); unsigned int nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)); unsigned int nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)); int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, struct nf_conn *ct, diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c index 7a7fea4711e5..086e2311438e 100644 --- a/net/ipv4/netfilter/iptable_nat.c +++ b/net/ipv4/netfilter/iptable_nat.c @@ -30,45 +30,41 @@ static const struct xt_table nf_nat_ipv4_table = { static unsigned int iptable_nat_do_chain(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct) { struct net *net = nf_ct_net(ct); - return ipt_do_table(skb, ops->hooknum, in, out, net->ipv4.nat_table); + return ipt_do_table(skb, ops->hooknum, state->in, state->out, + net->ipv4.nat_table); } static unsigned int iptable_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv4_fn(ops, skb, state->in, state->out, - iptable_nat_do_chain); + return nf_nat_ipv4_fn(ops, skb, state, iptable_nat_do_chain); } static unsigned int iptable_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv4_in(ops, skb, state->in, state->out, - iptable_nat_do_chain); + return nf_nat_ipv4_in(ops, skb, state, iptable_nat_do_chain); } static unsigned int iptable_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv4_out(ops, skb, state->in, state->out, - iptable_nat_do_chain); + return nf_nat_ipv4_out(ops, skb, state, iptable_nat_do_chain); } static unsigned int iptable_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv4_local_fn(ops, skb, state->in, state->out, - iptable_nat_do_chain); + return nf_nat_ipv4_local_fn(ops, skb, state, iptable_nat_do_chain); } static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = { diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c index fc37711e11f3..e59cc05c09e9 100644 --- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c @@ -256,11 +256,10 @@ EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); unsigned int nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)) { struct nf_conn *ct; @@ -309,7 +308,7 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, if (!nf_nat_initialized(ct, maniptype)) { unsigned int ret; - ret = do_chain(ops, skb, in, out, ct); + ret = do_chain(ops, skb, state, ct); if (ret != NF_ACCEPT) return ret; @@ -323,7 +322,8 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, pr_debug("Already setup manip %s for ct %p\n", maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", ct); - if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) + if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, + state->out)) goto oif_changed; } break; @@ -332,7 +332,7 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, /* ESTABLISHED */ NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == IP_CT_ESTABLISHED_REPLY); - if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) + if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, state->out)) goto oif_changed; } @@ -346,17 +346,16 @@ EXPORT_SYMBOL_GPL(nf_nat_ipv4_fn); unsigned int nf_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)) { unsigned int ret; __be32 daddr = ip_hdr(skb)->daddr; - ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain); + ret = nf_nat_ipv4_fn(ops, skb, state, do_chain); if (ret != NF_DROP && ret != NF_STOLEN && daddr != ip_hdr(skb)->daddr) skb_dst_drop(skb); @@ -367,11 +366,10 @@ EXPORT_SYMBOL_GPL(nf_nat_ipv4_in); unsigned int nf_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)) { #ifdef CONFIG_XFRM @@ -386,7 +384,7 @@ nf_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; - ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain); + ret = nf_nat_ipv4_fn(ops, skb, state, do_chain); #ifdef CONFIG_XFRM if (ret != NF_DROP && ret != NF_STOLEN && !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && @@ -410,11 +408,10 @@ EXPORT_SYMBOL_GPL(nf_nat_ipv4_out); unsigned int nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)) { const struct nf_conn *ct; @@ -427,7 +424,7 @@ nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; - ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain); + ret = nf_nat_ipv4_fn(ops, skb, state, do_chain); if (ret != NF_DROP && ret != NF_STOLEN && (ct = nf_ct_get(skb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c index d08db6b0fcc3..f56bbb1ab1a0 100644 --- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c @@ -28,13 +28,12 @@ static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct) { struct nft_pktinfo pkt; - nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); + nft_set_pktinfo_ipv4(&pkt, ops, skb, state->in, state->out); return nft_do_chain(&pkt, ops); } @@ -43,29 +42,28 @@ static unsigned int nft_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv4_fn(ops, skb, state->in, state->out, nft_nat_do_chain); + return nf_nat_ipv4_fn(ops, skb, state, nft_nat_do_chain); } static unsigned int nft_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv4_in(ops, skb, state->in, state->out, nft_nat_do_chain); + return nf_nat_ipv4_in(ops, skb, state, nft_nat_do_chain); } static unsigned int nft_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv4_out(ops, skb, state->in, state->out, nft_nat_do_chain); + return nf_nat_ipv4_out(ops, skb, state, nft_nat_do_chain); } static unsigned int nft_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv4_local_fn(ops, skb, state->in, state->out, - nft_nat_do_chain); + return nf_nat_ipv4_local_fn(ops, skb, state, nft_nat_do_chain); } static const struct nf_chain_type nft_chain_nat_ipv4 = { From 1c491ba2592f621f21a693d43fab06302527fc0f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 3 Apr 2015 20:56:08 -0400 Subject: [PATCH 536/567] netfilter: Pass nf_hook_state through ipt_do_table(). Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_tables.h | 3 +-- net/ipv4/netfilter/ip_tables.c | 13 ++++++------- net/ipv4/netfilter/iptable_filter.c | 3 +-- net/ipv4/netfilter/iptable_mangle.c | 11 ++++++----- net/ipv4/netfilter/iptable_nat.c | 3 +-- net/ipv4/netfilter/iptable_raw.c | 3 +-- net/ipv4/netfilter/iptable_security.c | 2 +- 7 files changed, 17 insertions(+), 21 deletions(-) diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 901e84db847d..4073510da485 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -65,8 +65,7 @@ struct ipt_error { extern void *ipt_alloc_initial_table(const struct xt_table *); extern unsigned int ipt_do_table(struct sk_buff *skb, unsigned int hook, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct xt_table *table); #ifdef CONFIG_COMPAT diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index cf5e82f39d3b..c69db7fa25ee 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -288,8 +288,7 @@ struct ipt_entry *ipt_next_entry(const struct ipt_entry *entry) unsigned int ipt_do_table(struct sk_buff *skb, unsigned int hook, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct xt_table *table) { static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); @@ -306,8 +305,8 @@ ipt_do_table(struct sk_buff *skb, /* Initialization */ ip = ip_hdr(skb); - indev = in ? in->name : nulldevname; - outdev = out ? out->name : nulldevname; + indev = state->in ? state->in->name : nulldevname; + outdev = state->out ? state->out->name : nulldevname; /* We handle fragments by dealing with the first fragment as * if it was a normal packet. All other fragments are treated * normally, except that they will NEVER match rules that ask @@ -317,8 +316,8 @@ ipt_do_table(struct sk_buff *skb, acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET; acpar.thoff = ip_hdrlen(skb); acpar.hotdrop = false; - acpar.in = in; - acpar.out = out; + acpar.in = state->in; + acpar.out = state->out; acpar.family = NFPROTO_IPV4; acpar.hooknum = hook; @@ -370,7 +369,7 @@ ipt_do_table(struct sk_buff *skb, #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) /* The packet is traced: log it */ if (unlikely(skb->nf_trace)) - trace_packet(skb, hook, in, out, + trace_packet(skb, hook, state->in, state->out, table->name, private, e); #endif /* Standard target? */ diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 1df0d42bfd39..a0f3beca52d2 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -45,8 +45,7 @@ iptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, return NF_ACCEPT; net = dev_net(state->in ? state->in : state->out); - return ipt_do_table(skb, ops->hooknum, state->in, state->out, - net->ipv4.iptable_filter); + return ipt_do_table(skb, ops->hooknum, state, net->ipv4.iptable_filter); } static struct nf_hook_ops *filter_ops __read_mostly; diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 7a825e740045..62cbb8c5f4a8 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -37,8 +37,9 @@ static const struct xt_table packet_mangler = { }; static unsigned int -ipt_mangle_out(struct sk_buff *skb, const struct net_device *out) +ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) { + struct net_device *out = state->out; unsigned int ret; const struct iphdr *iph; u_int8_t tos; @@ -58,7 +59,7 @@ ipt_mangle_out(struct sk_buff *skb, const struct net_device *out) daddr = iph->daddr; tos = iph->tos; - ret = ipt_do_table(skb, NF_INET_LOCAL_OUT, NULL, out, + ret = ipt_do_table(skb, NF_INET_LOCAL_OUT, state, dev_net(out)->ipv4.iptable_mangle); /* Reroute for ANY change. */ if (ret != NF_DROP && ret != NF_STOLEN) { @@ -84,12 +85,12 @@ iptable_mangle_hook(const struct nf_hook_ops *ops, const struct nf_hook_state *state) { if (ops->hooknum == NF_INET_LOCAL_OUT) - return ipt_mangle_out(skb, state->out); + return ipt_mangle_out(skb, state); if (ops->hooknum == NF_INET_POST_ROUTING) - return ipt_do_table(skb, ops->hooknum, state->in, state->out, + return ipt_do_table(skb, ops->hooknum, state, dev_net(state->out)->ipv4.iptable_mangle); /* PREROUTING/INPUT/FORWARD: */ - return ipt_do_table(skb, ops->hooknum, state->in, state->out, + return ipt_do_table(skb, ops->hooknum, state, dev_net(state->in)->ipv4.iptable_mangle); } diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c index 086e2311438e..0d4d9cdf98a4 100644 --- a/net/ipv4/netfilter/iptable_nat.c +++ b/net/ipv4/netfilter/iptable_nat.c @@ -35,8 +35,7 @@ static unsigned int iptable_nat_do_chain(const struct nf_hook_ops *ops, { struct net *net = nf_ct_net(ct); - return ipt_do_table(skb, ops->hooknum, state->in, state->out, - net->ipv4.nat_table); + return ipt_do_table(skb, ops->hooknum, state, net->ipv4.nat_table); } static unsigned int iptable_nat_ipv4_fn(const struct nf_hook_ops *ops, diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index fac8f607c70b..0356e6da4bb7 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -32,8 +32,7 @@ iptable_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, return NF_ACCEPT; net = dev_net(state->in ? state->in : state->out); - return ipt_do_table(skb, ops->hooknum, state->in, state->out, - net->ipv4.iptable_raw); + return ipt_do_table(skb, ops->hooknum, state, net->ipv4.iptable_raw); } static struct nf_hook_ops *rawtable_ops __read_mostly; diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c index d9ad60a57413..4bce3980ccd9 100644 --- a/net/ipv4/netfilter/iptable_security.c +++ b/net/ipv4/netfilter/iptable_security.c @@ -49,7 +49,7 @@ iptable_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, return NF_ACCEPT; net = dev_net(state->in ? state->in : state->out); - return ipt_do_table(skb, ops->hooknum, state->in, state->out, + return ipt_do_table(skb, ops->hooknum, state, net->ipv4.iptable_security); } From 8fe22382d1e73dc0ded8098ccf761c986149f72b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 3 Apr 2015 21:05:07 -0400 Subject: [PATCH 537/567] netfilter: Pass nf_hook_state through nf_nat_ipv6_{in,out,fn,local_fn}(). Signed-off-by: David S. Miller --- include/net/netfilter/nf_nat_l3proto.h | 24 ++++++------------ net/ipv6/netfilter/ip6table_nat.c | 18 ++++++------- net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 32 +++++++++++------------- net/ipv6/netfilter/nft_chain_nat_ipv6.c | 13 +++++----- 4 files changed, 35 insertions(+), 52 deletions(-) diff --git a/include/net/netfilter/nf_nat_l3proto.h b/include/net/netfilter/nf_nat_l3proto.h index e596f35f14c9..a3127325f624 100644 --- a/include/net/netfilter/nf_nat_l3proto.h +++ b/include/net/netfilter/nf_nat_l3proto.h @@ -77,40 +77,32 @@ int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, struct nf_conn *ct, unsigned int hooknum, unsigned int hdrlen); unsigned int nf_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)); unsigned int nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)); unsigned int nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)); unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)); #endif /* _NF_NAT_L3PROTO_H */ diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index e32b0d0315e6..d78f69c7abce 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c @@ -32,45 +32,41 @@ static const struct xt_table nf_nat_ipv6_table = { static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct) { struct net *net = nf_ct_net(ct); - return ip6t_do_table(skb, ops->hooknum, in, out, net->ipv6.ip6table_nat); + return ip6t_do_table(skb, ops->hooknum, state->in, state->out, + net->ipv6.ip6table_nat); } static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv6_fn(ops, skb, state->in, state->out, - ip6table_nat_do_chain); + return nf_nat_ipv6_fn(ops, skb, state, ip6table_nat_do_chain); } static unsigned int ip6table_nat_in(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv6_in(ops, skb, state->in, state->out, - ip6table_nat_do_chain); + return nf_nat_ipv6_in(ops, skb, state, ip6table_nat_do_chain); } static unsigned int ip6table_nat_out(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv6_out(ops, skb, state->in, state->out, - ip6table_nat_do_chain); + return nf_nat_ipv6_out(ops, skb, state, ip6table_nat_do_chain); } static unsigned int ip6table_nat_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv6_local_fn(ops, skb, state->in, state->out, - ip6table_nat_do_chain); + return nf_nat_ipv6_local_fn(ops, skb, state, ip6table_nat_do_chain); } static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c index c5812e1c1ffb..e76900e0aa92 100644 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c @@ -263,11 +263,10 @@ EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation); unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)) { struct nf_conn *ct; @@ -318,7 +317,7 @@ nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, if (!nf_nat_initialized(ct, maniptype)) { unsigned int ret; - ret = do_chain(ops, skb, in, out, ct); + ret = do_chain(ops, skb, state, ct); if (ret != NF_ACCEPT) return ret; @@ -332,7 +331,7 @@ nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, pr_debug("Already setup manip %s for ct %p\n", maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", ct); - if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) + if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, state->out)) goto oif_changed; } break; @@ -341,7 +340,7 @@ nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, /* ESTABLISHED */ NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == IP_CT_ESTABLISHED_REPLY); - if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) + if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, state->out)) goto oif_changed; } @@ -355,17 +354,16 @@ EXPORT_SYMBOL_GPL(nf_nat_ipv6_fn); unsigned int nf_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)) { unsigned int ret; struct in6_addr daddr = ipv6_hdr(skb)->daddr; - ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); + ret = nf_nat_ipv6_fn(ops, skb, state, do_chain); if (ret != NF_DROP && ret != NF_STOLEN && ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) skb_dst_drop(skb); @@ -376,11 +374,10 @@ EXPORT_SYMBOL_GPL(nf_nat_ipv6_in); unsigned int nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)) { #ifdef CONFIG_XFRM @@ -394,7 +391,7 @@ nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, if (skb->len < sizeof(struct ipv6hdr)) return NF_ACCEPT; - ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); + ret = nf_nat_ipv6_fn(ops, skb, state, do_chain); #ifdef CONFIG_XFRM if (ret != NF_DROP && ret != NF_STOLEN && !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && @@ -418,11 +415,10 @@ EXPORT_SYMBOL_GPL(nf_nat_ipv6_out); unsigned int nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, const struct net_device *out, + const struct nf_hook_state *state, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct)) { const struct nf_conn *ct; @@ -434,7 +430,7 @@ nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, if (skb->len < sizeof(struct ipv6hdr)) return NF_ACCEPT; - ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); + ret = nf_nat_ipv6_fn(ops, skb, state, do_chain); if (ret != NF_DROP && ret != NF_STOLEN && (ct = nf_ct_get(skb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c index f73f4ae25bc2..11c6f75fcc4d 100644 --- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c @@ -26,13 +26,12 @@ static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct nf_conn *ct) { struct nft_pktinfo pkt; - nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); + nft_set_pktinfo_ipv6(&pkt, ops, skb, state->in, state->out); return nft_do_chain(&pkt, ops); } @@ -41,28 +40,28 @@ static unsigned int nft_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv6_fn(ops, skb, state->in, state->out, nft_nat_do_chain); + return nf_nat_ipv6_fn(ops, skb, state, nft_nat_do_chain); } static unsigned int nft_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv6_in(ops, skb, state->in, state->out, nft_nat_do_chain); + return nf_nat_ipv6_in(ops, skb, state, nft_nat_do_chain); } static unsigned int nft_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv6_out(ops, skb, state->in, state->out, nft_nat_do_chain); + return nf_nat_ipv6_out(ops, skb, state, nft_nat_do_chain); } static unsigned int nft_nat_ipv6_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { - return nf_nat_ipv6_local_fn(ops, skb, state->in, state->out, nft_nat_do_chain); + return nf_nat_ipv6_local_fn(ops, skb, state, nft_nat_do_chain); } static const struct nf_chain_type nft_chain_nat_ipv6 = { From 8f8a37152df49d541c43f010543f2b0176fcfb8e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 3 Apr 2015 21:09:51 -0400 Subject: [PATCH 538/567] netfilter: Pass nf_hook_state through ip6t_do_table(). Signed-off-by: David S. Miller --- include/linux/netfilter_ipv6/ip6_tables.h | 3 +-- net/ipv6/netfilter/ip6_tables.c | 13 ++++++------- net/ipv6/netfilter/ip6table_filter.c | 3 +-- net/ipv6/netfilter/ip6table_mangle.c | 12 ++++++------ net/ipv6/netfilter/ip6table_nat.c | 3 +-- net/ipv6/netfilter/ip6table_raw.c | 3 +-- net/ipv6/netfilter/ip6table_security.c | 2 +- 7 files changed, 17 insertions(+), 22 deletions(-) diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 610208b18c05..b40d2b635778 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -31,8 +31,7 @@ extern struct xt_table *ip6t_register_table(struct net *net, extern void ip6t_unregister_table(struct net *net, struct xt_table *table); extern unsigned int ip6t_do_table(struct sk_buff *skb, unsigned int hook, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct xt_table *table); /* Check for an extension */ diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 83f59dc3cccc..1a732a1d3c8e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -317,8 +317,7 @@ ip6t_next_entry(const struct ip6t_entry *entry) unsigned int ip6t_do_table(struct sk_buff *skb, unsigned int hook, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct xt_table *table) { static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); @@ -333,8 +332,8 @@ ip6t_do_table(struct sk_buff *skb, unsigned int addend; /* Initialization */ - indev = in ? in->name : nulldevname; - outdev = out ? out->name : nulldevname; + indev = state->in ? state->in->name : nulldevname; + outdev = state->out ? state->out->name : nulldevname; /* We handle fragments by dealing with the first fragment as * if it was a normal packet. All other fragments are treated * normally, except that they will NEVER match rules that ask @@ -342,8 +341,8 @@ ip6t_do_table(struct sk_buff *skb, * rule is also a fragment-specific rule, non-fragments won't * match it. */ acpar.hotdrop = false; - acpar.in = in; - acpar.out = out; + acpar.in = state->in; + acpar.out = state->out; acpar.family = NFPROTO_IPV6; acpar.hooknum = hook; @@ -393,7 +392,7 @@ ip6t_do_table(struct sk_buff *skb, #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) /* The packet is traced: log it */ if (unlikely(skb->nf_trace)) - trace_packet(skb, hook, in, out, + trace_packet(skb, hook, state->in, state->out, table->name, private, e); #endif /* Standard target? */ diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index eb9ef093454f..5c33d8abc077 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -37,8 +37,7 @@ ip6table_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, { const struct net *net = dev_net(state->in ? state->in : state->out); - return ip6t_do_table(skb, ops->hooknum, state->in, state->out, - net->ipv6.ip6table_filter); + return ip6t_do_table(skb, ops->hooknum, state, net->ipv6.ip6table_filter); } static struct nf_hook_ops *filter_ops __read_mostly; diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index e713b8d3dbbc..b551f5b79fe2 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -32,7 +32,7 @@ static const struct xt_table packet_mangler = { }; static unsigned int -ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) +ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) { unsigned int ret; struct in6_addr saddr, daddr; @@ -57,8 +57,8 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) /* flowlabel and prio (includes version, which shouldn't change either */ flowlabel = *((u_int32_t *)ipv6_hdr(skb)); - ret = ip6t_do_table(skb, NF_INET_LOCAL_OUT, NULL, out, - dev_net(out)->ipv6.ip6table_mangle); + ret = ip6t_do_table(skb, NF_INET_LOCAL_OUT, state, + dev_net(state->out)->ipv6.ip6table_mangle); if (ret != NF_DROP && ret != NF_STOLEN && (!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) || @@ -80,12 +80,12 @@ ip6table_mangle_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { if (ops->hooknum == NF_INET_LOCAL_OUT) - return ip6t_mangle_out(skb, state->out); + return ip6t_mangle_out(skb, state); if (ops->hooknum == NF_INET_POST_ROUTING) - return ip6t_do_table(skb, ops->hooknum, state->in, state->out, + return ip6t_do_table(skb, ops->hooknum, state, dev_net(state->out)->ipv6.ip6table_mangle); /* INPUT/FORWARD */ - return ip6t_do_table(skb, ops->hooknum, state->in, state->out, + return ip6t_do_table(skb, ops->hooknum, state, dev_net(state->in)->ipv6.ip6table_mangle); } diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index d78f69c7abce..c3a7f7af0ed4 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c @@ -37,8 +37,7 @@ static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops, { struct net *net = nf_ct_net(ct); - return ip6t_do_table(skb, ops->hooknum, state->in, state->out, - net->ipv6.ip6table_nat); + return ip6t_do_table(skb, ops->hooknum, state, net->ipv6.ip6table_nat); } static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops, diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 937908e25862..0b33caad2b69 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -24,8 +24,7 @@ ip6table_raw_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, { const struct net *net = dev_net(state->in ? state->in : state->out); - return ip6t_do_table(skb, ops->hooknum, state->in, state->out, - net->ipv6.ip6table_raw); + return ip6t_do_table(skb, ops->hooknum, state, net->ipv6.ip6table_raw); } static struct nf_hook_ops *rawtable_ops __read_mostly; diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index f33b41e8e294..fcef83c25f7b 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c @@ -41,7 +41,7 @@ ip6table_security_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, { const struct net *net = dev_net(state->in ? state->in : state->out); - return ip6t_do_table(skb, ops->hooknum, state->in, state->out, + return ip6t_do_table(skb, ops->hooknum, state, net->ipv6.ip6table_security); } From 073bfd56860446a2cb349bcf282fc17a36ca386c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 3 Apr 2015 21:16:25 -0400 Subject: [PATCH 539/567] netfilter: Pass nf_hook_state through nft_set_pktinfo*(). Signed-off-by: David S. Miller --- include/net/netfilter/nf_tables.h | 7 +++---- include/net/netfilter/nf_tables_ipv4.h | 5 ++--- include/net/netfilter/nf_tables_ipv6.h | 5 ++--- net/bridge/netfilter/nf_tables_bridge.c | 24 +++++++++++------------ net/ipv4/netfilter/nf_tables_arp.c | 2 +- net/ipv4/netfilter/nf_tables_ipv4.c | 2 +- net/ipv4/netfilter/nft_chain_nat_ipv4.c | 2 +- net/ipv4/netfilter/nft_chain_route_ipv4.c | 2 +- net/ipv6/netfilter/nf_tables_ipv6.c | 2 +- net/ipv6/netfilter/nft_chain_nat_ipv6.c | 2 +- net/ipv6/netfilter/nft_chain_route_ipv6.c | 2 +- 11 files changed, 25 insertions(+), 30 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index b8cd60dcb4e1..804981980393 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -26,12 +26,11 @@ struct nft_pktinfo { static inline void nft_set_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out) + const struct nf_hook_state *state) { pkt->skb = skb; - pkt->in = pkt->xt.in = in; - pkt->out = pkt->xt.out = out; + pkt->in = pkt->xt.in = state->in; + pkt->out = pkt->xt.out = state->out; pkt->ops = ops; pkt->xt.hooknum = ops->hooknum; pkt->xt.family = ops->pf; diff --git a/include/net/netfilter/nf_tables_ipv4.h b/include/net/netfilter/nf_tables_ipv4.h index cba143fbd2e4..2df7f96902ee 100644 --- a/include/net/netfilter/nf_tables_ipv4.h +++ b/include/net/netfilter/nf_tables_ipv4.h @@ -8,12 +8,11 @@ static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out) + const struct nf_hook_state *state) { struct iphdr *ip; - nft_set_pktinfo(pkt, ops, skb, in, out); + nft_set_pktinfo(pkt, ops, skb, state); ip = ip_hdr(pkt->skb); pkt->tprot = ip->protocol; diff --git a/include/net/netfilter/nf_tables_ipv6.h b/include/net/netfilter/nf_tables_ipv6.h index 74d976137658..97db2e3a5e65 100644 --- a/include/net/netfilter/nf_tables_ipv6.h +++ b/include/net/netfilter/nf_tables_ipv6.h @@ -8,13 +8,12 @@ static inline int nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out) + const struct nf_hook_state *state) { int protohdr, thoff = 0; unsigned short frag_off; - nft_set_pktinfo(pkt, ops, skb, in, out); + nft_set_pktinfo(pkt, ops, skb, state); protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL); /* If malformed, drop it */ diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c index 2c46a47160a8..a343e62442b1 100644 --- a/net/bridge/netfilter/nf_tables_bridge.c +++ b/net/bridge/netfilter/nf_tables_bridge.c @@ -67,27 +67,25 @@ EXPORT_SYMBOL_GPL(nft_bridge_ip6hdr_validate); static inline void nft_bridge_set_pktinfo_ipv4(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops, struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out) + const struct nf_hook_state *state) { if (nft_bridge_iphdr_validate(skb)) - nft_set_pktinfo_ipv4(pkt, ops, skb, in, out); + nft_set_pktinfo_ipv4(pkt, ops, skb, state); else - nft_set_pktinfo(pkt, ops, skb, in, out); + nft_set_pktinfo(pkt, ops, skb, state); } static inline void nft_bridge_set_pktinfo_ipv6(struct nft_pktinfo *pkt, - const struct nf_hook_ops *ops, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out) + const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state) { #if IS_ENABLED(CONFIG_IPV6) if (nft_bridge_ip6hdr_validate(skb) && - nft_set_pktinfo_ipv6(pkt, ops, skb, in, out) == 0) + nft_set_pktinfo_ipv6(pkt, ops, skb, state) == 0) return; #endif - nft_set_pktinfo(pkt, ops, skb, in, out); + nft_set_pktinfo(pkt, ops, skb, state); } static unsigned int @@ -99,13 +97,13 @@ nft_do_chain_bridge(const struct nf_hook_ops *ops, switch (eth_hdr(skb)->h_proto) { case htons(ETH_P_IP): - nft_bridge_set_pktinfo_ipv4(&pkt, ops, skb, state->in, state->out); + nft_bridge_set_pktinfo_ipv4(&pkt, ops, skb, state); break; case htons(ETH_P_IPV6): - nft_bridge_set_pktinfo_ipv6(&pkt, ops, skb, state->in, state->out); + nft_bridge_set_pktinfo_ipv6(&pkt, ops, skb, state); break; default: - nft_set_pktinfo(&pkt, ops, skb, state->in, state->out); + nft_set_pktinfo(&pkt, ops, skb, state); break; } diff --git a/net/ipv4/netfilter/nf_tables_arp.c b/net/ipv4/netfilter/nf_tables_arp.c index fceb50e1e87d..8412268bbad1 100644 --- a/net/ipv4/netfilter/nf_tables_arp.c +++ b/net/ipv4/netfilter/nf_tables_arp.c @@ -21,7 +21,7 @@ nft_do_chain_arp(const struct nf_hook_ops *ops, { struct nft_pktinfo pkt; - nft_set_pktinfo(&pkt, ops, skb, state->in, state->out); + nft_set_pktinfo(&pkt, ops, skb, state); return nft_do_chain(&pkt, ops); } diff --git a/net/ipv4/netfilter/nf_tables_ipv4.c b/net/ipv4/netfilter/nf_tables_ipv4.c index 708e388e3dbe..aa180d3a69a5 100644 --- a/net/ipv4/netfilter/nf_tables_ipv4.c +++ b/net/ipv4/netfilter/nf_tables_ipv4.c @@ -24,7 +24,7 @@ static unsigned int nft_do_chain_ipv4(const struct nf_hook_ops *ops, { struct nft_pktinfo pkt; - nft_set_pktinfo_ipv4(&pkt, ops, skb, state->in, state->out); + nft_set_pktinfo_ipv4(&pkt, ops, skb, state); return nft_do_chain(&pkt, ops); } diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c index f56bbb1ab1a0..bf5c30ae14e4 100644 --- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c @@ -33,7 +33,7 @@ static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, { struct nft_pktinfo pkt; - nft_set_pktinfo_ipv4(&pkt, ops, skb, state->in, state->out); + nft_set_pktinfo_ipv4(&pkt, ops, skb, state); return nft_do_chain(&pkt, ops); } diff --git a/net/ipv4/netfilter/nft_chain_route_ipv4.c b/net/ipv4/netfilter/nft_chain_route_ipv4.c index 073d0776ae7f..e335b0afdaf3 100644 --- a/net/ipv4/netfilter/nft_chain_route_ipv4.c +++ b/net/ipv4/netfilter/nft_chain_route_ipv4.c @@ -37,7 +37,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; - nft_set_pktinfo_ipv4(&pkt, ops, skb, state->in, state->out); + nft_set_pktinfo_ipv4(&pkt, ops, skb, state); mark = skb->mark; iph = ip_hdr(skb); diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c index 224bc8971a0b..c8148ba76d1a 100644 --- a/net/ipv6/netfilter/nf_tables_ipv6.c +++ b/net/ipv6/netfilter/nf_tables_ipv6.c @@ -23,7 +23,7 @@ static unsigned int nft_do_chain_ipv6(const struct nf_hook_ops *ops, struct nft_pktinfo pkt; /* malformed packet, drop it */ - if (nft_set_pktinfo_ipv6(&pkt, ops, skb, state->in, state->out) < 0) + if (nft_set_pktinfo_ipv6(&pkt, ops, skb, state) < 0) return NF_DROP; return nft_do_chain(&pkt, ops); diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c index 11c6f75fcc4d..951bb458b7bd 100644 --- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c @@ -31,7 +31,7 @@ static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, { struct nft_pktinfo pkt; - nft_set_pktinfo_ipv6(&pkt, ops, skb, state->in, state->out); + nft_set_pktinfo_ipv6(&pkt, ops, skb, state); return nft_do_chain(&pkt, ops); } diff --git a/net/ipv6/netfilter/nft_chain_route_ipv6.c b/net/ipv6/netfilter/nft_chain_route_ipv6.c index c826c3c854b2..0dafdaac5e17 100644 --- a/net/ipv6/netfilter/nft_chain_route_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_route_ipv6.c @@ -33,7 +33,7 @@ static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, u32 mark, flowlabel; /* malformed packet, drop it */ - if (nft_set_pktinfo_ipv6(&pkt, ops, skb, state->in, state->out) < 0) + if (nft_set_pktinfo_ipv6(&pkt, ops, skb, state) < 0) return NF_DROP; /* save source/dest address, mark, hoplimit, flowlabel, priority */ From b85c3dc9bd5347ad9540ec8d103b7c049c48b7cd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 3 Apr 2015 21:18:46 -0400 Subject: [PATCH 540/567] netfilter: Pass nf_hook_state through arpt_do_table(). Signed-off-by: David S. Miller --- include/linux/netfilter_arp/arp_tables.h | 3 +-- net/ipv4/netfilter/arp_tables.c | 11 +++++------ net/ipv4/netfilter/arptable_filter.c | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index cfb7191e6efa..c22a7fb8d0df 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -54,8 +54,7 @@ extern struct xt_table *arpt_register_table(struct net *net, extern void arpt_unregister_table(struct xt_table *table); extern unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct xt_table *table); #ifdef CONFIG_COMPAT diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index f95b6f93814b..13bfe84bf3ca 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -248,8 +248,7 @@ struct arpt_entry *arpt_next_entry(const struct arpt_entry *entry) unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, - const struct net_device *in, - const struct net_device *out, + const struct nf_hook_state *state, struct xt_table *table) { static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); @@ -265,8 +264,8 @@ unsigned int arpt_do_table(struct sk_buff *skb, if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return NF_DROP; - indev = in ? in->name : nulldevname; - outdev = out ? out->name : nulldevname; + indev = state->in ? state->in->name : nulldevname; + outdev = state->out ? state->out->name : nulldevname; local_bh_disable(); addend = xt_write_recseq_begin(); @@ -281,8 +280,8 @@ unsigned int arpt_do_table(struct sk_buff *skb, e = get_entry(table_base, private->hook_entry[hook]); back = get_entry(table_base, private->underflow[hook]); - acpar.in = in; - acpar.out = out; + acpar.in = state->in; + acpar.out = state->out; acpar.hooknum = hook; acpar.family = NFPROTO_ARP; acpar.hotdrop = false; diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 6a641cb41062..93876d03120c 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -32,7 +32,7 @@ arptable_filter_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, { const struct net *net = dev_net(state->in ? state->in : state->out); - return arpt_do_table(skb, ops->hooknum, state->in, state->out, + return arpt_do_table(skb, ops->hooknum, state, net->ipv4.arptable_filter); } From 59c30afbd37c26168597e737297a1de68848c332 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 3 Apr 2015 17:14:40 -0700 Subject: [PATCH 541/567] Input: alps - report interleaved bare PS/2 packets via dev3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bare packets should be reported via the same evdev device independent on whether they are detected on the beginning of a packet or in the middle of a packet. This has been tested on a Dell Latitude E6400, where the DualPoint Stick reports bare packets, which get reported via dev3 when the touchpad is idle, and via dev2 when the touchpad and stick are used simultaneously. This commit fixes this inconsistency by always reporting bare packets via dev3. Note that since the come from a DualPoint Stick they really should be reported via dev2, this gets fixed in a later commit. Signed-off-by: Hans de Goede Reviewed-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 33198b91bebf..e32625ccf8b6 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1154,10 +1154,23 @@ out: mutex_unlock(&alps_mutex); } -static void alps_report_bare_ps2_packet(struct input_dev *dev, +static void alps_report_bare_ps2_packet(struct psmouse *psmouse, unsigned char packet[], bool report_buttons) { + struct alps_data *priv = psmouse->private; + struct input_dev *dev; + + if (unlikely(IS_ERR_OR_NULL(priv->dev3))) { + /* Register dev3 mouse if we received PS/2 packet first time */ + if (!IS_ERR(priv->dev3)) + psmouse_queue_work(psmouse, &priv->dev3_register_work, + 0); + return; + } else { + dev = priv->dev3; + } + if (report_buttons) alps_report_buttons(dev, NULL, packet[0] & 1, packet[0] & 2, packet[0] & 4); @@ -1232,8 +1245,8 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) * de-synchronization. */ - alps_report_bare_ps2_packet(priv->dev2, - &psmouse->packet[3], false); + alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], + false); /* * Continue with the standard ALPS protocol handling, @@ -1289,18 +1302,9 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) * properly we only do this if the device is fully synchronized. */ if (!psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) { - - /* Register dev3 mouse if we received PS/2 packet first time */ - if (unlikely(!priv->dev3)) - psmouse_queue_work(psmouse, - &priv->dev3_register_work, 0); - if (psmouse->pktcnt == 3) { - /* Once dev3 mouse device is registered report data */ - if (likely(!IS_ERR_OR_NULL(priv->dev3))) - alps_report_bare_ps2_packet(priv->dev3, - psmouse->packet, - true); + alps_report_bare_ps2_packet(psmouse, psmouse->packet, + true); return PSMOUSE_FULL_PACKET; } return PSMOUSE_GOOD_DATA; From e3a79212eae6eb64ed68c78409778f8d1a84c2a1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 3 Apr 2015 17:20:05 -0700 Subject: [PATCH 542/567] Input: alps - report V2 Dualpoint Stick events via the right evdev node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On V2 devices the DualPoint Stick reports bare packets, these should be reported via the "AlpsPS/2 ALPS DualPoint Stick" dev2 evdev node, which also has the INPUT_PROP_POINTING_STICK propbit set. Note that since there is no way to distinguish these packets from an external PS/2 mouse (insofar as these laptops have an external PS/2 port) this means that we will be reporting PS/2 mouse events via this evdev node too, as we've been doing in kernel 3.19 and older. This has been tested on a Dell Latitude D620 and a Dell Latitude E6400, which both have a V2 touchpad + a DualPoint Stick which reports bare packets. Signed-off-by: Hans de Goede Reviewed-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index e32625ccf8b6..27bcdbc950c9 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1161,7 +1161,12 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse, struct alps_data *priv = psmouse->private; struct input_dev *dev; - if (unlikely(IS_ERR_OR_NULL(priv->dev3))) { + /* Figure out which device to use to report the bare packet */ + if (priv->proto_version == ALPS_PROTO_V2 && + (priv->flags & ALPS_DUALPOINT)) { + /* On V2 devices the DualPoint Stick reports bare packets */ + dev = priv->dev2; + } else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) { /* Register dev3 mouse if we received PS/2 packet first time */ if (!IS_ERR(priv->dev3)) psmouse_queue_work(psmouse, &priv->dev3_register_work, From 58d8a3be36cf0fe2eb2609e205bb07a141c29a7c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 3 Apr 2015 17:30:31 -0700 Subject: [PATCH 543/567] Input: alps - document stick behavior for protocol V2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document that protocol V2 uses standard (bare) PS/2 mouse packets for the DualPoint stick. Signed-off-by: Hans de Goede Acked-By: Pali Rohár Signed-off-by: Dmitry Torokhov --- Documentation/input/alps.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/input/alps.txt b/Documentation/input/alps.txt index a63e5e013a8c..92ae734c00c3 100644 --- a/Documentation/input/alps.txt +++ b/Documentation/input/alps.txt @@ -114,6 +114,9 @@ ALPS Absolute Mode - Protocol Version 2 byte 4: 0 y6 y5 y4 y3 y2 y1 y0 byte 5: 0 z6 z5 z4 z3 z2 z1 z0 +Protocol Version 2 DualPoint devices send standard PS/2 mouse packets for +the DualPoint Stick. + Dualpoint device -- interleaved packet format --------------------------------------------- @@ -127,6 +130,11 @@ Dualpoint device -- interleaved packet format byte 7: 0 y6 y5 y4 y3 y2 y1 y0 byte 8: 0 z6 z5 z4 z3 z2 z1 z0 +Devices which use the interleaving format normally send standard PS/2 mouse +packets for the DualPoint Stick + ALPS Absolute Mode packets for the +touchpad, switching to the interleaved packet format when both the stick and +the touchpad are used at the same time. + ALPS Absolute Mode - Protocol Version 3 --------------------------------------- From f60e5990d9c1424af9dbca60a23ba2a1c7c1ce90 Mon Sep 17 00:00:00 2001 From: "hannes@stressinduktion.org" Date: Wed, 1 Apr 2015 17:07:44 +0200 Subject: [PATCH 544/567] ipv6: protect skb->sk accesses from recursive dereference inside the stack We should not consult skb->sk for output decisions in xmit recursion levels > 0 in the stack. Otherwise local socket settings could influence the result of e.g. tunnel encapsulation process. ipv6 does not conform with this in three places: 1) ip6_fragment: we do consult ipv6_npinfo for frag_size 2) sk_mc_loop in ipv6 uses skb->sk and checks if we should loop the packet back to the local socket 3) ip6_skb_dst_mtu could query the settings from the user socket and force a wrong MTU Furthermore: In sk_mc_loop we could potentially land in WARN_ON(1) if we use a PF_PACKET socket ontop of an IPv6-backed vxlan device. Reuse xmit_recursion as we are currently only interested in protecting tunnel devices. Cc: Jiri Pirko Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/netdevice.h | 6 ++++++ include/net/ip.h | 16 ---------------- include/net/ip6_route.h | 3 ++- include/net/sock.h | 2 ++ net/core/dev.c | 4 +++- net/core/sock.c | 19 +++++++++++++++++++ net/ipv6/ip6_output.c | 3 ++- 7 files changed, 34 insertions(+), 19 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index dcf6ec27739b..278738873703 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2185,6 +2185,12 @@ void netdev_freemem(struct net_device *dev); void synchronize_net(void); int init_dummy_netdev(struct net_device *dev); +DECLARE_PER_CPU(int, xmit_recursion); +static inline int dev_recursion_level(void) +{ + return this_cpu_read(xmit_recursion); +} + struct net_device *dev_get_by_index(struct net *net, int ifindex); struct net_device *__dev_get_by_index(struct net *net, int ifindex); struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex); diff --git a/include/net/ip.h b/include/net/ip.h index 025c61c0dffb..6cc1eafb153a 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -453,22 +453,6 @@ static __inline__ void inet_reset_saddr(struct sock *sk) #endif -static inline int sk_mc_loop(struct sock *sk) -{ - if (!sk) - return 1; - switch (sk->sk_family) { - case AF_INET: - return inet_sk(sk)->mc_loop; -#if IS_ENABLED(CONFIG_IPV6) - case AF_INET6: - return inet6_sk(sk)->mc_loop; -#endif - } - WARN_ON(1); - return 1; -} - bool ip_call_ra_chain(struct sk_buff *skb); /* diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 1d09b46c1e48..eda131d179d9 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -174,7 +174,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); static inline int ip6_skb_dst_mtu(struct sk_buff *skb) { - struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; + struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? + inet6_sk(skb->sk) : NULL; return (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) ? skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); diff --git a/include/net/sock.h b/include/net/sock.h index ab186b1d31ff..e4079c28e6b8 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1762,6 +1762,8 @@ struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie); struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie); +bool sk_mc_loop(struct sock *sk); + static inline bool sk_can_gso(const struct sock *sk) { return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type); diff --git a/net/core/dev.c b/net/core/dev.c index 962ee9d71964..45109b70664e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2848,7 +2848,9 @@ static void skb_update_prio(struct sk_buff *skb) #define skb_update_prio(skb) #endif -static DEFINE_PER_CPU(int, xmit_recursion); +DEFINE_PER_CPU(int, xmit_recursion); +EXPORT_SYMBOL(xmit_recursion); + #define RECURSION_LIMIT 10 /** diff --git a/net/core/sock.c b/net/core/sock.c index 78e89eb7eb70..71e3e5f1eaa0 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -653,6 +653,25 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) sock_reset_flag(sk, bit); } +bool sk_mc_loop(struct sock *sk) +{ + if (dev_recursion_level()) + return false; + if (!sk) + return true; + switch (sk->sk_family) { + case AF_INET: + return inet_sk(sk)->mc_loop; +#if IS_ENABLED(CONFIG_IPV6) + case AF_INET6: + return inet6_sk(sk)->mc_loop; +#endif + } + WARN_ON(1); + return true; +} +EXPORT_SYMBOL(sk_mc_loop); + /* * This is meant for all protocols to use and covers goings on * at the socket level. Everything here is generic. diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 7e80b61b51ff..36cf0ab685a0 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -542,7 +542,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) { struct sk_buff *frag; struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); - struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; + struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? + inet6_sk(skb->sk) : NULL; struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; unsigned int mtu, hlen, left, len; From ecf7b361a6bc1fd5441e4d6a3d7433abbe577064 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Wed, 1 Apr 2015 19:23:29 +0300 Subject: [PATCH 545/567] mvneta: dont call mvneta_adjust_link() manually mvneta_adjust_link() is a callback for of_phy_connect() and should not be called directly. The result of calling it directly is as below: Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 96208f17bb53..2db653225a0e 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2658,16 +2658,11 @@ static int mvneta_stop(struct net_device *dev) static int mvneta_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct mvneta_port *pp = netdev_priv(dev); - int ret; if (!pp->phy_dev) return -ENOTSUPP; - ret = phy_mii_ioctl(pp->phy_dev, ifr, cmd); - if (!ret) - mvneta_adjust_link(dev); - - return ret; + return phy_mii_ioctl(pp->phy_dev, ifr, cmd); } /* Ethtool methods */ From 91bc4822c3d61b9bb7ef66d3b77948a4f9177954 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 1 Apr 2015 17:12:13 -0700 Subject: [PATCH 546/567] tc: bpf: add checksum helpers Commit 608cd71a9c7c ("tc: bpf: generalize pedit action") has added the possibility to mangle packet data to BPF programs in the tc pipeline. This patch adds two helpers bpf_l3_csum_replace() and bpf_l4_csum_replace() for fixing up the protocol checksums after the packet mangling. It also adds 'flags' argument to bpf_skb_store_bytes() helper to avoid unnecessary checksum recomputations when BPF programs adjusting l3/l4 checksums and documents all three helpers in uapi header. Moreover, a sample program is added to show how BPF programs can make use of the mangle and csum helpers. Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/uapi/linux/bpf.h | 38 +++++++++++++- net/core/filter.c | 108 ++++++++++++++++++++++++++++++++++++-- samples/bpf/Makefile | 1 + samples/bpf/bpf_helpers.h | 7 +++ samples/bpf/tcbpf1_kern.c | 71 +++++++++++++++++++++++++ 5 files changed, 220 insertions(+), 5 deletions(-) create mode 100644 samples/bpf/tcbpf1_kern.c diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 0db8580f3cca..23df3e7f8e7d 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -168,7 +168,43 @@ enum bpf_func_id { BPF_FUNC_map_delete_elem, /* int map_delete_elem(&map, &key) */ BPF_FUNC_get_prandom_u32, /* u32 prandom_u32(void) */ BPF_FUNC_get_smp_processor_id, /* u32 raw_smp_processor_id(void) */ - BPF_FUNC_skb_store_bytes, /* int skb_store_bytes(skb, offset, from, len) */ + + /** + * skb_store_bytes(skb, offset, from, len, flags) - store bytes into packet + * @skb: pointer to skb + * @offset: offset within packet from skb->data + * @from: pointer where to copy bytes from + * @len: number of bytes to store into packet + * @flags: bit 0 - if true, recompute skb->csum + * other bits - reserved + * Return: 0 on success + */ + BPF_FUNC_skb_store_bytes, + + /** + * l3_csum_replace(skb, offset, from, to, flags) - recompute IP checksum + * @skb: pointer to skb + * @offset: offset within packet where IP checksum is located + * @from: old value of header field + * @to: new value of header field + * @flags: bits 0-3 - size of header field + * other bits - reserved + * Return: 0 on success + */ + BPF_FUNC_l3_csum_replace, + + /** + * l4_csum_replace(skb, offset, from, to, flags) - recompute TCP/UDP checksum + * @skb: pointer to skb + * @offset: offset within packet where TCP/UDP checksum is located + * @from: old value of header field + * @to: new value of header field + * @flags: bits 0-3 - size of header field + * bit 4 - is pseudo header + * other bits - reserved + * Return: 0 on success + */ + BPF_FUNC_l4_csum_replace, __BPF_FUNC_MAX_ID, }; diff --git a/net/core/filter.c b/net/core/filter.c index 955a7d77decd..b669e75d2b36 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1175,7 +1175,9 @@ int sk_attach_bpf(u32 ufd, struct sock *sk) return 0; } -static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +#define BPF_RECOMPUTE_CSUM(flags) ((flags) & 1) + +static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 flags) { struct sk_buff *skb = (struct sk_buff *) (long) r1; unsigned int offset = (unsigned int) r2; @@ -1192,7 +1194,7 @@ static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) * * so check for invalid 'offset' and too large 'len' */ - if (offset > 0xffff || len > sizeof(buf)) + if (unlikely(offset > 0xffff || len > sizeof(buf))) return -EFAULT; if (skb_cloned(skb) && !skb_clone_writable(skb, offset + len)) @@ -1202,7 +1204,8 @@ static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) if (unlikely(!ptr)) return -EFAULT; - skb_postpull_rcsum(skb, ptr, len); + if (BPF_RECOMPUTE_CSUM(flags)) + skb_postpull_rcsum(skb, ptr, len); memcpy(ptr, from, len); @@ -1210,7 +1213,7 @@ static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) /* skb_store_bits cannot return -EFAULT here */ skb_store_bits(skb, offset, ptr, len); - if (skb->ip_summed == CHECKSUM_COMPLETE) + if (BPF_RECOMPUTE_CSUM(flags) && skb->ip_summed == CHECKSUM_COMPLETE) skb->csum = csum_add(skb->csum, csum_partial(ptr, len, 0)); return 0; } @@ -1223,6 +1226,99 @@ const struct bpf_func_proto bpf_skb_store_bytes_proto = { .arg2_type = ARG_ANYTHING, .arg3_type = ARG_PTR_TO_STACK, .arg4_type = ARG_CONST_STACK_SIZE, + .arg5_type = ARG_ANYTHING, +}; + +#define BPF_HEADER_FIELD_SIZE(flags) ((flags) & 0x0f) +#define BPF_IS_PSEUDO_HEADER(flags) ((flags) & 0x10) + +static u64 bpf_l3_csum_replace(u64 r1, u64 offset, u64 from, u64 to, u64 flags) +{ + struct sk_buff *skb = (struct sk_buff *) (long) r1; + __sum16 sum, *ptr; + + if (unlikely(offset > 0xffff)) + return -EFAULT; + + if (skb_cloned(skb) && !skb_clone_writable(skb, offset + sizeof(sum))) + return -EFAULT; + + ptr = skb_header_pointer(skb, offset, sizeof(sum), &sum); + if (unlikely(!ptr)) + return -EFAULT; + + switch (BPF_HEADER_FIELD_SIZE(flags)) { + case 2: + csum_replace2(ptr, from, to); + break; + case 4: + csum_replace4(ptr, from, to); + break; + default: + return -EINVAL; + } + + if (ptr == &sum) + /* skb_store_bits guaranteed to not return -EFAULT here */ + skb_store_bits(skb, offset, ptr, sizeof(sum)); + + return 0; +} + +const struct bpf_func_proto bpf_l3_csum_replace_proto = { + .func = bpf_l3_csum_replace, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_ANYTHING, + .arg5_type = ARG_ANYTHING, +}; + +static u64 bpf_l4_csum_replace(u64 r1, u64 offset, u64 from, u64 to, u64 flags) +{ + struct sk_buff *skb = (struct sk_buff *) (long) r1; + u32 is_pseudo = BPF_IS_PSEUDO_HEADER(flags); + __sum16 sum, *ptr; + + if (unlikely(offset > 0xffff)) + return -EFAULT; + + if (skb_cloned(skb) && !skb_clone_writable(skb, offset + sizeof(sum))) + return -EFAULT; + + ptr = skb_header_pointer(skb, offset, sizeof(sum), &sum); + if (unlikely(!ptr)) + return -EFAULT; + + switch (BPF_HEADER_FIELD_SIZE(flags)) { + case 2: + inet_proto_csum_replace2(ptr, skb, from, to, is_pseudo); + break; + case 4: + inet_proto_csum_replace4(ptr, skb, from, to, is_pseudo); + break; + default: + return -EINVAL; + } + + if (ptr == &sum) + /* skb_store_bits guaranteed to not return -EFAULT here */ + skb_store_bits(skb, offset, ptr, sizeof(sum)); + + return 0; +} + +const struct bpf_func_proto bpf_l4_csum_replace_proto = { + .func = bpf_l4_csum_replace, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, + .arg4_type = ARG_ANYTHING, + .arg5_type = ARG_ANYTHING, }; static const struct bpf_func_proto * @@ -1250,6 +1346,10 @@ tc_cls_act_func_proto(enum bpf_func_id func_id) switch (func_id) { case BPF_FUNC_skb_store_bytes: return &bpf_skb_store_bytes_proto; + case BPF_FUNC_l3_csum_replace: + return &bpf_l3_csum_replace_proto; + case BPF_FUNC_l4_csum_replace: + return &bpf_l4_csum_replace_proto; default: return sk_filter_func_proto(func_id); } diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index b5b3600dcdf5..d24f51bca465 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -17,6 +17,7 @@ sockex2-objs := bpf_load.o libbpf.o sockex2_user.o always := $(hostprogs-y) always += sockex1_kern.o always += sockex2_kern.o +always += tcbpf1_kern.o HOSTCFLAGS += -I$(objtree)/usr/include diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h index ca0333146006..72540ec1f003 100644 --- a/samples/bpf/bpf_helpers.h +++ b/samples/bpf/bpf_helpers.h @@ -37,4 +37,11 @@ struct bpf_map_def { unsigned int max_entries; }; +static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = + (void *) BPF_FUNC_skb_store_bytes; +static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = + (void *) BPF_FUNC_l3_csum_replace; +static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = + (void *) BPF_FUNC_l4_csum_replace; + #endif diff --git a/samples/bpf/tcbpf1_kern.c b/samples/bpf/tcbpf1_kern.c new file mode 100644 index 000000000000..7cf3f42a6e39 --- /dev/null +++ b/samples/bpf/tcbpf1_kern.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include "bpf_helpers.h" + +/* compiler workaround */ +#define _htonl __builtin_bswap32 + +static inline void set_dst_mac(struct __sk_buff *skb, char *mac) +{ + bpf_skb_store_bytes(skb, 0, mac, ETH_ALEN, 1); +} + +/* use 1 below for ingress qdisc and 0 for egress */ +#if 0 +#undef ETH_HLEN +#define ETH_HLEN 0 +#endif + +#define IP_CSUM_OFF (ETH_HLEN + offsetof(struct iphdr, check)) +#define TOS_OFF (ETH_HLEN + offsetof(struct iphdr, tos)) + +static inline void set_ip_tos(struct __sk_buff *skb, __u8 new_tos) +{ + __u8 old_tos = load_byte(skb, TOS_OFF); + + bpf_l3_csum_replace(skb, IP_CSUM_OFF, htons(old_tos), htons(new_tos), 2); + bpf_skb_store_bytes(skb, TOS_OFF, &new_tos, sizeof(new_tos), 0); +} + +#define TCP_CSUM_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct tcphdr, check)) +#define IP_SRC_OFF (ETH_HLEN + offsetof(struct iphdr, saddr)) + +#define IS_PSEUDO 0x10 + +static inline void set_tcp_ip_src(struct __sk_buff *skb, __u32 new_ip) +{ + __u32 old_ip = _htonl(load_word(skb, IP_SRC_OFF)); + + bpf_l4_csum_replace(skb, TCP_CSUM_OFF, old_ip, new_ip, IS_PSEUDO | sizeof(new_ip)); + bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip)); + bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0); +} + +#define TCP_DPORT_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct tcphdr, dest)) +static inline void set_tcp_dest_port(struct __sk_buff *skb, __u16 new_port) +{ + __u16 old_port = htons(load_half(skb, TCP_DPORT_OFF)); + + bpf_l4_csum_replace(skb, TCP_CSUM_OFF, old_port, new_port, sizeof(new_port)); + bpf_skb_store_bytes(skb, TCP_DPORT_OFF, &new_port, sizeof(new_port), 0); +} + +SEC("classifier") +int bpf_prog1(struct __sk_buff *skb) +{ + __u8 proto = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol)); + long *value; + + if (proto == IPPROTO_TCP) { + set_ip_tos(skb, 8); + set_tcp_ip_src(skb, 0xA010101); + set_tcp_dest_port(skb, 5001); + } + + return 0; +} +char _license[] SEC("license") = "GPL"; From 60302ff631f0f3eac0ec592e128b776f0676b397 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 2 Apr 2015 13:05:47 +0200 Subject: [PATCH 547/567] virtio: document queue state logic commit d631b94e7a15277858ec5f88d674d93080506999 virtio: change comment in transmit started clarifying the logic behind queue state management, but introduced an inaccuracy: TX_BUSY does not cause a BUG message. Clean this up some more, explaining the tradeoffs in detail. Signed-off-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a829930dac15..63c7810e1545 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -939,11 +939,15 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) skb_orphan(skb); nf_reset(skb); - /* It is better to stop queue if running out of space - * instead of forcing queuing layer to requeue the skb - * by returning TX_BUSY (and cause a BUG message). - * Since most packets only take 1 or 2 ring slots - * this means 16 slots are typically wasted. + /* If running out of space, stop queue to avoid getting packets that we + * are then unable to transmit. + * An alternative would be to force queuing layer to requeue the skb by + * returning NETDEV_TX_BUSY. However, NETDEV_TX_BUSY should not be + * returned in a normal path of operation: it means that driver is not + * maintaining the TX queue stop/start state properly, and causes + * the stack to do a non-trivial amount of useless work. + * Since most packets only take 1 or 2 ring slots, stopping the queue + * early means 16 slots are typically wasted. */ if (sq->vq->num_free < 2+MAX_SKB_FRAGS) { netif_stop_subqueue(dev, qnum); From 67e04c29ec0daad9ba29341b4dab4b89526994cf Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 3 Apr 2015 13:46:09 -0700 Subject: [PATCH 548/567] l2tp: unregister l2tp_net_ops on failure path Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/l2tp/l2tp_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 895348e44c7d..a29a504492af 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1871,6 +1871,7 @@ static int __init l2tp_init(void) l2tp_wq = alloc_workqueue("l2tp", WQ_UNBOUND, 0); if (!l2tp_wq) { pr_err("alloc_workqueue failed\n"); + unregister_pernet_device(&l2tp_net_ops); rc = -ENOMEM; goto out; } From 303038135afbd0520d1e241c02592be6e4ea7204 Mon Sep 17 00:00:00 2001 From: Pavel Nakonechny Date: Sun, 5 Apr 2015 00:46:21 +0300 Subject: [PATCH 549/567] net: dsa: fix filling routing table from OF description According to description in 'include/net/dsa.h', in cascade switches configurations where there are more than one interconnected devices, 'rtable' array in 'dsa_chip_data' structure is used to indicate which port on this switch should be used to send packets to that are destined for corresponding switch. However, dsa_of_setup_routing_table() fills 'rtable' with port numbers of the _target_ switch, but not current one. This commit removes redundant devicetree parsing and adds needed port number as a function argument. So dsa_of_setup_routing_table() now just looks for target switch number by parsing parent of 'link' device node. To remove possible misunderstandings with the way of determining target switch number, a corresponding comment was added to the source code and to the DSA device tree bindings documentation file. This was tested on a custom board with two Marvell 88E6095 switches with following corresponding routing tables: { -1, 10 } and { 8, -1 }. Signed-off-by: Pavel Nakonechny Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../devicetree/bindings/net/dsa/dsa.txt | 4 +++- net/dsa/dsa.c | 23 ++++++------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt index e124847443f8..f0b4cd72411d 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.txt +++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt @@ -19,7 +19,9 @@ the parent DSA node. The maximum number of allowed child nodes is 4 (DSA_MAX_SWITCHES). Each of these switch child nodes should have the following required properties: -- reg : Describes the switch address on the MII bus +- reg : Contains two fields. The first one describes the + address on the MII bus. The second is the switch + number that must be unique in cascaded configurations - #address-cells : Must be 1 - #size-cells : Must be 0 diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 2173402d87e0..4dea2e0681d1 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -501,12 +501,10 @@ static struct net_device *dev_to_net_device(struct device *dev) #ifdef CONFIG_OF static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, struct dsa_chip_data *cd, - int chip_index, + int chip_index, int port_index, struct device_node *link) { - int ret; const __be32 *reg; - int link_port_addr; int link_sw_addr; struct device_node *parent_sw; int len; @@ -519,6 +517,10 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, if (!reg || (len != sizeof(*reg) * 2)) return -EINVAL; + /* + * Get the destination switch number from the second field of its 'reg' + * property, i.e. for "reg = <0x19 1>" sw_addr is '1'. + */ link_sw_addr = be32_to_cpup(reg + 1); if (link_sw_addr >= pd->nr_chips) @@ -535,20 +537,9 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd, memset(cd->rtable, -1, pd->nr_chips * sizeof(s8)); } - reg = of_get_property(link, "reg", NULL); - if (!reg) { - ret = -EINVAL; - goto out; - } - - link_port_addr = be32_to_cpup(reg); - - cd->rtable[link_sw_addr] = link_port_addr; + cd->rtable[link_sw_addr] = port_index; return 0; -out: - kfree(cd->rtable); - return ret; } static void dsa_of_free_platform_data(struct dsa_platform_data *pd) @@ -658,7 +649,7 @@ static int dsa_of_probe(struct platform_device *pdev) if (!strcmp(port_name, "dsa") && link && pd->nr_chips > 1) { ret = dsa_of_setup_routing_table(pd, cd, - chip_index, link); + chip_index, port_index, link); if (ret) goto out_free_chip; } From fde913e25496761a4e2a4c81230c913aba6289a2 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sun, 5 Apr 2015 17:50:48 +0300 Subject: [PATCH 550/567] net/mlx4_core: Fix error message deprecation for ConnectX-2 cards Commit 1daa4303b4ca ("net/mlx4_core: Deprecate error message at ConnectX-2 cards startup to debug") did the deprecation only for port 1 of the card. Need to deprecate for port 2 as well. Fixes: 1daa4303b4ca ("net/mlx4_core: Deprecate error message at ConnectX-2 cards startup to debug") Signed-off-by: Jack Morgenstein Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/cmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 3350721bf515..546ca4226916 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -724,7 +724,8 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, * on the host, we deprecate the error message for this * specific command/input_mod/opcode_mod/fw-status to be debug. */ - if (op == MLX4_CMD_SET_PORT && in_modifier == 1 && + if (op == MLX4_CMD_SET_PORT && + (in_modifier == 1 || in_modifier == 2) && op_modifier == 0 && context->fw_status == CMD_STAT_BAD_SIZE) mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n", op, context->fw_status); From f22e6e847115abc3a0e2ad7bb18d243d42275af1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 6 Apr 2015 15:39:45 -0700 Subject: [PATCH 551/567] Linux 4.0-rc7 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index da36a3be7969..54430f933b62 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 0 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = -rc7 NAME = Hurr durr I'ma sheep # *DOCUMENTATION* From 27d751bfa41bdc022d1357479ff67c6902c02c8c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 5 Apr 2015 14:06:21 +0200 Subject: [PATCH 552/567] wan: lmc: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/wan/lmc/lmc_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index bea0f313a7a8..317bc79cc8b9 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -850,6 +850,7 @@ static int lmc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev = alloc_hdlcdev(sc); if (!dev) { printk(KERN_ERR "lmc:alloc_netdev for device failed\n"); + err = -ENOMEM; goto err_hdlcdev; } From a3786a5ff7551d03029219f93306106d0a6bdf55 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 5 Apr 2015 14:06:28 +0200 Subject: [PATCH 553/567] cosa: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/wan/cosa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 88d121d43c08..bcfa01add7cc 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -579,6 +579,7 @@ static int cosa_probe(int base, int irq, int dma) /* Register the network interface */ if (!(chan->netdev = alloc_hdlcdev(chan))) { pr_warn("%s: alloc_hdlcdev failed\n", chan->name); + err = -ENOMEM; goto err_hdlcdev; } dev_to_hdlc(chan->netdev)->attach = cosa_net_attach; From 107a9f4dc9211c1f91703d1739d7fd22ac58b332 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 5 Apr 2015 22:18:54 -0400 Subject: [PATCH 554/567] netfilter: Add nf_hook_state initializer function. This way we can consolidate where we setup new nf_hook_state objects, to make sure the entire thing is initialized. The only other place an nf_hook_object is instantiated is nf_queue, wherein a structure copy is used. Signed-off-by: David S. Miller --- include/linux/netfilter.h | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index c480c43ad8f7..b8c88f3c85ff 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -54,6 +54,21 @@ struct nf_hook_state { int (*okfn)(struct sk_buff *); }; +static inline void nf_hook_state_init(struct nf_hook_state *p, + unsigned int hook, + int thresh, u_int8_t pf, + struct net_device *indev, + struct net_device *outdev, + int (*okfn)(struct sk_buff *)) +{ + p->hook = hook; + p->thresh = thresh; + p->pf = pf; + p->in = indev; + p->out = outdev; + p->okfn = okfn; +} + typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state); @@ -142,15 +157,10 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, int (*okfn)(struct sk_buff *), int thresh) { if (nf_hooks_active(pf, hook)) { - struct nf_hook_state state = { - .hook = hook, - .thresh = thresh, - .pf = pf, - .in = indev, - .out = outdev, - .okfn = okfn - }; + struct nf_hook_state state; + nf_hook_state_init(&state, hook, thresh, pf, + indev, outdev, okfn); return nf_hook_slow(skb, &state); } return 1; From 1c984f8a5df085bcf35364a8a870bd4db4da4ed3 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 5 Apr 2015 22:19:00 -0400 Subject: [PATCH 555/567] netfilter: Add socket pointer to nf_hook_state. It is currently always set to NULL, but nf_queue is adjusted to be prepared for it being set to a real socket by taking and releasing a reference to that socket when necessary. Signed-off-by: David S. Miller --- include/linux/netfilter.h | 7 ++++++- net/netfilter/nf_queue.c | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index b8c88f3c85ff..f8f58fab2402 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -45,12 +45,15 @@ struct sk_buff; struct nf_hook_ops; +struct sock; + struct nf_hook_state { unsigned int hook; int thresh; u_int8_t pf; struct net_device *in; struct net_device *out; + struct sock *sk; int (*okfn)(struct sk_buff *); }; @@ -59,6 +62,7 @@ static inline void nf_hook_state_init(struct nf_hook_state *p, int thresh, u_int8_t pf, struct net_device *indev, struct net_device *outdev, + struct sock *sk, int (*okfn)(struct sk_buff *)) { p->hook = hook; @@ -66,6 +70,7 @@ static inline void nf_hook_state_init(struct nf_hook_state *p, p->pf = pf; p->in = indev; p->out = outdev; + p->sk = sk; p->okfn = okfn; } @@ -160,7 +165,7 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, struct nf_hook_state state; nf_hook_state_init(&state, hook, thresh, pf, - indev, outdev, okfn); + indev, outdev, NULL, okfn); return nf_hook_slow(skb, &state); } return 1; diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index d3cd37edca18..c4a706678f88 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -54,6 +54,8 @@ void nf_queue_entry_release_refs(struct nf_queue_entry *entry) dev_put(state->in); if (state->out) dev_put(state->out); + if (state->sk) + sock_put(state->sk); #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (entry->skb->nf_bridge) { struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge; @@ -81,6 +83,8 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry) dev_hold(state->in); if (state->out) dev_hold(state->out); + if (state->sk) + sock_hold(state->sk); #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) if (entry->skb->nf_bridge) { struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge; From 7026b1ddb6b8d4e6ee33dc2bd06c0ca8746fa7ab Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 5 Apr 2015 22:19:04 -0400 Subject: [PATCH 556/567] netfilter: Pass socket pointer down through okfn(). On the output paths in particular, we have to sometimes deal with two socket contexts. First, and usually skb->sk, is the local socket that generated the frame. And second, is potentially the socket used to control a tunneling socket, such as one the encapsulates using UDP. We do not want to disassociate skb->sk when encapsulating in order to fix this, because that would break socket memory accounting. The most extreme case where this can cause huge problems is an AF_PACKET socket transmitting over a vxlan device. We hit code paths doing checks that assume they are dealing with an ipv4 socket, but are actually operating upon the AF_PACKET one. Signed-off-by: David S. Miller --- include/linux/netdevice.h | 14 +++-- include/linux/netfilter.h | 62 +++++++++++++---------- include/linux/netfilter_bridge.h | 2 +- include/net/dn_neigh.h | 6 +-- include/net/ip.h | 3 +- include/net/ip6_route.h | 3 +- include/net/ipv6.h | 2 +- include/net/xfrm.h | 8 +-- net/bridge/br_forward.c | 13 +++-- net/bridge/br_input.c | 16 +++--- net/bridge/br_multicast.c | 3 +- net/bridge/br_netfilter.c | 56 +++++++++++--------- net/bridge/br_private.h | 6 +-- net/bridge/br_stp_bpdu.c | 5 +- net/core/dev.c | 10 ++-- net/decnet/dn_neigh.c | 35 +++++++------ net/decnet/dn_nsp_in.c | 5 +- net/decnet/dn_route.c | 26 ++++++---- net/ipv4/arp.c | 10 ++-- net/ipv4/ip_forward.c | 8 +-- net/ipv4/ip_input.c | 10 ++-- net/ipv4/ip_output.c | 45 +++++++++------- net/ipv4/ipmr.c | 7 +-- net/ipv4/raw.c | 4 +- net/ipv4/xfrm4_input.c | 5 +- net/ipv4/xfrm4_output.c | 12 ++--- net/ipv6/ip6_input.c | 11 ++-- net/ipv6/ip6_output.c | 33 ++++++------ net/ipv6/ip6mr.c | 7 +-- net/ipv6/mcast.c | 9 ++-- net/ipv6/ndisc.c | 5 +- net/ipv6/netfilter/nf_defrag_ipv6_hooks.c | 2 +- net/ipv6/output_core.c | 4 +- net/ipv6/raw.c | 4 +- net/ipv6/xfrm6_input.c | 3 +- net/ipv6/xfrm6_output.c | 15 +++--- net/netfilter/ipvs/ip_vs_xmit.c | 8 +-- net/netfilter/nf_queue.c | 2 +- net/xfrm/xfrm_output.c | 16 +++--- 39 files changed, 277 insertions(+), 218 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 41bf58a2b936..45823db2efb0 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2165,8 +2165,12 @@ int dev_open(struct net_device *dev); int dev_close(struct net_device *dev); int dev_close_many(struct list_head *head, bool unlink); void dev_disable_lro(struct net_device *dev); -int dev_loopback_xmit(struct sk_buff *newskb); -int dev_queue_xmit(struct sk_buff *skb); +int dev_loopback_xmit(struct sock *sk, struct sk_buff *newskb); +int dev_queue_xmit_sk(struct sock *sk, struct sk_buff *skb); +static inline int dev_queue_xmit(struct sk_buff *skb) +{ + return dev_queue_xmit_sk(skb->sk, skb); +} int dev_queue_xmit_accel(struct sk_buff *skb, void *accel_priv); int register_netdevice(struct net_device *dev); void unregister_netdevice_queue(struct net_device *dev, struct list_head *head); @@ -2927,7 +2931,11 @@ static inline void dev_consume_skb_any(struct sk_buff *skb) int netif_rx(struct sk_buff *skb); int netif_rx_ni(struct sk_buff *skb); -int netif_receive_skb(struct sk_buff *skb); +int netif_receive_skb_sk(struct sock *sk, struct sk_buff *skb); +static inline int netif_receive_skb(struct sk_buff *skb) +{ + return netif_receive_skb_sk(skb->sk, skb); +} gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb); void napi_gro_flush(struct napi_struct *napi, bool flush_old); struct sk_buff *napi_get_frags(struct napi_struct *napi); diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index f8f58fab2402..63560d0a8dfe 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -54,7 +54,7 @@ struct nf_hook_state { struct net_device *in; struct net_device *out; struct sock *sk; - int (*okfn)(struct sk_buff *); + int (*okfn)(struct sock *, struct sk_buff *); }; static inline void nf_hook_state_init(struct nf_hook_state *p, @@ -63,7 +63,7 @@ static inline void nf_hook_state_init(struct nf_hook_state *p, struct net_device *indev, struct net_device *outdev, struct sock *sk, - int (*okfn)(struct sk_buff *)) + int (*okfn)(struct sock *, struct sk_buff *)) { p->hook = hook; p->thresh = thresh; @@ -156,26 +156,29 @@ int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state); * value indicates the packet has been consumed by the hook. */ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, + struct sock *sk, struct sk_buff *skb, struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct sk_buff *), int thresh) + int (*okfn)(struct sock *, struct sk_buff *), + int thresh) { if (nf_hooks_active(pf, hook)) { struct nf_hook_state state; nf_hook_state_init(&state, hook, thresh, pf, - indev, outdev, NULL, okfn); + indev, outdev, sk, okfn); return nf_hook_slow(skb, &state); } return 1; } -static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb, - struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct sk_buff *)) +static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sock *sk, + struct sk_buff *skb, struct net_device *indev, + struct net_device *outdev, + int (*okfn)(struct sock *, struct sk_buff *)) { - return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN); + return nf_hook_thresh(pf, hook, sk, skb, indev, outdev, okfn, INT_MIN); } /* Activate hook; either okfn or kfree_skb called, unless a hook @@ -196,35 +199,36 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb, */ static inline int -NF_HOOK_THRESH(uint8_t pf, unsigned int hook, struct sk_buff *skb, - struct net_device *in, struct net_device *out, - int (*okfn)(struct sk_buff *), int thresh) +NF_HOOK_THRESH(uint8_t pf, unsigned int hook, struct sock *sk, + struct sk_buff *skb, struct net_device *in, + struct net_device *out, + int (*okfn)(struct sock *, struct sk_buff *), int thresh) { - int ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, thresh); + int ret = nf_hook_thresh(pf, hook, sk, skb, in, out, okfn, thresh); if (ret == 1) - ret = okfn(skb); + ret = okfn(sk, skb); return ret; } static inline int -NF_HOOK_COND(uint8_t pf, unsigned int hook, struct sk_buff *skb, - struct net_device *in, struct net_device *out, - int (*okfn)(struct sk_buff *), bool cond) +NF_HOOK_COND(uint8_t pf, unsigned int hook, struct sock *sk, + struct sk_buff *skb, struct net_device *in, struct net_device *out, + int (*okfn)(struct sock *, struct sk_buff *), bool cond) { int ret; if (!cond || - ((ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, INT_MIN)) == 1)) - ret = okfn(skb); + ((ret = nf_hook_thresh(pf, hook, sk, skb, in, out, okfn, INT_MIN)) == 1)) + ret = okfn(sk, skb); return ret; } static inline int -NF_HOOK(uint8_t pf, unsigned int hook, struct sk_buff *skb, +NF_HOOK(uint8_t pf, unsigned int hook, struct sock *sk, struct sk_buff *skb, struct net_device *in, struct net_device *out, - int (*okfn)(struct sk_buff *)) + int (*okfn)(struct sock *, struct sk_buff *)) { - return NF_HOOK_THRESH(pf, hook, skb, in, out, okfn, INT_MIN); + return NF_HOOK_THRESH(pf, hook, sk, skb, in, out, okfn, INT_MIN); } /* Call setsockopt() */ @@ -324,19 +328,21 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) } #else /* !CONFIG_NETFILTER */ -#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) -#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb) +#define NF_HOOK(pf, hook, sk, skb, indev, outdev, okfn) (okfn)(sk, skb) +#define NF_HOOK_COND(pf, hook, sk, skb, indev, outdev, okfn, cond) (okfn)(sk, skb) static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, + struct sock *sk, struct sk_buff *skb, struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct sk_buff *), int thresh) + int (*okfn)(struct sock *sk, struct sk_buff *), int thresh) { - return okfn(skb); + return okfn(sk, skb); } -static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb, - struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct sk_buff *)) +static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sock *sk, + struct sk_buff *skb, struct net_device *indev, + struct net_device *outdev, + int (*okfn)(struct sock *, struct sk_buff *)) { return 1; } diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index 2734977199ca..5fc0a0fe244b 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h @@ -30,7 +30,7 @@ static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb) return 0; } -int br_handle_frame_finish(struct sk_buff *skb); +int br_handle_frame_finish(struct sock *sk, struct sk_buff *skb); static inline void br_drop_fake_rtable(struct sk_buff *skb) { diff --git a/include/net/dn_neigh.h b/include/net/dn_neigh.h index 0f26aa707e62..d0424269313f 100644 --- a/include/net/dn_neigh.h +++ b/include/net/dn_neigh.h @@ -18,11 +18,11 @@ struct dn_neigh { void dn_neigh_init(void); void dn_neigh_cleanup(void); -int dn_neigh_router_hello(struct sk_buff *skb); -int dn_neigh_endnode_hello(struct sk_buff *skb); +int dn_neigh_router_hello(struct sock *sk, struct sk_buff *skb); +int dn_neigh_endnode_hello(struct sock *sk, struct sk_buff *skb); void dn_neigh_pointopoint_hello(struct sk_buff *skb); int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n); -int dn_to_neigh_output(struct sk_buff *skb); +int dn_to_neigh_output(struct sock *sk, struct sk_buff *skb); extern struct neigh_table dn_neigh_table; diff --git a/include/net/ip.h b/include/net/ip.h index 69cd9cb8400c..d14af7edd197 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -108,7 +108,8 @@ int ip_local_deliver(struct sk_buff *skb); int ip_mr_input(struct sk_buff *skb); int ip_output(struct sock *sk, struct sk_buff *skb); int ip_mc_output(struct sock *sk, struct sk_buff *skb); -int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); +int ip_fragment(struct sock *sk, struct sk_buff *skb, + int (*output)(struct sock *, struct sk_buff *)); int ip_do_nat(struct sk_buff *skb); void ip_send_check(struct iphdr *ip); int __ip_local_out(struct sk_buff *skb); diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index eda131d179d9..5e192068e6cb 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -170,7 +170,8 @@ static inline bool ipv6_anycast_destination(const struct sk_buff *skb) return rt->rt6i_flags & RTF_ANYCAST; } -int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); +int ip6_fragment(struct sock *sk, struct sk_buff *skb, + int (*output)(struct sock *, struct sk_buff *)); static inline int ip6_skb_dst_mtu(struct sk_buff *skb) { diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 65142e6af440..b6ae959824ff 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -769,7 +769,7 @@ static inline u8 ip6_tclass(__be32 flowinfo) int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev); -int ip6_rcv_finish(struct sk_buff *skb); +int ip6_rcv_finish(struct sock *sk, struct sk_buff *skb); /* * upper-layer output functions diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 461f83539493..36ac102c97c7 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -332,7 +332,7 @@ struct xfrm_state_afinfo { int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); int (*output)(struct sock *sk, struct sk_buff *skb); - int (*output_finish)(struct sk_buff *skb); + int (*output_finish)(struct sock *sk, struct sk_buff *skb); int (*extract_input)(struct xfrm_state *x, struct sk_buff *skb); int (*extract_output)(struct xfrm_state *x, @@ -1503,7 +1503,7 @@ int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type); int xfrm_input_resume(struct sk_buff *skb, int nexthdr); int xfrm_output_resume(struct sk_buff *skb, int err); -int xfrm_output(struct sk_buff *skb); +int xfrm_output(struct sock *sk, struct sk_buff *skb); int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); void xfrm_local_error(struct sk_buff *skb, int mtu); int xfrm4_extract_header(struct sk_buff *skb); @@ -1524,7 +1524,7 @@ static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb); int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb); int xfrm4_output(struct sock *sk, struct sk_buff *skb); -int xfrm4_output_finish(struct sk_buff *skb); +int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb); int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err); int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol); int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char protocol); @@ -1549,7 +1549,7 @@ __be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr); int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb); int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb); int xfrm6_output(struct sock *sk, struct sk_buff *skb); -int xfrm6_output_finish(struct sk_buff *skb); +int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb); int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, u8 **prevhdr); diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 3304a5442331..e97572b5d2cc 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -35,7 +35,7 @@ static inline int should_deliver(const struct net_bridge_port *p, p->state == BR_STATE_FORWARDING; } -int br_dev_queue_push_xmit(struct sk_buff *skb) +int br_dev_queue_push_xmit(struct sock *sk, struct sk_buff *skb) { if (!is_skb_forwardable(skb->dev, skb)) { kfree_skb(skb); @@ -49,9 +49,10 @@ int br_dev_queue_push_xmit(struct sk_buff *skb) } EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit); -int br_forward_finish(struct sk_buff *skb) +int br_forward_finish(struct sock *sk, struct sk_buff *skb) { - return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev, + return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, sk, skb, + NULL, skb->dev, br_dev_queue_push_xmit); } @@ -75,7 +76,8 @@ static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) return; } - NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, + NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, + NULL, skb->dev, br_forward_finish); } @@ -96,7 +98,8 @@ static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb) skb->dev = to->dev; skb_forward_csum(skb); - NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, + NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, NULL, skb, + indev, skb->dev, br_forward_finish); } diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 052c5ebbc947..f921a5dce22d 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -55,8 +55,9 @@ static int br_pass_frame_up(struct sk_buff *skb) if (!skb) return NET_RX_DROP; - return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, - netif_receive_skb); + return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb, + indev, NULL, + netif_receive_skb_sk); } static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br, @@ -119,7 +120,7 @@ static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br, } /* note: already called with rcu_read_lock */ -int br_handle_frame_finish(struct sk_buff *skb) +int br_handle_frame_finish(struct sock *sk, struct sk_buff *skb) { const unsigned char *dest = eth_hdr(skb)->h_dest; struct net_bridge_port *p = br_port_get_rcu(skb->dev); @@ -207,7 +208,7 @@ drop: EXPORT_SYMBOL_GPL(br_handle_frame_finish); /* note: already called with rcu_read_lock */ -static int br_handle_local_finish(struct sk_buff *skb) +static int br_handle_local_finish(struct sock *sk, struct sk_buff *skb) { struct net_bridge_port *p = br_port_get_rcu(skb->dev); u16 vid = 0; @@ -277,8 +278,8 @@ rx_handler_result_t br_handle_frame(struct sk_buff **pskb) } /* Deliver packet to local host only */ - if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, - NULL, br_handle_local_finish)) { + if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, NULL, skb, + skb->dev, NULL, br_handle_local_finish)) { return RX_HANDLER_CONSUMED; /* consumed by filter */ } else { *pskb = skb; @@ -302,7 +303,8 @@ forward: if (ether_addr_equal(p->br->dev->dev_addr, dest)) skb->pkt_type = PACKET_HOST; - NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, + NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb, + skb->dev, NULL, br_handle_frame_finish); break; default: diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index c465876c7861..4b6722f8f179 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -814,7 +814,8 @@ static void __br_multicast_send_query(struct net_bridge *br, if (port) { skb->dev = port->dev; - NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, + NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, + NULL, skb->dev, br_dev_queue_push_xmit); } else { br_multicast_select_own_querier(br, ip, skb); diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 7527e94dd5dc..acd31c9f2116 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -261,7 +261,7 @@ static void nf_bridge_update_protocol(struct sk_buff *skb) /* PF_BRIDGE/PRE_ROUTING *********************************************/ /* Undo the changes made for ip6tables PREROUTING and continue the * bridge PRE_ROUTING hook. */ -static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) +static int br_nf_pre_routing_finish_ipv6(struct sock *sk, struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; struct rtable *rt; @@ -282,7 +282,8 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) skb->dev = nf_bridge->physindev; nf_bridge_update_protocol(skb); nf_bridge_push_encap_header(skb); - NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, + NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, sk, skb, + skb->dev, NULL, br_handle_frame_finish, 1); return 0; @@ -293,7 +294,7 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) * don't, we use the neighbour framework to find out. In both cases, we make * sure that br_handle_frame_finish() is called afterwards. */ -static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) +static int br_nf_pre_routing_finish_bridge(struct sock *sk, struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; struct neighbour *neigh; @@ -310,7 +311,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) if (neigh->hh.hh_len) { neigh_hh_bridge(&neigh->hh, skb); skb->dev = nf_bridge->physindev; - ret = br_handle_frame_finish(skb); + ret = br_handle_frame_finish(sk, skb); } else { /* the neighbour function below overwrites the complete * MAC header, so we save the Ethernet source address and @@ -387,7 +388,7 @@ static bool dnat_took_place(const struct sk_buff *skb) * device, we proceed as if ip_route_input() succeeded. If it differs from the * logical bridge port or if ip_route_output_key() fails we drop the packet. */ -static int br_nf_pre_routing_finish(struct sk_buff *skb) +static int br_nf_pre_routing_finish(struct sock *sk, struct sk_buff *skb) { struct net_device *dev = skb->dev; struct iphdr *iph = ip_hdr(skb); @@ -440,7 +441,7 @@ bridged_dnat: nf_bridge_push_encap_header(skb); NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, - skb, skb->dev, NULL, + sk, skb, skb->dev, NULL, br_nf_pre_routing_finish_bridge, 1); return 0; @@ -460,7 +461,8 @@ bridged_dnat: skb->dev = nf_bridge->physindev; nf_bridge_update_protocol(skb); nf_bridge_push_encap_header(skb); - NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, + NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, sk, skb, + skb->dev, NULL, br_handle_frame_finish, 1); return 0; @@ -596,7 +598,8 @@ static unsigned int br_nf_pre_routing_ipv6(const struct nf_hook_ops *ops, return NF_DROP; skb->protocol = htons(ETH_P_IPV6); - NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, + NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, state->sk, skb, + skb->dev, NULL, br_nf_pre_routing_finish_ipv6); return NF_STOLEN; @@ -651,7 +654,8 @@ static unsigned int br_nf_pre_routing(const struct nf_hook_ops *ops, skb->protocol = htons(ETH_P_IP); - NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, + NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->sk, skb, + skb->dev, NULL, br_nf_pre_routing_finish); return NF_STOLEN; @@ -674,7 +678,7 @@ static unsigned int br_nf_local_in(const struct nf_hook_ops *ops, } /* PF_BRIDGE/FORWARD *************************************************/ -static int br_nf_forward_finish(struct sk_buff *skb) +static int br_nf_forward_finish(struct sock *sk, struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; struct net_device *in; @@ -691,8 +695,8 @@ static int br_nf_forward_finish(struct sk_buff *skb) } nf_bridge_push_encap_header(skb); - NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, in, - skb->dev, br_forward_finish, 1); + NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_FORWARD, sk, skb, + in, skb->dev, br_forward_finish, 1); return 0; } @@ -746,7 +750,8 @@ static unsigned int br_nf_forward_ip(const struct nf_hook_ops *ops, else skb->protocol = htons(ETH_P_IPV6); - NF_HOOK(pf, NF_INET_FORWARD, skb, brnf_get_logical_dev(skb, state->in), + NF_HOOK(pf, NF_INET_FORWARD, NULL, skb, + brnf_get_logical_dev(skb, state->in), parent, br_nf_forward_finish); return NF_STOLEN; @@ -780,8 +785,8 @@ static unsigned int br_nf_forward_arp(const struct nf_hook_ops *ops, return NF_ACCEPT; } *d = state->in; - NF_HOOK(NFPROTO_ARP, NF_ARP_FORWARD, skb, state->in, - state->out, br_nf_forward_finish); + NF_HOOK(NFPROTO_ARP, NF_ARP_FORWARD, state->sk, skb, + state->in, state->out, br_nf_forward_finish); return NF_STOLEN; } @@ -804,24 +809,24 @@ static bool nf_bridge_copy_header(struct sk_buff *skb) return true; } -static int br_nf_push_frag_xmit(struct sk_buff *skb) +static int br_nf_push_frag_xmit(struct sock *sk, struct sk_buff *skb) { if (!nf_bridge_copy_header(skb)) { kfree_skb(skb); return 0; } - return br_dev_queue_push_xmit(skb); + return br_dev_queue_push_xmit(sk, skb); } -static int br_nf_dev_queue_xmit(struct sk_buff *skb) +static int br_nf_dev_queue_xmit(struct sock *sk, struct sk_buff *skb) { int ret; int frag_max_size; unsigned int mtu_reserved; if (skb_is_gso(skb) || skb->protocol != htons(ETH_P_IP)) - return br_dev_queue_push_xmit(skb); + return br_dev_queue_push_xmit(sk, skb); mtu_reserved = nf_bridge_mtu_reduction(skb); /* This is wrong! We should preserve the original fragment @@ -833,16 +838,16 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb) /* Drop invalid packet */ return NF_DROP; IPCB(skb)->frag_max_size = frag_max_size; - ret = ip_fragment(skb, br_nf_push_frag_xmit); + ret = ip_fragment(sk, skb, br_nf_push_frag_xmit); } else - ret = br_dev_queue_push_xmit(skb); + ret = br_dev_queue_push_xmit(sk, skb); return ret; } #else -static int br_nf_dev_queue_xmit(struct sk_buff *skb) +static int br_nf_dev_queue_xmit(struct sock *sk, struct sk_buff *skb) { - return br_dev_queue_push_xmit(skb); + return br_dev_queue_push_xmit(sk, skb); } #endif @@ -887,7 +892,8 @@ static unsigned int br_nf_post_routing(const struct nf_hook_ops *ops, else skb->protocol = htons(ETH_P_IPV6); - NF_HOOK(pf, NF_INET_POST_ROUTING, skb, NULL, realoutdev, + NF_HOOK(pf, NF_INET_POST_ROUTING, state->sk, skb, + NULL, realoutdev, br_nf_dev_queue_xmit); return NF_STOLEN; @@ -927,7 +933,7 @@ static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb) skb_copy_to_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN); skb->dev = nf_bridge->physindev; - br_handle_frame_finish(skb); + br_handle_frame_finish(NULL, skb); } static int br_nf_dev_xmit(struct sk_buff *skb) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index b46fa0c5b8ec..6ca0251cb478 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -410,10 +410,10 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, /* br_forward.c */ void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb); -int br_dev_queue_push_xmit(struct sk_buff *skb); +int br_dev_queue_push_xmit(struct sock *sk, struct sk_buff *skb); void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0); -int br_forward_finish(struct sk_buff *skb); +int br_forward_finish(struct sock *sk, struct sk_buff *skb); void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, bool unicast); void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, struct sk_buff *skb2, bool unicast); @@ -431,7 +431,7 @@ void br_port_flags_change(struct net_bridge_port *port, unsigned long mask); void br_manage_promisc(struct net_bridge *br); /* br_input.c */ -int br_handle_frame_finish(struct sk_buff *skb); +int br_handle_frame_finish(struct sock *sk, struct sk_buff *skb); rx_handler_result_t br_handle_frame(struct sk_buff **pskb); static inline bool br_rx_handler_check_rcu(const struct net_device *dev) diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index bdb459d21ad8..534fc4cd263e 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -54,8 +54,9 @@ static void br_send_bpdu(struct net_bridge_port *p, skb_reset_mac_header(skb); - NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, - dev_queue_xmit); + NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, NULL, skb, + NULL, skb->dev, + dev_queue_xmit_sk); } static inline void br_set_ticks(unsigned char *dest, int j) diff --git a/net/core/dev.c b/net/core/dev.c index 3b3965288f52..b2775f06c710 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2879,7 +2879,7 @@ EXPORT_SYMBOL(xmit_recursion); * dev_loopback_xmit - loop back @skb * @skb: buffer to transmit */ -int dev_loopback_xmit(struct sk_buff *skb) +int dev_loopback_xmit(struct sock *sk, struct sk_buff *skb) { skb_reset_mac_header(skb); __skb_pull(skb, skb_network_offset(skb)); @@ -3017,11 +3017,11 @@ out: return rc; } -int dev_queue_xmit(struct sk_buff *skb) +int dev_queue_xmit_sk(struct sock *sk, struct sk_buff *skb) { return __dev_queue_xmit(skb, NULL); } -EXPORT_SYMBOL(dev_queue_xmit); +EXPORT_SYMBOL(dev_queue_xmit_sk); int dev_queue_xmit_accel(struct sk_buff *skb, void *accel_priv) { @@ -3853,13 +3853,13 @@ static int netif_receive_skb_internal(struct sk_buff *skb) * NET_RX_SUCCESS: no congestion * NET_RX_DROP: packet was dropped */ -int netif_receive_skb(struct sk_buff *skb) +int netif_receive_skb_sk(struct sock *sk, struct sk_buff *skb) { trace_netif_receive_skb_entry(skb); return netif_receive_skb_internal(skb); } -EXPORT_SYMBOL(netif_receive_skb); +EXPORT_SYMBOL(netif_receive_skb_sk); /* Network device is going away, flush any packets still pending * Called with irqs disabled. diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index be1f08cdad29..4507b188fc51 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -194,7 +194,7 @@ static int dn_neigh_output(struct neighbour *neigh, struct sk_buff *skb) return err; } -static int dn_neigh_output_packet(struct sk_buff *skb) +static int dn_neigh_output_packet(struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct dn_route *rt = (struct dn_route *)dst; @@ -206,7 +206,8 @@ static int dn_neigh_output_packet(struct sk_buff *skb) /* * For talking to broadcast devices: Ethernet & PPP */ -static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb) +static int dn_long_output(struct neighbour *neigh, struct sock *sk, + struct sk_buff *skb) { struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3; @@ -245,14 +246,15 @@ static int dn_long_output(struct neighbour *neigh, struct sk_buff *skb) skb_reset_network_header(skb); - return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL, - neigh->dev, dn_neigh_output_packet); + return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, sk, skb, + NULL, neigh->dev, dn_neigh_output_packet); } /* * For talking to pointopoint and multidrop devices: DDCMP and X.25 */ -static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb) +static int dn_short_output(struct neighbour *neigh, struct sock *sk, + struct sk_buff *skb) { struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; @@ -284,8 +286,8 @@ static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb) skb_reset_network_header(skb); - return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL, - neigh->dev, dn_neigh_output_packet); + return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, sk, skb, + NULL, neigh->dev, dn_neigh_output_packet); } /* @@ -293,7 +295,8 @@ static int dn_short_output(struct neighbour *neigh, struct sk_buff *skb) * Phase 3 output is the same as short output, execpt that * it clears the area bits before transmission. */ -static int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb) +static int dn_phase3_output(struct neighbour *neigh, struct sock *sk, + struct sk_buff *skb) { struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; @@ -324,11 +327,11 @@ static int dn_phase3_output(struct neighbour *neigh, struct sk_buff *skb) skb_reset_network_header(skb); - return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL, - neigh->dev, dn_neigh_output_packet); + return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, sk, skb, + NULL, neigh->dev, dn_neigh_output_packet); } -int dn_to_neigh_output(struct sk_buff *skb) +int dn_to_neigh_output(struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct dn_route *rt = (struct dn_route *) dst; @@ -347,11 +350,11 @@ int dn_to_neigh_output(struct sk_buff *skb) rcu_read_unlock(); if (dn->flags & DN_NDFLAG_P3) - return dn_phase3_output(neigh, skb); + return dn_phase3_output(neigh, sk, skb); if (use_long) - return dn_long_output(neigh, skb); + return dn_long_output(neigh, sk, skb); else - return dn_short_output(neigh, skb); + return dn_short_output(neigh, sk, skb); } /* @@ -372,7 +375,7 @@ void dn_neigh_pointopoint_hello(struct sk_buff *skb) /* * Ethernet router hello message received */ -int dn_neigh_router_hello(struct sk_buff *skb) +int dn_neigh_router_hello(struct sock *sk, struct sk_buff *skb) { struct rtnode_hello_message *msg = (struct rtnode_hello_message *)skb->data; @@ -434,7 +437,7 @@ int dn_neigh_router_hello(struct sk_buff *skb) /* * Endnode hello message received */ -int dn_neigh_endnode_hello(struct sk_buff *skb) +int dn_neigh_endnode_hello(struct sock *sk, struct sk_buff *skb) { struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data; struct neighbour *neigh; diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index fe5f01485d33..a321eac9fd0c 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c @@ -714,7 +714,7 @@ out: return ret; } -static int dn_nsp_rx_packet(struct sk_buff *skb) +static int dn_nsp_rx_packet(struct sock *sk2, struct sk_buff *skb) { struct dn_skb_cb *cb = DN_SKB_CB(skb); struct sock *sk = NULL; @@ -814,7 +814,8 @@ free_out: int dn_nsp_rx(struct sk_buff *skb) { - return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_IN, skb, skb->dev, NULL, + return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_IN, NULL, skb, + skb->dev, NULL, dn_nsp_rx_packet); } diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 9ab0c4ba297f..03227ffd19ce 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -512,7 +512,7 @@ static int dn_return_long(struct sk_buff *skb) * * Returns: result of input function if route is found, error code otherwise */ -static int dn_route_rx_packet(struct sk_buff *skb) +static int dn_route_rx_packet(struct sock *sk, struct sk_buff *skb) { struct dn_skb_cb *cb; int err; @@ -573,7 +573,8 @@ static int dn_route_rx_long(struct sk_buff *skb) ptr++; cb->hops = *ptr++; /* Visit Count */ - return NF_HOOK(NFPROTO_DECNET, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, + return NF_HOOK(NFPROTO_DECNET, NF_DN_PRE_ROUTING, NULL, skb, + skb->dev, NULL, dn_route_rx_packet); drop_it: @@ -600,7 +601,8 @@ static int dn_route_rx_short(struct sk_buff *skb) ptr += 2; cb->hops = *ptr & 0x3f; - return NF_HOOK(NFPROTO_DECNET, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, + return NF_HOOK(NFPROTO_DECNET, NF_DN_PRE_ROUTING, NULL, skb, + skb->dev, NULL, dn_route_rx_packet); drop_it: @@ -608,7 +610,7 @@ drop_it: return NET_RX_DROP; } -static int dn_route_discard(struct sk_buff *skb) +static int dn_route_discard(struct sock *sk, struct sk_buff *skb) { /* * I know we drop the packet here, but thats considered success in @@ -618,7 +620,7 @@ static int dn_route_discard(struct sk_buff *skb) return NET_RX_SUCCESS; } -static int dn_route_ptp_hello(struct sk_buff *skb) +static int dn_route_ptp_hello(struct sock *sk, struct sk_buff *skb) { dn_dev_hello(skb); dn_neigh_pointopoint_hello(skb); @@ -704,22 +706,22 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type switch (flags & DN_RT_CNTL_MSK) { case DN_RT_PKT_HELO: return NF_HOOK(NFPROTO_DECNET, NF_DN_HELLO, - skb, skb->dev, NULL, + NULL, skb, skb->dev, NULL, dn_route_ptp_hello); case DN_RT_PKT_L1RT: case DN_RT_PKT_L2RT: return NF_HOOK(NFPROTO_DECNET, NF_DN_ROUTE, - skb, skb->dev, NULL, + NULL, skb, skb->dev, NULL, dn_route_discard); case DN_RT_PKT_ERTH: return NF_HOOK(NFPROTO_DECNET, NF_DN_HELLO, - skb, skb->dev, NULL, + NULL, skb, skb->dev, NULL, dn_neigh_router_hello); case DN_RT_PKT_EEDH: return NF_HOOK(NFPROTO_DECNET, NF_DN_HELLO, - skb, skb->dev, NULL, + NULL, skb, skb->dev, NULL, dn_neigh_endnode_hello); } } else { @@ -768,7 +770,8 @@ static int dn_output(struct sock *sk, struct sk_buff *skb) cb->rt_flags |= DN_RT_F_IE; cb->hops = 0; - return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_OUT, skb, NULL, dev, + return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_OUT, sk, skb, + NULL, dev, dn_to_neigh_output); error: @@ -816,7 +819,8 @@ static int dn_forward(struct sk_buff *skb) if (rt->rt_flags & RTCF_DOREDIRECT) cb->rt_flags |= DN_RT_F_IE; - return NF_HOOK(NFPROTO_DECNET, NF_DN_FORWARD, skb, dev, skb->dev, + return NF_HOOK(NFPROTO_DECNET, NF_DN_FORWARD, NULL, skb, + dev, skb->dev, dn_to_neigh_output); drop: diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index c6e67aa46c32..933a92820d26 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -591,7 +591,8 @@ EXPORT_SYMBOL(arp_create); void arp_xmit(struct sk_buff *skb) { /* Send it off, maybe filter it using firewalling first. */ - NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit); + NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, NULL, skb, + NULL, skb->dev, dev_queue_xmit_sk); } EXPORT_SYMBOL(arp_xmit); @@ -625,7 +626,7 @@ EXPORT_SYMBOL(arp_send); * Process an arp request. */ -static int arp_process(struct sk_buff *skb) +static int arp_process(struct sock *sk, struct sk_buff *skb) { struct net_device *dev = skb->dev; struct in_device *in_dev = __in_dev_get_rcu(dev); @@ -846,7 +847,7 @@ out: static void parp_redo(struct sk_buff *skb) { - arp_process(skb); + arp_process(NULL, skb); } @@ -879,7 +880,8 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev, memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); - return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, skb, dev, NULL, arp_process); + return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, NULL, skb, + dev, NULL, arp_process); consumeskb: consume_skb(skb); diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index d9bc28ac5d1b..939992c456f3 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -57,7 +57,7 @@ static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) } -static int ip_forward_finish(struct sk_buff *skb) +static int ip_forward_finish(struct sock *sk, struct sk_buff *skb) { struct ip_options *opt = &(IPCB(skb)->opt); @@ -68,7 +68,7 @@ static int ip_forward_finish(struct sk_buff *skb) ip_forward_options(skb); skb_sender_cpu_clear(skb); - return dst_output(skb); + return dst_output_sk(sk, skb); } int ip_forward(struct sk_buff *skb) @@ -136,8 +136,8 @@ int ip_forward(struct sk_buff *skb) skb->priority = rt_tos2priority(iph->tos); - return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev, - rt->dst.dev, ip_forward_finish); + return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, NULL, skb, + skb->dev, rt->dst.dev, ip_forward_finish); sr_failed: /* diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 2e0410ed8f16..2db4c8773c1b 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -187,7 +187,7 @@ bool ip_call_ra_chain(struct sk_buff *skb) return false; } -static int ip_local_deliver_finish(struct sk_buff *skb) +static int ip_local_deliver_finish(struct sock *sk, struct sk_buff *skb) { struct net *net = dev_net(skb->dev); @@ -253,7 +253,8 @@ int ip_local_deliver(struct sk_buff *skb) return 0; } - return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, skb, skb->dev, NULL, + return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, NULL, skb, + skb->dev, NULL, ip_local_deliver_finish); } @@ -309,7 +310,7 @@ drop: int sysctl_ip_early_demux __read_mostly = 1; EXPORT_SYMBOL(sysctl_ip_early_demux); -static int ip_rcv_finish(struct sk_buff *skb) +static int ip_rcv_finish(struct sock *sk, struct sk_buff *skb) { const struct iphdr *iph = ip_hdr(skb); struct rtable *rt; @@ -451,7 +452,8 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, /* Must drop socket now because of tproxy. */ skb_orphan(skb); - return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL, + return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, NULL, skb, + dev, NULL, ip_rcv_finish); csum_error: diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 26f6f7956168..5da4d15262fd 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -91,14 +91,19 @@ void ip_send_check(struct iphdr *iph) } EXPORT_SYMBOL(ip_send_check); -int __ip_local_out(struct sk_buff *skb) +int __ip_local_out_sk(struct sock *sk, struct sk_buff *skb) { struct iphdr *iph = ip_hdr(skb); iph->tot_len = htons(skb->len); ip_send_check(iph); - return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL, - skb_dst(skb)->dev, dst_output); + return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, sk, skb, NULL, + skb_dst(skb)->dev, dst_output_sk); +} + +int __ip_local_out(struct sk_buff *skb) +{ + return __ip_local_out_sk(skb->sk, skb); } int ip_local_out_sk(struct sock *sk, struct sk_buff *skb) @@ -163,7 +168,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, } EXPORT_SYMBOL_GPL(ip_build_and_send_pkt); -static inline int ip_finish_output2(struct sk_buff *skb) +static inline int ip_finish_output2(struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct rtable *rt = (struct rtable *)dst; @@ -211,7 +216,7 @@ static inline int ip_finish_output2(struct sk_buff *skb) return -EINVAL; } -static int ip_finish_output_gso(struct sk_buff *skb) +static int ip_finish_output_gso(struct sock *sk, struct sk_buff *skb) { netdev_features_t features; struct sk_buff *segs; @@ -220,7 +225,7 @@ static int ip_finish_output_gso(struct sk_buff *skb) /* common case: locally created skb or seglen is <= mtu */ if (((IPCB(skb)->flags & IPSKB_FORWARDED) == 0) || skb_gso_network_seglen(skb) <= ip_skb_dst_mtu(skb)) - return ip_finish_output2(skb); + return ip_finish_output2(sk, skb); /* Slowpath - GSO segment length is exceeding the dst MTU. * @@ -243,7 +248,7 @@ static int ip_finish_output_gso(struct sk_buff *skb) int err; segs->next = NULL; - err = ip_fragment(segs, ip_finish_output2); + err = ip_fragment(sk, segs, ip_finish_output2); if (err && ret == 0) ret = err; @@ -253,22 +258,22 @@ static int ip_finish_output_gso(struct sk_buff *skb) return ret; } -static int ip_finish_output(struct sk_buff *skb) +static int ip_finish_output(struct sock *sk, struct sk_buff *skb) { #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) /* Policy lookup after SNAT yielded a new policy */ if (skb_dst(skb)->xfrm) { IPCB(skb)->flags |= IPSKB_REROUTED; - return dst_output(skb); + return dst_output_sk(sk, skb); } #endif if (skb_is_gso(skb)) - return ip_finish_output_gso(skb); + return ip_finish_output_gso(sk, skb); if (skb->len > ip_skb_dst_mtu(skb)) - return ip_fragment(skb, ip_finish_output2); + return ip_fragment(sk, skb, ip_finish_output2); - return ip_finish_output2(skb); + return ip_finish_output2(sk, skb); } int ip_mc_output(struct sock *sk, struct sk_buff *skb) @@ -307,7 +312,7 @@ int ip_mc_output(struct sock *sk, struct sk_buff *skb) struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); if (newskb) NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, - newskb, NULL, newskb->dev, + sk, newskb, NULL, newskb->dev, dev_loopback_xmit); } @@ -322,11 +327,11 @@ int ip_mc_output(struct sock *sk, struct sk_buff *skb) if (rt->rt_flags&RTCF_BROADCAST) { struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); if (newskb) - NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, newskb, + NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, sk, newskb, NULL, newskb->dev, dev_loopback_xmit); } - return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, + return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, sk, skb, NULL, skb->dev, ip_finish_output, !(IPCB(skb)->flags & IPSKB_REROUTED)); } @@ -340,7 +345,8 @@ int ip_output(struct sock *sk, struct sk_buff *skb) skb->dev = dev; skb->protocol = htons(ETH_P_IP); - return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev, + return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, sk, skb, + NULL, dev, ip_finish_output, !(IPCB(skb)->flags & IPSKB_REROUTED)); } @@ -480,7 +486,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) * single device frame, and queue such a frame for sending. */ -int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) +int ip_fragment(struct sock *sk, struct sk_buff *skb, + int (*output)(struct sock *, struct sk_buff *)) { struct iphdr *iph; int ptr; @@ -593,7 +600,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) ip_send_check(iph); } - err = output(skb); + err = output(sk, skb); if (!err) IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGCREATES); @@ -730,7 +737,7 @@ slow_path: ip_send_check(iph); - err = output(skb2); + err = output(sk, skb2); if (err) goto fail; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 5f17d0e78071..3a2c0162c3ba 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1679,7 +1679,7 @@ static void ip_encap(struct net *net, struct sk_buff *skb, nf_reset(skb); } -static inline int ipmr_forward_finish(struct sk_buff *skb) +static inline int ipmr_forward_finish(struct sock *sk, struct sk_buff *skb) { struct ip_options *opt = &(IPCB(skb)->opt); @@ -1689,7 +1689,7 @@ static inline int ipmr_forward_finish(struct sk_buff *skb) if (unlikely(opt->optlen)) ip_forward_options(skb); - return dst_output(skb); + return dst_output_sk(sk, skb); } /* @@ -1788,7 +1788,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, * not mrouter) cannot join to more than one interface - it will * result in receiving multiple packets. */ - NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev, dev, + NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, NULL, skb, + skb->dev, dev, ipmr_forward_finish); return; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 6d0fa8fb8af0..c0bb648fb2f9 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -412,8 +412,8 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, icmp_out_count(net, ((struct icmphdr *) skb_transport_header(skb))->type); - err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL, - rt->dst.dev, dst_output); + err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, sk, skb, + NULL, rt->dst.dev, dst_output_sk); if (err > 0) err = net_xmit_errno(err); if (err) diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index cac7468db0a1..60b032f58ccc 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -22,7 +22,7 @@ int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb) return xfrm4_extract_header(skb); } -static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb) +static inline int xfrm4_rcv_encap_finish(struct sock *sk, struct sk_buff *skb) { if (!skb_dst(skb)) { const struct iphdr *iph = ip_hdr(skb); @@ -52,7 +52,8 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) iph->tot_len = htons(skb->len); ip_send_check(iph); - NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, + NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, NULL, skb, + skb->dev, NULL, xfrm4_rcv_encap_finish); return 0; } diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index dab73813cb92..2878dbfffeb7 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -69,7 +69,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) } EXPORT_SYMBOL(xfrm4_prepare_output); -int xfrm4_output_finish(struct sk_buff *skb) +int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb) { memset(IPCB(skb), 0, sizeof(*IPCB(skb))); @@ -77,26 +77,26 @@ int xfrm4_output_finish(struct sk_buff *skb) IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; #endif - return xfrm_output(skb); + return xfrm_output(sk, skb); } -static int __xfrm4_output(struct sk_buff *skb) +static int __xfrm4_output(struct sock *sk, struct sk_buff *skb) { struct xfrm_state *x = skb_dst(skb)->xfrm; #ifdef CONFIG_NETFILTER if (!x) { IPCB(skb)->flags |= IPSKB_REROUTED; - return dst_output(skb); + return dst_output_sk(sk, skb); } #endif - return x->outer_mode->afinfo->output_finish(skb); + return x->outer_mode->afinfo->output_finish(sk, skb); } int xfrm4_output(struct sock *sk, struct sk_buff *skb) { - return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, + return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, sk, skb, NULL, skb_dst(skb)->dev, __xfrm4_output, !(IPCB(skb)->flags & IPSKB_REROUTED)); } diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index fb97f7f8d4ed..f2e464eba5ef 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -46,8 +46,7 @@ #include #include - -int ip6_rcv_finish(struct sk_buff *skb) +int ip6_rcv_finish(struct sock *sk, struct sk_buff *skb) { if (sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) { const struct inet6_protocol *ipprot; @@ -183,7 +182,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt /* Must drop socket now because of tproxy. */ skb_orphan(skb); - return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, dev, NULL, + return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, NULL, skb, + dev, NULL, ip6_rcv_finish); err: IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS); @@ -198,7 +198,7 @@ drop: */ -static int ip6_input_finish(struct sk_buff *skb) +static int ip6_input_finish(struct sock *sk, struct sk_buff *skb) { struct net *net = dev_net(skb_dst(skb)->dev); const struct inet6_protocol *ipprot; @@ -277,7 +277,8 @@ discard: int ip6_input(struct sk_buff *skb) { - return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, skb, skb->dev, NULL, + return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, NULL, skb, + skb->dev, NULL, ip6_input_finish); } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 654f245aa930..7fde1f265c90 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -56,7 +56,7 @@ #include #include -static int ip6_finish_output2(struct sk_buff *skb) +static int ip6_finish_output2(struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct net_device *dev = dst->dev; @@ -70,7 +70,7 @@ static int ip6_finish_output2(struct sk_buff *skb) if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); - if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) && + if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(sk) && ((mroute6_socket(dev_net(dev), skb) && !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, @@ -82,7 +82,7 @@ static int ip6_finish_output2(struct sk_buff *skb) */ if (newskb) NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, - newskb, NULL, newskb->dev, + sk, newskb, NULL, newskb->dev, dev_loopback_xmit); if (ipv6_hdr(skb)->hop_limit == 0) { @@ -122,14 +122,14 @@ static int ip6_finish_output2(struct sk_buff *skb) return -EINVAL; } -static int ip6_finish_output(struct sk_buff *skb) +static int ip6_finish_output(struct sock *sk, struct sk_buff *skb) { if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || dst_allfrag(skb_dst(skb)) || (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size)) - return ip6_fragment(skb, ip6_finish_output2); + return ip6_fragment(sk, skb, ip6_finish_output2); else - return ip6_finish_output2(skb); + return ip6_finish_output2(sk, skb); } int ip6_output(struct sock *sk, struct sk_buff *skb) @@ -143,7 +143,8 @@ int ip6_output(struct sock *sk, struct sk_buff *skb) return 0; } - return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev, + return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, sk, skb, + NULL, dev, ip6_finish_output, !(IP6CB(skb)->flags & IP6SKB_REROUTED)); } @@ -223,8 +224,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) { IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUT, skb->len); - return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, - dst->dev, dst_output); + return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb, + NULL, dst->dev, dst_output_sk); } skb->dev = dst->dev; @@ -316,10 +317,10 @@ static int ip6_forward_proxy_check(struct sk_buff *skb) return 0; } -static inline int ip6_forward_finish(struct sk_buff *skb) +static inline int ip6_forward_finish(struct sock *sk, struct sk_buff *skb) { skb_sender_cpu_clear(skb); - return dst_output(skb); + return dst_output_sk(sk, skb); } static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) @@ -511,7 +512,8 @@ int ip6_forward(struct sk_buff *skb) IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); IP6_ADD_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len); - return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev, + return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, NULL, skb, + skb->dev, dst->dev, ip6_forward_finish); error: @@ -538,7 +540,8 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) skb_copy_secmark(to, from); } -int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) +int ip6_fragment(struct sock *sk, struct sk_buff *skb, + int (*output)(struct sock *, struct sk_buff *)) { struct sk_buff *frag; struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); @@ -667,7 +670,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) ip6_copy_metadata(frag, skb); } - err = output(skb); + err = output(sk, skb); if (!err) IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), IPSTATS_MIB_FRAGCREATES); @@ -800,7 +803,7 @@ slow_path: /* * Put this fragment into the sending queue. */ - err = output(frag); + err = output(sk, frag); if (err) goto fail; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 8493a22e74eb..74ceb73c1c9a 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1986,13 +1986,13 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) } #endif -static inline int ip6mr_forward2_finish(struct sk_buff *skb) +static inline int ip6mr_forward2_finish(struct sock *sk, struct sk_buff *skb) { IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTFORWDATAGRAMS); IP6_ADD_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTOCTETS, skb->len); - return dst_output(skb); + return dst_output_sk(sk, skb); } /* @@ -2064,7 +2064,8 @@ static int ip6mr_forward2(struct net *net, struct mr6_table *mrt, IP6CB(skb)->flags |= IP6SKB_FORWARDED; - return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev, + return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, NULL, skb, + skb->dev, dev, ip6mr_forward2_finish); out_free: diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index fac1f27e428e..083b2927fc67 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1644,8 +1644,9 @@ static void mld_sendpack(struct sk_buff *skb) payload_len = skb->len; - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, - dst_output); + err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, + net->ipv6.igmp_sk, skb, NULL, skb->dev, + dst_output_sk); out: if (!err) { ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT); @@ -2007,8 +2008,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) } skb_dst_set(skb, dst); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, - dst_output); + err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb, + NULL, skb->dev, dst_output_sk); out: if (!err) { ICMP6MSGOUT_INC_STATS(net, idev, type); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 71fde6cafb35..96f153c0846b 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -463,8 +463,9 @@ static void ndisc_send_skb(struct sk_buff *skb, idev = __in6_dev_get(dst->dev); IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, - dst_output); + err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb, + NULL, dst->dev, + dst_output_sk); if (!err) { ICMP6MSGOUT_INC_STATS(net, idev, type); ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c index e2b882056751..a45db0b4785c 100644 --- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c @@ -75,7 +75,7 @@ static unsigned int ipv6_defrag(const struct nf_hook_ops *ops, nf_ct_frag6_consume_orig(reasm); - NF_HOOK_THRESH(NFPROTO_IPV6, ops->hooknum, reasm, + NF_HOOK_THRESH(NFPROTO_IPV6, ops->hooknum, state->sk, reasm, state->in, state->out, state->okfn, NF_IP6_PRI_CONNTRACK_DEFRAG + 1); diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 4016a6ef9d61..7d1131dc29fe 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -146,8 +146,8 @@ int __ip6_local_out(struct sk_buff *skb) ipv6_hdr(skb)->payload_len = htons(len); IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); - return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, - skb_dst(skb)->dev, dst_output); + return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb->sk, skb, + NULL, skb_dst(skb)->dev, dst_output_sk); } EXPORT_SYMBOL_GPL(__ip6_local_out); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 79ccdb4c1b33..8072bd4139b7 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -652,8 +652,8 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, goto error_fault; IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, - rt->dst.dev, dst_output); + err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb, + NULL, rt->dst.dev, dst_output_sk); if (err > 0) err = net_xmit_errno(err); if (err) diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index f48fbe4d16f5..74bd17882a2f 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -42,7 +42,8 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) ipv6_hdr(skb)->payload_len = htons(skb->len); __skb_push(skb, skb->data - skb_network_header(skb)); - NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL, + NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, NULL, skb, + skb->dev, NULL, ip6_rcv_finish); return -1; } diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 010f8bd2d577..09c76a7b474d 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -120,7 +120,7 @@ int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) } EXPORT_SYMBOL(xfrm6_prepare_output); -int xfrm6_output_finish(struct sk_buff *skb) +int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb) { memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); @@ -128,10 +128,10 @@ int xfrm6_output_finish(struct sk_buff *skb) IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; #endif - return xfrm_output(skb); + return xfrm_output(sk, skb); } -static int __xfrm6_output(struct sk_buff *skb) +static int __xfrm6_output(struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct xfrm_state *x = dst->xfrm; @@ -140,7 +140,7 @@ static int __xfrm6_output(struct sk_buff *skb) #ifdef CONFIG_NETFILTER if (!x) { IP6CB(skb)->flags |= IP6SKB_REROUTED; - return dst_output(skb); + return dst_output_sk(sk, skb); } #endif @@ -160,14 +160,15 @@ static int __xfrm6_output(struct sk_buff *skb) if (x->props.mode == XFRM_MODE_TUNNEL && ((skb->len > mtu && !skb_is_gso(skb)) || dst_allfrag(skb_dst(skb)))) { - return ip6_fragment(skb, x->outer_mode->afinfo->output_finish); + return ip6_fragment(sk, skb, + x->outer_mode->afinfo->output_finish); } - return x->outer_mode->afinfo->output_finish(skb); + return x->outer_mode->afinfo->output_finish(sk, skb); } int xfrm6_output(struct sock *sk, struct sk_buff *skb) { - return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, + return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, sk, skb, NULL, skb_dst(skb)->dev, __xfrm6_output, !(IP6CB(skb)->flags & IP6SKB_REROUTED)); } diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index bf02932b7188..19986ec5f21a 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -536,8 +536,8 @@ static inline int ip_vs_nat_send_or_cont(int pf, struct sk_buff *skb, ip_vs_update_conntrack(skb, cp, 1); if (!local) { skb_forward_csum(skb); - NF_HOOK(pf, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, - dst_output); + NF_HOOK(pf, NF_INET_LOCAL_OUT, NULL, skb, + NULL, skb_dst(skb)->dev, dst_output_sk); } else ret = NF_ACCEPT; return ret; @@ -554,8 +554,8 @@ static inline int ip_vs_send_or_cont(int pf, struct sk_buff *skb, ip_vs_notrack(skb); if (!local) { skb_forward_csum(skb); - NF_HOOK(pf, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev, - dst_output); + NF_HOOK(pf, NF_INET_LOCAL_OUT, NULL, skb, + NULL, skb_dst(skb)->dev, dst_output_sk); } else ret = NF_ACCEPT; return ret; diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index c4a706678f88..3f3ac57b2998 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -202,7 +202,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) case NF_ACCEPT: case NF_STOP: local_bh_disable(); - entry->state.okfn(skb); + entry->state.okfn(entry->state.sk, skb); local_bh_enable(); break; case NF_QUEUE: diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 7c532856b398..fbcedbe33190 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -19,7 +19,7 @@ #include #include -static int xfrm_output2(struct sk_buff *skb); +static int xfrm_output2(struct sock *sk, struct sk_buff *skb); static int xfrm_skb_check_space(struct sk_buff *skb) { @@ -130,7 +130,7 @@ int xfrm_output_resume(struct sk_buff *skb, int err) return dst_output(skb); err = nf_hook(skb_dst(skb)->ops->family, - NF_INET_POST_ROUTING, skb, + NF_INET_POST_ROUTING, skb->sk, skb, NULL, skb_dst(skb)->dev, xfrm_output2); if (unlikely(err != 1)) goto out; @@ -144,12 +144,12 @@ out: } EXPORT_SYMBOL_GPL(xfrm_output_resume); -static int xfrm_output2(struct sk_buff *skb) +static int xfrm_output2(struct sock *sk, struct sk_buff *skb) { return xfrm_output_resume(skb, 1); } -static int xfrm_output_gso(struct sk_buff *skb) +static int xfrm_output_gso(struct sock *sk, struct sk_buff *skb) { struct sk_buff *segs; @@ -165,7 +165,7 @@ static int xfrm_output_gso(struct sk_buff *skb) int err; segs->next = NULL; - err = xfrm_output2(segs); + err = xfrm_output2(sk, segs); if (unlikely(err)) { kfree_skb_list(nskb); @@ -178,13 +178,13 @@ static int xfrm_output_gso(struct sk_buff *skb) return 0; } -int xfrm_output(struct sk_buff *skb) +int xfrm_output(struct sock *sk, struct sk_buff *skb) { struct net *net = dev_net(skb_dst(skb)->dev); int err; if (skb_is_gso(skb)) - return xfrm_output_gso(skb); + return xfrm_output_gso(sk, skb); if (skb->ip_summed == CHECKSUM_PARTIAL) { err = skb_checksum_help(skb); @@ -195,7 +195,7 @@ int xfrm_output(struct sk_buff *skb) } } - return xfrm_output2(skb); + return xfrm_output2(sk, skb); } EXPORT_SYMBOL_GPL(xfrm_output); From 79b16aadea32cce077acbe9e229fcb58a7801687 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 5 Apr 2015 22:19:09 -0400 Subject: [PATCH 557/567] udp_tunnel: Pass UDP socket down through udp_tunnel{, 6}_xmit_skb(). That was we can make sure the output path of ipv4/ipv6 operate on the UDP socket rather than whatever random thing happens to be in skb->sk. Based upon a patch by Jiri Pirko. Signed-off-by: David S. Miller Acked-by: Hannes Frederic Sowa --- drivers/net/vxlan.c | 14 ++++++++------ include/net/ip6_tunnel.h | 5 +++-- include/net/ipv6.h | 1 + include/net/udp_tunnel.h | 5 +++-- include/net/vxlan.h | 2 +- net/ipv4/geneve.c | 2 +- net/ipv4/ip_tunnel.c | 2 +- net/ipv4/udp_tunnel.c | 4 ++-- net/ipv6/ip6_gre.c | 2 +- net/ipv6/ip6_tunnel.c | 2 +- net/ipv6/ip6_udp_tunnel.c | 5 +++-- net/ipv6/output_core.c | 21 ++++++++++++++++----- net/openvswitch/vport-vxlan.c | 5 +++-- net/tipc/udp_media.c | 6 ++++-- 14 files changed, 48 insertions(+), 28 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index b5fecb49a0c6..51baac725a48 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1672,7 +1672,8 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags, } #if IS_ENABLED(CONFIG_IPV6) -static int vxlan6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, +static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, __be16 src_port, __be16 dst_port, @@ -1748,7 +1749,7 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - udp_tunnel6_xmit_skb(dst, skb, dev, saddr, daddr, prio, + udp_tunnel6_xmit_skb(dst, sk, skb, dev, saddr, daddr, prio, ttl, src_port, dst_port, !!(vxflags & VXLAN_F_UDP_ZERO_CSUM6_TX)); return 0; @@ -1758,7 +1759,7 @@ err: } #endif -int vxlan_xmit_skb(struct rtable *rt, struct sk_buff *skb, +int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, struct vxlan_metadata *md, bool xnet, u32 vxflags) @@ -1827,7 +1828,7 @@ int vxlan_xmit_skb(struct rtable *rt, struct sk_buff *skb, skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - return udp_tunnel_xmit_skb(rt, skb, src, dst, tos, + return udp_tunnel_xmit_skb(rt, sk, skb, src, dst, tos, ttl, df, src_port, dst_port, xnet, !(vxflags & VXLAN_F_UDP_CSUM)); } @@ -1882,6 +1883,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_rdst *rdst, bool did_rsc) { struct vxlan_dev *vxlan = netdev_priv(dev); + struct sock *sk = vxlan->vn_sock->sock->sk; struct rtable *rt = NULL; const struct iphdr *old_iph; struct flowi4 fl4; @@ -1961,7 +1963,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, md.vni = htonl(vni << 8); md.gbp = skb->mark; - err = vxlan_xmit_skb(rt, skb, fl4.saddr, + err = vxlan_xmit_skb(rt, sk, skb, fl4.saddr, dst->sin.sin_addr.s_addr, tos, ttl, df, src_port, dst_port, &md, !net_eq(vxlan->net, dev_net(vxlan->dev)), @@ -2021,7 +2023,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, md.vni = htonl(vni << 8); md.gbp = skb->mark; - err = vxlan6_xmit_skb(ndst, skb, dev, &fl6.saddr, &fl6.daddr, + err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr, 0, ttl, src_port, dst_port, &md, !net_eq(vxlan->net, dev_net(vxlan->dev)), vxlan->flags); diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h index 1668be5937e6..b8529aa1dae7 100644 --- a/include/net/ip6_tunnel.h +++ b/include/net/ip6_tunnel.h @@ -73,13 +73,14 @@ __u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr, struct net *ip6_tnl_get_link_net(const struct net_device *dev); int ip6_tnl_get_iflink(const struct net_device *dev); -static inline void ip6tunnel_xmit(struct sk_buff *skb, struct net_device *dev) +static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb, + struct net_device *dev) { struct net_device_stats *stats = &dev->stats; int pkt_len, err; pkt_len = skb->len; - err = ip6_local_out(skb); + err = ip6_local_out_sk(sk, skb); if (net_xmit_eval(err) == 0) { struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index b6ae959824ff..27470cd1d5f8 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -827,6 +827,7 @@ int ip6_input(struct sk_buff *skb); int ip6_mc_input(struct sk_buff *skb); int __ip6_local_out(struct sk_buff *skb); +int ip6_local_out_sk(struct sock *sk, struct sk_buff *skb); int ip6_local_out(struct sk_buff *skb); /* diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index 1a20d33d56bc..c491c1221606 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h @@ -77,13 +77,14 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock, struct udp_tunnel_sock_cfg *sock_cfg); /* Transmit the skb using UDP encapsulation. */ -int udp_tunnel_xmit_skb(struct rtable *rt, struct sk_buff *skb, +int udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, bool xnet, bool nocheck); #if IS_ENABLED(CONFIG_IPV6) -int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, +int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, __be16 src_port, diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 756e4636bad8..0082b5d33d7d 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -145,7 +145,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, void vxlan_sock_release(struct vxlan_sock *vs); -int vxlan_xmit_skb(struct rtable *rt, struct sk_buff *skb, +int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, struct vxlan_metadata *md, bool xnet, u32 vxflags); diff --git a/net/ipv4/geneve.c b/net/ipv4/geneve.c index e64f8e9785d1..b77f5e84c623 100644 --- a/net/ipv4/geneve.c +++ b/net/ipv4/geneve.c @@ -136,7 +136,7 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - return udp_tunnel_xmit_skb(rt, skb, src, dst, + return udp_tunnel_xmit_skb(rt, gs->sock->sk, skb, src, dst, tos, ttl, df, src_port, dst_port, xnet, !csum); } diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 6d364ab8e14e..4c2c3ba4ba65 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -782,7 +782,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, return; } - err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, protocol, + err = iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl, df, !net_eq(tunnel->net, dev_net(dev))); iptunnel_xmit_stats(err, &dev->stats, dev->tstats); diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c index c83b35485056..6bb98cc193c9 100644 --- a/net/ipv4/udp_tunnel.c +++ b/net/ipv4/udp_tunnel.c @@ -75,7 +75,7 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock, } EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock); -int udp_tunnel_xmit_skb(struct rtable *rt, struct sk_buff *skb, +int udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, bool xnet, bool nocheck) @@ -92,7 +92,7 @@ int udp_tunnel_xmit_skb(struct rtable *rt, struct sk_buff *skb, udp_set_csum(nocheck, skb, src, dst, skb->len); - return iptunnel_xmit(skb->sk, rt, skb, src, dst, IPPROTO_UDP, + return iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet); } EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb); diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index f724329d7436..b5e6cc1d4a73 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -760,7 +760,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, skb_set_inner_protocol(skb, protocol); - ip6tunnel_xmit(skb, dev); + ip6tunnel_xmit(NULL, skb, dev); if (ndst) ip6_tnl_dst_store(tunnel, ndst); return 0; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index b6a211a150b2..5cafd92c2312 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1100,7 +1100,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, ipv6h->nexthdr = proto; ipv6h->saddr = fl6->saddr; ipv6h->daddr = fl6->daddr; - ip6tunnel_xmit(skb, dev); + ip6tunnel_xmit(NULL, skb, dev); if (ndst) ip6_tnl_dst_store(t, ndst); return 0; diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index 32d9b268e7d8..bba8903e871f 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c @@ -62,7 +62,8 @@ error: } EXPORT_SYMBOL_GPL(udp_sock_create6); -int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, +int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, __be16 src_port, @@ -97,7 +98,7 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, ip6h->daddr = *daddr; ip6h->saddr = *saddr; - ip6tunnel_xmit(skb, dev); + ip6tunnel_xmit(sk, skb, dev); return 0; } EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb); diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 7d1131dc29fe..85892af57364 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -136,7 +136,7 @@ int ip6_dst_hoplimit(struct dst_entry *dst) EXPORT_SYMBOL(ip6_dst_hoplimit); #endif -int __ip6_local_out(struct sk_buff *skb) +static int __ip6_local_out_sk(struct sock *sk, struct sk_buff *skb) { int len; @@ -146,19 +146,30 @@ int __ip6_local_out(struct sk_buff *skb) ipv6_hdr(skb)->payload_len = htons(len); IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); - return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb->sk, skb, + return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb, NULL, skb_dst(skb)->dev, dst_output_sk); } + +int __ip6_local_out(struct sk_buff *skb) +{ + return __ip6_local_out_sk(skb->sk, skb); +} EXPORT_SYMBOL_GPL(__ip6_local_out); -int ip6_local_out(struct sk_buff *skb) +int ip6_local_out_sk(struct sock *sk, struct sk_buff *skb) { int err; - err = __ip6_local_out(skb); + err = __ip6_local_out_sk(sk, skb); if (likely(err == 1)) - err = dst_output(skb); + err = dst_output_sk(sk, skb); return err; } +EXPORT_SYMBOL_GPL(ip6_local_out_sk); + +int ip6_local_out(struct sk_buff *skb) +{ + return ip6_local_out_sk(skb->sk, skb); +} EXPORT_SYMBOL_GPL(ip6_local_out); diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 3277a7520e31..6d39766e7828 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -222,7 +222,8 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) { struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); - __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport; + struct sock *sk = vxlan_port->vs->sock->sk; + __be16 dst_port = inet_sk(sk)->inet_sport; const struct ovs_key_ipv4_tunnel *tun_key; struct vxlan_metadata md = {0}; struct rtable *rt; @@ -255,7 +256,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) vxflags = vxlan_port->exts | (tun_key->tun_flags & TUNNEL_CSUM ? VXLAN_F_UDP_CSUM : 0); - err = vxlan_xmit_skb(rt, skb, fl.saddr, tun_key->ipv4_dst, + err = vxlan_xmit_skb(rt, sk, skb, fl.saddr, tun_key->ipv4_dst, tun_key->ipv4_tos, tun_key->ipv4_ttl, df, src_port, dst_port, &md, false, vxflags); diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index ef3d7aa2854a..66deebc66aa1 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -176,7 +176,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, goto tx_error; } ttl = ip4_dst_hoplimit(&rt->dst); - err = udp_tunnel_xmit_skb(rt, clone, src->ipv4.s_addr, + err = udp_tunnel_xmit_skb(rt, ub->ubsock->sk, clone, + src->ipv4.s_addr, dst->ipv4.s_addr, 0, ttl, 0, src->udp_port, dst->udp_port, false, true); @@ -197,7 +198,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, if (err) goto tx_error; ttl = ip6_dst_hoplimit(ndst); - err = udp_tunnel6_xmit_skb(ndst, clone, ndst->dev, &src->ipv6, + err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, clone, + ndst->dev, &src->ipv6, &dst->ipv6, 0, ttl, src->udp_port, dst->udp_port, false); #endif From b111e4e1112316e800dd1f1debdf017d2cf940b2 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 7 Apr 2015 11:51:52 +0200 Subject: [PATCH 558/567] netns: minor cleanup in rtnl_net_getid() No need to initialize err, it will be overridden by the value of nlmsg_parse(). Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/net_namespace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index e7345d9031df..be28afccfbbb 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -565,8 +565,8 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh) struct net *net = sock_net(skb->sk); struct nlattr *tb[NETNSA_MAX + 1]; struct sk_buff *msg; - int err = -ENOBUFS; struct net *peer; + int err; err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, rtnl_net_policy); From 9a9634545c7051f567096117d417e9c3be24706d Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 7 Apr 2015 11:51:53 +0200 Subject: [PATCH 559/567] netns: notify netns id events With this patch, netns ids that are created and deleted are advertised into the group RTNLGRP_NSID. Because callers of rtnl_net_notifyid() already know the id of the peer, there is no need to call __peernet2id() in rtnl_net_fill(). Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- include/uapi/linux/rtnetlink.h | 4 +++ net/core/net_namespace.c | 52 ++++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index bea910f924dd..974db03f7b1a 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -134,6 +134,8 @@ enum { RTM_NEWNSID = 88, #define RTM_NEWNSID RTM_NEWNSID + RTM_DELNSID = 89, +#define RTM_DELNSID RTM_DELNSID RTM_GETNSID = 90, #define RTM_GETNSID RTM_GETNSID @@ -635,6 +637,8 @@ enum rtnetlink_groups { #define RTNLGRP_MDB RTNLGRP_MDB RTNLGRP_MPLS_ROUTE, #define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE + RTNLGRP_NSID, +#define RTNLGRP_NSID RTNLGRP_NSID __RTNLGRP_MAX }; #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index be28afccfbbb..b3b5f22f0e90 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -148,9 +148,11 @@ static void ops_free_list(const struct pernet_operations *ops, } } +static void rtnl_net_notifyid(struct net *net, struct net *peer, int cmd, + int id); static int alloc_netid(struct net *net, struct net *peer, int reqid) { - int min = 0, max = 0; + int min = 0, max = 0, id; ASSERT_RTNL(); @@ -159,7 +161,11 @@ static int alloc_netid(struct net *net, struct net *peer, int reqid) max = reqid + 1; } - return idr_alloc(&net->netns_ids, peer, min, max, GFP_KERNEL); + id = idr_alloc(&net->netns_ids, peer, min, max, GFP_KERNEL); + if (id >= 0) + rtnl_net_notifyid(net, peer, RTM_NEWNSID, id); + + return id; } /* This function is used by idr_for_each(). If net is equal to peer, the @@ -359,8 +365,10 @@ static void cleanup_net(struct work_struct *work) for_each_net(tmp) { int id = __peernet2id(tmp, net, false); - if (id >= 0) + if (id >= 0) { + rtnl_net_notifyid(tmp, net, RTM_DELNSID, id); idr_remove(&tmp->netns_ids, id); + } } idr_destroy(&net->netns_ids); @@ -531,7 +539,8 @@ static int rtnl_net_get_size(void) } static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags, - int cmd, struct net *net, struct net *peer) + int cmd, struct net *net, struct net *peer, + int nsid) { struct nlmsghdr *nlh; struct rtgenmsg *rth; @@ -546,9 +555,13 @@ static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags, rth = nlmsg_data(nlh); rth->rtgen_family = AF_UNSPEC; - id = __peernet2id(net, peer, false); - if (id < 0) - id = NETNSA_NSID_NOT_ASSIGNED; + if (nsid >= 0) { + id = nsid; + } else { + id = __peernet2id(net, peer, false); + if (id < 0) + id = NETNSA_NSID_NOT_ASSIGNED; + } if (nla_put_s32(skb, NETNSA_NSID, id)) goto nla_put_failure; @@ -589,7 +602,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh) } err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, - RTM_GETNSID, net, peer); + RTM_GETNSID, net, peer, -1); if (err < 0) goto err_out; @@ -603,6 +616,29 @@ out: return err; } +static void rtnl_net_notifyid(struct net *net, struct net *peer, int cmd, + int id) +{ + struct sk_buff *msg; + int err = -ENOMEM; + + msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL); + if (!msg) + goto out; + + err = rtnl_net_fill(msg, 0, 0, 0, cmd, net, peer, id); + if (err < 0) + goto err_out; + + rtnl_notify(msg, net, 0, RTNLGRP_NSID, NULL, 0); + return; + +err_out: + nlmsg_free(msg); +out: + rtnl_set_sk_err(net, RTNLGRP_NSID, err); +} + static int __init net_ns_init(void) { struct net_generic *ng; From a143c40c32bb8a6d6a556920646021d7e96d1f91 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 7 Apr 2015 11:51:54 +0200 Subject: [PATCH 560/567] netns: allow to dump netns ids Which this patch, it's possible to dump the list of ids allocated for peer netns. Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/core/net_namespace.c | 49 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index b3b5f22f0e90..a3abb719221f 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -616,6 +616,52 @@ out: return err; } +struct rtnl_net_dump_cb { + struct net *net; + struct sk_buff *skb; + struct netlink_callback *cb; + int idx; + int s_idx; +}; + +static int rtnl_net_dumpid_one(int id, void *peer, void *data) +{ + struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data; + int ret; + + if (net_cb->idx < net_cb->s_idx) + goto cont; + + ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid, + net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI, + RTM_NEWNSID, net_cb->net, peer, id); + if (ret < 0) + return ret; + +cont: + net_cb->idx++; + return 0; +} + +static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct rtnl_net_dump_cb net_cb = { + .net = net, + .skb = skb, + .cb = cb, + .idx = 0, + .s_idx = cb->args[0], + }; + + ASSERT_RTNL(); + + idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb); + + cb->args[0] = net_cb.idx; + return skb->len; +} + static void rtnl_net_notifyid(struct net *net, struct net *peer, int cmd, int id) { @@ -673,7 +719,8 @@ static int __init net_ns_init(void) register_pernet_subsys(&net_ns_ops); rtnl_register(PF_UNSPEC, RTM_NEWNSID, rtnl_net_newid, NULL, NULL); - rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, NULL, NULL); + rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, rtnl_net_dumpid, + NULL); return 0; } From 388069d30240e9524ad69ce6cc692fff2a5a7829 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 7 Apr 2015 12:10:16 +0200 Subject: [PATCH 561/567] netdevice.h: remove iflink description Also move 'group' description to match the order of the net_device structure. Fixes: 7a66bbc96ce9 ("net: remove iflink field from struct net_device") Reported-by: Fengguang Wu Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 45823db2efb0..bf6d9df34d7b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1328,7 +1328,7 @@ enum netdev_priv_flags { * @mpls_features: Mask of features inheritable by MPLS * * @ifindex: interface index - * @iflink: unique device identifier + * @group: The group, that the device belongs to * * @stats: Statistics struct, which was left as a legacy, use * rtnl_link_stats64 instead @@ -1488,7 +1488,6 @@ enum netdev_priv_flags { * * @qdisc_tx_busylock: XXX: need comments on this one * - * @group: The group, that the device belongs to * @pm_qos_req: Power Management QoS object * * FIXME: cleanup struct net_device such that network protocol info From 812034f11628aaaab0e2d7af1d3bc50a49eb396b Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 6 Apr 2015 20:23:23 +0530 Subject: [PATCH 562/567] cxgb4: Move ethtool related code to a separate file Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/Makefile | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 47 + .../ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 915 ++++++++++ .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 1618 +---------------- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 728 ++++++++ 5 files changed, 1702 insertions(+), 1608 deletions(-) create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index 07d9b68a4da2..ace0ab98d0f1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o -cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o +cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 6c80eb2e61f4..524d11098c56 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -59,6 +59,11 @@ enum { PN_LEN = 16, /* Part Number length */ }; +enum { + T4_REGMAP_SIZE = (160 * 1024), + T5_REGMAP_SIZE = (332 * 1024), +}; + enum { MEM_EDC0, MEM_EDC1, @@ -373,6 +378,17 @@ enum { MAX_ISCSI_QUEUES = NCHAN, /* # of streaming iSCSI Rx queues */ }; +enum { + MAX_TXQ_ENTRIES = 16384, + MAX_CTRL_TXQ_ENTRIES = 1024, + MAX_RSPQ_ENTRIES = 16384, + MAX_RX_BUFFERS = 16384, + MIN_TXQ_ENTRIES = 32, + MIN_CTRL_TXQ_ENTRIES = 32, + MIN_RSPQ_ENTRIES = 128, + MIN_FL_ENTRIES = 16 +}; + enum { INGQ_EXTRAS = 2, /* firmware event queue and */ /* forwarded interrupts */ @@ -1000,6 +1016,30 @@ static inline bool cxgb_poll_busy_polling(struct sge_rspq *q) } #endif /* CONFIG_NET_RX_BUSY_POLL */ +/* Return a version number to identify the type of adapter. The scheme is: + * - bits 0..9: chip version + * - bits 10..15: chip revision + * - bits 16..23: register dump version + */ +static inline unsigned int mk_adap_vers(struct adapter *ap) +{ + return CHELSIO_CHIP_VERSION(ap->params.chip) | + (CHELSIO_CHIP_RELEASE(ap->params.chip) << 10) | (1 << 16); +} + +/* Return a queue's interrupt hold-off time in us. 0 means no timer. */ +static inline unsigned int qtimer_val(const struct adapter *adap, + const struct sge_rspq *q) +{ + unsigned int idx = q->intr_params >> 1; + + return idx < SGE_NTIMERS ? adap->sge.timer_val[idx] : 0; +} + +/* driver version & name used for ethtool_drvinfo */ +extern char cxgb4_driver_name[]; +extern const char cxgb4_driver_version[]; + void t4_os_portmod_changed(const struct adapter *adap, int port_id); void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat); @@ -1029,6 +1069,10 @@ int t4_sge_init(struct adapter *adap); void t4_sge_start(struct adapter *adap); void t4_sge_stop(struct adapter *adap); int cxgb_busy_poll(struct napi_struct *napi); +int cxgb4_set_rspq_intr_params(struct sge_rspq *q, unsigned int us, + unsigned int cnt); +void cxgb4_set_ethtool_ops(struct net_device *netdev); +int cxgb4_write_rss(const struct port_info *pi, const u16 *queues); extern int dbfifo_int_thresh; #define for_each_port(adapter, iter) \ @@ -1117,6 +1161,9 @@ static inline int t4_memory_write(struct adapter *adap, int mtype, u32 addr, return t4_memory_rw(adap, 0, mtype, addr, len, buf, 0); } +unsigned int t4_get_regs_len(struct adapter *adapter); +void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size); + int t4_seeprom_wp(struct adapter *adapter, bool enable); int get_vpd_params(struct adapter *adapter, struct vpd_params *p); int t4_read_flash(struct adapter *adapter, unsigned int addr, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c new file mode 100644 index 000000000000..10d82b51d7ef --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -0,0 +1,915 @@ +/* + * Copyright (C) 2013-2015 Chelsio Communications. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#include +#include + +#include "cxgb4.h" +#include "t4_regs.h" +#include "t4fw_api.h" + +#define EEPROM_MAGIC 0x38E2F10C + +static u32 get_msglevel(struct net_device *dev) +{ + return netdev2adap(dev)->msg_enable; +} + +static void set_msglevel(struct net_device *dev, u32 val) +{ + netdev2adap(dev)->msg_enable = val; +} + +static const char stats_strings[][ETH_GSTRING_LEN] = { + "TxOctetsOK ", + "TxFramesOK ", + "TxBroadcastFrames ", + "TxMulticastFrames ", + "TxUnicastFrames ", + "TxErrorFrames ", + + "TxFrames64 ", + "TxFrames65To127 ", + "TxFrames128To255 ", + "TxFrames256To511 ", + "TxFrames512To1023 ", + "TxFrames1024To1518 ", + "TxFrames1519ToMax ", + + "TxFramesDropped ", + "TxPauseFrames ", + "TxPPP0Frames ", + "TxPPP1Frames ", + "TxPPP2Frames ", + "TxPPP3Frames ", + "TxPPP4Frames ", + "TxPPP5Frames ", + "TxPPP6Frames ", + "TxPPP7Frames ", + + "RxOctetsOK ", + "RxFramesOK ", + "RxBroadcastFrames ", + "RxMulticastFrames ", + "RxUnicastFrames ", + + "RxFramesTooLong ", + "RxJabberErrors ", + "RxFCSErrors ", + "RxLengthErrors ", + "RxSymbolErrors ", + "RxRuntFrames ", + + "RxFrames64 ", + "RxFrames65To127 ", + "RxFrames128To255 ", + "RxFrames256To511 ", + "RxFrames512To1023 ", + "RxFrames1024To1518 ", + "RxFrames1519ToMax ", + + "RxPauseFrames ", + "RxPPP0Frames ", + "RxPPP1Frames ", + "RxPPP2Frames ", + "RxPPP3Frames ", + "RxPPP4Frames ", + "RxPPP5Frames ", + "RxPPP6Frames ", + "RxPPP7Frames ", + + "RxBG0FramesDropped ", + "RxBG1FramesDropped ", + "RxBG2FramesDropped ", + "RxBG3FramesDropped ", + "RxBG0FramesTrunc ", + "RxBG1FramesTrunc ", + "RxBG2FramesTrunc ", + "RxBG3FramesTrunc ", + + "TSO ", + "TxCsumOffload ", + "RxCsumGood ", + "VLANextractions ", + "VLANinsertions ", + "GROpackets ", + "GROmerged ", + "WriteCoalSuccess ", + "WriteCoalFail ", +}; + +static int get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(stats_strings); + default: + return -EOPNOTSUPP; + } +} + +static int get_regs_len(struct net_device *dev) +{ + struct adapter *adap = netdev2adap(dev); + + return t4_get_regs_len(adap); +} + +static int get_eeprom_len(struct net_device *dev) +{ + return EEPROMSIZE; +} + +static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct adapter *adapter = netdev2adap(dev); + u32 exprom_vers; + + strlcpy(info->driver, cxgb4_driver_name, sizeof(info->driver)); + strlcpy(info->version, cxgb4_driver_version, + sizeof(info->version)); + strlcpy(info->bus_info, pci_name(adapter->pdev), + sizeof(info->bus_info)); + + if (adapter->params.fw_vers) + snprintf(info->fw_version, sizeof(info->fw_version), + "%u.%u.%u.%u, TP %u.%u.%u.%u", + FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers), + FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers), + FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers), + FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers), + FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers), + FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), + FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), + FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); + + if (!t4_get_exprom_version(adapter, &exprom_vers)) + snprintf(info->erom_version, sizeof(info->erom_version), + "%u.%u.%u.%u", + FW_HDR_FW_VER_MAJOR_G(exprom_vers), + FW_HDR_FW_VER_MINOR_G(exprom_vers), + FW_HDR_FW_VER_MICRO_G(exprom_vers), + FW_HDR_FW_VER_BUILD_G(exprom_vers)); +} + +static void get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, stats_strings, sizeof(stats_strings)); +} + +/* port stats maintained per queue of the port. They should be in the same + * order as in stats_strings above. + */ +struct queue_port_stats { + u64 tso; + u64 tx_csum; + u64 rx_csum; + u64 vlan_ex; + u64 vlan_ins; + u64 gro_pkts; + u64 gro_merged; +}; + +static void collect_sge_port_stats(const struct adapter *adap, + const struct port_info *p, + struct queue_port_stats *s) +{ + int i; + const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; + const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; + + memset(s, 0, sizeof(*s)); + for (i = 0; i < p->nqsets; i++, rx++, tx++) { + s->tso += tx->tso; + s->tx_csum += tx->tx_cso; + s->rx_csum += rx->stats.rx_cso; + s->vlan_ex += rx->stats.vlan_ex; + s->vlan_ins += tx->vlan_ins; + s->gro_pkts += rx->stats.lro_pkts; + s->gro_merged += rx->stats.lro_merged; + } +} + +static void get_stats(struct net_device *dev, struct ethtool_stats *stats, + u64 *data) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + u32 val1, val2; + + t4_get_port_stats(adapter, pi->tx_chan, (struct port_stats *)data); + + data += sizeof(struct port_stats) / sizeof(u64); + collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); + data += sizeof(struct queue_port_stats) / sizeof(u64); + if (!is_t4(adapter->params.chip)) { + t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7)); + val1 = t4_read_reg(adapter, SGE_STAT_TOTAL_A); + val2 = t4_read_reg(adapter, SGE_STAT_MATCH_A); + *data = val1 - val2; + data++; + *data = val2; + data++; + } else { + memset(data, 0, 2 * sizeof(u64)); + *data += 2; + } +} + +static void get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct adapter *adap = netdev2adap(dev); + size_t buf_size; + + buf_size = t4_get_regs_len(adap); + regs->version = mk_adap_vers(adap); + t4_get_regs(adap, buf, buf_size); +} + +static int restart_autoneg(struct net_device *dev) +{ + struct port_info *p = netdev_priv(dev); + + if (!netif_running(dev)) + return -EAGAIN; + if (p->link_cfg.autoneg != AUTONEG_ENABLE) + return -EINVAL; + t4_restart_aneg(p->adapter, p->adapter->fn, p->tx_chan); + return 0; +} + +static int identify_port(struct net_device *dev, + enum ethtool_phys_id_state state) +{ + unsigned int val; + struct adapter *adap = netdev2adap(dev); + + if (state == ETHTOOL_ID_ACTIVE) + val = 0xffff; + else if (state == ETHTOOL_ID_INACTIVE) + val = 0; + else + return -EINVAL; + + return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val); +} + +static unsigned int from_fw_linkcaps(enum fw_port_type type, unsigned int caps) +{ + unsigned int v = 0; + + if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || + type == FW_PORT_TYPE_BT_XAUI) { + v |= SUPPORTED_TP; + if (caps & FW_PORT_CAP_SPEED_100M) + v |= SUPPORTED_100baseT_Full; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { + v |= SUPPORTED_Backplane; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseKX_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseKX4_Full; + } else if (type == FW_PORT_TYPE_KR) { + v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; + } else if (type == FW_PORT_TYPE_BP_AP) { + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; + } else if (type == FW_PORT_TYPE_BP4_AP) { + v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | + SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | + SUPPORTED_10000baseKX4_Full; + } else if (type == FW_PORT_TYPE_FIBER_XFI || + type == FW_PORT_TYPE_FIBER_XAUI || + type == FW_PORT_TYPE_SFP || + type == FW_PORT_TYPE_QSFP_10G || + type == FW_PORT_TYPE_QSA) { + v |= SUPPORTED_FIBRE; + if (caps & FW_PORT_CAP_SPEED_1G) + v |= SUPPORTED_1000baseT_Full; + if (caps & FW_PORT_CAP_SPEED_10G) + v |= SUPPORTED_10000baseT_Full; + } else if (type == FW_PORT_TYPE_BP40_BA || + type == FW_PORT_TYPE_QSFP) { + v |= SUPPORTED_40000baseSR4_Full; + v |= SUPPORTED_FIBRE; + } + + if (caps & FW_PORT_CAP_ANEG) + v |= SUPPORTED_Autoneg; + return v; +} + +static unsigned int to_fw_linkcaps(unsigned int caps) +{ + unsigned int v = 0; + + if (caps & ADVERTISED_100baseT_Full) + v |= FW_PORT_CAP_SPEED_100M; + if (caps & ADVERTISED_1000baseT_Full) + v |= FW_PORT_CAP_SPEED_1G; + if (caps & ADVERTISED_10000baseT_Full) + v |= FW_PORT_CAP_SPEED_10G; + if (caps & ADVERTISED_40000baseSR4_Full) + v |= FW_PORT_CAP_SPEED_40G; + return v; +} + +static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + const struct port_info *p = netdev_priv(dev); + + if (p->port_type == FW_PORT_TYPE_BT_SGMII || + p->port_type == FW_PORT_TYPE_BT_XFI || + p->port_type == FW_PORT_TYPE_BT_XAUI) { + cmd->port = PORT_TP; + } else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || + p->port_type == FW_PORT_TYPE_FIBER_XAUI) { + cmd->port = PORT_FIBRE; + } else if (p->port_type == FW_PORT_TYPE_SFP || + p->port_type == FW_PORT_TYPE_QSFP_10G || + p->port_type == FW_PORT_TYPE_QSA || + p->port_type == FW_PORT_TYPE_QSFP) { + if (p->mod_type == FW_PORT_MOD_TYPE_LR || + p->mod_type == FW_PORT_MOD_TYPE_SR || + p->mod_type == FW_PORT_MOD_TYPE_ER || + p->mod_type == FW_PORT_MOD_TYPE_LRM) + cmd->port = PORT_FIBRE; + else if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || + p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) + cmd->port = PORT_DA; + else + cmd->port = PORT_OTHER; + } else { + cmd->port = PORT_OTHER; + } + + if (p->mdio_addr >= 0) { + cmd->phy_address = p->mdio_addr; + cmd->transceiver = XCVR_EXTERNAL; + cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? + MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; + } else { + cmd->phy_address = 0; /* not really, but no better option */ + cmd->transceiver = XCVR_INTERNAL; + cmd->mdio_support = 0; + } + + cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); + cmd->advertising = from_fw_linkcaps(p->port_type, + p->link_cfg.advertising); + ethtool_cmd_speed_set(cmd, + netif_carrier_ok(dev) ? p->link_cfg.speed : 0); + cmd->duplex = DUPLEX_FULL; + cmd->autoneg = p->link_cfg.autoneg; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static unsigned int speed_to_caps(int speed) +{ + if (speed == 100) + return FW_PORT_CAP_SPEED_100M; + if (speed == 1000) + return FW_PORT_CAP_SPEED_1G; + if (speed == 10000) + return FW_PORT_CAP_SPEED_10G; + if (speed == 40000) + return FW_PORT_CAP_SPEED_40G; + return 0; +} + +static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + unsigned int cap; + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_cfg; + u32 speed = ethtool_cmd_speed(cmd); + + if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ + return -EINVAL; + + if (!(lc->supported & FW_PORT_CAP_ANEG)) { + /* PHY offers a single speed. See if that's what's + * being requested. + */ + if (cmd->autoneg == AUTONEG_DISABLE && + (lc->supported & speed_to_caps(speed))) + return 0; + return -EINVAL; + } + + if (cmd->autoneg == AUTONEG_DISABLE) { + cap = speed_to_caps(speed); + + if (!(lc->supported & cap) || + (speed == 1000) || + (speed == 10000) || + (speed == 40000)) + return -EINVAL; + lc->requested_speed = cap; + lc->advertising = 0; + } else { + cap = to_fw_linkcaps(cmd->advertising); + if (!(lc->supported & cap)) + return -EINVAL; + lc->requested_speed = 0; + lc->advertising = cap | FW_PORT_CAP_ANEG; + } + lc->autoneg = cmd->autoneg; + + if (netif_running(dev)) + return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, + lc); + return 0; +} + +static void get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + + epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; + epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; + epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; +} + +static int set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_cfg; + + if (epause->autoneg == AUTONEG_DISABLE) + lc->requested_fc = 0; + else if (lc->supported & FW_PORT_CAP_ANEG) + lc->requested_fc = PAUSE_AUTONEG; + else + return -EINVAL; + + if (epause->rx_pause) + lc->requested_fc |= PAUSE_RX; + if (epause->tx_pause) + lc->requested_fc |= PAUSE_TX; + if (netif_running(dev)) + return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, + lc); + return 0; +} + +static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + const struct port_info *pi = netdev_priv(dev); + const struct sge *s = &pi->adapter->sge; + + e->rx_max_pending = MAX_RX_BUFFERS; + e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; + e->rx_jumbo_max_pending = 0; + e->tx_max_pending = MAX_TXQ_ENTRIES; + + e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; + e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; + e->rx_jumbo_pending = 0; + e->tx_pending = s->ethtxq[pi->first_qset].q.size; +} + +static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + int i; + const struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + struct sge *s = &adapter->sge; + + if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || + e->tx_pending > MAX_TXQ_ENTRIES || + e->rx_mini_pending > MAX_RSPQ_ENTRIES || + e->rx_mini_pending < MIN_RSPQ_ENTRIES || + e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) + return -EINVAL; + + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + + for (i = 0; i < pi->nqsets; ++i) { + s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; + s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; + s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; + } + return 0; +} + +/** + * set_rx_intr_params - set a net devices's RX interrupt holdoff paramete! + * @dev: the network device + * @us: the hold-off time in us, or 0 to disable timer + * @cnt: the hold-off packet count, or 0 to disable counter + * + * Set the RX interrupt hold-off parameters for a network device. + */ +static int set_rx_intr_params(struct net_device *dev, + unsigned int us, unsigned int cnt) +{ + int i, err; + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; + + for (i = 0; i < pi->nqsets; i++, q++) { + err = cxgb4_set_rspq_intr_params(&q->rspq, us, cnt); + if (err) + return err; + } + return 0; +} + +static int set_adaptive_rx_setting(struct net_device *dev, int adaptive_rx) +{ + int i; + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; + + for (i = 0; i < pi->nqsets; i++, q++) + q->rspq.adaptive_rx = adaptive_rx; + + return 0; +} + +static int get_adaptive_rx_setting(struct net_device *dev) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adap = pi->adapter; + struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; + + return q->rspq.adaptive_rx; +} + +static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + set_adaptive_rx_setting(dev, c->use_adaptive_rx_coalesce); + return set_rx_intr_params(dev, c->rx_coalesce_usecs, + c->rx_max_coalesced_frames); +} + +static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + const struct port_info *pi = netdev_priv(dev); + const struct adapter *adap = pi->adapter; + const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; + + c->rx_coalesce_usecs = qtimer_val(adap, rq); + c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN) ? + adap->sge.counter_val[rq->pktcnt_idx] : 0; + c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev); + return 0; +} + +/** + * eeprom_ptov - translate a physical EEPROM address to virtual + * @phys_addr: the physical EEPROM address + * @fn: the PCI function number + * @sz: size of function-specific area + * + * Translate a physical EEPROM address to virtual. The first 1K is + * accessed through virtual addresses starting at 31K, the rest is + * accessed through virtual addresses starting at 0. + * + * The mapping is as follows: + * [0..1K) -> [31K..32K) + * [1K..1K+A) -> [31K-A..31K) + * [1K+A..ES) -> [0..ES-A-1K) + * + * where A = @fn * @sz, and ES = EEPROM size. + */ +static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz) +{ + fn *= sz; + if (phys_addr < 1024) + return phys_addr + (31 << 10); + if (phys_addr < 1024 + fn) + return 31744 - fn + phys_addr - 1024; + if (phys_addr < EEPROMSIZE) + return phys_addr - 1024 - fn; + return -EINVAL; +} + +/* The next two routines implement eeprom read/write from physical addresses. + */ +static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) +{ + int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); + + if (vaddr >= 0) + vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); + return vaddr < 0 ? vaddr : 0; +} + +static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) +{ + int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); + + if (vaddr >= 0) + vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); + return vaddr < 0 ? vaddr : 0; +} + +#define EEPROM_MAGIC 0x38E2F10C + +static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, + u8 *data) +{ + int i, err = 0; + struct adapter *adapter = netdev2adap(dev); + u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + e->magic = EEPROM_MAGIC; + for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) + err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); + + if (!err) + memcpy(data, buf + e->offset, e->len); + kfree(buf); + return err; +} + +static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 *data) +{ + u8 *buf; + int err = 0; + u32 aligned_offset, aligned_len, *p; + struct adapter *adapter = netdev2adap(dev); + + if (eeprom->magic != EEPROM_MAGIC) + return -EINVAL; + + aligned_offset = eeprom->offset & ~3; + aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; + + if (adapter->fn > 0) { + u32 start = 1024 + adapter->fn * EEPROMPFSIZE; + + if (aligned_offset < start || + aligned_offset + aligned_len > start + EEPROMPFSIZE) + return -EPERM; + } + + if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { + /* RMW possibly needed for first or last words. + */ + buf = kmalloc(aligned_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); + if (!err && aligned_len > 4) + err = eeprom_rd_phys(adapter, + aligned_offset + aligned_len - 4, + (u32 *)&buf[aligned_len - 4]); + if (err) + goto out; + memcpy(buf + (eeprom->offset & 3), data, eeprom->len); + } else { + buf = data; + } + + err = t4_seeprom_wp(adapter, false); + if (err) + goto out; + + for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { + err = eeprom_wr_phys(adapter, aligned_offset, *p); + aligned_offset += 4; + } + + if (!err) + err = t4_seeprom_wp(adapter, true); +out: + if (buf != data) + kfree(buf); + return err; +} + +static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) +{ + int ret; + const struct firmware *fw; + struct adapter *adap = netdev2adap(netdev); + unsigned int mbox = PCIE_FW_MASTER_M + 1; + + ef->data[sizeof(ef->data) - 1] = '\0'; + ret = request_firmware(&fw, ef->data, adap->pdev_dev); + if (ret < 0) + return ret; + + /* If the adapter has been fully initialized then we'll go ahead and + * try to get the firmware's cooperation in upgrading to the new + * firmware image otherwise we'll try to do the entire job from the + * host ... and we always "force" the operation in this path. + */ + if (adap->flags & FULL_INIT_DONE) + mbox = adap->mbox; + + ret = t4_fw_upgrade(adap, mbox, fw->data, fw->size, 1); + release_firmware(fw); + if (!ret) + dev_info(adap->pdev_dev, + "loaded firmware %s, reload cxgb4 driver\n", ef->data); + return ret; +} + +#define WOL_SUPPORTED (WAKE_BCAST | WAKE_MAGIC) +#define BCAST_CRC 0xa0ccc1a6 + +static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + wol->supported = WAKE_BCAST | WAKE_MAGIC; + wol->wolopts = netdev2adap(dev)->wol; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + int err = 0; + struct port_info *pi = netdev_priv(dev); + + if (wol->wolopts & ~WOL_SUPPORTED) + return -EINVAL; + t4_wol_magic_enable(pi->adapter, pi->tx_chan, + (wol->wolopts & WAKE_MAGIC) ? dev->dev_addr : NULL); + if (wol->wolopts & WAKE_BCAST) { + err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0xfe, ~0ULL, + ~0ULL, 0, false); + if (!err) + err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 1, + ~6ULL, ~0ULL, BCAST_CRC, true); + } else { + t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0, 0, 0, 0, false); + } + return err; +} + +static u32 get_rss_table_size(struct net_device *dev) +{ + const struct port_info *pi = netdev_priv(dev); + + return pi->rss_size; +} + +static int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc) +{ + const struct port_info *pi = netdev_priv(dev); + unsigned int n = pi->rss_size; + + if (hfunc) + *hfunc = ETH_RSS_HASH_TOP; + if (!p) + return 0; + while (n--) + p[n] = pi->rss[n]; + return 0; +} + +static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key, + const u8 hfunc) +{ + unsigned int i; + struct port_info *pi = netdev_priv(dev); + + /* We require at least one supported parameter to be changed and no + * change in any of the unsupported parameters + */ + if (key || + (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) + return -EOPNOTSUPP; + if (!p) + return 0; + + for (i = 0; i < pi->rss_size; i++) + pi->rss[i] = p[i]; + if (pi->adapter->flags & FULL_INIT_DONE) + return cxgb4_write_rss(pi, pi->rss); + return 0; +} + +static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, + u32 *rules) +{ + const struct port_info *pi = netdev_priv(dev); + + switch (info->cmd) { + case ETHTOOL_GRXFH: { + unsigned int v = pi->rss_mode; + + info->data = 0; + switch (info->flow_type) { + case TCP_V4_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case UDP_V4_FLOW: + if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) && + (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case SCTP_V4_FLOW: + case AH_ESP_V4_FLOW: + case IPV4_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case TCP_V6_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case UDP_V6_FLOW: + if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) && + (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) + info->data = RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3; + else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + case SCTP_V6_FLOW: + case AH_ESP_V6_FLOW: + case IPV6_FLOW: + if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) + info->data = RXH_IP_SRC | RXH_IP_DST; + break; + } + return 0; + } + case ETHTOOL_GRXRINGS: + info->data = pi->nqsets; + return 0; + } + return -EOPNOTSUPP; +} + +static const struct ethtool_ops cxgb_ethtool_ops = { + .get_settings = get_settings, + .set_settings = set_settings, + .get_drvinfo = get_drvinfo, + .get_msglevel = get_msglevel, + .set_msglevel = set_msglevel, + .get_ringparam = get_sge_param, + .set_ringparam = set_sge_param, + .get_coalesce = get_coalesce, + .set_coalesce = set_coalesce, + .get_eeprom_len = get_eeprom_len, + .get_eeprom = get_eeprom, + .set_eeprom = set_eeprom, + .get_pauseparam = get_pauseparam, + .set_pauseparam = set_pauseparam, + .get_link = ethtool_op_get_link, + .get_strings = get_strings, + .set_phys_id = identify_port, + .nway_reset = restart_autoneg, + .get_sset_count = get_sset_count, + .get_ethtool_stats = get_stats, + .get_regs_len = get_regs_len, + .get_regs = get_regs, + .get_wol = get_wol, + .set_wol = set_wol, + .get_rxnfc = get_rxnfc, + .get_rxfh_indir_size = get_rss_table_size, + .get_rxfh = get_rss_table, + .set_rxfh = set_rss_table, + .flash_device = set_flash, +}; + +void cxgb4_set_ethtool_ops(struct net_device *netdev) +{ + netdev->ethtool_ops = &cxgb_ethtool_ops; +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 58c537f16763..24e10ea3d5ef 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -76,23 +76,15 @@ #include "clip_tbl.h" #include "l2t.h" +char cxgb4_driver_name[] = KBUILD_MODNAME; + #ifdef DRV_VERSION #undef DRV_VERSION #endif #define DRV_VERSION "2.0.0-ko" +const char cxgb4_driver_version[] = DRV_VERSION; #define DRV_DESC "Chelsio T4/T5 Network Driver" -enum { - MAX_TXQ_ENTRIES = 16384, - MAX_CTRL_TXQ_ENTRIES = 1024, - MAX_RSPQ_ENTRIES = 16384, - MAX_RX_BUFFERS = 16384, - MIN_TXQ_ENTRIES = 32, - MIN_CTRL_TXQ_ENTRIES = 32, - MIN_RSPQ_ENTRIES = 128, - MIN_FL_ENTRIES = 16 -}; - /* Host shadow copy of ingress filter entry. This is in host native format * and doesn't match the ordering or bit order, etc. of the hardware of the * firmware command. The use of bit-field structure elements is purely to @@ -857,14 +849,14 @@ static void free_msix_queue_irqs(struct adapter *adap) } /** - * write_rss - write the RSS table for a given port + * cxgb4_write_rss - write the RSS table for a given port * @pi: the port * @queues: array of queue indices for RSS * * Sets up the portion of the HW RSS table for the port's VI to distribute * packets to the Rx queues in @queues. */ -static int write_rss(const struct port_info *pi, const u16 *queues) +int cxgb4_write_rss(const struct port_info *pi, const u16 *queues) { u16 *rss; int i, err; @@ -897,7 +889,7 @@ static int setup_rss(struct adapter *adap) for_each_port(adap, i) { const struct port_info *pi = adap2pinfo(adap, i); - err = write_rss(pi, pi->rss); + err = cxgb4_write_rss(pi, pi->rss); if (err) return err; } @@ -1327,1192 +1319,6 @@ static inline int is_offload(const struct adapter *adap) return adap->params.offload; } -/* - * Implementation of ethtool operations. - */ - -static u32 get_msglevel(struct net_device *dev) -{ - return netdev2adap(dev)->msg_enable; -} - -static void set_msglevel(struct net_device *dev, u32 val) -{ - netdev2adap(dev)->msg_enable = val; -} - -static char stats_strings[][ETH_GSTRING_LEN] = { - "TxOctetsOK ", - "TxFramesOK ", - "TxBroadcastFrames ", - "TxMulticastFrames ", - "TxUnicastFrames ", - "TxErrorFrames ", - - "TxFrames64 ", - "TxFrames65To127 ", - "TxFrames128To255 ", - "TxFrames256To511 ", - "TxFrames512To1023 ", - "TxFrames1024To1518 ", - "TxFrames1519ToMax ", - - "TxFramesDropped ", - "TxPauseFrames ", - "TxPPP0Frames ", - "TxPPP1Frames ", - "TxPPP2Frames ", - "TxPPP3Frames ", - "TxPPP4Frames ", - "TxPPP5Frames ", - "TxPPP6Frames ", - "TxPPP7Frames ", - - "RxOctetsOK ", - "RxFramesOK ", - "RxBroadcastFrames ", - "RxMulticastFrames ", - "RxUnicastFrames ", - - "RxFramesTooLong ", - "RxJabberErrors ", - "RxFCSErrors ", - "RxLengthErrors ", - "RxSymbolErrors ", - "RxRuntFrames ", - - "RxFrames64 ", - "RxFrames65To127 ", - "RxFrames128To255 ", - "RxFrames256To511 ", - "RxFrames512To1023 ", - "RxFrames1024To1518 ", - "RxFrames1519ToMax ", - - "RxPauseFrames ", - "RxPPP0Frames ", - "RxPPP1Frames ", - "RxPPP2Frames ", - "RxPPP3Frames ", - "RxPPP4Frames ", - "RxPPP5Frames ", - "RxPPP6Frames ", - "RxPPP7Frames ", - - "RxBG0FramesDropped ", - "RxBG1FramesDropped ", - "RxBG2FramesDropped ", - "RxBG3FramesDropped ", - "RxBG0FramesTrunc ", - "RxBG1FramesTrunc ", - "RxBG2FramesTrunc ", - "RxBG3FramesTrunc ", - - "TSO ", - "TxCsumOffload ", - "RxCsumGood ", - "VLANextractions ", - "VLANinsertions ", - "GROpackets ", - "GROmerged ", - "WriteCoalSuccess ", - "WriteCoalFail ", -}; - -static int get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(stats_strings); - default: - return -EOPNOTSUPP; - } -} - -#define T4_REGMAP_SIZE (160 * 1024) -#define T5_REGMAP_SIZE (332 * 1024) - -static int get_regs_len(struct net_device *dev) -{ - struct adapter *adap = netdev2adap(dev); - if (is_t4(adap->params.chip)) - return T4_REGMAP_SIZE; - else - return T5_REGMAP_SIZE; -} - -static int get_eeprom_len(struct net_device *dev) -{ - return EEPROMSIZE; -} - -static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct adapter *adapter = netdev2adap(dev); - u32 exprom_vers; - - strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, pci_name(adapter->pdev), - sizeof(info->bus_info)); - - if (adapter->params.fw_vers) - snprintf(info->fw_version, sizeof(info->fw_version), - "%u.%u.%u.%u, TP %u.%u.%u.%u", - FW_HDR_FW_VER_MAJOR_G(adapter->params.fw_vers), - FW_HDR_FW_VER_MINOR_G(adapter->params.fw_vers), - FW_HDR_FW_VER_MICRO_G(adapter->params.fw_vers), - FW_HDR_FW_VER_BUILD_G(adapter->params.fw_vers), - FW_HDR_FW_VER_MAJOR_G(adapter->params.tp_vers), - FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers), - FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers), - FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers)); - - if (!t4_get_exprom_version(adapter, &exprom_vers)) - snprintf(info->erom_version, sizeof(info->erom_version), - "%u.%u.%u.%u", - FW_HDR_FW_VER_MAJOR_G(exprom_vers), - FW_HDR_FW_VER_MINOR_G(exprom_vers), - FW_HDR_FW_VER_MICRO_G(exprom_vers), - FW_HDR_FW_VER_BUILD_G(exprom_vers)); -} - -static void get_strings(struct net_device *dev, u32 stringset, u8 *data) -{ - if (stringset == ETH_SS_STATS) - memcpy(data, stats_strings, sizeof(stats_strings)); -} - -/* - * port stats maintained per queue of the port. They should be in the same - * order as in stats_strings above. - */ -struct queue_port_stats { - u64 tso; - u64 tx_csum; - u64 rx_csum; - u64 vlan_ex; - u64 vlan_ins; - u64 gro_pkts; - u64 gro_merged; -}; - -static void collect_sge_port_stats(const struct adapter *adap, - const struct port_info *p, struct queue_port_stats *s) -{ - int i; - const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; - const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; - - memset(s, 0, sizeof(*s)); - for (i = 0; i < p->nqsets; i++, rx++, tx++) { - s->tso += tx->tso; - s->tx_csum += tx->tx_cso; - s->rx_csum += rx->stats.rx_cso; - s->vlan_ex += rx->stats.vlan_ex; - s->vlan_ins += tx->vlan_ins; - s->gro_pkts += rx->stats.lro_pkts; - s->gro_merged += rx->stats.lro_merged; - } -} - -static void get_stats(struct net_device *dev, struct ethtool_stats *stats, - u64 *data) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - u32 val1, val2; - - t4_get_port_stats(adapter, pi->tx_chan, (struct port_stats *)data); - - data += sizeof(struct port_stats) / sizeof(u64); - collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data); - data += sizeof(struct queue_port_stats) / sizeof(u64); - if (!is_t4(adapter->params.chip)) { - t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7)); - val1 = t4_read_reg(adapter, SGE_STAT_TOTAL_A); - val2 = t4_read_reg(adapter, SGE_STAT_MATCH_A); - *data = val1 - val2; - data++; - *data = val2; - data++; - } else { - memset(data, 0, 2 * sizeof(u64)); - *data += 2; - } -} - -/* - * Return a version number to identify the type of adapter. The scheme is: - * - bits 0..9: chip version - * - bits 10..15: chip revision - * - bits 16..23: register dump version - */ -static inline unsigned int mk_adap_vers(const struct adapter *ap) -{ - return CHELSIO_CHIP_VERSION(ap->params.chip) | - (CHELSIO_CHIP_RELEASE(ap->params.chip) << 10) | (1 << 16); -} - -static void reg_block_dump(struct adapter *ap, void *buf, unsigned int start, - unsigned int end) -{ - u32 *p = buf + start; - - for ( ; start <= end; start += sizeof(u32)) - *p++ = t4_read_reg(ap, start); -} - -static void get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *buf) -{ - static const unsigned int t4_reg_ranges[] = { - 0x1008, 0x1108, - 0x1180, 0x11b4, - 0x11fc, 0x123c, - 0x1300, 0x173c, - 0x1800, 0x18fc, - 0x3000, 0x30d8, - 0x30e0, 0x5924, - 0x5960, 0x59d4, - 0x5a00, 0x5af8, - 0x6000, 0x6098, - 0x6100, 0x6150, - 0x6200, 0x6208, - 0x6240, 0x6248, - 0x6280, 0x6338, - 0x6370, 0x638c, - 0x6400, 0x643c, - 0x6500, 0x6524, - 0x6a00, 0x6a38, - 0x6a60, 0x6a78, - 0x6b00, 0x6b84, - 0x6bf0, 0x6c84, - 0x6cf0, 0x6d84, - 0x6df0, 0x6e84, - 0x6ef0, 0x6f84, - 0x6ff0, 0x7084, - 0x70f0, 0x7184, - 0x71f0, 0x7284, - 0x72f0, 0x7384, - 0x73f0, 0x7450, - 0x7500, 0x7530, - 0x7600, 0x761c, - 0x7680, 0x76cc, - 0x7700, 0x7798, - 0x77c0, 0x77fc, - 0x7900, 0x79fc, - 0x7b00, 0x7c38, - 0x7d00, 0x7efc, - 0x8dc0, 0x8e1c, - 0x8e30, 0x8e78, - 0x8ea0, 0x8f6c, - 0x8fc0, 0x9074, - 0x90fc, 0x90fc, - 0x9400, 0x9458, - 0x9600, 0x96bc, - 0x9800, 0x9808, - 0x9820, 0x983c, - 0x9850, 0x9864, - 0x9c00, 0x9c6c, - 0x9c80, 0x9cec, - 0x9d00, 0x9d6c, - 0x9d80, 0x9dec, - 0x9e00, 0x9e6c, - 0x9e80, 0x9eec, - 0x9f00, 0x9f6c, - 0x9f80, 0x9fec, - 0xd004, 0xd03c, - 0xdfc0, 0xdfe0, - 0xe000, 0xea7c, - 0xf000, 0x11110, - 0x11118, 0x11190, - 0x19040, 0x1906c, - 0x19078, 0x19080, - 0x1908c, 0x19124, - 0x19150, 0x191b0, - 0x191d0, 0x191e8, - 0x19238, 0x1924c, - 0x193f8, 0x19474, - 0x19490, 0x194f8, - 0x19800, 0x19f30, - 0x1a000, 0x1a06c, - 0x1a0b0, 0x1a120, - 0x1a128, 0x1a138, - 0x1a190, 0x1a1c4, - 0x1a1fc, 0x1a1fc, - 0x1e040, 0x1e04c, - 0x1e284, 0x1e28c, - 0x1e2c0, 0x1e2c0, - 0x1e2e0, 0x1e2e0, - 0x1e300, 0x1e384, - 0x1e3c0, 0x1e3c8, - 0x1e440, 0x1e44c, - 0x1e684, 0x1e68c, - 0x1e6c0, 0x1e6c0, - 0x1e6e0, 0x1e6e0, - 0x1e700, 0x1e784, - 0x1e7c0, 0x1e7c8, - 0x1e840, 0x1e84c, - 0x1ea84, 0x1ea8c, - 0x1eac0, 0x1eac0, - 0x1eae0, 0x1eae0, - 0x1eb00, 0x1eb84, - 0x1ebc0, 0x1ebc8, - 0x1ec40, 0x1ec4c, - 0x1ee84, 0x1ee8c, - 0x1eec0, 0x1eec0, - 0x1eee0, 0x1eee0, - 0x1ef00, 0x1ef84, - 0x1efc0, 0x1efc8, - 0x1f040, 0x1f04c, - 0x1f284, 0x1f28c, - 0x1f2c0, 0x1f2c0, - 0x1f2e0, 0x1f2e0, - 0x1f300, 0x1f384, - 0x1f3c0, 0x1f3c8, - 0x1f440, 0x1f44c, - 0x1f684, 0x1f68c, - 0x1f6c0, 0x1f6c0, - 0x1f6e0, 0x1f6e0, - 0x1f700, 0x1f784, - 0x1f7c0, 0x1f7c8, - 0x1f840, 0x1f84c, - 0x1fa84, 0x1fa8c, - 0x1fac0, 0x1fac0, - 0x1fae0, 0x1fae0, - 0x1fb00, 0x1fb84, - 0x1fbc0, 0x1fbc8, - 0x1fc40, 0x1fc4c, - 0x1fe84, 0x1fe8c, - 0x1fec0, 0x1fec0, - 0x1fee0, 0x1fee0, - 0x1ff00, 0x1ff84, - 0x1ffc0, 0x1ffc8, - 0x20000, 0x2002c, - 0x20100, 0x2013c, - 0x20190, 0x201c8, - 0x20200, 0x20318, - 0x20400, 0x20528, - 0x20540, 0x20614, - 0x21000, 0x21040, - 0x2104c, 0x21060, - 0x210c0, 0x210ec, - 0x21200, 0x21268, - 0x21270, 0x21284, - 0x212fc, 0x21388, - 0x21400, 0x21404, - 0x21500, 0x21518, - 0x2152c, 0x2153c, - 0x21550, 0x21554, - 0x21600, 0x21600, - 0x21608, 0x21628, - 0x21630, 0x2163c, - 0x21700, 0x2171c, - 0x21780, 0x2178c, - 0x21800, 0x21c38, - 0x21c80, 0x21d7c, - 0x21e00, 0x21e04, - 0x22000, 0x2202c, - 0x22100, 0x2213c, - 0x22190, 0x221c8, - 0x22200, 0x22318, - 0x22400, 0x22528, - 0x22540, 0x22614, - 0x23000, 0x23040, - 0x2304c, 0x23060, - 0x230c0, 0x230ec, - 0x23200, 0x23268, - 0x23270, 0x23284, - 0x232fc, 0x23388, - 0x23400, 0x23404, - 0x23500, 0x23518, - 0x2352c, 0x2353c, - 0x23550, 0x23554, - 0x23600, 0x23600, - 0x23608, 0x23628, - 0x23630, 0x2363c, - 0x23700, 0x2371c, - 0x23780, 0x2378c, - 0x23800, 0x23c38, - 0x23c80, 0x23d7c, - 0x23e00, 0x23e04, - 0x24000, 0x2402c, - 0x24100, 0x2413c, - 0x24190, 0x241c8, - 0x24200, 0x24318, - 0x24400, 0x24528, - 0x24540, 0x24614, - 0x25000, 0x25040, - 0x2504c, 0x25060, - 0x250c0, 0x250ec, - 0x25200, 0x25268, - 0x25270, 0x25284, - 0x252fc, 0x25388, - 0x25400, 0x25404, - 0x25500, 0x25518, - 0x2552c, 0x2553c, - 0x25550, 0x25554, - 0x25600, 0x25600, - 0x25608, 0x25628, - 0x25630, 0x2563c, - 0x25700, 0x2571c, - 0x25780, 0x2578c, - 0x25800, 0x25c38, - 0x25c80, 0x25d7c, - 0x25e00, 0x25e04, - 0x26000, 0x2602c, - 0x26100, 0x2613c, - 0x26190, 0x261c8, - 0x26200, 0x26318, - 0x26400, 0x26528, - 0x26540, 0x26614, - 0x27000, 0x27040, - 0x2704c, 0x27060, - 0x270c0, 0x270ec, - 0x27200, 0x27268, - 0x27270, 0x27284, - 0x272fc, 0x27388, - 0x27400, 0x27404, - 0x27500, 0x27518, - 0x2752c, 0x2753c, - 0x27550, 0x27554, - 0x27600, 0x27600, - 0x27608, 0x27628, - 0x27630, 0x2763c, - 0x27700, 0x2771c, - 0x27780, 0x2778c, - 0x27800, 0x27c38, - 0x27c80, 0x27d7c, - 0x27e00, 0x27e04 - }; - - static const unsigned int t5_reg_ranges[] = { - 0x1008, 0x1148, - 0x1180, 0x11b4, - 0x11fc, 0x123c, - 0x1280, 0x173c, - 0x1800, 0x18fc, - 0x3000, 0x3028, - 0x3060, 0x30d8, - 0x30e0, 0x30fc, - 0x3140, 0x357c, - 0x35a8, 0x35cc, - 0x35ec, 0x35ec, - 0x3600, 0x5624, - 0x56cc, 0x575c, - 0x580c, 0x5814, - 0x5890, 0x58bc, - 0x5940, 0x59dc, - 0x59fc, 0x5a18, - 0x5a60, 0x5a9c, - 0x5b9c, 0x5bfc, - 0x6000, 0x6040, - 0x6058, 0x614c, - 0x7700, 0x7798, - 0x77c0, 0x78fc, - 0x7b00, 0x7c54, - 0x7d00, 0x7efc, - 0x8dc0, 0x8de0, - 0x8df8, 0x8e84, - 0x8ea0, 0x8f84, - 0x8fc0, 0x90f8, - 0x9400, 0x9470, - 0x9600, 0x96f4, - 0x9800, 0x9808, - 0x9820, 0x983c, - 0x9850, 0x9864, - 0x9c00, 0x9c6c, - 0x9c80, 0x9cec, - 0x9d00, 0x9d6c, - 0x9d80, 0x9dec, - 0x9e00, 0x9e6c, - 0x9e80, 0x9eec, - 0x9f00, 0x9f6c, - 0x9f80, 0xa020, - 0xd004, 0xd03c, - 0xdfc0, 0xdfe0, - 0xe000, 0x11088, - 0x1109c, 0x11110, - 0x11118, 0x1117c, - 0x11190, 0x11204, - 0x19040, 0x1906c, - 0x19078, 0x19080, - 0x1908c, 0x19124, - 0x19150, 0x191b0, - 0x191d0, 0x191e8, - 0x19238, 0x19290, - 0x193f8, 0x19474, - 0x19490, 0x194cc, - 0x194f0, 0x194f8, - 0x19c00, 0x19c60, - 0x19c94, 0x19e10, - 0x19e50, 0x19f34, - 0x19f40, 0x19f50, - 0x19f90, 0x19fe4, - 0x1a000, 0x1a06c, - 0x1a0b0, 0x1a120, - 0x1a128, 0x1a138, - 0x1a190, 0x1a1c4, - 0x1a1fc, 0x1a1fc, - 0x1e008, 0x1e00c, - 0x1e040, 0x1e04c, - 0x1e284, 0x1e290, - 0x1e2c0, 0x1e2c0, - 0x1e2e0, 0x1e2e0, - 0x1e300, 0x1e384, - 0x1e3c0, 0x1e3c8, - 0x1e408, 0x1e40c, - 0x1e440, 0x1e44c, - 0x1e684, 0x1e690, - 0x1e6c0, 0x1e6c0, - 0x1e6e0, 0x1e6e0, - 0x1e700, 0x1e784, - 0x1e7c0, 0x1e7c8, - 0x1e808, 0x1e80c, - 0x1e840, 0x1e84c, - 0x1ea84, 0x1ea90, - 0x1eac0, 0x1eac0, - 0x1eae0, 0x1eae0, - 0x1eb00, 0x1eb84, - 0x1ebc0, 0x1ebc8, - 0x1ec08, 0x1ec0c, - 0x1ec40, 0x1ec4c, - 0x1ee84, 0x1ee90, - 0x1eec0, 0x1eec0, - 0x1eee0, 0x1eee0, - 0x1ef00, 0x1ef84, - 0x1efc0, 0x1efc8, - 0x1f008, 0x1f00c, - 0x1f040, 0x1f04c, - 0x1f284, 0x1f290, - 0x1f2c0, 0x1f2c0, - 0x1f2e0, 0x1f2e0, - 0x1f300, 0x1f384, - 0x1f3c0, 0x1f3c8, - 0x1f408, 0x1f40c, - 0x1f440, 0x1f44c, - 0x1f684, 0x1f690, - 0x1f6c0, 0x1f6c0, - 0x1f6e0, 0x1f6e0, - 0x1f700, 0x1f784, - 0x1f7c0, 0x1f7c8, - 0x1f808, 0x1f80c, - 0x1f840, 0x1f84c, - 0x1fa84, 0x1fa90, - 0x1fac0, 0x1fac0, - 0x1fae0, 0x1fae0, - 0x1fb00, 0x1fb84, - 0x1fbc0, 0x1fbc8, - 0x1fc08, 0x1fc0c, - 0x1fc40, 0x1fc4c, - 0x1fe84, 0x1fe90, - 0x1fec0, 0x1fec0, - 0x1fee0, 0x1fee0, - 0x1ff00, 0x1ff84, - 0x1ffc0, 0x1ffc8, - 0x30000, 0x30030, - 0x30100, 0x30144, - 0x30190, 0x301d0, - 0x30200, 0x30318, - 0x30400, 0x3052c, - 0x30540, 0x3061c, - 0x30800, 0x30834, - 0x308c0, 0x30908, - 0x30910, 0x309ac, - 0x30a00, 0x30a04, - 0x30a0c, 0x30a2c, - 0x30a44, 0x30a50, - 0x30a74, 0x30c24, - 0x30d08, 0x30d14, - 0x30d1c, 0x30d20, - 0x30d3c, 0x30d50, - 0x31200, 0x3120c, - 0x31220, 0x31220, - 0x31240, 0x31240, - 0x31600, 0x31600, - 0x31608, 0x3160c, - 0x31a00, 0x31a1c, - 0x31e04, 0x31e20, - 0x31e38, 0x31e3c, - 0x31e80, 0x31e80, - 0x31e88, 0x31ea8, - 0x31eb0, 0x31eb4, - 0x31ec8, 0x31ed4, - 0x31fb8, 0x32004, - 0x32208, 0x3223c, - 0x32600, 0x32630, - 0x32a00, 0x32abc, - 0x32b00, 0x32b70, - 0x33000, 0x33048, - 0x33060, 0x3309c, - 0x330f0, 0x33148, - 0x33160, 0x3319c, - 0x331f0, 0x332e4, - 0x332f8, 0x333e4, - 0x333f8, 0x33448, - 0x33460, 0x3349c, - 0x334f0, 0x33548, - 0x33560, 0x3359c, - 0x335f0, 0x336e4, - 0x336f8, 0x337e4, - 0x337f8, 0x337fc, - 0x33814, 0x33814, - 0x3382c, 0x3382c, - 0x33880, 0x3388c, - 0x338e8, 0x338ec, - 0x33900, 0x33948, - 0x33960, 0x3399c, - 0x339f0, 0x33ae4, - 0x33af8, 0x33b10, - 0x33b28, 0x33b28, - 0x33b3c, 0x33b50, - 0x33bf0, 0x33c10, - 0x33c28, 0x33c28, - 0x33c3c, 0x33c50, - 0x33cf0, 0x33cfc, - 0x34000, 0x34030, - 0x34100, 0x34144, - 0x34190, 0x341d0, - 0x34200, 0x34318, - 0x34400, 0x3452c, - 0x34540, 0x3461c, - 0x34800, 0x34834, - 0x348c0, 0x34908, - 0x34910, 0x349ac, - 0x34a00, 0x34a04, - 0x34a0c, 0x34a2c, - 0x34a44, 0x34a50, - 0x34a74, 0x34c24, - 0x34d08, 0x34d14, - 0x34d1c, 0x34d20, - 0x34d3c, 0x34d50, - 0x35200, 0x3520c, - 0x35220, 0x35220, - 0x35240, 0x35240, - 0x35600, 0x35600, - 0x35608, 0x3560c, - 0x35a00, 0x35a1c, - 0x35e04, 0x35e20, - 0x35e38, 0x35e3c, - 0x35e80, 0x35e80, - 0x35e88, 0x35ea8, - 0x35eb0, 0x35eb4, - 0x35ec8, 0x35ed4, - 0x35fb8, 0x36004, - 0x36208, 0x3623c, - 0x36600, 0x36630, - 0x36a00, 0x36abc, - 0x36b00, 0x36b70, - 0x37000, 0x37048, - 0x37060, 0x3709c, - 0x370f0, 0x37148, - 0x37160, 0x3719c, - 0x371f0, 0x372e4, - 0x372f8, 0x373e4, - 0x373f8, 0x37448, - 0x37460, 0x3749c, - 0x374f0, 0x37548, - 0x37560, 0x3759c, - 0x375f0, 0x376e4, - 0x376f8, 0x377e4, - 0x377f8, 0x377fc, - 0x37814, 0x37814, - 0x3782c, 0x3782c, - 0x37880, 0x3788c, - 0x378e8, 0x378ec, - 0x37900, 0x37948, - 0x37960, 0x3799c, - 0x379f0, 0x37ae4, - 0x37af8, 0x37b10, - 0x37b28, 0x37b28, - 0x37b3c, 0x37b50, - 0x37bf0, 0x37c10, - 0x37c28, 0x37c28, - 0x37c3c, 0x37c50, - 0x37cf0, 0x37cfc, - 0x38000, 0x38030, - 0x38100, 0x38144, - 0x38190, 0x381d0, - 0x38200, 0x38318, - 0x38400, 0x3852c, - 0x38540, 0x3861c, - 0x38800, 0x38834, - 0x388c0, 0x38908, - 0x38910, 0x389ac, - 0x38a00, 0x38a04, - 0x38a0c, 0x38a2c, - 0x38a44, 0x38a50, - 0x38a74, 0x38c24, - 0x38d08, 0x38d14, - 0x38d1c, 0x38d20, - 0x38d3c, 0x38d50, - 0x39200, 0x3920c, - 0x39220, 0x39220, - 0x39240, 0x39240, - 0x39600, 0x39600, - 0x39608, 0x3960c, - 0x39a00, 0x39a1c, - 0x39e04, 0x39e20, - 0x39e38, 0x39e3c, - 0x39e80, 0x39e80, - 0x39e88, 0x39ea8, - 0x39eb0, 0x39eb4, - 0x39ec8, 0x39ed4, - 0x39fb8, 0x3a004, - 0x3a208, 0x3a23c, - 0x3a600, 0x3a630, - 0x3aa00, 0x3aabc, - 0x3ab00, 0x3ab70, - 0x3b000, 0x3b048, - 0x3b060, 0x3b09c, - 0x3b0f0, 0x3b148, - 0x3b160, 0x3b19c, - 0x3b1f0, 0x3b2e4, - 0x3b2f8, 0x3b3e4, - 0x3b3f8, 0x3b448, - 0x3b460, 0x3b49c, - 0x3b4f0, 0x3b548, - 0x3b560, 0x3b59c, - 0x3b5f0, 0x3b6e4, - 0x3b6f8, 0x3b7e4, - 0x3b7f8, 0x3b7fc, - 0x3b814, 0x3b814, - 0x3b82c, 0x3b82c, - 0x3b880, 0x3b88c, - 0x3b8e8, 0x3b8ec, - 0x3b900, 0x3b948, - 0x3b960, 0x3b99c, - 0x3b9f0, 0x3bae4, - 0x3baf8, 0x3bb10, - 0x3bb28, 0x3bb28, - 0x3bb3c, 0x3bb50, - 0x3bbf0, 0x3bc10, - 0x3bc28, 0x3bc28, - 0x3bc3c, 0x3bc50, - 0x3bcf0, 0x3bcfc, - 0x3c000, 0x3c030, - 0x3c100, 0x3c144, - 0x3c190, 0x3c1d0, - 0x3c200, 0x3c318, - 0x3c400, 0x3c52c, - 0x3c540, 0x3c61c, - 0x3c800, 0x3c834, - 0x3c8c0, 0x3c908, - 0x3c910, 0x3c9ac, - 0x3ca00, 0x3ca04, - 0x3ca0c, 0x3ca2c, - 0x3ca44, 0x3ca50, - 0x3ca74, 0x3cc24, - 0x3cd08, 0x3cd14, - 0x3cd1c, 0x3cd20, - 0x3cd3c, 0x3cd50, - 0x3d200, 0x3d20c, - 0x3d220, 0x3d220, - 0x3d240, 0x3d240, - 0x3d600, 0x3d600, - 0x3d608, 0x3d60c, - 0x3da00, 0x3da1c, - 0x3de04, 0x3de20, - 0x3de38, 0x3de3c, - 0x3de80, 0x3de80, - 0x3de88, 0x3dea8, - 0x3deb0, 0x3deb4, - 0x3dec8, 0x3ded4, - 0x3dfb8, 0x3e004, - 0x3e208, 0x3e23c, - 0x3e600, 0x3e630, - 0x3ea00, 0x3eabc, - 0x3eb00, 0x3eb70, - 0x3f000, 0x3f048, - 0x3f060, 0x3f09c, - 0x3f0f0, 0x3f148, - 0x3f160, 0x3f19c, - 0x3f1f0, 0x3f2e4, - 0x3f2f8, 0x3f3e4, - 0x3f3f8, 0x3f448, - 0x3f460, 0x3f49c, - 0x3f4f0, 0x3f548, - 0x3f560, 0x3f59c, - 0x3f5f0, 0x3f6e4, - 0x3f6f8, 0x3f7e4, - 0x3f7f8, 0x3f7fc, - 0x3f814, 0x3f814, - 0x3f82c, 0x3f82c, - 0x3f880, 0x3f88c, - 0x3f8e8, 0x3f8ec, - 0x3f900, 0x3f948, - 0x3f960, 0x3f99c, - 0x3f9f0, 0x3fae4, - 0x3faf8, 0x3fb10, - 0x3fb28, 0x3fb28, - 0x3fb3c, 0x3fb50, - 0x3fbf0, 0x3fc10, - 0x3fc28, 0x3fc28, - 0x3fc3c, 0x3fc50, - 0x3fcf0, 0x3fcfc, - 0x40000, 0x4000c, - 0x40040, 0x40068, - 0x40080, 0x40144, - 0x40180, 0x4018c, - 0x40200, 0x40298, - 0x402ac, 0x4033c, - 0x403f8, 0x403fc, - 0x41304, 0x413c4, - 0x41400, 0x4141c, - 0x41480, 0x414d0, - 0x44000, 0x44078, - 0x440c0, 0x44278, - 0x442c0, 0x44478, - 0x444c0, 0x44678, - 0x446c0, 0x44878, - 0x448c0, 0x449fc, - 0x45000, 0x45068, - 0x45080, 0x45084, - 0x450a0, 0x450b0, - 0x45200, 0x45268, - 0x45280, 0x45284, - 0x452a0, 0x452b0, - 0x460c0, 0x460e4, - 0x47000, 0x4708c, - 0x47200, 0x47250, - 0x47400, 0x47420, - 0x47600, 0x47618, - 0x47800, 0x47814, - 0x48000, 0x4800c, - 0x48040, 0x48068, - 0x48080, 0x48144, - 0x48180, 0x4818c, - 0x48200, 0x48298, - 0x482ac, 0x4833c, - 0x483f8, 0x483fc, - 0x49304, 0x493c4, - 0x49400, 0x4941c, - 0x49480, 0x494d0, - 0x4c000, 0x4c078, - 0x4c0c0, 0x4c278, - 0x4c2c0, 0x4c478, - 0x4c4c0, 0x4c678, - 0x4c6c0, 0x4c878, - 0x4c8c0, 0x4c9fc, - 0x4d000, 0x4d068, - 0x4d080, 0x4d084, - 0x4d0a0, 0x4d0b0, - 0x4d200, 0x4d268, - 0x4d280, 0x4d284, - 0x4d2a0, 0x4d2b0, - 0x4e0c0, 0x4e0e4, - 0x4f000, 0x4f08c, - 0x4f200, 0x4f250, - 0x4f400, 0x4f420, - 0x4f600, 0x4f618, - 0x4f800, 0x4f814, - 0x50000, 0x500cc, - 0x50400, 0x50400, - 0x50800, 0x508cc, - 0x50c00, 0x50c00, - 0x51000, 0x5101c, - 0x51300, 0x51308, - }; - - int i; - struct adapter *ap = netdev2adap(dev); - static const unsigned int *reg_ranges; - int arr_size = 0, buf_size = 0; - - if (is_t4(ap->params.chip)) { - reg_ranges = &t4_reg_ranges[0]; - arr_size = ARRAY_SIZE(t4_reg_ranges); - buf_size = T4_REGMAP_SIZE; - } else { - reg_ranges = &t5_reg_ranges[0]; - arr_size = ARRAY_SIZE(t5_reg_ranges); - buf_size = T5_REGMAP_SIZE; - } - - regs->version = mk_adap_vers(ap); - - memset(buf, 0, buf_size); - for (i = 0; i < arr_size; i += 2) - reg_block_dump(ap, buf, reg_ranges[i], reg_ranges[i + 1]); -} - -static int restart_autoneg(struct net_device *dev) -{ - struct port_info *p = netdev_priv(dev); - - if (!netif_running(dev)) - return -EAGAIN; - if (p->link_cfg.autoneg != AUTONEG_ENABLE) - return -EINVAL; - t4_restart_aneg(p->adapter, p->adapter->fn, p->tx_chan); - return 0; -} - -static int identify_port(struct net_device *dev, - enum ethtool_phys_id_state state) -{ - unsigned int val; - struct adapter *adap = netdev2adap(dev); - - if (state == ETHTOOL_ID_ACTIVE) - val = 0xffff; - else if (state == ETHTOOL_ID_INACTIVE) - val = 0; - else - return -EINVAL; - - return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val); -} - -static unsigned int from_fw_linkcaps(enum fw_port_type type, unsigned int caps) -{ - unsigned int v = 0; - - if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI || - type == FW_PORT_TYPE_BT_XAUI) { - v |= SUPPORTED_TP; - if (caps & FW_PORT_CAP_SPEED_100M) - v |= SUPPORTED_100baseT_Full; - if (caps & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseT_Full; - if (caps & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseT_Full; - } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) { - v |= SUPPORTED_Backplane; - if (caps & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseKX_Full; - if (caps & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseKX4_Full; - } else if (type == FW_PORT_TYPE_KR) - v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full; - else if (type == FW_PORT_TYPE_BP_AP) - v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | - SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full; - else if (type == FW_PORT_TYPE_BP4_AP) - v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC | - SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | - SUPPORTED_10000baseKX4_Full; - else if (type == FW_PORT_TYPE_FIBER_XFI || - type == FW_PORT_TYPE_FIBER_XAUI || - type == FW_PORT_TYPE_SFP || - type == FW_PORT_TYPE_QSFP_10G || - type == FW_PORT_TYPE_QSA) { - v |= SUPPORTED_FIBRE; - if (caps & FW_PORT_CAP_SPEED_1G) - v |= SUPPORTED_1000baseT_Full; - if (caps & FW_PORT_CAP_SPEED_10G) - v |= SUPPORTED_10000baseT_Full; - } else if (type == FW_PORT_TYPE_BP40_BA || - type == FW_PORT_TYPE_QSFP) { - v |= SUPPORTED_40000baseSR4_Full; - v |= SUPPORTED_FIBRE; - } - - if (caps & FW_PORT_CAP_ANEG) - v |= SUPPORTED_Autoneg; - return v; -} - -static unsigned int to_fw_linkcaps(unsigned int caps) -{ - unsigned int v = 0; - - if (caps & ADVERTISED_100baseT_Full) - v |= FW_PORT_CAP_SPEED_100M; - if (caps & ADVERTISED_1000baseT_Full) - v |= FW_PORT_CAP_SPEED_1G; - if (caps & ADVERTISED_10000baseT_Full) - v |= FW_PORT_CAP_SPEED_10G; - if (caps & ADVERTISED_40000baseSR4_Full) - v |= FW_PORT_CAP_SPEED_40G; - return v; -} - -static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - const struct port_info *p = netdev_priv(dev); - - if (p->port_type == FW_PORT_TYPE_BT_SGMII || - p->port_type == FW_PORT_TYPE_BT_XFI || - p->port_type == FW_PORT_TYPE_BT_XAUI) - cmd->port = PORT_TP; - else if (p->port_type == FW_PORT_TYPE_FIBER_XFI || - p->port_type == FW_PORT_TYPE_FIBER_XAUI) - cmd->port = PORT_FIBRE; - else if (p->port_type == FW_PORT_TYPE_SFP || - p->port_type == FW_PORT_TYPE_QSFP_10G || - p->port_type == FW_PORT_TYPE_QSA || - p->port_type == FW_PORT_TYPE_QSFP) { - if (p->mod_type == FW_PORT_MOD_TYPE_LR || - p->mod_type == FW_PORT_MOD_TYPE_SR || - p->mod_type == FW_PORT_MOD_TYPE_ER || - p->mod_type == FW_PORT_MOD_TYPE_LRM) - cmd->port = PORT_FIBRE; - else if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE || - p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE) - cmd->port = PORT_DA; - else - cmd->port = PORT_OTHER; - } else - cmd->port = PORT_OTHER; - - if (p->mdio_addr >= 0) { - cmd->phy_address = p->mdio_addr; - cmd->transceiver = XCVR_EXTERNAL; - cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ? - MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45; - } else { - cmd->phy_address = 0; /* not really, but no better option */ - cmd->transceiver = XCVR_INTERNAL; - cmd->mdio_support = 0; - } - - cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported); - cmd->advertising = from_fw_linkcaps(p->port_type, - p->link_cfg.advertising); - ethtool_cmd_speed_set(cmd, - netif_carrier_ok(dev) ? p->link_cfg.speed : 0); - cmd->duplex = DUPLEX_FULL; - cmd->autoneg = p->link_cfg.autoneg; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; - return 0; -} - -static unsigned int speed_to_caps(int speed) -{ - if (speed == 100) - return FW_PORT_CAP_SPEED_100M; - if (speed == 1000) - return FW_PORT_CAP_SPEED_1G; - if (speed == 10000) - return FW_PORT_CAP_SPEED_10G; - if (speed == 40000) - return FW_PORT_CAP_SPEED_40G; - return 0; -} - -static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - unsigned int cap; - struct port_info *p = netdev_priv(dev); - struct link_config *lc = &p->link_cfg; - u32 speed = ethtool_cmd_speed(cmd); - - if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */ - return -EINVAL; - - if (!(lc->supported & FW_PORT_CAP_ANEG)) { - /* - * PHY offers a single speed. See if that's what's - * being requested. - */ - if (cmd->autoneg == AUTONEG_DISABLE && - (lc->supported & speed_to_caps(speed))) - return 0; - return -EINVAL; - } - - if (cmd->autoneg == AUTONEG_DISABLE) { - cap = speed_to_caps(speed); - - if (!(lc->supported & cap) || - (speed == 1000) || - (speed == 10000) || - (speed == 40000)) - return -EINVAL; - lc->requested_speed = cap; - lc->advertising = 0; - } else { - cap = to_fw_linkcaps(cmd->advertising); - if (!(lc->supported & cap)) - return -EINVAL; - lc->requested_speed = 0; - lc->advertising = cap | FW_PORT_CAP_ANEG; - } - lc->autoneg = cmd->autoneg; - - if (netif_running(dev)) - return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, - lc); - return 0; -} - -static void get_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct port_info *p = netdev_priv(dev); - - epause->autoneg = (p->link_cfg.requested_fc & PAUSE_AUTONEG) != 0; - epause->rx_pause = (p->link_cfg.fc & PAUSE_RX) != 0; - epause->tx_pause = (p->link_cfg.fc & PAUSE_TX) != 0; -} - -static int set_pauseparam(struct net_device *dev, - struct ethtool_pauseparam *epause) -{ - struct port_info *p = netdev_priv(dev); - struct link_config *lc = &p->link_cfg; - - if (epause->autoneg == AUTONEG_DISABLE) - lc->requested_fc = 0; - else if (lc->supported & FW_PORT_CAP_ANEG) - lc->requested_fc = PAUSE_AUTONEG; - else - return -EINVAL; - - if (epause->rx_pause) - lc->requested_fc |= PAUSE_RX; - if (epause->tx_pause) - lc->requested_fc |= PAUSE_TX; - if (netif_running(dev)) - return t4_link_start(p->adapter, p->adapter->fn, p->tx_chan, - lc); - return 0; -} - -static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - const struct port_info *pi = netdev_priv(dev); - const struct sge *s = &pi->adapter->sge; - - e->rx_max_pending = MAX_RX_BUFFERS; - e->rx_mini_max_pending = MAX_RSPQ_ENTRIES; - e->rx_jumbo_max_pending = 0; - e->tx_max_pending = MAX_TXQ_ENTRIES; - - e->rx_pending = s->ethrxq[pi->first_qset].fl.size - 8; - e->rx_mini_pending = s->ethrxq[pi->first_qset].rspq.size; - e->rx_jumbo_pending = 0; - e->tx_pending = s->ethtxq[pi->first_qset].q.size; -} - -static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) -{ - int i; - const struct port_info *pi = netdev_priv(dev); - struct adapter *adapter = pi->adapter; - struct sge *s = &adapter->sge; - - if (e->rx_pending > MAX_RX_BUFFERS || e->rx_jumbo_pending || - e->tx_pending > MAX_TXQ_ENTRIES || - e->rx_mini_pending > MAX_RSPQ_ENTRIES || - e->rx_mini_pending < MIN_RSPQ_ENTRIES || - e->rx_pending < MIN_FL_ENTRIES || e->tx_pending < MIN_TXQ_ENTRIES) - return -EINVAL; - - if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; - - for (i = 0; i < pi->nqsets; ++i) { - s->ethtxq[pi->first_qset + i].q.size = e->tx_pending; - s->ethrxq[pi->first_qset + i].fl.size = e->rx_pending + 8; - s->ethrxq[pi->first_qset + i].rspq.size = e->rx_mini_pending; - } - return 0; -} - static int closest_timer(const struct sge *s, int time) { int i, delta, match = 0, min_delta = INT_MAX; @@ -2545,19 +1351,8 @@ static int closest_thres(const struct sge *s, int thres) return match; } -/* - * Return a queue's interrupt hold-off time in us. 0 means no timer. - */ -unsigned int qtimer_val(const struct adapter *adap, - const struct sge_rspq *q) -{ - unsigned int idx = q->intr_params >> 1; - - return idx < SGE_NTIMERS ? adap->sge.timer_val[idx] : 0; -} - /** - * set_rspq_intr_params - set a queue's interrupt holdoff parameters + * cxgb4_set_rspq_intr_params - set a queue's interrupt holdoff parameters * @q: the Rx queue * @us: the hold-off time in us, or 0 to disable timer * @cnt: the hold-off packet count, or 0 to disable counter @@ -2565,8 +1360,8 @@ unsigned int qtimer_val(const struct adapter *adap, * Sets an Rx queue's interrupt hold-off time and packet count. At least * one of the two needs to be enabled for the queue to generate interrupts. */ -static int set_rspq_intr_params(struct sge_rspq *q, - unsigned int us, unsigned int cnt) +int cxgb4_set_rspq_intr_params(struct sge_rspq *q, + unsigned int us, unsigned int cnt) { struct adapter *adap = q->adap; @@ -2597,259 +1392,6 @@ static int set_rspq_intr_params(struct sge_rspq *q, return 0; } -/** - * set_rx_intr_params - set a net devices's RX interrupt holdoff paramete! - * @dev: the network device - * @us: the hold-off time in us, or 0 to disable timer - * @cnt: the hold-off packet count, or 0 to disable counter - * - * Set the RX interrupt hold-off parameters for a network device. - */ -static int set_rx_intr_params(struct net_device *dev, - unsigned int us, unsigned int cnt) -{ - int i, err; - struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; - - for (i = 0; i < pi->nqsets; i++, q++) { - err = set_rspq_intr_params(&q->rspq, us, cnt); - if (err) - return err; - } - return 0; -} - -static int set_adaptive_rx_setting(struct net_device *dev, int adaptive_rx) -{ - int i; - struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; - - for (i = 0; i < pi->nqsets; i++, q++) - q->rspq.adaptive_rx = adaptive_rx; - - return 0; -} - -static int get_adaptive_rx_setting(struct net_device *dev) -{ - struct port_info *pi = netdev_priv(dev); - struct adapter *adap = pi->adapter; - struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset]; - - return q->rspq.adaptive_rx; -} - -static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - set_adaptive_rx_setting(dev, c->use_adaptive_rx_coalesce); - return set_rx_intr_params(dev, c->rx_coalesce_usecs, - c->rx_max_coalesced_frames); -} - -static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) -{ - const struct port_info *pi = netdev_priv(dev); - const struct adapter *adap = pi->adapter; - const struct sge_rspq *rq = &adap->sge.ethrxq[pi->first_qset].rspq; - - c->rx_coalesce_usecs = qtimer_val(adap, rq); - c->rx_max_coalesced_frames = (rq->intr_params & QINTR_CNT_EN) ? - adap->sge.counter_val[rq->pktcnt_idx] : 0; - c->use_adaptive_rx_coalesce = get_adaptive_rx_setting(dev); - return 0; -} - -/** - * eeprom_ptov - translate a physical EEPROM address to virtual - * @phys_addr: the physical EEPROM address - * @fn: the PCI function number - * @sz: size of function-specific area - * - * Translate a physical EEPROM address to virtual. The first 1K is - * accessed through virtual addresses starting at 31K, the rest is - * accessed through virtual addresses starting at 0. - * - * The mapping is as follows: - * [0..1K) -> [31K..32K) - * [1K..1K+A) -> [31K-A..31K) - * [1K+A..ES) -> [0..ES-A-1K) - * - * where A = @fn * @sz, and ES = EEPROM size. - */ -static int eeprom_ptov(unsigned int phys_addr, unsigned int fn, unsigned int sz) -{ - fn *= sz; - if (phys_addr < 1024) - return phys_addr + (31 << 10); - if (phys_addr < 1024 + fn) - return 31744 - fn + phys_addr - 1024; - if (phys_addr < EEPROMSIZE) - return phys_addr - 1024 - fn; - return -EINVAL; -} - -/* - * The next two routines implement eeprom read/write from physical addresses. - */ -static int eeprom_rd_phys(struct adapter *adap, unsigned int phys_addr, u32 *v) -{ - int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); - - if (vaddr >= 0) - vaddr = pci_read_vpd(adap->pdev, vaddr, sizeof(u32), v); - return vaddr < 0 ? vaddr : 0; -} - -static int eeprom_wr_phys(struct adapter *adap, unsigned int phys_addr, u32 v) -{ - int vaddr = eeprom_ptov(phys_addr, adap->fn, EEPROMPFSIZE); - - if (vaddr >= 0) - vaddr = pci_write_vpd(adap->pdev, vaddr, sizeof(u32), &v); - return vaddr < 0 ? vaddr : 0; -} - -#define EEPROM_MAGIC 0x38E2F10C - -static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, - u8 *data) -{ - int i, err = 0; - struct adapter *adapter = netdev2adap(dev); - - u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - e->magic = EEPROM_MAGIC; - for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) - err = eeprom_rd_phys(adapter, i, (u32 *)&buf[i]); - - if (!err) - memcpy(data, buf + e->offset, e->len); - kfree(buf); - return err; -} - -static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, - u8 *data) -{ - u8 *buf; - int err = 0; - u32 aligned_offset, aligned_len, *p; - struct adapter *adapter = netdev2adap(dev); - - if (eeprom->magic != EEPROM_MAGIC) - return -EINVAL; - - aligned_offset = eeprom->offset & ~3; - aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; - - if (adapter->fn > 0) { - u32 start = 1024 + adapter->fn * EEPROMPFSIZE; - - if (aligned_offset < start || - aligned_offset + aligned_len > start + EEPROMPFSIZE) - return -EPERM; - } - - if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { - /* - * RMW possibly needed for first or last words. - */ - buf = kmalloc(aligned_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - err = eeprom_rd_phys(adapter, aligned_offset, (u32 *)buf); - if (!err && aligned_len > 4) - err = eeprom_rd_phys(adapter, - aligned_offset + aligned_len - 4, - (u32 *)&buf[aligned_len - 4]); - if (err) - goto out; - memcpy(buf + (eeprom->offset & 3), data, eeprom->len); - } else - buf = data; - - err = t4_seeprom_wp(adapter, false); - if (err) - goto out; - - for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { - err = eeprom_wr_phys(adapter, aligned_offset, *p); - aligned_offset += 4; - } - - if (!err) - err = t4_seeprom_wp(adapter, true); -out: - if (buf != data) - kfree(buf); - return err; -} - -static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) -{ - int ret; - const struct firmware *fw; - struct adapter *adap = netdev2adap(netdev); - unsigned int mbox = PCIE_FW_MASTER_M + 1; - - ef->data[sizeof(ef->data) - 1] = '\0'; - ret = request_firmware(&fw, ef->data, adap->pdev_dev); - if (ret < 0) - return ret; - - /* If the adapter has been fully initialized then we'll go ahead and - * try to get the firmware's cooperation in upgrading to the new - * firmware image otherwise we'll try to do the entire job from the - * host ... and we always "force" the operation in this path. - */ - if (adap->flags & FULL_INIT_DONE) - mbox = adap->mbox; - - ret = t4_fw_upgrade(adap, mbox, fw->data, fw->size, 1); - release_firmware(fw); - if (!ret) - dev_info(adap->pdev_dev, "loaded firmware %s," - " reload cxgb4 driver\n", ef->data); - return ret; -} - -#define WOL_SUPPORTED (WAKE_BCAST | WAKE_MAGIC) -#define BCAST_CRC 0xa0ccc1a6 - -static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - wol->supported = WAKE_BCAST | WAKE_MAGIC; - wol->wolopts = netdev2adap(dev)->wol; - memset(&wol->sopass, 0, sizeof(wol->sopass)); -} - -static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - int err = 0; - struct port_info *pi = netdev_priv(dev); - - if (wol->wolopts & ~WOL_SUPPORTED) - return -EINVAL; - t4_wol_magic_enable(pi->adapter, pi->tx_chan, - (wol->wolopts & WAKE_MAGIC) ? dev->dev_addr : NULL); - if (wol->wolopts & WAKE_BCAST) { - err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0xfe, ~0ULL, - ~0ULL, 0, false); - if (!err) - err = t4_wol_pat_enable(pi->adapter, pi->tx_chan, 1, - ~6ULL, ~0ULL, BCAST_CRC, true); - } else - t4_wol_pat_enable(pi->adapter, pi->tx_chan, 0, 0, 0, 0, false); - return err; -} - static int cxgb_set_features(struct net_device *dev, netdev_features_t features) { const struct port_info *pi = netdev_priv(dev); @@ -2867,144 +1409,6 @@ static int cxgb_set_features(struct net_device *dev, netdev_features_t features) return err; } -static u32 get_rss_table_size(struct net_device *dev) -{ - const struct port_info *pi = netdev_priv(dev); - - return pi->rss_size; -} - -static int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc) -{ - const struct port_info *pi = netdev_priv(dev); - unsigned int n = pi->rss_size; - - if (hfunc) - *hfunc = ETH_RSS_HASH_TOP; - if (!p) - return 0; - while (n--) - p[n] = pi->rss[n]; - return 0; -} - -static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key, - const u8 hfunc) -{ - unsigned int i; - struct port_info *pi = netdev_priv(dev); - - /* We require at least one supported parameter to be changed and no - * change in any of the unsupported parameters - */ - if (key || - (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) - return -EOPNOTSUPP; - if (!p) - return 0; - - for (i = 0; i < pi->rss_size; i++) - pi->rss[i] = p[i]; - if (pi->adapter->flags & FULL_INIT_DONE) - return write_rss(pi, pi->rss); - return 0; -} - -static int get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, - u32 *rules) -{ - const struct port_info *pi = netdev_priv(dev); - - switch (info->cmd) { - case ETHTOOL_GRXFH: { - unsigned int v = pi->rss_mode; - - info->data = 0; - switch (info->flow_type) { - case TCP_V4_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case UDP_V4_FLOW: - if ((v & FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN_F) && - (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case SCTP_V4_FLOW: - case AH_ESP_V4_FLOW: - case IPV4_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case TCP_V6_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case UDP_V6_FLOW: - if ((v & FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN_F) && - (v & FW_RSS_VI_CONFIG_CMD_UDPEN_F)) - info->data = RXH_IP_SRC | RXH_IP_DST | - RXH_L4_B_0_1 | RXH_L4_B_2_3; - else if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - case SCTP_V6_FLOW: - case AH_ESP_V6_FLOW: - case IPV6_FLOW: - if (v & FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN_F) - info->data = RXH_IP_SRC | RXH_IP_DST; - break; - } - return 0; - } - case ETHTOOL_GRXRINGS: - info->data = pi->nqsets; - return 0; - } - return -EOPNOTSUPP; -} - -static const struct ethtool_ops cxgb_ethtool_ops = { - .get_settings = get_settings, - .set_settings = set_settings, - .get_drvinfo = get_drvinfo, - .get_msglevel = get_msglevel, - .set_msglevel = set_msglevel, - .get_ringparam = get_sge_param, - .set_ringparam = set_sge_param, - .get_coalesce = get_coalesce, - .set_coalesce = set_coalesce, - .get_eeprom_len = get_eeprom_len, - .get_eeprom = get_eeprom, - .set_eeprom = set_eeprom, - .get_pauseparam = get_pauseparam, - .set_pauseparam = set_pauseparam, - .get_link = ethtool_op_get_link, - .get_strings = get_strings, - .set_phys_id = identify_port, - .nway_reset = restart_autoneg, - .get_sset_count = get_sset_count, - .get_ethtool_stats = get_stats, - .get_regs_len = get_regs_len, - .get_regs = get_regs, - .get_wol = get_wol, - .set_wol = set_wol, - .get_rxnfc = get_rxnfc, - .get_rxfh_indir_size = get_rss_table_size, - .get_rxfh = get_rss_table, - .set_rxfh = set_rss_table, - .flash_device = set_flash, -}; - static int setup_debugfs(struct adapter *adap) { if (IS_ERR_OR_NULL(adap->debugfs_root)) @@ -5689,7 +4093,7 @@ static inline void init_rspq(struct adapter *adap, struct sge_rspq *q, unsigned int size, unsigned int iqe_size) { q->adap = adap; - set_rspq_intr_params(q, us, cnt); + cxgb4_set_rspq_intr_params(q, us, cnt); q->iqe_len = iqe_size; q->size = size; } @@ -6184,7 +4588,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->dcbnl_ops = &cxgb4_dcb_ops; cxgb4_dcb_state_init(netdev); #endif - netdev->ethtool_ops = &cxgb_ethtool_ops; + cxgb4_set_ethtool_ops(netdev); } pci_set_drvdata(pdev, adapter); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 5ed8db977432..5959e3ae72da 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -625,6 +625,734 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr, return 0; } +/** + * t4_get_regs_len - return the size of the chips register set + * @adapter: the adapter + * + * Returns the size of the chip's BAR0 register space. + */ +unsigned int t4_get_regs_len(struct adapter *adapter) +{ + unsigned int chip_version = CHELSIO_CHIP_VERSION(adapter->params.chip); + + switch (chip_version) { + case CHELSIO_T4: + return T4_REGMAP_SIZE; + + case CHELSIO_T5: + return T5_REGMAP_SIZE; + } + + dev_err(adapter->pdev_dev, + "Unsupported chip version %d\n", chip_version); + return 0; +} + +/** + * t4_get_regs - read chip registers into provided buffer + * @adap: the adapter + * @buf: register buffer + * @buf_size: size (in bytes) of register buffer + * + * If the provided register buffer isn't large enough for the chip's + * full register range, the register dump will be truncated to the + * register buffer's size. + */ +void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) +{ + static const unsigned int t4_reg_ranges[] = { + 0x1008, 0x1108, + 0x1180, 0x11b4, + 0x11fc, 0x123c, + 0x1300, 0x173c, + 0x1800, 0x18fc, + 0x3000, 0x30d8, + 0x30e0, 0x5924, + 0x5960, 0x59d4, + 0x5a00, 0x5af8, + 0x6000, 0x6098, + 0x6100, 0x6150, + 0x6200, 0x6208, + 0x6240, 0x6248, + 0x6280, 0x6338, + 0x6370, 0x638c, + 0x6400, 0x643c, + 0x6500, 0x6524, + 0x6a00, 0x6a38, + 0x6a60, 0x6a78, + 0x6b00, 0x6b84, + 0x6bf0, 0x6c84, + 0x6cf0, 0x6d84, + 0x6df0, 0x6e84, + 0x6ef0, 0x6f84, + 0x6ff0, 0x7084, + 0x70f0, 0x7184, + 0x71f0, 0x7284, + 0x72f0, 0x7384, + 0x73f0, 0x7450, + 0x7500, 0x7530, + 0x7600, 0x761c, + 0x7680, 0x76cc, + 0x7700, 0x7798, + 0x77c0, 0x77fc, + 0x7900, 0x79fc, + 0x7b00, 0x7c38, + 0x7d00, 0x7efc, + 0x8dc0, 0x8e1c, + 0x8e30, 0x8e78, + 0x8ea0, 0x8f6c, + 0x8fc0, 0x9074, + 0x90fc, 0x90fc, + 0x9400, 0x9458, + 0x9600, 0x96bc, + 0x9800, 0x9808, + 0x9820, 0x983c, + 0x9850, 0x9864, + 0x9c00, 0x9c6c, + 0x9c80, 0x9cec, + 0x9d00, 0x9d6c, + 0x9d80, 0x9dec, + 0x9e00, 0x9e6c, + 0x9e80, 0x9eec, + 0x9f00, 0x9f6c, + 0x9f80, 0x9fec, + 0xd004, 0xd03c, + 0xdfc0, 0xdfe0, + 0xe000, 0xea7c, + 0xf000, 0x11110, + 0x11118, 0x11190, + 0x19040, 0x1906c, + 0x19078, 0x19080, + 0x1908c, 0x19124, + 0x19150, 0x191b0, + 0x191d0, 0x191e8, + 0x19238, 0x1924c, + 0x193f8, 0x19474, + 0x19490, 0x194f8, + 0x19800, 0x19f30, + 0x1a000, 0x1a06c, + 0x1a0b0, 0x1a120, + 0x1a128, 0x1a138, + 0x1a190, 0x1a1c4, + 0x1a1fc, 0x1a1fc, + 0x1e040, 0x1e04c, + 0x1e284, 0x1e28c, + 0x1e2c0, 0x1e2c0, + 0x1e2e0, 0x1e2e0, + 0x1e300, 0x1e384, + 0x1e3c0, 0x1e3c8, + 0x1e440, 0x1e44c, + 0x1e684, 0x1e68c, + 0x1e6c0, 0x1e6c0, + 0x1e6e0, 0x1e6e0, + 0x1e700, 0x1e784, + 0x1e7c0, 0x1e7c8, + 0x1e840, 0x1e84c, + 0x1ea84, 0x1ea8c, + 0x1eac0, 0x1eac0, + 0x1eae0, 0x1eae0, + 0x1eb00, 0x1eb84, + 0x1ebc0, 0x1ebc8, + 0x1ec40, 0x1ec4c, + 0x1ee84, 0x1ee8c, + 0x1eec0, 0x1eec0, + 0x1eee0, 0x1eee0, + 0x1ef00, 0x1ef84, + 0x1efc0, 0x1efc8, + 0x1f040, 0x1f04c, + 0x1f284, 0x1f28c, + 0x1f2c0, 0x1f2c0, + 0x1f2e0, 0x1f2e0, + 0x1f300, 0x1f384, + 0x1f3c0, 0x1f3c8, + 0x1f440, 0x1f44c, + 0x1f684, 0x1f68c, + 0x1f6c0, 0x1f6c0, + 0x1f6e0, 0x1f6e0, + 0x1f700, 0x1f784, + 0x1f7c0, 0x1f7c8, + 0x1f840, 0x1f84c, + 0x1fa84, 0x1fa8c, + 0x1fac0, 0x1fac0, + 0x1fae0, 0x1fae0, + 0x1fb00, 0x1fb84, + 0x1fbc0, 0x1fbc8, + 0x1fc40, 0x1fc4c, + 0x1fe84, 0x1fe8c, + 0x1fec0, 0x1fec0, + 0x1fee0, 0x1fee0, + 0x1ff00, 0x1ff84, + 0x1ffc0, 0x1ffc8, + 0x20000, 0x2002c, + 0x20100, 0x2013c, + 0x20190, 0x201c8, + 0x20200, 0x20318, + 0x20400, 0x20528, + 0x20540, 0x20614, + 0x21000, 0x21040, + 0x2104c, 0x21060, + 0x210c0, 0x210ec, + 0x21200, 0x21268, + 0x21270, 0x21284, + 0x212fc, 0x21388, + 0x21400, 0x21404, + 0x21500, 0x21518, + 0x2152c, 0x2153c, + 0x21550, 0x21554, + 0x21600, 0x21600, + 0x21608, 0x21628, + 0x21630, 0x2163c, + 0x21700, 0x2171c, + 0x21780, 0x2178c, + 0x21800, 0x21c38, + 0x21c80, 0x21d7c, + 0x21e00, 0x21e04, + 0x22000, 0x2202c, + 0x22100, 0x2213c, + 0x22190, 0x221c8, + 0x22200, 0x22318, + 0x22400, 0x22528, + 0x22540, 0x22614, + 0x23000, 0x23040, + 0x2304c, 0x23060, + 0x230c0, 0x230ec, + 0x23200, 0x23268, + 0x23270, 0x23284, + 0x232fc, 0x23388, + 0x23400, 0x23404, + 0x23500, 0x23518, + 0x2352c, 0x2353c, + 0x23550, 0x23554, + 0x23600, 0x23600, + 0x23608, 0x23628, + 0x23630, 0x2363c, + 0x23700, 0x2371c, + 0x23780, 0x2378c, + 0x23800, 0x23c38, + 0x23c80, 0x23d7c, + 0x23e00, 0x23e04, + 0x24000, 0x2402c, + 0x24100, 0x2413c, + 0x24190, 0x241c8, + 0x24200, 0x24318, + 0x24400, 0x24528, + 0x24540, 0x24614, + 0x25000, 0x25040, + 0x2504c, 0x25060, + 0x250c0, 0x250ec, + 0x25200, 0x25268, + 0x25270, 0x25284, + 0x252fc, 0x25388, + 0x25400, 0x25404, + 0x25500, 0x25518, + 0x2552c, 0x2553c, + 0x25550, 0x25554, + 0x25600, 0x25600, + 0x25608, 0x25628, + 0x25630, 0x2563c, + 0x25700, 0x2571c, + 0x25780, 0x2578c, + 0x25800, 0x25c38, + 0x25c80, 0x25d7c, + 0x25e00, 0x25e04, + 0x26000, 0x2602c, + 0x26100, 0x2613c, + 0x26190, 0x261c8, + 0x26200, 0x26318, + 0x26400, 0x26528, + 0x26540, 0x26614, + 0x27000, 0x27040, + 0x2704c, 0x27060, + 0x270c0, 0x270ec, + 0x27200, 0x27268, + 0x27270, 0x27284, + 0x272fc, 0x27388, + 0x27400, 0x27404, + 0x27500, 0x27518, + 0x2752c, 0x2753c, + 0x27550, 0x27554, + 0x27600, 0x27600, + 0x27608, 0x27628, + 0x27630, 0x2763c, + 0x27700, 0x2771c, + 0x27780, 0x2778c, + 0x27800, 0x27c38, + 0x27c80, 0x27d7c, + 0x27e00, 0x27e04 + }; + + static const unsigned int t5_reg_ranges[] = { + 0x1008, 0x1148, + 0x1180, 0x11b4, + 0x11fc, 0x123c, + 0x1280, 0x173c, + 0x1800, 0x18fc, + 0x3000, 0x3028, + 0x3060, 0x30d8, + 0x30e0, 0x30fc, + 0x3140, 0x357c, + 0x35a8, 0x35cc, + 0x35ec, 0x35ec, + 0x3600, 0x5624, + 0x56cc, 0x575c, + 0x580c, 0x5814, + 0x5890, 0x58bc, + 0x5940, 0x59dc, + 0x59fc, 0x5a18, + 0x5a60, 0x5a9c, + 0x5b9c, 0x5bfc, + 0x6000, 0x6040, + 0x6058, 0x614c, + 0x7700, 0x7798, + 0x77c0, 0x78fc, + 0x7b00, 0x7c54, + 0x7d00, 0x7efc, + 0x8dc0, 0x8de0, + 0x8df8, 0x8e84, + 0x8ea0, 0x8f84, + 0x8fc0, 0x90f8, + 0x9400, 0x9470, + 0x9600, 0x96f4, + 0x9800, 0x9808, + 0x9820, 0x983c, + 0x9850, 0x9864, + 0x9c00, 0x9c6c, + 0x9c80, 0x9cec, + 0x9d00, 0x9d6c, + 0x9d80, 0x9dec, + 0x9e00, 0x9e6c, + 0x9e80, 0x9eec, + 0x9f00, 0x9f6c, + 0x9f80, 0xa020, + 0xd004, 0xd03c, + 0xdfc0, 0xdfe0, + 0xe000, 0x11088, + 0x1109c, 0x11110, + 0x11118, 0x1117c, + 0x11190, 0x11204, + 0x19040, 0x1906c, + 0x19078, 0x19080, + 0x1908c, 0x19124, + 0x19150, 0x191b0, + 0x191d0, 0x191e8, + 0x19238, 0x19290, + 0x193f8, 0x19474, + 0x19490, 0x194cc, + 0x194f0, 0x194f8, + 0x19c00, 0x19c60, + 0x19c94, 0x19e10, + 0x19e50, 0x19f34, + 0x19f40, 0x19f50, + 0x19f90, 0x19fe4, + 0x1a000, 0x1a06c, + 0x1a0b0, 0x1a120, + 0x1a128, 0x1a138, + 0x1a190, 0x1a1c4, + 0x1a1fc, 0x1a1fc, + 0x1e008, 0x1e00c, + 0x1e040, 0x1e04c, + 0x1e284, 0x1e290, + 0x1e2c0, 0x1e2c0, + 0x1e2e0, 0x1e2e0, + 0x1e300, 0x1e384, + 0x1e3c0, 0x1e3c8, + 0x1e408, 0x1e40c, + 0x1e440, 0x1e44c, + 0x1e684, 0x1e690, + 0x1e6c0, 0x1e6c0, + 0x1e6e0, 0x1e6e0, + 0x1e700, 0x1e784, + 0x1e7c0, 0x1e7c8, + 0x1e808, 0x1e80c, + 0x1e840, 0x1e84c, + 0x1ea84, 0x1ea90, + 0x1eac0, 0x1eac0, + 0x1eae0, 0x1eae0, + 0x1eb00, 0x1eb84, + 0x1ebc0, 0x1ebc8, + 0x1ec08, 0x1ec0c, + 0x1ec40, 0x1ec4c, + 0x1ee84, 0x1ee90, + 0x1eec0, 0x1eec0, + 0x1eee0, 0x1eee0, + 0x1ef00, 0x1ef84, + 0x1efc0, 0x1efc8, + 0x1f008, 0x1f00c, + 0x1f040, 0x1f04c, + 0x1f284, 0x1f290, + 0x1f2c0, 0x1f2c0, + 0x1f2e0, 0x1f2e0, + 0x1f300, 0x1f384, + 0x1f3c0, 0x1f3c8, + 0x1f408, 0x1f40c, + 0x1f440, 0x1f44c, + 0x1f684, 0x1f690, + 0x1f6c0, 0x1f6c0, + 0x1f6e0, 0x1f6e0, + 0x1f700, 0x1f784, + 0x1f7c0, 0x1f7c8, + 0x1f808, 0x1f80c, + 0x1f840, 0x1f84c, + 0x1fa84, 0x1fa90, + 0x1fac0, 0x1fac0, + 0x1fae0, 0x1fae0, + 0x1fb00, 0x1fb84, + 0x1fbc0, 0x1fbc8, + 0x1fc08, 0x1fc0c, + 0x1fc40, 0x1fc4c, + 0x1fe84, 0x1fe90, + 0x1fec0, 0x1fec0, + 0x1fee0, 0x1fee0, + 0x1ff00, 0x1ff84, + 0x1ffc0, 0x1ffc8, + 0x30000, 0x30030, + 0x30100, 0x30144, + 0x30190, 0x301d0, + 0x30200, 0x30318, + 0x30400, 0x3052c, + 0x30540, 0x3061c, + 0x30800, 0x30834, + 0x308c0, 0x30908, + 0x30910, 0x309ac, + 0x30a00, 0x30a04, + 0x30a0c, 0x30a2c, + 0x30a44, 0x30a50, + 0x30a74, 0x30c24, + 0x30d08, 0x30d14, + 0x30d1c, 0x30d20, + 0x30d3c, 0x30d50, + 0x31200, 0x3120c, + 0x31220, 0x31220, + 0x31240, 0x31240, + 0x31600, 0x31600, + 0x31608, 0x3160c, + 0x31a00, 0x31a1c, + 0x31e04, 0x31e20, + 0x31e38, 0x31e3c, + 0x31e80, 0x31e80, + 0x31e88, 0x31ea8, + 0x31eb0, 0x31eb4, + 0x31ec8, 0x31ed4, + 0x31fb8, 0x32004, + 0x32208, 0x3223c, + 0x32600, 0x32630, + 0x32a00, 0x32abc, + 0x32b00, 0x32b70, + 0x33000, 0x33048, + 0x33060, 0x3309c, + 0x330f0, 0x33148, + 0x33160, 0x3319c, + 0x331f0, 0x332e4, + 0x332f8, 0x333e4, + 0x333f8, 0x33448, + 0x33460, 0x3349c, + 0x334f0, 0x33548, + 0x33560, 0x3359c, + 0x335f0, 0x336e4, + 0x336f8, 0x337e4, + 0x337f8, 0x337fc, + 0x33814, 0x33814, + 0x3382c, 0x3382c, + 0x33880, 0x3388c, + 0x338e8, 0x338ec, + 0x33900, 0x33948, + 0x33960, 0x3399c, + 0x339f0, 0x33ae4, + 0x33af8, 0x33b10, + 0x33b28, 0x33b28, + 0x33b3c, 0x33b50, + 0x33bf0, 0x33c10, + 0x33c28, 0x33c28, + 0x33c3c, 0x33c50, + 0x33cf0, 0x33cfc, + 0x34000, 0x34030, + 0x34100, 0x34144, + 0x34190, 0x341d0, + 0x34200, 0x34318, + 0x34400, 0x3452c, + 0x34540, 0x3461c, + 0x34800, 0x34834, + 0x348c0, 0x34908, + 0x34910, 0x349ac, + 0x34a00, 0x34a04, + 0x34a0c, 0x34a2c, + 0x34a44, 0x34a50, + 0x34a74, 0x34c24, + 0x34d08, 0x34d14, + 0x34d1c, 0x34d20, + 0x34d3c, 0x34d50, + 0x35200, 0x3520c, + 0x35220, 0x35220, + 0x35240, 0x35240, + 0x35600, 0x35600, + 0x35608, 0x3560c, + 0x35a00, 0x35a1c, + 0x35e04, 0x35e20, + 0x35e38, 0x35e3c, + 0x35e80, 0x35e80, + 0x35e88, 0x35ea8, + 0x35eb0, 0x35eb4, + 0x35ec8, 0x35ed4, + 0x35fb8, 0x36004, + 0x36208, 0x3623c, + 0x36600, 0x36630, + 0x36a00, 0x36abc, + 0x36b00, 0x36b70, + 0x37000, 0x37048, + 0x37060, 0x3709c, + 0x370f0, 0x37148, + 0x37160, 0x3719c, + 0x371f0, 0x372e4, + 0x372f8, 0x373e4, + 0x373f8, 0x37448, + 0x37460, 0x3749c, + 0x374f0, 0x37548, + 0x37560, 0x3759c, + 0x375f0, 0x376e4, + 0x376f8, 0x377e4, + 0x377f8, 0x377fc, + 0x37814, 0x37814, + 0x3782c, 0x3782c, + 0x37880, 0x3788c, + 0x378e8, 0x378ec, + 0x37900, 0x37948, + 0x37960, 0x3799c, + 0x379f0, 0x37ae4, + 0x37af8, 0x37b10, + 0x37b28, 0x37b28, + 0x37b3c, 0x37b50, + 0x37bf0, 0x37c10, + 0x37c28, 0x37c28, + 0x37c3c, 0x37c50, + 0x37cf0, 0x37cfc, + 0x38000, 0x38030, + 0x38100, 0x38144, + 0x38190, 0x381d0, + 0x38200, 0x38318, + 0x38400, 0x3852c, + 0x38540, 0x3861c, + 0x38800, 0x38834, + 0x388c0, 0x38908, + 0x38910, 0x389ac, + 0x38a00, 0x38a04, + 0x38a0c, 0x38a2c, + 0x38a44, 0x38a50, + 0x38a74, 0x38c24, + 0x38d08, 0x38d14, + 0x38d1c, 0x38d20, + 0x38d3c, 0x38d50, + 0x39200, 0x3920c, + 0x39220, 0x39220, + 0x39240, 0x39240, + 0x39600, 0x39600, + 0x39608, 0x3960c, + 0x39a00, 0x39a1c, + 0x39e04, 0x39e20, + 0x39e38, 0x39e3c, + 0x39e80, 0x39e80, + 0x39e88, 0x39ea8, + 0x39eb0, 0x39eb4, + 0x39ec8, 0x39ed4, + 0x39fb8, 0x3a004, + 0x3a208, 0x3a23c, + 0x3a600, 0x3a630, + 0x3aa00, 0x3aabc, + 0x3ab00, 0x3ab70, + 0x3b000, 0x3b048, + 0x3b060, 0x3b09c, + 0x3b0f0, 0x3b148, + 0x3b160, 0x3b19c, + 0x3b1f0, 0x3b2e4, + 0x3b2f8, 0x3b3e4, + 0x3b3f8, 0x3b448, + 0x3b460, 0x3b49c, + 0x3b4f0, 0x3b548, + 0x3b560, 0x3b59c, + 0x3b5f0, 0x3b6e4, + 0x3b6f8, 0x3b7e4, + 0x3b7f8, 0x3b7fc, + 0x3b814, 0x3b814, + 0x3b82c, 0x3b82c, + 0x3b880, 0x3b88c, + 0x3b8e8, 0x3b8ec, + 0x3b900, 0x3b948, + 0x3b960, 0x3b99c, + 0x3b9f0, 0x3bae4, + 0x3baf8, 0x3bb10, + 0x3bb28, 0x3bb28, + 0x3bb3c, 0x3bb50, + 0x3bbf0, 0x3bc10, + 0x3bc28, 0x3bc28, + 0x3bc3c, 0x3bc50, + 0x3bcf0, 0x3bcfc, + 0x3c000, 0x3c030, + 0x3c100, 0x3c144, + 0x3c190, 0x3c1d0, + 0x3c200, 0x3c318, + 0x3c400, 0x3c52c, + 0x3c540, 0x3c61c, + 0x3c800, 0x3c834, + 0x3c8c0, 0x3c908, + 0x3c910, 0x3c9ac, + 0x3ca00, 0x3ca04, + 0x3ca0c, 0x3ca2c, + 0x3ca44, 0x3ca50, + 0x3ca74, 0x3cc24, + 0x3cd08, 0x3cd14, + 0x3cd1c, 0x3cd20, + 0x3cd3c, 0x3cd50, + 0x3d200, 0x3d20c, + 0x3d220, 0x3d220, + 0x3d240, 0x3d240, + 0x3d600, 0x3d600, + 0x3d608, 0x3d60c, + 0x3da00, 0x3da1c, + 0x3de04, 0x3de20, + 0x3de38, 0x3de3c, + 0x3de80, 0x3de80, + 0x3de88, 0x3dea8, + 0x3deb0, 0x3deb4, + 0x3dec8, 0x3ded4, + 0x3dfb8, 0x3e004, + 0x3e208, 0x3e23c, + 0x3e600, 0x3e630, + 0x3ea00, 0x3eabc, + 0x3eb00, 0x3eb70, + 0x3f000, 0x3f048, + 0x3f060, 0x3f09c, + 0x3f0f0, 0x3f148, + 0x3f160, 0x3f19c, + 0x3f1f0, 0x3f2e4, + 0x3f2f8, 0x3f3e4, + 0x3f3f8, 0x3f448, + 0x3f460, 0x3f49c, + 0x3f4f0, 0x3f548, + 0x3f560, 0x3f59c, + 0x3f5f0, 0x3f6e4, + 0x3f6f8, 0x3f7e4, + 0x3f7f8, 0x3f7fc, + 0x3f814, 0x3f814, + 0x3f82c, 0x3f82c, + 0x3f880, 0x3f88c, + 0x3f8e8, 0x3f8ec, + 0x3f900, 0x3f948, + 0x3f960, 0x3f99c, + 0x3f9f0, 0x3fae4, + 0x3faf8, 0x3fb10, + 0x3fb28, 0x3fb28, + 0x3fb3c, 0x3fb50, + 0x3fbf0, 0x3fc10, + 0x3fc28, 0x3fc28, + 0x3fc3c, 0x3fc50, + 0x3fcf0, 0x3fcfc, + 0x40000, 0x4000c, + 0x40040, 0x40068, + 0x40080, 0x40144, + 0x40180, 0x4018c, + 0x40200, 0x40298, + 0x402ac, 0x4033c, + 0x403f8, 0x403fc, + 0x41304, 0x413c4, + 0x41400, 0x4141c, + 0x41480, 0x414d0, + 0x44000, 0x44078, + 0x440c0, 0x44278, + 0x442c0, 0x44478, + 0x444c0, 0x44678, + 0x446c0, 0x44878, + 0x448c0, 0x449fc, + 0x45000, 0x45068, + 0x45080, 0x45084, + 0x450a0, 0x450b0, + 0x45200, 0x45268, + 0x45280, 0x45284, + 0x452a0, 0x452b0, + 0x460c0, 0x460e4, + 0x47000, 0x4708c, + 0x47200, 0x47250, + 0x47400, 0x47420, + 0x47600, 0x47618, + 0x47800, 0x47814, + 0x48000, 0x4800c, + 0x48040, 0x48068, + 0x48080, 0x48144, + 0x48180, 0x4818c, + 0x48200, 0x48298, + 0x482ac, 0x4833c, + 0x483f8, 0x483fc, + 0x49304, 0x493c4, + 0x49400, 0x4941c, + 0x49480, 0x494d0, + 0x4c000, 0x4c078, + 0x4c0c0, 0x4c278, + 0x4c2c0, 0x4c478, + 0x4c4c0, 0x4c678, + 0x4c6c0, 0x4c878, + 0x4c8c0, 0x4c9fc, + 0x4d000, 0x4d068, + 0x4d080, 0x4d084, + 0x4d0a0, 0x4d0b0, + 0x4d200, 0x4d268, + 0x4d280, 0x4d284, + 0x4d2a0, 0x4d2b0, + 0x4e0c0, 0x4e0e4, + 0x4f000, 0x4f08c, + 0x4f200, 0x4f250, + 0x4f400, 0x4f420, + 0x4f600, 0x4f618, + 0x4f800, 0x4f814, + 0x50000, 0x500cc, + 0x50400, 0x50400, + 0x50800, 0x508cc, + 0x50c00, 0x50c00, + 0x51000, 0x5101c, + 0x51300, 0x51308, + }; + + u32 *buf_end = (u32 *)((char *)buf + buf_size); + const unsigned int *reg_ranges; + int reg_ranges_size, range; + unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); + + /* Select the right set of register ranges to dump depending on the + * adapter chip type. + */ + switch (chip_version) { + case CHELSIO_T4: + reg_ranges = t4_reg_ranges; + reg_ranges_size = ARRAY_SIZE(t4_reg_ranges); + break; + + case CHELSIO_T5: + reg_ranges = t5_reg_ranges; + reg_ranges_size = ARRAY_SIZE(t5_reg_ranges); + break; + + default: + dev_err(adap->pdev_dev, + "Unsupported chip version %d\n", chip_version); + return; + } + + /* Clear the register buffer and insert the appropriate register + * values selected by the above register ranges. + */ + memset(buf, 0, buf_size); + for (range = 0; range < reg_ranges_size; range += 2) { + unsigned int reg = reg_ranges[range]; + unsigned int last_reg = reg_ranges[range + 1]; + u32 *bufp = (u32 *)((char *)buf + reg); + + /* Iterate across the register range filling in the register + * buffer but don't write past the end of the register buffer. + */ + while (reg <= last_reg && bufp < buf_end) { + *bufp++ = t4_read_reg(adap, reg); + reg += sizeof(u32); + } + } +} + #define EEPROM_STAT_ADDR 0x7bfc #define VPD_BASE 0x400 #define VPD_BASE_OLD 0 From 7f9b838b71eb78a27de27a12ca5de8542fac3115 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 6 Apr 2015 14:37:26 -0700 Subject: [PATCH 563/567] tcp: RFC7413 option support for Fast Open server Fast Open has been using the experimental option with a magic number (RFC6994) to request and grant Fast Open cookies. This patch enables the server to support the official IANA option 34 in RFC7413 in addition. The change has passed all existing Fast Open tests with both old and new options at Google. Signed-off-by: Daniel Lee Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller --- include/linux/tcp.h | 1 + include/net/tcp.h | 2 ++ net/ipv4/tcp_fastopen.c | 1 + net/ipv4/tcp_input.c | 42 +++++++++++++++++++++++++++++------------ net/ipv4/tcp_output.c | 34 ++++++++++++++++++++++----------- 5 files changed, 57 insertions(+), 23 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index f869ae8afbaf..a48d00318683 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -58,6 +58,7 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb) struct tcp_fastopen_cookie { s8 len; u8 val[TCP_FASTOPEN_COOKIE_MAX]; + bool exp; /* In RFC6994 experimental option format */ }; /* This defines a selective acknowledgement block. */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 963303fb96ae..7292c3c575bc 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -179,6 +179,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOPT_SACK 5 /* SACK Block */ #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ +#define TCPOPT_FASTOPEN 34 /* Fast open (RFC7413) */ #define TCPOPT_EXP 254 /* Experimental */ /* Magic number to be after the option value for sharing TCP * experimental options. See draft-ietf-tcpm-experimental-options-00.txt @@ -194,6 +195,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); #define TCPOLEN_SACK_PERM 2 #define TCPOLEN_TIMESTAMP 10 #define TCPOLEN_MD5SIG 18 +#define TCPOLEN_FASTOPEN_BASE 2 #define TCPOLEN_EXP_FASTOPEN_BASE 4 /* But this is what stacks really send out. */ diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 5da55e2b5cd2..e3d87aca6be8 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -303,6 +303,7 @@ fastopen: } else if (foc->len > 0) /* Client presents an invalid cookie */ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENPASSIVEFAIL); + valid_foc.exp = foc->exp; *foc = valid_foc; return false; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c1ce304ba8d2..24f1630b2afb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3603,6 +3603,23 @@ old_ack: return 0; } +static void tcp_parse_fastopen_option(int len, const unsigned char *cookie, + bool syn, struct tcp_fastopen_cookie *foc, + bool exp_opt) +{ + /* Valid only in SYN or SYN-ACK with an even length. */ + if (!foc || !syn || len < 0 || (len & 1)) + return; + + if (len >= TCP_FASTOPEN_COOKIE_MIN && + len <= TCP_FASTOPEN_COOKIE_MAX) + memcpy(foc->val, cookie, len); + else if (len != 0) + len = -1; + foc->len = len; + foc->exp = exp_opt; +} + /* Look for tcp options. Normally only called on SYN and SYNACK packets. * But, this can also be called on packets in the established flow when * the fast version below fails. @@ -3692,21 +3709,22 @@ void tcp_parse_options(const struct sk_buff *skb, */ break; #endif + case TCPOPT_FASTOPEN: + tcp_parse_fastopen_option( + opsize - TCPOLEN_FASTOPEN_BASE, + ptr, th->syn, foc, false); + break; + case TCPOPT_EXP: /* Fast Open option shares code 254 using a - * 16 bits magic number. It's valid only in - * SYN or SYN-ACK with an even size. + * 16 bits magic number. */ - if (opsize < TCPOLEN_EXP_FASTOPEN_BASE || - get_unaligned_be16(ptr) != TCPOPT_FASTOPEN_MAGIC || - !foc || !th->syn || (opsize & 1)) - break; - foc->len = opsize - TCPOLEN_EXP_FASTOPEN_BASE; - if (foc->len >= TCP_FASTOPEN_COOKIE_MIN && - foc->len <= TCP_FASTOPEN_COOKIE_MAX) - memcpy(foc->val, ptr + 2, foc->len); - else if (foc->len != 0) - foc->len = -1; + if (opsize >= TCPOLEN_EXP_FASTOPEN_BASE && + get_unaligned_be16(ptr) == + TCPOPT_FASTOPEN_MAGIC) + tcp_parse_fastopen_option(opsize - + TCPOLEN_EXP_FASTOPEN_BASE, + ptr + 2, th->syn, foc, true); break; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7404e5238e00..464bd8c5de69 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -518,17 +518,26 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, if (unlikely(OPTION_FAST_OPEN_COOKIE & options)) { struct tcp_fastopen_cookie *foc = opts->fastopen_cookie; + u8 *p = (u8 *)ptr; + u32 len; /* Fast Open option length */ - *ptr++ = htonl((TCPOPT_EXP << 24) | - ((TCPOLEN_EXP_FASTOPEN_BASE + foc->len) << 16) | - TCPOPT_FASTOPEN_MAGIC); - - memcpy(ptr, foc->val, foc->len); - if ((foc->len & 3) == 2) { - u8 *align = ((u8 *)ptr) + foc->len; - align[0] = align[1] = TCPOPT_NOP; + if (foc->exp) { + len = TCPOLEN_EXP_FASTOPEN_BASE + foc->len; + *ptr = htonl((TCPOPT_EXP << 24) | (len << 16) | + TCPOPT_FASTOPEN_MAGIC); + p += TCPOLEN_EXP_FASTOPEN_BASE; + } else { + len = TCPOLEN_FASTOPEN_BASE + foc->len; + *p++ = TCPOPT_FASTOPEN; + *p++ = len; } - ptr += (foc->len + 3) >> 2; + + memcpy(p, foc->val, foc->len); + if ((len & 3) == 2) { + p[foc->len] = TCPOPT_NOP; + p[foc->len + 1] = TCPOPT_NOP; + } + ptr += (len + 3) >> 2; } } @@ -641,8 +650,11 @@ static unsigned int tcp_synack_options(struct sock *sk, if (unlikely(!ireq->tstamp_ok)) remaining -= TCPOLEN_SACKPERM_ALIGNED; } - if (foc && foc->len >= 0) { - u32 need = TCPOLEN_EXP_FASTOPEN_BASE + foc->len; + if (foc != NULL && foc->len >= 0) { + u32 need = foc->len; + + need += foc->exp ? TCPOLEN_EXP_FASTOPEN_BASE : + TCPOLEN_FASTOPEN_BASE; need = (need + 3) & ~3U; /* Align to 32 bits */ if (remaining >= need) { opts->options |= OPTION_FAST_OPEN_COOKIE; From 2646c831c00c5d22aa72b79d24069c1b412cda7c Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Mon, 6 Apr 2015 14:37:27 -0700 Subject: [PATCH 564/567] tcp: RFC7413 option support for Fast Open client Fast Open has been using an experimental option with a magic number (RFC6994). This patch makes the client by default use the RFC7413 option (34) to get and send Fast Open cookies. This patch makes the client solicit cookies from a given server first with the RFC7413 option. If that fails to elicit a cookie, then it tries the RFC6994 experimental option. If that also fails, it uses the RFC7413 option on all subsequent connect attempts. If the server returns a Fast Open cookie then the client caches the form of the option that successfully elicited a cookie, and uses that form on later connects when it presents that cookie. The idea is to gradually obsolete the use of experimental options as the servers and clients upgrade, while keeping the interoperability meanwhile. Signed-off-by: Daniel Lee Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller --- include/linux/tcp.h | 1 + include/net/tcp.h | 3 ++- net/ipv4/tcp_input.c | 29 +++++++++++++++++++---------- net/ipv4/tcp_metrics.c | 13 +++++++++++-- net/ipv4/tcp_output.c | 6 +++++- net/ipv4/tcp_timer.c | 2 +- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index a48d00318683..0caa3a2d4106 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -189,6 +189,7 @@ struct tcp_sock { u8 do_early_retrans:1,/* Enable RFC5827 early-retransmit */ syn_data:1, /* SYN includes data */ syn_fastopen:1, /* SYN includes Fast Open option */ + syn_fastopen_exp:1,/* SYN includes Fast Open exp. option */ syn_data_acked:1,/* data in SYN is acked by SYN-ACK */ is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */ u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 7292c3c575bc..9598871485ce 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1339,7 +1339,8 @@ void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, struct tcp_fastopen_cookie *cookie, int *syn_loss, unsigned long *last_syn_loss); void tcp_fastopen_cache_set(struct sock *sk, u16 mss, - struct tcp_fastopen_cookie *cookie, bool syn_lost); + struct tcp_fastopen_cookie *cookie, bool syn_lost, + u16 try_exp); struct tcp_fastopen_request { /* Fast Open cookie. Size 0 means a cookie request */ struct tcp_fastopen_cookie cookie; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 24f1630b2afb..031cf72cd05c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5378,8 +5378,8 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *data = tp->syn_data ? tcp_write_queue_head(sk) : NULL; - u16 mss = tp->rx_opt.mss_clamp; - bool syn_drop; + u16 mss = tp->rx_opt.mss_clamp, try_exp = 0; + bool syn_drop = false; if (mss == tp->rx_opt.user_mss) { struct tcp_options_received opt; @@ -5391,16 +5391,25 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, mss = opt.mss_clamp; } - if (!tp->syn_fastopen) /* Ignore an unsolicited cookie */ + if (!tp->syn_fastopen) { + /* Ignore an unsolicited cookie */ cookie->len = -1; + } else if (tp->total_retrans) { + /* SYN timed out and the SYN-ACK neither has a cookie nor + * acknowledges data. Presumably the remote received only + * the retransmitted (regular) SYNs: either the original + * SYN-data or the corresponding SYN-ACK was dropped. + */ + syn_drop = (cookie->len < 0 && data); + } else if (cookie->len < 0 && !tp->syn_data) { + /* We requested a cookie but didn't get it. If we did not use + * the (old) exp opt format then try so next time (try_exp=1). + * Otherwise we go back to use the RFC7413 opt (try_exp=2). + */ + try_exp = tp->syn_fastopen_exp ? 2 : 1; + } - /* The SYN-ACK neither has cookie nor acknowledges the data. Presumably - * the remote receives only the retransmitted (regular) SYNs: either - * the original SYN-data or the corresponding SYN-ACK is lost. - */ - syn_drop = (cookie->len <= 0 && data && tp->total_retrans); - - tcp_fastopen_cache_set(sk, mss, cookie, syn_drop); + tcp_fastopen_cache_set(sk, mss, cookie, syn_drop, try_exp); if (data) { /* Retransmit unacked data in SYN */ tcp_for_write_queue_from(data, sk) { diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 78ecc4a01712..a51d63a43e33 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -28,7 +28,8 @@ static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *s struct tcp_fastopen_metrics { u16 mss; - u16 syn_loss:10; /* Recurring Fast Open SYN losses */ + u16 syn_loss:10, /* Recurring Fast Open SYN losses */ + try_exp:2; /* Request w/ exp. option (once) */ unsigned long last_syn_loss; /* Last Fast Open SYN loss */ struct tcp_fastopen_cookie cookie; }; @@ -131,6 +132,8 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, if (fastopen_clear) { tm->tcpm_fastopen.mss = 0; tm->tcpm_fastopen.syn_loss = 0; + tm->tcpm_fastopen.try_exp = 0; + tm->tcpm_fastopen.cookie.exp = false; tm->tcpm_fastopen.cookie.len = 0; } } @@ -713,6 +716,8 @@ void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, if (tfom->mss) *mss = tfom->mss; *cookie = tfom->cookie; + if (cookie->len <= 0 && tfom->try_exp == 1) + cookie->exp = true; *syn_loss = tfom->syn_loss; *last_syn_loss = *syn_loss ? tfom->last_syn_loss : 0; } while (read_seqretry(&fastopen_seqlock, seq)); @@ -721,7 +726,8 @@ void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, } void tcp_fastopen_cache_set(struct sock *sk, u16 mss, - struct tcp_fastopen_cookie *cookie, bool syn_lost) + struct tcp_fastopen_cookie *cookie, bool syn_lost, + u16 try_exp) { struct dst_entry *dst = __sk_dst_get(sk); struct tcp_metrics_block *tm; @@ -738,6 +744,9 @@ void tcp_fastopen_cache_set(struct sock *sk, u16 mss, tfom->mss = mss; if (cookie && cookie->len > 0) tfom->cookie = *cookie; + else if (try_exp > tfom->try_exp && + tfom->cookie.len <= 0 && !tfom->cookie.exp) + tfom->try_exp = try_exp; if (syn_lost) { ++tfom->syn_loss; tfom->last_syn_loss = jiffies; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 464bd8c5de69..e662d85d1635 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -592,13 +592,17 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb, } if (fastopen && fastopen->cookie.len >= 0) { - u32 need = TCPOLEN_EXP_FASTOPEN_BASE + fastopen->cookie.len; + u32 need = fastopen->cookie.len; + + need += fastopen->cookie.exp ? TCPOLEN_EXP_FASTOPEN_BASE : + TCPOLEN_FASTOPEN_BASE; need = (need + 3) & ~3U; /* Align to 32 bits */ if (remaining >= need) { opts->options |= OPTION_FAST_OPEN_COOKIE; opts->fastopen_cookie = &fastopen->cookie; remaining -= need; tp->syn_fastopen = 1; + tp->syn_fastopen_exp = fastopen->cookie.exp ? 1 : 0; } } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 2568fd282873..8c65dc147d8b 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -167,7 +167,7 @@ static int tcp_write_timeout(struct sock *sk) if (icsk->icsk_retransmits) { dst_negative_advice(sk); if (tp->syn_fastopen || tp->syn_data) - tcp_fastopen_cache_set(sk, 0, NULL, true); + tcp_fastopen_cache_set(sk, 0, NULL, true, 0); if (tp->syn_data) NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVEFAIL); From 0d158852a8089099a6959ae235b20f230871982f Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 6 Apr 2015 15:22:52 -0700 Subject: [PATCH 565/567] hv_netvsc: Clean up two unused variables Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 1 - drivers/net/hyperv/netvsc.c | 1 - drivers/net/hyperv/rndis_filter.c | 2 -- 3 files changed, 4 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 309adee6e791..95a25e4b2601 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -130,7 +130,6 @@ struct hv_netvsc_packet { u32 status; bool part_of_skb; - struct hv_device *device; bool is_data_pkt; bool xmit_more; /* from skb */ u16 vlan_tci; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index f69923695b5b..7e83c6ad4bb5 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1011,7 +1011,6 @@ static void netvsc_receive(struct netvsc_device *net_device, } count = vmxferpage_packet->range_cnt; - netvsc_packet->device = device; netvsc_packet->channel = channel; /* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */ diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index a1604376aee1..0d92efefd796 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -47,8 +47,6 @@ struct rndis_request { /* Simplify allocation by having a netvsc packet inline */ struct hv_netvsc_packet pkt; - /* Set 2 pages for rndis requests crossing page boundary */ - struct hv_page_buffer buf[2]; struct rndis_message request_msg; /* From 721514222db13498613706709409c21c105e0f4a Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 6 Apr 2015 15:22:53 -0700 Subject: [PATCH 566/567] hv_netvsc: Define a macro RNDIS_AND_PPI_SIZE The sum of RNDIS msg and PPI struct sizes is used in multiple places, so we define a macro for them. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 6 ++++++ drivers/net/hyperv/netvsc_drv.c | 15 +++------------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 95a25e4b2601..80bc52eb000c 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -958,6 +958,10 @@ struct ndis_tcp_lso_info { #define NDIS_HASH_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ sizeof(u32)) +/* Total size of all PPI data */ +#define NDIS_ALL_PPI_SIZE (NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE + \ + NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE) + /* Format of Information buffer passed in a SetRequest for the OID */ /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ struct rndis_config_parameter_info { @@ -1170,6 +1174,8 @@ struct rndis_message { #define RNDIS_HEADER_SIZE (sizeof(struct rndis_message) - \ sizeof(union rndis_message_container)) +#define RNDIS_AND_PPI_SIZE (sizeof(struct rndis_message) + NDIS_ALL_PPI_SIZE) + #define NDIS_PACKET_TYPE_DIRECTED 0x00000001 #define NDIS_PACKET_TYPE_MULTICAST 0x00000002 #define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index f9db6bc513e9..73f8fba62a52 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -401,10 +401,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) return NETDEV_TX_OK; } - pkt_sz = sizeof(struct hv_netvsc_packet) + - sizeof(struct rndis_message) + - NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE + - NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE; + pkt_sz = sizeof(struct hv_netvsc_packet) + RNDIS_AND_PPI_SIZE; if (head_room < pkt_sz) { packet = kmalloc(pkt_sz, GFP_ATOMIC); @@ -436,11 +433,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->rndis_msg = (struct rndis_message *)((unsigned long)packet + sizeof(struct hv_netvsc_packet)); - memset(packet->rndis_msg, 0, sizeof(struct rndis_message) + - NDIS_VLAN_PPI_SIZE + - NDIS_CSUM_PPI_SIZE + - NDIS_LSO_PPI_SIZE + - NDIS_HASH_PPI_SIZE); + memset(packet->rndis_msg, 0, RNDIS_AND_PPI_SIZE); /* Set the completion routine */ packet->send_completion = netvsc_xmit_completion; @@ -872,9 +865,7 @@ static int netvsc_probe(struct hv_device *dev, return -ENOMEM; max_needed_headroom = sizeof(struct hv_netvsc_packet) + - sizeof(struct rndis_message) + - NDIS_VLAN_PPI_SIZE + NDIS_CSUM_PPI_SIZE + - NDIS_LSO_PPI_SIZE + NDIS_HASH_PPI_SIZE; + RNDIS_AND_PPI_SIZE; netif_carrier_off(net); From ee90b81203a91d4e5385622811ee7872b5bcfe76 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 6 Apr 2015 15:22:54 -0700 Subject: [PATCH 567/567] hv_netvsc: Fix the packet free when it is in skb headroom In the two places changed, we now use netvsc_xmit_completion() which properly frees hv_netvsc_packet in or not in skb headroom. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 1 + drivers/net/hyperv/netvsc.c | 6 ++++-- drivers/net/hyperv/netvsc_drv.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 80bc52eb000c..f0b8b3e0ed7c 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -188,6 +188,7 @@ int netvsc_send(struct hv_device *device, struct hv_netvsc_packet *packet); void netvsc_linkstatus_callback(struct hv_device *device_obj, struct rndis_message *resp); +void netvsc_xmit_completion(void *context); int netvsc_recv_callback(struct hv_device *device_obj, struct hv_netvsc_packet *packet, struct ndis_tcp_ip_checksum_info *csum_info); diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 7e83c6ad4bb5..4d4d497d5762 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -878,7 +878,9 @@ int netvsc_send(struct hv_device *device, packet->send_buf_index = section_index; packet->total_data_buflen += msd_len; - kfree(msdp->pkt); + if (msdp->pkt) + netvsc_xmit_completion(msdp->pkt); + if (packet->xmit_more) { msdp->pkt = packet; msdp->count++; @@ -902,7 +904,7 @@ int netvsc_send(struct hv_device *device, if (m_ret != 0) { netvsc_free_send_slot(net_device, msd_send->send_buf_index); - kfree(msd_send); + netvsc_xmit_completion(msd_send); } } diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 73f8fba62a52..e5fa094e6fe2 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -229,7 +229,7 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb, return q_idx; } -static void netvsc_xmit_completion(void *context) +void netvsc_xmit_completion(void *context) { struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; struct sk_buff *skb = (struct sk_buff *)