From c27602086d08d22b067a1267e09fb32b4b096aa0 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 10 Jul 2014 23:36:29 +0200 Subject: PCI: mvebu: Remove ARCH_KIRKWOOD dependency mach-kirkwood has been removed, now that kirkwood lives in mach-mvebu. ARCH_MVEBU is sufficient. Signed-off-by: Andrew Lunn Signed-off-by: Bjorn Helgaas Acked-by: Jason Cooper --- drivers/pci/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 21df477..88f4862 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -3,7 +3,7 @@ menu "PCI host controller drivers" config PCI_MVEBU bool "Marvell EBU PCIe controller" - depends on ARCH_MVEBU || ARCH_DOVE || ARCH_KIRKWOOD + depends on ARCH_MVEBU || ARCH_DOVE depends on OF config PCIE_DW -- cgit v1.1 From 2cb989f6e99aa84997961fcef516e5cd123b9a78 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 22 Jul 2014 12:30:46 -0600 Subject: PCI: tegra: Add debugfs support Provide a debugfs file ("pcie/ports") that shows the current link status for each root port. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas Reviewed-by: Stephen Warren --- drivers/pci/host/pci-tegra.c | 118 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index c284e84..869a921 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -277,6 +278,7 @@ struct tegra_pcie { struct regulator *avdd_supply; const struct tegra_pcie_soc_data *soc_data; + struct dentry *debugfs; }; struct tegra_pcie_port { @@ -1638,6 +1640,115 @@ static const struct of_device_id tegra_pcie_of_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_pcie_of_match); +static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos) +{ + struct tegra_pcie *pcie = s->private; + + if (list_empty(&pcie->ports)) + return NULL; + + seq_printf(s, "Index Status\n"); + + return seq_list_start(&pcie->ports, *pos); +} + +static void *tegra_pcie_ports_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct tegra_pcie *pcie = s->private; + + return seq_list_next(v, &pcie->ports, pos); +} + +static void tegra_pcie_ports_seq_stop(struct seq_file *s, void *v) +{ +} + +static int tegra_pcie_ports_seq_show(struct seq_file *s, void *v) +{ + bool up = false, active = false; + struct tegra_pcie_port *port; + unsigned int value; + + port = list_entry(v, struct tegra_pcie_port, list); + + value = readl(port->base + RP_VEND_XP); + + if (value & RP_VEND_XP_DL_UP) + up = true; + + value = readl(port->base + RP_LINK_CONTROL_STATUS); + + if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE) + active = true; + + seq_printf(s, "%2u ", port->index); + + if (up) + seq_printf(s, "up"); + + if (active) { + if (up) + seq_printf(s, ", "); + + seq_printf(s, "active"); + } + + seq_printf(s, "\n"); + return 0; +} + +static const struct seq_operations tegra_pcie_ports_seq_ops = { + .start = tegra_pcie_ports_seq_start, + .next = tegra_pcie_ports_seq_next, + .stop = tegra_pcie_ports_seq_stop, + .show = tegra_pcie_ports_seq_show, +}; + +static int tegra_pcie_ports_open(struct inode *inode, struct file *file) +{ + struct tegra_pcie *pcie = inode->i_private; + struct seq_file *s; + int err; + + err = seq_open(file, &tegra_pcie_ports_seq_ops); + if (err) + return err; + + s = file->private_data; + s->private = pcie; + + return 0; +} + +static const struct file_operations tegra_pcie_ports_ops = { + .owner = THIS_MODULE, + .open = tegra_pcie_ports_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int tegra_pcie_debugfs_init(struct tegra_pcie *pcie) +{ + struct dentry *file; + + pcie->debugfs = debugfs_create_dir("pcie", NULL); + if (!pcie->debugfs) + return -ENOMEM; + + file = debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs, + pcie, &tegra_pcie_ports_ops); + if (!file) + goto remove; + + return 0; + +remove: + debugfs_remove_recursive(pcie->debugfs); + pcie->debugfs = NULL; + return -ENOMEM; +} + static int tegra_pcie_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -1692,6 +1803,13 @@ static int tegra_pcie_probe(struct platform_device *pdev) goto disable_msi; } + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + err = tegra_pcie_debugfs_init(pcie); + if (err < 0) + dev_err(&pdev->dev, "failed to setup debugfs: %d\n", + err); + } + platform_set_drvdata(pdev, pcie); return 0; -- cgit v1.1 From 4dd964df36d0e548e1806ec2ec275b62d4dc46e8 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 17 Jul 2014 14:30:40 +0530 Subject: PCI: designware: Look for configuration space in 'reg', not 'ranges' The configuration address space has so far been specified in *ranges*, however it should be specified in *reg* making it a platform MEM resource. Hence used 'platform_get_resource_*' API to get configuration address space in the designware driver. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Bjorn Helgaas Acked-by: Mohit Kumar Acked-by: Jingoo Han Cc: Jason Gunthorpe Cc: Marek Vasut Cc: Arnd Bergmann --- .../devicetree/bindings/pci/designware-pcie.txt | 4 ++++ drivers/pci/host/pcie-designware.c | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt index d0d15ee..ed0d9b9 100644 --- a/Documentation/devicetree/bindings/pci/designware-pcie.txt +++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt @@ -2,6 +2,10 @@ Required properties: - compatible: should contain "snps,dw-pcie" to identify the core. +- reg: Should contain the configuration address space. +- reg-names: Must be "config" for the PCIe configuration space. + (The old way of getting the configuration address space from "ranges" + is deprecated and should be avoided.) - #address-cells: set to <3> - #size-cells: set to <2> - device_type: set to "pci" diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 1eaf4df..0b7b455 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "pcie-designware.h" @@ -396,11 +397,23 @@ static const struct irq_domain_ops msi_domain_ops = { int __init dw_pcie_host_init(struct pcie_port *pp) { struct device_node *np = pp->dev->of_node; + struct platform_device *pdev = to_platform_device(pp->dev); struct of_pci_range range; struct of_pci_range_parser parser; + struct resource *cfg_res; u32 val; int i; + cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); + if (cfg_res) { + pp->config.cfg0_size = resource_size(cfg_res)/2; + pp->config.cfg1_size = resource_size(cfg_res)/2; + pp->cfg0_base = cfg_res->start; + pp->cfg1_base = cfg_res->start + pp->config.cfg0_size; + } else { + dev_err(pp->dev, "missing *config* reg space\n"); + } + if (of_pci_range_parser_init(&parser, np)) { dev_err(pp->dev, "missing ranges property\n"); return -EINVAL; @@ -433,6 +446,8 @@ int __init dw_pcie_host_init(struct pcie_port *pp) of_pci_range_to_resource(&range, np, &pp->cfg); pp->config.cfg0_size = resource_size(&pp->cfg)/2; pp->config.cfg1_size = resource_size(&pp->cfg)/2; + pp->cfg0_base = pp->cfg.start; + pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size; } } @@ -445,8 +460,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp) } } - pp->cfg0_base = pp->cfg.start; - pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size; pp->mem_base = pp->mem.start; pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base, -- cgit v1.1 From f4c55c5a3f7f68c06cc559ed7af8b2d017cbb0a7 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 17 Jul 2014 14:30:41 +0530 Subject: PCI: designware: Program ATU with untranslated address In DRA7, the CPU sees 32-bit addresses, but the PCIe controller can see only 28-bit addresses. So whenever the CPU issues a read/write request, the 4 most significant bits are used by L3 to determine the target controller. For example, the CPU reserves [mem 0x20000000-0x2fffffff] for the PCIe controller but the PCIe controller will see only [0x00000000-0x0fffffff]. For programming the outbound translation window the *base* should be programmed as 0x00000000. Whenever we try to write to, e.g., 0x20000000, it will be translated to whatever we have programmed in the translation window with base as 0x00000000. This is needed when the dt node is modelled something like this: axi { compatible = "simple-bus"; #size-cells = <1>; #address-cells = <1>; ranges = <0x0 0x20000000 0x10000000 // 28-bit bus 0x51000000 0x51000000 0x3000>; pcie@51000000 { reg = <0x1000 0x2000>, <0x51002000 0x14c>, <0x51000000 0x2000>; reg-names = "config", "ti_conf", "rc_dbics"; #address-cells = <3>; #size-cells = <2>; ranges = <0x81000000 0 0 0x03000 0 0x00010000 0x82000000 0 0x20013000 0x13000 0 0xffed000>; }; }; Here the CPU address for configuration space is 0x20013000 and the controller address for configuration space is 0x13000. The controller address should be used while programming the ATU (in order for translation to happen properly in DRA7xx). Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Bjorn Helgaas Reviewed-by: Mohit Kumar Cc: Jason Gunthorpe Cc: Jingoo Han Cc: Marek Vasut Cc: Arnd Bergmann --- drivers/pci/host/pcie-designware.c | 55 ++++++++++++++++++++++++++++---------- drivers/pci/host/pcie-designware.h | 4 +++ 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 0b7b455..8aab1d6 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -401,8 +401,15 @@ int __init dw_pcie_host_init(struct pcie_port *pp) struct of_pci_range range; struct of_pci_range_parser parser; struct resource *cfg_res; - u32 val; - int i; + u32 val, na, ns; + const __be32 *addrp; + int i, index; + + /* Find the address cell size and the number of cells in order to get + * the untranslated address. + */ + of_property_read_u32(np, "#address-cells", &na); + ns = of_n_size_cells(np); cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); if (cfg_res) { @@ -410,6 +417,12 @@ int __init dw_pcie_host_init(struct pcie_port *pp) pp->config.cfg1_size = resource_size(cfg_res)/2; pp->cfg0_base = cfg_res->start; pp->cfg1_base = cfg_res->start + pp->config.cfg0_size; + + /* Find the untranslated configuration space address */ + index = of_property_match_string(np, "reg-names", "config"); + addrp = of_get_address(np, index, false, false); + pp->cfg0_mod_base = of_read_number(addrp, ns); + pp->cfg1_mod_base = pp->cfg0_mod_base + pp->config.cfg0_size; } else { dev_err(pp->dev, "missing *config* reg space\n"); } @@ -435,12 +448,20 @@ int __init dw_pcie_host_init(struct pcie_port *pp) pp->config.io_size = resource_size(&pp->io); pp->config.io_bus_addr = range.pci_addr; pp->io_base = range.cpu_addr; + + /* Find the untranslated IO space address */ + pp->io_mod_base = of_read_number(parser.range - + parser.np + na, ns); } if (restype == IORESOURCE_MEM) { of_pci_range_to_resource(&range, np, &pp->mem); pp->mem.name = "MEM"; pp->config.mem_size = resource_size(&pp->mem); pp->config.mem_bus_addr = range.pci_addr; + + /* Find the untranslated MEM space address */ + pp->mem_mod_base = of_read_number(parser.range - + parser.np + na, ns); } if (restype == 0) { of_pci_range_to_resource(&range, np, &pp->cfg); @@ -448,6 +469,12 @@ int __init dw_pcie_host_init(struct pcie_port *pp) pp->config.cfg1_size = resource_size(&pp->cfg)/2; pp->cfg0_base = pp->cfg.start; pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size; + + /* Find the untranslated configuration space address */ + pp->cfg0_mod_base = of_read_number(parser.range - + parser.np + na, ns); + pp->cfg1_mod_base = pp->cfg0_mod_base + + pp->config.cfg0_size; } } @@ -522,9 +549,9 @@ static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev) /* Program viewport 0 : OUTBOUND : CFG0 */ dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, PCIE_ATU_VIEWPORT); - dw_pcie_writel_rc(pp, pp->cfg0_base, PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, (pp->cfg0_base >> 32), PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, pp->cfg0_base + pp->config.cfg0_size - 1, + dw_pcie_writel_rc(pp, pp->cfg0_mod_base, PCIE_ATU_LOWER_BASE); + dw_pcie_writel_rc(pp, (pp->cfg0_mod_base >> 32), PCIE_ATU_UPPER_BASE); + dw_pcie_writel_rc(pp, pp->cfg0_mod_base + pp->config.cfg0_size - 1, PCIE_ATU_LIMIT); dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); @@ -538,9 +565,9 @@ static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev) dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, PCIE_ATU_VIEWPORT); dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, pp->cfg1_base, PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, (pp->cfg1_base >> 32), PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1, + dw_pcie_writel_rc(pp, pp->cfg1_mod_base, PCIE_ATU_LOWER_BASE); + dw_pcie_writel_rc(pp, (pp->cfg1_mod_base >> 32), PCIE_ATU_UPPER_BASE); + dw_pcie_writel_rc(pp, pp->cfg1_mod_base + pp->config.cfg1_size - 1, PCIE_ATU_LIMIT); dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); @@ -553,9 +580,9 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, PCIE_ATU_VIEWPORT); dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1, + dw_pcie_writel_rc(pp, pp->mem_mod_base, PCIE_ATU_LOWER_BASE); + dw_pcie_writel_rc(pp, (pp->mem_mod_base >> 32), PCIE_ATU_UPPER_BASE); + dw_pcie_writel_rc(pp, pp->mem_mod_base + pp->config.mem_size - 1, PCIE_ATU_LIMIT); dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr), @@ -569,9 +596,9 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, PCIE_ATU_VIEWPORT); dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE); - dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE); - dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1, + dw_pcie_writel_rc(pp, pp->io_mod_base, PCIE_ATU_LOWER_BASE); + dw_pcie_writel_rc(pp, (pp->io_mod_base >> 32), PCIE_ATU_UPPER_BASE); + dw_pcie_writel_rc(pp, pp->io_mod_base + pp->config.io_size - 1, PCIE_ATU_LIMIT); dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr), diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index 77f592f..add6527 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -36,11 +36,15 @@ struct pcie_port { u8 root_bus_nr; void __iomem *dbi_base; u64 cfg0_base; + u64 cfg0_mod_base; void __iomem *va_cfg0_base; u64 cfg1_base; + u64 cfg1_mod_base; void __iomem *va_cfg1_base; u64 io_base; + u64 io_mod_base; u64 mem_base; + u64 mem_mod_base; struct resource cfg; struct resource io; struct resource mem; -- cgit v1.1 From 47ff3de911a728cdf9ecc6ad777131902cff62b4 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 22 Jul 2014 15:23:45 -0600 Subject: PCI: dra7xx: Add TI DRA7xx PCIe driver Add support for PCIe controller in DRA7xx. This driver re-uses the designware core code that is already present in kernel. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Bjorn Helgaas Acked-by: Jingoo Han Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: Jason Gunthorpe Cc: Mohit Kumar Cc: Marek Vasut Cc: Arnd Bergmann --- Documentation/devicetree/bindings/pci/ti-pci.txt | 59 +++ MAINTAINERS | 8 + drivers/pci/host/Kconfig | 9 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pci-dra7xx.c | 458 +++++++++++++++++++++++ 5 files changed, 535 insertions(+) create mode 100644 Documentation/devicetree/bindings/pci/ti-pci.txt create mode 100644 drivers/pci/host/pci-dra7xx.c diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt b/Documentation/devicetree/bindings/pci/ti-pci.txt new file mode 100644 index 0000000..3d21791 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/ti-pci.txt @@ -0,0 +1,59 @@ +TI PCI Controllers + +PCIe Designware Controller + - compatible: Should be "ti,dra7-pcie"" + - reg : Two register ranges as listed in the reg-names property + - reg-names : The first entry must be "ti-conf" for the TI specific registers + The second entry must be "rc-dbics" for the designware pcie + registers + The third entry must be "config" for the PCIe configuration space + - phys : list of PHY specifiers (used by generic PHY framework) + - phy-names : must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the + number of PHYs as specified in *phys* property. + - ti,hwmods : Name of the hwmod associated to the pcie, "pcie", + where is the instance number of the pcie from the HW spec. + - interrupts : Two interrupt entries must be specified. The first one is for + main interrupt line and the second for MSI interrupt line. + - #address-cells, + #size-cells, + #interrupt-cells, + device_type, + ranges, + num-lanes, + interrupt-map-mask, + interrupt-map : as specified in ../designware-pcie.txt + +Example: +axi { + compatible = "simple-bus"; + #size-cells = <1>; + #address-cells = <1>; + ranges = <0x51000000 0x51000000 0x3000 + 0x0 0x20000000 0x10000000>; + pcie@51000000 { + compatible = "ti,dra7-pcie"; + reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>; + reg-names = "rc_dbics", "ti_conf", "config"; + interrupts = <0 232 0x4>, <0 233 0x4>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x03000 0 0x00010000 + 0x82000000 0 0x20013000 0x13000 0 0xffed000>; + #interrupt-cells = <1>; + num-lanes = <1>; + ti,hwmods = "pcie1"; + phys = <&pcie1_phy>; + phy-names = "pcie-phy0"; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc 1>, + <0 0 0 2 &pcie_intc 2>, + <0 0 0 3 &pcie_intc 3>, + <0 0 0 4 &pcie_intc 4>; + pcie_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index 134483f..fdd34d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6796,6 +6796,14 @@ S: Supported F: Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt F: drivers/pci/host/pci-tegra.c +PCI DRIVER FOR TI DRA7XX +M: Kishon Vijay Abraham I +L: linux-omap@vger.kernel.org +L: linux-pci@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/pci/ti-pci.txt +F: drivers/pci/host/pci-dra7xx.c + PCI DRIVER FOR RENESAS R-CAR M: Simon Horman L: linux-pci@vger.kernel.org diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 21df477..f9492cc 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -1,6 +1,15 @@ menu "PCI host controller drivers" depends on PCI +config PCI_DRA7XX + bool "TI DRA7xx PCIe controller" + select PCIE_DW + depends on OF && HAS_IOMEM && TI_PIPE3 + help + Enables support for the PCIe controller in the DRA7xx SoC. There + are two instances of PCIe controller in DRA7xx. This controller can + act both as EP and RC. This reuses the Designware core. + config PCI_MVEBU bool "Marvell EBU PCIe controller" depends on ARCH_MVEBU || ARCH_DOVE || ARCH_KIRKWOOD diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 611ba4b..c42844d 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_PCIE_DW) += pcie-designware.o +obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o obj-$(CONFIG_PCI_IMX6) += pci-imx6.o obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c new file mode 100644 index 0000000..52b34fe --- /dev/null +++ b/drivers/pci/host/pci-dra7xx.c @@ -0,0 +1,458 @@ +/* + * pcie-dra7xx - PCIe controller driver for TI DRA7xx SoCs + * + * Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: Kishon Vijay Abraham I + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcie-designware.h" + +/* PCIe controller wrapper DRA7XX configuration registers */ + +#define PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN 0x0024 +#define PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN 0x0028 +#define ERR_SYS BIT(0) +#define ERR_FATAL BIT(1) +#define ERR_NONFATAL BIT(2) +#define ERR_COR BIT(3) +#define ERR_AXI BIT(4) +#define ERR_ECRC BIT(5) +#define PME_TURN_OFF BIT(8) +#define PME_TO_ACK BIT(9) +#define PM_PME BIT(10) +#define LINK_REQ_RST BIT(11) +#define LINK_UP_EVT BIT(12) +#define CFG_BME_EVT BIT(13) +#define CFG_MSE_EVT BIT(14) +#define INTERRUPTS (ERR_SYS | ERR_FATAL | ERR_NONFATAL | ERR_COR | ERR_AXI | \ + ERR_ECRC | PME_TURN_OFF | PME_TO_ACK | PM_PME | \ + LINK_REQ_RST | LINK_UP_EVT | CFG_BME_EVT | CFG_MSE_EVT) + +#define PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI 0x0034 +#define PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI 0x0038 +#define INTA BIT(0) +#define INTB BIT(1) +#define INTC BIT(2) +#define INTD BIT(3) +#define MSI BIT(4) +#define LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD) + +#define PCIECTRL_DRA7XX_CONF_DEVICE_CMD 0x0104 +#define LTSSM_EN 0x1 + +#define PCIECTRL_DRA7XX_CONF_PHY_CS 0x010C +#define LINK_UP BIT(16) + +struct dra7xx_pcie { + void __iomem *base; + struct phy **phy; + int phy_count; + struct device *dev; + struct pcie_port pp; +}; + +#define to_dra7xx_pcie(x) container_of((x), struct dra7xx_pcie, pp) + +static inline u32 dra7xx_pcie_readl(struct dra7xx_pcie *pcie, u32 offset) +{ + return readl(pcie->base + offset); +} + +static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset, + u32 value) +{ + writel(value, pcie->base + offset); +} + +static int dra7xx_pcie_link_up(struct pcie_port *pp) +{ + struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); + u32 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS); + + return !!(reg & LINK_UP); +} + +static int dra7xx_pcie_establish_link(struct pcie_port *pp) +{ + u32 reg; + unsigned int retries = 1000; + struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); + + if (dw_pcie_link_up(pp)) { + dev_err(pp->dev, "link is already up\n"); + return 0; + } + + reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); + reg |= LTSSM_EN; + dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); + + while (retries--) { + reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS); + if (reg & LINK_UP) + break; + usleep_range(10, 20); + } + + if (retries == 0) { + dev_err(pp->dev, "link is not up\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp) +{ + struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); + + dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, + ~INTERRUPTS); + dra7xx_pcie_writel(dra7xx, + PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN, INTERRUPTS); + dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, + ~LEG_EP_INTERRUPTS & ~MSI); + + if (IS_ENABLED(CONFIG_PCI_MSI)) + dra7xx_pcie_writel(dra7xx, + PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, MSI); + else + dra7xx_pcie_writel(dra7xx, + PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, + LEG_EP_INTERRUPTS); +} + +static void dra7xx_pcie_host_init(struct pcie_port *pp) +{ + dw_pcie_setup_rc(pp); + dra7xx_pcie_establish_link(pp); + if (IS_ENABLED(CONFIG_PCI_MSI)) + dw_pcie_msi_init(pp); + dra7xx_pcie_enable_interrupts(pp); +} + +static struct pcie_host_ops dra7xx_pcie_host_ops = { + .link_up = dra7xx_pcie_link_up, + .host_init = dra7xx_pcie_host_init, +}; + +static int dra7xx_pcie_intx_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq); + irq_set_chip_data(irq, domain->host_data); + set_irq_flags(irq, IRQF_VALID); + + return 0; +} + +static const struct irq_domain_ops intx_domain_ops = { + .map = dra7xx_pcie_intx_map, +}; + +static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp) +{ + struct device *dev = pp->dev; + struct device_node *node = dev->of_node; + struct device_node *pcie_intc_node = of_get_next_child(node, NULL); + + if (!pcie_intc_node) { + dev_err(dev, "No PCIe Intc node found\n"); + return PTR_ERR(pcie_intc_node); + } + + pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4, + &intx_domain_ops, pp); + if (!pp->irq_domain) { + dev_err(dev, "Failed to get a INTx IRQ domain\n"); + return PTR_ERR(pp->irq_domain); + } + + return 0; +} + +static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg) +{ + struct pcie_port *pp = arg; + struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp); + u32 reg; + + reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI); + + switch (reg) { + case MSI: + dw_handle_msi_irq(pp); + break; + case INTA: + case INTB: + case INTC: + case INTD: + generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg))); + break; + } + + dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, reg); + + return IRQ_HANDLED; +} + + +static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg) +{ + struct dra7xx_pcie *dra7xx = arg; + u32 reg; + + reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN); + + if (reg & ERR_SYS) + dev_dbg(dra7xx->dev, "System Error\n"); + + if (reg & ERR_FATAL) + dev_dbg(dra7xx->dev, "Fatal Error\n"); + + if (reg & ERR_NONFATAL) + dev_dbg(dra7xx->dev, "Non Fatal Error\n"); + + if (reg & ERR_COR) + dev_dbg(dra7xx->dev, "Correctable Error\n"); + + if (reg & ERR_AXI) + dev_dbg(dra7xx->dev, "AXI tag lookup fatal Error\n"); + + if (reg & ERR_ECRC) + dev_dbg(dra7xx->dev, "ECRC Error\n"); + + if (reg & PME_TURN_OFF) + dev_dbg(dra7xx->dev, + "Power Management Event Turn-Off message received\n"); + + if (reg & PME_TO_ACK) + dev_dbg(dra7xx->dev, + "Power Management Turn-Off Ack message received\n"); + + if (reg & PM_PME) + dev_dbg(dra7xx->dev, + "PM Power Management Event message received\n"); + + if (reg & LINK_REQ_RST) + dev_dbg(dra7xx->dev, "Link Request Reset\n"); + + if (reg & LINK_UP_EVT) + dev_dbg(dra7xx->dev, "Link-up state change\n"); + + if (reg & CFG_BME_EVT) + dev_dbg(dra7xx->dev, "CFG 'Bus Master Enable' change\n"); + + if (reg & CFG_MSE_EVT) + dev_dbg(dra7xx->dev, "CFG 'Memory Space Enable' change\n"); + + dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, reg); + + return IRQ_HANDLED; +} + +static int add_pcie_port(struct dra7xx_pcie *dra7xx, + struct platform_device *pdev) +{ + int ret; + struct pcie_port *pp; + struct resource *res; + struct device *dev = &pdev->dev; + + pp = &dra7xx->pp; + pp->dev = dev; + pp->ops = &dra7xx_pcie_host_ops; + + pp->irq = platform_get_irq(pdev, 1); + if (pp->irq < 0) { + dev_err(dev, "missing IRQ resource\n"); + return -EINVAL; + } + + ret = devm_request_irq(&pdev->dev, pp->irq, + dra7xx_pcie_msi_irq_handler, IRQF_SHARED, + "dra7-pcie-msi", pp); + if (ret) { + dev_err(&pdev->dev, "failed to request irq\n"); + return ret; + } + + if (!IS_ENABLED(CONFIG_PCI_MSI)) { + ret = dra7xx_pcie_init_irq_domain(pp); + if (ret < 0) + return ret; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbics"); + pp->dbi_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!pp->dbi_base) + return -ENOMEM; + + ret = dw_pcie_host_init(pp); + if (ret) { + dev_err(dra7xx->dev, "failed to initialize host\n"); + return ret; + } + + return 0; +} + +static int __init dra7xx_pcie_probe(struct platform_device *pdev) +{ + u32 reg; + int ret; + int irq; + int i; + int phy_count; + struct phy **phy; + void __iomem *base; + struct resource *res; + struct dra7xx_pcie *dra7xx; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + char name[10]; + + dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL); + if (!dra7xx) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "missing IRQ resource\n"); + return -EINVAL; + } + + ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler, + IRQF_SHARED, "dra7xx-pcie-main", dra7xx); + if (ret) { + dev_err(dev, "failed to request irq\n"); + return ret; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf"); + base = devm_ioremap_nocache(dev, res->start, resource_size(res)); + if (!base) + return -ENOMEM; + + phy_count = of_property_count_strings(np, "phy-names"); + if (phy_count < 0) { + dev_err(dev, "unable to find the strings\n"); + return phy_count; + } + + phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL); + if (!phy) + return -ENOMEM; + + for (i = 0; i < phy_count; i++) { + snprintf(name, sizeof(name), "pcie-phy%d", i); + phy[i] = devm_phy_get(dev, name); + if (IS_ERR(phy[i])) + return PTR_ERR(phy[i]); + + ret = phy_init(phy[i]); + if (ret < 0) + goto err_phy; + + ret = phy_power_on(phy[i]); + if (ret < 0) { + phy_exit(phy[i]); + goto err_phy; + } + } + + dra7xx->base = base; + dra7xx->phy = phy; + dra7xx->dev = dev; + dra7xx->phy_count = phy_count; + + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (IS_ERR_VALUE(ret)) { + dev_err(dev, "pm_runtime_get_sync failed\n"); + goto err_phy; + } + + reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD); + reg &= ~LTSSM_EN; + dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); + + platform_set_drvdata(pdev, dra7xx); + + ret = add_pcie_port(dra7xx, pdev); + if (ret < 0) + goto err_add_port; + + return 0; + +err_add_port: + pm_runtime_put(dev); + pm_runtime_disable(dev); + +err_phy: + while (--i >= 0) { + phy_power_off(phy[i]); + phy_exit(phy[i]); + } + + return ret; +} + +static int __exit dra7xx_pcie_remove(struct platform_device *pdev) +{ + struct dra7xx_pcie *dra7xx = platform_get_drvdata(pdev); + struct pcie_port *pp = &dra7xx->pp; + struct device *dev = &pdev->dev; + int count = dra7xx->phy_count; + + if (pp->irq_domain) + irq_domain_remove(pp->irq_domain); + pm_runtime_put(dev); + pm_runtime_disable(dev); + while (count--) { + phy_power_off(dra7xx->phy[count]); + phy_exit(dra7xx->phy[count]); + } + + return 0; +} + +static const struct of_device_id of_dra7xx_pcie_match[] = { + { .compatible = "ti,dra7-pcie", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_dra7xx_pcie_match); + +static struct platform_driver dra7xx_pcie_driver = { + .remove = __exit_p(dra7xx_pcie_remove), + .driver = { + .name = "dra7-pcie", + .owner = THIS_MODULE, + .of_match_table = of_dra7xx_pcie_match, + }, +}; + +module_platform_driver_probe(dra7xx_pcie_driver, dra7xx_pcie_probe); + +MODULE_AUTHOR("Kishon Vijay Abraham I "); +MODULE_DESCRIPTION("TI PCIe controller driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.1 From a1c0ae9c24627a12c781ebd9947a6442861f6168 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Mon, 21 Jul 2014 12:58:41 -0400 Subject: PCI: designware: Add config access-related pcie_host_ops for v3.65 hardware DesignWare v3.65 hardware requires application space registers to be configured to access the remote EP config space. To support this, add rd_other_conf() and wr_other_conf() to pcie_host_ops. [bhelgaas: changelog] Signed-off-by: Murali Karicheri Signed-off-by: Bjorn Helgaas Reviewed-by: Pratyush Anand Acked-by: Mohit Kumar Acked-by: Jingoo Han Acked-by: Santosh Shilimkar CC: Russell King CC: Grant Likely CC: Rob Herring CC: Richard Zhu CC: Kishon Vijay Abraham I CC: Marek Vasut CC: Arnd Bergmann CC: Pawel Moll CC: Mark Rutland CC: Ian Campbell CC: Kumar Gala CC: Randy Dunlap CC: Grant Likely --- drivers/pci/host/pcie-designware.c | 12 ++++++++++-- drivers/pci/host/pcie-designware.h | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 8aab1d6..0e9838a 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -696,7 +696,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, } if (bus->number != pp->root_bus_nr) - ret = dw_pcie_rd_other_conf(pp, bus, devfn, + if (pp->ops->rd_other_conf) + ret = pp->ops->rd_other_conf(pp, bus, devfn, + where, size, val); + else + ret = dw_pcie_rd_other_conf(pp, bus, devfn, where, size, val); else ret = dw_pcie_rd_own_conf(pp, where, size, val); @@ -719,7 +723,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn, return PCIBIOS_DEVICE_NOT_FOUND; if (bus->number != pp->root_bus_nr) - ret = dw_pcie_wr_other_conf(pp, bus, devfn, + if (pp->ops->wr_other_conf) + ret = pp->ops->wr_other_conf(pp, bus, devfn, + where, size, val); + else + ret = dw_pcie_wr_other_conf(pp, bus, devfn, where, size, val); else ret = dw_pcie_wr_own_conf(pp, where, size, val); diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index add6527..93062229 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -65,6 +65,10 @@ struct pcie_host_ops { u32 val, void __iomem *dbi_base); int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val); int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val); + int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 *val); + int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus, + unsigned int devfn, int where, int size, u32 val); int (*link_up)(struct pcie_port *pp); void (*host_init)(struct pcie_port *pp); }; -- cgit v1.1 From 2f37c5a81cff2c341fa19fdd132ece6aea30a735 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Mon, 21 Jul 2014 12:58:42 -0400 Subject: PCI: designware: Add MSI-related pcie_host_ops for v3.65 hardware DesignWare v3.65 hardware implements MSI controller registers in application space. This requires updates to the DesignWare core to support controllers based on this older hardware. Add msi_irq_set()/clear() interfaces to allow Set/Clear MSI IRQ enable bit in the application register. Also, v3.65 hardware uses the MSI_IRQ register in application register space to raise MSI IRQ to the RC from EP. Current code uses the standard mechanism as per PCI spec. So add get_msi_data() to get the address of this register so common code can work on both v3.65 and newer hardware. [bhelgaas: changelog] Signed-off-by: Murali Karicheri Signed-off-by: Bjorn Helgaas Reviewed-by: Pratyush Anand Acked-by: Mohit Kumar Acked-by: Jingoo Han Acked-by: Santosh Shilimkar CC: Russell King CC: Grant Likely CC: Rob Herring CC: Richard Zhu CC: Kishon Vijay Abraham I CC: Marek Vasut CC: Arnd Bergmann CC: Pawel Moll CC: Mark Rutland CC: Ian Campbell CC: Kumar Gala CC: Randy Dunlap CC: Grant Likely --- drivers/pci/host/pcie-designware.c | 50 +++++++++++++++++++++++++++----------- drivers/pci/host/pcie-designware.h | 3 +++ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 0e9838a..52bd3a1 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -218,27 +218,47 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0) return 0; } +static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) +{ + unsigned int res, bit, val; + + res = (irq / 32) * 12; + bit = irq % 32; + dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); + val &= ~(1 << bit); + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); +} + static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, unsigned int nvec, unsigned int pos) { - unsigned int i, res, bit, val; + unsigned int i; for (i = 0; i < nvec; i++) { irq_set_msi_desc_off(irq_base, i, NULL); clear_bit(pos + i, pp->msi_irq_in_use); /* Disable corresponding interrupt on MSI controller */ - res = ((pos + i) / 32) * 12; - bit = (pos + i) % 32; - dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); - val &= ~(1 << bit); - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); + if (pp->ops->msi_clear_irq) + pp->ops->msi_clear_irq(pp, pos + i); + else + dw_pcie_msi_clear_irq(pp, pos + i); } } +static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) +{ + unsigned int res, bit, val; + + res = (irq / 32) * 12; + bit = irq % 32; + dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); + val |= 1 << bit; + dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); +} + static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) { - int res, bit, irq, pos0, pos1, i; - u32 val; + int irq, pos0, pos1, i; struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata); if (!pp) { @@ -282,11 +302,10 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) } set_bit(pos0 + i, pp->msi_irq_in_use); /*Enable corresponding interrupt in MSI interrupt controller */ - res = ((pos0 + i) / 32) * 12; - bit = (pos0 + i) % 32; - dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); - val |= 1 << bit; - dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); + if (pp->ops->msi_set_irq) + pp->ops->msi_set_irq(pp, pos0 + i); + else + dw_pcie_msi_set_irq(pp, pos0 + i); } *pos = pos0; @@ -354,7 +373,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, */ desc->msi_attrib.multiple = msgvec; - msg.address_lo = virt_to_phys((void *)pp->msi_data); + if (pp->ops->get_msi_data) + msg.address_lo = pp->ops->get_msi_data(pp); + else + msg.address_lo = virt_to_phys((void *)pp->msi_data); msg.address_hi = 0x0; msg.data = pos; write_msi_msg(irq, &msg); diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index 93062229..daf81f9 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -71,6 +71,9 @@ struct pcie_host_ops { unsigned int devfn, int where, int size, u32 val); int (*link_up)(struct pcie_port *pp); void (*host_init)(struct pcie_port *pp); + void (*msi_set_irq)(struct pcie_port *pp, int irq); + void (*msi_clear_irq)(struct pcie_port *pp, int irq); + u32 (*get_msi_data)(struct pcie_port *pp); }; int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val); -- cgit v1.1 From 495bccf3917b04c6727d720b56620e265c693ace Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 21 Jul 2014 22:54:27 +0800 Subject: ARM: dt: sun6i: Add #address-cells and #size-cells to i2c controller nodes dtc was giving warnings for missing #address-cells and #size-cells for the new sun6i-a31-hummingbird.dts, which has a i2c-based rtc device. This patch adds the properties for all i2c controller nodes for sun6i. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- arch/arm/boot/dts/sun6i-a31.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index 44b07e5..e06fbfc 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -660,6 +660,8 @@ clock-frequency = <100000>; resets = <&apb2_rst 0>; status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; }; i2c1: i2c@01c2b000 { @@ -670,6 +672,8 @@ clock-frequency = <100000>; resets = <&apb2_rst 1>; status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; }; i2c2: i2c@01c2b400 { @@ -680,6 +684,8 @@ clock-frequency = <100000>; resets = <&apb2_rst 2>; status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; }; i2c3: i2c@01c2b800 { @@ -690,6 +696,8 @@ clock-frequency = <100000>; resets = <&apb2_rst 3>; status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; }; gmac: ethernet@01c30000 { -- cgit v1.1 From 7c7f1547b627092737493f0781780af85cc9b1a4 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 7 Aug 2014 10:58:41 -0700 Subject: x86/mm: Fix RCU splat from new TLB tracepoints Dave Jones reported seeing a bug from one of my TLB tracepoints: http://lkml.kernel.org/r/20140806181801.GA4605@redhat.com According to Paul McKenney, the right way to fix this is adding an _rcuidle suffix to the tracepoint. http://lkml.kernel.org/r/20140807065055.GA5821@linux.vnet.ibm.com This patch does just that. Reported-by: Dave Jones , Signed-off-by: Dave Hansen Reviewed-by: Paul E. McKenney Cc: Dave Hansen Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20140807175841.5C92D878@viggo.jf.intel.com Signed-off-by: Ingo Molnar --- arch/x86/mm/tlb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 1fe3398..98b7976 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -49,7 +49,13 @@ void leave_mm(int cpu) if (cpumask_test_cpu(cpu, mm_cpumask(active_mm))) { cpumask_clear_cpu(cpu, mm_cpumask(active_mm)); load_cr3(swapper_pg_dir); - trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL); + /* + * This gets called in the idle path where RCU + * functions differently. Tracing normally + * uses RCU, so we have to call the tracepoint + * specially here. + */ + trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL); } } EXPORT_SYMBOL_GPL(leave_mm); -- cgit v1.1 From f96f56780ca584930bb3a2769d73fd9a101bcbbe Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Mon, 4 Aug 2014 03:10:16 +0000 Subject: kprobes: Skip kretprobe hit in NMI context to avoid deadlock Skip kretprobe hit in NMI context, because if an NMI happens inside the critical section protected by kretprobe_table.lock and another(or same) kretprobe hit, pre_kretprobe_handler tries to lock kretprobe_table.lock again. Normal interrupts have no problem because they are disabled with the lock. Signed-off-by: Masami Hiramatsu Acked-by: Ananth N Mavinakayanahalli Cc: David S. Miller Link: http://lkml.kernel.org/r/20140804031016.11433.65539.stgit@kbuild-fedora.novalocal [ Minor edits for clarity. ] Signed-off-by: Ingo Molnar --- kernel/kprobes.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 734e9a7..3995f54 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1778,7 +1778,18 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) unsigned long hash, flags = 0; struct kretprobe_instance *ri; - /*TODO: consider to only swap the RA after the last pre_handler fired */ + /* + * To avoid deadlocks, prohibit return probing in NMI contexts, + * just skip the probe and increase the (inexact) 'nmissed' + * statistical counter, so that the user is informed that + * something happened: + */ + if (unlikely(in_nmi())) { + rp->nmissed++; + return 0; + } + + /* TODO: consider to only swap the RA after the last pre_handler fired */ hash = hash_ptr(current, KPROBE_HASH_BITS); raw_spin_lock_irqsave(&rp->lock, flags); if (!hlist_empty(&rp->free_instances)) { -- cgit v1.1 From 86426851c38d3fe84dee34d7daa71d26c174d409 Mon Sep 17 00:00:00 2001 From: Jeremiah Mahler Date: Sat, 9 Aug 2014 00:38:33 -0700 Subject: x86/mm: Fix sparse 'tlb_single_page_flush_ceiling' warning and make the variable read-mostly A sparse warning is generated about 'tlb_single_page_flush_ceiling' not being declared. arch/x86/mm/tlb.c:177:15: warning: symbol 'tlb_single_page_flush_ceiling' was not declared. Should it be static? Since it isn't used anywhere outside this file, fix the warning by making it static. Also, optimize the use of this variable by adding the __read_mostly directive, as suggested by David Rientjes. Suggested-by: David Rientjes Signed-off-by: Jeremiah Mahler Cc: Dave Hansen Cc: Rik van Riel Cc: Mel Gorman Link: http://lkml.kernel.org/r/1407569913-4035-1-git-send-email-jmmahler@gmail.com Signed-off-by: Ingo Molnar --- arch/x86/mm/tlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 98b7976..ee61c36 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -180,7 +180,7 @@ void flush_tlb_current_task(void) * * This is in units of pages. */ -unsigned long tlb_single_page_flush_ceiling = 33; +static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33; void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, unsigned long end, unsigned long vmflag) -- cgit v1.1 From 129ea00594bf993251a5c70d14cbe16f3624e505 Mon Sep 17 00:00:00 2001 From: Jeremiah Mahler Date: Fri, 8 Aug 2014 00:49:55 -0700 Subject: x86/doc: Fix the 'tlb_single_page_flush_ceiling' sysconfig path Fix the documented sysconfig location of 'tlb_single_page_flush_ceiling' which is under /sys/kernel/debug/... not /sys/debug/kernel/... Signed-off-by: Jeremiah Mahler Acked-by: Dave Hansen Cc: Randy Dunlap Link: http://lkml.kernel.org/r/1407484195-1441-1-git-send-email-jmmahler@gmail.com Signed-off-by: Ingo Molnar --- Documentation/x86/tlb.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/x86/tlb.txt b/Documentation/x86/tlb.txt index 2b3a82e..39d1723 100644 --- a/Documentation/x86/tlb.txt +++ b/Documentation/x86/tlb.txt @@ -35,7 +35,7 @@ invlpg instruction (or instructions _near_ it) show up high in profiles. If you believe that individual invalidations being called too often, you can lower the tunable: - /sys/debug/kernel/x86/tlb_single_page_flush_ceiling + /sys/kernel/debug/x86/tlb_single_page_flush_ceiling This will cause us to do the global flush for more cases. Lowering it to 0 will disable the use of the individual flushes. -- cgit v1.1 From e91259f3c72648976511b1600f983d202dda1af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Stehl=C3=A9?= Date: Mon, 21 Jul 2014 23:47:36 +0200 Subject: cifs: remove unused function cifs_oplock_break_wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 743162013d40 ("sched: Remove proliferation of wait_on_bit() action functions") has removed the call to cifs_oplock_break_wait, making this function unused; remove it. This fixes the following compilation warning: fs/cifs/misc.c:578:1: warning: ‘cifs_oplock_break_wait’ defined but not used [-Wunused-function] Signed-off-by: Vincent Stehlé Cc: Steve French Signed-off-by: Steve French --- fs/cifs/misc.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 81340c6..b7415d5 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -574,13 +574,6 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) cinode->oplock = 0; } -static int -cifs_oplock_break_wait(void *unused) -{ - schedule(); - return signal_pending(current) ? -ERESTARTSYS : 0; -} - /* * We wait for oplock breaks to be processed before we attempt to perform * writes. -- cgit v1.1 From 657d6dc4197e9bc13522d0ed0e1a4ae7d0d84614 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Mon, 11 Aug 2014 20:45:31 +0300 Subject: HID: huion: Fail on parameter retrieval errors Fail Huion tablet interface enabling and probing, if parameter retrieval fails. Move the main code path out of the else block accordingly. This should prevent devices appearing in a half-working state due to original report descriptor being used, simplifying diagnostics. This also makes it easier to add cleanup in later commits, as error handling is simplified. Signed-off-by: Nikolai Kondrashov Signed-off-by: Jiri Kosina --- drivers/hid/hid-huion.c | 96 +++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/drivers/hid/hid-huion.c b/drivers/hid/hid-huion.c index 60f44cd..a683d4b 100644 --- a/drivers/hid/hid-huion.c +++ b/drivers/hid/hid-huion.c @@ -116,6 +116,10 @@ static int huion_tablet_enable(struct hid_device *hdev) struct usb_device *usb_dev = hid_to_usb_dev(hdev); struct huion_drvdata *drvdata = hid_get_drvdata(hdev); __le16 buf[6]; + s32 params[HUION_PH_ID_NUM]; + s32 resolution; + __u8 *p; + s32 v; /* * Read string descriptor containing tablet parameters. The specific @@ -128,56 +132,54 @@ static int huion_tablet_enable(struct hid_device *hdev) (USB_DT_STRING << 8) + 0x64, 0x0409, buf, sizeof(buf), USB_CTRL_GET_TIMEOUT); - if (rc == -EPIPE) - hid_warn(hdev, "device parameters not found\n"); - else if (rc < 0) - hid_warn(hdev, "failed to get device parameters: %d\n", rc); - else if (rc != sizeof(buf)) - hid_warn(hdev, "invalid device parameters\n"); - else { - s32 params[HUION_PH_ID_NUM]; - s32 resolution; - __u8 *p; - s32 v; + if (rc == -EPIPE) { + hid_err(hdev, "device parameters not found\n"); + return -ENODEV; + } else if (rc < 0) { + hid_err(hdev, "failed to get device parameters: %d\n", rc); + return -ENODEV; + } else if (rc != sizeof(buf)) { + hid_err(hdev, "invalid device parameters\n"); + return -ENODEV; + } - /* Extract device parameters */ - params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]); - params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]); - params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]); - resolution = le16_to_cpu(buf[5]); - if (resolution == 0) { - params[HUION_PH_ID_X_PM] = 0; - params[HUION_PH_ID_Y_PM] = 0; - } else { - params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] * - 1000 / resolution; - params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] * - 1000 / resolution; - } + /* Extract device parameters */ + params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]); + params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]); + params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]); + resolution = le16_to_cpu(buf[5]); + if (resolution == 0) { + params[HUION_PH_ID_X_PM] = 0; + params[HUION_PH_ID_Y_PM] = 0; + } else { + params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] * + 1000 / resolution; + params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] * + 1000 / resolution; + } - /* Allocate fixed report descriptor */ - drvdata->rdesc = devm_kmalloc(&hdev->dev, - sizeof(huion_tablet_rdesc_template), - GFP_KERNEL); - if (drvdata->rdesc == NULL) { - hid_err(hdev, "failed to allocate fixed rdesc\n"); - return -ENOMEM; - } - drvdata->rsize = sizeof(huion_tablet_rdesc_template); + /* Allocate fixed report descriptor */ + drvdata->rdesc = devm_kmalloc(&hdev->dev, + sizeof(huion_tablet_rdesc_template), + GFP_KERNEL); + if (drvdata->rdesc == NULL) { + hid_err(hdev, "failed to allocate fixed rdesc\n"); + return -ENOMEM; + } + drvdata->rsize = sizeof(huion_tablet_rdesc_template); - /* Format fixed report descriptor */ - memcpy(drvdata->rdesc, huion_tablet_rdesc_template, - drvdata->rsize); - for (p = drvdata->rdesc; - p <= drvdata->rdesc + drvdata->rsize - 4;) { - if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D && - p[3] < sizeof(params)) { - v = params[p[3]]; - put_unaligned(cpu_to_le32(v), (s32 *)p); - p += 4; - } else { - p++; - } + /* Format fixed report descriptor */ + memcpy(drvdata->rdesc, huion_tablet_rdesc_template, + drvdata->rsize); + for (p = drvdata->rdesc; + p <= drvdata->rdesc + drvdata->rsize - 4;) { + if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D && + p[3] < sizeof(params)) { + v = params[p[3]]; + put_unaligned(cpu_to_le32(v), (s32 *)p); + p += 4; + } else { + p++; } } -- cgit v1.1 From 6498d02306b337393b0bc92164857f3e6949c4e8 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Mon, 11 Aug 2014 20:45:32 +0300 Subject: HID: huion: Use allocated buffer for DMA Allocate a buffer with kmalloc for receiving the parameters string descriptor with usb_control_msg, instead of using a buffer on the stack, as the latter is unsafe. Use an enum for indices into the buffer to ensure the buffer size if sufficient. This fixes the static checker error "doing dma on the stack (buf)". Signed-off-by: Nikolai Kondrashov Signed-off-by: Jiri Kosina --- drivers/hid/hid-huion.c | 50 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/drivers/hid/hid-huion.c b/drivers/hid/hid-huion.c index a683d4b..61b68ca 100644 --- a/drivers/hid/hid-huion.c +++ b/drivers/hid/hid-huion.c @@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = { 0xC0 /* End Collection */ }; +/* Parameter indices */ +enum huion_prm { + HUION_PRM_X_LM = 1, + HUION_PRM_Y_LM = 2, + HUION_PRM_PRESSURE_LM = 4, + HUION_PRM_RESOLUTION = 5, + HUION_PRM_NUM +}; + /* Driver data */ struct huion_drvdata { __u8 *rdesc; @@ -115,7 +124,8 @@ static int huion_tablet_enable(struct hid_device *hdev) int rc; struct usb_device *usb_dev = hid_to_usb_dev(hdev); struct huion_drvdata *drvdata = hid_get_drvdata(hdev); - __le16 buf[6]; + __le16 *buf = NULL; + size_t len; s32 params[HUION_PH_ID_NUM]; s32 resolution; __u8 *p; @@ -127,27 +137,38 @@ static int huion_tablet_enable(struct hid_device *hdev) * driver traffic. * NOTE: This enables fully-functional tablet mode. */ + len = HUION_PRM_NUM * sizeof(*buf); + buf = kmalloc(len, GFP_KERNEL); + if (buf == NULL) { + hid_err(hdev, "failed to allocate parameter buffer\n"); + rc = -ENOMEM; + goto cleanup; + } rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (USB_DT_STRING << 8) + 0x64, - 0x0409, buf, sizeof(buf), + 0x0409, buf, len, USB_CTRL_GET_TIMEOUT); if (rc == -EPIPE) { hid_err(hdev, "device parameters not found\n"); - return -ENODEV; + rc = -ENODEV; + goto cleanup; } else if (rc < 0) { hid_err(hdev, "failed to get device parameters: %d\n", rc); - return -ENODEV; - } else if (rc != sizeof(buf)) { + rc = -ENODEV; + goto cleanup; + } else if (rc != len) { hid_err(hdev, "invalid device parameters\n"); - return -ENODEV; + rc = -ENODEV; + goto cleanup; } /* Extract device parameters */ - params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]); - params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]); - params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]); - resolution = le16_to_cpu(buf[5]); + params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]); + params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]); + params[HUION_PH_ID_PRESSURE_LM] = + le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]); + resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]); if (resolution == 0) { params[HUION_PH_ID_X_PM] = 0; params[HUION_PH_ID_Y_PM] = 0; @@ -164,7 +185,8 @@ static int huion_tablet_enable(struct hid_device *hdev) GFP_KERNEL); if (drvdata->rdesc == NULL) { hid_err(hdev, "failed to allocate fixed rdesc\n"); - return -ENOMEM; + rc = -ENOMEM; + goto cleanup; } drvdata->rsize = sizeof(huion_tablet_rdesc_template); @@ -183,7 +205,11 @@ static int huion_tablet_enable(struct hid_device *hdev) } } - return 0; + rc = 0; + +cleanup: + kfree(buf); + return rc; } static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id) -- cgit v1.1 From 5be5db24fc0883d9e38df378c1de9a00f8933999 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 3 Aug 2014 03:41:35 +0530 Subject: HID: hid-sensor-hub: use devm_ functions consistently Use devm_kzalloc for all calls to kzalloc and not just the first. Use devm functions for other allocations as well. The calls to free the allocated memory in the probe and remove functions are done away with and a label is removed in the probe function. The semantic match that finds the inconsistency is as follows: // @@ @@ *devm_kzalloc(...) ... *kzalloc(...) // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Reviewed-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/hid-sensor-hub.c | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index e244e44..2ac2576 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -604,9 +604,9 @@ static int sensor_hub_probe(struct hid_device *hdev, ret = -EINVAL; goto err_stop_hw; } - sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt * - sizeof(struct mfd_cell), - GFP_KERNEL); + sd->hid_sensor_hub_client_devs = devm_kzalloc(&hdev->dev, dev_cnt * + sizeof(struct mfd_cell), + GFP_KERNEL); if (sd->hid_sensor_hub_client_devs == NULL) { hid_err(hdev, "Failed to allocate memory for mfd cells\n"); ret = -ENOMEM; @@ -618,11 +618,12 @@ static int sensor_hub_probe(struct hid_device *hdev, if (collection->type == HID_COLLECTION_PHYSICAL) { - hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); + hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev), + GFP_KERNEL); if (!hsdev) { hid_err(hdev, "cannot allocate hid_sensor_hub_device\n"); ret = -ENOMEM; - goto err_no_mem; + goto err_stop_hw; } hsdev->hdev = hdev; hsdev->vendor_id = hdev->vendor; @@ -631,13 +632,13 @@ static int sensor_hub_probe(struct hid_device *hdev, if (last_hsdev) last_hsdev->end_collection_index = i; last_hsdev = hsdev; - name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x", - collection->usage); + name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "HID-SENSOR-%x", + collection->usage); if (name == NULL) { hid_err(hdev, "Failed MFD device name\n"); ret = -ENOMEM; - kfree(hsdev); - goto err_no_mem; + goto err_stop_hw; } sd->hid_sensor_hub_client_devs[ sd->hid_sensor_client_cnt].id = @@ -661,16 +662,10 @@ static int sensor_hub_probe(struct hid_device *hdev, ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs, sd->hid_sensor_client_cnt, NULL, 0, NULL); if (ret < 0) - goto err_no_mem; + goto err_stop_hw; return ret; -err_no_mem: - for (i = 0; i < sd->hid_sensor_client_cnt; ++i) { - kfree(sd->hid_sensor_hub_client_devs[i].name); - kfree(sd->hid_sensor_hub_client_devs[i].platform_data); - } - kfree(sd->hid_sensor_hub_client_devs); err_stop_hw: hid_hw_stop(hdev); @@ -681,7 +676,6 @@ static void sensor_hub_remove(struct hid_device *hdev) { struct sensor_hub_data *data = hid_get_drvdata(hdev); unsigned long flags; - int i; hid_dbg(hdev, " hardware removed\n"); hid_hw_close(hdev); @@ -691,11 +685,6 @@ static void sensor_hub_remove(struct hid_device *hdev) complete(&data->pending.ready); spin_unlock_irqrestore(&data->lock, flags); mfd_remove_devices(&hdev->dev); - for (i = 0; i < data->hid_sensor_client_cnt; ++i) { - kfree(data->hid_sensor_hub_client_devs[i].name); - kfree(data->hid_sensor_hub_client_devs[i].platform_data); - } - kfree(data->hid_sensor_hub_client_devs); hid_set_drvdata(hdev, NULL); mutex_destroy(&data->mutex); } -- cgit v1.1 From 8ae31240ccc8ff339101e2d023b82cb7c93dd002 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 11 Aug 2014 19:29:30 -0500 Subject: Add missing definitions for CIFS File System Attributes Signed-off-by: Steve French Acked-by: Shirish Pargaonkar --- fs/cifs/cifspdu.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 33df36e..5f9822ac 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -2253,6 +2253,29 @@ typedef struct { /* minimum includes first three fields, and empty FS Name */ #define MIN_FS_ATTR_INFO_SIZE 12 + +/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */ +#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000 +#define FILE_SUPPORTS_USN_JOURNAL 0x02000000 +#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000 +#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000 +#define FILE_SUPPORTS_HARD_LINKS 0x00400000 +#define FILE_SUPPORTS_TRANSACTIONS 0x00200000 +#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000 +#define FILE_READ_ONLY_VOLUME 0x00080000 +#define FILE_NAMED_STREAMS 0x00040000 +#define FILE_SUPPORTS_ENCRYPTION 0x00020000 +#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 +#define FILE_VOLUME_IS_COMPRESSED 0x00008000 +#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 +#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 +#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 +#define FILE_VOLUME_QUOTAS 0x00000020 +#define FILE_FILE_COMPRESSION 0x00000010 +#define FILE_PERSISTENT_ACLS 0x00000008 +#define FILE_UNICODE_ON_DISK 0x00000004 +#define FILE_CASE_PRESERVED_NAMES 0x00000002 +#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 typedef struct { __le32 Attributes; __le32 MaxPathNameComponentLength; -- cgit v1.1 From 3d1a3745d8ca7ccdf00905b01fd5ab42ff523a94 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 11 Aug 2014 21:05:25 -0500 Subject: Add sparse file support to SMB2/SMB3 mounts Many Linux filesystes make a file "sparse" when extending a file with ftruncate. This does work for CIFS to Samba (only) but not for SMB2/SMB3 (to Samba or Windows) since there is a "set sparse" fsctl which is supposed to be sent to mark a file as sparse. This patch marks a file as sparse by sending this simple set sparse fsctl if it is extended more than 2 pages. It has been tested to Windows 8.1, Samba and various SMB2/SMB3 servers which do support setting sparse (and MacOS which does not appear to support the fsctl yet). If a server share does not support setting a file as sparse, then we do not retry setting sparse on that share. The disk space savings for sparse files can be quite large (even more significant on Windows servers than Samba). Signed-off-by: Steve French Reviewed-by: Shirish Pargaonkar --- fs/cifs/cifsglob.h | 1 + fs/cifs/smb2ops.c | 43 +++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.c | 4 +++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0012e1e..bc20a6e 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -883,6 +883,7 @@ struct cifs_tcon { for this mount even if server would support */ bool local_lease:1; /* check leases (only) on local system not remote */ bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ + bool broken_sparse_sup; /* if server or share does not support sparse */ bool need_reconnect:1; /* connection reset, tid now invalid */ #ifdef CONFIG_CIFS_SMB2 bool print:1; /* set if connection to printer share */ diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 77f8aeb..7463436 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -736,6 +736,49 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile, __u64 size, bool set_alloc) { __le64 eof = cpu_to_le64(size); + struct inode *inode; + + /* + * If extending file more than one page make sparse. Many Linux fs + * make files sparse by default when extending via ftruncate + */ + inode = cfile->dentry->d_inode; + + if (!set_alloc && (size > inode->i_size + 8192)) { + struct cifsInodeInfo *cifsi; + __u8 set_sparse = 1; + int rc; + + cifsi = CIFS_I(inode); + + /* if file already sparse or no server support don't bother */ + if (cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) + goto smb2_set_eof; + + /* + * Can't check for sparse support on share the usual way via the + * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share + * since Samba server doesn't set the flag on the share, yet + * supports the set sparse FSCTL and returns sparse correctly + * in the file attributes. If we fail setting sparse though we + * mark that server does not support sparse files for this share + * to avoid repeatedly sending the unsupported fsctl to server + * if the file is repeatedly extended. + */ + if (tcon->broken_sparse_sup) + goto smb2_set_eof; + + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, FSCTL_SET_SPARSE, + true /* is_fctl */, &set_sparse, 1, NULL, NULL); + if (rc) { + tcon->broken_sparse_sup = true; + cifs_dbg(FYI, "set sparse rc = %d\n", rc); + } else + cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE; + } + +smb2_set_eof: return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid, cfile->pid, &eof, false); } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 42ebc1a..74440af 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1224,7 +1224,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, cifs_dbg(FYI, "SMB2 IOCTL\n"); - *out_data = NULL; + if (out_data != NULL) + *out_data = NULL; + /* zero out returned data len, in case of error */ if (plen) *plen = 0; -- cgit v1.1 From daebdd7ee30b4ec7dd6a4e90f1f66c86ec113bbc Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Wed, 6 Aug 2014 13:37:40 -0700 Subject: HID: rmi: print an error if F11 is not found instead of stopping the device Currently rmi_probe will return -EIO if the device doesn't report that it has F11. This would indicate that something happened and the device is in the bootloader. We can recover the device using a userspace firmware update tool, but it needs access to the device through the hidraw device file. If the probe returns -EIO the hidraw device won't be created. So instead of failing the probe, just print an error message, but leave the device accessible from userspace. Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina --- drivers/hid/hid-rmi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 0dc2514..8389e81 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -909,10 +909,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } - if (!test_bit(RMI_STARTED, &data->flags)) { - hid_hw_stop(hdev); - return -EIO; - } + if (!test_bit(RMI_STARTED, &data->flags)) + /* + * The device maybe in the bootloader if rmi_input_configured + * failed to find F11 in the PDT. Print an error, but don't + * return an error from rmi_probe so that hidraw will be + * accessible from userspace. That way a userspace tool + * can be used to reload working firmware on the touchpad. + */ + hid_err(hdev, "Device failed to be properly configured\n"); return 0; } -- cgit v1.1 From 6e909f74db2aa9c5b5606b81efcbe18f2749b008 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 7 Aug 2014 09:28:31 -0400 Subject: drm/radeon: add bapm module parameter Add a module paramter to enable bapm on APUs. It's disabled by default on certain APUs due to stability issues. This option makes it easier to test and to enable it on systems that are stable. bug: https://bugzilla.kernel.org/show_bug.cgi?id=81021 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/kv_dpm.c | 5 ++++- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_drv.c | 4 ++++ drivers/gpu/drm/radeon/trinity_dpm.c | 24 +++++++++++++++--------- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index 9ef8c38..c667d83 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -2726,7 +2726,10 @@ int kv_dpm_init(struct radeon_device *rdev) pi->caps_sclk_ds = true; pi->enable_auto_thermal_throttling = true; pi->disable_nb_ps3_in_battery = false; - pi->bapm_enable = true; + if (radeon_bapm == 0) + pi->bapm_enable = false; + else + pi->bapm_enable = true; pi->voltage_drop_t = 0; pi->caps_sclk_throttle_low_notification = false; pi->caps_fps = false; /* true? */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 9e1732e..e715e0c 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -105,6 +105,7 @@ extern int radeon_vm_size; extern int radeon_vm_block_size; extern int radeon_deep_color; extern int radeon_use_pflipirq; +extern int radeon_bapm; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 092d067..8df8889 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -180,6 +180,7 @@ int radeon_vm_size = 8; int radeon_vm_block_size = -1; int radeon_deep_color = 0; int radeon_use_pflipirq = 2; +int radeon_bapm = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -259,6 +260,9 @@ module_param_named(deep_color, radeon_deep_color, int, 0444); MODULE_PARM_DESC(use_pflipirq, "Pflip irqs for pageflip completion (0 = disable, 1 = as fallback, 2 = exclusive (default))"); module_param_named(use_pflipirq, radeon_use_pflipirq, int, 0444); +MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(bapm, radeon_bapm, int, 0444); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 32e50be..57f7800 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -1874,16 +1874,22 @@ int trinity_dpm_init(struct radeon_device *rdev) for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) pi->at[i] = TRINITY_AT_DFLT; - /* There are stability issues reported on with - * bapm enabled when switching between AC and battery - * power. At the same time, some MSI boards hang - * if it's not enabled and dpm is enabled. Just enable - * it for MSI boards right now. - */ - if (rdev->pdev->subsystem_vendor == 0x1462) - pi->enable_bapm = true; - else + if (radeon_bapm == -1) { + /* There are stability issues reported on with + * bapm enabled when switching between AC and battery + * power. At the same time, some MSI boards hang + * if it's not enabled and dpm is enabled. Just enable + * it for MSI boards right now. + */ + if (rdev->pdev->subsystem_vendor == 0x1462) + pi->enable_bapm = true; + else + pi->enable_bapm = false; + } else if (radeon_bapm == 0) { pi->enable_bapm = false; + } else { + pi->enable_bapm = true; + } pi->enable_nbps_policy = true; pi->enable_sclk_ds = true; pi->enable_gfx_power_gating = true; -- cgit v1.1 From 4fb0bbd5d0f13f39a2fe5e092a64cece3a4afcb9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 7 Aug 2014 09:57:21 -0400 Subject: drm/radeon: use pfp for all vm_flush related updates May fix hangs in some cases. Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/cik.c | 8 ++++---- drivers/gpu/drm/radeon/si.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index b625646..e7d99e1 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -5958,14 +5958,14 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* update SH_MEM_* regs */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); radeon_ring_write(ring, 0); radeon_ring_write(ring, VMID(vm->id)); radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, SH_MEM_BASES >> 2); radeon_ring_write(ring, 0); @@ -5976,7 +5976,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) radeon_ring_write(ring, 0); /* SH_MEM_APE1_LIMIT */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, SRBM_GFX_CNTL >> 2); radeon_ring_write(ring, 0); @@ -5987,7 +5987,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* bits 0-15 are the VM contexts0-15 */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); radeon_ring_write(ring, 0); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 011779b..dbd9d81 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -5028,7 +5028,7 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* flush hdp cache */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2); radeon_ring_write(ring, 0); @@ -5036,7 +5036,7 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm) /* bits 0-15 are the VM contexts0-15 */ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); - radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | + radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) | WRITE_DATA_DST_SEL(0))); radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2); radeon_ring_write(ring, 0); -- cgit v1.1 From 68b1ea30e4b64c6c5a1ed7c1970062d61c1a892c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 7 Aug 2014 18:27:37 +0300 Subject: drm/radeon: add a check for allocation failure (v2) We can easily return -ENOMEM here if kzalloc() fails. v2: agd5f: drop the vm mutex Signed-off-by: Dan Carpenter Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_vm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index ccae4d9..9c8358f 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -483,6 +483,10 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, /* add a clone of the bo_va to clear the old address */ struct radeon_bo_va *tmp; tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); + if (!tmp) { + mutex_unlock(&vm->mutex); + return -ENOMEM; + } tmp->it.start = bo_va->it.start; tmp->it.last = bo_va->it.last; tmp->vm = vm; -- cgit v1.1 From 6f28ef4797fe651aca36430102cff321c172b29b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 7 Aug 2014 16:46:56 +0900 Subject: drm/radeon: Always flush VM again on < CIK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not doing this causes piglit hangs[0] on my Cape Verde card. No issues on Bonaire and Kaveri though. [0] Same symptoms as those fixed on CIK by 'drm/radeon: set VM base addr using the PFP v2'. Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_vm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index 9c8358f..058f200 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -238,7 +238,9 @@ void radeon_vm_flush(struct radeon_device *rdev, uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory); /* if we can't remember our last VM flush then flush now! */ - if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) { + /* XXX figure out why we have to flush all the time before CIK */ + if (rdev->family < CHIP_BONAIRE || + !vm->last_flush || pd_addr != vm->pd_gpu_addr) { trace_radeon_vm_flush(pd_addr, ring, vm->id); vm->pd_gpu_addr = pd_addr; radeon_ring_vm_flush(rdev, ring, vm); -- cgit v1.1 From 6bce8d9772c1c606921a9c99e566eb14202f6669 Mon Sep 17 00:00:00 2001 From: Oleg Chernovskiy Date: Mon, 11 Aug 2014 21:53:46 +0400 Subject: drm/radeon: Add missing lines to ci_set_thermal_temperature_range Properly set the thermal min and max temp on CI. Otherwise, we end up setting the thermal ranges to 0 on resume and end up in the lowest power state. Signed-off-by: Oleg Chernovskiy Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/ci_dpm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index 022561e..d416bb2 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -869,6 +869,9 @@ static int ci_set_thermal_temperature_range(struct radeon_device *rdev, WREG32_SMC(CG_THERMAL_CTRL, tmp); #endif + rdev->pm.dpm.thermal.min_temp = low_temp; + rdev->pm.dpm.thermal.max_temp = high_temp; + return 0; } -- cgit v1.1 From b07a657e3a05b81c8a30d60e3f3746ca5a48ee62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 11 Aug 2014 19:01:58 +0200 Subject: drm/radeon: Add ability to get and change dpm state when radeon PX card is turned off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixing commit 4f2f203976964e267dc477de6648bdb3acd2b74b bug: https://bugzilla.kernel.org/show_bug.cgi?id=76321 Signed-off-by: Pali Rohár Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_pm.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 23314be..164898b 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -460,10 +460,6 @@ static ssize_t radeon_get_dpm_state(struct device *dev, struct radeon_device *rdev = ddev->dev_private; enum radeon_pm_state_type pm = rdev->pm.dpm.user_state; - if ((rdev->flags & RADEON_IS_PX) && - (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) - return snprintf(buf, PAGE_SIZE, "off\n"); - return snprintf(buf, PAGE_SIZE, "%s\n", (pm == POWER_STATE_TYPE_BATTERY) ? "battery" : (pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance"); @@ -477,11 +473,6 @@ static ssize_t radeon_set_dpm_state(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct radeon_device *rdev = ddev->dev_private; - /* Can't set dpm state when the card is off */ - if ((rdev->flags & RADEON_IS_PX) && - (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) - return -EINVAL; - mutex_lock(&rdev->pm.mutex); if (strncmp("battery", buf, strlen("battery")) == 0) rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY; @@ -495,7 +486,12 @@ static ssize_t radeon_set_dpm_state(struct device *dev, goto fail; } mutex_unlock(&rdev->pm.mutex); - radeon_pm_compute_clocks(rdev); + + /* Can't set dpm state when the card is off */ + if (!(rdev->flags & RADEON_IS_PX) || + (ddev->switch_power_state == DRM_SWITCH_POWER_ON)) + radeon_pm_compute_clocks(rdev); + fail: return count; } -- cgit v1.1 From c83dec3bb6c38629398b65c231c80978b3e00e14 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 14 Aug 2014 01:22:31 -0400 Subject: drm/radeon/dpm: select the appropriate vce power state for KV/KB/ML Compare the clock in the limits table to the requested evclk rather than just taking the first value. Improves vce performance in certain cases. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/kv_dpm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index c667d83..8b58e11 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -1438,14 +1438,14 @@ static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate) return kv_enable_uvd_dpm(rdev, !gate); } -static u8 kv_get_vce_boot_level(struct radeon_device *rdev) +static u8 kv_get_vce_boot_level(struct radeon_device *rdev, u32 evclk) { u8 i; struct radeon_vce_clock_voltage_dependency_table *table = &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; for (i = 0; i < table->count; i++) { - if (table->entries[i].evclk >= 0) /* XXX */ + if (table->entries[i].evclk >= evclk) break; } @@ -1468,7 +1468,7 @@ static int kv_update_vce_dpm(struct radeon_device *rdev, if (pi->caps_stable_p_state) pi->vce_boot_level = table->count - 1; else - pi->vce_boot_level = kv_get_vce_boot_level(rdev); + pi->vce_boot_level = kv_get_vce_boot_level(rdev, radeon_new_state->evclk); ret = kv_copy_bytes_to_smc(rdev, pi->dpm_table_start + -- cgit v1.1 From c8ad8b563c7e724e2fedc3aee5bcbd401668474c Mon Sep 17 00:00:00 2001 From: Andreas Ruprecht Date: Fri, 15 Aug 2014 00:50:31 -0400 Subject: drm/radeon: Remove duplicate include from Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the Makefile, radeon_uvd.o is added to radeon-y twice. As it belongs to the UVD block marked with a comment, the other include from the block of includes labelled as "KMS driver" is deleted. Signed-off-by: Andreas Ruprecht Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 0013ad0..f77b713 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -76,7 +76,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ evergreen.o evergreen_cs.o evergreen_blit_shaders.o \ evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \ atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \ - si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \ + si_blit_shaders.o radeon_prime.o cik.o cik_blit_shaders.o \ r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \ rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \ trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \ -- cgit v1.1 From 29ff66571d38f01c5a5d3af871401b8a65323422 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Thu, 14 Aug 2014 20:43:01 -0600 Subject: HID: logitech: Prevent possibility of infinite loop when using /sys interface If the device data is not accessible for some reason, returning 0 will cause the call to be continuously called again as none of the string has been 'consumed'. Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg4ff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index cc2bd20..7835717 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -451,13 +451,13 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at drv_data = hid_get_drvdata(hid); if (!drv_data) { hid_err(hid, "Private driver data not found!\n"); - return 0; + return -EINVAL; } entry = drv_data->device_props; if (!entry) { hid_err(hid, "Device properties not found!\n"); - return 0; + return -EINVAL; } if (range == 0) -- cgit v1.1 From 478c9e74204f7bd5f97cca92e917749434ed6f92 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Thu, 10 Jul 2014 07:58:18 +0000 Subject: i40e: Fix for recent kernel panic Whenever we get a Tx hang we issue a PFR, which means we send AQ messages to VFS about the reset coming. Unfortunately with the recent fix to be able to send messages to all VFS which earlier was not happening at all we now are sending messages to not just the VFS that are up but also to VFS that are not up. AQ complains about this and sends us an error in ARQ called LAN overflow event for a queue. We check if the queue belongs to a VF and if it does we try to send a vc_notify_vf_reset message to that VF. Well if the VF is not up/enabled we will be entering this function with a non-active VF id. In this function we were assuming VF struct is populated but it won't be if the VF is not active. Change-ID: Ic6733cda4582d3609fe6d83b2872bb2dcdc73f4a Signed-off-by: Ashish N Shah Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 18 +++++++++++++++--- 1 file changed, 15 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 8967255..502b534 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1928,17 +1928,22 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf, { struct i40e_hw *hw = &pf->hw; struct i40e_vf *vf = pf->vf; - int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; + int abs_vf_id; int i; for (i = 0; i < pf->num_alloc_vfs; i++) { + /* Not all vfs are enabled so skip the ones that are not */ + if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states) && + !test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) + continue; + /* Ignore return value on purpose - a given VF may fail, but * we need to keep going and send to all of them */ + abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; i40e_aq_send_msg_to_vf(hw, abs_vf_id, v_opcode, v_retval, msg, msglen, NULL); vf++; - abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; } } @@ -2002,7 +2007,14 @@ void i40e_vc_notify_reset(struct i40e_pf *pf) void i40e_vc_notify_vf_reset(struct i40e_vf *vf) { struct i40e_virtchnl_pf_event pfe; - int abs_vf_id = vf->vf_id + vf->pf->hw.func_caps.vf_base_id; + int abs_vf_id; + + /* verify if the VF is in either init or active before proceeding */ + if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states) && + !test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) + return; + + abs_vf_id = vf->vf_id + vf->pf->hw.func_caps.vf_base_id; pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING; pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM; -- cgit v1.1 From 6e7b5bd32c7cd303eec4880149636ffbc2098df8 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Thu, 10 Jul 2014 07:58:21 +0000 Subject: i40e: Fix a few potential VF dereferences In some functions we might be doing potential dereference without a check. This patch puts the check in place for all these functions. Also fix the "for loops" so that we increment VF at the right place so that we always do it even if we are short-circuiting the loop through continue. Change-ID: Id4276cfb1e841031bb7b6d6790c414242f364a9f Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 30 ++++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 502b534..3ac6a0d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1003,11 +1003,19 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs) static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen) { - struct i40e_pf *pf = vf->pf; - struct i40e_hw *hw = &pf->hw; - int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; + struct i40e_pf *pf; + struct i40e_hw *hw; + int abs_vf_id; i40e_status aq_ret; + /* validate the request */ + if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs) + return -EINVAL; + + pf = vf->pf; + hw = &pf->hw; + abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; + /* single place to detect unsuccessful return values */ if (v_retval) { vf->num_invalid_msgs++; @@ -1928,10 +1936,10 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf, { struct i40e_hw *hw = &pf->hw; struct i40e_vf *vf = pf->vf; - int abs_vf_id; int i; - for (i = 0; i < pf->num_alloc_vfs; i++) { + for (i = 0; i < pf->num_alloc_vfs; i++, vf++) { + int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; /* Not all vfs are enabled so skip the ones that are not */ if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states) && !test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) @@ -1940,10 +1948,8 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf, /* Ignore return value on purpose - a given VF may fail, but * we need to keep going and send to all of them */ - abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; i40e_aq_send_msg_to_vf(hw, abs_vf_id, v_opcode, v_retval, msg, msglen, NULL); - vf++; } } @@ -1959,12 +1965,12 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf) struct i40e_hw *hw = &pf->hw; struct i40e_vf *vf = pf->vf; struct i40e_link_status *ls = &pf->hw.phy.link_info; - int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; int i; pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE; pfe.severity = I40E_PF_EVENT_SEVERITY_INFO; - for (i = 0; i < pf->num_alloc_vfs; i++) { + for (i = 0; i < pf->num_alloc_vfs; i++, vf++) { + int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; if (vf->link_forced) { pfe.event_data.link_event.link_status = vf->link_up; pfe.event_data.link_event.link_speed = @@ -1977,8 +1983,6 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf) i40e_aq_send_msg_to_vf(hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT, 0, (u8 *)&pfe, sizeof(pfe), NULL); - vf++; - abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id; } } @@ -2009,6 +2013,10 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf) struct i40e_virtchnl_pf_event pfe; int abs_vf_id; + /* validate the request */ + if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs) + return; + /* verify if the VF is in either init or active before proceeding */ if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states) && !test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) -- cgit v1.1 From db6d2bee7953842ea7b38167c31d8ab246e7d4a2 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 12 Aug 2014 06:33:13 +0000 Subject: i40e: fix PTP bug The receive hang detection routine was never being run when PTP was enabled. Change-ID: I200f35b0f3190d31b595df89d678f4c8a2131ba0 Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index bb7fe98b..537b621 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -247,7 +247,7 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi) u32 prttsyn_stat; int n; - if (pf->flags & I40E_FLAG_PTP) + if (!(pf->flags & I40E_FLAG_PTP)) return; prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); -- cgit v1.1 From 045065d8a300a37218c548e9aa7becd581c6a0e8 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 10 Aug 2014 05:54:25 -0700 Subject: [SCSI] fix qemu boot hang problem The latest kernel fails to boot qemu arm images when using scsi for disk access. Boot gets stuck after the following messages. brd: module loaded sym53c8xx 0000:00:0c.0: enabling device (0100 -> 0103) sym0: <895a> rev 0x0 at pci 0000:00:0c.0 irq 93 sym0: No NVRAM, ID 7, Fast-40, LVD, parity checking sym0: SCSI BUS has been reset. scsi host0: sym-2.2.3 Bisect points to commit 71e75c97f97a ("scsi: convert device_busy to atomic_t"). Code inspection shows the following suspicious change in scsi_request_fn. out_delay: - if (sdev->device_busy == 0 && !scsi_device_blocked(sdev)) + if (atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev)) blk_delay_queue(q, SCSI_QUEUE_DELAY); } 'sdev->device_busy == 0' was replaced with 'atomic_read(&sdev->device_busy)', meaning the logic was reversed. Changing this expression to '!atomic_read(&sdev->device_busy)' fixes the problem. Signed-off-by: Guenter Roeck Reviewed-by: Hannes Reinecke Acked-by: Jens Axboe Signed-off-by: Christoph Hellwig Fixes: 71e75c97f97a Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9c44392..ce62e87 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1774,7 +1774,7 @@ static void scsi_request_fn(struct request_queue *q) blk_requeue_request(q, req); atomic_dec(&sdev->device_busy); out_delay: - if (atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev)) + if (!atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev)) blk_delay_queue(q, SCSI_QUEUE_DELAY); } -- cgit v1.1 From f6105c0808880c2c432b79bc81b37cc244c300c8 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 4 Aug 2014 13:30:02 +0200 Subject: [SCSI] save command pool address of Scsi_Host If a scsi host driver specifies .cmd_len in it's scsi_host_template, a driver's private command pool is needed. scsi_find_host_cmd_pool() will locate it, but scsi_alloc_host_cmd_pool() isn't saving the pool address in the host template. This will result in an access error when the host is removed. Avoid the problem by saving the address of a new allocated command pool where it is expected. Signed-off-by: Juergen Gross Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig Fixes: 89d9a567952baec13e26ada3e438f1b642d66b6e Cc: stable@vger.kernel.org Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index df33060..d81f3cc 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -377,6 +377,10 @@ scsi_alloc_host_cmd_pool(struct Scsi_Host *shost) pool->slab_flags |= SLAB_CACHE_DMA; pool->gfp_mask = __GFP_DMA; } + + if (hostt->cmd_size) + hostt->cmd_pool = pool; + return pool; } @@ -421,8 +425,10 @@ out: out_free_slab: kmem_cache_destroy(pool->cmd_slab); out_free_pool: - if (hostt->cmd_size) + if (hostt->cmd_size) { scsi_free_host_cmd_pool(pool); + hostt->cmd_pool = NULL; + } goto out; } @@ -444,8 +450,10 @@ static void scsi_put_host_cmd_pool(struct Scsi_Host *shost) if (!--pool->users) { kmem_cache_destroy(pool->cmd_slab); kmem_cache_destroy(pool->sense_slab); - if (hostt->cmd_size) + if (hostt->cmd_size) { scsi_free_host_cmd_pool(pool); + hostt->cmd_pool = NULL; + } } mutex_unlock(&host_cmd_pool_mutex); } -- cgit v1.1 From fb21b84e7f809ef04b1e5aed5d463cf0d4866638 Mon Sep 17 00:00:00 2001 From: Stefan Bader Date: Fri, 15 Aug 2014 10:57:46 +0200 Subject: x86_32, entry: Clean up sysenter_badsys declaration commit 554086d85e "x86_32, entry: Do syscall exit work on badsys (CVE-2014-4508)" introduced a new jump label (sysenter_badsys) but somehow the END statements seem to have gone wrong (at least it feels that way to me). This does not seem to be a fatal problem, but just for the sake of symmetry, change the second syscall_badsys to sysenter_badsys. Signed-off-by: Stefan Bader Link: http://lkml.kernel.org/r/1408093066-31021-1-git-send-email-stefan.bader@canonical.com Acked-by: Andy Lutomirski Signed-off-by: H. Peter Anvin --- arch/x86/kernel/entry_32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 47c410d..4b0e1df 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -683,7 +683,7 @@ END(syscall_badsys) sysenter_badsys: movl $-ENOSYS,%eax jmp sysenter_after_call -END(syscall_badsys) +END(sysenter_badsys) CFI_ENDPROC .macro FIXUP_ESPFIX_STACK -- cgit v1.1 From d43cc79343dfabf9f168531d3f5cff313205c8fb Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 13 Aug 2014 17:16:29 -0500 Subject: Cleanup sparse file support by creating worker function for it Simply move code to new function (for clarity). Function sets or clears the sparse file attribute flag. Signed-off-by: Steve French Reviewed-by: David Disseldorp --- fs/cifs/smb2ops.c | 80 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 7463436..85be34a 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -731,6 +731,52 @@ smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, return SMB2_write(xid, parms, written, iov, nr_segs); } +/* Set or clear the SPARSE_FILE attribute based on value passed in setsparse */ +static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon, + struct cifsFileInfo *cfile, struct inode *inode, __u8 setsparse) +{ + struct cifsInodeInfo *cifsi; + int rc; + + cifsi = CIFS_I(inode); + + /* if file already sparse don't bother setting sparse again */ + if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && setsparse) + return true; /* already sparse */ + + if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && !setsparse) + return true; /* already not sparse */ + + /* + * Can't check for sparse support on share the usual way via the + * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share + * since Samba server doesn't set the flag on the share, yet + * supports the set sparse FSCTL and returns sparse correctly + * in the file attributes. If we fail setting sparse though we + * mark that server does not support sparse files for this share + * to avoid repeatedly sending the unsupported fsctl to server + * if the file is repeatedly extended. + */ + if (tcon->broken_sparse_sup) + return false; + + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, FSCTL_SET_SPARSE, + true /* is_fctl */, &setsparse, 1, NULL, NULL); + if (rc) { + tcon->broken_sparse_sup = true; + cifs_dbg(FYI, "set sparse rc = %d\n", rc); + return false; + } + + if (setsparse) + cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE; + else + cifsi->cifsAttrs &= (~FILE_ATTRIBUTE_SPARSE_FILE); + + return true; +} + static int smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile, __u64 size, bool set_alloc) @@ -745,40 +791,12 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, inode = cfile->dentry->d_inode; if (!set_alloc && (size > inode->i_size + 8192)) { - struct cifsInodeInfo *cifsi; __u8 set_sparse = 1; - int rc; - - cifsi = CIFS_I(inode); - - /* if file already sparse or no server support don't bother */ - if (cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) - goto smb2_set_eof; - - /* - * Can't check for sparse support on share the usual way via the - * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share - * since Samba server doesn't set the flag on the share, yet - * supports the set sparse FSCTL and returns sparse correctly - * in the file attributes. If we fail setting sparse though we - * mark that server does not support sparse files for this share - * to avoid repeatedly sending the unsupported fsctl to server - * if the file is repeatedly extended. - */ - if (tcon->broken_sparse_sup) - goto smb2_set_eof; - - rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, - cfile->fid.volatile_fid, FSCTL_SET_SPARSE, - true /* is_fctl */, &set_sparse, 1, NULL, NULL); - if (rc) { - tcon->broken_sparse_sup = true; - cifs_dbg(FYI, "set sparse rc = %d\n", rc); - } else - cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE; + + /* whether set sparse succeeds or not, extend the file */ + smb2_set_sparse(xid, tcon, cfile, inode, set_sparse); } -smb2_set_eof: return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid, cfile->pid, &eof, false); } -- cgit v1.1 From 024408062b21af7316221c420ff16bdaac478fa8 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Sat, 9 Aug 2014 10:16:44 -0400 Subject: cifs: handle lease F_UNLCK requests properly Currently any F_UNLCK request for a lease just gets back -EAGAIN. Allow them to go immediately to generic_setlease instead. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8883980..0a4a4d7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -812,8 +812,9 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) if (!(S_ISREG(inode->i_mode))) return -EINVAL; - /* check if file is oplocked */ - if (((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) || + /* Check if file is oplocked if this is request for new lease */ + if (arg == F_UNLCK || + ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) || ((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode)))) return generic_setlease(file, arg, lease); else if (tlink_tcon(cfile->tlink)->local_lease && -- cgit v1.1 From 754789a1c046106cfdb067102642f73e0fd35fb3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 15 Aug 2014 23:49:01 -0500 Subject: [CIFS] Workaround MacOS server problem with SMB2.1 write response Writes fail to Mac servers with SMB2.1 mounts (works with cifs though) due to them sending an incorrect RFC1001 length for the SMB2.1 Write response. Workaround this problem. MacOS server sends a write response with 3 bytes of pad beyond the end of the SMB itself. The RFC1001 length is 3 bytes more than the sum of the SMB2.1 header length + the write reponse. Incorporate feedback from Jeff and JRA to allow servers to send a tcp frame that is even more than three bytes too long (ie much longer than the SMB2/SMB3 request that it contains) but we do log it once now. In the earlier version of the patch I had limited how far off the length field could be before we fail the request. Signed-off-by: Steve French --- fs/cifs/smb2misc.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index f2e6ac2..4aa7a0f 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -178,9 +178,24 @@ smb2_check_message(char *buf, unsigned int length) /* Windows 7 server returns 24 bytes more */ if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE) return 0; - /* server can return one byte more */ + /* server can return one byte more due to implied bcc[0] */ if (clc_len == 4 + len + 1) return 0; + + /* + * MacOS server pads after SMB2.1 write response with 3 bytes + * of junk. Other servers match RFC1001 len to actual + * SMB2/SMB3 frame length (header + smb2 response specific data) + * Log the server error (once), but allow it and continue + * since the frame is parseable. + */ + if (clc_len < 4 /* RFC1001 header size */ + len) { + printk_once(KERN_WARNING + "SMB2 server sent bad RFC1001 len %d not %d\n", + len, clc_len - 4); + return 0; + } + return 1; } return 0; -- cgit v1.1 From b5f2a8c02697c3685ccbbb66495465742ffa0dc1 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Wed, 6 Aug 2014 16:30:04 -0400 Subject: of: Allow mem_reserve of memory with a base address of zero __reserved_mem_reserve_reg() won't reserve memory if the base address is zero. This change removes the check for a base address of zero and allows it to be reserved. Allowing the first 4K of memory to be reserved will help solve a problem on some ARM systems where the the first 16K of memory is unused and becomes allocable memory. This will prevent this memory from being used for DMA by drivers like the USB OHCI driver which consider a physical address of zero to be illegal. Cc: stable@vger.kernel.org # 3.15+ Signed-off-by: Al Cooper Signed-off-by: Grant Likely --- drivers/of/fdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index f46a24f..79cb831 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -453,7 +453,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, base = dt_mem_next_cell(dt_root_addr_cells, &prop); size = dt_mem_next_cell(dt_root_size_cells, &prop); - if (base && size && + if (size && early_init_dt_reserve_memory_arch(base, size, nomap) == 0) pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n", uname, &base, (unsigned long)size / SZ_1M); -- cgit v1.1 From b951f9dc7f25fc1e39aafda5edb4b47b38285d9f Mon Sep 17 00:00:00 2001 From: Gaurav Minocha Date: Sat, 26 Jul 2014 12:48:50 -0700 Subject: Enabling OF selftest to run without machine's devicetree If there is no devicetree present, this patch adds the selftest data as a live devicetree. It also removes the same after the testcase execution is complete. Tested with and without machine's devicetree. Signed-off-by: Gaurav Minocha Signed-off-by: Grant Likely --- drivers/of/selftest.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index d410026..a737cb5 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c @@ -27,6 +27,7 @@ static struct selftest_results { #define NO_OF_NODES 2 static struct device_node *nodes[NO_OF_NODES]; static int last_node_index; +static bool selftest_live_tree; #define selftest(result, fmt, ...) { \ if (!(result)) { \ @@ -630,13 +631,6 @@ static int attach_node_and_children(struct device_node *np) { struct device_node *next, *root = np, *dup; - if (!np) { - pr_warn("%s: No tree to attach; not running tests\n", - __func__); - return -ENODATA; - } - - /* skip root node */ np = np->child; /* storing a copy in temporary node */ @@ -672,12 +666,12 @@ static int attach_node_and_children(struct device_node *np) static int __init selftest_data_add(void) { void *selftest_data; - struct device_node *selftest_data_node; + struct device_node *selftest_data_node, *np; extern uint8_t __dtb_testcases_begin[]; extern uint8_t __dtb_testcases_end[]; const int size = __dtb_testcases_end - __dtb_testcases_begin; - if (!size || !of_allnodes) { + if (!size) { pr_warn("%s: No testcase data to attach; not running tests\n", __func__); return -ENODATA; @@ -692,6 +686,22 @@ static int __init selftest_data_add(void) return -ENOMEM; } of_fdt_unflatten_tree(selftest_data, &selftest_data_node); + if (!selftest_data_node) { + pr_warn("%s: No tree to attach; not running tests\n", __func__); + return -ENODATA; + } + + if (!of_allnodes) { + /* enabling flag for removing nodes */ + selftest_live_tree = true; + of_allnodes = selftest_data_node; + + for_each_of_allnodes(np) + __of_attach_node_sysfs(np); + of_aliases = of_find_node_by_path("/aliases"); + of_chosen = of_find_node_by_path("/chosen"); + return 0; + } /* attach the sub-tree to live tree */ return attach_node_and_children(selftest_data_node); @@ -723,6 +733,18 @@ static void selftest_data_remove(void) struct device_node *np; struct property *prop; + if (selftest_live_tree) { + of_node_put(of_aliases); + of_node_put(of_chosen); + of_aliases = NULL; + of_chosen = NULL; + for_each_child_of_node(of_allnodes, np) + detach_node_and_children(np); + __of_detach_node_sysfs(of_allnodes); + of_allnodes = NULL; + return; + } + while (last_node_index >= 0) { if (nodes[last_node_index]) { np = of_find_node_by_path(nodes[last_node_index]->full_name); -- cgit v1.1 From a9ecdc0fdc54aa499604dbd43132988effcac9b4 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 6 Aug 2014 13:02:27 -0700 Subject: of/irq: Fix lookup to use 'interrupts-extended' property first In case the Device Tree blob passed by the boot agent supplies both an 'interrupts-extended' and an 'interrupts' property in order to allow for older kernels to be usable, prefer the new-style 'interrupts-extended' property which conveys a lot more information. This allows us to have bootloaders willingly maintaining backwards compatibility with older kernels without entirely deprecating the 'interrupts' property. Update the bindings documentation to describe a situation where both the 'interrupts-extended' and the 'interrupts' property are present, and which one takes precedence over the other. Cc: stable@vger.kernel.org # 3.13+ Acked-by: Rob Herring Signed-off-by: Brian Norris Signed-off-by: Florian Fainelli Signed-off-by: Grant Likely --- .../bindings/interrupt-controller/interrupts.txt | 12 +++++++----- drivers/of/irq.c | 17 +++++++++-------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt index 1486497..ce6a1a0 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt @@ -4,11 +4,13 @@ Specifying interrupt information for devices 1) Interrupt client nodes ------------------------- -Nodes that describe devices which generate interrupts must contain an either an -"interrupts" property or an "interrupts-extended" property. These properties -contain a list of interrupt specifiers, one per output interrupt. The format of -the interrupt specifier is determined by the interrupt controller to which the -interrupts are routed; see section 2 below for details. +Nodes that describe devices which generate interrupts must contain an +"interrupts" property, an "interrupts-extended" property, or both. If both are +present, the latter should take precedence; the former may be provided simply +for compatibility with software that does not recognize the latter. These +properties contain a list of interrupt specifiers, one per output interrupt. The +format of the interrupt specifier is determined by the interrupt controller to +which the interrupts are routed; see section 2 below for details. Example: interrupt-parent = <&intc1>; diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 3e06a69..1471e0a 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -301,16 +301,17 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar /* Get the reg property (if any) */ addr = of_get_property(device, "reg", NULL); + /* Try the new-style interrupts-extended first */ + res = of_parse_phandle_with_args(device, "interrupts-extended", + "#interrupt-cells", index, out_irq); + if (!res) + return of_irq_parse_raw(addr, out_irq); + /* Get the interrupts property */ intspec = of_get_property(device, "interrupts", &intlen); - if (intspec == NULL) { - /* Try the new-style interrupts-extended */ - res = of_parse_phandle_with_args(device, "interrupts-extended", - "#interrupt-cells", index, out_irq); - if (res) - return -EINVAL; - return of_irq_parse_raw(addr, out_irq); - } + if (intspec == NULL) + return -EINVAL; + intlen /= sizeof(*intspec); pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); -- cgit v1.1 From 16466f4284154311f163a58b77379eb186274f87 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 14 Aug 2014 16:52:51 -0700 Subject: net: phy: bcm7xxx: remove 28nm wildcard entry A wildcard entry with the 32-bits OUI 0x600d8400 was added as part of the BCM7xxx internal PHY driver, but that entry might match other PHYs that are not covered by this driver, so let's just remove it. Fixes: b560a58c45c6 ("net: phy: add Broadcom BCM7xxx internal PHY driver") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/bcm7xxx.c | 14 -------------- include/linux/brcmphy.h | 1 - 2 files changed, 15 deletions(-) diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 526b94c..2b40548 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -287,19 +287,6 @@ static struct phy_driver bcm7xxx_driver[] = { .resume = bcm7xxx_28nm_config_init, .driver = { .owner = THIS_MODULE }, }, { - .name = "Broadcom BCM7XXX 28nm", - .phy_id = PHY_ID_BCM7XXX_28, - .phy_id_mask = PHY_BCM_OUI_MASK, - .features = PHY_GBIT_FEATURES | - SUPPORTED_Pause | SUPPORTED_Asym_Pause, - .flags = PHY_IS_INTERNAL, - .config_init = bcm7xxx_28nm_config_init, - .config_aneg = genphy_config_aneg, - .read_status = genphy_read_status, - .suspend = bcm7xxx_suspend, - .resume = bcm7xxx_28nm_config_init, - .driver = { .owner = THIS_MODULE }, -}, { .phy_id = PHY_BCM_OUI_4, .phy_id_mask = 0xffff0000, .name = "Broadcom BCM7XXX 40nm", @@ -331,7 +318,6 @@ static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { { PHY_ID_BCM7366, 0xfffffff0, }, { PHY_ID_BCM7439, 0xfffffff0, }, { PHY_ID_BCM7445, 0xfffffff0, }, - { PHY_ID_BCM7XXX_28, 0xfffffc00 }, { PHY_BCM_OUI_4, 0xffff0000 }, { PHY_BCM_OUI_5, 0xffffff00 }, { } diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index 6f76277..61219b9 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -16,7 +16,6 @@ #define PHY_ID_BCM7366 0x600d8490 #define PHY_ID_BCM7439 0x600d8480 #define PHY_ID_BCM7445 0x600d8510 -#define PHY_ID_BCM7XXX_28 0x600d8400 #define PHY_BCM_OUI_MASK 0xfffffc00 #define PHY_BCM_OUI_1 0x00206000 -- cgit v1.1 From 4fd14e0b4a4fdb57a2b96659cb8adae255cd225d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 14 Aug 2014 16:52:52 -0700 Subject: net: phy: bcm7xxx: re-advertise all supported modes out of suspend The BCM7xxx internal Gigabit PHYs on 28nm process platforms come out reset without any half-duplex or "hub" compatible advertised modes, which was causing auto-negotiation issues coming out of S3 suspend/resume, we just could not establish a link with a half-duplex only link partner. Make sure that the resume function properly re-configures the PHY device to advertise all supported modes. Fixes: b560a58c45c6 ("net: phy: add Broadcom BCM7xxx internal PHY driver") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/bcm7xxx.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 2b40548..a8ca03f 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -157,6 +157,23 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev) return bcm7xxx_28nm_afe_config_init(phydev); } +static int bcm7xxx_28nm_resume(struct phy_device *phydev) +{ + int ret; + + /* Re-apply workarounds coming out suspend/resume */ + ret = bcm7xxx_28nm_config_init(phydev); + if (ret) + return ret; + + /* 28nm Gigabit PHYs come out of reset without any half-duplex + * or "hub" compliant advertised mode, fix that. This does not + * cause any problems with the PHY library since genphy_config_aneg() + * gracefully handles auto-negotiated and forced modes. + */ + return genphy_config_aneg(phydev); +} + static int phy_set_clr_bits(struct phy_device *dev, int location, int set_mask, int clr_mask) { @@ -258,7 +275,7 @@ static struct phy_driver bcm7xxx_driver[] = { .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .suspend = bcm7xxx_suspend, - .resume = bcm7xxx_28nm_afe_config_init, + .resume = bcm7xxx_28nm_resume, .driver = { .owner = THIS_MODULE }, }, { .phy_id = PHY_ID_BCM7439, @@ -271,7 +288,7 @@ static struct phy_driver bcm7xxx_driver[] = { .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .suspend = bcm7xxx_suspend, - .resume = bcm7xxx_28nm_afe_config_init, + .resume = bcm7xxx_28nm_resume, .driver = { .owner = THIS_MODULE }, }, { .phy_id = PHY_ID_BCM7445, @@ -284,7 +301,7 @@ static struct phy_driver bcm7xxx_driver[] = { .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .suspend = bcm7xxx_suspend, - .resume = bcm7xxx_28nm_config_init, + .resume = bcm7xxx_28nm_afe_config_init, .driver = { .owner = THIS_MODULE }, }, { .phy_id = PHY_BCM_OUI_4, -- cgit v1.1 From 82c084f56a01160afa39d4b6899b66c7153d0002 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 14 Aug 2014 16:52:53 -0700 Subject: net: phy: bcm7xxx: remove suspend callback for 28nm PHYs BCM7xxx internal Gigabit PHY on 28nm process do not need anything special to be done during suspend, remove the suspend callback since it might be harmful rather than useful. While at it, update the comment above bcm7xxx_suspend() to reflect that it applies only to 40nm and 65nm process PHY devices. Fixes: b560a58c45c6 ("net: phy: add Broadcom BCM7xxx internal PHY driver") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/bcm7xxx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index a8ca03f..fdce1ea 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -229,7 +229,7 @@ static int bcm7xxx_config_init(struct phy_device *phydev) } /* Workaround for putting the PHY in IDDQ mode, required - * for all BCM7XXX PHYs + * for all BCM7XXX 40nm and 65nm PHYs */ static int bcm7xxx_suspend(struct phy_device *phydev) { @@ -274,7 +274,6 @@ static struct phy_driver bcm7xxx_driver[] = { .config_init = bcm7xxx_28nm_afe_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, - .suspend = bcm7xxx_suspend, .resume = bcm7xxx_28nm_resume, .driver = { .owner = THIS_MODULE }, }, { @@ -287,7 +286,6 @@ static struct phy_driver bcm7xxx_driver[] = { .config_init = bcm7xxx_28nm_afe_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, - .suspend = bcm7xxx_suspend, .resume = bcm7xxx_28nm_resume, .driver = { .owner = THIS_MODULE }, }, { @@ -300,7 +298,6 @@ static struct phy_driver bcm7xxx_driver[] = { .config_init = bcm7xxx_28nm_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, - .suspend = bcm7xxx_suspend, .resume = bcm7xxx_28nm_afe_config_init, .driver = { .owner = THIS_MODULE }, }, { -- cgit v1.1 From e050dbeb0d1e19072d0d656b51f06af1af860f19 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 15 Aug 2014 10:19:39 +0200 Subject: batman-adv: Fix parameter order of hlist_add_behind 1d023284c31a4e40a94d5bbcb7dbb7a35ee0bcbc ("list: fix order of arguments for hlist_add_after(_rcu)") was incorrectly rebased on top of d9124268d84a836f14a6ead54ff9d8eee4c43be5 ("batman-adv: Fix out-of-order fragmentation support"). The parameter order change of the rebased patch was not re-applied as expected. This causes a memory leak and can cause crashes when out-of-order packets are received. hlist_add_behind will try to access the uninitalized list pointers of frag_entry_new to find the previous/next entry and may modify/read random memory locations. Signed-off-by: Sven Eckelmann Cc: Andrew Morton Signed-off-by: David S. Miller --- net/batman-adv/fragmentation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index 52c43f9..fc1835c 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -188,7 +188,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, /* Reached the end of the list, so insert after 'frag_entry_last'. */ if (likely(frag_entry_last)) { - hlist_add_behind(&frag_entry_last->list, &frag_entry_new->list); + hlist_add_behind(&frag_entry_new->list, &frag_entry_last->list); chain->size += skb->len - hdr_size; chain->timestamp = jiffies; ret = true; -- cgit v1.1 From 21009686662fd21412ca35def7cb3cc8346e1c3d Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Fri, 15 Aug 2014 15:00:38 +0200 Subject: net: phy: smsc: move smsc_phy_config_init reset part in a soft_reset function On the one hand, phy_device.c provides a generic reset function if the phy driver does not provide a soft_reset pointer. This generic reset does not take into account the state of the phy, with a potential failure if the phy is in powerdown mode. On the other hand, smsc driver provides a function with both correct reset behaviour and configuration. This patch moves the reset part into a new smsc_phy_reset function and provides the soft_reset pointer to have a correct reset behaviour by default. Signed-off-by: Gwenhael Goavec-Merou Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/smsc.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 180c494..a4b0819 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -43,6 +43,22 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev) static int smsc_phy_config_init(struct phy_device *phydev) { + int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); + + if (rc < 0) + return rc; + + /* Enable energy detect mode for this SMSC Transceivers */ + rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, + rc | MII_LAN83C185_EDPWRDOWN); + if (rc < 0) + return rc; + + return smsc_phy_ack_interrupt(phydev); +} + +static int smsc_phy_reset(struct phy_device *phydev) +{ int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES); if (rc < 0) return rc; @@ -66,18 +82,7 @@ static int smsc_phy_config_init(struct phy_device *phydev) rc = phy_read(phydev, MII_BMCR); } while (rc & BMCR_RESET); } - - rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); - if (rc < 0) - return rc; - - /* Enable energy detect mode for this SMSC Transceivers */ - rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, - rc | MII_LAN83C185_EDPWRDOWN); - if (rc < 0) - return rc; - - return smsc_phy_ack_interrupt (phydev); + return 0; } static int lan911x_config_init(struct phy_device *phydev) @@ -142,6 +147,7 @@ static struct phy_driver smsc_phy_driver[] = { .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .config_init = smsc_phy_config_init, + .soft_reset = smsc_phy_reset, /* IRQ related */ .ack_interrupt = smsc_phy_ack_interrupt, @@ -164,6 +170,7 @@ static struct phy_driver smsc_phy_driver[] = { .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .config_init = smsc_phy_config_init, + .soft_reset = smsc_phy_reset, /* IRQ related */ .ack_interrupt = smsc_phy_ack_interrupt, @@ -186,6 +193,7 @@ static struct phy_driver smsc_phy_driver[] = { .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .config_init = smsc_phy_config_init, + .soft_reset = smsc_phy_reset, /* IRQ related */ .ack_interrupt = smsc_phy_ack_interrupt, @@ -230,6 +238,7 @@ static struct phy_driver smsc_phy_driver[] = { .config_aneg = genphy_config_aneg, .read_status = lan87xx_read_status, .config_init = smsc_phy_config_init, + .soft_reset = smsc_phy_reset, /* IRQ related */ .ack_interrupt = smsc_phy_ack_interrupt, -- cgit v1.1 From ac32c7f705692b92fe12dcbe88fe87136fdfff6f Mon Sep 17 00:00:00 2001 From: Erik Hugne Date: Fri, 15 Aug 2014 16:44:35 +0200 Subject: tipc: fix message importance range check Commit 3b4f302d8578 ("tipc: eliminate redundant locking") introduced a bug by removing the sanity check for message importance, allowing programs to assign any value to the msg_user field. This will mess up the packet reception logic and may cause random link resets. Signed-off-by: Erik Hugne Signed-off-by: David S. Miller --- net/tipc/port.h | 4 +++- net/tipc/socket.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/net/tipc/port.h b/net/tipc/port.h index 3f93454..a69118f 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -179,8 +179,10 @@ static inline int tipc_port_importance(struct tipc_port *port) return msg_importance(&port->phdr); } -static inline void tipc_port_set_importance(struct tipc_port *port, int imp) +static inline int tipc_port_set_importance(struct tipc_port *port, int imp) { + if (imp > TIPC_CRITICAL_IMPORTANCE) + return -EINVAL msg_set_importance(&port->phdr, (u32)imp); } diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 7d423ee..ff8c811 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1973,7 +1973,7 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt, switch (opt) { case TIPC_IMPORTANCE: - tipc_port_set_importance(port, value); + res = tipc_port_set_importance(port, value); break; case TIPC_SRC_DROPPABLE: if (sock->type != SOCK_STREAM) -- cgit v1.1 From 18f39e7be0121317550d03e267e3ebd4dbfbb3ce Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 17 Aug 2014 00:22:24 -0500 Subject: [CIFS] Possible null ptr deref in SMB2_tcon As Raphael Geissert pointed out, tcon_error_exit can dereference tcon and there is one path in which tcon can be null. Signed-off-by: Steve French CC: Stable # v3.7+ Reported-by: Raphael Geissert --- fs/cifs/smb2pdu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 74440af..240c627 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -907,7 +907,8 @@ tcon_exit: tcon_error_exit: if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); - tcon->bad_network_name = true; + if (tcon) + tcon->bad_network_name = true; } goto tcon_exit; } -- cgit v1.1 From 52755808d4525f4d5b86d112d36ffc7a46f3fb48 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Mon, 18 Aug 2014 20:49:57 +0400 Subject: CIFS: Fix SMB2 readdir error handling SMB2 servers indicates the end of a directory search with STATUS_NO_MORE_FILE error code that is not processed now. This causes generic/257 xfstest to fail. Fix this by triggering the end of search by this error code in SMB2_query_directory. Also when negotiating CIFS protocol we tell the server to close the search automatically at the end and there is no need to do it itself. In the case of SMB2 protocol, we need to close it explicitly - separate close directory checks for different protocols. Cc: Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 2 ++ fs/cifs/file.c | 2 +- fs/cifs/readdir.c | 2 +- fs/cifs/smb1ops.c | 7 +++++++ fs/cifs/smb2maperror.c | 2 +- fs/cifs/smb2ops.c | 9 +++++++++ fs/cifs/smb2pdu.c | 9 ++++----- 7 files changed, 25 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index bc20a6e..ce24c1f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -409,6 +409,8 @@ struct smb_version_operations { /* get mtu credits */ int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int, unsigned int *, unsigned int *); + /* check if we need to issue closedir */ + bool (*dir_needs_close)(struct cifsFileInfo *); }; struct smb_version_values { diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 4ab2f79..d5fec92 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -762,7 +762,7 @@ int cifs_closedir(struct inode *inode, struct file *file) cifs_dbg(FYI, "Freeing private data in close dir\n"); spin_lock(&cifs_file_list_lock); - if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { + if (server->ops->dir_needs_close(cfile)) { cfile->invalidHandle = true; spin_unlock(&cifs_file_list_lock); if (server->ops->close_dir) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b15862e..798c80a 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -593,7 +593,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, /* close and restart search */ cifs_dbg(FYI, "search backing up - close and restart search\n"); spin_lock(&cifs_file_list_lock); - if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { + if (server->ops->dir_needs_close(cfile)) { cfile->invalidHandle = true; spin_unlock(&cifs_file_list_lock); if (server->ops->close) diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 5e8c22d..1a6df4b 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -1015,6 +1015,12 @@ cifs_wp_retry_size(struct inode *inode) return CIFS_SB(inode->i_sb)->wsize; } +static bool +cifs_dir_needs_close(struct cifsFileInfo *cfile) +{ + return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle; +} + struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, @@ -1086,6 +1092,7 @@ struct smb_version_operations smb1_operations = { .create_mf_symlink = cifs_create_mf_symlink, .is_read_op = cifs_is_read_op, .wp_retry_size = cifs_wp_retry_size, + .dir_needs_close = cifs_dir_needs_close, #ifdef CONFIG_CIFS_XATTR .query_all_EAs = CIFSSMBQAllEAs, .set_EA = CIFSSMBSetEA, diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index e31a9df..a689514 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"}, {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"}, {STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"}, - {STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"}, + {STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"}, {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"}, {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"}, {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"}, diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 85be34a..3fcd410 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1222,6 +1222,12 @@ smb2_wp_retry_size(struct inode *inode) SMB2_MAX_BUFFER_SIZE); } +static bool +smb2_dir_needs_close(struct cifsFileInfo *cfile) +{ + return !cfile->invalidHandle; +} + struct smb_version_operations smb20_operations = { .compare_fids = smb2_compare_fids, .setup_request = smb2_setup_request, @@ -1297,6 +1303,7 @@ struct smb_version_operations smb20_operations = { .parse_lease_buf = smb2_parse_lease_buf, .clone_range = smb2_clone_range, .wp_retry_size = smb2_wp_retry_size, + .dir_needs_close = smb2_dir_needs_close, }; struct smb_version_operations smb21_operations = { @@ -1374,6 +1381,7 @@ struct smb_version_operations smb21_operations = { .parse_lease_buf = smb2_parse_lease_buf, .clone_range = smb2_clone_range, .wp_retry_size = smb2_wp_retry_size, + .dir_needs_close = smb2_dir_needs_close, }; struct smb_version_operations smb30_operations = { @@ -1454,6 +1462,7 @@ struct smb_version_operations smb30_operations = { .clone_range = smb2_clone_range, .validate_negotiate = smb3_validate_negotiate, .wp_retry_size = smb2_wp_retry_size, + .dir_needs_close = smb2_dir_needs_close, }; struct smb_version_values smb20_values = { diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 240c627..fa0dd04 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2180,6 +2180,10 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base; if (rc) { + if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) { + srch_inf->endOfSearch = true; + rc = 0; + } cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); goto qdir_exit; } @@ -2217,11 +2221,6 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, else cifs_dbg(VFS, "illegal search buffer type\n"); - if (rsp->hdr.Status == STATUS_NO_MORE_FILES) - srch_inf->endOfSearch = 1; - else - srch_inf->endOfSearch = 0; - return rc; qdir_exit: -- cgit v1.1 From b46799a8f28c43c5264ac8d8ffa28b311b557e03 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Mon, 18 Aug 2014 20:49:58 +0400 Subject: CIFS: Fix wrong directory attributes after rename When we requests rename we also need to update attributes of both source and target parent directories. Not doing it causes generic/309 xfstest to fail on SMB2 mounts. Fix this by marking these directories for force revalidating. Cc: Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/inode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 41de393..753e7a3 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1717,6 +1717,12 @@ unlink_target: target_dentry, to_name); } + /* force revalidate to go get info when needed */ + CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0; + + source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime = + target_dir->i_mtime = current_fs_time(source_dir->i_sb); + cifs_rename_exit: kfree(info_buf_source); kfree(from_name); -- cgit v1.1 From 72f79f9e35bd3f78ee8853f2fcacaa197d23ebac Mon Sep 17 00:00:00 2001 From: Suman Tripathi Date: Fri, 8 Aug 2014 21:44:25 +0530 Subject: ahci_xgene: Removing NCQ support from the APM X-Gene SoC AHCI SATA Host Controller driver. This patch removes the NCQ support from the APM X-Gene SoC AHCI Host Controller driver as it doesn't support it. Signed-off-by: Loc Ho Signed-off-by: Suman Tripathi Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/ahci_xgene.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index bc28111..c696230 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -344,7 +344,7 @@ static struct ata_port_operations xgene_ahci_ops = { }; static const struct ata_port_info xgene_ahci_port_info = { - .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ, + .flags = AHCI_FLAG_COMMON, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &xgene_ahci_ops, @@ -480,7 +480,7 @@ static int xgene_ahci_probe(struct platform_device *pdev) /* Configure the host controller */ xgene_ahci_hw_init(hpriv); - hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ; + hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ; rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info); if (rc) -- cgit v1.1 From b741e8d4cf812da665c763e1b1c4a8fd20121565 Mon Sep 17 00:00:00 2001 From: Arjun Sreedharan Date: Sat, 16 Aug 2014 18:38:34 +0530 Subject: pata_samsung_cf: change ret type to signed Change return type to signed int since it could be a negative errno. Signed-off-by: Arjun Sreedharan Signed-off-by: Tejun Heo --- drivers/ata/pata_samsung_cf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index 2578fc1..1a24a5d 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -360,7 +360,7 @@ static int pata_s3c_wait_after_reset(struct ata_link *link, /* * pata_s3c_bus_softreset - PATA device software reset */ -static unsigned int pata_s3c_bus_softreset(struct ata_port *ap, +static int pata_s3c_bus_softreset(struct ata_port *ap, unsigned long deadline) { struct ata_ioports *ioaddr = &ap->ioaddr; -- cgit v1.1 From 0e5740770f34381b5742654a5f297e335c548de5 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Mon, 11 Aug 2014 13:17:48 +0300 Subject: ata: ahci_tegra: Change include to fix compilation Before this patch, the driver included , which was effectively renamed to at about the same time the ahci_tegra series landed. Fix the include path so that the driver compiles. Signed-off-by: Mikko Perttunen Acked-by: Thierry Reding Signed-off-by: Tejun Heo --- drivers/ata/ahci_tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c index fc3df47..f1fef74 100644 --- a/drivers/ata/ahci_tegra.c +++ b/drivers/ata/ahci_tegra.c @@ -24,8 +24,8 @@ #include #include #include -#include #include +#include #include "ahci.h" #define SATA_CONFIGURATION_0 0x180 -- cgit v1.1 From 5e163903ba59c347ad8ecd18decf0a1901518a92 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 29 Jul 2014 11:10:07 -0700 Subject: MAINTAINERS: Change maintainer for gpio-bcm-kona.c Since I no longer have access to the hardware, Ray Jui will take over maintaining the Kona GPIO driver. In addition, my former e-mail addresses mmayer@broadcom.com and markus.mayer@linaro.org will cease to function shortly. So, I used an address I can still be reached at as the "author" addess here. Signed-off-by: Markus Mayer Signed-off-by: Markus Mayer Signed-off-by: Linus Walleij --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index aefa948..98f578f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2059,7 +2059,7 @@ S: Supported F: drivers/scsi/bnx2i/ BROADCOM KONA GPIO DRIVER -M: Markus Mayer +M: Ray Jui L: bcm-kernel-feedback-list@broadcom.com S: Supported F: drivers/gpio/gpio-bcm-kona.c -- cgit v1.1 From 0f05a3ae45f09c20240c8b47152e0333d4d3f717 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 29 Jul 2014 17:16:48 +0200 Subject: gpiolib: devres: use correct structure type name in sizeof Correct typo in the name of the type given to sizeof. Because it is the size of a pointer that is wanted, the typo has no impact on compilation or execution. This problem was found using Coccinelle (http://coccinelle.lip6.fr/). The semantic patch used can be found in message 0 of this patch series. Signed-off-by: Julia Lawall Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/devres.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 41b2f40..954b9f6 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -90,7 +90,7 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, struct gpio_desc **dr; struct gpio_desc *desc; - dr = devres_alloc(devm_gpiod_release, sizeof(struct gpiod_desc *), + dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *), GFP_KERNEL); if (!dr) return ERR_PTR(-ENOMEM); -- cgit v1.1 From 6dd859508336f0fd078fd62f3b9fe42a32aa38e2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 18 Jul 2014 11:52:13 +0200 Subject: gpio: zynq: Fix IRQ handlers The Zynq GPIO interrupt handling code as two main issues: 1) It does not support IRQF_ONESHOT interrupt since it uses handle_simple_irq() for the interrupt handler. handle_simple_irq() does not do masking and unmasking of the IRQ that is required for this chip to be able to support IRQF_ONESHOT IRQs, causing the CPU to lock up in a interrupt storm if such a interrupt is requested. 2) Interrupts are acked after the primary interrupt handlers for all asserted interrupts in a bank have been called. For edge triggered interrupt this is to late and may cause a interrupt to be missed. For level triggered oneshot interrupts this is to early and causes the interrupt handler to run twice per interrupt. This patch addresses the issue by updating the driver to use the correct IRQ chip handler functions that are appropriate for this kind of IRQ controller. The following diagram gives an overview of how the interrupt detection circuit works, it is not necessarily a accurate depiction of the real hardware though. INT_POL/INT_ON_ANY | | +---+ INT_STATUS `-| | | | E |-. | ,---| | \ |\ +----+ | +---+ | +---+ `----| | ,-------|S | ,*--| | GPIO_IN -* | |- | Q|- | & |-- IRQ_OUT | +---+ ,-----| | ,-|R | ,o| | `---| | / |/ | +----+ | +---+ | = |- | | | ,-| | INT_TYPE ACK INT_MASK | +---+ | INT_POL GPIO_IN is the raw signal level connected to the hardware pin. This signal is routed to a edge detector and to a level detector. The edge detector can be configured to either detect a rising or falling edge or both edges. The level detector can detect either a level high or level low event. Depending on the setting of the INT_TYPE register either the edge or level event will be propagated to the INT_STATUS register. As long as a interrupt condition is detected the INT_STATUS register will be set to 1. It can be cleared to 0 if (and only if) the interrupt condition is no longer detected and software acknowledges the interrupt by writing a 1 to the address of the INT_STATUS register. There is also the INT_MASK register which can be used to disable the propagation of the INT_STATUS signal to the upstream IRQ controller. What is important to note is that the interrupt detection logic itself can not be disabled, only the propagation of the INT_STATUS register can be delayed. This means that for level type interrupts the interrupt must only be acknowledged after the interrupt source has been cleared otherwise it will stay asserted and the interrupt handler will be run a second time. For IRQF_ONESHOT interrupts this means that the IRQ must only be acknowledged after the threaded interrupt has finished running. If a second interrupt comes in between handling the first interrupt and acknowledging it the external interrupt will be asserted, which means trying to acknowledge the first interrupt will not clear the INT_STATUS register and the interrupt handler will be run a second time when the IRQ is unmasked, so no interrupts will be lost. The handle_fasteoi_irq() handler in combination with the IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED flags will have the desired behavior. For edge triggered interrupts a slightly different strategy is necessary. For edge triggered interrupts the interrupt condition is only true when the edge itself is detected, this means this is the only time the INT_STATUS register is set, acknowledging the interrupt any time after that will clear the INT_STATUS register until the next interrupt happens. This means in order to not loose any interrupts the interrupt needs to be acknowledged before running the interrupt handler. If a second interrupt occurs after the first interrupt handler has finished but before the interrupt is unmasked the INT_STATUS register will be re-asserted and the interrupt handler runs a second time once the interrupt is unmasked. This means with this flow handling strategy no interrupts are lost for edge triggered interrupts. The handle_level_irq() handler will have the desired behavior. (Note: The handle_edge_irq() only needs to be used for edge triggered interrupts where the controller stops detecting the interrupt event when the interrupt is masked, for this controller the detection logic still works, while only the propagation is delayed when the interrupt is masked.) Signed-off-by: Lars-Peter Clausen Acked-by: Soren Brinkmann Signed-off-by: Linus Walleij --- drivers/gpio/gpio-zynq.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index c3145f9..31ad5df 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -95,6 +95,9 @@ struct zynq_gpio { struct clk *clk; }; +static struct irq_chip zynq_gpio_level_irqchip; +static struct irq_chip zynq_gpio_edge_irqchip; + /** * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank * for a given pin in the GPIO device @@ -410,6 +413,15 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) gpio->base_addr + ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); writel_relaxed(int_any, gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); + + if (type & IRQ_TYPE_LEVEL_MASK) { + __irq_set_chip_handler_name_locked(irq_data->irq, + &zynq_gpio_level_irqchip, handle_fasteoi_irq, NULL); + } else { + __irq_set_chip_handler_name_locked(irq_data->irq, + &zynq_gpio_edge_irqchip, handle_level_irq, NULL); + } + return 0; } @@ -424,9 +436,21 @@ static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on) } /* irq chip descriptor */ -static struct irq_chip zynq_gpio_irqchip = { +static struct irq_chip zynq_gpio_level_irqchip = { .name = DRIVER_NAME, .irq_enable = zynq_gpio_irq_enable, + .irq_eoi = zynq_gpio_irq_ack, + .irq_mask = zynq_gpio_irq_mask, + .irq_unmask = zynq_gpio_irq_unmask, + .irq_set_type = zynq_gpio_set_irq_type, + .irq_set_wake = zynq_gpio_set_wake, + .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED, +}; + +static struct irq_chip zynq_gpio_edge_irqchip = { + .name = DRIVER_NAME, + .irq_enable = zynq_gpio_irq_enable, + .irq_ack = zynq_gpio_irq_ack, .irq_mask = zynq_gpio_irq_mask, .irq_unmask = zynq_gpio_irq_unmask, .irq_set_type = zynq_gpio_set_irq_type, @@ -469,10 +493,6 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) offset); generic_handle_irq(gpio_irq); } - - /* clear IRQ in HW */ - writel_relaxed(int_sts, gpio->base_addr + - ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); } } @@ -610,14 +630,14 @@ static int zynq_gpio_probe(struct platform_device *pdev) writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); - ret = gpiochip_irqchip_add(chip, &zynq_gpio_irqchip, 0, - handle_simple_irq, IRQ_TYPE_NONE); + ret = gpiochip_irqchip_add(chip, &zynq_gpio_edge_irqchip, 0, + handle_level_irq, IRQ_TYPE_NONE); if (ret) { dev_err(&pdev->dev, "Failed to add irq chip\n"); goto err_rm_gpiochip; } - gpiochip_set_chained_irqchip(chip, &zynq_gpio_irqchip, irq, + gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, irq, zynq_gpio_irqhandler); pm_runtime_set_active(&pdev->dev); -- cgit v1.1 From 8a69155040bf8745a9a95da8cbaab2940b4093d5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 8 Aug 2014 12:07:51 +0200 Subject: gpio: delete unneeded test before of_node_put MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Of_node_put supports NULL as its argument, so the initial test is not necessary. Suggested by Uwe Kleine-König. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression e; @@ -if (e) of_node_put(e); // Signed-off-by: Julia Lawall Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 7cfdc22..604dbe6 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -307,7 +307,5 @@ void of_gpiochip_add(struct gpio_chip *chip) void of_gpiochip_remove(struct gpio_chip *chip) { gpiochip_remove_pin_ranges(chip); - - if (chip->of_node) - of_node_put(chip->of_node); + of_node_put(chip->of_node); } -- cgit v1.1 From ad3829cf1db5cf6a5dfafd54f9291b44f5fb1da8 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 17 Aug 2014 06:43:58 -0500 Subject: Incorrect error returned on setting file compressed on SMB2 When the server (for an SMB2 or SMB3 mount) doesn't support an ioctl (such as setting the compressed flag on a file) we were incorrectly returning EIO instead of EOPNOTSUPP, this is confusing e.g. doing chattr +c to a file on a non-btrfs Samba partition, now the error returned is more intuitive to the user. Also fixes error mapping on setting hardlink to servers which don't support that. Signed-off-by: Steve French Reviewed-by: David Disseldorp --- fs/cifs/smb2maperror.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index a689514..af59d03 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -298,7 +298,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { {STATUS_INVALID_PARAMETER, -EINVAL, "STATUS_INVALID_PARAMETER"}, {STATUS_NO_SUCH_DEVICE, -ENODEV, "STATUS_NO_SUCH_DEVICE"}, {STATUS_NO_SUCH_FILE, -ENOENT, "STATUS_NO_SUCH_FILE"}, - {STATUS_INVALID_DEVICE_REQUEST, -EIO, "STATUS_INVALID_DEVICE_REQUEST"}, + {STATUS_INVALID_DEVICE_REQUEST, -EOPNOTSUPP, "STATUS_INVALID_DEVICE_REQUEST"}, {STATUS_END_OF_FILE, -ENODATA, "STATUS_END_OF_FILE"}, {STATUS_WRONG_VOLUME, -EIO, "STATUS_WRONG_VOLUME"}, {STATUS_NO_MEDIA_IN_DEVICE, -EIO, "STATUS_NO_MEDIA_IN_DEVICE"}, -- cgit v1.1 From 31742c5a331766bc7df6b0d525df00c6cd20d5a6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 17 Aug 2014 08:38:47 -0500 Subject: enable fallocate punch hole ("fallocate -p") for SMB3 Implement FALLOC_FL_PUNCH_HOLE (which does not change the file size fortunately so this matches the behavior of the equivalent SMB3 fsctl call) for SMB3 mounts. This allows "fallocate -p" to work. It requires that the server support setting files as sparse (which Windows allows). Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 19 +++++++++++++++++++ fs/cifs/cifsglob.h | 2 ++ fs/cifs/smb2ops.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.h | 6 ++++++ fs/cifs/smbfsctl.h | 2 +- 5 files changed, 73 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0a4a4d7..155347e 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -207,6 +207,19 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } +static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len) +{ + struct super_block *sb = file->f_path.dentry->d_sb; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); + struct TCP_Server_Info *server = tcon->ses->server; + + if (server->ops->fallocate) + return server->ops->fallocate(file, tcon, mode, off, len); + + return -EOPNOTSUPP; +} + static int cifs_permission(struct inode *inode, int mask) { struct cifs_sb_info *cifs_sb; @@ -909,6 +922,7 @@ const struct file_operations cifs_file_ops = { .unlocked_ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ .setlease = cifs_setlease, + .fallocate = cifs_fallocate, }; const struct file_operations cifs_file_strict_ops = { @@ -928,6 +942,7 @@ const struct file_operations cifs_file_strict_ops = { .unlocked_ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ .setlease = cifs_setlease, + .fallocate = cifs_fallocate, }; const struct file_operations cifs_file_direct_ops = { @@ -948,6 +963,7 @@ const struct file_operations cifs_file_direct_ops = { #endif /* CONFIG_CIFS_POSIX */ .llseek = cifs_llseek, .setlease = cifs_setlease, + .fallocate = cifs_fallocate, }; const struct file_operations cifs_file_nobrl_ops = { @@ -966,6 +982,7 @@ const struct file_operations cifs_file_nobrl_ops = { .unlocked_ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ .setlease = cifs_setlease, + .fallocate = cifs_fallocate, }; const struct file_operations cifs_file_strict_nobrl_ops = { @@ -984,6 +1001,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = { .unlocked_ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ .setlease = cifs_setlease, + .fallocate = cifs_fallocate, }; const struct file_operations cifs_file_direct_nobrl_ops = { @@ -1003,6 +1021,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = { #endif /* CONFIG_CIFS_POSIX */ .llseek = cifs_llseek, .setlease = cifs_setlease, + .fallocate = cifs_fallocate, }; const struct file_operations cifs_dir_ops = { diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ce24c1f..dfc731b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -411,6 +411,8 @@ struct smb_version_operations { unsigned int *, unsigned int *); /* check if we need to issue closedir */ bool (*dir_needs_close)(struct cifsFileInfo *); + long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, + loff_t); }; struct smb_version_values { diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 3fcd410..101670c 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1015,6 +1015,50 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, + loff_t offset, loff_t len) +{ + struct inode *inode; + struct cifsInodeInfo *cifsi; + struct cifsFileInfo *cfile = file->private_data; + struct file_zero_data_information fsctl_buf; + long rc; + unsigned int xid; + __u8 set_sparse = 1; + + xid = get_xid(); + + inode = cfile->dentry->d_inode; + cifsi = CIFS_I(inode); + + /* Need to make file sparse, if not already, before freeing range. */ + /* Consider adding equivalent for compressed since it could also work */ + if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) + return -EOPNOTSUPP; + + cifs_dbg(FYI, "offset %lld len %lld", offset, len); + + fsctl_buf.FileOffset = cpu_to_le64(offset); + fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len); + + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, + true /* is_fctl */, (char *)&fsctl_buf, + sizeof(struct file_zero_data_information), NULL, NULL); + free_xid(xid); + return rc; +} + +static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, + loff_t off, loff_t len) +{ + /* KEEP_SIZE already checked for by do_fallocate */ + if (mode & FALLOC_FL_PUNCH_HOLE) + return smb3_punch_hole(file, tcon, off, len); + + return -EOPNOTSUPP; +} + static void smb2_downgrade_oplock(struct TCP_Server_Info *server, struct cifsInodeInfo *cinode, bool set_level2) @@ -1463,6 +1507,7 @@ struct smb_version_operations smb30_operations = { .validate_negotiate = smb3_validate_negotiate, .wp_retry_size = smb2_wp_retry_size, .dir_needs_close = smb2_dir_needs_close, + .fallocate = smb3_fallocate, }; struct smb_version_values smb20_values = { diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 69f3595..fbe486c 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -573,6 +573,12 @@ struct copychunk_ioctl { __u32 Reserved2; } __packed; +/* this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA */ +struct file_zero_data_information { + __le64 FileOffset; + __le64 BeyondFinalZero; +} __packed; + struct copychunk_ioctl_rsp { __le32 ChunksWritten; __le32 ChunkBytesWritten; diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h index 0e538b5..83efa59 100644 --- a/fs/cifs/smbfsctl.h +++ b/fs/cifs/smbfsctl.h @@ -63,7 +63,7 @@ #define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */ #define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */ #define FSCTL_SET_SPARSE 0x000900C4 /* BB add struct */ -#define FSCTL_SET_ZERO_DATA 0x000900C8 /* BB add struct */ +#define FSCTL_SET_ZERO_DATA 0x000980C8 #define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */ #define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */ #define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */ -- cgit v1.1 From 30175628bf7f521e9ee31ac98fa6d6fe7441a556 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 17 Aug 2014 18:16:40 -0500 Subject: [SMB3] Enable fallocate -z support for SMB3 mounts fallocate -z (FALLOC_FL_ZERO_RANGE) can map to SMB3 FSCTL_SET_ZERO_DATA SMB3 FSCTL but FALLOC_FL_ZERO_RANGE when called without the FALLOC_FL_KEEPSIZE flag set could want the file size changed so we can not support that subcase unless the file is cached (and thus we know the file size). Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky --- fs/cifs/smb2ops.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 101670c..5a48aa2 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1015,6 +1015,56 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, return rc; } +static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, + loff_t offset, loff_t len, bool keep_size) +{ + struct inode *inode; + struct cifsInodeInfo *cifsi; + struct cifsFileInfo *cfile = file->private_data; + struct file_zero_data_information fsctl_buf; + long rc; + unsigned int xid; + + xid = get_xid(); + + inode = cfile->dentry->d_inode; + cifsi = CIFS_I(inode); + + /* if file not oplocked can't be sure whether asking to extend size */ + if (!CIFS_CACHE_READ(cifsi)) + if (keep_size == false) + return -EOPNOTSUPP; + + /* + * Must check if file sparse since fallocate -z (zero range) assumes + * non-sparse allocation + */ + if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) + return -EOPNOTSUPP; + + /* + * need to make sure we are not asked to extend the file since the SMB3 + * fsctl does not change the file size. In the future we could change + * this to zero the first part of the range then set the file size + * which for a non sparse file would zero the newly extended range + */ + if (keep_size == false) + if (i_size_read(inode) < offset + len) + return -EOPNOTSUPP; + + cifs_dbg(FYI, "offset %lld len %lld", offset, len); + + fsctl_buf.FileOffset = cpu_to_le64(offset); + fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len); + + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, + true /* is_fctl */, (char *)&fsctl_buf, + sizeof(struct file_zero_data_information), NULL, NULL); + free_xid(xid); + return rc; +} + static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, loff_t offset, loff_t len) { @@ -1055,6 +1105,11 @@ static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, /* KEEP_SIZE already checked for by do_fallocate */ if (mode & FALLOC_FL_PUNCH_HOLE) return smb3_punch_hole(file, tcon, off, len); + else if (mode & FALLOC_FL_ZERO_RANGE) { + if (mode & FALLOC_FL_KEEP_SIZE) + return smb3_zero_range(file, tcon, off, len, true); + return smb3_zero_range(file, tcon, off, len, false); + } return -EOPNOTSUPP; } -- cgit v1.1 From 060d517de88867b06225119beeba3a0472cc6bc5 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 22 Jul 2014 10:30:50 +0200 Subject: ARM: imx6: fix SMP compilation again My earlier patch 1fc593feaf8e ("ARM: imx: build i.MX6 functions only when needed") fixed a problem with building an i.MX5 kernel, but now the problem has returned for the case where we allow ARMv6K SMP builds in multiplatform. With CONFIG_CPU_V7 disabled, but i.MX3 and SMP enabled, we get this build error: arch/arm/mach-imx/built-in.o: In function `v7_secondary_startup': :(.text+0x5124): undefined reference to `v7_invalidate_l1' This puts the code inside of an "ifdef CONFIG_SOC_IMX6" to hopefully do the right thing in all configurations. Signed-off-by: Arnd Bergmann Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index ac88599..23c0293 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -93,9 +93,11 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o +ifdef CONFIG_SOC_IMX6 AFLAGS_headsmp.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +endif obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o mach-imx6sx.o -- cgit v1.1 From 59d05b518321618177b898a6801503e31b15b25b Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sat, 26 Jul 2014 10:33:03 +0800 Subject: ARM: imx: fix TLB missing of IOMUXC base address during suspend After the suspend routine running in OCRAM puts DDR into self-refresh, it will access IOMUXC block to float DDR IO for power saving. A TLB missing of IOMUXC base address may happen in this case, and triggers an access to DDR, and thus hangs the system. The failure is discovered by running suspend/resume on a Cubox-i board. Though the issue is not Cubox-i specific, it can be hit the on the board quite easily with the 3.15 or 3.16 kernel. Fix the issue with a dummy access to IOMUXC block at the beginning of suspend routine, so that the address translation can be filled into TLB before DDR is put into self-refresh. Signed-off-by: Shawn Guo Cc: Acked-by: Anson Huang --- arch/arm/mach-imx/suspend-imx6.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S index 74b50f1..ca4ea2d 100644 --- a/arch/arm/mach-imx/suspend-imx6.S +++ b/arch/arm/mach-imx/suspend-imx6.S @@ -173,6 +173,8 @@ ENTRY(imx6_suspend) ldr r6, [r11, #0x0] ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] ldr r6, [r11, #0x0] + ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] + ldr r6, [r11, #0x0] /* use r11 to store the IO address */ ldr r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET] -- cgit v1.1 From df2160749d389933e8cf43d88e3ed2e072eafc64 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 29 Jul 2014 15:29:45 +0800 Subject: ARM: imx: remove unnecessary ARCH_HAS_OPP select Since ARCH_MXC already selects ARCH_HAS_OPP, it's really unnecessary for SOC_IMX27 and SOC_IMX5 to select it again. Signed-off-by: Shawn Guo --- arch/arm/mach-imx/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 9de84a2..be9a51a 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -85,7 +85,6 @@ config SOC_IMX25 config SOC_IMX27 bool - select ARCH_HAS_OPP select CPU_ARM926T select IMX_HAVE_IOMUX_V1 select MXC_AVIC @@ -659,7 +658,6 @@ comment "Device tree only" config SOC_IMX5 bool - select ARCH_HAS_OPP select HAVE_IMX_SRC select MXC_TZIC -- cgit v1.1 From 0aa4dcb5b730f5da2540926b94d98636fe7d1cbc Mon Sep 17 00:00:00 2001 From: Bill Pringlemeir Date: Tue, 5 Aug 2014 13:34:00 -0400 Subject: ARM: dts: vf610-twr: Fix pinctrl_esdhc1 pin definitions. Previous version had an extra 'fsl' which made the pins not match any entry. The console message, vf610-pinctrl 40048000.iomuxc: no fsl,pins property in node \ /soc/aips-bus@40000000/iomuxc@40048000/vf610-twr/esdhc1grp is displayed without the fix. The prior version would generally work as u-boot sets the pins properly for sdhc. This change allows Linux sdhc use even if u-boot is built without sdhc support. Signed-off-by: Bill Pringlemeir Acked-by: Stefan Agner Fixes: 0517fe6aa880 ("ARM: dts: vf610-twr: Add support for sdhc1") Cc: Signed-off-by: Shawn Guo --- arch/arm/boot/dts/vf610-twr.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts index 11d7334..b8a5e8c 100644 --- a/arch/arm/boot/dts/vf610-twr.dts +++ b/arch/arm/boot/dts/vf610-twr.dts @@ -168,7 +168,7 @@ }; pinctrl_esdhc1: esdhc1grp { - fsl,fsl,pins = < + fsl,pins = < VF610_PAD_PTA24__ESDHC1_CLK 0x31ef VF610_PAD_PTA25__ESDHC1_CMD 0x31ef VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef -- cgit v1.1 From a40687ff73a5b14909d6aa522f7d778b158911c5 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 13 Aug 2014 09:48:45 +1000 Subject: md/raid5: avoid livelock caused by non-aligned writes. If a stripe in a raid6 array received a write to each data block while the array is degraded, and if any of these writes to a missing device are not page-aligned, then a live-lock happens. In this case the P and Q blocks need to be read so that the part of the missing block which is *not* being updated by the write can be constructed. Due to a logic error, these blocks are not loaded, so the update cannot proceed and the stripe is 'handled' repeatedly in an infinite loop. This bug is unlikely as most writes are page aligned. However as it can lead to a livelock it is suitable for -stable. It was introduced in 3.16. Cc: stable@vger.kernel.org (v3.16) Fixed: 67f455486d2ea20b2d94d6adf5b9b783d079e321 Signed-off-by: NeilBrown --- drivers/md/raid5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6234b2e..6b2d615 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2922,7 +2922,7 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) && !test_bit(R5_OVERWRITE, &fdev[0]->flags)) || (sh->raid_conf->level == 6 && s->failed && s->to_write && - s->to_write < sh->raid_conf->raid_disks - 2 && + s->to_write - s->non_overwrite < sh->raid_conf->raid_disks - 2 && (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))))) { /* we would like to get this block, possibly by computing it, * otherwise read it if the backing disk is insync -- cgit v1.1 From 9c4bdf697c39805078392d5ddbbba5ae5680e0dd Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 13 Aug 2014 09:57:07 +1000 Subject: md/raid6: avoid data corruption during recovery of double-degraded RAID6 During recovery of a double-degraded RAID6 it is possible for some blocks not to be recovered properly, leading to corruption. If a write happens to one block in a stripe that would be written to a missing device, and at the same time that stripe is recovering data to the other missing device, then that recovered data may not be written. This patch skips, in the double-degraded case, an optimisation that is only safe for single-degraded arrays. Bug was introduced in 2.6.32 and fix is suitable for any kernel since then. In an older kernel with separate handle_stripe5() and handle_stripe6() functions the patch must change handle_stripe6(). Cc: stable@vger.kernel.org (2.6.32+) Fixes: 6c0069c0ae9659e3a91b68eaed06a5c6c37f45c8 Cc: Yuri Tikhonov Cc: Dan Williams Reported-by: "Manibalan P" Tested-by: "Manibalan P" Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1090423 Signed-off-by: NeilBrown Acked-by: Dan Williams --- drivers/md/raid5.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6b2d615..183588b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3817,6 +3817,8 @@ static void handle_stripe(struct stripe_head *sh) set_bit(R5_Wantwrite, &dev->flags); if (prexor) continue; + if (s.failed > 1) + continue; if (!test_bit(R5_Insync, &dev->flags) || ((i == sh->pd_idx || i == sh->qd_idx) && s.failed == 0)) -- cgit v1.1 From 2f643105e53256058d53bc26867c441fe70f21fc Mon Sep 17 00:00:00 2001 From: Silvio Fricke Date: Mon, 11 Aug 2014 15:53:11 +0200 Subject: ARM: dts: imx6: edmqmx6: change enet reset pin Signed-off-by: Silvio Fricke Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts index 8c1cb53..4fa2543 100644 --- a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts +++ b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts @@ -119,7 +119,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enet>; phy-mode = "rgmii"; - phy-reset-gpios = <&gpio3 23 0>; + phy-reset-gpios = <&gpio1 25 0>; phy-supply = <&vgen2_1v2_eth>; status = "okay"; }; @@ -339,6 +339,7 @@ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0 MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 >; }; -- cgit v1.1 From 6248c273eb305fb4fa3240cc0b840118c44cd122 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 12 Aug 2014 17:26:03 +0800 Subject: ARM: imx: correct gpu2d_axi and gpu3d_axi clock setting On i.MX6Q, gpu2d_axi and gpu3d_axi are either from AXI or AHB clock, but on i.MX6DL, gpu2d_axi and gpu3d_axi are from mmdc_ch0_axi_podf, and they can NOT be gated by mmdc_ch0_axi 's clock gate, the mux option register field(CCM_CBCMR) is marked as "Reserved" now on i.MX6DL RM, so correct these two clks setting. Signed-off-by: Anson Huang Signed-off-by: Shawn Guo --- arch/arm/mach-imx/clk-imx6q.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 6cceb77..29d4129 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -194,6 +194,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); clk[IMX6QDL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); clk[IMX6QDL_CLK_TWD] = imx_clk_fixed_factor("twd", "arm", 1, 2); + if (cpu_is_imx6dl()) { + clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1); + clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1); + } clk[IMX6QDL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); clk[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock); @@ -217,8 +221,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels)); clk[IMX6QDL_CLK_ASRC_SEL] = imx_clk_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); clk[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); - clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); - clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); + if (cpu_is_imx6q()) { + clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); + clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); + } clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels)); clk[IMX6QDL_CLK_GPU3D_CORE_SEL] = imx_clk_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels)); clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); -- cgit v1.1 From fa97d2f7448a2f998bca0f4d4e40d6ad49026554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Wed, 13 Aug 2014 15:47:47 +0200 Subject: ARM: dts: i.MX53: fix apparent bug in VPU clks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VPU on i.MX53 has two distinct clocks for register access and internal function. Signed-off-by: Lothar Waßmann Fixes: fbf970f61eb9 ("ARM: dts: mx53qsb: Enable VPU support") Cc: Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx53.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 64fa27b..c6c58c1 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -731,7 +731,7 @@ compatible = "fsl,imx53-vpu"; reg = <0x63ff4000 0x1000>; interrupts = <9>; - clocks = <&clks IMX5_CLK_VPU_GATE>, + clocks = <&clks IMX5_CLK_VPU_REFERENCE_GATE>, <&clks IMX5_CLK_VPU_GATE>; clock-names = "per", "ahb"; resets = <&src 1>; -- cgit v1.1 From 208bf9fdcd3575aa4a5d48b3e0295f7cdaf6fc44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 11 Aug 2014 13:15:35 +0300 Subject: drm/i915: Fix locking for intel_enable_pipe_a() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_enable_pipe_a() gets called with all the modeset locks already held (by drm_modeset_lock_all()), so trying to grab the same locks using another drm_modeset_acquire_ctx is going to fail miserably. Move most of the drm_modeset_acquire_ctx handling (init/drop/fini) out from intel_{get,release}_load_detect_pipe() into the callers (intel_{crt,tv}_detect()). Only the actual locking and backoff handling is left in intel_get_load_detect_pipe(). And in intel_enable_pipe_a() we just share the mode_config.acquire_ctx from drm_modeset_lock_all() which is already holding all the relevant locks. It's perfectly legal to lock the same ww_mutex multiple times using the same ww_acquire_ctx. drm_modeset_lock() will convert the returned -EALREADY into 0, so the caller doesn't need to do antyhing special. Fixes a hang on resume on my 830. Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Cc: stable@vger.kernel.org Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_crt.c | 7 ++++++- drivers/gpu/drm/i915/intel_display.c | 21 ++++----------------- drivers/gpu/drm/i915/intel_drv.h | 3 +-- drivers/gpu/drm/i915/intel_tv.c | 7 ++++++- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 2efaf8e..e8abfce 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -699,16 +699,21 @@ intel_crt_detect(struct drm_connector *connector, bool force) goto out; } + drm_modeset_acquire_init(&ctx, 0); + /* for pre-945g platforms use load detect */ if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) { if (intel_crt_detect_ddc(connector)) status = connector_status_connected; else status = intel_crt_load_detect(crt); - intel_release_load_detect_pipe(connector, &tmp, &ctx); + intel_release_load_detect_pipe(connector, &tmp); } else status = connector_status_unknown; + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + out: intel_display_power_put(dev_priv, power_domain); return status; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 018fb72..f02c80d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8462,8 +8462,6 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, connector->base.id, connector->name, encoder->base.id, encoder->name); - drm_modeset_acquire_init(ctx, 0); - retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); if (ret) @@ -8574,15 +8572,11 @@ fail_unlock: goto retry; } - drm_modeset_drop_locks(ctx); - drm_modeset_acquire_fini(ctx); - return false; } void intel_release_load_detect_pipe(struct drm_connector *connector, - struct intel_load_detect_pipe *old, - struct drm_modeset_acquire_ctx *ctx) + struct intel_load_detect_pipe *old) { struct intel_encoder *intel_encoder = intel_attached_encoder(connector); @@ -8606,17 +8600,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, drm_framebuffer_unreference(old->release_fb); } - goto unlock; return; } /* Switch crtc and encoder back off if necessary */ if (old->dpms_mode != DRM_MODE_DPMS_ON) connector->funcs->dpms(connector, old->dpms_mode); - -unlock: - drm_modeset_drop_locks(ctx); - drm_modeset_acquire_fini(ctx); } static int i9xx_pll_refclk(struct drm_device *dev, @@ -12659,7 +12648,7 @@ static void intel_enable_pipe_a(struct drm_device *dev) struct intel_connector *connector; struct drm_connector *crt = NULL; struct intel_load_detect_pipe load_detect_temp; - struct drm_modeset_acquire_ctx ctx; + struct drm_modeset_acquire_ctx *ctx = dev->mode_config.acquire_ctx; /* We can't just switch on the pipe A, we need to set things up with a * proper mode and output configuration. As a gross hack, enable pipe A @@ -12676,10 +12665,8 @@ static void intel_enable_pipe_a(struct drm_device *dev) if (!crt) return; - if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, &ctx)) - intel_release_load_detect_pipe(crt, &load_detect_temp, &ctx); - - + if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx)) + intel_release_load_detect_pipe(crt, &load_detect_temp); } static bool diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4b2664b..fe3431f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -830,8 +830,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, struct intel_load_detect_pipe *old, struct drm_modeset_acquire_ctx *ctx); void intel_release_load_detect_pipe(struct drm_connector *connector, - struct intel_load_detect_pipe *old, - struct drm_modeset_acquire_ctx *ctx); + struct intel_load_detect_pipe *old); int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, struct intel_engine_cs *pipelined); diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index e211eef..32186a6 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1323,11 +1323,16 @@ intel_tv_detect(struct drm_connector *connector, bool force) struct intel_load_detect_pipe tmp; struct drm_modeset_acquire_ctx ctx; + drm_modeset_acquire_init(&ctx, 0); + if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) { type = intel_tv_detect_type(intel_tv, connector); - intel_release_load_detect_pipe(connector, &tmp, &ctx); + intel_release_load_detect_pipe(connector, &tmp); } else return connector_status_unknown; + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); } else return connector->status; -- cgit v1.1 From a459249c73eaec1daf4e4657ea3564cc3550e66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 11 Aug 2014 13:15:36 +0300 Subject: drm/i915: Skip load detect when intel_crtc->new_enable==true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During suspend we turn off the crtcs, but leave the staged config in place so that we can restore the display(s) to their previous state on resume. During resume when we attempt to apply the force pipe A quirk we use the load detect mechanism. That doesn't check whether there was an already staged configuration for the crtc since that's not even possible during normal runtime load detection. But during resume it is possible, and if we just blindly go and overwrite the staged crtc configuration for the load detection we can no longer restore the display to the correct state. Even worse, we don't even clear all the staged connector->encoder->crtc links so we may end up using a cloned setup for the load detection, and after we're done we just clear the links related to the VGA output leaving the links for the other outputs in place. This will eventually result in calling intel_set_mode() with mode==NULL but with valid connector->encoder->crtc links which will result in dereferencing the NULL mode since the code thinks it will have to a modeset. To avoid these problems don't use any crtc with new_enabled==true for load detection. Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Cc: stable@vger.kernel.org (for 3.16) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f02c80d..c2b8146 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8500,10 +8500,14 @@ retry: i++; if (!(encoder->possible_crtcs & (1 << i))) continue; - if (!possible_crtc->enabled) { - crtc = possible_crtc; - break; - } + if (possible_crtc->enabled) + continue; + /* This can occur when applying the pipe A quirk on resume. */ + if (to_intel_crtc(possible_crtc)->new_enabled) + continue; + + crtc = possible_crtc; + break; } /* -- cgit v1.1 From 1add143caf593cfc7514f1c83470fba0664ae0a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 12 Aug 2014 19:39:52 +0300 Subject: drm/i915: Don't try to enable cursor from setplane when crtc is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure the cursor gets fully clipped when enabling it on a disabled crtc via setplane. This will prevent the lower level code from attempting to enable the cursor in hardware. Cc: Paulo Zanoni Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Cc: stable@vger.kernel.org Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c2b8146..2838300 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11693,8 +11693,8 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, }; const struct drm_rect clip = { /* integer pixels */ - .x2 = intel_crtc->config.pipe_src_w, - .y2 = intel_crtc->config.pipe_src_h, + .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0, + .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0, }; bool visible; int ret; -- cgit v1.1 From d717ea73e36dd5659640fae82605ad85c4117f4d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Aug 2014 17:18:53 +0200 Subject: pwm: Fix period and polarity in pwm_get() for non-perfect matches If pwm_get() finds a look-up entry with a perfect match (both dev_id and con_id match), the loop is aborted, and "p" still points to the correct struct pwm_lookup. If only an entry with a matching dev_id or con_id is found, the loop terminates after traversing the whole list, and "p" now points to arbitrary memory, not part of the pwm_lookup list. Then pwm_set_period() and pwm_set_polarity() will set random values for period resp. polarity. To fix this, save period and polarity when finding a new best match, just like is done for chip (for the provider) and index. This fixes the LCD backlight on r8a7740/armadillo-legacy, which was fed period 0 and polarity -1068821144 instead of 33333 resp. 1. Fixes: 3796ce1d4d4b ("pwm: add period and polarity to struct pwm_lookup") Signed-off-by: Geert Uytterhoeven Cc: stable@vger.kernel.org Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 4b66bf0..d2c3592 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -606,6 +606,8 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) unsigned int best = 0; struct pwm_lookup *p; unsigned int match; + unsigned int period; + enum pwm_polarity polarity; /* look up via DT first */ if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) @@ -653,6 +655,8 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) if (match > best) { chip = pwmchip_find_by_name(p->provider); index = p->index; + period = p->period; + polarity = p->polarity; if (match != 3) best = match; @@ -668,8 +672,8 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id) if (IS_ERR(pwm)) return pwm; - pwm_set_period(pwm, p->period); - pwm_set_polarity(pwm, p->polarity); + pwm_set_period(pwm, period); + pwm_set_polarity(pwm, polarity); return pwm; -- cgit v1.1 From e7f9fa5498d91fcdc63d93007ba43f36b1a30538 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Aug 2014 12:55:45 +0200 Subject: iommu/vt-d: Defer domain removal if device is assigned to a driver When the BUS_NOTIFY_DEL_DEVICE event is received the device might still be attached to a driver. In this case the domain can't be released as the mappings might still be in use. Defer the domain removal in this case until we receivce the BUS_NOTIFY_UNBOUND_DRIVER event. Cc: Jiang Liu Cc: David Woodhouse Cc: stable@vger.kernel.org # v3.15, v3.16 Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index d1f5caa..5619f26 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -3869,6 +3869,14 @@ static int device_notifier(struct notifier_block *nb, action != BUS_NOTIFY_DEL_DEVICE) return 0; + /* + * If the device is still attached to a device driver we can't + * tear down the domain yet as DMA mappings may still be in use. + * Wait for the BUS_NOTIFY_UNBOUND_DRIVER event to do that. + */ + if (action == BUS_NOTIFY_DEL_DEVICE && dev->driver != NULL) + return 0; + domain = find_domain(dev); if (!domain) return 0; -- cgit v1.1 From 9b29d3c6510407d91786c1cf9183ff4debb3473a Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 5 Aug 2014 17:50:15 +0200 Subject: iommu/amd: Fix cleanup_domain for mass device removal When multiple devices are detached in __detach_device, they are also removed from the domains dev_list. This makes it unsafe to use list_for_each_entry_safe, as the next pointer might also not be in the list anymore after __detach_device returns. So just repeatedly remove the first element of the list until it is empty. Cc: stable@vger.kernel.org Tested-by: Marti Raudsepp Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 1840531..ecb0109 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -3149,14 +3149,16 @@ free_domains: static void cleanup_domain(struct protection_domain *domain) { - struct iommu_dev_data *dev_data, *next; + struct iommu_dev_data *entry; unsigned long flags; write_lock_irqsave(&amd_iommu_devtable_lock, flags); - list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) { - __detach_device(dev_data); - atomic_set(&dev_data->bind, 0); + while (!list_empty(&domain->dev_list)) { + entry = list_first_entry(&domain->dev_list, + struct iommu_dev_data, list); + __detach_device(entry); + atomic_set(&entry->bind, 0); } write_unlock_irqrestore(&amd_iommu_devtable_lock, flags); -- cgit v1.1 From 4dc7c76cd500fa78c64adfda4b070b870a2b993c Mon Sep 17 00:00:00 2001 From: Arjun Sreedharan Date: Sun, 17 Aug 2014 20:00:09 +0530 Subject: pata_scc: propagate return value of scc_wait_after_reset scc_bus_softreset not necessarily should return zero. Propagate the error code. Signed-off-by: Arjun Sreedharan Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/pata_scc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 4e006d7..7f4cb76 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -585,7 +585,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask, * Note: Original code is ata_bus_softreset(). */ -static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, +static int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, unsigned long deadline) { struct ata_ioports *ioaddr = &ap->ioaddr; @@ -599,9 +599,7 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask, udelay(20); out_be32(ioaddr->ctl_addr, ap->ctl); - scc_wait_after_reset(&ap->link, devmask, deadline); - - return 0; + return scc_wait_after_reset(&ap->link, devmask, deadline); } /** @@ -618,7 +616,8 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes, { struct ata_port *ap = link->ap; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; - unsigned int devmask = 0, err_mask; + unsigned int devmask = 0; + int rc; u8 err; DPRINTK("ENTER\n"); @@ -634,9 +633,9 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes, /* issue bus reset */ DPRINTK("about to softreset, devmask=%x\n", devmask); - err_mask = scc_bus_softreset(ap, devmask, deadline); - if (err_mask) { - ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", err_mask); + rc = scc_bus_softreset(ap, devmask, deadline); + if (rc) { + ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", rc); return -EIO; } -- cgit v1.1 From 1c767b339b3938b19076ffdc9d70aa1e4235a45b Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 18 Aug 2014 14:42:42 +0300 Subject: drm/i915: take display port power domain in DP HPD handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville noticed that we can call ibx_digital_port_connected() which accesses the HW without holding any power well/runtime pm reference. Fix this by holding a display port power domain reference around the whole hpd_pulse handler. Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Reviewed-by: Dave Airlie Cc: stable@vger.kernel.org (3.16+) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ee3942f..a520188 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4037,15 +4037,21 @@ bool intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) { struct intel_dp *intel_dp = &intel_dig_port->dp; + struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - int ret; + enum intel_display_power_domain power_domain; + bool ret = true; + if (intel_dig_port->base.type != INTEL_OUTPUT_EDP) intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT; DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port, long_hpd ? "long" : "short"); + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + if (long_hpd) { if (!ibx_digital_port_connected(dev_priv, intel_dig_port)) goto mst_fail; @@ -4061,8 +4067,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) } else { if (intel_dp->is_mst) { - ret = intel_dp_check_mst_status(intel_dp); - if (ret == -EINVAL) + if (intel_dp_check_mst_status(intel_dp) == -EINVAL) goto mst_fail; } @@ -4076,7 +4081,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) drm_modeset_unlock(&dev->mode_config.connection_mutex); } } - return false; + ret = false; + goto put_power; mst_fail: /* if we were in MST mode, and device is not there get out of MST mode */ if (intel_dp->is_mst) { @@ -4084,7 +4090,10 @@ mst_fail: intel_dp->is_mst = false; drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst); } - return true; +put_power: + intel_display_power_put(dev_priv, power_domain); + + return ret; } /* Return which DP Port should be selected for Transcoder DP control */ -- cgit v1.1 From 6323751d28b0cc785dab972eff6b7fca1a165a40 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 18 Aug 2014 15:37:02 +0300 Subject: drm/i915: fix HPD IRQ reenable work cancelation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atm, the HPD IRQ reenable timer can get rearmed right after it's canceled. Also to access the HPD IRQ mask registers we need to wake up the HW. Solve both issues by converting the reenable timer to a delayed work and grabbing a runtime PM reference in the work. By this we can also forgo canceling the timer during runtime suspend, since the only important thing there is that the HW is awake when we write the registers and that's ensured by the RPM ref. So do the cancelation only during driver unload time; this is also a requirement for an upcoming patch where we want to cancel all HPD related works only during system suspend and driver unload time, but not during runtime suspend. Note that there is still a race between the HPD IRQ reenable work and drm_irq_uninstall() during driver unload, where the work can reenable the HPD IRQs disabled by drm_irq_uninstall(). This isn't a problem since the HPD IRQs will still be effectively masked by the first level interrupt mask. v2-3: - unchanged v4: - use proper API for changing the expiration time for an already pending delayed work (Jani) Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä (v2) Cc: stable@vger.kernel.org (3.16+) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_irq.c | 33 ++++++++++++--------------------- drivers/gpu/drm/i915/intel_display.c | 1 + 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4412f6a..1263aac 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1458,7 +1458,7 @@ struct drm_i915_private { } hpd_mark; } hpd_stats[HPD_NUM_PINS]; u32 hpd_event_bits; - struct timer_list hotplug_reenable_timer; + struct delayed_work hotplug_reenable_work; struct i915_fbc fbc; struct i915_drrs drrs; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 390ccc2..0050ee9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1189,8 +1189,8 @@ static void i915_hotplug_work_func(struct work_struct *work) * some connectors */ if (hpd_disabled) { drm_kms_helper_poll_enable(dev); - mod_timer(&dev_priv->hotplug_reenable_timer, - jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); + mod_delayed_work(system_wq, &dev_priv->hotplug_reenable_work, + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); } spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -1213,11 +1213,6 @@ static void i915_hotplug_work_func(struct work_struct *work) drm_kms_helper_hotplug_event(dev); } -static void intel_hpd_irq_uninstall(struct drm_i915_private *dev_priv) -{ - del_timer_sync(&dev_priv->hotplug_reenable_timer); -} - static void ironlake_rps_change_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3892,8 +3887,6 @@ static void gen8_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; - intel_hpd_irq_uninstall(dev_priv); - gen8_irq_reset(dev); } @@ -3908,8 +3901,6 @@ static void valleyview_irq_uninstall(struct drm_device *dev) I915_WRITE(VLV_MASTER_IER, 0); - intel_hpd_irq_uninstall(dev_priv); - for_each_pipe(pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); @@ -3988,8 +3979,6 @@ static void ironlake_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; - intel_hpd_irq_uninstall(dev_priv); - ironlake_irq_reset(dev); } @@ -4360,8 +4349,6 @@ static void i915_irq_uninstall(struct drm_device * dev) struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - intel_hpd_irq_uninstall(dev_priv); - if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -4598,8 +4585,6 @@ static void i965_irq_uninstall(struct drm_device * dev) if (!dev_priv) return; - intel_hpd_irq_uninstall(dev_priv); - I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -4615,14 +4600,18 @@ static void i965_irq_uninstall(struct drm_device * dev) I915_WRITE(IIR, I915_READ(IIR)); } -static void intel_hpd_irq_reenable(unsigned long data) +static void intel_hpd_irq_reenable(struct work_struct *work) { - struct drm_i915_private *dev_priv = (struct drm_i915_private *)data; + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), + hotplug_reenable_work.work); struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; unsigned long irqflags; int i; + intel_runtime_pm_get(dev_priv); + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) { struct drm_connector *connector; @@ -4648,6 +4637,8 @@ static void intel_hpd_irq_reenable(unsigned long data) if (dev_priv->display.hpd_irq_setup) dev_priv->display.hpd_irq_setup(dev); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + intel_runtime_pm_put(dev_priv); } void intel_irq_init(struct drm_device *dev) @@ -4670,8 +4661,8 @@ void intel_irq_init(struct drm_device *dev) setup_timer(&dev_priv->gpu_error.hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); - setup_timer(&dev_priv->hotplug_reenable_timer, intel_hpd_irq_reenable, - (unsigned long) dev_priv); + INIT_DELAYED_WORK(&dev_priv->hotplug_reenable_work, + intel_hpd_irq_reenable); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2838300..bcf8d18 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13104,6 +13104,7 @@ void intel_modeset_cleanup(struct drm_device *dev) */ drm_irq_uninstall(dev); cancel_work_sync(&dev_priv->hotplug_work); + cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work); dev_priv->pm._irqs_disabled = true; /* -- cgit v1.1 From 1d0d343abb70922adebebc1cfcef6622f4c7edec Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 18 Aug 2014 14:42:44 +0300 Subject: drm/i915: cancel hotplug and dig_port work during suspend and unload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure these work handlers don't run after we system suspend or unload the driver. Note that we don't cancel the handlers during runtime suspend. That could lead to a lockup, since we take a runtime PM ref from the handlers themselves. Fortunaltely canceling there is not needed since the RPM ref itself provides for the needed serialization. v2: - fix the order of canceling dig_port_work wrt. hotplug_work (Ville) - zero out {long,short}_hpd_port_mask and hpd_event_bits for speed (Ville) Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Cc: stable@vger.kernel.org (3.16+) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.c | 16 ++++++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 3 +-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ec96f9a..3f9c8f6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -494,6 +494,21 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) return true; } +void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) +{ + spin_lock_irq(&dev_priv->irq_lock); + + dev_priv->long_hpd_port_mask = 0; + dev_priv->short_hpd_port_mask = 0; + dev_priv->hpd_event_bits = 0; + + spin_unlock_irq(&dev_priv->irq_lock); + + cancel_work_sync(&dev_priv->dig_port_work); + cancel_work_sync(&dev_priv->hotplug_work); + cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work); +} + static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -538,6 +553,7 @@ static int i915_drm_freeze(struct drm_device *dev) flush_delayed_work(&dev_priv->rps.delayed_resume_work); intel_runtime_pm_disable_interrupts(dev); + intel_hpd_cancel_work(dev_priv); intel_suspend_gt_powersave(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1263aac..7a830ea 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2178,6 +2178,7 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on); +void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); extern void intel_console_resume(struct work_struct *work); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bcf8d18..d074d70 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13103,8 +13103,7 @@ void intel_modeset_cleanup(struct drm_device *dev) * experience fancy races otherwise. */ drm_irq_uninstall(dev); - cancel_work_sync(&dev_priv->hotplug_work); - cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work); + intel_hpd_cancel_work(dev_priv); dev_priv->pm._irqs_disabled = true; /* -- cgit v1.1 From 07f9cd0b3870e306ddc5abcc3af2d748c9bd378c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 18 Aug 2014 14:42:45 +0300 Subject: drm/i915: make sure VDD is turned off during system suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atm we may leave eDP VDD enabled during system suspend after the CRTCs are disabled through an HPD->DPCD read event. So disable VDD during suspend at a point when no HPDs can occur. Note that runtime suspend doesn't have the same problem, since there the RPM ref held by VDD provides already the needed serialization. v2: - add note to commit message about the runtime suspend path (Ville) - use edp_panel_vdd_off_sync(), so we can keep the WARN in edp_panel_vdd_off() (Ville) v3: - rebased on -fixes (for_each_intel_encoder()->list_for_each_entry()) (Imre) Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä (v2) Cc: stable@vger.kernel.org (3.16+) [Jani: fix sparse warning reported by Fengguang Wu] Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.c | 17 +++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 11 +++++++++++ drivers/gpu/drm/i915/intel_drv.h | 6 ++++++ 3 files changed, 34 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 3f9c8f6..e27cdbe 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -509,6 +509,21 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work); } +static void intel_suspend_encoders(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_encoder *encoder; + + drm_modeset_lock_all(dev); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + + if (intel_encoder->suspend) + intel_encoder->suspend(intel_encoder); + } + drm_modeset_unlock_all(dev); +} + static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -555,6 +570,8 @@ static int i915_drm_freeze(struct drm_device *dev) intel_runtime_pm_disable_interrupts(dev); intel_hpd_cancel_work(dev_priv); + intel_suspend_encoders(dev_priv); + intel_suspend_gt_powersave(dev); intel_modeset_suspend_hw(dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a520188..39b6431 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4003,6 +4003,16 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) kfree(intel_dig_port); } +static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); + + if (!is_edp(intel_dp)) + return; + + edp_panel_vdd_off_sync(intel_dp); +} + static void intel_dp_encoder_reset(struct drm_encoder *encoder) { intel_edp_panel_vdd_sanitize(to_intel_encoder(encoder)); @@ -4731,6 +4741,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->disable = intel_disable_dp; intel_encoder->get_hw_state = intel_dp_get_hw_state; intel_encoder->get_config = intel_dp_get_config; + intel_encoder->suspend = intel_dp_encoder_suspend; if (IS_CHERRYVIEW(dev)) { intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable; intel_encoder->pre_enable = chv_pre_enable_dp; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fe3431f..b8c8bbd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -153,6 +153,12 @@ struct intel_encoder { * be set correctly before calling this function. */ void (*get_config)(struct intel_encoder *, struct intel_crtc_config *pipe_config); + /* + * Called during system suspend after all pending requests for the + * encoder are flushed (for example for DP AUX transactions) and + * device interrupts are disabled. + */ + void (*suspend)(struct intel_encoder *); int crtc_mask; enum hpd_pin hpd_pin; }; -- cgit v1.1 From 1a125d8a2c22b11741fc47d4ffcf7a5ffa044dd3 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 18 Aug 2014 14:42:46 +0300 Subject: drm/i915: don't try to retrain a DP link on an inactive CRTC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atm we may retrain the DP link even if the CRTC is inactive through HPD work->intel_dp_check_link_status(). This in turn can lock up the PHY (at least on BYT), since the DP port is disabled. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=81948 Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Cc: stable@vger.kernel.org (3.16+) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 39b6431..67cfed6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3553,6 +3553,9 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) if (WARN_ON(!intel_encoder->base.crtc)) return; + if (!to_intel_crtc(intel_encoder->base.crtc)->active) + return; + /* Try to read receiver status if the link appears to be up */ if (!intel_dp_get_link_status(intel_dp, link_status)) { return; -- cgit v1.1 From 703e6a6ed6088705e48ca9d0e4567962ebddca36 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Mon, 18 Aug 2014 10:29:52 -0700 Subject: [IA64] Wire up memfd_create() system call Yet another system call. This one added by: commit 9183df25fe7b194563db3fec6dc3202a5855839c shm: add memfd_create() syscall Signed-off-by: Tony Luck --- arch/ia64/include/asm/unistd.h | 2 +- arch/ia64/include/uapi/asm/unistd.h | 1 + arch/ia64/kernel/entry.S | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index 4254f5d..10a14ea 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h @@ -11,7 +11,7 @@ -#define NR_syscalls 316 /* length of syscall table */ +#define NR_syscalls 317 /* length of syscall table */ /* * The following defines stop scripts/checksyscalls.sh from complaining about diff --git a/arch/ia64/include/uapi/asm/unistd.h b/arch/ia64/include/uapi/asm/unistd.h index 99801c3..6a65bb7 100644 --- a/arch/ia64/include/uapi/asm/unistd.h +++ b/arch/ia64/include/uapi/asm/unistd.h @@ -329,5 +329,6 @@ #define __NR_sched_getattr 1337 #define __NR_renameat2 1338 #define __NR_getrandom 1339 +#define __NR_memfd_create 1339 #endif /* _UAPI_ASM_IA64_UNISTD_H */ diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 4c13837..01edf24 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1777,6 +1777,7 @@ sys_call_table: data8 sys_sched_getattr data8 sys_renameat2 data8 sys_getrandom + data8 sys_memfd_create // 1340 .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */ -- cgit v1.1 From a3a80544acb3dfa97d43b8eee1332fe1fca7fe51 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 5 Aug 2014 10:25:55 +0100 Subject: arm64: fix typo in I-cache policy detection This removes an unfortunately placed semi-colon resulting in all instruction caches being classified as AIVIVT. Signed-off-by: Ard Biesheuvel Acked-by: Mark Rutland Signed-off-by: Will Deacon --- arch/arm64/kernel/cpuinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index f798f66..1771696 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -49,7 +49,7 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info) if (l1ip != ICACHE_POLICY_PIPT) set_bit(ICACHEF_ALIASING, &__icache_flags); - if (l1ip == ICACHE_POLICY_AIVIVT); + if (l1ip == ICACHE_POLICY_AIVIVT) set_bit(ICACHEF_AIVIVT, &__icache_flags); pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu); -- cgit v1.1 From a97a42c47608d0bb6f2dfc2e162cc84a27beb43a Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 11 Aug 2014 14:23:37 +0100 Subject: arm64: compat: wire up memfd_create and getrandom syscalls for aarch32 arch/arm/ just grew support for the new memfd_create and getrandom syscalls, so add them to our compat layer too. Signed-off-by: Will Deacon --- arch/arm64/include/asm/unistd.h | 2 +- arch/arm64/include/asm/unistd32.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index 4bc95d2..6d2bf41 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -41,7 +41,7 @@ #define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2) #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5) -#define __NR_compat_syscalls 383 +#define __NR_compat_syscalls 386 #endif #define __ARCH_WANT_SYS_CLONE diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index e242600..da1f06b 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h @@ -787,3 +787,8 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr) __SYSCALL(__NR_sched_getattr, sys_sched_getattr) #define __NR_renameat2 382 __SYSCALL(__NR_renameat2, sys_renameat2) + /* 383 for seccomp */ +#define __NR_getrandom 384 +__SYSCALL(__NR_getrandom, sys_getrandom) +#define __NR_memfd_create 385 +__SYSCALL(__NR_memfd_create, sys_memfd_create) -- cgit v1.1 From 503e6636b6f96056210062be703356f4253b6db9 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 11 Aug 2014 14:24:47 +0100 Subject: asm-generic: add memfd_create system call to unistd.h Commit 9183df25fe7b ("shm: add memfd_create() syscall") added a new system call (memfd_create) but didn't update the asm-generic unistd header. This patch adds the new system call to the asm-generic version of unistd.h so that it can be used by architectures such as arm64. Cc: Arnd Bergmann Reviewed-by: David Herrmann Signed-off-by: Will Deacon --- include/uapi/asm-generic/unistd.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index f1afd60..11d11bc 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -703,9 +703,11 @@ __SYSCALL(__NR_renameat2, sys_renameat2) __SYSCALL(__NR_seccomp, sys_seccomp) #define __NR_getrandom 278 __SYSCALL(__NR_getrandom, sys_getrandom) +#define __NR_memfd_create 279 +__SYSCALL(__NR_memfd_create, sys_memfd_create) #undef __NR_syscalls -#define __NR_syscalls 279 +#define __NR_syscalls 280 /* * All syscalls below here should go away really, -- cgit v1.1 From ec756d45b7f21888f4b44cb71b047e33ee2c8d8f Mon Sep 17 00:00:00 2001 From: Yang Wei Date: Tue, 5 Aug 2014 13:37:47 +0800 Subject: MIPS: perf: Mark pmu interupt IRQF_NO_THREAD In RT kernel, I ran into the following calltrace, so PMU interrupts cannot be threaded in_atomic(): 1, irqs_disabled(): 1, pid: 0, name: swapper/0 INFO: lockdep is turned off. Call Trace: [] dump_stack+0x1c/0x50 [] __might_sleep+0x13c/0x148 [] rt_spin_lock+0x3c/0xb0 [] __wake_up+0x3c/0x80 [] perf_event_wakeup+0x8c/0xf8 [] perf_pending_event+0x40/0x78 [] irq_work_run+0x74/0xc0 [] mipsxx_pmu_handle_shared_irq+0x110/0x228 [] mipsxx_pmu_handle_irq+0x14/0x30 [] handle_irq_event_percpu+0xbc/0x470 [] handle_percpu_irq+0x98/0xc8 [] generic_handle_irq+0x4c/0x68 [] do_IRQ+0x2c/0x48 [] plat_irq_dispatch+0x64/0xd0 [ralf@linux-mips.org: I don't see why based on this register dump the handler should be marked IRQF_NO_THREAD - but the handler is manipulating per-CPU resources so we don't want it to be rescheduled to another CPU.] Signed-off-by: Yang Wei Cc: a.p.zijlstra@chello.nl Cc: paulus@samba.org Cc: mingo@redhat.com Cc: acme@kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7506/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/perf_event_mipsxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index 14bf74b..b63f248 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -558,7 +558,7 @@ static int mipspmu_get_irq(void) if (mipspmu.irq >= 0) { /* Request my own irq handler. */ err = request_irq(mipspmu.irq, mipsxx_pmu_handle_irq, - IRQF_PERCPU | IRQF_NOBALANCING, + IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_THREAD, "mips_perf_pmu", NULL); if (err) { pr_warning("Unable to request IRQ%d for MIPS " -- cgit v1.1 From f28ff3d1ead40515c14ee841dc8b801c7d64353b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 8 Aug 2014 15:09:40 +0200 Subject: MIPS: GIC: Remove useless parens from GICBIS(). Signed-off-by: Ralf Baechle --- arch/mips/include/asm/gic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h index 3f20b21..d7699cf 100644 --- a/arch/mips/include/asm/gic.h +++ b/arch/mips/include/asm/gic.h @@ -49,7 +49,7 @@ #endif #define GICBIS(reg, mask, bits) \ do { u32 data; \ - GICREAD((reg), data); \ + GICREAD(reg, data); \ data &= ~(mask); \ data |= ((bits) & (mask)); \ GICWRITE((reg), data); \ -- cgit v1.1 From 701e1e789142042144c8cc10b8f6d1554e960144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 15 Aug 2014 11:52:53 +0200 Subject: drm/radeon: properly document reloc priority mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of hard coding the value properly document that this is an userspace interface. No intended functional change. Signed-off-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_cs.c | 3 ++- include/uapi/drm/radeon_drm.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index ee712c1..cb12df7 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -132,7 +132,8 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) * the buffers used for read only, which doubles the range * to 0 to 31. 32 is reserved for the kernel driver. */ - priority = (r->flags & 0xf) * 2 + !!r->write_domain; + priority = (r->flags & RADEON_RELOC_PRIO_MASK) * 2 + + !!r->write_domain; /* the first reloc of an UVD job is the msg and that must be in VRAM, also but everything into VRAM on AGP cards to avoid diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index 509b2d7..fea6099 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h @@ -944,6 +944,7 @@ struct drm_radeon_cs_chunk { }; /* drm_radeon_cs_reloc.flags */ +#define RADEON_RELOC_PRIO_MASK (0xf << 0) struct drm_radeon_cs_reloc { uint32_t handle; -- cgit v1.1 From 1538a9e0e04f6a5b323cd3d65e9320512978fcec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 18 Aug 2014 17:34:55 +0900 Subject: drm/radeon: Only flush HDP cache for indirect buffers from userspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It isn't necessary for command streams generated by the kernel (at least not while we aren't storing ring or indirect buffers in VRAM). Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/cik.c | 8 ++++---- drivers/gpu/drm/radeon/cik_sdma.c | 6 +++--- drivers/gpu/drm/radeon/evergreen.c | 4 ++-- drivers/gpu/drm/radeon/evergreen_dma.c | 2 +- drivers/gpu/drm/radeon/ni.c | 4 ++-- drivers/gpu/drm/radeon/r100.c | 8 ++++---- drivers/gpu/drm/radeon/r200.c | 2 +- drivers/gpu/drm/radeon/r300.c | 2 +- drivers/gpu/drm/radeon/r420.c | 4 ++-- drivers/gpu/drm/radeon/r600.c | 8 ++++---- drivers/gpu/drm/radeon/r600_dma.c | 6 +++--- drivers/gpu/drm/radeon/radeon.h | 8 +++++--- drivers/gpu/drm/radeon/radeon_cs.c | 6 +++--- drivers/gpu/drm/radeon/radeon_ib.c | 5 +++-- drivers/gpu/drm/radeon/radeon_ring.c | 16 ++++++++++------ drivers/gpu/drm/radeon/radeon_semaphore.c | 2 +- drivers/gpu/drm/radeon/radeon_test.c | 18 +++++++++--------- drivers/gpu/drm/radeon/radeon_uvd.c | 2 +- drivers/gpu/drm/radeon/radeon_vce.c | 6 +++--- drivers/gpu/drm/radeon/radeon_vm.c | 6 +++--- drivers/gpu/drm/radeon/rv515.c | 2 +- drivers/gpu/drm/radeon/rv770_dma.c | 2 +- drivers/gpu/drm/radeon/si.c | 6 +++--- drivers/gpu/drm/radeon/si_dma.c | 2 +- drivers/gpu/drm/radeon/uvd_v1_0.c | 4 ++-- 25 files changed, 73 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index e7d99e1..d61bc18 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -3801,7 +3801,7 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1)); radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2)); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); @@ -4004,7 +4004,7 @@ int cik_copy_cpdma(struct radeon_device *rdev, return r; } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); radeon_semaphore_free(rdev, &sem, *fence); return r; @@ -4103,7 +4103,7 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2); ib.ptr[2] = 0xDEADBEEF; ib.length_dw = 3; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_scratch_free(rdev, scratch); radeon_ib_free(rdev, &ib); @@ -4324,7 +4324,7 @@ static int cik_cp_gfx_start(struct radeon_device *rdev) radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */ - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); return 0; } diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index bcf4805..192278b 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -596,7 +596,7 @@ int cik_copy_dma(struct radeon_device *rdev, return r; } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); radeon_semaphore_free(rdev, &sem, *fence); return r; @@ -638,7 +638,7 @@ int cik_sdma_ring_test(struct radeon_device *rdev, radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr)); radeon_ring_write(ring, 1); /* number of DWs to follow */ radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = readl(ptr); @@ -695,7 +695,7 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.ptr[4] = 0xDEADBEEF; ib.length_dw = 5; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_ib_free(rdev, &ib); DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 4fedd14..dbca60c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2869,7 +2869,7 @@ static int evergreen_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); radeon_ring_write(ring, 0); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); cp_me = 0xff; WREG32(CP_ME_CNTL, cp_me); @@ -2912,7 +2912,7 @@ static int evergreen_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ radeon_ring_write(ring, 0x00000010); /* */ - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); return 0; } diff --git a/drivers/gpu/drm/radeon/evergreen_dma.c b/drivers/gpu/drm/radeon/evergreen_dma.c index 478caef..afaba38 100644 --- a/drivers/gpu/drm/radeon/evergreen_dma.c +++ b/drivers/gpu/drm/radeon/evergreen_dma.c @@ -155,7 +155,7 @@ int evergreen_copy_dma(struct radeon_device *rdev, return r; } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); radeon_semaphore_free(rdev, &sem, *fence); return r; diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 327b85f..ba89375 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1505,7 +1505,7 @@ static int cayman_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); radeon_ring_write(ring, 0); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); cayman_cp_enable(rdev, true); @@ -1547,7 +1547,7 @@ static int cayman_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ radeon_ring_write(ring, 0x00000010); /* */ - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); /* XXX init other rings */ diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 04b5940..4c5ec44 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -925,7 +925,7 @@ int r100_copy_blit(struct radeon_device *rdev, if (fence) { r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX); } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); return r; } @@ -958,7 +958,7 @@ void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) RADEON_ISYNC_ANY3D_IDLE2D | RADEON_ISYNC_WAIT_IDLEGUI | RADEON_ISYNC_CPSCRATCH_IDLEGUI); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } @@ -3638,7 +3638,7 @@ int r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) } radeon_ring_write(ring, PACKET0(scratch, 0)); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); if (tmp == 0xDEADBEEF) { @@ -3700,7 +3700,7 @@ int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.ptr[6] = PACKET2(0); ib.ptr[7] = PACKET2(0); ib.length_dw = 8; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); goto free_ib; diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c index 58f0473..6778037 100644 --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -121,7 +121,7 @@ int r200_copy_dma(struct radeon_device *rdev, if (fence) { r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX); } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); return r; } diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 75b3033..1bc4704 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -295,7 +295,7 @@ void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_write(ring, R300_GEOMETRY_ROUND_NEAREST | R300_COLOR_ROUND_NEAREST); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } static void r300_errata(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 802b192..2828605 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -219,7 +219,7 @@ static void r420_cp_errata_init(struct radeon_device *rdev) radeon_ring_write(ring, PACKET0(R300_CP_RESYNC_ADDR, 1)); radeon_ring_write(ring, rdev->config.r300.resync_scratch); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } static void r420_cp_errata_fini(struct radeon_device *rdev) @@ -232,7 +232,7 @@ static void r420_cp_errata_fini(struct radeon_device *rdev) radeon_ring_lock(rdev, ring, 8); radeon_ring_write(ring, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); radeon_ring_write(ring, R300_RB3D_DC_FINISH); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); radeon_scratch_free(rdev, rdev->config.r300.resync_scratch); } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c70a504..1e47701 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2547,7 +2547,7 @@ int r600_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1)); radeon_ring_write(ring, 0); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); cp_me = 0xff; WREG32(R_0086D8_CP_ME_CNTL, cp_me); @@ -2683,7 +2683,7 @@ int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1)); radeon_ring_write(ring, ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2)); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(scratch); if (tmp == 0xDEADBEEF) @@ -2845,7 +2845,7 @@ int r600_copy_cpdma(struct radeon_device *rdev, return r; } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); radeon_semaphore_free(rdev, &sem, *fence); return r; @@ -3165,7 +3165,7 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); ib.ptr[2] = 0xDEADBEEF; ib.length_dw = 3; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); goto free_ib; diff --git a/drivers/gpu/drm/radeon/r600_dma.c b/drivers/gpu/drm/radeon/r600_dma.c index 4969cef..51fd985 100644 --- a/drivers/gpu/drm/radeon/r600_dma.c +++ b/drivers/gpu/drm/radeon/r600_dma.c @@ -261,7 +261,7 @@ int r600_dma_ring_test(struct radeon_device *rdev, radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc); radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = readl(ptr); @@ -368,7 +368,7 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) ib.ptr[3] = 0xDEADBEEF; ib.length_dw = 4; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_ib_free(rdev, &ib); DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); @@ -493,7 +493,7 @@ int r600_copy_dma(struct radeon_device *rdev, return r; } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); radeon_semaphore_free(rdev, &sem, *fence); return r; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e715e0c..b281886 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -968,7 +968,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring, unsigned size); void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib); int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, - struct radeon_ib *const_ib); + struct radeon_ib *const_ib, bool hdp_flush); int radeon_ib_pool_init(struct radeon_device *rdev); void radeon_ib_pool_fini(struct radeon_device *rdev); int radeon_ib_ring_tests(struct radeon_device *rdev); @@ -978,8 +978,10 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev, void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *cp); int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ndw); int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ndw); -void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp); -void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp); +void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp, + bool hdp_flush); +void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp, + bool hdp_flush); void radeon_ring_undo(struct radeon_ring *ring); void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *cp); int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index cb12df7..83f382e 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -451,7 +451,7 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev, radeon_vce_note_usage(rdev); radeon_cs_sync_rings(parser); - r = radeon_ib_schedule(rdev, &parser->ib, NULL); + r = radeon_ib_schedule(rdev, &parser->ib, NULL, true); if (r) { DRM_ERROR("Failed to schedule IB !\n"); } @@ -542,9 +542,9 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, if ((rdev->family >= CHIP_TAHITI) && (parser->chunk_const_ib_idx != -1)) { - r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib); + r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib, true); } else { - r = radeon_ib_schedule(rdev, &parser->ib, NULL); + r = radeon_ib_schedule(rdev, &parser->ib, NULL, true); } out: diff --git a/drivers/gpu/drm/radeon/radeon_ib.c b/drivers/gpu/drm/radeon/radeon_ib.c index 65b0c21..5bf2c0a 100644 --- a/drivers/gpu/drm/radeon/radeon_ib.c +++ b/drivers/gpu/drm/radeon/radeon_ib.c @@ -107,6 +107,7 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib) * @rdev: radeon_device pointer * @ib: IB object to schedule * @const_ib: Const IB to schedule (SI only) + * @hdp_flush: Whether or not to perform an HDP cache flush * * Schedule an IB on the associated ring (all asics). * Returns 0 on success, error on failure. @@ -122,7 +123,7 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib) * to SI there was just a DE IB. */ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, - struct radeon_ib *const_ib) + struct radeon_ib *const_ib, bool hdp_flush) { struct radeon_ring *ring = &rdev->ring[ib->ring]; int r = 0; @@ -176,7 +177,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, if (ib->vm) radeon_vm_fence(rdev, ib->vm, ib->fence); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, hdp_flush); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 5b4e0cf..0678998 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -177,16 +177,18 @@ int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *ring, unsig * * @rdev: radeon_device pointer * @ring: radeon_ring structure holding ring information + * @hdp_flush: Whether or not to perform an HDP cache flush * * Update the wptr (write pointer) to tell the GPU to * execute new commands on the ring buffer (all asics). */ -void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring) +void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring, + bool hdp_flush) { /* If we are emitting the HDP flush via the ring buffer, we need to * do it before padding. */ - if (rdev->asic->ring[ring->idx]->hdp_flush) + if (hdp_flush && rdev->asic->ring[ring->idx]->hdp_flush) rdev->asic->ring[ring->idx]->hdp_flush(rdev, ring); /* We pad to match fetch size */ while (ring->wptr & ring->align_mask) { @@ -196,7 +198,7 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring) /* If we are emitting the HDP flush via MMIO, we need to do it after * all CPU writes to VRAM finished. */ - if (rdev->asic->mmio_hdp_flush) + if (hdp_flush && rdev->asic->mmio_hdp_flush) rdev->asic->mmio_hdp_flush(rdev); radeon_ring_set_wptr(rdev, ring); } @@ -207,12 +209,14 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring) * * @rdev: radeon_device pointer * @ring: radeon_ring structure holding ring information + * @hdp_flush: Whether or not to perform an HDP cache flush * * Call radeon_ring_commit() then unlock the ring (all asics). */ -void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring) +void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring, + bool hdp_flush) { - radeon_ring_commit(rdev, ring); + radeon_ring_commit(rdev, ring, hdp_flush); mutex_unlock(&rdev->ring_lock); } @@ -372,7 +376,7 @@ int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring, radeon_ring_write(ring, data[i]); } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); kfree(data); return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index dbd6bcd..56d9fd6 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -179,7 +179,7 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev, continue; } - radeon_ring_commit(rdev, &rdev->ring[i]); + radeon_ring_commit(rdev, &rdev->ring[i], false); radeon_fence_note_sync(fence, ring); semaphore->gpu_addr += 8; diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 5adf420..17bc3dc 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c @@ -288,7 +288,7 @@ static int radeon_test_create_and_emit_fence(struct radeon_device *rdev, return r; } radeon_fence_emit(rdev, fence, ring->idx); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } return 0; } @@ -313,7 +313,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringA); + radeon_ring_unlock_commit(rdev, ringA, false); r = radeon_test_create_and_emit_fence(rdev, ringA, &fence1); if (r) @@ -325,7 +325,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringA); + radeon_ring_unlock_commit(rdev, ringA, false); r = radeon_test_create_and_emit_fence(rdev, ringA, &fence2); if (r) @@ -344,7 +344,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_signal(rdev, ringB->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringB); + radeon_ring_unlock_commit(rdev, ringB, false); r = radeon_fence_wait(fence1, false); if (r) { @@ -365,7 +365,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_signal(rdev, ringB->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringB); + radeon_ring_unlock_commit(rdev, ringB, false); r = radeon_fence_wait(fence2, false); if (r) { @@ -408,7 +408,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringA); + radeon_ring_unlock_commit(rdev, ringA, false); r = radeon_test_create_and_emit_fence(rdev, ringA, &fenceA); if (r) @@ -420,7 +420,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_wait(rdev, ringB->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringB); + radeon_ring_unlock_commit(rdev, ringB, false); r = radeon_test_create_and_emit_fence(rdev, ringB, &fenceB); if (r) goto out_cleanup; @@ -442,7 +442,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_signal(rdev, ringC->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringC); + radeon_ring_unlock_commit(rdev, ringC, false); for (i = 0; i < 30; ++i) { mdelay(100); @@ -468,7 +468,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, goto out_cleanup; } radeon_semaphore_emit_signal(rdev, ringC->idx, semaphore); - radeon_ring_unlock_commit(rdev, ringC); + radeon_ring_unlock_commit(rdev, ringC, false); mdelay(1000); diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 6bf55ec..341848a 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -646,7 +646,7 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev, ib.ptr[i] = PACKET2(0); ib.length_dw = 16; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) goto err; ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence); diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c index f9b70a4..c7190aa 100644 --- a/drivers/gpu/drm/radeon/radeon_vce.c +++ b/drivers/gpu/drm/radeon/radeon_vce.c @@ -368,7 +368,7 @@ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, for (i = ib.length_dw; i < ib_size_dw; ++i) ib.ptr[i] = 0x0; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); } @@ -425,7 +425,7 @@ int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, for (i = ib.length_dw; i < ib_size_dw; ++i) ib.ptr[i] = 0x0; - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); } @@ -715,7 +715,7 @@ int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) return r; } radeon_ring_write(ring, VCE_CMD_END); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { if (vce_v1_0_get_rptr(rdev, ring) != rptr) diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index 058f200..832ef32 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -422,7 +422,7 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev, radeon_asic_vm_pad_ib(rdev, &ib); WARN_ON(ib.length_dw > 64); - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) goto error; @@ -699,7 +699,7 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev, radeon_semaphore_sync_to(ib.semaphore, pd->tbo.sync_obj); radeon_semaphore_sync_to(ib.semaphore, vm->last_id_use); WARN_ON(ib.length_dw > ndw); - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_ib_free(rdev, &ib); return r; @@ -963,7 +963,7 @@ int radeon_vm_bo_update(struct radeon_device *rdev, WARN_ON(ib.length_dw > ndw); radeon_semaphore_sync_to(ib.semaphore, vm->fence); - r = radeon_ib_schedule(rdev, &ib, NULL); + r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_ib_free(rdev, &ib); return r; diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 3e21e86..8a477bf 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -124,7 +124,7 @@ void rv515_ring_start(struct radeon_device *rdev, struct radeon_ring *ring) radeon_ring_write(ring, GEOMETRY_ROUND_NEAREST | COLOR_ROUND_NEAREST); radeon_ring_write(ring, PACKET0(0x20C8, 0)); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } int rv515_mc_wait_for_idle(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rv770_dma.c b/drivers/gpu/drm/radeon/rv770_dma.c index bbf2e07..74426ac 100644 --- a/drivers/gpu/drm/radeon/rv770_dma.c +++ b/drivers/gpu/drm/radeon/rv770_dma.c @@ -90,7 +90,7 @@ int rv770_copy_dma(struct radeon_device *rdev, return r; } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); radeon_semaphore_free(rdev, &sem, *fence); return r; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index dbd9d81..7e58423 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -3541,7 +3541,7 @@ static int si_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE)); radeon_ring_write(ring, 0xc000); radeon_ring_write(ring, 0xe000); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); si_cp_enable(rdev, true); @@ -3570,7 +3570,7 @@ static int si_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */ radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */ - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = RADEON_RING_TYPE_GFX_INDEX; i <= CAYMAN_RING_TYPE_CP2_INDEX; ++i) { ring = &rdev->ring[i]; @@ -3580,7 +3580,7 @@ static int si_cp_start(struct radeon_device *rdev) radeon_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0)); radeon_ring_write(ring, 0); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); } return 0; diff --git a/drivers/gpu/drm/radeon/si_dma.c b/drivers/gpu/drm/radeon/si_dma.c index 7165051..7c22baa 100644 --- a/drivers/gpu/drm/radeon/si_dma.c +++ b/drivers/gpu/drm/radeon/si_dma.c @@ -275,7 +275,7 @@ int si_copy_dma(struct radeon_device *rdev, return r; } - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); radeon_semaphore_free(rdev, &sem, *fence); return r; diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index be42c81..cda3913 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -124,7 +124,7 @@ int uvd_v1_0_init(struct radeon_device *rdev) radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0)); radeon_ring_write(ring, 3); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); done: /* lower clocks again */ @@ -331,7 +331,7 @@ int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) } radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); radeon_ring_write(ring, 0xDEADBEEF); - radeon_ring_unlock_commit(rdev, ring); + radeon_ring_unlock_commit(rdev, ring, false); for (i = 0; i < rdev->usec_timeout; i++) { tmp = RREG32(UVD_CONTEXT_ID); if (tmp == 0xDEADBEEF) -- cgit v1.1 From 2a13772a144d2956a7fedd18685921d0a9b8b783 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 18 Aug 2014 17:40:09 -0400 Subject: libata: widen Crucial M550 blacklist matching Crucial M550 may cause data corruption on queued trims and is blacklisted. The pattern used for it fails to match 1TB one as the capacity section will be four chars instead of three. Widen the pattern. Signed-off-by: Tejun Heo Reported-by: Charles Reiss Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=81071 Cc: stable@vger.kernel.org --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index dbdc5d3..f3e7b9f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4228,7 +4228,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, { "Crucial_CT???M500SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, { "Micron_M550*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, - { "Crucial_CT???M550SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, + { "Crucial_CT*M550SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, /* * Some WD SATA-I drives spin up and down erratically when the link -- cgit v1.1 From 9db4ad9183aad0e9567f6afb23db1bdc9aa6c2a9 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 19 Aug 2014 00:19:26 +0200 Subject: iommu/core: Check for the right function pointer in iommu_map() Check for the ->map and not the ->unmap pointer. Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 1698360..ac4adb3 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -995,7 +995,7 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova, size_t orig_size = size; int ret = 0; - if (unlikely(domain->ops->unmap == NULL || + if (unlikely(domain->ops->map == NULL || domain->ops->pgsize_bitmap == 0UL)) return -ENODEV; -- cgit v1.1 From ce0b0a46955d1bb389684a2605dbcaa990ba0154 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Aug 2014 13:56:38 +1000 Subject: md/raid10: fix memory leak when reshaping a RAID10. raid10 reshape clears unwanted bits from a bio->bi_flags using a method which, while clumsy, worked until 3.10 when BIO_OWNS_VEC was added. Since then it clears that bit but shouldn't. This results in a memory leak. So change to used the approved method of clearing unwanted bits. As this causes a memory leak which can consume all of memory the fix is suitable for -stable. Fixes: a38352e0ac02dbbd4fa464dc22d1352b5fbd06fd Cc: stable@vger.kernel.org (v3.10+) Reported-by: mdraid.pkoch@dfgh.net (Peter Koch) Signed-off-by: NeilBrown --- drivers/md/raid10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index b08c188..d9073a1 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -4410,7 +4410,7 @@ read_more: read_bio->bi_private = r10_bio; read_bio->bi_end_io = end_sync_read; read_bio->bi_rw = READ; - read_bio->bi_flags &= ~(BIO_POOL_MASK - 1); + read_bio->bi_flags &= (~0UL << BIO_RESET_BITS); read_bio->bi_flags |= 1 << BIO_UPTODATE; read_bio->bi_vcnt = 0; read_bio->bi_iter.bi_size = 0; -- cgit v1.1 From b39685526f46976bcd13aa08c82480092befa46c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Aug 2014 13:59:50 +1000 Subject: md/raid10: Fix memory leak when raid10 reshape completes. When a raid10 commences a resync/recovery/reshape it allocates some buffer space. When a resync/recovery completes the buffer space is freed. But not when the reshape completes. This can result in a small memory leak. There is a subtle side-effect of this bug. When a RAID10 is reshaped to a larger array (more devices), the reshape is immediately followed by a "resync" of the new space. This "resync" will use the buffer space which was allocated for "reshape". This can cause problems including a "BUG" in the SCSI layer. So this is suitable for -stable. Cc: stable@vger.kernel.org (v3.5+) Fixes: 3ea7daa5d7fde47cd41f4d56c2deb949114da9d6 Signed-off-by: NeilBrown --- drivers/md/raid10.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index d9073a1..a46124e 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2953,6 +2953,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, */ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { end_reshape(conf); + close_sync(conf); return 0; } -- cgit v1.1 From e337aead3aa127f083e64ad678a9e89defefcec5 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Aug 2014 14:48:54 +1000 Subject: md/raid10: avoid memory leak on error path during reshape. If raid10 reshape fails to find somewhere to read a block from, it returns without freeing memory... Signed-off-by: NeilBrown --- drivers/md/raid10.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a46124e..e5037e2 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -4399,6 +4399,7 @@ read_more: * on all the target devices. */ // FIXME + mempool_free(r10_bio, conf->r10buf_pool); set_bit(MD_RECOVERY_INTR, &mddev->recovery); return sectors_done; } -- cgit v1.1 From cb8b12b5d81cf8522076f99a90bc3b795825c3b3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Aug 2014 14:38:45 +1000 Subject: md/raid10: always initialise ->state on newly allocated r10_bio Most places which allocate an r10_bio zero the ->state, some don't. As the r10_bio comes from a mempool, and the allocation function uses kzalloc it is often zero anyway. But sometimes it isn't and it is best to be safe. I only noticed this because of the bug fixed by an earlier patch where the r10_bios allocated for a reshape were left around to be used by a subsequent resync. In that case the R10BIO_IsReshape flag caused problems. Signed-off-by: NeilBrown --- drivers/md/raid10.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index e5037e2..6703751 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3082,6 +3082,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, } r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO); + r10_bio->state = 0; raise_barrier(conf, rb2 != NULL); atomic_set(&r10_bio->remaining, 0); @@ -3270,6 +3271,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, if (sync_blocks < max_sync) max_sync = sync_blocks; r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO); + r10_bio->state = 0; r10_bio->mddev = mddev; atomic_set(&r10_bio->remaining, 0); @@ -4385,6 +4387,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, read_more: /* Now schedule reads for blocks from sector_nr to last */ r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO); + r10_bio->state = 0; raise_barrier(conf, sectors_done != 0); atomic_set(&r10_bio->remaining, 0); r10_bio->mddev = mddev; -- cgit v1.1 From d35f64e748e7752a5a60b1c7798cece51d19a213 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Tue, 19 Aug 2014 16:20:11 +0800 Subject: ALSA: hda/hdmi - set depop_delay for haswell plus Both Haswell and Broadwell need set depop_delay to 0. So apply this setting to haswell plus. Signed-off-by: Libin Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 36badba..5e229f7 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2330,9 +2330,8 @@ static int patch_generic_hdmi(struct hda_codec *codec) intel_haswell_fixup_enable_dp12(codec); } - if (is_haswell(codec) || is_valleyview(codec)) { + if (is_haswell_plus(codec) || is_valleyview(codec)) codec->depop_delay = 0; - } if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; -- cgit v1.1 From ca2e7224d7e7d424e69616634f90f3f428710085 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Tue, 19 Aug 2014 16:20:12 +0800 Subject: ALSA: hda/hdmi - apply Valleyview fix-ups to Cherryview display codec Valleyview and Cherryview have the same behavior on display audio. So this patch defines is_valleyview_plus() to include codecs for both Valleyview and its successor Cherryview, and apply Valleyview fix-ups to Cherryview. Signed-off-by: Libin Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5e229f7..99d7d7f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -50,6 +50,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec)) #define is_valleyview(codec) ((codec)->vendor_id == 0x80862882) +#define is_cherryview(codec) ((codec)->vendor_id == 0x80862883) +#define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec)) struct hdmi_spec_per_cvt { hda_nid_t cvt_nid; @@ -1459,7 +1461,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, mux_idx); /* configure unused pins to choose other converters */ - if (is_haswell_plus(codec) || is_valleyview(codec)) + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx); snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid); @@ -1598,7 +1600,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) * and this can make HW reset converter selection on a pin. */ if (eld->eld_valid && !old_eld_valid && per_pin->setup) { - if (is_haswell_plus(codec) || is_valleyview(codec)) { + if (is_haswell_plus(codec) || + is_valleyview_plus(codec)) { intel_verify_pin_cvt_connect(codec, per_pin); intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx); @@ -1779,7 +1782,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, bool non_pcm; int pinctl; - if (is_haswell_plus(codec) || is_valleyview(codec)) { + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { /* Verify pin:cvt selections to avoid silent audio after S3. * After S3, the audio driver restores pin:cvt selections * but this can happen before gfx is ready and such selection @@ -2330,7 +2333,7 @@ static int patch_generic_hdmi(struct hda_codec *codec) intel_haswell_fixup_enable_dp12(codec); } - if (is_haswell_plus(codec) || is_valleyview(codec)) + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) codec->depop_delay = 0; if (hdmi_parse_codec(codec) < 0) { -- cgit v1.1 From b3804d8da18f4649c3fb1755078312cdf8f40ffc Mon Sep 17 00:00:00 2001 From: Sergey Ryazanov Date: Thu, 14 Aug 2014 02:09:35 +0400 Subject: MIPS: MSP71xx: remove unused plat_irq_dispatch() argument Remove unused argument to make the plat_irq_dispatch() function declaration similar to the realization of other platforms. Signed-off-by: Sergey Ryazanov Cc: Linux MIPS Patchwork: https://patchwork.linux-mips.org/patch/7538/ Signed-off-by: Ralf Baechle --- arch/mips/pmcs-msp71xx/msp_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/pmcs-msp71xx/msp_irq.c b/arch/mips/pmcs-msp71xx/msp_irq.c index 941744a..f914c75 100644 --- a/arch/mips/pmcs-msp71xx/msp_irq.c +++ b/arch/mips/pmcs-msp71xx/msp_irq.c @@ -51,7 +51,7 @@ static inline void sec_int_dispatch(void) { do_IRQ(MSP_INT_SEC); } * the range 40-71. */ -asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +asmlinkage void plat_irq_dispatch(void) { u32 pending; -- cgit v1.1 From 950e97ca50942efb1066785ce3a40836c93306e2 Mon Sep 17 00:00:00 2001 From: Sergey Ryazanov Date: Thu, 14 Aug 2014 02:09:36 +0400 Subject: MIPS: Add common plat_irq_dispatch declaration Add common declaration to get rid of following sparse warning: "symbol 'plat_irq_dispatch' was not declared. Should it be static?" Signed-off-by: Sergey Ryazanov Cc: Linux MIPS Patchwork: https://patchwork.linux-mips.org/patch/7539/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/setup.c | 1 - arch/mips/include/asm/irq.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index 008e9c8..dba7cf7 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -263,7 +263,6 @@ static uint64_t crashk_size, crashk_base; static int octeon_uart; extern asmlinkage void handle_int(void); -extern asmlinkage void plat_irq_dispatch(void); /** * Return non zero if we are currently running in the Octeon simulator diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index ae1f7b2..39f07ae 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -26,6 +26,8 @@ static inline int irq_canonicalize(int irq) #define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */ #endif +asmlinkage void plat_irq_dispatch(void); + extern void do_IRQ(unsigned int irq); extern void arch_init_irq(void); -- cgit v1.1 From 92d01f71c86a02c6e224b3e74f2368def3be1dfb Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 12 Aug 2014 20:26:22 +0800 Subject: MIPS: Remove duplicated include from numa.c Signed-off-by: Wei Yongjun Cc: Huacai Chen Cc: Wei Yongjun Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7537/ Signed-off-by: Ralf Baechle --- arch/mips/loongson/loongson-3/numa.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/mips/loongson/loongson-3/numa.c b/arch/mips/loongson/loongson-3/numa.c index ca025a6..37ed184 100644 --- a/arch/mips/loongson/loongson-3/numa.c +++ b/arch/mips/loongson/loongson-3/numa.c @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include #include #include -- cgit v1.1 From 2727cab25a26a0e65e8d9d247ba5a8e9b3e552c7 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Mon, 18 Aug 2014 22:01:16 +0200 Subject: MIPS: BCM47XX: Fix reboot problem on BCM4705/BCM4785 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds some code based on code from the Broadcom GPL tar to fix the reboot problems on BCM4705/BCM4785. I tried rebooting my device for ~10 times and have never seen a problem. This reverts the changes in the previous commit and adds the real fix as suggested by Rafał. Setting bit 22 in Reg 22, sel 4 puts the BIU (Bus Interface Unit) into async mode. The previous commit was 316cad5c1d4daee998cd1f83ccdb437f6f20d45c [MIPS: BCM47XX: make reboot more relaiable] Signed-off-by: Hauke Mehrtens Cc: jogo@openwrt.org Cc: zajec5@gmail.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7545/ Signed-off-by: Ralf Baechle --- arch/mips/bcm47xx/setup.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 2b63e7e..ad439c2 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -59,12 +59,21 @@ static void bcm47xx_machine_restart(char *command) switch (bcm47xx_bus_type) { #ifdef CONFIG_BCM47XX_SSB case BCM47XX_BUS_TYPE_SSB: - ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 3); + if (bcm47xx_bus.ssb.chip_id == 0x4785) + write_c0_diag4(1 << 22); + ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1); + if (bcm47xx_bus.ssb.chip_id == 0x4785) { + __asm__ __volatile__( + ".set\tmips3\n\t" + "sync\n\t" + "wait\n\t" + ".set\tmips0"); + } break; #endif #ifdef CONFIG_BCM47XX_BCMA case BCM47XX_BUS_TYPE_BCMA: - bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 3); + bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1); break; #endif } -- cgit v1.1 From 293076f300f52e1593b596b3f09ec057ee6e4a36 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 18 Aug 2014 17:10:32 +0200 Subject: MIPS: Alchemy: Fix db1200 PSC clock enablement Enable PSC0 (I2C/SPI) clock and leave PSC1 (Audio) alone. This patch restores functionality to both Audio and I2C/SPI. Signed-off-by: Manuel Lauss Cc: Linux-MIPS Patchwork: https://patchwork.linux-mips.org/patch/7544/ Signed-off-by: Ralf Baechle --- arch/mips/alchemy/devboards/db1200.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c index 7761889..8c13675 100644 --- a/arch/mips/alchemy/devboards/db1200.c +++ b/arch/mips/alchemy/devboards/db1200.c @@ -847,6 +847,7 @@ int __init db1200_dev_setup(void) pr_warn("DB1200: cant get I2C close to 50MHz\n"); else clk_set_rate(c, pfc); + clk_prepare_enable(c); clk_put(c); } @@ -922,11 +923,6 @@ int __init db1200_dev_setup(void) } /* Audio PSC clock is supplied externally. (FIXME: platdata!!) */ - c = clk_get(NULL, "psc1_intclk"); - if (!IS_ERR(c)) { - clk_prepare_enable(c); - clk_put(c); - } __raw_writel(PSC_SEL_CLK_SERCLK, (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); wmb(); -- cgit v1.1 From 64615682658373516863b5b5971ff1d922d0ae7b Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 18 Aug 2014 15:04:11 +0100 Subject: MIPS: Malta: Improve system memory detection for '{e, }memsize' >= 2G Using kstrtol to parse the "{e,}memsize" variables was wrong because this parses signed long numbers. In case of '{e,}memsize' >= 2G, the top bit is set, resulting to -ERANGE errors and possibly random system memory boundaries. We fix this by replacing "kstrtol" with "kstrtoul". We also improve the code to check the kstrtoul return value and print a warning if an error was returned. Signed-off-by: Markos Chandras Cc: # v3.15+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7543/ Signed-off-by: Ralf Baechle --- arch/mips/mti-malta/malta-memory.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c index 0c35dee0..8fddd2cd 100644 --- a/arch/mips/mti-malta/malta-memory.c +++ b/arch/mips/mti-malta/malta-memory.c @@ -35,13 +35,19 @@ fw_memblock_t * __init fw_getmdesc(int eva) /* otherwise look in the environment */ memsize_str = fw_getenv("memsize"); - if (memsize_str) - tmp = kstrtol(memsize_str, 0, &memsize); + if (memsize_str) { + tmp = kstrtoul(memsize_str, 0, &memsize); + if (tmp) + pr_warn("Failed to read the 'memsize' env variable.\n"); + } if (eva) { /* Look for ememsize for EVA */ ememsize_str = fw_getenv("ememsize"); - if (ememsize_str) - tmp = kstrtol(ememsize_str, 0, &ememsize); + if (ememsize_str) { + tmp = kstrtoul(ememsize_str, 0, &ememsize); + if (tmp) + pr_warn("Failed to read the 'ememsize' env variable.\n"); + } } if (!memsize && !ememsize) { pr_warn("memsize not set in YAMON, set to default (32Mb)\n"); -- cgit v1.1 From 2a4a8b1e5d9d343e13ff22e19af7b353f7b52d6f Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Fri, 8 Aug 2014 15:47:48 +0200 Subject: MIPS: Remove race window in page fault handling Multicore MIPSes without I/D hardware coherency suffered from a race condition in the page fault handler. The page table entry was published before any pending lazy D-cache flush was committed, hence it allowed execution of stale page cache data by other VPEs in the system. To make the cache handling safe we need to perform flushing already in the set_pte_at function. MIPSes without coherent I-caches can get a small increase in flushes due to the unavailability of the execute flag in set_pte_at. [ralf@linux-mips.org: outlining set_pte_at() saves a good k in a test build, so I moved its definition from pgtable.h to cache.c.] Signed-off-by: Lars Persson Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/7511/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable.h | 8 +++----- arch/mips/mm/cache.c | 27 +++++++++++++++++++-------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 027c74d..df49a30 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -122,6 +122,9 @@ do { \ } \ } while(0) +extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, + pte_t pteval); + #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32) #define pte_none(pte) (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL)) @@ -145,7 +148,6 @@ static inline void set_pte(pte_t *ptep, pte_t pte) } } } -#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { @@ -183,7 +185,6 @@ static inline void set_pte(pte_t *ptep, pte_t pteval) } #endif } -#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { @@ -390,15 +391,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) extern void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte); -extern void __update_cache(struct vm_area_struct *vma, unsigned long address, - pte_t pte); static inline void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { pte_t pte = *ptep; __update_tlb(vma, address, pte); - __update_cache(vma, address, pte); } static inline void update_mmu_cache_pmd(struct vm_area_struct *vma, diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index f7b91d3..7e3ea77 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -119,25 +119,36 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr) EXPORT_SYMBOL(__flush_anon_page); -void __update_cache(struct vm_area_struct *vma, unsigned long address, - pte_t pte) +static void mips_flush_dcache_from_pte(pte_t pteval, unsigned long address) { struct page *page; - unsigned long pfn, addr; - int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc; + unsigned long pfn = pte_pfn(pteval); - pfn = pte_pfn(pte); if (unlikely(!pfn_valid(pfn))) return; + page = pfn_to_page(pfn); if (page_mapping(page) && Page_dcache_dirty(page)) { - addr = (unsigned long) page_address(page); - if (exec || pages_do_alias(addr, address & PAGE_MASK)) - flush_data_cache_page(addr); + unsigned long page_addr = (unsigned long) page_address(page); + + if (!cpu_has_ic_fills_f_dc || + pages_do_alias(page_addr, address & PAGE_MASK)) + flush_data_cache_page(page_addr); ClearPageDcacheDirty(page); } } +void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval) +{ + if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) { + if (pte_present(pteval)) + mips_flush_dcache_from_pte(pteval, addr); + } + + set_pte(ptep, pteval); +} + unsigned long _page_cachable_default; EXPORT_SYMBOL(_page_cachable_default); -- cgit v1.1 From 3bc4d037c6791c5089a04845995410aac4fdb514 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Mon, 18 Aug 2014 16:11:24 +0800 Subject: ARM: dts: imx6sx: fix the pad setting for uart CTS_B The current pinfunc define all uart CTS_B IO port for DCE uart 'CTS_B' IP port. Since uart IP port 'CTS_B' is output, and it don't need to set 'SELECT_INPUT' bit. Signed-off-by: Fugang Duan Signed-off-by: Shawn Guo --- arch/arm/boot/dts/imx6sx-pinfunc.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/boot/dts/imx6sx-pinfunc.h b/arch/arm/boot/dts/imx6sx-pinfunc.h index 3e0b816..bb9c6b7 100644 --- a/arch/arm/boot/dts/imx6sx-pinfunc.h +++ b/arch/arm/boot/dts/imx6sx-pinfunc.h @@ -78,7 +78,7 @@ #define MX6SX_PAD_GPIO1_IO07__USDHC2_WP 0x0030 0x0378 0x0870 0x1 0x1 #define MX6SX_PAD_GPIO1_IO07__ENET2_MDIO 0x0030 0x0378 0x0770 0x2 0x0 #define MX6SX_PAD_GPIO1_IO07__AUDMUX_MCLK 0x0030 0x0378 0x0000 0x3 0x0 -#define MX6SX_PAD_GPIO1_IO07__UART1_CTS_B 0x0030 0x0378 0x082C 0x4 0x1 +#define MX6SX_PAD_GPIO1_IO07__UART1_CTS_B 0x0030 0x0378 0x0000 0x4 0x0 #define MX6SX_PAD_GPIO1_IO07__GPIO1_IO_7 0x0030 0x0378 0x0000 0x5 0x0 #define MX6SX_PAD_GPIO1_IO07__SRC_EARLY_RESET 0x0030 0x0378 0x0000 0x6 0x0 #define MX6SX_PAD_GPIO1_IO07__DCIC2_OUT 0x0030 0x0378 0x0000 0x7 0x0 @@ -96,7 +96,7 @@ #define MX6SX_PAD_GPIO1_IO09__WDOG2_WDOG_B 0x0038 0x0380 0x0000 0x1 0x0 #define MX6SX_PAD_GPIO1_IO09__SDMA_EXT_EVENT_1 0x0038 0x0380 0x0820 0x2 0x0 #define MX6SX_PAD_GPIO1_IO09__CCM_OUT0 0x0038 0x0380 0x0000 0x3 0x0 -#define MX6SX_PAD_GPIO1_IO09__UART2_CTS_B 0x0038 0x0380 0x0834 0x4 0x1 +#define MX6SX_PAD_GPIO1_IO09__UART2_CTS_B 0x0038 0x0380 0x0000 0x4 0x0 #define MX6SX_PAD_GPIO1_IO09__GPIO1_IO_9 0x0038 0x0380 0x0000 0x5 0x0 #define MX6SX_PAD_GPIO1_IO09__SRC_INT_BOOT 0x0038 0x0380 0x0000 0x6 0x0 #define MX6SX_PAD_GPIO1_IO09__OBSERVE_MUX_OUT_4 0x0038 0x0380 0x0000 0x7 0x0 @@ -213,7 +213,7 @@ #define MX6SX_PAD_CSI_DATA07__ESAI_TX3_RX2 0x0068 0x03B0 0x079C 0x1 0x1 #define MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x0068 0x03B0 0x07C4 0x2 0x2 #define MX6SX_PAD_CSI_DATA07__KPP_ROW_7 0x0068 0x03B0 0x07DC 0x3 0x0 -#define MX6SX_PAD_CSI_DATA07__UART6_CTS_B 0x0068 0x03B0 0x0854 0x4 0x1 +#define MX6SX_PAD_CSI_DATA07__UART6_CTS_B 0x0068 0x03B0 0x0000 0x4 0x0 #define MX6SX_PAD_CSI_DATA07__GPIO1_IO_21 0x0068 0x03B0 0x0000 0x5 0x0 #define MX6SX_PAD_CSI_DATA07__WEIM_DATA_16 0x0068 0x03B0 0x0000 0x6 0x0 #define MX6SX_PAD_CSI_DATA07__DCIC1_OUT 0x0068 0x03B0 0x0000 0x7 0x0 @@ -254,7 +254,7 @@ #define MX6SX_PAD_CSI_VSYNC__CSI1_VSYNC 0x0078 0x03C0 0x0708 0x0 0x0 #define MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0 0x0078 0x03C0 0x07A4 0x1 0x1 #define MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD 0x0078 0x03C0 0x0674 0x2 0x1 -#define MX6SX_PAD_CSI_VSYNC__UART4_CTS_B 0x0078 0x03C0 0x0844 0x3 0x3 +#define MX6SX_PAD_CSI_VSYNC__UART4_CTS_B 0x0078 0x03C0 0x0000 0x3 0x0 #define MX6SX_PAD_CSI_VSYNC__MQS_RIGHT 0x0078 0x03C0 0x0000 0x4 0x0 #define MX6SX_PAD_CSI_VSYNC__GPIO1_IO_25 0x0078 0x03C0 0x0000 0x5 0x0 #define MX6SX_PAD_CSI_VSYNC__WEIM_DATA_24 0x0078 0x03C0 0x0000 0x6 0x0 @@ -352,7 +352,7 @@ #define MX6SX_PAD_ENET2_TX_CLK__ENET2_TX_CLK 0x00A0 0x03E8 0x0000 0x0 0x0 #define MX6SX_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x00A0 0x03E8 0x076C 0x1 0x1 #define MX6SX_PAD_ENET2_TX_CLK__I2C3_SDA 0x00A0 0x03E8 0x07BC 0x2 0x1 -#define MX6SX_PAD_ENET2_TX_CLK__UART1_CTS_B 0x00A0 0x03E8 0x082C 0x3 0x3 +#define MX6SX_PAD_ENET2_TX_CLK__UART1_CTS_B 0x00A0 0x03E8 0x0000 0x3 0x0 #define MX6SX_PAD_ENET2_TX_CLK__MLB_CLK 0x00A0 0x03E8 0x07E8 0x4 0x1 #define MX6SX_PAD_ENET2_TX_CLK__GPIO2_IO_9 0x00A0 0x03E8 0x0000 0x5 0x0 #define MX6SX_PAD_ENET2_TX_CLK__USB_OTG2_PWR 0x00A0 0x03E8 0x0000 0x6 0x0 @@ -404,7 +404,7 @@ #define MX6SX_PAD_KEY_COL4__SAI2_RX_BCLK 0x00B4 0x03FC 0x0808 0x7 0x0 #define MX6SX_PAD_KEY_ROW0__KPP_ROW_0 0x00B8 0x0400 0x0000 0x0 0x0 #define MX6SX_PAD_KEY_ROW0__USDHC3_WP 0x00B8 0x0400 0x0000 0x1 0x0 -#define MX6SX_PAD_KEY_ROW0__UART6_CTS_B 0x00B8 0x0400 0x0854 0x2 0x3 +#define MX6SX_PAD_KEY_ROW0__UART6_CTS_B 0x00B8 0x0400 0x0000 0x2 0x0 #define MX6SX_PAD_KEY_ROW0__ECSPI1_MOSI 0x00B8 0x0400 0x0718 0x3 0x0 #define MX6SX_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x00B8 0x0400 0x0660 0x4 0x0 #define MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x00B8 0x0400 0x0000 0x5 0x0 @@ -423,7 +423,7 @@ #define MX6SX_PAD_KEY_ROW1__M4_NMI 0x00BC 0x0404 0x0000 0x8 0x0 #define MX6SX_PAD_KEY_ROW2__KPP_ROW_2 0x00C0 0x0408 0x0000 0x0 0x0 #define MX6SX_PAD_KEY_ROW2__USDHC4_WP 0x00C0 0x0408 0x0878 0x1 0x1 -#define MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x00C0 0x0408 0x084C 0x2 0x3 +#define MX6SX_PAD_KEY_ROW2__UART5_CTS_B 0x00C0 0x0408 0x0000 0x2 0x0 #define MX6SX_PAD_KEY_ROW2__CAN1_RX 0x00C0 0x0408 0x068C 0x3 0x1 #define MX6SX_PAD_KEY_ROW2__CANFD_RX1 0x00C0 0x0408 0x0694 0x4 0x1 #define MX6SX_PAD_KEY_ROW2__GPIO2_IO_17 0x00C0 0x0408 0x0000 0x5 0x0 @@ -815,7 +815,7 @@ #define MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05 0x0164 0x04AC 0x0000 0x0 0x0 #define MX6SX_PAD_NAND_DATA05__USDHC2_DATA5 0x0164 0x04AC 0x0000 0x1 0x0 #define MX6SX_PAD_NAND_DATA05__QSPI2_B_DQS 0x0164 0x04AC 0x0000 0x2 0x0 -#define MX6SX_PAD_NAND_DATA05__UART3_CTS_B 0x0164 0x04AC 0x083C 0x3 0x1 +#define MX6SX_PAD_NAND_DATA05__UART3_CTS_B 0x0164 0x04AC 0x0000 0x3 0x0 #define MX6SX_PAD_NAND_DATA05__AUDMUX_AUD4_RXC 0x0164 0x04AC 0x064C 0x4 0x0 #define MX6SX_PAD_NAND_DATA05__GPIO4_IO_9 0x0164 0x04AC 0x0000 0x5 0x0 #define MX6SX_PAD_NAND_DATA05__WEIM_AD_5 0x0164 0x04AC 0x0000 0x6 0x0 @@ -957,7 +957,7 @@ #define MX6SX_PAD_QSPI1A_SS1_B__SIM_M_HADDR_12 0x019C 0x04E4 0x0000 0x7 0x0 #define MX6SX_PAD_QSPI1A_SS1_B__SDMA_DEBUG_PC_3 0x019C 0x04E4 0x0000 0x9 0x0 #define MX6SX_PAD_QSPI1B_DATA0__QSPI1_B_DATA_0 0x01A0 0x04E8 0x0000 0x0 0x0 -#define MX6SX_PAD_QSPI1B_DATA0__UART3_CTS_B 0x01A0 0x04E8 0x083C 0x1 0x4 +#define MX6SX_PAD_QSPI1B_DATA0__UART3_CTS_B 0x01A0 0x04E8 0x0000 0x1 0x0 #define MX6SX_PAD_QSPI1B_DATA0__ECSPI3_MOSI 0x01A0 0x04E8 0x0738 0x2 0x1 #define MX6SX_PAD_QSPI1B_DATA0__ESAI_RX_FS 0x01A0 0x04E8 0x0778 0x3 0x2 #define MX6SX_PAD_QSPI1B_DATA0__CSI1_DATA_22 0x01A0 0x04E8 0x06F4 0x4 0x1 @@ -1236,7 +1236,7 @@ #define MX6SX_PAD_SD1_DATA2__AUDMUX_AUD5_TXFS 0x0230 0x0578 0x0670 0x1 0x1 #define MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x0230 0x0578 0x0000 0x2 0x0 #define MX6SX_PAD_SD1_DATA2__GPT_COMPARE2 0x0230 0x0578 0x0000 0x3 0x0 -#define MX6SX_PAD_SD1_DATA2__UART2_CTS_B 0x0230 0x0578 0x0834 0x4 0x2 +#define MX6SX_PAD_SD1_DATA2__UART2_CTS_B 0x0230 0x0578 0x0000 0x4 0x0 #define MX6SX_PAD_SD1_DATA2__GPIO6_IO_4 0x0230 0x0578 0x0000 0x5 0x0 #define MX6SX_PAD_SD1_DATA2__ECSPI4_RDY 0x0230 0x0578 0x0000 0x6 0x0 #define MX6SX_PAD_SD1_DATA2__CCM_OUT0 0x0230 0x0578 0x0000 0x7 0x0 @@ -1315,7 +1315,7 @@ #define MX6SX_PAD_SD2_DATA3__VADC_CLAMP_CURRENT_3 0x024C 0x0594 0x0000 0x8 0x0 #define MX6SX_PAD_SD2_DATA3__MMDC_DEBUG_31 0x024C 0x0594 0x0000 0x9 0x0 #define MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x0250 0x0598 0x0000 0x0 0x0 -#define MX6SX_PAD_SD3_CLK__UART4_CTS_B 0x0250 0x0598 0x0844 0x1 0x0 +#define MX6SX_PAD_SD3_CLK__UART4_CTS_B 0x0250 0x0598 0x0000 0x1 0x0 #define MX6SX_PAD_SD3_CLK__ECSPI4_SCLK 0x0250 0x0598 0x0740 0x2 0x0 #define MX6SX_PAD_SD3_CLK__AUDMUX_AUD6_RXFS 0x0250 0x0598 0x0680 0x3 0x0 #define MX6SX_PAD_SD3_CLK__LCDIF2_VSYNC 0x0250 0x0598 0x0000 0x4 0x0 @@ -1409,7 +1409,7 @@ #define MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x0274 0x05BC 0x0000 0x0 0x0 #define MX6SX_PAD_SD3_DATA7__CAN1_RX 0x0274 0x05BC 0x068C 0x1 0x0 #define MX6SX_PAD_SD3_DATA7__CANFD_RX1 0x0274 0x05BC 0x0694 0x2 0x0 -#define MX6SX_PAD_SD3_DATA7__UART3_CTS_B 0x0274 0x05BC 0x083C 0x3 0x3 +#define MX6SX_PAD_SD3_DATA7__UART3_CTS_B 0x0274 0x05BC 0x0000 0x3 0x0 #define MX6SX_PAD_SD3_DATA7__LCDIF2_DATA_5 0x0274 0x05BC 0x0000 0x4 0x0 #define MX6SX_PAD_SD3_DATA7__GPIO7_IO_9 0x0274 0x05BC 0x0000 0x5 0x0 #define MX6SX_PAD_SD3_DATA7__ENET1_1588_EVENT0_IN 0x0274 0x05BC 0x0000 0x6 0x0 @@ -1510,7 +1510,7 @@ #define MX6SX_PAD_SD4_DATA6__SDMA_DEBUG_EVENT_CHANNEL_1 0x0298 0x05E0 0x0000 0x9 0x0 #define MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x029C 0x05E4 0x0000 0x0 0x0 #define MX6SX_PAD_SD4_DATA7__RAWNAND_DATA08 0x029C 0x05E4 0x0000 0x1 0x0 -#define MX6SX_PAD_SD4_DATA7__UART5_CTS_B 0x029C 0x05E4 0x084C 0x2 0x1 +#define MX6SX_PAD_SD4_DATA7__UART5_CTS_B 0x029C 0x05E4 0x0000 0x2 0x0 #define MX6SX_PAD_SD4_DATA7__ECSPI3_SS0 0x029C 0x05E4 0x073C 0x3 0x0 #define MX6SX_PAD_SD4_DATA7__LCDIF2_DATA_15 0x029C 0x05E4 0x0000 0x4 0x0 #define MX6SX_PAD_SD4_DATA7__GPIO6_IO_21 0x029C 0x05E4 0x0000 0x5 0x0 -- cgit v1.1 From 350b8bdd689cd2ab2c67c8a86a0be86cfa0751a7 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 19 Aug 2014 19:14:50 +0800 Subject: kvm: iommu: fix the third parameter of kvm_iommu_put_pages (CVE-2014-3601) The third parameter of kvm_iommu_put_pages is wrong, It should be 'gfn - slot->base_gfn'. By making gfn very large, malicious guest or userspace can cause kvm to go to this error path, and subsequently to pass a huge value as size. Alternatively if gfn is small, then pages would be pinned but never unpinned, causing host memory leak and local DOS. Passing a reasonable but large value could be the most dangerous case, because it would unpin a page that should have stayed pinned, and thus allow the device to DMA into arbitrary memory. However, this cannot happen because of the condition that can trigger the error: - out of memory (where you can't allocate even a single page) should not be possible for the attacker to trigger - when exceeding the iommu's address space, guest pages after gfn will also exceed the iommu's address space, and inside kvm_iommu_put_pages() the iommu_iova_to_phys() will fail. The page thus would not be unpinned at all. Reported-by: Jack Morgenstein Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- virt/kvm/iommu.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index 0df7d4b..714b949 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -61,6 +61,14 @@ static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn, return pfn; } +static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages) +{ + unsigned long i; + + for (i = 0; i < npages; ++i) + kvm_release_pfn_clean(pfn + i); +} + int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) { gfn_t gfn, end_gfn; @@ -123,6 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) if (r) { printk(KERN_ERR "kvm_iommu_map_address:" "iommu failed to map pfn=%llx\n", pfn); + kvm_unpin_pages(kvm, pfn, page_size); goto unmap_pages; } @@ -134,7 +143,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) return 0; unmap_pages: - kvm_iommu_put_pages(kvm, slot->base_gfn, gfn); + kvm_iommu_put_pages(kvm, slot->base_gfn, gfn - slot->base_gfn); return r; } @@ -266,14 +275,6 @@ out_unlock: return r; } -static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages) -{ - unsigned long i; - - for (i = 0; i < npages; ++i) - kvm_release_pfn_clean(pfn + i); -} - static void kvm_iommu_put_pages(struct kvm *kvm, gfn_t base_gfn, unsigned long npages) { -- cgit v1.1 From c04fa5831d4d89dfbc88406f4a46f9846841a560 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 14 Aug 2014 15:03:07 +1000 Subject: PC, KVM, CMA: Fix regression caused by wrong get_order() use fc95ca7284bc54953165cba76c3228bd2cdb9591 claims that there is no functional change but this is not true as it calls get_order() (which takes bytes) where it should have called order_base_2() and the kernel stops on VM_BUG_ON(). This replaces get_order() with order_base_2() (round-up version of ilog2). Suggested-by: Paul Mackerras Cc: Alexander Graf Cc: Joonsoo Kim Cc: Benjamin Herrenschmidt Reviewed-by: Aneesh Kumar K.V Signed-off-by: Alexey Kardashevskiy Signed-off-by: Paolo Bonzini --- arch/powerpc/kvm/book3s_hv_builtin.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index 329d7fd..b9615ba 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -101,7 +101,7 @@ struct kvm_rma_info *kvm_alloc_rma() ri = kmalloc(sizeof(struct kvm_rma_info), GFP_KERNEL); if (!ri) return NULL; - page = cma_alloc(kvm_cma, kvm_rma_pages, get_order(kvm_rma_pages)); + page = cma_alloc(kvm_cma, kvm_rma_pages, order_base_2(kvm_rma_pages)); if (!page) goto err_out; atomic_set(&ri->use_count, 1); @@ -135,12 +135,12 @@ struct page *kvm_alloc_hpt(unsigned long nr_pages) { unsigned long align_pages = HPT_ALIGN_PAGES; - VM_BUG_ON(get_order(nr_pages) < KVM_CMA_CHUNK_ORDER - PAGE_SHIFT); + VM_BUG_ON(order_base_2(nr_pages) < KVM_CMA_CHUNK_ORDER - PAGE_SHIFT); /* Old CPUs require HPT aligned on a multiple of its size */ if (!cpu_has_feature(CPU_FTR_ARCH_206)) align_pages = nr_pages; - return cma_alloc(kvm_cma, nr_pages, get_order(align_pages)); + return cma_alloc(kvm_cma, nr_pages, order_base_2(align_pages)); } EXPORT_SYMBOL_GPL(kvm_alloc_hpt); -- cgit v1.1 From 3a6095a0173ad8f20c508446880558c9f9224324 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Wed, 13 Aug 2014 16:50:13 +0300 Subject: KVM: x86: Avoid emulating instructions on #UD mistakenly Commit d40a6898e5 mistakenly caused instructions which are not marked as EmulateOnUD to be emulated upon #UD exception. The commit caused the check of whether the instruction flags include EmulateOnUD to never be evaluated. As a result instructions whose emulation is broken may be emulated. This fix moves the evaluation of EmulateOnUD so it would be evaluated. Signed-off-by: Nadav Amit [Tweak operand order in &&, remove EmulateOnUD where it's now superfluous. - Paolo] Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 56657b0..ef117b8 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -4394,8 +4394,11 @@ done_prefixes: ctxt->execute = opcode.u.execute; + if (unlikely(ctxt->ud) && likely(!(ctxt->d & EmulateOnUD))) + return EMULATION_FAILED; + if (unlikely(ctxt->d & - (NotImpl|EmulateOnUD|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm))) { + (NotImpl|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm))) { /* * These are copied unconditionally here, and checked unconditionally * in x86_emulate_insn. @@ -4406,9 +4409,6 @@ done_prefixes: if (ctxt->d & NotImpl) return EMULATION_FAILED; - if (!(ctxt->d & EmulateOnUD) && ctxt->ud) - return EMULATION_FAILED; - if (mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack)) ctxt->op_bytes = 8; -- cgit v1.1 From 9a4cfb27f7233610c5ddc82329c26d39683fad72 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 18 Aug 2014 13:15:51 +0200 Subject: KVM: x86: do not check CS.DPL against RPL during task switch This reverts the check added by commit 5045b468037d (KVM: x86: check CS.DPL against RPL during task switch, 2014-05-15). Although the CS.DPL=CS.RPL check is mentioned in table 7-1 of the SDM as causing a #TSS exception, it is not mentioned in table 6-6 that lists "invalid TSS conditions" which cause #TSS exceptions. In fact it causes some tests to fail, which pass on bare-metal. Keep the rest of the commit, since we will find new uses for it in 3.18. Reported-by: Nadav Amit Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index ef117b8..03954f7 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1491,9 +1491,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, goto exception; break; case VCPU_SREG_CS: - if (in_task_switch && rpl != dpl) - goto exception; - if (!(seg_desc.type & 8)) goto exception; -- cgit v1.1 From 0d234daf7e0a3290a3a20c8087eefbd6335a5bd4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 18 Aug 2014 16:39:48 +0200 Subject: Revert "KVM: x86: Increase the number of fixed MTRR regs to 10" This reverts commit 682367c494869008eb89ef733f196e99415ae862, which causes 32-bit SMP Windows 7 guests to panic. SeaBIOS has a limit on the number of MTRRs that it can handle, and this patch exceeded the limit. Better revert it. Thanks to Nadav Amit for debugging the cause. Cc: stable@nongnu.org Reported-by: Wanpeng Li Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 5724601..7c492ed 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -95,7 +95,7 @@ static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level) #define KVM_REFILL_PAGES 25 #define KVM_MAX_CPUID_ENTRIES 80 #define KVM_NR_FIXED_MTRR_REGION 88 -#define KVM_NR_VAR_MTRR 10 +#define KVM_NR_VAR_MTRR 8 #define ASYNC_PF_PER_VCPU 64 -- cgit v1.1 From 30d1e0e806e5b2fadc297ba78f2d7afd6ba309cf Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Fri, 8 Aug 2014 23:37:59 +0800 Subject: virt/kvm/assigned-dev.c: Set 'dev->irq_source_id' to '-1' after free it As a generic function, deassign_guest_irq() assumes it can be called even if assign_guest_irq() is not be called successfully (which can be triggered by ioctl from user mode, indirectly). So for assign_guest_irq() failure process, need set 'dev->irq_source_id' to -1 after free 'dev->irq_source_id', or deassign_guest_irq() may free it again. Signed-off-by: Chen Gang Signed-off-by: Paolo Bonzini --- virt/kvm/assigned-dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c index bf06577..5819a27 100644 --- a/virt/kvm/assigned-dev.c +++ b/virt/kvm/assigned-dev.c @@ -526,8 +526,10 @@ static int assign_guest_irq(struct kvm *kvm, dev->irq_requested_type |= guest_irq_type; if (dev->ack_notifier.gsi != -1) kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier); - } else + } else { kvm_free_irq_source_id(kvm, dev->irq_source_id); + dev->irq_source_id = -1; + } return r; } -- cgit v1.1 From f325f1643abca9fac5b8e04e9faa46effc984a61 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Mon, 18 Aug 2014 13:00:39 -0700 Subject: frv: Define cpu_relax_lowlatency() 3a6bfbc91df0 "(arch,locking: Ciao arch_mutex_cpu_relax()") broke building the frv arch. Fixes errors such as: kernel/locking/mcs_spinlock.h:87:2: error: implicit declaration of function 'cpu_relax_lowlatency' Signed-off-by: Davidlohr Bueso Compile-tested-by: Guenter Roeck Signed-off-by: Linus Torvalds --- arch/frv/include/asm/processor.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/frv/include/asm/processor.h b/arch/frv/include/asm/processor.h index a34f309..6554e78 100644 --- a/arch/frv/include/asm/processor.h +++ b/arch/frv/include/asm/processor.h @@ -129,7 +129,8 @@ unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) ((tsk)->thread.frame0->pc) #define KSTK_ESP(tsk) ((tsk)->thread.frame0->sp) -#define cpu_relax() barrier() +#define cpu_relax() barrier() +#define cpu_relax_lowlatency() cpu_relax() /* data cache prefetch */ #define ARCH_HAS_PREFETCH -- cgit v1.1 From 366047515c6eab2ff886bc28d1c2b0ad041d040a Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Fri, 15 Aug 2014 13:38:59 +0800 Subject: i2c: rework kernel config I2C_ACPI Commit da3c6647(I2C/ACPI: Clean up I2C ACPI code and Add CONFIG_I2C_ACPI config) adds a new kernel config I2C_ACPI and make I2C core built in when the config is selected. This is wrong because distributions etc generally compile I2C as a module and the commit broken that. This patch is to rename I2C_ACPI to ACPI_I2C_OPREGION. New config only controls ACPI I2C operation region code and depends on I2C=y. Signed-off-by: Lan Tianyu Reviewed-by: Mika Westerberg [wsa: removed unrelated change for Kconfig] Signed-off-by: Wolfram Sang --- drivers/i2c/Kconfig | 15 ++++++--------- drivers/i2c/Makefile | 2 +- drivers/i2c/i2c-acpi.c | 2 ++ include/linux/i2c.h | 12 ++++++++---- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 3e3b680..b51a402 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -23,17 +23,14 @@ config I2C This I2C support can also be built as a module. If so, the module will be called i2c-core. -config I2C_ACPI - bool "I2C ACPI support" - select I2C - depends on ACPI +config ACPI_I2C_OPREGION + bool "ACPI I2C Operation region support" + depends on I2C=y && ACPI default y help - Say Y here if you want to enable ACPI I2C support. This includes support - for automatic enumeration of I2C slave devices and support for ACPI I2C - Operation Regions. Operation Regions allow firmware (BIOS) code to - access I2C slave devices, such as smart batteries through an I2C host - controller driver. + Say Y here if you want to enable ACPI I2C operation region support. + Operation Regions allow firmware (BIOS) code to access I2C slave devices, + such as smart batteries through an I2C host controller driver. if I2C diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index a1f590c..e0228b2 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -3,7 +3,7 @@ # i2ccore-y := i2c-core.o -i2ccore-$(CONFIG_I2C_ACPI) += i2c-acpi.o +i2ccore-$(CONFIG_ACPI) += i2c-acpi.o obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o obj-$(CONFIG_I2C) += i2ccore.o diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c index e8b6196..0dbc18c 100644 --- a/drivers/i2c/i2c-acpi.c +++ b/drivers/i2c/i2c-acpi.c @@ -126,6 +126,7 @@ void acpi_i2c_register_devices(struct i2c_adapter *adap) dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); } +#ifdef CONFIG_ACPI_I2C_OPREGION static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, u8 cmd, u8 *data, u8 data_len) { @@ -360,3 +361,4 @@ void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) acpi_bus_detach_private_data(handle); } +#endif diff --git a/include/linux/i2c.h b/include/linux/i2c.h index ea50766..a95efeb 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -577,16 +577,20 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node } #endif /* CONFIG_OF */ -#ifdef CONFIG_I2C_ACPI -int acpi_i2c_install_space_handler(struct i2c_adapter *adapter); -void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter); +#ifdef CONFIG_ACPI void acpi_i2c_register_devices(struct i2c_adapter *adap); #else static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } +#endif /* CONFIG_ACPI */ + +#ifdef CONFIG_ACPI_I2C_OPREGION +int acpi_i2c_install_space_handler(struct i2c_adapter *adapter); +void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter); +#else static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) { } static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) { return 0; } -#endif +#endif /* CONFIG_ACPI_I2C_OPREGION */ #endif /* _LINUX_I2C_H */ -- cgit v1.1 From 39e8e30ee544a62c148033d64a979028b958ca05 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 19 Aug 2014 17:37:28 +0300 Subject: i2c: i801: Add PCI ID for Intel Braswell The SMBus host controller is the same as used in Baytrail so add the new PCI ID to the driver's list of supported IDs. Signed-off-by: Alan Cox Signed-off-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 2994690..10467a3 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -164,6 +164,7 @@ /* Older devices have their ID defined in */ #define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12 +#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */ @@ -828,6 +829,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, { 0, } }; -- cgit v1.1 From c940b4476f4fb649f6493b6a0ae837474ded8915 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 18 Aug 2014 11:57:28 -0400 Subject: drm/radeon: fix pm handling in radeon_gpu_reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pm_suspend is handled in the radeon_suspend callbacks. pm_resume has special handling depending on whether dpm or legacy pm is enabled. Change radeon_gpu_reset to mirror the behavior in the suspend and resume pathes. Signed-off-by: Alex Deucher Reviewed-by: Christian König Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_device.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index c8ea050..8e61870 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1680,7 +1680,6 @@ int radeon_gpu_reset(struct radeon_device *rdev) radeon_save_bios_scratch_regs(rdev); /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); - radeon_pm_suspend(rdev); radeon_suspend(rdev); for (i = 0; i < RADEON_NUM_RINGS; ++i) { @@ -1726,9 +1725,24 @@ retry: } } - radeon_pm_resume(rdev); + if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { + /* do dpm late init */ + r = radeon_pm_late_init(rdev); + if (r) { + rdev->pm.dpm_enabled = false; + DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); + } + } else { + /* resume old pm late */ + radeon_pm_resume(rdev); + } + drm_helper_resume_force_mode(rdev->ddev); + /* set the power state here in case we are a PX system or headless */ + if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) + radeon_pm_compute_clocks(rdev); + ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); if (r) { /* bad news, how to tell it to userspace ? */ -- cgit v1.1 From 73ef0e0d62de4a8d40d34a6f645faee2f6e1ac33 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 18 Aug 2014 16:51:46 -0400 Subject: drm/radeon: fix display handling in radeon_gpu_reset If the display hw was reset or a hard reset was used, we need to re-init some of the common display hardware as well. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_device.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 8e61870..6a219bc 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1681,6 +1681,7 @@ int radeon_gpu_reset(struct radeon_device *rdev) /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); radeon_suspend(rdev); + radeon_hpd_fini(rdev); for (i = 0; i < RADEON_NUM_RINGS; ++i) { ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i], @@ -1737,6 +1738,21 @@ retry: radeon_pm_resume(rdev); } + /* init dig PHYs, disp eng pll */ + if (rdev->is_atom_bios) { + radeon_atom_encoder_init(rdev); + radeon_atom_disp_eng_pll_init(rdev); + /* turn on the BL */ + if (rdev->mode_info.bl_encoder) { + u8 bl_level = radeon_get_backlight_level(rdev, + rdev->mode_info.bl_encoder); + radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder, + bl_level); + } + } + /* reset hpd state */ + radeon_hpd_init(rdev); + drm_helper_resume_force_mode(rdev->ddev); /* set the power state here in case we are a PX system or headless */ -- cgit v1.1 From 4560d67722816cca4b2f3dfb1d7c5b902fd2075b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Aug 2014 10:08:35 -0500 Subject: MAINTAINERS: add maintainer for ACPI parts of I2C Mika has done great work in that field, so let people know. Signed-off-by: Wolfram Sang Acked-by: Mika Westerberg --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index aefa948..edba18c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4446,6 +4446,13 @@ F: include/linux/i2c-*.h F: include/uapi/linux/i2c.h F: include/uapi/linux/i2c-*.h +I2C ACPI SUPPORT +M: Mika Westerberg +L: linux-i2c@vger.kernel.org +L: linux-acpi@vger.kernel.org +S: Maintained +F: drivers/i2c/i2c-acpi.c + I2C-TAOS-EVM DRIVER M: Jean Delvare L: linux-i2c@vger.kernel.org -- cgit v1.1 From 86302eeadebfab94530b00f5e53a23f911ff41e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 18 Aug 2014 16:30:12 +0200 Subject: drm/radeon: Sync ME and PFP after CP semaphore waits v4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes lockups due to CP read GPUVM faults when running piglit on Cape Verde. v2 (chk): apply the fix to R600+ as well, on CIK only the GFX CP has a PFP, add more comments to R600 code, enable flushing again v3: (agd5f): only apply to 7xx+. r6xx does not have the packet. v4: (agd5f): split flush change into a separate patch, fix formatting Signed-off-by: Michel Dänzer Signed-off-by: Christian König Signed-off-by: Alex Deucher Tested-by: Michel Dänzer --- drivers/gpu/drm/radeon/cik.c | 17 +++++++++++++++++ drivers/gpu/drm/radeon/r600.c | 18 ++++++++++++++++++ drivers/gpu/drm/radeon/r600d.h | 1 + 3 files changed, 36 insertions(+) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index d61bc18..af2cbc6 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -3920,6 +3920,17 @@ void cik_fence_compute_ring_emit(struct radeon_device *rdev, radeon_ring_write(ring, 0); } +/** + * cik_semaphore_ring_emit - emit a semaphore on the CP ring + * + * @rdev: radeon_device pointer + * @ring: radeon ring buffer object + * @semaphore: radeon semaphore object + * @emit_wait: Is this a sempahore wait? + * + * Emits a semaphore signal/wait packet to the CP ring and prevents the PFP + * from running ahead of semaphore waits. + */ bool cik_semaphore_ring_emit(struct radeon_device *rdev, struct radeon_ring *ring, struct radeon_semaphore *semaphore, @@ -3932,6 +3943,12 @@ bool cik_semaphore_ring_emit(struct radeon_device *rdev, radeon_ring_write(ring, lower_32_bits(addr)); radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel); + if (emit_wait && ring->idx == RADEON_RING_TYPE_GFX_INDEX) { + /* Prevent the PFP from running ahead of the semaphore wait */ + radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); + radeon_ring_write(ring, 0x0); + } + return true; } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1e47701..e8bf0ea 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2753,6 +2753,17 @@ void r600_fence_ring_emit(struct radeon_device *rdev, } } +/** + * r600_semaphore_ring_emit - emit a semaphore on the CP ring + * + * @rdev: radeon_device pointer + * @ring: radeon ring buffer object + * @semaphore: radeon semaphore object + * @emit_wait: Is this a sempahore wait? + * + * Emits a semaphore signal/wait packet to the CP ring and prevents the PFP + * from running ahead of semaphore waits. + */ bool r600_semaphore_ring_emit(struct radeon_device *rdev, struct radeon_ring *ring, struct radeon_semaphore *semaphore, @@ -2768,6 +2779,13 @@ bool r600_semaphore_ring_emit(struct radeon_device *rdev, radeon_ring_write(ring, lower_32_bits(addr)); radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | sel); + /* PFP_SYNC_ME packet only exists on 7xx+ */ + if (emit_wait && (rdev->family >= CHIP_RV770)) { + /* Prevent the PFP from running ahead of the semaphore wait */ + radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0)); + radeon_ring_write(ring, 0x0); + } + return true; } diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index f94e7a9..0c4a7d8 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -1597,6 +1597,7 @@ */ # define PACKET3_CP_DMA_CMD_SAIC (1 << 28) # define PACKET3_CP_DMA_CMD_DAIC (1 << 29) +#define PACKET3_PFP_SYNC_ME 0x42 /* r7xx+ only */ #define PACKET3_SURFACE_SYNC 0x43 # define PACKET3_CB0_DEST_BASE_ENA (1 << 6) # define PACKET3_FULL_CACHE_ENA (1 << 20) /* r7xx+ only */ -- cgit v1.1 From cd1c9c1a4b06d3bc264e774ad84c410ce02e124e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Aug 2014 11:48:30 -0400 Subject: drm/radeon: re-enable selective GPUVM flushing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the PFP and ME synchronization is fixed, we can enable this again reliably. Signed-off-by: Alex Deucher Tested-by: Michel Dänzer --- drivers/gpu/drm/radeon/radeon_vm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index 832ef32..088ffdc 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -238,9 +238,7 @@ void radeon_vm_flush(struct radeon_device *rdev, uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory); /* if we can't remember our last VM flush then flush now! */ - /* XXX figure out why we have to flush all the time before CIK */ - if (rdev->family < CHIP_BONAIRE || - !vm->last_flush || pd_addr != vm->pd_gpu_addr) { + if (!vm->last_flush || pd_addr != vm->pd_gpu_addr) { trace_radeon_vm_flush(pd_addr, ring, vm->id); vm->pd_gpu_addr = pd_addr; radeon_ring_vm_flush(rdev, ring, vm); -- cgit v1.1 From bbbf6d8768f5cac3523c408917083a111b1f3ffe Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 9 Aug 2014 10:54:03 -0700 Subject: MIPS: NL: Fix nlm_xlp_defconfig build error The nlm_xlp_defconfig build fails with ./arch/mips/include/asm/mach-netlogic/topology.h:15:0: error: "topology_core_id" redefined [-Werror] In file included from include/linux/smp.h:59:0, [ ...] from arch/mips/mm/dma-default.c:12: ./arch/mips/include/asm/smp.h:41:0: note: this is the location of the previous definition and similar errors. This is caused by commit bda4584cd943d7 ("MIPS: Support CPU topology files in sysfs") which adds the defines to arch/mips/include/asm/smp.h. Remove the defines from arch/mips/include/asm/mach-netlogic/topology.h as no longer necessary. Signed-off-by: Guenter Roeck Cc: Huacai Chen Cc: Andreas Herrmann Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7513/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mach-netlogic/topology.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/mips/include/asm/mach-netlogic/topology.h b/arch/mips/include/asm/mach-netlogic/topology.h index ceeb1f5..0eb43c8 100644 --- a/arch/mips/include/asm/mach-netlogic/topology.h +++ b/arch/mips/include/asm/mach-netlogic/topology.h @@ -10,13 +10,6 @@ #include -#ifdef CONFIG_SMP -#define topology_physical_package_id(cpu) cpu_to_node(cpu) -#define topology_core_id(cpu) (cpu_logical_map(cpu) / NLM_THREADS_PER_CORE) -#define topology_thread_cpumask(cpu) (&cpu_sibling_map[cpu]) -#define topology_core_cpumask(cpu) cpumask_of_node(cpu_to_node(cpu)) -#endif - #include #endif /* _ASM_MACH_NETLOGIC_TOPOLOGY_H */ -- cgit v1.1 From 6101b3ae94b4f266456308824e9ca4eab1235d1a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Aug 2014 11:54:15 -0400 Subject: drm/radeon: fix active cu count for SI and CIK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the CU count reported to userspace for OpenCL. bug: https://bugzilla.kernel.org/show_bug.cgi?id=82581 Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/cik.c | 8 +++----- drivers/gpu/drm/radeon/si.c | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index af2cbc6..23d56c6 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -3483,7 +3483,7 @@ static void cik_gpu_init(struct radeon_device *rdev) u32 mc_shared_chmap, mc_arb_ramcfg; u32 hdp_host_path_cntl; u32 tmp; - int i, j, k; + int i, j; switch (rdev->family) { case CHIP_BONAIRE: @@ -3674,10 +3674,8 @@ static void cik_gpu_init(struct radeon_device *rdev) for (i = 0; i < rdev->config.cik.max_shader_engines; i++) { for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) { - for (k = 0; k < rdev->config.cik.max_cu_per_sh; k++) { - rdev->config.cik.active_cus += - hweight32(cik_get_cu_active_bitmap(rdev, i, j)); - } + rdev->config.cik.active_cus += + hweight32(cik_get_cu_active_bitmap(rdev, i, j)); } } diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 7e58423..c8f359c 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -3057,7 +3057,7 @@ static void si_gpu_init(struct radeon_device *rdev) u32 sx_debug_1; u32 hdp_host_path_cntl; u32 tmp; - int i, j, k; + int i, j; switch (rdev->family) { case CHIP_TAHITI: @@ -3257,10 +3257,8 @@ static void si_gpu_init(struct radeon_device *rdev) for (i = 0; i < rdev->config.si.max_shader_engines; i++) { for (j = 0; j < rdev->config.si.max_sh_per_se; j++) { - for (k = 0; k < rdev->config.si.max_cu_per_sh; k++) { - rdev->config.si.active_cus += - hweight32(si_get_cu_active_bitmap(rdev, i, j)); - } + rdev->config.si.active_cus += + hweight32(si_get_cu_active_bitmap(rdev, i, j)); } } -- cgit v1.1 From 52da51f0f9ea9d213adfc99223630707b26d1d38 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Aug 2014 11:56:38 -0400 Subject: drm/radeon: fix active_cu mask on SI and CIK after re-init (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Need to initialize the mask to 0 on init, otherwise it keeps increasing. bug: https://bugzilla.kernel.org/show_bug.cgi?id=82581 v2: also fix cu count v3: split count fix into separate patch Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/cik.c | 1 + drivers/gpu/drm/radeon/si.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 23d56c6..f4e1470 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -3672,6 +3672,7 @@ static void cik_gpu_init(struct radeon_device *rdev) rdev->config.cik.max_sh_per_se, rdev->config.cik.max_backends_per_se); + rdev->config.cik.active_cus = 0; for (i = 0; i < rdev->config.cik.max_shader_engines; i++) { for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) { rdev->config.cik.active_cus += diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index c8f359c..a1274a3 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -3255,6 +3255,7 @@ static void si_gpu_init(struct radeon_device *rdev) rdev->config.si.max_sh_per_se, rdev->config.si.max_cu_per_sh); + rdev->config.si.active_cus = 0; for (i = 0; i < rdev->config.si.max_shader_engines; i++) { for (j = 0; j < rdev->config.si.max_sh_per_se; j++) { rdev->config.si.active_cus += -- cgit v1.1 From b738ca5d68e4051c86e32f46f67a69f3bb9cee5e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 18 Aug 2014 12:32:05 -0400 Subject: Revert "drm/radeon: Use write-combined CPU mappings of ring buffers with PCIe" This reverts commit 1490434f0da63afc6006411c8829c6a7935a4e7e. Several people have reported regressions with this patch on kabini. --- drivers/gpu/drm/radeon/radeon_ring.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 0678998..d656079 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -404,9 +404,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig /* Allocate ring buffer */ if (ring->ring_obj == NULL) { r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true, - RADEON_GEM_DOMAIN_GTT, - (rdev->flags & RADEON_IS_PCIE) ? - RADEON_GEM_GTT_WC : 0, + RADEON_GEM_DOMAIN_GTT, 0, NULL, &ring->ring_obj); if (r) { dev_err(rdev->dev, "(%d) ring create failed\n", r); -- cgit v1.1 From bfcdf1306361951b104c6858d07f6778b53e4368 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Mon, 11 Aug 2014 17:10:38 +0800 Subject: MIPS: Loongson: Fix COP2 usage for preemptible kernel In preemptible kernel, only TIF_USEDFPU flag is reliable to distinguish whether _init_fpu()/_restore_fp() is needed. Because the value of the CP0_Status.CU1 isn't changed during preemption. V2: Fix coding style. Signed-off-by: Huacai Chen Cc: John Crispin Cc: Steven J. Hill Cc: Aurelien Jarno Cc: linux-mips@linux-mips.org Cc: Fuxin Zhang Cc: Zhangjin Wu Patchwork: https://patchwork.linux-mips.org/patch/7515/ Signed-off-by: Ralf Baechle --- arch/mips/loongson/loongson-3/cop2-ex.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/mips/loongson/loongson-3/cop2-ex.c b/arch/mips/loongson/loongson-3/cop2-ex.c index 9182e8d..b03e37d 100644 --- a/arch/mips/loongson/loongson-3/cop2-ex.c +++ b/arch/mips/loongson/loongson-3/cop2-ex.c @@ -22,13 +22,13 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action, void *data) { - int fpu_enabled; + int fpu_owned; int fr = !test_thread_flag(TIF_32BIT_FPREGS); switch (action) { case CU2_EXCEPTION: preempt_disable(); - fpu_enabled = read_c0_status() & ST0_CU1; + fpu_owned = __is_fpu_owner(); if (!fr) set_c0_status(ST0_CU1 | ST0_CU2); else @@ -39,8 +39,8 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action, KSTK_STATUS(current) |= ST0_FR; else KSTK_STATUS(current) &= ~ST0_FR; - /* If FPU is enabled, we needn't init or restore fp */ - if(!fpu_enabled) { + /* If FPU is owned, we needn't init or restore fp */ + if (!fpu_owned) { set_thread_flag(TIF_USEDFPU); if (!used_math()) { _init_fpu(); -- cgit v1.1 From 40381529f84c4cda3bd2d20cab6a707508856b21 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 24 Jul 2014 12:10:01 +0100 Subject: MIPS: syscall: Fix AUDIT value for O32 processes on MIPS64 On MIPS64, O32 processes set both TIF_32BIT_ADDR and TIF_32BIT_REGS so the previous condition treated O32 applications as N32 when evaluating seccomp filters. Fix the condition to check both TIF_32BIT_{REGS, ADDR} for the N32 AUDIT flag. Signed-off-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7480/ Cc: # v3.15+ Signed-off-by: James Hogan --- arch/mips/include/asm/syscall.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h index 17960fe..cdf68b3 100644 --- a/arch/mips/include/asm/syscall.h +++ b/arch/mips/include/asm/syscall.h @@ -131,10 +131,12 @@ static inline int syscall_get_arch(void) { int arch = EM_MIPS; #ifdef CONFIG_64BIT - if (!test_thread_flag(TIF_32BIT_REGS)) + if (!test_thread_flag(TIF_32BIT_REGS)) { arch |= __AUDIT_ARCH_64BIT; - if (test_thread_flag(TIF_32BIT_ADDR)) - arch |= __AUDIT_ARCH_CONVENTION_MIPS64_N32; + /* N32 sets only TIF_32BIT_ADDR */ + if (test_thread_flag(TIF_32BIT_ADDR)) + arch |= __AUDIT_ARCH_CONVENTION_MIPS64_N32; + } #endif #if defined(__LITTLE_ENDIAN) arch |= __AUDIT_ARCH_LE; -- cgit v1.1 From 5245689900804604fdc349c8d9b8985b0e401ae2 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 24 Jul 2014 12:10:02 +0100 Subject: MIPS: scall64-o32: Fix indirect syscall detection Commit 4c21b8fd8f14 (MIPS: seccomp: Handle indirect system calls (o32)) added indirect syscall detection for O32 processes running on MIPS64 but it did not work as expected. The reason is the the scall64-o32 implementation differs compared to scall32-o32. In the former, the v0 (syscall number) register contains the absolute syscall number (4000 + X) whereas in the latter it contains the relative syscall number (X). Fix the code to avoid doing an extra addition, and load the v0 register directly to the first argument for syscall_trace_enter. Moreover, set the .reorder assembler option in order to have better control on this part of the assembly code. Signed-off-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7481/ Cc: # v3.15+ Signed-off-by: James Hogan --- arch/mips/kernel/scall64-o32.S | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 13b964f..25bb840 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -113,15 +113,19 @@ trace_a_syscall: move s0, t2 # Save syscall pointer move a0, sp /* - * syscall number is in v0 unless we called syscall(__NR_###) + * absolute syscall number is in v0 unless we called syscall(__NR_###) * where the real syscall number is in a0 * note: NR_syscall is the first O32 syscall but the macro is * only defined when compiling with -mabi=32 (CONFIG_32BIT) * therefore __NR_O32_Linux is used (4000) */ - addiu a1, v0, __NR_O32_Linux - bnez v0, 1f /* __NR_syscall at offset 0 */ - lw a1, PT_R4(sp) + .set push + .set reorder + subu t1, v0, __NR_O32_Linux + move a1, v0 + bnez t1, 1f /* __NR_syscall at offset 0 */ + lw a1, PT_R4(sp) /* Arg1 for __NR_syscall case */ + .set pop 1: jal syscall_trace_enter -- cgit v1.1 From f85b71ceabb9d8d8a9e34b045b5c43ffde3623b3 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 21 Jul 2014 14:35:54 +0100 Subject: MIPS: EVA: Add new EVA header Generic code may need to perform certain operations when EVA is enabled, for example, configure the segmentation registers during boot. In order to avoid using more CONFIG_EVA ifdefs in the arch code, such functions will be added in this header instead. Initially this header contains a macro which will be used by generic code later on during VPEs configuration on secondary cores. All it does is to call the platform specific EVA init code in case EVA is enabled. Reviewed-by: Paul Burton Signed-off-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7422/ Signed-off-by: James Hogan --- arch/mips/include/asm/eva.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 arch/mips/include/asm/eva.h diff --git a/arch/mips/include/asm/eva.h b/arch/mips/include/asm/eva.h new file mode 100644 index 0000000..a3d1807 --- /dev/null +++ b/arch/mips/include/asm/eva.h @@ -0,0 +1,43 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2014, Imagination Technologies Ltd. + * + * EVA functions for generic code + */ + +#ifndef _ASM_EVA_H +#define _ASM_EVA_H + +#include + +#ifdef __ASSEMBLY__ + +#ifdef CONFIG_EVA + +/* + * EVA early init code + * + * Platforms must define their own 'platform_eva_init' macro in + * their kernel-entry-init.h header. This macro usually does the + * platform specific configuration of the segmentation registers, + * and it is normally called from assembly code. + * + */ + +.macro eva_init +platform_eva_init +.endm + +#else + +.macro eva_init +.endm + +#endif /* CONFIG_EVA */ + +#endif /* __ASSEMBLY__ */ + +#endif -- cgit v1.1 From ca4d24f7954f3746742ba350c2276ff777f21173 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 21 Jul 2014 14:35:55 +0100 Subject: MIPS: Malta: EVA: Rename 'eva_entry' to 'platform_eva_init' Rename 'eva_entry' to 'platform_eva_init' as required by the new 'eva_init' macro in the eva.h header. Since this macro is now used in a platform dependent way, it must not depend on its caller so move the t1 register initialization inside this macro. Also set the .reorder assembler option in case the caller may have previously set .noreorder. This may allow a few assembler optimizations. Finally include missing headers and document the register usage for this macro. Reviewed-by: Paul Burton Signed-off-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7423/ Signed-off-by: James Hogan --- .../include/asm/mach-malta/kernel-entry-init.h | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/mach-malta/kernel-entry-init.h b/arch/mips/include/asm/mach-malta/kernel-entry-init.h index 77eeda7..0cf8622 100644 --- a/arch/mips/include/asm/mach-malta/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-malta/kernel-entry-init.h @@ -10,14 +10,15 @@ #ifndef __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H #define __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H +#include +#include + /* * Prepare segments for EVA boot: * * This is in case the processor boots in legacy configuration * (SI_EVAReset is de-asserted and CONFIG5.K == 0) * - * On entry, t1 is loaded with CP0_CONFIG - * * ========================= Mappings ============================= * Virtual memory Physical memory Mapping * 0x00000000 - 0x7fffffff 0x80000000 - 0xfffffffff MUSUK (kuseg) @@ -30,12 +31,20 @@ * * * Lowmem is expanded to 2GB + * + * The following code uses the t0, t1, t2 and ra registers without + * previously preserving them. + * */ - .macro eva_entry + .macro platform_eva_init + + .set push + .set reorder /* * Get Config.K0 value and use it to program * the segmentation registers */ + mfc0 t1, CP0_CONFIG andi t1, 0x7 /* CCA */ move t2, t1 ins t2, t1, 16, 3 @@ -77,6 +86,8 @@ mtc0 t0, $16, 5 sync jal mips_ihb + + .set pop .endm .macro kernel_entry_setup @@ -95,7 +106,7 @@ sll t0, t0, 6 /* SC bit */ bgez t0, 9f - eva_entry + platform_eva_init b 0f 9: /* Assume we came from YAMON... */ @@ -127,8 +138,7 @@ nonsc_processor: #ifdef CONFIG_EVA sync ehb - mfc0 t1, CP0_CONFIG - eva_entry + platform_eva_init #endif .endm -- cgit v1.1 From 6521d9a436a62e83ce57d6be6e5484e1098c1380 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Mon, 21 Jul 2014 14:35:56 +0100 Subject: MIPS: CPS: Initialize EVA before bringing up VPEs from secondary cores The CPS code is doing several memory loads when configuring the VPEs from secondary cores, so the segmentation control registers must be initialized in time otherwise the kernel will crash with strange TLB exceptions. Reviewed-by: Paul Burton Signed-off-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7424/ Signed-off-by: James Hogan --- arch/mips/kernel/cps-vec.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 6f4f739..e6e97d2 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -166,6 +167,9 @@ dcache_done: 1: jal mips_cps_core_init nop + /* Do any EVA initialization if necessary */ + eva_init + /* * Boot any other VPEs within this core that should be online, and * deactivate this VPE if it should be offline. -- cgit v1.1 From 608308682addfdc7b8e2aee88f0e028331d88e4d Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Tue, 22 Jul 2014 14:51:08 +0300 Subject: MIPS: OCTEON: make get_system_type() thread-safe get_system_type() is not thread-safe on OCTEON. It uses static data, also more dangerous issue is that it's calling cvmx_fuse_read_byte() every time without any synchronization. Currently it's possible to get processes stuck looping forever in kernel simply by launching multiple readers of /proc/cpuinfo: (while true; do cat /proc/cpuinfo > /dev/null; done) & (while true; do cat /proc/cpuinfo > /dev/null; done) & ... Fix by initializing the system type string only once during the early boot. Signed-off-by: Aaro Koskinen Cc: stable@vger.kernel.org Reviewed-by: Markos Chandras Patchwork: http://patchwork.linux-mips.org/patch/7437/ Signed-off-by: James Hogan --- arch/mips/cavium-octeon/setup.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c index dba7cf7..38f4c32 100644 --- a/arch/mips/cavium-octeon/setup.c +++ b/arch/mips/cavium-octeon/setup.c @@ -457,6 +457,18 @@ static void octeon_halt(void) octeon_kill_core(NULL); } +static char __read_mostly octeon_system_type[80]; + +static int __init init_octeon_system_type(void) +{ + snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)", + cvmx_board_type_to_string(octeon_bootinfo->board_type), + octeon_model_get_string(read_c0_prid())); + + return 0; +} +early_initcall(init_octeon_system_type); + /** * Return a string representing the system type * @@ -464,11 +476,7 @@ static void octeon_halt(void) */ const char *octeon_board_type_string(void) { - static char name[80]; - sprintf(name, "%s (%s)", - cvmx_board_type_to_string(octeon_bootinfo->board_type), - octeon_model_get_string(read_c0_prid())); - return name; + return octeon_system_type; } const char *get_system_type(void) -- cgit v1.1 From 85cd083b498572fb9fa575cce3ed910c8ee84294 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sat, 9 Aug 2014 09:49:31 +0800 Subject: udf: avoid unneeded up_write when fail to add entry in ->symlink We have released the ->i_data_sem before invoking udf_add_entry(), so in following error path, we should not release this lock again. Signed-off-by: Chao Yu Signed-off-by: Jan Kara --- fs/udf/namei.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 9737cba..83a0600 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -1014,7 +1014,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err); if (!fi) - goto out_no_entry; + goto out_fail; cfi.icb.extLength = cpu_to_le32(sb->s_blocksize); cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location); if (UDF_SB(inode->i_sb)->s_lvid_bh) { @@ -1036,6 +1036,7 @@ out: out_no_entry: up_write(&iinfo->i_data_sem); +out_fail: inode_dec_link_count(inode); iput(inode); goto out; -- cgit v1.1 From 410dd3cf4c9b36f27ed4542ee18b1af5e68645a4 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Sun, 17 Aug 2014 11:49:57 +0200 Subject: isofs: Fix unbounded recursion when processing relocated directories We did not check relocated directory in any way when processing Rock Ridge 'CL' tag. Thus a corrupted isofs image can possibly have a CL entry pointing to another CL entry leading to possibly unbounded recursion in kernel code and thus stack overflow or deadlocks (if there is a loop created from CL entries). Fix the problem by not allowing CL entry to point to a directory entry with CL entry (such use makes no good sense anyway) and by checking whether CL entry doesn't point to itself. CC: stable@vger.kernel.org Reported-by: Chris Evans Signed-off-by: Jan Kara --- fs/isofs/inode.c | 15 ++++++++------- fs/isofs/isofs.h | 23 +++++++++++++++++++---- fs/isofs/rock.c | 39 ++++++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 4556ce1..5ddaf86 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -61,7 +61,7 @@ static void isofs_put_super(struct super_block *sb) return; } -static int isofs_read_inode(struct inode *); +static int isofs_read_inode(struct inode *, int relocated); static int isofs_statfs (struct dentry *, struct kstatfs *); static struct kmem_cache *isofs_inode_cachep; @@ -1259,7 +1259,7 @@ out_toomany: goto out; } -static int isofs_read_inode(struct inode *inode) +static int isofs_read_inode(struct inode *inode, int relocated) { struct super_block *sb = inode->i_sb; struct isofs_sb_info *sbi = ISOFS_SB(sb); @@ -1404,7 +1404,7 @@ static int isofs_read_inode(struct inode *inode) */ if (!high_sierra) { - parse_rock_ridge_inode(de, inode); + parse_rock_ridge_inode(de, inode, relocated); /* if we want uid/gid set, override the rock ridge setting */ if (sbi->s_uid_set) inode->i_uid = sbi->s_uid; @@ -1483,9 +1483,10 @@ static int isofs_iget5_set(struct inode *ino, void *data) * offset that point to the underlying meta-data for the inode. The * code below is otherwise similar to the iget() code in * include/linux/fs.h */ -struct inode *isofs_iget(struct super_block *sb, - unsigned long block, - unsigned long offset) +struct inode *__isofs_iget(struct super_block *sb, + unsigned long block, + unsigned long offset, + int relocated) { unsigned long hashval; struct inode *inode; @@ -1507,7 +1508,7 @@ struct inode *isofs_iget(struct super_block *sb, return ERR_PTR(-ENOMEM); if (inode->i_state & I_NEW) { - ret = isofs_read_inode(inode); + ret = isofs_read_inode(inode, relocated); if (ret < 0) { iget_failed(inode); inode = ERR_PTR(ret); diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index 9916723..0ac4c1f 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h @@ -107,7 +107,7 @@ extern int iso_date(char *, int); struct inode; /* To make gcc happy */ -extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *); +extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *, int relocated); extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *); extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *); @@ -118,9 +118,24 @@ extern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int extern struct buffer_head *isofs_bread(struct inode *, sector_t); extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long); -extern struct inode *isofs_iget(struct super_block *sb, - unsigned long block, - unsigned long offset); +struct inode *__isofs_iget(struct super_block *sb, + unsigned long block, + unsigned long offset, + int relocated); + +static inline struct inode *isofs_iget(struct super_block *sb, + unsigned long block, + unsigned long offset) +{ + return __isofs_iget(sb, block, offset, 0); +} + +static inline struct inode *isofs_iget_reloc(struct super_block *sb, + unsigned long block, + unsigned long offset) +{ + return __isofs_iget(sb, block, offset, 1); +} /* Because the inode number is no longer relevant to finding the * underlying meta-data for an inode, we are free to choose a more diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index c0bf424..f488bba 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -288,12 +288,16 @@ eio: goto out; } +#define RR_REGARD_XA 1 +#define RR_RELOC_DE 2 + static int parse_rock_ridge_inode_internal(struct iso_directory_record *de, - struct inode *inode, int regard_xa) + struct inode *inode, int flags) { int symlink_len = 0; int cnt, sig; + unsigned int reloc_block; struct inode *reloc; struct rock_ridge *rr; int rootflag; @@ -305,7 +309,7 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, init_rock_state(&rs, inode); setup_rock_ridge(de, inode, &rs); - if (regard_xa) { + if (flags & RR_REGARD_XA) { rs.chr += 14; rs.len -= 14; if (rs.len < 0) @@ -485,12 +489,22 @@ repeat: "relocated directory\n"); goto out; case SIG('C', 'L'): - ISOFS_I(inode)->i_first_extent = - isonum_733(rr->u.CL.location); - reloc = - isofs_iget(inode->i_sb, - ISOFS_I(inode)->i_first_extent, - 0); + if (flags & RR_RELOC_DE) { + printk(KERN_ERR + "ISOFS: Recursive directory relocation " + "is not supported\n"); + goto eio; + } + reloc_block = isonum_733(rr->u.CL.location); + if (reloc_block == ISOFS_I(inode)->i_iget5_block && + ISOFS_I(inode)->i_iget5_offset == 0) { + printk(KERN_ERR + "ISOFS: Directory relocation points to " + "itself\n"); + goto eio; + } + ISOFS_I(inode)->i_first_extent = reloc_block; + reloc = isofs_iget_reloc(inode->i_sb, reloc_block, 0); if (IS_ERR(reloc)) { ret = PTR_ERR(reloc); goto out; @@ -637,9 +651,11 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) return rpnt; } -int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) +int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode, + int relocated) { - int result = parse_rock_ridge_inode_internal(de, inode, 0); + int flags = relocated ? RR_RELOC_DE : 0; + int result = parse_rock_ridge_inode_internal(de, inode, flags); /* * if rockridge flag was reset and we didn't look for attributes @@ -647,7 +663,8 @@ int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode) */ if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1) && (ISOFS_SB(inode->i_sb)->s_rock == 2)) { - result = parse_rock_ridge_inode_internal(de, inode, 14); + result = parse_rock_ridge_inode_internal(de, inode, + flags | RR_REGARD_XA); } return result; } -- cgit v1.1 From 480cadc2b7e0fa2bbab20141efb547dfe0c3707c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 10 Aug 2014 05:54:25 -0700 Subject: scsi: Fix qemu boot hang problem The latest kernel fails to boot qemu arm images when using scsi for disk access. Boot gets stuck after the following messages. brd: module loaded sym53c8xx 0000:00:0c.0: enabling device (0100 -> 0103) sym0: <895a> rev 0x0 at pci 0000:00:0c.0 irq 93 sym0: No NVRAM, ID 7, Fast-40, LVD, parity checking sym0: SCSI BUS has been reset. scsi host0: sym-2.2.3 Bisect points to commit 71e75c97f97a ("scsi: convert device_busy to atomic_t"). Code inspection shows the following suspicious change in scsi_request_fn. out_delay: - if (sdev->device_busy == 0 && !scsi_device_blocked(sdev)) + if (atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev)) blk_delay_queue(q, SCSI_QUEUE_DELAY); } 'sdev->device_busy == 0' was replaced with 'atomic_read(&sdev->device_busy)', meaning the logic was reversed. Changing this expression to '!atomic_read(&sdev->device_busy)' fixes the problem. Signed-off-by: Guenter Roeck Reviewed-by: Hannes Reinecke Acked-by: Jens Axboe Reviewed-by: Venkatesh Srinivas Reviewed-by: Webb Scales Cc: Christoph Hellwig Signed-off-by: Linus Torvalds --- drivers/scsi/scsi_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9c44392..ce62e87 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1774,7 +1774,7 @@ static void scsi_request_fn(struct request_queue *q) blk_requeue_request(q, req); atomic_dec(&sdev->device_busy); out_delay: - if (atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev)) + if (!atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev)) blk_delay_queue(q, SCSI_QUEUE_DELAY); } -- cgit v1.1 From 73d0f37ac4ee5b60e6b9c1b3ccb8766bade9d9c5 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Thu, 14 Aug 2014 12:27:47 +0400 Subject: cbq: incorrectly low bandwidth setting blocks limited traffic Mainstream commit f0f6ee1f70c4 ("cbq: incorrect processing of high limits") have side effect: if cbq bandwidth setting is less than real interface throughput non-limited traffic can delay limited traffic for a very long time. This happen because of q->now changes incorrectly in cbq_dequeue(): in described scenario L2T is much greater than real time delay, and q->now gets an extra boost for each transmitted packet. Accumulated boost prevents update q->now, and blocked class can wait very long time until (q->now >= cl->undertime) will be true again. To fix the problem the patch updates q->now on each cbq_update() call. L2T-related pre-modification q->now was moved to cbq_update(). My testing confirmed that it fixes the problem and did not discover any side-effects Fixes: f0f6ee1f70c4 ("cbq: incorrect processing of high limits") Signed-off-by: Vasily Averin Signed-off-by: David S. Miller --- net/sched/sch_cbq.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index ead5264..550be95 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -700,8 +700,13 @@ cbq_update(struct cbq_sched_data *q) struct cbq_class *this = q->tx_class; struct cbq_class *cl = this; int len = q->tx_len; + psched_time_t now; q->tx_class = NULL; + /* Time integrator. We calculate EOS time + * by adding expected packet transmission time. + */ + now = q->now + L2T(&q->link, len); for ( ; cl; cl = cl->share) { long avgidle = cl->avgidle; @@ -717,7 +722,7 @@ cbq_update(struct cbq_sched_data *q) * idle = (now - last) - last_pktlen/rate */ - idle = q->now - cl->last; + idle = now - cl->last; if ((unsigned long)idle > 128*1024*1024) { avgidle = cl->maxidle; } else { @@ -761,7 +766,7 @@ cbq_update(struct cbq_sched_data *q) idle -= L2T(&q->link, len); idle += L2T(cl, len); - cl->undertime = q->now + idle; + cl->undertime = now + idle; } else { /* Underlimit */ @@ -771,7 +776,8 @@ cbq_update(struct cbq_sched_data *q) else cl->avgidle = avgidle; } - cl->last = q->now; + if ((s64)(now - cl->last) > 0) + cl->last = now; } cbq_update_toplevel(q, this, q->tx_borrowed); @@ -943,30 +949,13 @@ cbq_dequeue(struct Qdisc *sch) struct sk_buff *skb; struct cbq_sched_data *q = qdisc_priv(sch); psched_time_t now; - psched_tdiff_t incr; now = psched_get_time(); - incr = now - q->now_rt; - - if (q->tx_class) { - psched_tdiff_t incr2; - /* Time integrator. We calculate EOS time - * by adding expected packet transmission time. - * If real time is greater, we warp artificial clock, - * so that: - * - * cbq_time = max(real_time, work); - */ - incr2 = L2T(&q->link, q->tx_len); - q->now += incr2; + + if (q->tx_class) cbq_update(q); - if ((incr -= incr2) < 0) - incr = 0; - q->now += incr; - } else { - if (now > q->now) - q->now = now; - } + + q->now = now; q->now_rt = now; for (;;) { -- cgit v1.1 From 7201c1ddf774c12daa2dd5da098b8929db53f047 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Thu, 14 Aug 2014 12:27:59 +0400 Subject: cbq: now_rt removal Now q->now_rt is identical to q->now and is not required anymore. Signed-off-by: Vasily Averin Signed-off-by: David S. Miller --- net/sched/sch_cbq.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 550be95..762a04b 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -159,7 +159,6 @@ struct cbq_sched_data { struct cbq_class *tx_borrowed; int tx_len; psched_time_t now; /* Cached timestamp */ - psched_time_t now_rt; /* Cached real time */ unsigned int pmask; struct hrtimer delay_timer; @@ -353,12 +352,7 @@ cbq_mark_toplevel(struct cbq_sched_data *q, struct cbq_class *cl) int toplevel = q->toplevel; if (toplevel > cl->level && !(qdisc_is_throttled(cl->q))) { - psched_time_t now; - psched_tdiff_t incr; - - now = psched_get_time(); - incr = now - q->now_rt; - now = q->now + incr; + psched_time_t now = psched_get_time(); do { if (cl->undertime < now) { @@ -956,7 +950,6 @@ cbq_dequeue(struct Qdisc *sch) cbq_update(q); q->now = now; - q->now_rt = now; for (;;) { q->wd_expires = 0; @@ -1212,7 +1205,6 @@ cbq_reset(struct Qdisc *sch) hrtimer_cancel(&q->delay_timer); q->toplevel = TC_CBQ_MAXLEVEL; q->now = psched_get_time(); - q->now_rt = q->now; for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++) q->active[prio] = NULL; @@ -1396,7 +1388,6 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) q->delay_timer.function = cbq_undelay; q->toplevel = TC_CBQ_MAXLEVEL; q->now = psched_get_time(); - q->now_rt = q->now; cbq_link_class(&q->link); -- cgit v1.1 From 02784f1b05b8f241c8180af88869e717e2758593 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 19 Aug 2014 11:14:02 -0700 Subject: tipc: Fix build. Missing semicolon in range check fix. Signed-off-by: David S. Miller --- net/tipc/port.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/tipc/port.h b/net/tipc/port.h index a69118f..3087da3 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h @@ -182,8 +182,9 @@ static inline int tipc_port_importance(struct tipc_port *port) static inline int tipc_port_set_importance(struct tipc_port *port, int imp) { if (imp > TIPC_CRITICAL_IMPORTANCE) - return -EINVAL + return -EINVAL; msg_set_importance(&port->phdr, (u32)imp); + return 0; } #endif -- cgit v1.1 From 4190312beb2acfb7bfb1bb971e24a759aa96b0e8 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 13 Aug 2014 18:53:03 +0100 Subject: arm64: align randomized TEXT_OFFSET on 4 kB boundary When booting via UEFI, the kernel Image is loaded at a 4 kB boundary and the embedded EFI stub is executed in place. The EFI stub relocates the Image to reside TEXT_OFFSET bytes above a 2 MB boundary, and jumps into the kernel proper. In AArch64, PC relative symbol references are emitted using adrp/add or adrp/ldr pairs, where the offset into a 4 kB page is resolved using a separate :lo12: relocation. This implicitly assumes that the code will always be executed at the same relative offset with respect to a 4 kB boundary, or the references will point to the wrong address. This means we should link the kernel at a 4 kB aligned base address in order to remain compatible with the base address the UEFI loader uses when doing the initial load of Image. So update the code that generates TEXT_OFFSET to choose a multiple of 4 kB. At the same time, update the code so it chooses from the interval [0..2MB) as the author originally intended. Reviewed-by: Mark Rutland Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm64/Makefile | 2 +- arch/arm64/kernel/head.S | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 5783354..2df5e5d 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -39,7 +39,7 @@ head-y := arch/arm64/kernel/head.o # The byte offset of the kernel image in RAM from the start of RAM. ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y) -TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%04x0\n", int(65535 * rand())}') +TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%03x000\n", int(512 * rand())}') else TEXT_OFFSET := 0x00080000 endif diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 144f105..bed0283 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -38,11 +38,11 @@ #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) -#if (TEXT_OFFSET & 0xf) != 0 -#error TEXT_OFFSET must be at least 16B aligned -#elif (PAGE_OFFSET & 0xfffff) != 0 +#if (TEXT_OFFSET & 0xfff) != 0 +#error TEXT_OFFSET must be at least 4KB aligned +#elif (PAGE_OFFSET & 0x1fffff) != 0 #error PAGE_OFFSET must be at least 2MB aligned -#elif TEXT_OFFSET > 0xfffff +#elif TEXT_OFFSET > 0x1fffff #error TEXT_OFFSET must be less than 2MB #endif -- cgit v1.1 From 49d947facece74577abe29717626bc32d45477c4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 14 Aug 2014 20:57:16 +0100 Subject: arm64: configs: Enable X-Gene SATA and ethernet in defconfig Currently when run on an APM platform the ARMv8 defconfig has no viable options for rootfs other than ramdisk which is rather limiting. Since we already have both SATA and the bits needed for NFS root enabled we just need to enable the relevant drivers so do that, helping enable direct testing of upstream. If the configuration ends up becoming too big we can consider modularising some of the drivers and asking people to use an initramfs but for now this is not an issue. Signed-off-by: Mark Brown Signed-off-by: Will Deacon --- arch/arm64/configs/defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 1e52b74..d92ef3c 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -64,6 +64,8 @@ CONFIG_VIRTIO_BLK=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_ATA=y +CONFIG_AHCI_XGENE=y +CONFIG_PHY_XGENE=y CONFIG_PATA_PLATFORM=y CONFIG_PATA_OF_PLATFORM=y CONFIG_NETDEVICES=y @@ -71,6 +73,7 @@ CONFIG_TUN=y CONFIG_VIRTIO_NET=y CONFIG_SMC91X=y CONFIG_SMSC911X=y +CONFIG_NET_XGENE=y # CONFIG_WLAN is not set CONFIG_INPUT_EVDEV=y # CONFIG_SERIO_SERPORT is not set -- cgit v1.1 From 86c8b27a01cf6c16fc159ade223cb2ccc70dc4b5 Mon Sep 17 00:00:00 2001 From: Leif Lindholm Date: Mon, 28 Jul 2014 19:03:03 +0100 Subject: arm64: ignore DT memreserve entries when booting in UEFI mode UEFI provides its own method for marking regions to reserve, via the memory map which is also used to initialise memblock. So when using the UEFI memory map, ignore any memreserve entries present in the DT. Reported-by: Mark Rutland Reviewed-by: Mark Rutland Acked-by: Catalin Marinas Signed-off-by: Leif Lindholm Signed-off-by: Will Deacon --- arch/arm64/kernel/efi.c | 2 ++ arch/arm64/mm/init.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index e72f310..24f0c6f 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -188,6 +188,8 @@ static __init void reserve_regions(void) if (uefi_debug) pr_cont("\n"); } + + set_bit(EFI_MEMMAP, &efi.flags); } diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 5b4526e..5472c24 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -148,7 +149,8 @@ void __init arm64_memblock_init(void) memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start); #endif - early_init_fdt_scan_reserved_mem(); + if (!efi_enabled(EFI_MEMMAP)) + early_init_fdt_scan_reserved_mem(); /* 4GB maximum for 32-bit only capable devices */ if (IS_ENABLED(CONFIG_ZONE_DMA)) -- cgit v1.1 From 07a15dd55a3d65f81b4b09eab293f4afc720b082 Mon Sep 17 00:00:00 2001 From: Ganapatrao Kulkarni Date: Thu, 14 Aug 2014 20:49:46 +0530 Subject: arm64: mm: update max pa bits to 48 Now that we support 48-bit physical addressing, update MAX_PHYSMEM_BITS accordingly. Acked-by: Catalin Marinas Signed-off-by: Ganapatrao Kulkarni Signed-off-by: Will Deacon --- arch/arm64/include/asm/sparsemem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/sparsemem.h b/arch/arm64/include/asm/sparsemem.h index 1be62bc..74a9d30 100644 --- a/arch/arm64/include/asm/sparsemem.h +++ b/arch/arm64/include/asm/sparsemem.h @@ -17,7 +17,7 @@ #define __ASM_SPARSEMEM_H #ifdef CONFIG_SPARSEMEM -#define MAX_PHYSMEM_BITS 40 +#define MAX_PHYSMEM_BITS 48 #define SECTION_SIZE_BITS 30 #endif -- cgit v1.1 From 44b375070fa3defa6bf1010bd0e4e64f7986bfc4 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 19 Aug 2014 22:05:45 +0100 Subject: Revert "arm64: Do not invoke audit_syscall_* functions if !CONFIG_AUDIT_SYSCALL" For some reason, the audit patches didn't make it out of -next this merge window, so revert our temporary hack and let the audit guys deal with fixing up -next. This reverts commit 2a8f45b040bcb9b2ad2845f061499d1b6f41cc7b. Signed-off-by: Will Deacon --- arch/arm64/kernel/ptrace.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 0310811..70526cf 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -1115,19 +1115,15 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_enter(regs, regs->syscallno); -#ifdef CONFIG_AUDITSYSCALL audit_syscall_entry(syscall_get_arch(), regs->syscallno, regs->orig_x0, regs->regs[1], regs->regs[2], regs->regs[3]); -#endif return regs->syscallno; } asmlinkage void syscall_trace_exit(struct pt_regs *regs) { -#ifdef CONFIG_AUDITSYSCALL audit_syscall_exit(regs); -#endif if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_exit(regs, regs_return_value(regs)); -- cgit v1.1 From 4cde3733daa044961cdd3b9be63eee73c8b34589 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 16 Jul 2014 09:50:05 +0100 Subject: ARM: dts: Enable PMIC interrupts on ODROID The ODROID kernel shows that the PMIC interrupt line is hooked up to pin GPX3-2. This is needed for the max77686-irq driver to create the PMIC IRQ domain, which is needed by max77686-rtc. Signed-off-by: Daniel Drake Tested-by: Tomeu Vizoso Signed-off-by: Olof Johansson --- arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index 6d6d23c..cb6f55f 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -148,6 +148,10 @@ max77686: pmic@09 { compatible = "maxim,max77686"; + interrupt-parent = <&gpx3>; + interrupts = <2 0>; + pinctrl-names = "default"; + pinctrl-0 = <&max77686_irq>; reg = <0x09>; #clock-cells = <1>; @@ -368,4 +372,11 @@ samsung,pins = "gpx1-3"; samsung,pin-pud = <0>; }; + + max77686_irq: max77686-irq { + samsung,pins = "gpx3-2"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; }; -- cgit v1.1 From 95d516b9fca8ce77d6babd0c35513e7354441e7d Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 16 Jul 2014 09:50:06 +0100 Subject: ARM: dts: ODROID i2c improvements Increase max i2c bus frequency beyond the default for faster data transfers. According to the manual, these faster speeds are only available when the board is wired up the right way. In this case, the vendor kernel has run at this speed for a long time. sda-delay is needed for talking to RTC on PMIC, otherwise the i2c controller never sees an ACK. Strangely the other PMIC i2c slave (the main one) works fine even without this delay. I Chose value 100 to match the vendor kernel. Signed-off-by: Daniel Drake Reviewed-by: Tomasz Figa Tested-by: Tomeu Vizoso Signed-off-by: Olof Johansson --- arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi index cb6f55f..adadaf9 100644 --- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi +++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi @@ -134,6 +134,8 @@ i2c@13860000 { pinctrl-0 = <&i2c0_bus>; pinctrl-names = "default"; + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <400000>; status = "okay"; usb3503: usb3503@08 { -- cgit v1.1 From e6d8fb340f20bc5275ceed86133d1823dec9478d Mon Sep 17 00:00:00 2001 From: Chin-Tsung Cheng Date: Fri, 15 Aug 2014 15:49:31 +0800 Subject: ext3: Count internal journal as bsddf overhead in ext3_statfs The journal blocks of external journal device should not be counted as overhead. Signed-off-by: Chin-Tsung Cheng Signed-off-by: Jan Kara --- fs/ext3/super.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 08cdfe5..622e882 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2828,8 +2828,9 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) */ overhead += ngroups * (2 + sbi->s_itb_per_group); - /* Add the journal blocks as well */ - overhead += sbi->s_journal->j_maxlen; + /* Add the internal journal blocks as well */ + if (sbi->s_journal && !sbi->journal_bdev) + overhead += sbi->s_journal->j_maxlen; sbi->s_overhead_last = overhead; smp_wmb(); -- cgit v1.1 From b3f207855f57b9c8f43a547a801340bb5cbc59e5 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Fri, 13 Jun 2014 16:03:32 +0100 Subject: perf: Handle compat ioctl When running a 32-bit userspace on a 64-bit kernel (eg. i386 application on x86_64 kernel or 32-bit arm userspace on arm64 kernel) some of the perf ioctls must be treated with special care, as they have a pointer size encoded in the command. For example, PERF_EVENT_IOC_ID in 32-bit world will be encoded as 0x80042407, but 64-bit kernel will expect 0x80082407. In result the ioctl will fail returning -ENOTTY. This patch solves the problem by adding code fixing up the size as compat_ioctl file operation. Reported-by: Drew Richardson Signed-off-by: Pawel Moll Signed-off-by: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1402671812-9078-1-git-send-email-pawel.moll@arm.com Signed-off-by: Ingo Molnar --- kernel/events/core.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 1cf24b3..f9c1ed0 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "internal.h" @@ -3717,6 +3718,26 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return 0; } +#ifdef CONFIG_COMPAT +static long perf_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + switch (_IOC_NR(cmd)) { + case _IOC_NR(PERF_EVENT_IOC_SET_FILTER): + case _IOC_NR(PERF_EVENT_IOC_ID): + /* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case */ + if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) { + cmd &= ~IOCSIZE_MASK; + cmd |= sizeof(void *) << IOCSIZE_SHIFT; + } + break; + } + return perf_ioctl(file, cmd, arg); +} +#else +# define perf_compat_ioctl NULL +#endif + int perf_event_task_enable(void) { struct perf_event *event; @@ -4222,7 +4243,7 @@ static const struct file_operations perf_fops = { .read = perf_read, .poll = perf_poll, .unlocked_ioctl = perf_ioctl, - .compat_ioctl = perf_ioctl, + .compat_ioctl = perf_compat_ioctl, .mmap = perf_mmap, .fasync = perf_fasync, }; -- cgit v1.1 From 8039aabb6c9f802bca04cc77ca210060a5b53916 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 20 Aug 2014 08:18:18 -0700 Subject: Revert "platform/x86/toshiba-apci.c possible bad if test?" This reverts commit bdc3ae7221213963f438faeaa69c8b4a2195f491. Signed-off-by: Matthew Garrett --- drivers/platform/x86/toshiba_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index e4da61b..b062d3d 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1258,7 +1258,7 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev, int mode = -1; int time = -1; - if (sscanf(buf, "%i", &mode) != 1 || (mode != 2 || mode != 1)) + if (sscanf(buf, "%i", &mode) != 1 && (mode != 2 || mode != 1)) return -EINVAL; /* Set the Keyboard Backlight Mode where: -- cgit v1.1 From b7609491446c73240f60af4b691a9f8b377f2025 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 7 Aug 2014 15:57:41 +0200 Subject: microblaze: Wire-up seccomp syscall Add new seccomp syscall. Signed-off-by: Michal Simek --- arch/microblaze/include/uapi/asm/unistd.h | 1 + arch/microblaze/kernel/syscall_table.S | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/microblaze/include/uapi/asm/unistd.h b/arch/microblaze/include/uapi/asm/unistd.h index 4e1ddc9..3fafcd2 100644 --- a/arch/microblaze/include/uapi/asm/unistd.h +++ b/arch/microblaze/include/uapi/asm/unistd.h @@ -399,5 +399,6 @@ #define __NR_sched_setattr 381 #define __NR_sched_getattr 382 #define __NR_renameat2 383 +#define __NR_seccomp 384 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */ diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index 1a23d5d..342da7e 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -384,3 +384,4 @@ ENTRY(sys_call_table) .long sys_sched_setattr .long sys_sched_getattr .long sys_renameat2 + .long sys_seccomp -- cgit v1.1 From 53133453a9f791dff5b6403bc2f1208b474ae792 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 7 Aug 2014 15:59:05 +0200 Subject: microblaze: Wire-up getrandom syscall Add new getrandom syscall. Signed-off-by: Michal Simek --- arch/microblaze/include/uapi/asm/unistd.h | 1 + arch/microblaze/kernel/syscall_table.S | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/microblaze/include/uapi/asm/unistd.h b/arch/microblaze/include/uapi/asm/unistd.h index 3fafcd2..ad5526a 100644 --- a/arch/microblaze/include/uapi/asm/unistd.h +++ b/arch/microblaze/include/uapi/asm/unistd.h @@ -400,5 +400,6 @@ #define __NR_sched_getattr 382 #define __NR_renameat2 383 #define __NR_seccomp 384 +#define __NR_getrandom 385 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */ diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index 342da7e..c7c806d 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -385,3 +385,4 @@ ENTRY(sys_call_table) .long sys_sched_getattr .long sys_renameat2 .long sys_seccomp + .long sys_getrandom /* 385 */ -- cgit v1.1 From 83c43c498a0a269e8334e53994c75dad8824cca2 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 21 Aug 2014 10:19:28 +0200 Subject: microblaze: Wire-up memfd_create syscall Add new memfd_create syscall. Signed-off-by: Michal Simek --- arch/microblaze/include/uapi/asm/unistd.h | 1 + arch/microblaze/kernel/syscall_table.S | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/microblaze/include/uapi/asm/unistd.h b/arch/microblaze/include/uapi/asm/unistd.h index ad5526a..1c2380b 100644 --- a/arch/microblaze/include/uapi/asm/unistd.h +++ b/arch/microblaze/include/uapi/asm/unistd.h @@ -401,5 +401,6 @@ #define __NR_renameat2 383 #define __NR_seccomp 384 #define __NR_getrandom 385 +#define __NR_memfd_create 386 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */ diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S index c7c806d..de59ee1 100644 --- a/arch/microblaze/kernel/syscall_table.S +++ b/arch/microblaze/kernel/syscall_table.S @@ -386,3 +386,4 @@ ENTRY(sys_call_table) .long sys_renameat2 .long sys_seccomp .long sys_getrandom /* 385 */ + .long sys_memfd_create -- cgit v1.1 From 9e37bc6c635a85e0ae3067f19d6f84e1c4516a6c Mon Sep 17 00:00:00 2001 From: Mirza Krak Date: Fri, 8 Aug 2014 14:30:50 +0200 Subject: can: sja1000: Validate initialization state in start method When sja1000 is not compiled as module the SJA1000 chip is only initialized during device registration on kernel boot. Should the chip get a hardware reset there is no way to reinitialize it without re- booting the Linux kernel. This patch adds a check in sja1000_start if the chip is initialized, if not we initialize it. Signed-off-by: Mirza Krak Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000.c | 62 +++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index d169215..b27ac60 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -172,6 +172,35 @@ static void set_normal_mode(struct net_device *dev) netdev_err(dev, "setting SJA1000 into normal mode failed!\n"); } +/* + * initialize SJA1000 chip: + * - reset chip + * - set output mode + * - set baudrate + * - enable interrupts + * - start operating mode + */ +static void chipset_init(struct net_device *dev) +{ + struct sja1000_priv *priv = netdev_priv(dev); + + /* set clock divider and output control register */ + priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN); + + /* set acceptance filter (accept all) */ + priv->write_reg(priv, SJA1000_ACCC0, 0x00); + priv->write_reg(priv, SJA1000_ACCC1, 0x00); + priv->write_reg(priv, SJA1000_ACCC2, 0x00); + priv->write_reg(priv, SJA1000_ACCC3, 0x00); + + priv->write_reg(priv, SJA1000_ACCM0, 0xFF); + priv->write_reg(priv, SJA1000_ACCM1, 0xFF); + priv->write_reg(priv, SJA1000_ACCM2, 0xFF); + priv->write_reg(priv, SJA1000_ACCM3, 0xFF); + + priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL); +} + static void sja1000_start(struct net_device *dev) { struct sja1000_priv *priv = netdev_priv(dev); @@ -180,6 +209,10 @@ static void sja1000_start(struct net_device *dev) if (priv->can.state != CAN_STATE_STOPPED) set_reset_mode(dev); + /* Initialize chip if uninitialized at this stage */ + if (!(priv->read_reg(priv, SJA1000_CDR) & CDR_PELICAN)) + chipset_init(dev); + /* Clear error counters and error code capture */ priv->write_reg(priv, SJA1000_TXERR, 0x0); priv->write_reg(priv, SJA1000_RXERR, 0x0); @@ -237,35 +270,6 @@ static int sja1000_get_berr_counter(const struct net_device *dev, } /* - * initialize SJA1000 chip: - * - reset chip - * - set output mode - * - set baudrate - * - enable interrupts - * - start operating mode - */ -static void chipset_init(struct net_device *dev) -{ - struct sja1000_priv *priv = netdev_priv(dev); - - /* set clock divider and output control register */ - priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN); - - /* set acceptance filter (accept all) */ - priv->write_reg(priv, SJA1000_ACCC0, 0x00); - priv->write_reg(priv, SJA1000_ACCC1, 0x00); - priv->write_reg(priv, SJA1000_ACCC2, 0x00); - priv->write_reg(priv, SJA1000_ACCC3, 0x00); - - priv->write_reg(priv, SJA1000_ACCM0, 0xFF); - priv->write_reg(priv, SJA1000_ACCM1, 0xFF); - priv->write_reg(priv, SJA1000_ACCM2, 0xFF); - priv->write_reg(priv, SJA1000_ACCM3, 0xFF); - - priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL); -} - -/* * transmit a CAN message * message layout in the sk_buff should be like this: * xx xx xx xx ff ll 00 11 22 33 44 55 66 77 -- cgit v1.1 From 37b75a3aa8ec7031df75219fe2f8e5e9b7be398f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 1 Aug 2014 11:53:44 +0300 Subject: can: c_can: checking IS_ERR() instead of NULL devm_ioremap() returns NULL on error, not an ERR_PTR(). Fixes: 33cf75656923 ('can: c_can_platform: Fix raminit, use devm_ioremap() instead of devm_ioremap_resource()') Signed-off-by: Dan Carpenter Cc: linux-stable # >= v3.11 Signed-off-by: Marc Kleine-Budde --- drivers/net/can/c_can/c_can_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index 5dede6e..109cb44 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -280,7 +280,7 @@ static int c_can_plat_probe(struct platform_device *pdev) priv->raminit_ctrlreg = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0) + if (!priv->raminit_ctrlreg || priv->instance < 0) dev_info(&pdev->dev, "control memory is not used for raminit\n"); else priv->raminit = c_can_hw_raminit_ti; -- cgit v1.1 From bc03a54139baafcd8fe89ad115411c2c9c8a4905 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Aug 2014 10:47:21 +0200 Subject: can: flexcan: Disable error interrupt when bus error reporting is disabled In case we don't have FLEXCAN_HAS_BROKEN_ERR_STATE and the user set CAN_CTRLMODE_BERR_REPORTING once it can not be unset again until reboot. So in case neither hardware nor user wants the error interrupt disable the bit. Signed-off-by: Alexander Stein Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index f425ec2..a691651 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -852,6 +852,8 @@ static int flexcan_chip_start(struct net_device *dev) if (priv->devtype_data->features & FLEXCAN_HAS_BROKEN_ERR_STATE || priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) reg_ctrl |= FLEXCAN_CTRL_ERR_MSK; + else + reg_ctrl &= ~FLEXCAN_CTRL_ERR_MSK; /* save for later use */ priv->reg_ctrl_default = reg_ctrl; -- cgit v1.1 From 8ce261d0bb491da957278cdcba207791f329d1da Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 25 Jul 2014 20:16:40 +0200 Subject: can: flexcan: handle state passive -> warning transition Once the CAN-bus is open and a packet is sent, the controller switches into the PASSIVE state. Once the BUS is closed again it goes the back err-warning. The TX error counter goes 0 -> 0x80 -> 0x7f. This patch makes sure that the user learns about this state chang (CAN_STATE_ERROR_WARNING => CAN_STATE_ERROR_PASSIVE) Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Matthias Klein Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index a691651..944aa5d 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -549,6 +549,13 @@ static void do_state(struct net_device *dev, /* process state changes depending on the new state */ switch (new_state) { + case CAN_STATE_ERROR_WARNING: + netdev_dbg(dev, "Error Warning\n"); + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = (bec.txerr > bec.rxerr) ? + CAN_ERR_CRTL_TX_WARNING : + CAN_ERR_CRTL_RX_WARNING; + break; case CAN_STATE_ERROR_ACTIVE: netdev_dbg(dev, "Error Active\n"); cf->can_id |= CAN_ERR_PROT; -- cgit v1.1 From 58b84f6a97f7f8811e0636836734809ff52cad43 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Aug 2014 12:00:53 -0500 Subject: gpio: move GPIOD flags outside #ifdef The GPIOD flags are defined inside the #ifdef CONFIG_GPIOLIB switch, making the gpiolib stubs fail if these flags are used by a consumer. This is not correct: the stubs should compile fine without GPIOLIB. Reported-by: Ulf Hansson Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- include/linux/gpio/consumer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index b7ce0c6..c7e17de 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -16,8 +16,6 @@ struct device; */ struct gpio_desc; -#ifdef CONFIG_GPIOLIB - #define GPIOD_FLAGS_BIT_DIR_SET BIT(0) #define GPIOD_FLAGS_BIT_DIR_OUT BIT(1) #define GPIOD_FLAGS_BIT_DIR_VAL BIT(2) @@ -34,6 +32,8 @@ enum gpiod_flags { GPIOD_FLAGS_BIT_DIR_VAL, }; +#ifdef CONFIG_GPIOLIB + /* Acquire and dispose GPIOs */ struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id, -- cgit v1.1 From 8117bd531501ec329e4c9ea96fb7f9d5504c82f5 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Tue, 19 Aug 2014 14:00:01 +0300 Subject: gpio-lynxpoint: enable input sensing in resume It appears that input sensing bit might be reset during suspend/resume. Set input sensing again for all requested gpios in resume Tested-by: Jerome Blin Signed-off-by: Mathias Nyman Acked-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpio-lynxpoint.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index ff9eb91..fa945ec 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -407,9 +407,27 @@ static int lp_gpio_runtime_resume(struct device *dev) return 0; } +static int lp_gpio_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lp_gpio *lg = platform_get_drvdata(pdev); + unsigned long reg; + int i; + + /* on some hardware suspend clears input sensing, re-enable it here */ + for (i = 0; i < lg->chip.ngpio; i++) { + if (gpiochip_is_requested(&lg->chip, i) != NULL) { + reg = lp_gpio_reg(&lg->chip, i, LP_CONFIG2); + outl(inl(reg) & ~GPINDIS_BIT, reg); + } + } + return 0; +} + static const struct dev_pm_ops lp_gpio_pm_ops = { .runtime_suspend = lp_gpio_runtime_suspend, .runtime_resume = lp_gpio_runtime_resume, + .resume = lp_gpio_resume, }; static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { -- cgit v1.1 From 51217e69697fba92a06e07e16f55c9a52d8e8945 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 21 Aug 2014 09:56:47 -0500 Subject: HID: logitech: fix bounds checking on LED report size The check on report size for REPORT_TYPE_LEDS in logi_dj_ll_raw_request() is wrong; the current check doesn't make any sense -- the report allocated by HID core in hid_hw_raw_request() can be much larger than DJREPORT_SHORT_LENGTH, and currently logi_dj_ll_raw_request() doesn't handle this properly at all. Fix the check by actually trimming down the report size properly if it is too large. Cc: stable@vger.kernel.org Reported-by: Ben Hawkes Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-dj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 486dbde..ca0ab51 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -557,7 +557,7 @@ static int logi_dj_ll_raw_request(struct hid_device *hid, if (!out_buf) return -ENOMEM; - if (count < DJREPORT_SHORT_LENGTH - 2) + if (count > DJREPORT_SHORT_LENGTH - 2) count = DJREPORT_SHORT_LENGTH - 2; out_buf[0] = REPORT_ID_DJ_SHORT; -- cgit v1.1 From ad3e14d7c5268c2e24477c6ef54bbdf88add5d36 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 21 Aug 2014 09:57:17 -0500 Subject: HID: logitech: perform bounds checking on device_id early enough device_index is a char type and the size of paired_dj_deivces is 7 elements, therefore proper bounds checking has to be applied to device_index before it is used. We are currently performing the bounds checking in logi_dj_recv_add_djhid_device(), which is too late, as malicious device could send REPORT_TYPE_NOTIF_DEVICE_UNPAIRED early enough and trigger the problem in one of the report forwarding functions called from logi_dj_raw_event(). Fix this by performing the check at the earliest possible ocasion in logi_dj_raw_event(). Cc: stable@vger.kernel.org Reported-by: Ben Hawkes Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-dj.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index ca0ab51..b7ba829 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -238,13 +238,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, return; } - if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || - (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { - dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n", - __func__, dj_report->device_index); - return; - } - if (djrcv_dev->paired_dj_devices[dj_report->device_index]) { /* The device is already known. No need to reallocate it. */ dbg_hid("%s: device is already known\n", __func__); @@ -690,6 +683,12 @@ static int logi_dj_raw_event(struct hid_device *hdev, * device (via hid_input_report() ) and return 1 so hid-core does not do * anything else with it. */ + if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) || + (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) { + dev_err(&hdev->dev, "%s: invalid device index:%d\n", + __func__, dj_report->device_index); + return false; + } spin_lock_irqsave(&djrcv_dev->lock, flags); if (dj_report->report_id == REPORT_ID_DJ_SHORT) { -- cgit v1.1 From 4ab25786c87eb20857bbb715c3ae34ec8fd6a214 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 21 Aug 2014 09:57:48 -0500 Subject: HID: fix a couple of off-by-ones There are a few very theoretical off-by-one bugs in report descriptor size checking when performing a pre-parsing fixup. Fix those. Cc: stable@vger.kernel.org Reported-by: Ben Hawkes Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-cherry.c | 2 +- drivers/hid/hid-kye.c | 2 +- drivers/hid/hid-lg.c | 4 ++-- drivers/hid/hid-monterey.c | 2 +- drivers/hid/hid-petalynx.c | 2 +- drivers/hid/hid-sunplus.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c index 1bdcccc..f745d2c 100644 --- a/drivers/hid/hid-cherry.c +++ b/drivers/hid/hid-cherry.c @@ -28,7 +28,7 @@ static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { + if (*rsize >= 18 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n"); rdesc[11] = rdesc[16] = 0xff; rdesc[12] = rdesc[17] = 0x03; diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index e776963..b92bf01 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -300,7 +300,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, * - change the button usage range to 4-7 for the extra * buttons */ - if (*rsize >= 74 && + if (*rsize >= 75 && rdesc[61] == 0x05 && rdesc[62] == 0x08 && rdesc[63] == 0x19 && rdesc[64] == 0x08 && rdesc[65] == 0x29 && rdesc[66] == 0x0f && diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index a976f48..f91ff14 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -345,14 +345,14 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, struct usb_device_descriptor *udesc; __u16 bcdDevice, rev_maj, rev_min; - if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 && + if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 && rdesc[84] == 0x8c && rdesc[85] == 0x02) { hid_info(hdev, "fixing up Logitech keyboard report descriptor\n"); rdesc[84] = rdesc[89] = 0x4d; rdesc[85] = rdesc[90] = 0x10; } - if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 && + if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 && rdesc[32] == 0x81 && rdesc[33] == 0x06 && rdesc[49] == 0x81 && rdesc[50] == 0x06) { hid_info(hdev, diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c index 9e14c00..25daf28 100644 --- a/drivers/hid/hid-monterey.c +++ b/drivers/hid/hid-monterey.c @@ -24,7 +24,7 @@ static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { + if (*rsize >= 31 && rdesc[29] == 0x05 && rdesc[30] == 0x09) { hid_info(hdev, "fixing up button/consumer in HID report descriptor\n"); rdesc[30] = 0x0c; } diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c index 736b250..6aca4f2 100644 --- a/drivers/hid/hid-petalynx.c +++ b/drivers/hid/hid-petalynx.c @@ -25,7 +25,7 @@ static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && + if (*rsize >= 62 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 && rdesc[41] == 0x00 && rdesc[59] == 0x26 && rdesc[60] == 0xf9 && rdesc[61] == 0x00) { hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n"); diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c index 87fc91e..91072fa 100644 --- a/drivers/hid/hid-sunplus.c +++ b/drivers/hid/hid-sunplus.c @@ -24,7 +24,7 @@ static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { - if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && + if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 && rdesc[106] == 0x03) { hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n"); rdesc[105] = rdesc[110] = 0x03; -- cgit v1.1 From 6df378d2d1f87a249a88ac4a8c7a14861d9c9474 Mon Sep 17 00:00:00 2001 From: chas williams - CONTRACTOR Date: Thu, 14 Aug 2014 09:19:47 -0400 Subject: lec: Use rtnl lock/unlock when updating MTU The LECS response contains the MTU that should be used. Correctly synchronize with other layers when updating. Signed-off-by: Chas Williams - CONTRACTOR Signed-off-by: David S. Miller --- net/atm/lec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/atm/lec.c b/net/atm/lec.c index e4853b5..4b98f89 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -410,9 +410,11 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) priv->lane2_ops = NULL; if (priv->lane_version > 1) priv->lane2_ops = &lane2_ops; + rtnl_lock(); if (dev_set_mtu(dev, mesg->content.config.mtu)) pr_info("%s: change_mtu to %d failed\n", dev->name, mesg->content.config.mtu); + rtnl_unlock(); priv->is_proxy = mesg->content.config.is_proxy; break; case l_flush_tran_id: -- cgit v1.1 From 564ee3606fe6c9e014c4bee9d74a5eaef96034c8 Mon Sep 17 00:00:00 2001 From: Dariusz Marcinkiewicz Date: Fri, 15 Aug 2014 17:50:47 +0200 Subject: MAINTAINERS: add entry for ec_bhf driver Added entry for ec_bhf driver. Signed-off-by: Dariusz Marcinkiewicz Signed-off-by: David S. Miller --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 2f85f55..ae1ed19 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1843,6 +1843,12 @@ S: Orphan F: Documentation/filesystems/befs.txt F: fs/befs/ +BECKHOFF CX5020 ETHERCAT MASTER DRIVER +M: Dariusz Marcinkiewicz +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/ec_bhf.c + BFS FILE SYSTEM M: "Tigran A. Aivazian" S: Maintained -- cgit v1.1 From dc808110bb62b64a448696ecac3938902c92e1ab Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 15 Aug 2014 09:16:04 -0700 Subject: packet: handle too big packets for PACKET_V3 af_packet can currently overwrite kernel memory by out of bound accesses, because it assumed a [new] block can always hold one frame. This is not generally the case, even if most existing tools do it right. This patch clamps too long frames as API permits, and issue a one time error on syslog. [ 394.357639] tpacket_rcv: packet too big, clamped from 5042 to 3966. macoff=82 In this example, packet header tp_snaplen was set to 3966, and tp_len was set to 5042 (skb->len) Signed-off-by: Eric Dumazet Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") Acked-by: Daniel Borkmann Acked-by: Neil Horman Signed-off-by: David S. Miller --- net/packet/af_packet.c | 17 +++++++++++++++++ net/packet/internal.h | 1 + 2 files changed, 18 insertions(+) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 8d9f804..93896d2 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -632,6 +632,7 @@ static void init_prb_bdqc(struct packet_sock *po, p1->tov_in_jiffies = msecs_to_jiffies(p1->retire_blk_tov); p1->blk_sizeof_priv = req_u->req3.tp_sizeof_priv; + p1->max_frame_len = p1->kblk_size - BLK_PLUS_PRIV(p1->blk_sizeof_priv); prb_init_ft_ops(p1, req_u); prb_setup_retire_blk_timer(po, tx_ring); prb_open_block(p1, pbd); @@ -1942,6 +1943,18 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if ((int)snaplen < 0) snaplen = 0; } + } else if (unlikely(macoff + snaplen > + GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len)) { + u32 nval; + + nval = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len - macoff; + pr_err_once("tpacket_rcv: packet too big, clamped from %u to %u. macoff=%u\n", + snaplen, nval, macoff); + snaplen = nval; + if (unlikely((int)snaplen < 0)) { + snaplen = 0; + macoff = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len; + } } spin_lock(&sk->sk_receive_queue.lock); h.raw = packet_current_rx_frame(po, skb, @@ -3783,6 +3796,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, goto out; if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) goto out; + if (po->tp_version >= TPACKET_V3 && + (int)(req->tp_block_size - + BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0) + goto out; if (unlikely(req->tp_frame_size < po->tp_hdrlen + po->tp_reserve)) goto out; diff --git a/net/packet/internal.h b/net/packet/internal.h index eb9580a..cdddf6a 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -29,6 +29,7 @@ struct tpacket_kbdq_core { char *pkblk_start; char *pkblk_end; int kblk_size; + unsigned int max_frame_len; unsigned int knum_blocks; uint64_t knxt_seq_num; char *prev; -- cgit v1.1 From 8a50f11c3b176d7a1df8cd5e29cbe965905e51ee Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 15 Aug 2014 13:04:59 -0400 Subject: macvlan: Allow setting multicast filter on all macvlan types Currently, macvlan code restricts multicast and unicast filter setting only to passthru devices. As a result, if a guest using macvtap wants to receive multicast traffic, it has to set IFF_ALLMULTI or IFF_PROMISC. This patch makes it possible to use the fdb interface to add multicast addresses to the filter thus allowing a guest to receive only targeted multicast traffic. CC: John Fastabend CC: Michael S. Tsirkin CC: Jason Wang Signed-off-by: Vladislav Yasevich Acked-by: John Fastabend Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 60e4ca0..a969555 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -739,7 +739,10 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct macvlan_dev *vlan = netdev_priv(dev); int err = -EINVAL; - if (!vlan->port->passthru) + /* Support unicast filter only on passthru devices. + * Multicast filter should be allowed on all devices. + */ + if (!vlan->port->passthru && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (flags & NLM_F_REPLACE) @@ -760,7 +763,10 @@ static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct macvlan_dev *vlan = netdev_priv(dev); int err = -EINVAL; - if (!vlan->port->passthru) + /* Support unicast filter only on passthru devices. + * Multicast filter should be allowed on all devices. + */ + if (!vlan->port->passthru && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (is_unicast_ether_addr(addr)) -- cgit v1.1 From d7155691127d69dff28e371e61fa68375a70a456 Mon Sep 17 00:00:00 2001 From: Alan Ott Date: Sat, 16 Aug 2014 17:09:03 -0400 Subject: MAINTAINERS: Add section for MRF24J40 IEEE 802.15.4 radio driver Alan is the original author of the driver. This change was discussed with the 802.15.4 subsystem maintainer, Alexander Aring. Signed-off-by: Alan Ott Acked-by: Alexander Aring Signed-off-by: David S. Miller --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ae1ed19..92b5234 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5978,6 +5978,12 @@ T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/radio/radio-mr800.c +MRF24J40 IEEE 802.15.4 RADIO DRIVER +M: Alan Ott +L: linux-wpan@vger.kernel.org +S: Maintained +F: drivers/net/ieee802154/mrf24j40.c + MSI LAPTOP SUPPORT M: "Lee, Chun-Yi" L: platform-driver-x86@vger.kernel.org -- cgit v1.1 From 26acc712526e9a8a849c819ffb8fe2d4e1f7c063 Mon Sep 17 00:00:00 2001 From: Jitendra Kalsaria Date: Mon, 18 Aug 2014 09:31:53 -0400 Subject: qlcnic: Fix flash access interface to application Application expects flash data in little endian, but driver reads/writes flash data using readl()/writel() APIs which swaps data on big endian machine. So, swap the data after reading from and before writing to flash memory. Signed-off-by: Jitendra Kalsaria Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 15 ++++++++++++++- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 6 +++--- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 16 +++++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 16039d1..b84f5ea 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -268,7 +268,7 @@ struct qlcnic_fdt { u16 cksum; u16 unused; u8 model[16]; - u16 mfg_id; + u8 mfg_id; u16 id; u8 flag; u8 erase_cmd; @@ -2362,6 +2362,19 @@ static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter) return QLC_DEFAULT_VNIC_COUNT; } +static inline void qlcnic_swap32_buffer(u32 *buffer, int count) +{ +#if defined(__BIG_ENDIAN) + u32 *tmp = buffer; + int i; + + for (i = 0; i < count; i++) { + *tmp = swab32(*tmp); + tmp++; + } +#endif +} + #ifdef CONFIG_QLCNIC_HWMON void qlcnic_register_hwmon_dev(struct qlcnic_adapter *); void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index a4a4ec0..476e499 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -2603,7 +2603,7 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter, } qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_DIRECT_WINDOW, - (addr)); + (addr & 0xFFFF0000)); range = flash_offset + (count * sizeof(u32)); /* Check if data is spread across multiple sectors */ @@ -2753,7 +2753,7 @@ int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *adapter) ret = qlcnic_83xx_lockless_flash_read32(adapter, QLCNIC_FDT_LOCATION, (u8 *)&adapter->ahw->fdt, count); - + qlcnic_swap32_buffer((u32 *)&adapter->ahw->fdt, count); qlcnic_83xx_unlock_flash(adapter); return ret; } @@ -2788,7 +2788,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter, addr1 = (sector_start_addr & 0xFF) << 16; addr2 = (sector_start_addr & 0xFF0000) >> 16; - reversed_addr = addr1 | addr2; + reversed_addr = addr1 | addr2 | (sector_start_addr & 0xFF00); qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA, reversed_addr); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index f5786d5..59a721f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -280,6 +280,7 @@ static ssize_t qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj, if (ret != 0) return ret; qlcnic_read_crb(adapter, buf, offset, size); + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); return size; } @@ -296,6 +297,7 @@ static ssize_t qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj, if (ret != 0) return ret; + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); qlcnic_write_crb(adapter, buf, offset, size); return size; } @@ -329,6 +331,7 @@ static ssize_t qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj, return -EIO; memcpy(buf, &data, size); + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); return size; } @@ -346,6 +349,7 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj, if (ret != 0) return ret; + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); memcpy(&data, buf, size); if (qlcnic_pci_mem_write_2M(adapter, offset, data)) @@ -412,6 +416,7 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp, if (rem) return QL_STATUS_INVALID_PARAM; + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); pm_cfg = (struct qlcnic_pm_func_cfg *)buf; ret = validate_pm_config(adapter, pm_cfg, count); @@ -474,6 +479,7 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp, pm_cfg[pci_func].dest_npar = 0; pm_cfg[pci_func].pci_func = i; } + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); return size; } @@ -555,6 +561,7 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file, if (rem) return QL_STATUS_INVALID_PARAM; + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); esw_cfg = (struct qlcnic_esw_func_cfg *)buf; ret = validate_esw_config(adapter, esw_cfg, count); if (ret) @@ -649,6 +656,7 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file, if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func])) return QL_STATUS_INVALID_PARAM; } + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); return size; } @@ -688,6 +696,7 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file, if (rem) return QL_STATUS_INVALID_PARAM; + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); np_cfg = (struct qlcnic_npar_func_cfg *)buf; ret = validate_npar_config(adapter, np_cfg, count); if (ret) @@ -759,6 +768,7 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file, np_cfg[pci_func].max_tx_queues = nic_info.max_tx_ques; np_cfg[pci_func].max_rx_queues = nic_info.max_rx_ques; } + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); return size; } @@ -916,6 +926,7 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, pci_cfg = (struct qlcnic_pci_func_cfg *)buf; count = size / sizeof(struct qlcnic_pci_func_cfg); + qlcnic_swap32_buffer((u32 *)pci_info, size / sizeof(u32)); for (i = 0; i < count; i++) { pci_cfg[i].pci_func = pci_info[i].id; pci_cfg[i].func_type = pci_info[i].type; @@ -969,6 +980,7 @@ static ssize_t qlcnic_83xx_sysfs_flash_read_handler(struct file *filp, } qlcnic_83xx_unlock_flash(adapter); + qlcnic_swap32_buffer((u32 *)p_read_buf, count); memcpy(buf, p_read_buf, size); kfree(p_read_buf); @@ -986,9 +998,10 @@ static int qlcnic_83xx_sysfs_flash_bulk_write(struct qlcnic_adapter *adapter, if (!p_cache) return -ENOMEM; + count = size / sizeof(u32); + qlcnic_swap32_buffer((u32 *)buf, count); memcpy(p_cache, buf, size); p_src = p_cache; - count = size / sizeof(u32); if (qlcnic_83xx_lock_flash(adapter) != 0) { kfree(p_cache); @@ -1053,6 +1066,7 @@ static int qlcnic_83xx_sysfs_flash_write(struct qlcnic_adapter *adapter, if (!p_cache) return -ENOMEM; + qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32)); memcpy(p_cache, buf, size); p_src = p_cache; count = size / sizeof(u32); -- cgit v1.1 From d874df58ff2eefadd22623d4e53ff92e38117b40 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Mon, 18 Aug 2014 09:31:54 -0400 Subject: qlcnic: Fix endianess issue in FW dump template header Firmware dump template header is read from adapter using readl() which swaps the data. So, adjust structure element on the boundary of 32bit dword. Signed-off-by: Rajesh Borundia Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- .../net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index e46fc39..c9f57fb 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -47,15 +47,26 @@ struct qlcnic_common_entry_hdr { u32 type; u32 offset; u32 cap_size; +#if defined(__LITTLE_ENDIAN) u8 mask; u8 rsvd[2]; u8 flags; +#else + u8 flags; + u8 rsvd[2]; + u8 mask; +#endif } __packed; struct __crb { u32 addr; +#if defined(__LITTLE_ENDIAN) u8 stride; u8 rsvd1[3]; +#else + u8 rsvd1[3]; + u8 stride; +#endif u32 data_size; u32 no_ops; u32 rsvd2[4]; @@ -63,15 +74,28 @@ struct __crb { struct __ctrl { u32 addr; +#if defined(__LITTLE_ENDIAN) u8 stride; u8 index_a; u16 timeout; +#else + u16 timeout; + u8 index_a; + u8 stride; +#endif u32 data_size; u32 no_ops; +#if defined(__LITTLE_ENDIAN) u8 opcode; u8 index_v; u8 shl_val; u8 shr_val; +#else + u8 shr_val; + u8 shl_val; + u8 index_v; + u8 opcode; +#endif u32 val1; u32 val2; u32 val3; @@ -79,16 +103,27 @@ struct __ctrl { struct __cache { u32 addr; +#if defined(__LITTLE_ENDIAN) u16 stride; u16 init_tag_val; +#else + u16 init_tag_val; + u16 stride; +#endif u32 size; u32 no_ops; u32 ctrl_addr; u32 ctrl_val; u32 read_addr; +#if defined(__LITTLE_ENDIAN) u8 read_addr_stride; u8 read_addr_num; u8 rsvd1[2]; +#else + u8 rsvd1[2]; + u8 read_addr_num; + u8 read_addr_stride; +#endif } __packed; struct __ocm { @@ -122,23 +157,39 @@ struct __mux { struct __queue { u32 sel_addr; +#if defined(__LITTLE_ENDIAN) u16 stride; u8 rsvd[2]; +#else + u8 rsvd[2]; + u16 stride; +#endif u32 size; u32 no_ops; u8 rsvd2[8]; u32 read_addr; +#if defined(__LITTLE_ENDIAN) u8 read_addr_stride; u8 read_addr_cnt; u8 rsvd3[2]; +#else + u8 rsvd3[2]; + u8 read_addr_cnt; + u8 read_addr_stride; +#endif } __packed; struct __pollrd { u32 sel_addr; u32 read_addr; u32 sel_val; +#if defined(__LITTLE_ENDIAN) u16 sel_val_stride; u16 no_ops; +#else + u16 no_ops; + u16 sel_val_stride; +#endif u32 poll_wait; u32 poll_mask; u32 data_size; @@ -153,9 +204,15 @@ struct __mux2 { u32 no_ops; u32 sel_val_mask; u32 read_addr; +#if defined(__LITTLE_ENDIAN) u8 sel_val_stride; u8 data_size; u8 rsvd[2]; +#else + u8 rsvd[2]; + u8 data_size; + u8 sel_val_stride; +#endif } __packed; struct __pollrdmwr { -- cgit v1.1 From 3d8623e60054e6ada897e6295f137fa7f1399a97 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Mon, 18 Aug 2014 09:31:55 -0400 Subject: qlcnic: Fix endianess issue in firmware load from file operation Firmware binary file is in little endian. On big-endian architecture, while writing this binary FW file to adapters memory, writel() swaps the data resulting into corruption of FW image. So, swap the data before writing into adapters memory. Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 35 +++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index f33559b..86783e1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -1378,31 +1378,45 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) { struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info; const struct firmware *fw = fw_info->fw; - u32 dest, *p_cache; + u32 dest, *p_cache, *temp; int i, ret = -EIO; + __le32 *temp_le; u8 data[16]; size_t size; u64 addr; + temp = kzalloc(fw->size, GFP_KERNEL); + if (!temp) { + release_firmware(fw); + fw_info->fw = NULL; + return -ENOMEM; + } + + temp_le = (__le32 *)fw->data; + + /* FW image in file is in little endian, swap the data to nullify + * the effect of writel() operation on big endian platform. + */ + for (i = 0; i < fw->size / sizeof(u32); i++) + temp[i] = __le32_to_cpu(temp_le[i]); + dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR); size = (fw->size & ~0xF); - p_cache = (u32 *)fw->data; + p_cache = temp; addr = (u64)dest; ret = qlcnic_ms_mem_write128(adapter, addr, p_cache, size / 16); if (ret) { dev_err(&adapter->pdev->dev, "MS memory write failed\n"); - release_firmware(fw); - fw_info->fw = NULL; - return -EIO; + goto exit; } /* alignment check */ if (fw->size & 0xF) { addr = dest + size; for (i = 0; i < (fw->size & 0xF); i++) - data[i] = fw->data[size + i]; + data[i] = temp[size + i]; for (; i < 16; i++) data[i] = 0; ret = qlcnic_ms_mem_write128(adapter, addr, @@ -1410,15 +1424,16 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) if (ret) { dev_err(&adapter->pdev->dev, "MS memory write failed\n"); - release_firmware(fw); - fw_info->fw = NULL; - return -EIO; + goto exit; } } + +exit: release_firmware(fw); fw_info->fw = NULL; + kfree(temp); - return 0; + return ret; } static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter) -- cgit v1.1 From 7c3afd85dc1610bb2fc049644cd1b52c7af96f98 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Mon, 18 Aug 2014 22:36:23 +0300 Subject: bnx2x: Revert UNDI flushing mechanism Commit 91ebb929b6f8 ("bnx2x: Add support for Multi-Function UNDI") [which was later supposedly fixed by de682941eef3 ("bnx2x: Fix UNDI driver unload")] introduced a bug in which in some [yet-to-be-determined] scenarios the alternative flushing mechanism which was to guarantee the Rx buffers are empty before resetting them during device probe will fail. If this happens, when device will be loaded once more a fatal attention will occur; Since this most likely happens in boot from SAN scenarios, the machine will fail to load. Notice this may occur not only in the 'Multi-Function' scenario but in the regular scenario as well, i.e., this introduced a regression in the driver's ability to perform boot from SAN. The patch reverts the mechanism and applies the old scheme to multi-function devices as well as to single-function devices. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 92 +++++------------------- 1 file changed, 17 insertions(+), 75 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index c13364b..900cab4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -10052,6 +10052,8 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp, } #define BNX2X_PREV_UNDI_PROD_ADDR(p) (BAR_TSTRORM_INTMEM + 0x1508 + ((p) << 4)) +#define BNX2X_PREV_UNDI_PROD_ADDR_H(f) (BAR_TSTRORM_INTMEM + \ + 0x1848 + ((f) << 4)) #define BNX2X_PREV_UNDI_RCQ(val) ((val) & 0xffff) #define BNX2X_PREV_UNDI_BD(val) ((val) >> 16 & 0xffff) #define BNX2X_PREV_UNDI_PROD(rcq, bd) ((bd) << 16 | (rcq)) @@ -10059,8 +10061,6 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp, #define BCM_5710_UNDI_FW_MF_MAJOR (0x07) #define BCM_5710_UNDI_FW_MF_MINOR (0x08) #define BCM_5710_UNDI_FW_MF_VERS (0x05) -#define BNX2X_PREV_UNDI_MF_PORT(p) (BAR_TSTRORM_INTMEM + 0x150c + ((p) << 4)) -#define BNX2X_PREV_UNDI_MF_FUNC(f) (BAR_TSTRORM_INTMEM + 0x184c + ((f) << 4)) static bool bnx2x_prev_is_after_undi(struct bnx2x *bp) { @@ -10079,72 +10079,25 @@ static bool bnx2x_prev_is_after_undi(struct bnx2x *bp) return false; } -static bool bnx2x_prev_unload_undi_fw_supports_mf(struct bnx2x *bp) -{ - u8 major, minor, version; - u32 fw; - - /* Must check that FW is loaded */ - if (!(REG_RD(bp, MISC_REG_RESET_REG_1) & - MISC_REGISTERS_RESET_REG_1_RST_XSEM)) { - BNX2X_DEV_INFO("XSEM is reset - UNDI MF FW is not loaded\n"); - return false; - } - - /* Read Currently loaded FW version */ - fw = REG_RD(bp, XSEM_REG_PRAM); - major = fw & 0xff; - minor = (fw >> 0x8) & 0xff; - version = (fw >> 0x10) & 0xff; - BNX2X_DEV_INFO("Loaded FW: 0x%08x: Major 0x%02x Minor 0x%02x Version 0x%02x\n", - fw, major, minor, version); - - if (major > BCM_5710_UNDI_FW_MF_MAJOR) - return true; - - if ((major == BCM_5710_UNDI_FW_MF_MAJOR) && - (minor > BCM_5710_UNDI_FW_MF_MINOR)) - return true; - - if ((major == BCM_5710_UNDI_FW_MF_MAJOR) && - (minor == BCM_5710_UNDI_FW_MF_MINOR) && - (version >= BCM_5710_UNDI_FW_MF_VERS)) - return true; - - return false; -} - -static void bnx2x_prev_unload_undi_mf(struct bnx2x *bp) -{ - int i; - - /* Due to legacy (FW) code, the first function on each engine has a - * different offset macro from the rest of the functions. - * Setting this for all 8 functions is harmless regardless of whether - * this is actually a multi-function device. - */ - for (i = 0; i < 2; i++) - REG_WR(bp, BNX2X_PREV_UNDI_MF_PORT(i), 1); - - for (i = 2; i < 8; i++) - REG_WR(bp, BNX2X_PREV_UNDI_MF_FUNC(i - 2), 1); - - BNX2X_DEV_INFO("UNDI FW (MF) set to discard\n"); -} - -static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 port, u8 inc) +static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 inc) { u16 rcq, bd; - u32 tmp_reg = REG_RD(bp, BNX2X_PREV_UNDI_PROD_ADDR(port)); + u32 addr, tmp_reg; + if (BP_FUNC(bp) < 2) + addr = BNX2X_PREV_UNDI_PROD_ADDR(BP_PORT(bp)); + else + addr = BNX2X_PREV_UNDI_PROD_ADDR_H(BP_FUNC(bp) - 2); + + tmp_reg = REG_RD(bp, addr); rcq = BNX2X_PREV_UNDI_RCQ(tmp_reg) + inc; bd = BNX2X_PREV_UNDI_BD(tmp_reg) + inc; tmp_reg = BNX2X_PREV_UNDI_PROD(rcq, bd); - REG_WR(bp, BNX2X_PREV_UNDI_PROD_ADDR(port), tmp_reg); + REG_WR(bp, addr, tmp_reg); - BNX2X_DEV_INFO("UNDI producer [%d] rings bd -> 0x%04x, rcq -> 0x%04x\n", - port, bd, rcq); + BNX2X_DEV_INFO("UNDI producer [%d/%d][%08x] rings bd -> 0x%04x, rcq -> 0x%04x\n", + BP_PORT(bp), BP_FUNC(bp), addr, bd, rcq); } static int bnx2x_prev_mcp_done(struct bnx2x *bp) @@ -10383,7 +10336,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) /* Reset should be performed after BRB is emptied */ if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) { u32 timer_count = 1000; - bool need_write = true; /* Close the MAC Rx to prevent BRB from filling up */ bnx2x_prev_unload_close_mac(bp, &mac_vals); @@ -10420,20 +10372,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp) else timer_count--; - /* New UNDI FW supports MF and contains better - * cleaning methods - might be redundant but harmless. - */ - if (bnx2x_prev_unload_undi_fw_supports_mf(bp)) { - if (need_write) { - bnx2x_prev_unload_undi_mf(bp); - need_write = false; - } - } else if (prev_undi) { - /* If UNDI resides in memory, - * manually increment it - */ - bnx2x_prev_unload_undi_inc(bp, BP_PORT(bp), 1); - } + /* If UNDI resides in memory, manually increment it */ + if (prev_undi) + bnx2x_prev_unload_undi_inc(bp, 1); + udelay(10); } -- cgit v1.1 From 049d28048be595e0a10a58fe1c104b153c386633 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 20 Aug 2014 15:39:22 +0200 Subject: sh: intc: Confine SH_INTC to platforms that need it Currently the sh-intc driver is compiled on all SuperH and non-multiplatform SH-Mobile platforms, while it's only used on a limited number of platforms: - SuperH: SH2(A), SH3(A), SH4(A)(L) (all but SH5) - ARM: sh7372, sh73a0 Drop the "default y" on SH_INTC, make all CPU platforms that use it select it, and protect all sub-options by "if SH_INTC" to fix this. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 2 ++ arch/sh/Kconfig | 3 +++ drivers/sh/Makefile | 3 +-- drivers/sh/intc/Kconfig | 6 +++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index e15dff7..1e6c51c 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -75,6 +75,7 @@ config ARCH_SH7372 select ARM_CPU_SUSPEND if PM || CPU_IDLE select CPU_V7 select SH_CLK_CPG + select SH_INTC select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_TMU @@ -85,6 +86,7 @@ config ARCH_SH73A0 select CPU_V7 select I2C select SH_CLK_CPG + select SH_INTC select RENESAS_INTC_IRQPIN select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_TMU diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 453fa5c..b319846 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -172,6 +172,7 @@ menu "System type" # config CPU_SH2 bool + select SH_INTC config CPU_SH2A bool @@ -182,6 +183,7 @@ config CPU_SH3 bool select CPU_HAS_INTEVT select CPU_HAS_SR_RB + select SH_INTC select SYS_SUPPORTS_SH_TMU config CPU_SH4 @@ -189,6 +191,7 @@ config CPU_SH4 select CPU_HAS_INTEVT select CPU_HAS_SR_RB select CPU_HAS_FPU if !CPU_SH4AL_DSP + select SH_INTC select SYS_SUPPORTS_SH_TMU select SYS_SUPPORTS_HUGETLBFS if MMU diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index 788ed9b..114203f 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile @@ -1,8 +1,7 @@ # # Makefile for the SuperH specific drivers. # -obj-$(CONFIG_SUPERH) += intc/ -obj-$(CONFIG_ARCH_SHMOBILE_LEGACY) += intc/ +obj-$(CONFIG_SH_INTC) += intc/ ifneq ($(CONFIG_COMMON_CLK),y) obj-$(CONFIG_HAVE_CLK) += clk/ endif diff --git a/drivers/sh/intc/Kconfig b/drivers/sh/intc/Kconfig index 60228fa..6a1b05d 100644 --- a/drivers/sh/intc/Kconfig +++ b/drivers/sh/intc/Kconfig @@ -1,7 +1,9 @@ config SH_INTC - def_bool y + bool select IRQ_DOMAIN +if SH_INTC + comment "Interrupt controller options" config INTC_USERIMASK @@ -37,3 +39,5 @@ config INTC_MAPPING_DEBUG between system IRQs and the per-controller id tables. If in doubt, say N. + +endif -- cgit v1.1 From 061079ac0b9be7a578dcd09f7865c2c0d6ac894a Mon Sep 17 00:00:00 2001 From: zhuyj Date: Wed, 20 Aug 2014 17:31:43 +0800 Subject: sctp: not send SCTP_PEER_ADDR_CHANGE notifications with failed probe Since the transport has always been in state SCTP_UNCONFIRMED, it therefore wasn't active before and hasn't been used before, and it always has been, so it is unnecessary to bug the user with a notification. Reported-by: Deepak Khandelwal Suggested-by: Vlad Yasevich Suggested-by: Michael Tuexen Suggested-by: Daniel Borkmann Signed-off-by: Zhu Yanjun Acked-by: Vlad Yasevich Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/sctp/associola.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 06a9ee6..aaafb32 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -813,6 +813,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, else { dst_release(transport->dst); transport->dst = NULL; + ulp_notify = false; } spc_state = SCTP_ADDR_UNREACHABLE; -- cgit v1.1 From 29aaee65bc28cc75281dc9fe0998cc5e10ac37f9 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Wed, 20 Aug 2014 13:44:06 -0700 Subject: cxgb4: Fix race condition in cleanup There is a possible race condition when we unregister the PCI Driver and then flush/destroy the global "workq". This could lead to situations where there are tasks on the Work Queue with references to now deleted adapter data structures. Instead, have per-adapter Work Queues which were instantiated and torn down in init_one() and remove_one(), respectively. v2: Remove unnecessary call to flush_workqueue() before destroy_workqueue() Signed-off-by: Anish Bhatt Signed-off-by: Casey Leedom Acked-by: Neil Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 32 ++++++++++++++----------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index d572821..c067b78 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -652,6 +652,7 @@ struct adapter { struct tid_info tids; void **tid_release_head; spinlock_t tid_release_lock; + struct workqueue_struct *workq; struct work_struct tid_release_task; struct work_struct db_full_task; struct work_struct db_drop_task; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 1afee70..18fb9c6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -643,8 +643,6 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok) return ret; } -static struct workqueue_struct *workq; - /** * link_start - enable a port * @dev: the port to enable @@ -3340,7 +3338,7 @@ static void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan, adap->tid_release_head = (void **)((uintptr_t)p | chan); if (!adap->tid_release_task_busy) { adap->tid_release_task_busy = true; - queue_work(workq, &adap->tid_release_task); + queue_work(adap->workq, &adap->tid_release_task); } spin_unlock_bh(&adap->tid_release_lock); } @@ -4140,7 +4138,7 @@ void t4_db_full(struct adapter *adap) notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); t4_set_reg_field(adap, SGE_INT_ENABLE3, DBFIFO_HP_INT | DBFIFO_LP_INT, 0); - queue_work(workq, &adap->db_full_task); + queue_work(adap->workq, &adap->db_full_task); } } @@ -4150,7 +4148,7 @@ void t4_db_dropped(struct adapter *adap) disable_dbs(adap); notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL); } - queue_work(workq, &adap->db_drop_task); + queue_work(adap->workq, &adap->db_drop_task); } static void uld_attach(struct adapter *adap, unsigned int uld) @@ -6517,6 +6515,12 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_disable_device; } + adapter->workq = create_singlethread_workqueue("cxgb4"); + if (!adapter->workq) { + err = -ENOMEM; + goto out_free_adapter; + } + /* PCI device has been enabled */ adapter->flags |= DEV_ENABLED; @@ -6715,6 +6719,9 @@ sriov: out_unmap_bar0: iounmap(adapter->regs); out_free_adapter: + if (adapter->workq) + destroy_workqueue(adapter->workq); + kfree(adapter); out_disable_device: pci_disable_pcie_error_reporting(pdev); @@ -6736,6 +6743,11 @@ static void remove_one(struct pci_dev *pdev) if (adapter) { int i; + /* Tear down per-adapter Work Queue first since it can contain + * references to our adapter data structure. + */ + destroy_workqueue(adapter->workq); + if (is_offload(adapter)) detach_ulds(adapter); @@ -6788,20 +6800,14 @@ static int __init cxgb4_init_module(void) { int ret; - workq = create_singlethread_workqueue("cxgb4"); - if (!workq) - return -ENOMEM; - /* Debugfs support is optional, just warn if this fails */ cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); if (!cxgb4_debugfs_root) pr_warn("could not create debugfs entry, continuing\n"); ret = pci_register_driver(&cxgb4_driver); - if (ret < 0) { + if (ret < 0) debugfs_remove(cxgb4_debugfs_root); - destroy_workqueue(workq); - } register_inet6addr_notifier(&cxgb4_inet6addr_notifier); @@ -6813,8 +6819,6 @@ static void __exit cxgb4_cleanup_module(void) unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier); pci_unregister_driver(&cxgb4_driver); debugfs_remove(cxgb4_debugfs_root); /* NULL ok */ - flush_workqueue(workq); - destroy_workqueue(workq); } module_init(cxgb4_init_module); -- cgit v1.1 From 08f1a1b9d1a9902498f7c4bd93b14899dda18708 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 21 Aug 2014 17:04:46 +0530 Subject: cxgb4: Free completed tx skbs promptly Description of problem: The NIC card is not reporting back to the driver the transmitted skbs, so they get stuck in the TX ring causing issues with reference counters in other kernel components. Developed a new Automatic Egress Queue Update firmware facility to slowly tick through Egress Queues and send back any outstanding CIDX Updates which are laying around. Based on original work by Casey Leedom Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 3 ++- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 1 + drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index b0bba32..d22d728 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2303,7 +2303,8 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq, FW_EQ_ETH_CMD_PFN(adap->fn) | FW_EQ_ETH_CMD_VFN(0)); c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC | FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c)); - c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid)); + c.viid_pkd = htonl(FW_EQ_ETH_CMD_AUTOEQUEQE | + FW_EQ_ETH_CMD_VIID(pi->viid)); c.fetchszm_to_iqid = htonl(FW_EQ_ETH_CMD_HOSTFCMODE(2) | FW_EQ_ETH_CMD_PCIECHN(pi->tx_chan) | FW_EQ_ETH_CMD_FETCHRO(1) | diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 0549170..5f2729e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -1227,6 +1227,7 @@ struct fw_eq_eth_cmd { #define FW_EQ_ETH_CMD_CIDXFTHRESH(x) ((x) << 16) #define FW_EQ_ETH_CMD_EQSIZE(x) ((x) << 0) +#define FW_EQ_ETH_CMD_AUTOEQUEQE (1U << 30) #define FW_EQ_ETH_CMD_VIID(x) ((x) << 16) struct fw_eq_ctrl_cmd { diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index bdfa80c..a5fb949 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -2250,7 +2250,8 @@ int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq, cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC | FW_EQ_ETH_CMD_EQSTART | FW_LEN16(cmd)); - cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_VIID(pi->viid)); + cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_AUTOEQUEQE | + FW_EQ_ETH_CMD_VIID(pi->viid)); cmd.fetchszm_to_iqid = cpu_to_be32(FW_EQ_ETH_CMD_HOSTFCMODE(SGE_HOSTFCMODE_STPG) | FW_EQ_ETH_CMD_PCIECHN(pi->port_id) | -- cgit v1.1 From aee530cfecf4f3ec83b78406bac618cec35853f8 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 13 Aug 2014 11:21:34 -0700 Subject: firmware: Do not use WARN_ON(!spin_is_locked()) spin_is_locked() always returns false for uniprocessor configurations in several architectures, so do not use WARN_ON with it. Use lockdep_assert_held() instead to also reduce overhead in non-debug kernels. Signed-off-by: Guenter Roeck Cc: Signed-off-by: Matt Fleming --- drivers/firmware/efi/vars.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index f0a4364..5abe943 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -481,7 +481,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_remove); */ static void efivar_entry_list_del_unlock(struct efivar_entry *entry) { - WARN_ON(!spin_is_locked(&__efivars->lock)); + lockdep_assert_held(&__efivars->lock); list_del(&entry->list); spin_unlock_irq(&__efivars->lock); @@ -507,7 +507,7 @@ int __efivar_entry_delete(struct efivar_entry *entry) const struct efivar_operations *ops = __efivars->ops; efi_status_t status; - WARN_ON(!spin_is_locked(&__efivars->lock)); + lockdep_assert_held(&__efivars->lock); status = ops->set_variable(entry->var.VariableName, &entry->var.VendorGuid, @@ -667,7 +667,7 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, int strsize1, strsize2; bool found = false; - WARN_ON(!spin_is_locked(&__efivars->lock)); + lockdep_assert_held(&__efivars->lock); list_for_each_entry_safe(entry, n, head, list) { strsize1 = ucs2_strsize(name, 1024); @@ -739,7 +739,7 @@ int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes, const struct efivar_operations *ops = __efivars->ops; efi_status_t status; - WARN_ON(!spin_is_locked(&__efivars->lock)); + lockdep_assert_held(&__efivars->lock); status = ops->get_variable(entry->var.VariableName, &entry->var.VendorGuid, -- cgit v1.1 From 6a7519e81321343165f89abb8b616df186d3e57a Mon Sep 17 00:00:00 2001 From: Semen Protsenko Date: Fri, 15 Aug 2014 16:22:44 +0300 Subject: efi/arm64: Store Runtime Services revision "efi" global data structure contains "runtime_version" field which must be assigned in order to use it later in Runtime Services virtual calls (virt_efi_* functions). Before this patch "runtime_version" was unassigned (0), so each Runtime Service virtual call that checks revision would fail. Signed-off-by: Semen Protsenko Acked-by: Ard Biesheuvel Cc: Signed-off-by: Matt Fleming --- arch/arm64/kernel/efi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index e72f310..5dbb7bd 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -463,6 +463,8 @@ static int __init arm64_enter_virtual_mode(void) efi_native_runtime_setup(); set_bit(EFI_RUNTIME_SERVICES, &efi.flags); + efi.runtime_version = efi.systab->hdr.revision; + return 0; err_unmap: -- cgit v1.1 From 6dc14baf4ced769017c7a7045019c7a19f373865 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 21 Aug 2014 10:41:42 -0400 Subject: drm/radeon: add new KV pci id bug: https://bugs.freedesktop.org/show_bug.cgi?id=82912 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/cik.c | 1 + include/drm/drm_pciids.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index f4e1470..79a5a55 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -3544,6 +3544,7 @@ static void cik_gpu_init(struct radeon_device *rdev) (rdev->pdev->device == 0x130B) || (rdev->pdev->device == 0x130E) || (rdev->pdev->device == 0x1315) || + (rdev->pdev->device == 0x1318) || (rdev->pdev->device == 0x131B)) { rdev->config.cik.max_cu_per_sh = 4; rdev->config.cik.max_backends_per_se = 1; diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 6dfd64b..3a9281b 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -17,6 +17,7 @@ {0x1002, 0x1315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x1316, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x1317, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x1318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x131B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x131C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x131D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -- cgit v1.1 From 5fc540edc8ea1297c76685f74bc82a2107fe6731 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 21 Aug 2014 10:48:11 -0400 Subject: drm/radeon: add new bonaire pci ids Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- include/drm/drm_pciids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 3a9281b..b75b9a5 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -176,6 +176,8 @@ {0x1002, 0x6631, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \ -- cgit v1.1 From 37dbeab788a8f23fd946c0be083e5484d6f929a1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 21 Aug 2014 10:55:07 -0400 Subject: drm/radeon: add additional SI pci ids Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- include/drm/drm_pciids.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index b75b9a5..e973540 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -165,8 +165,11 @@ {0x1002, 0x6601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6602, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6603, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6604, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6605, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6606, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6607, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \ @@ -300,6 +303,7 @@ {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x682C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ -- cgit v1.1 From 33b7f99cf003ca6c1d31c42b50e1100ad71aaec0 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Fri, 15 Aug 2014 17:23:02 -0400 Subject: ftrace: Allow ftrace_ops to use the hashes from other ops Currently the top level debug file system function tracer shares its ftrace_ops with the function graph tracer. This was thought to be fine because the tracers are not used together, as one can only enable function or function_graph tracer in the current_tracer file. But that assumption proved to be incorrect. The function profiler can use the function graph tracer when function tracing is enabled. Since all function graph users uses the function tracing ftrace_ops this causes a conflict and when a user enables both function profiling as well as the function tracer it will crash ftrace and disable it. The quick solution so far is to move them as separate ftrace_ops like it was earlier. The problem though is to synchronize the functions that are traced because both function and function_graph tracer are limited by the selections made in the set_ftrace_filter and set_ftrace_notrace files. To handle this, a new structure is made called ftrace_ops_hash. This structure will now hold the filter_hash and notrace_hash, and the ftrace_ops will point to this structure. That will allow two ftrace_ops to share the same hashes. Since most ftrace_ops do not share the hashes, and to keep allocation simple, the ftrace_ops structure will include both a pointer to the ftrace_ops_hash called func_hash, as well as the structure itself, called local_hash. When the ops are registered, the func_hash pointer will be initialized to point to the local_hash within the ftrace_ops structure. Some of the ftrace internal ftrace_ops will be initialized statically. This will allow for the function and function_graph tracer to have separate ops but still share the same hash tables that determine what functions they trace. Cc: stable@vger.kernel.org # 3.16 (apply after 3.17-rc4 is out) Signed-off-by: Steven Rostedt --- include/linux/ftrace.h | 14 +++++-- kernel/trace/ftrace.c | 100 +++++++++++++++++++++++++------------------------ 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 6bb5e3f..f0b0edb 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -102,6 +102,15 @@ enum { FTRACE_OPS_FL_DELETED = 1 << 8, }; +#ifdef CONFIG_DYNAMIC_FTRACE +/* The hash used to know what functions callbacks trace */ +struct ftrace_ops_hash { + struct ftrace_hash *notrace_hash; + struct ftrace_hash *filter_hash; + struct mutex regex_lock; +}; +#endif + /* * Note, ftrace_ops can be referenced outside of RCU protection. * (Although, for perf, the control ops prevent that). If ftrace_ops is @@ -121,10 +130,9 @@ struct ftrace_ops { int __percpu *disabled; #ifdef CONFIG_DYNAMIC_FTRACE int nr_trampolines; - struct ftrace_hash *notrace_hash; - struct ftrace_hash *filter_hash; + struct ftrace_ops_hash local_hash; + struct ftrace_ops_hash *func_hash; struct ftrace_hash *tramp_hash; - struct mutex regex_lock; unsigned long trampoline; #endif }; diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 1654b12..c92757a 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -65,15 +65,17 @@ #define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_CONTROL) #ifdef CONFIG_DYNAMIC_FTRACE -#define INIT_REGEX_LOCK(opsname) \ - .regex_lock = __MUTEX_INITIALIZER(opsname.regex_lock), +#define INIT_OPS_HASH(opsname) \ + .func_hash = &opsname.local_hash, \ + .local_hash.regex_lock = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock), #else -#define INIT_REGEX_LOCK(opsname) +#define INIT_OPS_HASH(opsname) #endif static struct ftrace_ops ftrace_list_end __read_mostly = { .func = ftrace_stub, .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_STUB, + INIT_OPS_HASH(ftrace_list_end) }; /* ftrace_enabled is a method to turn ftrace on or off */ @@ -140,7 +142,8 @@ static inline void ftrace_ops_init(struct ftrace_ops *ops) { #ifdef CONFIG_DYNAMIC_FTRACE if (!(ops->flags & FTRACE_OPS_FL_INITIALIZED)) { - mutex_init(&ops->regex_lock); + mutex_init(&ops->local_hash.regex_lock); + ops->func_hash = &ops->local_hash; ops->flags |= FTRACE_OPS_FL_INITIALIZED; } #endif @@ -899,7 +902,7 @@ static void unregister_ftrace_profiler(void) static struct ftrace_ops ftrace_profile_ops __read_mostly = { .func = function_profile_call, .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED, - INIT_REGEX_LOCK(ftrace_profile_ops) + INIT_OPS_HASH(ftrace_profile_ops) }; static int register_ftrace_profiler(void) @@ -1081,11 +1084,12 @@ static const struct ftrace_hash empty_hash = { #define EMPTY_HASH ((struct ftrace_hash *)&empty_hash) static struct ftrace_ops global_ops = { - .func = ftrace_stub, - .notrace_hash = EMPTY_HASH, - .filter_hash = EMPTY_HASH, - .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED, - INIT_REGEX_LOCK(global_ops) + .func = ftrace_stub, + .local_hash.notrace_hash = EMPTY_HASH, + .local_hash.filter_hash = EMPTY_HASH, + INIT_OPS_HASH(global_ops) + .flags = FTRACE_OPS_FL_RECURSION_SAFE | + FTRACE_OPS_FL_INITIALIZED, }; struct ftrace_page { @@ -1226,8 +1230,8 @@ static void free_ftrace_hash_rcu(struct ftrace_hash *hash) void ftrace_free_filter(struct ftrace_ops *ops) { ftrace_ops_init(ops); - free_ftrace_hash(ops->filter_hash); - free_ftrace_hash(ops->notrace_hash); + free_ftrace_hash(ops->func_hash->filter_hash); + free_ftrace_hash(ops->func_hash->notrace_hash); } static struct ftrace_hash *alloc_ftrace_hash(int size_bits) @@ -1382,8 +1386,8 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs) return 0; #endif - filter_hash = rcu_dereference_raw_notrace(ops->filter_hash); - notrace_hash = rcu_dereference_raw_notrace(ops->notrace_hash); + filter_hash = rcu_dereference_raw_notrace(ops->func_hash->filter_hash); + notrace_hash = rcu_dereference_raw_notrace(ops->func_hash->notrace_hash); if ((ftrace_hash_empty(filter_hash) || ftrace_lookup_ip(filter_hash, ip)) && @@ -1554,14 +1558,14 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, * gets inversed. */ if (filter_hash) { - hash = ops->filter_hash; - other_hash = ops->notrace_hash; + hash = ops->func_hash->filter_hash; + other_hash = ops->func_hash->notrace_hash; if (ftrace_hash_empty(hash)) all = 1; } else { inc = !inc; - hash = ops->notrace_hash; - other_hash = ops->filter_hash; + hash = ops->func_hash->notrace_hash; + other_hash = ops->func_hash->filter_hash; /* * If the notrace hash has no items, * then there's nothing to do. @@ -2436,8 +2440,8 @@ static inline int ops_traces_mod(struct ftrace_ops *ops) * Filter_hash being empty will default to trace module. * But notrace hash requires a test of individual module functions. */ - return ftrace_hash_empty(ops->filter_hash) && - ftrace_hash_empty(ops->notrace_hash); + return ftrace_hash_empty(ops->func_hash->filter_hash) && + ftrace_hash_empty(ops->func_hash->notrace_hash); } /* @@ -2459,12 +2463,12 @@ ops_references_rec(struct ftrace_ops *ops, struct dyn_ftrace *rec) return 0; /* The function must be in the filter */ - if (!ftrace_hash_empty(ops->filter_hash) && - !ftrace_lookup_ip(ops->filter_hash, rec->ip)) + if (!ftrace_hash_empty(ops->func_hash->filter_hash) && + !ftrace_lookup_ip(ops->func_hash->filter_hash, rec->ip)) return 0; /* If in notrace hash, we ignore it too */ - if (ftrace_lookup_ip(ops->notrace_hash, rec->ip)) + if (ftrace_lookup_ip(ops->func_hash->notrace_hash, rec->ip)) return 0; return 1; @@ -2785,10 +2789,10 @@ t_next(struct seq_file *m, void *v, loff_t *pos) } else { rec = &iter->pg->records[iter->idx++]; if (((iter->flags & FTRACE_ITER_FILTER) && - !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) || + !(ftrace_lookup_ip(ops->func_hash->filter_hash, rec->ip))) || ((iter->flags & FTRACE_ITER_NOTRACE) && - !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) || + !ftrace_lookup_ip(ops->func_hash->notrace_hash, rec->ip)) || ((iter->flags & FTRACE_ITER_ENABLED) && !(rec->flags & FTRACE_FL_ENABLED))) { @@ -2837,9 +2841,9 @@ static void *t_start(struct seq_file *m, loff_t *pos) * functions are enabled. */ if ((iter->flags & FTRACE_ITER_FILTER && - ftrace_hash_empty(ops->filter_hash)) || + ftrace_hash_empty(ops->func_hash->filter_hash)) || (iter->flags & FTRACE_ITER_NOTRACE && - ftrace_hash_empty(ops->notrace_hash))) { + ftrace_hash_empty(ops->func_hash->notrace_hash))) { if (*pos > 0) return t_hash_start(m, pos); iter->flags |= FTRACE_ITER_PRINTALL; @@ -3001,12 +3005,12 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag, iter->ops = ops; iter->flags = flag; - mutex_lock(&ops->regex_lock); + mutex_lock(&ops->func_hash->regex_lock); if (flag & FTRACE_ITER_NOTRACE) - hash = ops->notrace_hash; + hash = ops->func_hash->notrace_hash; else - hash = ops->filter_hash; + hash = ops->func_hash->filter_hash; if (file->f_mode & FMODE_WRITE) { const int size_bits = FTRACE_HASH_DEFAULT_BITS; @@ -3041,7 +3045,7 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag, file->private_data = iter; out_unlock: - mutex_unlock(&ops->regex_lock); + mutex_unlock(&ops->func_hash->regex_lock); return ret; } @@ -3279,7 +3283,7 @@ static struct ftrace_ops trace_probe_ops __read_mostly = { .func = function_trace_probe_call, .flags = FTRACE_OPS_FL_INITIALIZED, - INIT_REGEX_LOCK(trace_probe_ops) + INIT_OPS_HASH(trace_probe_ops) }; static int ftrace_probe_registered; @@ -3342,7 +3346,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, void *data) { struct ftrace_func_probe *entry; - struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash; + struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash; struct ftrace_hash *hash; struct ftrace_page *pg; struct dyn_ftrace *rec; @@ -3359,7 +3363,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, if (WARN_ON(not)) return -EINVAL; - mutex_lock(&trace_probe_ops.regex_lock); + mutex_lock(&trace_probe_ops.func_hash->regex_lock); hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); if (!hash) { @@ -3428,7 +3432,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, out_unlock: mutex_unlock(&ftrace_lock); out: - mutex_unlock(&trace_probe_ops.regex_lock); + mutex_unlock(&trace_probe_ops.func_hash->regex_lock); free_ftrace_hash(hash); return count; @@ -3446,7 +3450,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, struct ftrace_func_entry *rec_entry; struct ftrace_func_probe *entry; struct ftrace_func_probe *p; - struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash; + struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash; struct list_head free_list; struct ftrace_hash *hash; struct hlist_node *tmp; @@ -3468,7 +3472,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, return; } - mutex_lock(&trace_probe_ops.regex_lock); + mutex_lock(&trace_probe_ops.func_hash->regex_lock); hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash); if (!hash) @@ -3521,7 +3525,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, mutex_unlock(&ftrace_lock); out_unlock: - mutex_unlock(&trace_probe_ops.regex_lock); + mutex_unlock(&trace_probe_ops.func_hash->regex_lock); free_ftrace_hash(hash); } @@ -3717,12 +3721,12 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, if (unlikely(ftrace_disabled)) return -ENODEV; - mutex_lock(&ops->regex_lock); + mutex_lock(&ops->func_hash->regex_lock); if (enable) - orig_hash = &ops->filter_hash; + orig_hash = &ops->func_hash->filter_hash; else - orig_hash = &ops->notrace_hash; + orig_hash = &ops->func_hash->notrace_hash; if (reset) hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS); @@ -3752,7 +3756,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len, mutex_unlock(&ftrace_lock); out_regex_unlock: - mutex_unlock(&ops->regex_lock); + mutex_unlock(&ops->func_hash->regex_lock); free_ftrace_hash(hash); return ret; @@ -3975,15 +3979,15 @@ int ftrace_regex_release(struct inode *inode, struct file *file) trace_parser_put(parser); - mutex_lock(&iter->ops->regex_lock); + mutex_lock(&iter->ops->func_hash->regex_lock); if (file->f_mode & FMODE_WRITE) { filter_hash = !!(iter->flags & FTRACE_ITER_FILTER); if (filter_hash) - orig_hash = &iter->ops->filter_hash; + orig_hash = &iter->ops->func_hash->filter_hash; else - orig_hash = &iter->ops->notrace_hash; + orig_hash = &iter->ops->func_hash->notrace_hash; mutex_lock(&ftrace_lock); ret = ftrace_hash_move(iter->ops, filter_hash, @@ -3994,7 +3998,7 @@ int ftrace_regex_release(struct inode *inode, struct file *file) mutex_unlock(&ftrace_lock); } - mutex_unlock(&iter->ops->regex_lock); + mutex_unlock(&iter->ops->func_hash->regex_lock); free_ftrace_hash(iter->hash); kfree(iter); @@ -4611,7 +4615,7 @@ void __init ftrace_init(void) static struct ftrace_ops global_ops = { .func = ftrace_stub, .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED, - INIT_REGEX_LOCK(global_ops) + INIT_OPS_HASH(global_ops) }; static int __init ftrace_nodyn_init(void) @@ -4713,7 +4717,7 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip, static struct ftrace_ops control_ops = { .func = ftrace_ops_control_func, .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED, - INIT_REGEX_LOCK(control_ops) + INIT_OPS_HASH(control_ops) }; static inline void -- cgit v1.1 From 84261912ebee41269004e8a9f3614ba38ef6b206 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Mon, 18 Aug 2014 13:21:08 -0400 Subject: ftrace: Update all ftrace_ops for a ftrace_hash_ops update When updating what an ftrace_ops traces, if it is registered (that is, actively tracing), and that ftrace_ops uses the shared global_ops local_hash, then we need to update all tracers that are active and also share the global_ops' ftrace_hash_ops. Cc: stable@vger.kernel.org # 3.16 (apply after 3.17-rc4 is out) Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index c92757a..37f9e90 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1292,9 +1292,9 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash) } static void -ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash); +ftrace_hash_rec_disable_modify(struct ftrace_ops *ops, int filter_hash); static void -ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash); +ftrace_hash_rec_enable_modify(struct ftrace_ops *ops, int filter_hash); static int ftrace_hash_move(struct ftrace_ops *ops, int enable, @@ -1346,13 +1346,13 @@ update: * Remove the current set, update the hash and add * them back. */ - ftrace_hash_rec_disable(ops, enable); + ftrace_hash_rec_disable_modify(ops, enable); old_hash = *dst; rcu_assign_pointer(*dst, new_hash); free_ftrace_hash_rcu(old_hash); - ftrace_hash_rec_enable(ops, enable); + ftrace_hash_rec_enable_modify(ops, enable); return 0; } @@ -1686,6 +1686,41 @@ static void ftrace_hash_rec_enable(struct ftrace_ops *ops, __ftrace_hash_rec_update(ops, filter_hash, 1); } +static void ftrace_hash_rec_update_modify(struct ftrace_ops *ops, + int filter_hash, int inc) +{ + struct ftrace_ops *op; + + __ftrace_hash_rec_update(ops, filter_hash, inc); + + if (ops->func_hash != &global_ops.local_hash) + return; + + /* + * If the ops shares the global_ops hash, then we need to update + * all ops that are enabled and use this hash. + */ + do_for_each_ftrace_op(op, ftrace_ops_list) { + /* Already done */ + if (op == ops) + continue; + if (op->func_hash == &global_ops.local_hash) + __ftrace_hash_rec_update(op, filter_hash, inc); + } while_for_each_ftrace_op(op); +} + +static void ftrace_hash_rec_disable_modify(struct ftrace_ops *ops, + int filter_hash) +{ + ftrace_hash_rec_update_modify(ops, filter_hash, 0); +} + +static void ftrace_hash_rec_enable_modify(struct ftrace_ops *ops, + int filter_hash) +{ + ftrace_hash_rec_update_modify(ops, filter_hash, 1); +} + static void print_ip_ins(const char *fmt, unsigned char *p) { int i; -- cgit v1.1 From 91c0d987a9788dcc5fe26baafd73bf9242b68900 Mon Sep 17 00:00:00 2001 From: Nimrod Andy Date: Thu, 21 Aug 2014 17:09:38 +0800 Subject: net: fec: ptp: avoid register access when ipg clock is disabled The current kernel hang on i.MX6SX with rootfs mount from MMC. The root cause is that ptp uses a periodic timer to access enet register even if ipg clock is disabled. FEC ptp driver start one period timer to read 1588 counter register in the ptp init function that is called after FEC driver is probed. To save power, after FEC probe finish, FEC driver disable all clocks including ipg clock that is needed for register access. i.MX5x, i.MX6q/dl/sl FEC register access don't cause system hang when ipg clock is disabled, just return zero value. But for i.MX6sx SOC, it cause system hang. To avoid the issue, we need to check ptp clock status before ptp timer count access. Signed-off-by: Fugang Duan Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec.h | 5 ++++- drivers/net/ethernet/freescale/fec_main.c | 18 ++++++++++++++--- drivers/net/ethernet/freescale/fec_ptp.c | 33 ++++++++++++++++++++----------- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 9f7fa64..ee41d98 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -275,6 +275,9 @@ struct fec_enet_private { struct clk *clk_enet_out; struct clk *clk_ptp; + bool ptp_clk_on; + struct mutex ptp_clk_mutex; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ unsigned char *tx_bounce[TX_RING_SIZE]; struct sk_buff *tx_skbuff[TX_RING_SIZE]; @@ -335,7 +338,7 @@ struct fec_enet_private { u32 cycle_speed; int hwts_rx_en; int hwts_tx_en; - struct timer_list time_keep; + struct delayed_work time_keep; struct regulator *reg_phy; }; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 4f87dff..89355a7 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1611,17 +1611,27 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable) goto failed_clk_enet_out; } if (fep->clk_ptp) { + mutex_lock(&fep->ptp_clk_mutex); ret = clk_prepare_enable(fep->clk_ptp); - if (ret) + if (ret) { + mutex_unlock(&fep->ptp_clk_mutex); goto failed_clk_ptp; + } else { + fep->ptp_clk_on = true; + } + mutex_unlock(&fep->ptp_clk_mutex); } } else { clk_disable_unprepare(fep->clk_ahb); clk_disable_unprepare(fep->clk_ipg); if (fep->clk_enet_out) clk_disable_unprepare(fep->clk_enet_out); - if (fep->clk_ptp) + if (fep->clk_ptp) { + mutex_lock(&fep->ptp_clk_mutex); clk_disable_unprepare(fep->clk_ptp); + fep->ptp_clk_on = false; + mutex_unlock(&fep->ptp_clk_mutex); + } } return 0; @@ -2625,6 +2635,8 @@ fec_probe(struct platform_device *pdev) if (IS_ERR(fep->clk_enet_out)) fep->clk_enet_out = NULL; + fep->ptp_clk_on = false; + mutex_init(&fep->ptp_clk_mutex); fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp"); fep->bufdesc_ex = pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX; @@ -2715,10 +2727,10 @@ fec_drv_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(ndev); + cancel_delayed_work_sync(&fep->time_keep); cancel_work_sync(&fep->tx_timeout_work); unregister_netdev(ndev); fec_enet_mii_remove(fep); - del_timer_sync(&fep->time_keep); if (fep->reg_phy) regulator_disable(fep->reg_phy); if (fep->ptp_clock) diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 82386b2..cca3617 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -245,12 +245,20 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp, u64 ns; unsigned long flags; + mutex_lock(&fep->ptp_clk_mutex); + /* Check the ptp clock */ + if (!fep->ptp_clk_on) { + mutex_unlock(&fep->ptp_clk_mutex); + return -EINVAL; + } + ns = ts->tv_sec * 1000000000ULL; ns += ts->tv_nsec; spin_lock_irqsave(&fep->tmreg_lock, flags); timecounter_init(&fep->tc, &fep->cc, ns); spin_unlock_irqrestore(&fep->tmreg_lock, flags); + mutex_unlock(&fep->ptp_clk_mutex); return 0; } @@ -338,17 +346,22 @@ int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr) * fec_time_keep - call timecounter_read every second to avoid timer overrun * because ENET just support 32bit counter, will timeout in 4s */ -static void fec_time_keep(unsigned long _data) +static void fec_time_keep(struct work_struct *work) { - struct fec_enet_private *fep = (struct fec_enet_private *)_data; + struct delayed_work *dwork = to_delayed_work(work); + struct fec_enet_private *fep = container_of(dwork, struct fec_enet_private, time_keep); u64 ns; unsigned long flags; - spin_lock_irqsave(&fep->tmreg_lock, flags); - ns = timecounter_read(&fep->tc); - spin_unlock_irqrestore(&fep->tmreg_lock, flags); + mutex_lock(&fep->ptp_clk_mutex); + if (fep->ptp_clk_on) { + spin_lock_irqsave(&fep->tmreg_lock, flags); + ns = timecounter_read(&fep->tc); + spin_unlock_irqrestore(&fep->tmreg_lock, flags); + } + mutex_unlock(&fep->ptp_clk_mutex); - mod_timer(&fep->time_keep, jiffies + HZ); + schedule_delayed_work(&fep->time_keep, HZ); } /** @@ -386,15 +399,13 @@ void fec_ptp_init(struct platform_device *pdev) fec_ptp_start_cyclecounter(ndev); - init_timer(&fep->time_keep); - fep->time_keep.data = (unsigned long)fep; - fep->time_keep.function = fec_time_keep; - fep->time_keep.expires = jiffies + HZ; - add_timer(&fep->time_keep); + INIT_DELAYED_WORK(&fep->time_keep, fec_time_keep); fep->ptp_clock = ptp_clock_register(&fep->ptp_caps, &pdev->dev); if (IS_ERR(fep->ptp_clock)) { fep->ptp_clock = NULL; pr_err("ptp_clock_register failed\n"); } + + schedule_delayed_work(&fep->time_keep, HZ); } -- cgit v1.1 From 793c3b4000a1ef611ae7e5c89bd2a9c6b776cb5e Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Thu, 21 Aug 2014 19:37:48 +0200 Subject: net: ipv6: fib: don't sleep inside atomic lock The function fib6_commit_metrics() allocates a piece of memory in mode GFP_KERNEL while holding an atomic lock from higher up in the stack, in the function __ip6_ins_rt(). This produces the following BUG: > BUG: sleeping function called from invalid context at mm/slub.c:1250 > in_atomic(): 1, irqs_disabled(): 0, pid: 2909, name: dhcpcd > 2 locks held by dhcpcd/2909: > #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x17/0x20 > #1: (&tb->tb6_lock){++--+.}, at: [] ip6_route_add+0x65a/0x800 > CPU: 1 PID: 2909 Comm: dhcpcd Not tainted 3.17.0-rc1 #1 > Hardware name: ASUS All Series/Q87T, BIOS 0216 10/16/2013 > 0000000000000008 ffff8800c8f13858 ffffffff81af135a 0000000000000000 > ffff880212202430 ffff8800c8f13878 ffffffff810f8d3a ffff880212202c98 > 0000000000000010 ffff8800c8f138c8 ffffffff8121ad0e 0000000000000001 > Call Trace: > [] dump_stack+0x4e/0x68 > [] __might_sleep+0x10a/0x120 > [] kmem_cache_alloc_trace+0x4e/0x190 > [] ? fib6_commit_metrics+0x66/0x110 > [] fib6_commit_metrics+0x66/0x110 > [] fib6_add+0x883/0xa80 > [] ? ip6_route_add+0x65a/0x800 > [] ip6_route_add+0x675/0x800 > [] ? ip6_route_add+0x6a/0x800 > [] inet6_rtm_newroute+0x5c/0x80 > [] rtnetlink_rcv_msg+0x211/0x260 > [] ? rtnl_lock+0x17/0x20 > [] ? lock_release_holdtime+0x28/0x180 > [] ? rtnl_lock+0x17/0x20 > [] ? __rtnl_unlock+0x20/0x20 > [] netlink_rcv_skb+0x6e/0xd0 > [] rtnetlink_rcv+0x25/0x40 > [] netlink_unicast+0xd9/0x180 > [] netlink_sendmsg+0x700/0x770 > [] ? local_clock+0x25/0x30 > [] sock_sendmsg+0x6c/0x90 > [] ? might_fault+0xa3/0xb0 > [] ? verify_iovec+0x7d/0xf0 > [] ___sys_sendmsg+0x37e/0x3b0 > [] ? trace_hardirqs_on_caller+0x185/0x220 > [] ? mutex_unlock+0xe/0x10 > [] ? netlink_insert+0xbc/0xe0 > [] ? netlink_autobind.isra.30+0x125/0x150 > [] ? netlink_autobind.isra.30+0x60/0x150 > [] ? netlink_bind+0x159/0x230 > [] ? might_fault+0x5a/0xb0 > [] ? SYSC_bind+0x7e/0xd0 > [] __sys_sendmsg+0x4d/0x80 > [] SyS_sendmsg+0x12/0x20 > [] system_call_fastpath+0x16/0x1b Fixing this by replacing the mode GFP_KERNEL with GFP_ATOMIC. Signed-off-by: Benjamin Block Acked-by: David Rientjes Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index cb4459b..76b7f5e 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -643,7 +643,7 @@ static int fib6_commit_metrics(struct dst_entry *dst, if (dst->flags & DST_HOST) { mp = dst_metrics_write_ptr(dst); } else { - mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL); + mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC); if (!mp) return -ENOMEM; dst_init_metrics(dst, mp, 0); -- cgit v1.1 From 2ba5af42a7b59ef01f9081234d8855140738defd Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 21 Aug 2014 21:33:44 +0200 Subject: openvswitch: fix panic with multiple vlan headers When there are multiple vlan headers present in a received frame, the first one is put into vlan_tci and protocol is set to ETH_P_8021Q. Anything in the skb beyond the VLAN TPID may be still non-linear, including the inner TCI and ethertype. While ovs_flow_extract takes care of IP and IPv6 headers, it does nothing with ETH_P_8021Q. Later, if OVS_ACTION_ATTR_POP_VLAN is executed, __pop_vlan_tci pulls the next vlan header into vlan_tci. This leads to two things: 1. Part of the resulting ethernet header is in the non-linear part of the skb. When eth_type_trans is called later as the result of OVS_ACTION_ATTR_OUTPUT, kernel BUGs in __skb_pull. Also, __pop_vlan_tci is in fact accessing random data when it reads past the TPID. 2. network_header points into the ethernet header instead of behind it. mac_len is set to a wrong value (10), too. Reported-by: Yulong Pei Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- net/openvswitch/actions.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index fe5cda0..5231652 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -42,6 +42,9 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, static int make_writable(struct sk_buff *skb, int write_len) { + if (!pskb_may_pull(skb, write_len)) + return -ENOMEM; + if (!skb_cloned(skb) || skb_clone_writable(skb, write_len)) return 0; @@ -70,6 +73,8 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci) vlan_set_encap_proto(skb, vhdr); skb->mac_header += VLAN_HLEN; + if (skb_network_offset(skb) < ETH_HLEN) + skb_set_network_header(skb, ETH_HLEN); skb_reset_mac_len(skb); return 0; -- cgit v1.1 From c10e4cafa2698dedb9b61bbf6d68f209e779cb19 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Thu, 21 Aug 2014 13:44:48 -0700 Subject: net: xgene: fix possible NULL dereference in xgene_enet_free_desc_rings() A NULL pointer dereference is possible for the argument ring->buf_pool which is passed to xgene_enet_free_desc_ring(), as ring could be NULL. And now since NULL pointers are being checked for before the calls to xgene_enet_free_desc_ring(), might as well take advantage of them and not call the function if the argument would be NULL. Reported-by: Dan Carpenter Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index e1a8f4e..e4222af 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -563,15 +563,21 @@ static void xgene_enet_free_desc_rings(struct xgene_enet_pdata *pdata) struct xgene_enet_desc_ring *ring; ring = pdata->tx_ring; - if (ring && ring->cp_ring && ring->cp_ring->cp_skb) - devm_kfree(dev, ring->cp_ring->cp_skb); - xgene_enet_free_desc_ring(ring); + if (ring) { + if (ring->cp_ring && ring->cp_ring->cp_skb) + devm_kfree(dev, ring->cp_ring->cp_skb); + xgene_enet_free_desc_ring(ring); + } ring = pdata->rx_ring; - if (ring && ring->buf_pool && ring->buf_pool->rx_skb) - devm_kfree(dev, ring->buf_pool->rx_skb); - xgene_enet_free_desc_ring(ring->buf_pool); - xgene_enet_free_desc_ring(ring); + if (ring) { + if (ring->buf_pool) { + if (ring->buf_pool->rx_skb) + devm_kfree(dev, ring->buf_pool->rx_skb); + xgene_enet_free_desc_ring(ring->buf_pool); + } + xgene_enet_free_desc_ring(ring); + } } static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring( -- cgit v1.1 From cbd5228199d8be45d895d9d0cc2b8ce53835fc21 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Fri, 22 Aug 2014 11:36:52 +1000 Subject: ibmveth: Fix endian issues with rx_no_buffer statistic Hidden away in the last 8 bytes of the buffer_list page is a solitary statistic. It needs to be byte swapped or else ethtool -S will produce numbers that terrify the user. Since we do this in multiple places, create a helper function with a comment explaining what is going on. Signed-off-by: Anton Blanchard Cc: stable@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmveth.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index c912756..21978cc 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -292,6 +292,18 @@ failure: atomic_add(buffers_added, &(pool->available)); } +/* + * The final 8 bytes of the buffer list is a counter of frames dropped + * because there was not a buffer in the buffer list capable of holding + * the frame. + */ +static void ibmveth_update_rx_no_buffer(struct ibmveth_adapter *adapter) +{ + __be64 *p = adapter->buffer_list_addr + 4096 - 8; + + adapter->rx_no_buffer = be64_to_cpup(p); +} + /* replenish routine */ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) { @@ -307,8 +319,7 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) ibmveth_replenish_buffer_pool(adapter, pool); } - adapter->rx_no_buffer = *(u64 *)(((char*)adapter->buffer_list_addr) + - 4096 - 8); + ibmveth_update_rx_no_buffer(adapter); } /* empty and free ana buffer pool - also used to do cleanup in error paths */ @@ -698,8 +709,7 @@ static int ibmveth_close(struct net_device *netdev) free_irq(netdev->irq, netdev); - adapter->rx_no_buffer = *(u64 *)(((char *)adapter->buffer_list_addr) + - 4096 - 8); + ibmveth_update_rx_no_buffer(adapter); ibmveth_cleanup(adapter); -- cgit v1.1 From 7d149c5268d78d740cfdb20834328975251e7388 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 20 Aug 2014 15:14:49 +0200 Subject: net: ethernet: broadcom: bnx2x: Remove redundant #ifdef Nothing defines _ASM_GENERIC_INT_L64_H, it is a weird way to check for 64 bit longs, and u64 should be printed using %llx anyway. Signed-off-by: Rasmus Villemoes Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 4e6c82e..4ccc806 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -483,11 +483,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue, #ifdef BNX2X_STOP_ON_ERROR fp->tpa_queue_used |= (1 << queue); -#ifdef _ASM_GENERIC_INT_L64_H - DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n", -#else DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n", -#endif fp->tpa_queue_used); #endif } -- cgit v1.1 From ea4f19c1f81d4bf709c74e3789ec785828bc6e51 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 22 Aug 2014 13:03:29 +0200 Subject: net: sctp: spare unnecessary comparison in sctp_trans_elect_best When both transports are the same, we don't have to go down that road only to realize that we will return the very same transport. We are guaranteed that curr is always non-NULL. Therefore, just short-circuit this special case. Signed-off-by: Daniel Borkmann Acked-by: Neil Horman Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/associola.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index aaafb32..104fae4 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1245,7 +1245,7 @@ static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr, { u8 score_curr, score_best; - if (best == NULL) + if (best == NULL || curr == best) return curr; score_curr = sctp_trans_score(curr); -- cgit v1.1 From aa4a83ee8bbc08342c4acfd59ef234cac51a1eef Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 22 Aug 2014 13:03:30 +0200 Subject: net: sctp: fix suboptimal edge-case on non-active active/retrans path selection In SCTP, selection of active (T.ACT) and retransmission (T.RET) transports is being done whenever transport control operations (UP, DOWN, PF, ...) are engaged through sctp_assoc_control_transport(). Commits 4c47af4d5eb2 ("net: sctp: rework multihoming retransmission path selection to rfc4960") and a7288c4dd509 ("net: sctp: improve sctp_select_active_and_retran_path selection") have both improved it towards a more fine-grained and optimal path selection. Currently, the selection algorithm for T.ACT and T.RET is as follows: 1) Elect the two most recently used ACTIVE transports T1, T2 for T.ACT, T.RET, where T.ACT<-T1 and T1 is most recently used 2) In case primary path T.PRI not in {T1, T2} but ACTIVE, set T.ACT<-T.PRI and T.RET<-T1 3) If only T1 is ACTIVE from the set, set T.ACT<-T1 and T.RET<-T1 4) If none is ACTIVE, set T.ACT<-best(T.PRI, T.RET, T3) where T3 is the most recently used (if avail) in PF, set T.RET<-T.PRI Prior to above commits, 4) was simply a camp on T.ACT<-T.PRI and T.RET<-T.PRI, ignoring possible paths in PF. Camping on T.PRI is still slightly suboptimal as it can lead to the following scenario: Setup: T1: p1p1 (10.0.10.10) <==> .'`) <==> p1p1 (10.0.10.12) <= T.PRI T2: p1p2 (10.0.10.20) <==> (_ . ) <==> p1p2 (10.0.10.22) net.sctp.rto_min = 1000 net.sctp.path_max_retrans = 2 net.sctp.pf_retrans = 0 net.sctp.hb_interval = 1000 T.PRI is permanently down, T2 is put briefly into PF state (e.g. due to link flapping). Here, the first time transmission is sent over PF path T2 as it's the only non-INACTIVE path, but the retransmitted data-chunks are sent over the INACTIVE path T1 (T.PRI), which is not good. After the patch, it's choosing better transports in both cases by modifying step 4): 4) If none is ACTIVE, set T.ACT_new<-best(T.ACT_old, T3) where T3 is the most recently used (if avail) in PF, set T.RET<-T.ACT_new This will still select a best possible path in PF if available (which can also include T.PRI/T.RET), and set both T.ACT/T.RET to it. In case sctp_assoc_control_transport() *just* put T.ACT_old into INACTIVE as it transitioned from ACTIVE->PF->INACTIVE and stays in INACTIVE just for a very short while before going back ACTIVE, it will guarantee that this path will be reselected for T.ACT/T.RET since T3 (PF) is not available. Previously, this was not possible, as we would only select between T.PRI and T.RET, and a possible T3 would be NULL due to the fact that we have just transitioned T3 in sctp_assoc_control_transport() from PF->INACTIVE and would select a suboptimal path when T.PRI/T.RET have worse properties. In the case that T.ACT_old permanently went to INACTIVE during this transition and there's no PF path available, plus T.PRI and T.RET are INACTIVE as well, we would now camp on T.ACT_old, but if everything is being INACTIVE there's really not much we can do except hoping for a successful HB to bring one of the transports back up again and, thus cause a new selection through sctp_assoc_control_transport(). Now both tests work fine: Case 1: 1. T1 S(ACTIVE) T.ACT T2 S(ACTIVE) T.RET 2. T1 S(ACTIVE) T.ACT, T.RET T2 S(PF) 3. T1 S(ACTIVE) T.ACT, T.RET T2 S(INACTIVE) 5. T1 S(PF) T.ACT, T.RET T2 S(INACTIVE) [ 5.1 T1 S(INACTIVE) T.ACT, T.RET T2 S(INACTIVE) ] 6. T1 S(ACTIVE) T.ACT, T.RET T2 S(INACTIVE) 7. T1 S(ACTIVE) T.ACT T2 S(ACTIVE) T.RET Case 2: 1. T1 S(ACTIVE) T.ACT T2 S(ACTIVE) T.RET 2. T1 S(PF) T2 S(ACTIVE) T.ACT, T.RET 3. T1 S(INACTIVE) T2 S(ACTIVE) T.ACT, T.RET 5. T1 S(INACTIVE) T2 S(PF) T.ACT, T.RET [ 5.1 T1 S(INACTIVE) T2 S(INACTIVE) T.ACT, T.RET ] 6. T1 S(INACTIVE) T2 S(ACTIVE) T.ACT, T.RET 7. T1 S(ACTIVE) T.ACT T2 S(ACTIVE) T.RET Signed-off-by: Daniel Borkmann Acked-by: Neil Horman Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/associola.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 104fae4..a88b852 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1356,14 +1356,11 @@ static void sctp_select_active_and_retran_path(struct sctp_association *asoc) trans_sec = trans_pri; /* If we failed to find a usable transport, just camp on the - * primary or retran, even if they are inactive, if possible - * pick a PF iff it's the better choice. + * active or pick a PF iff it's the better choice. */ if (trans_pri == NULL) { - trans_pri = sctp_trans_elect_best(asoc->peer.primary_path, - asoc->peer.retran_path); - trans_pri = sctp_trans_elect_best(trans_pri, trans_pf); - trans_sec = asoc->peer.primary_path; + trans_pri = sctp_trans_elect_best(asoc->peer.active_path, trans_pf); + trans_sec = trans_pri; } /* Set the active and retran transports. */ -- cgit v1.1 From faaa55241f3a6fb5bbe5b075d0595199821eb585 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 22 Aug 2014 18:39:14 +0200 Subject: drivers: isdn: eicon: xdi_msg.h: Fix typo in #ifndef Test for definedness of the macro which is actually defined (the change is hard to see: it is s/SSS/SSA/). Signed-off-by: Rasmus Villemoes Signed-off-by: David S. Miller --- drivers/isdn/hardware/eicon/xdi_msg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/hardware/eicon/xdi_msg.h b/drivers/isdn/hardware/eicon/xdi_msg.h index 58368f7..2498c34 100644 --- a/drivers/isdn/hardware/eicon/xdi_msg.h +++ b/drivers/isdn/hardware/eicon/xdi_msg.h @@ -1,6 +1,6 @@ /* $Id: xdi_msg.h,v 1.1.2.2 2001/02/16 08:40:36 armin Exp $ */ -#ifndef __DIVA_XDI_UM_CFG_MESSSGE_H__ +#ifndef __DIVA_XDI_UM_CFG_MESSAGE_H__ #define __DIVA_XDI_UM_CFG_MESSAGE_H__ /* -- cgit v1.1 From bce0b6c51ac76fc0e763262a6c2a9d05e486f0d8 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 20 Aug 2014 23:57:04 -0400 Subject: ftrace: Fix up trampoline accounting with looping on hash ops Now that a ftrace_hash can be shared by multiple ftrace_ops, they can dec the rec->flags by more than once (one per those that share the ftrace_hash). This means that the tramp_hash may not have a hash item when it was added. For example, if two ftrace_ops share a hash for a ftrace record, and the first ops has a trampoline, when it adds itself it will set the rec->flags TRAMP flag and increments its nr_trampolines counter. When the second ops is added, it must clear that tramp flag but also decrement the other ops that shares its hash. As the update to the function callbacks has not yet been performed, the other ops will not have the tramp hash set yet and it can not be used to know to decrement its nr_trampolines. Luckily, the tramp_hash does not need to be used. As the ftrace_mutex is held, a ops with a trampoline to a record during an update of another ops that shares the record will have its func_hash pointing to it. Since a trampoline can only be set for a record if only one ops is attached to it, we can just check if the record has a trampoline (the FTRACE_FL_TRAMP flag is set) and then find the ops that has this record in its hashes. Also added some output to help debug when things go wrong. Cc: stable@vger.kernel.org # 3.16+ (apply after 3.17-rc4 is out) Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 37f9e90..92376ae 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1507,25 +1507,38 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec) static void ftrace_remove_tramp(struct ftrace_ops *ops, struct dyn_ftrace *rec) { - struct ftrace_func_entry *entry; - - entry = ftrace_lookup_ip(ops->tramp_hash, rec->ip); - if (!entry) + /* If TRAMP is not set, no ops should have a trampoline for this */ + if (!(rec->flags & FTRACE_FL_TRAMP)) return; + rec->flags &= ~FTRACE_FL_TRAMP; + + if ((!ftrace_hash_empty(ops->func_hash->filter_hash) && + !ftrace_lookup_ip(ops->func_hash->filter_hash, rec->ip)) || + ftrace_lookup_ip(ops->func_hash->notrace_hash, rec->ip)) + return; /* * The tramp_hash entry will be removed at time * of update. */ ops->nr_trampolines--; - rec->flags &= ~FTRACE_FL_TRAMP; } -static void ftrace_clear_tramps(struct dyn_ftrace *rec) +static void ftrace_clear_tramps(struct dyn_ftrace *rec, struct ftrace_ops *ops) { struct ftrace_ops *op; + /* If TRAMP is not set, no ops should have a trampoline for this */ + if (!(rec->flags & FTRACE_FL_TRAMP)) + return; + do_for_each_ftrace_op(op, ftrace_ops_list) { + /* + * This function is called to clear other tramps + * not the one that is being updated. + */ + if (op == ops) + continue; if (op->nr_trampolines) ftrace_remove_tramp(op, rec); } while_for_each_ftrace_op(op); @@ -1626,13 +1639,10 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, /* * If we are adding another function callback * to this function, and the previous had a - * trampoline used, then we need to go back to - * the default trampoline. + * custom trampoline in use, then we need to go + * back to the default trampoline. */ - rec->flags &= ~FTRACE_FL_TRAMP; - - /* remove trampolines from any ops for this rec */ - ftrace_clear_tramps(rec); + ftrace_clear_tramps(rec, ops); } /* @@ -1935,8 +1945,8 @@ unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec) if (rec->flags & FTRACE_FL_TRAMP) { ops = ftrace_find_tramp_ops_new(rec); if (FTRACE_WARN_ON(!ops || !ops->trampoline)) { - pr_warning("Bad trampoline accounting at: %p (%pS)\n", - (void *)rec->ip, (void *)rec->ip); + pr_warn("Bad trampoline accounting at: %p (%pS) (%lx)\n", + (void *)rec->ip, (void *)rec->ip, rec->flags); /* Ftrace is shutting down, return anything */ return (unsigned long)FTRACE_ADDR; } @@ -2266,7 +2276,10 @@ static int ftrace_save_ops_tramp_hash(struct ftrace_ops *ops) } while_for_each_ftrace_rec(); /* The number of recs in the hash must match nr_trampolines */ - FTRACE_WARN_ON(ops->tramp_hash->count != ops->nr_trampolines); + if (FTRACE_WARN_ON(ops->tramp_hash->count != ops->nr_trampolines)) + pr_warn("count=%ld trampolines=%d\n", + ops->tramp_hash->count, + ops->nr_trampolines); return 0; } -- cgit v1.1 From 47e4df94d129cbca84de252ff63c4ded08a513e7 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 18 Aug 2014 13:19:09 +0200 Subject: mac80211: fix channel switch for chanctx-based drivers The new_ctx pointer is set only for non-chanctx drivers. This yielded a crash for chanctx-based drivers during channel switch finalization: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 IP: ieee80211_vif_use_reserved_switch+0x71c/0xb00 [mac80211] Use an adequate chanctx pointer to fix this. Reported-by: Linus Torvalds Signed-off-by: Michal Kazior Signed-off-by: Linus Torvalds --- net/mac80211/chan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 6d537f0..0375009 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1444,7 +1444,7 @@ ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) list_del(&sdata->reserved_chanctx_list); list_move(&sdata->assigned_chanctx_list, - &new_ctx->assigned_vifs); + &ctx->assigned_vifs); sdata->reserved_chanctx = NULL; ieee80211_vif_chanctx_reservation_complete(sdata); -- cgit v1.1 From fd2f3a06d30c85a17cf035ebc60c88c2a13a8ece Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Fri, 8 Aug 2014 11:00:53 -0400 Subject: nfs: change nfs_page_group_lock argument Flip the meaning of the second argument from 'wait' to 'nonblock' to match related functions. Update all five calls to reflect this change. Signed-off-by: Weston Andros Adamson Reviewed-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 11 ++++++----- fs/nfs/write.c | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index ba49192..7efa615 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -139,13 +139,14 @@ nfs_iocounter_wait(struct nfs_io_counter *c) /* * nfs_page_group_lock - lock the head of the page group * @req - request in group that is to be locked + * @nonblock - if true don't block waiting for lock * * this lock must be held if modifying the page group list * * returns result from wait_on_bit_lock: 0 on success, < 0 on error */ int -nfs_page_group_lock(struct nfs_page *req, bool wait) +nfs_page_group_lock(struct nfs_page *req, bool nonblock) { struct nfs_page *head = req->wb_head; int ret; @@ -155,7 +156,7 @@ nfs_page_group_lock(struct nfs_page *req, bool wait) do { ret = wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, TASK_UNINTERRUPTIBLE); - } while (wait && ret != 0); + } while (!nonblock && ret != 0); WARN_ON_ONCE(ret > 0); return ret; @@ -219,7 +220,7 @@ bool nfs_page_group_sync_on_bit(struct nfs_page *req, unsigned int bit) { bool ret; - nfs_page_group_lock(req, true); + nfs_page_group_lock(req, false); ret = nfs_page_group_sync_on_bit_locked(req, bit); nfs_page_group_unlock(req); @@ -860,7 +861,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, unsigned int offset, pgbase; int ret; - ret = nfs_page_group_lock(req, false); + ret = nfs_page_group_lock(req, true); if (ret < 0) { desc->pg_error = ret; return 0; @@ -886,7 +887,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, if (desc->pg_recoalesce) return 0; /* retry add_request for this subreq */ - ret = nfs_page_group_lock(req, false); + ret = nfs_page_group_lock(req, true); if (ret < 0) { desc->pg_error = ret; return 0; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e3b5cf2..2771530 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -241,7 +241,7 @@ static bool nfs_page_group_covers_page(struct nfs_page *req) unsigned int pos = 0; unsigned int len = nfs_page_length(req->wb_page); - nfs_page_group_lock(req, true); + nfs_page_group_lock(req, false); do { tmp = nfs_page_group_search_locked(req->wb_head, pos); @@ -479,7 +479,7 @@ try_again: } /* lock each request in the page group */ - ret = nfs_page_group_lock(head, false); + ret = nfs_page_group_lock(head, true); if (ret < 0) return ERR_PTR(ret); subreq = head; -- cgit v1.1 From bc8a309e88a86205fc3e17f06e42a2e56fc6f807 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Fri, 8 Aug 2014 11:00:54 -0400 Subject: nfs: fix nonblocking calls to nfs_page_group_lock nfs_page_group_lock was calling wait_on_bit_lock even when told not to block. Fix by first trying test_and_set_bit, followed by wait_on_bit_lock if and only if blocking is allowed. Return -EAGAIN if nonblocking and the test_and_set of the bit was already locked. Signed-off-by: Weston Andros Adamson Reviewed-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 7efa615..89d5d43 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -143,23 +143,28 @@ nfs_iocounter_wait(struct nfs_io_counter *c) * * this lock must be held if modifying the page group list * - * returns result from wait_on_bit_lock: 0 on success, < 0 on error + * return 0 on success, < 0 on error: -EDELAY if nonblocking or the + * result from wait_on_bit_lock + * + * NOTE: calling with nonblock=false should always have set the + * lock bit (see fs/buffer.c and other uses of wait_on_bit_lock + * with TASK_UNINTERRUPTIBLE), so there is no need to check the result. */ int nfs_page_group_lock(struct nfs_page *req, bool nonblock) { struct nfs_page *head = req->wb_head; - int ret; WARN_ON_ONCE(head != head->wb_head); - do { - ret = wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, - TASK_UNINTERRUPTIBLE); - } while (!nonblock && ret != 0); + if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags)) + return 0; - WARN_ON_ONCE(ret > 0); - return ret; + if (!nonblock) + return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, + TASK_UNINTERRUPTIBLE); + + return -EAGAIN; } /* -- cgit v1.1 From bfd484a5606d6a0379a0a2f04251b1e5c1f8995c Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Fri, 8 Aug 2014 11:00:55 -0400 Subject: nfs: use blocking page_group_lock in add_request __nfs_pageio_add_request was calling nfs_page_group_lock nonblocking, but this can return -EAGAIN which would end up passing -EIO to the application. There is no reason not to block in this path, so change the two calls to do so. Also, there is no need to check the return value of nfs_page_group_lock when nonblock=false, so remove the error handling code. Signed-off-by: Weston Andros Adamson Reviewed-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 89d5d43..30c9626 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -864,13 +864,8 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, struct nfs_page *subreq; unsigned int bytes_left = 0; unsigned int offset, pgbase; - int ret; - ret = nfs_page_group_lock(req, true); - if (ret < 0) { - desc->pg_error = ret; - return 0; - } + nfs_page_group_lock(req, false); subreq = req; bytes_left = subreq->wb_bytes; @@ -892,11 +887,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, if (desc->pg_recoalesce) return 0; /* retry add_request for this subreq */ - ret = nfs_page_group_lock(req, true); - if (ret < 0) { - desc->pg_error = ret; - return 0; - } + nfs_page_group_lock(req, false); continue; } -- cgit v1.1 From 94970014c46223cbcdfbfc67b89596a412f9e3dd Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Fri, 8 Aug 2014 11:00:56 -0400 Subject: nfs: fix error handling in lock_and_join_requests This fixes handling of errors from nfs_page_group_lock in nfs_lock_and_join_requests. It now releases the inode lock and the reference to the head request. Reported-by: Peng Tao Signed-off-by: Weston Andros Adamson Reviewed-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/write.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 2771530..e056f61 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -480,8 +480,11 @@ try_again: /* lock each request in the page group */ ret = nfs_page_group_lock(head, true); - if (ret < 0) + if (ret < 0) { + spin_unlock(&inode->i_lock); + nfs_release_request(head); return ERR_PTR(ret); + } subreq = head; do { /* -- cgit v1.1 From 7c3af975257383ece54b83c0505d3e0656cb7daf Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Fri, 8 Aug 2014 11:00:57 -0400 Subject: nfs: don't sleep with inode lock in lock_and_join_requests This handles the 'nonblock=false' case in nfs_lock_and_join_requests. If the group is already locked and blocking is allowed, drop the inode lock and wait for the group lock to be cleared before trying it all again. This should fix warnings found in peterz's tree (sched/wait branch), where might_sleep() checks are added to wait.[ch]. Reported-by: Fengguang Wu Signed-off-by: Weston Andros Adamson Reviewed-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 17 +++++++++++++++++ fs/nfs/write.c | 12 +++++++++++- include/linux/nfs_page.h | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 30c9626..4ec67f8 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -168,6 +168,23 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock) } /* + * nfs_page_group_lock_wait - wait for the lock to clear, but don't grab it + * @req - a request in the group + * + * This is a blocking call to wait for the group lock to be cleared. + */ +void +nfs_page_group_lock_wait(struct nfs_page *req) +{ + struct nfs_page *head = req->wb_head; + + WARN_ON_ONCE(head != head->wb_head); + + wait_on_bit(&head->wb_flags, PG_HEADLOCK, + TASK_UNINTERRUPTIBLE); +} + +/* * nfs_page_group_unlock - unlock the head of the page group * @req - request in group that is to be unlocked */ diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e056f61..175d5d0 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -478,13 +478,23 @@ try_again: return NULL; } - /* lock each request in the page group */ + /* holding inode lock, so always make a non-blocking call to try the + * page group lock */ ret = nfs_page_group_lock(head, true); if (ret < 0) { spin_unlock(&inode->i_lock); + + if (!nonblock && ret == -EAGAIN) { + nfs_page_group_lock_wait(head); + nfs_release_request(head); + goto try_again; + } + nfs_release_request(head); return ERR_PTR(ret); } + + /* lock each request in the page group */ subreq = head; do { /* diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 6ad2bbc..6c3e06e 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -123,6 +123,7 @@ extern int nfs_wait_on_request(struct nfs_page *); extern void nfs_unlock_request(struct nfs_page *req); extern void nfs_unlock_and_release_request(struct nfs_page *); extern int nfs_page_group_lock(struct nfs_page *, bool); +extern void nfs_page_group_lock_wait(struct nfs_page *); extern void nfs_page_group_unlock(struct nfs_page *); extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); -- cgit v1.1 From bba5c1887a925a9945d22217d38d58d8b3ba1043 Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Thu, 14 Aug 2014 17:39:32 -0400 Subject: nfs: disallow duplicate pages in pgio page vectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjacent requests that share the same page are allowed, but should only use one entry in the page vector. This avoids overruning the page vector - it is sized based on how many bytes there are, not by request count. This fixes issues that manifest as "Redzone overwritten" bugs (the vector overrun) and hangs waiting on page read / write, as it waits on the same page more than once. This also adds bounds checking to the page vector with a graceful failure (WARN_ON_ONCE and pgio error returned to application). Reported-by: Toralf Förster Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 4ec67f8..a1d1de7 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -724,10 +724,11 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr) { struct nfs_page *req; - struct page **pages; + struct page **pages, + *last_page; struct list_head *head = &desc->pg_list; struct nfs_commit_info cinfo; - unsigned int pagecount; + unsigned int pagecount, pageused; pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count); if (!nfs_pgarray_set(&hdr->page_array, pagecount)) @@ -735,12 +736,23 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); pages = hdr->page_array.pagevec; + last_page = NULL; + pageused = 0; while (!list_empty(head)) { req = nfs_list_entry(head->next); nfs_list_remove_request(req); nfs_list_add_request(req, &hdr->pages); - *pages++ = req->wb_page; + + if (WARN_ON_ONCE(pageused >= pagecount)) + return nfs_pgio_error(desc, hdr); + + if (!last_page || last_page != req->wb_page) { + *pages++ = last_page = req->wb_page; + pageused++; + } } + if (WARN_ON_ONCE(pageused != pagecount)) + return nfs_pgio_error(desc, hdr); if ((desc->pg_ioflags & FLUSH_COND_STABLE) && (desc->pg_moreio || nfs_reqs_to_commit(&cinfo))) -- cgit v1.1 From 78270e8fbc2916bfc8305b8f58f33474cce1ec0e Mon Sep 17 00:00:00 2001 From: Weston Andros Adamson Date: Thu, 14 Aug 2014 17:39:33 -0400 Subject: nfs: can_coalesce_requests must enforce contiguity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 6094f83864c1d1296566a282cba05ba613f151ee "nfs: allow coalescing of subpage requests" got rid of the requirement that requests cover whole pages, but it made some incorrect assumptions. It turns out that callers of this interface can map adjacent requests (by file position as seen by req_offset + req->wb_bytes) to different pages, even when they could share a page. An example is the direct I/O interface - iov_iter_get_pages_alloc may return one segment with a partial page filled and the next segment (which is adjacent in the file position) starts with a new page. Reported-by: Toralf Förster Signed-off-by: Weston Andros Adamson Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index a1d1de7..932c6cc 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -823,6 +823,14 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, return false; if (req_offset(req) != req_offset(prev) + prev->wb_bytes) return false; + if (req->wb_page == prev->wb_page) { + if (req->wb_pgbase != prev->wb_pgbase + prev->wb_bytes) + return false; + } else { + if (req->wb_pgbase != 0 || + prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE) + return false; + } } size = pgio->pg_ops->pg_test(pgio, prev, req); WARN_ON_ONCE(size > req->wb_bytes); -- cgit v1.1 From 92a56555bd576c61b27a5cab9f38a33a1e9a1df5 Mon Sep 17 00:00:00 2001 From: David Jeffery Date: Tue, 5 Aug 2014 11:19:42 -0400 Subject: nfs: Don't busy-wait on SIGKILL in __nfs_iocounter_wait If a SIGKILL is sent to a task waiting in __nfs_iocounter_wait, it will busy-wait or soft lockup in its while loop. nfs_wait_bit_killable won't sleep, and the loop won't exit on the error return. Stop the busy-wait by breaking out of the loop when nfs_wait_bit_killable returns an error. Signed-off-by: David Jeffery Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 932c6cc..be7cbce 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -116,7 +116,7 @@ __nfs_iocounter_wait(struct nfs_io_counter *c) if (atomic_read(&c->io_count) == 0) break; ret = nfs_wait_bit_killable(&q.key); - } while (atomic_read(&c->io_count) != 0); + } while (atomic_read(&c->io_count) != 0 && !ret); finish_wait(wq, &q.wait); return ret; } -- cgit v1.1 From 5f151b240192a1557119d5375af71efc26825bc8 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Fri, 15 Aug 2014 17:18:46 -0400 Subject: ftrace: Fix function_profiler and function tracer together The latest rewrite of ftrace removed the separate ftrace_ops of the function tracer and the function graph tracer and had them share the same ftrace_ops. This simplified the accounting by removing the multiple layers of functions called, where the global_ops func would call a special list that would iterate over the other ops that were registered within it (like function and function graph), which itself was registered to the ftrace ops list of all functions currently active. If that sounds confusing, the code that implemented it was also confusing and its removal is a good thing. The problem with this change was that it assumed that the function and function graph tracer can never be used at the same time. This is mostly true, but there is an exception. That is when the function profiler uses the function graph tracer to profile. The function profiler can be activated the same time as the function tracer, and this breaks the assumption and the result is that ftrace will crash (it detects the error and shuts itself down, it does not cause a kernel oops). To solve this issue, a previous change allowed the hash tables for the functions traced by a ftrace_ops to be a pointer and let multiple ftrace_ops share the same hash. This allows the function and function_graph tracer to have separate ftrace_ops, but still share the hash, which is what is done. Now the function and function graph tracers have separate ftrace_ops again, and the function tracer can be run while the function_profile is active. Cc: stable@vger.kernel.org # 3.16 (apply after 3.17-rc4 is out) Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 60 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 92376ae..08aca65d 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -68,8 +68,12 @@ #define INIT_OPS_HASH(opsname) \ .func_hash = &opsname.local_hash, \ .local_hash.regex_lock = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock), +#define ASSIGN_OPS_HASH(opsname, val) \ + .func_hash = val, \ + .local_hash.regex_lock = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock), #else #define INIT_OPS_HASH(opsname) +#define ASSIGN_OPS_HASH(opsname, val) #endif static struct ftrace_ops ftrace_list_end __read_mostly = { @@ -4663,7 +4667,6 @@ void __init ftrace_init(void) static struct ftrace_ops global_ops = { .func = ftrace_stub, .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED, - INIT_OPS_HASH(global_ops) }; static int __init ftrace_nodyn_init(void) @@ -5197,6 +5200,17 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, #ifdef CONFIG_FUNCTION_GRAPH_TRACER +static struct ftrace_ops graph_ops = { + .func = ftrace_stub, + .flags = FTRACE_OPS_FL_RECURSION_SAFE | + FTRACE_OPS_FL_INITIALIZED | + FTRACE_OPS_FL_STUB, +#ifdef FTRACE_GRAPH_TRAMP_ADDR + .trampoline = FTRACE_GRAPH_TRAMP_ADDR, +#endif + ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash) +}; + static int ftrace_graph_active; int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace) @@ -5359,12 +5373,28 @@ static int ftrace_graph_entry_test(struct ftrace_graph_ent *trace) */ static void update_function_graph_func(void) { - if (ftrace_ops_list == &ftrace_list_end || - (ftrace_ops_list == &global_ops && - global_ops.next == &ftrace_list_end)) - ftrace_graph_entry = __ftrace_graph_entry; - else + struct ftrace_ops *op; + bool do_test = false; + + /* + * The graph and global ops share the same set of functions + * to test. If any other ops is on the list, then + * the graph tracing needs to test if its the function + * it should call. + */ + do_for_each_ftrace_op(op, ftrace_ops_list) { + if (op != &global_ops && op != &graph_ops && + op != &ftrace_list_end) { + do_test = true; + /* in double loop, break out with goto */ + goto out; + } + } while_for_each_ftrace_op(op); + out: + if (do_test) ftrace_graph_entry = ftrace_graph_entry_test; + else + ftrace_graph_entry = __ftrace_graph_entry; } static struct notifier_block ftrace_suspend_notifier = { @@ -5405,16 +5435,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc, ftrace_graph_entry = ftrace_graph_entry_test; update_function_graph_func(); - /* Function graph doesn't use the .func field of global_ops */ - global_ops.flags |= FTRACE_OPS_FL_STUB; - -#ifdef CONFIG_DYNAMIC_FTRACE - /* Optimize function graph calling (if implemented by arch) */ - if (FTRACE_GRAPH_TRAMP_ADDR != 0) - global_ops.trampoline = FTRACE_GRAPH_TRAMP_ADDR; -#endif - - ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET); + ret = ftrace_startup(&graph_ops, FTRACE_START_FUNC_RET); out: mutex_unlock(&ftrace_lock); @@ -5432,12 +5453,7 @@ void unregister_ftrace_graph(void) ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; ftrace_graph_entry = ftrace_graph_entry_stub; __ftrace_graph_entry = ftrace_graph_entry_stub; - ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET); - global_ops.flags &= ~FTRACE_OPS_FL_STUB; -#ifdef CONFIG_DYNAMIC_FTRACE - if (FTRACE_GRAPH_TRAMP_ADDR != 0) - global_ops.trampoline = 0; -#endif + ftrace_shutdown(&graph_ops, FTRACE_STOP_FUNC_RET); unregister_pm_notifier(&ftrace_suspend_notifier); unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL); -- cgit v1.1 From 39b5552cd5090d4c210d278cd2732f493075f033 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Sun, 17 Aug 2014 20:59:10 -0400 Subject: ftrace: Use current addr when converting to nop in __ftrace_replace_code() In __ftrace_replace_code(), when converting the call to a nop in a function it needs to compare against the "curr" (current) value of the ftrace ops, and not the "new" one. It currently does not affect x86 which is the only arch to do the trampolines with function graph tracer, but when other archs that do depend on this code implement the function graph trampoline, it can crash. Here's an example when ARM uses the trampolines (in the future): ------------[ cut here ]------------ WARNING: CPU: 0 PID: 9 at kernel/trace/ftrace.c:1716 ftrace_bug+0x17c/0x1f4() Modules linked in: omap_rng rng_core ipv6 CPU: 0 PID: 9 Comm: migration/0 Not tainted 3.16.0-test-10959-gf0094b28f303-dirty #52 [] (unwind_backtrace) from [] (show_stack+0x20/0x24) [] (show_stack) from [] (dump_stack+0x78/0x94) [] (dump_stack) from [] (warn_slowpath_common+0x7c/0x9c) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x2c/0x34) [] (warn_slowpath_null) from [] (ftrace_bug+0x17c/0x1f4) [] (ftrace_bug) from [] (ftrace_replace_code+0x80/0x9c) [] (ftrace_replace_code) from [] (ftrace_modify_all_code+0xb8/0x164) [] (ftrace_modify_all_code) from [] (__ftrace_modify_code+0x14/0x1c) [] (__ftrace_modify_code) from [] (multi_cpu_stop+0xf4/0x134) [] (multi_cpu_stop) from [] (cpu_stopper_thread+0x54/0x130) [] (cpu_stopper_thread) from [] (smpboot_thread_fn+0x1ac/0x1bc) [] (smpboot_thread_fn) from [] (kthread+0xe0/0xfc) [] (kthread) from [] (ret_from_fork+0x14/0x20) ---[ end trace dc9ce72c5b617d8f ]--- [ 65.047264] ftrace failed to modify [] asm_do_IRQ+0x10/0x1c [ 65.054070] actual: 85:1b:00:eb Fixes: 7413af1fb70e7 "ftrace: Make get_ftrace_addr() and get_ftrace_addr_old() global" Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 08aca65d..5916a8e 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2017,7 +2017,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) return ftrace_make_call(rec, ftrace_addr); case FTRACE_UPDATE_MAKE_NOP: - return ftrace_make_nop(NULL, rec, ftrace_addr); + return ftrace_make_nop(NULL, rec, ftrace_old_addr); case FTRACE_UPDATE_MODIFY_CALL: return ftrace_modify_call(rec, ftrace_old_addr, ftrace_addr); -- cgit v1.1 From 1302d32c8411f8cff75ce722451767c3aa5e9fda Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 11 Aug 2014 19:51:44 +0200 Subject: ARM: dts: rockchip: readd missing mmc0 pinctrl settings During the restructuring of the Rockchip Cortex-A9 dtsi files it seems like the pinctrl settings vanished at some point from the mmc0 support. This of course renders them unusable, so readd the necessary pinctrl properties. Signed-off-by: Heiko Stuebner --- arch/arm/boot/dts/rk3066a-bqcurie2.dts | 2 ++ arch/arm/boot/dts/rk3188-radxarock.dts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/rk3066a-bqcurie2.dts b/arch/arm/boot/dts/rk3066a-bqcurie2.dts index 042f821d..c9d912d 100644 --- a/arch/arm/boot/dts/rk3066a-bqcurie2.dts +++ b/arch/arm/boot/dts/rk3066a-bqcurie2.dts @@ -149,6 +149,8 @@ &mmc0 { /* sdmmc */ num-slots = <1>; status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>; vmmc-supply = <&vcc_sd0>; slot@0 { diff --git a/arch/arm/boot/dts/rk3188-radxarock.dts b/arch/arm/boot/dts/rk3188-radxarock.dts index 171b610..5e4e3c23 100644 --- a/arch/arm/boot/dts/rk3188-radxarock.dts +++ b/arch/arm/boot/dts/rk3188-radxarock.dts @@ -179,6 +179,8 @@ &mmc0 { num-slots = <1>; status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>; vmmc-supply = <&vcc_sd0>; slot@0 { -- cgit v1.1 From 00250b529313d6262bb0ebbd6bdf0a88c809f6f0 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 20 Aug 2014 12:31:03 +0200 Subject: MAINTAINERS: add new Rockchip SoC list Add the new list that Rockchip-specific patches should also be directed to. Signed-off-by: Heiko Stuebner --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index aefa948..c2ecffb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1277,6 +1277,7 @@ F: drivers/scsi/arm/ ARM/Rockchip SoC support M: Heiko Stuebner L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +L: linux-rockchip@lists.infradead.org S: Maintained F: arch/arm/mach-rockchip/ F: drivers/*/*rockchip* -- cgit v1.1 From a284e9d14e35b776807c3a40dd1ff1e05429d4a4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 19 Aug 2014 23:04:31 +0200 Subject: MAINTAINERS: Add entry for Renesas DRM drivers Signed-off-by: Laurent Pinchart Signed-off-by: Dave Airlie --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index aefa948..858de85 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3115,6 +3115,17 @@ F: include/linux/host1x.h F: include/uapi/drm/tegra_drm.h F: Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +DRM DRIVERS FOR RENESAS +M: Laurent Pinchart +L: dri-devel@lists.freedesktop.org +L: linux-sh@vger.kernel.org +T: git git://people.freedesktop.org/~airlied/linux +S: Supported +F: drivers/gpu/drm/rcar-du/ +F: drivers/gpu/drm/shmobile/ +F: include/linux/platform_data/rcar-du.h +F: include/linux/platform_data/shmob_drm.h + DSBR100 USB FM RADIO DRIVER M: Alexey Klimov L: linux-media@vger.kernel.org -- cgit v1.1 From caa9eac5bcc835cfd98085fcd3944f44890d8a8f Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Fri, 22 Aug 2014 13:25:10 -0600 Subject: ARM: tegra: apalis/colibri t30: fix on-module 5v0 supplies Working on Gigabit/PCIe support in U-Boot for Apalis T30 I realised that the current device tree source includes for our modules only happen to work due to referencing the on-carrier 5v0 supply from USB which is not at all available on-module. The modules actually contain TPS60150 charge pumps to generate the PMIC required 5 volts from the one and only 3.3 volt module supply. This patch fixes this. (Note: When back-porting this to v3.16 stable releases, simply drop the change to tegra30-apalis.dtsi; that file was added in v3.17) Cc: #v3.16+ Signed-off-by: Marcel Ziswiler Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson --- arch/arm/boot/dts/tegra30-apalis.dtsi | 11 ++++++++++- arch/arm/boot/dts/tegra30-colibri.dtsi | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/tegra30-apalis.dtsi b/arch/arm/boot/dts/tegra30-apalis.dtsi index 8adaa78..a5446cb 100644 --- a/arch/arm/boot/dts/tegra30-apalis.dtsi +++ b/arch/arm/boot/dts/tegra30-apalis.dtsi @@ -423,7 +423,7 @@ vcc4-supply = <&sys_3v3_reg>; vcc5-supply = <&sys_3v3_reg>; vcc6-supply = <&vio_reg>; - vcc7-supply = <&sys_5v0_reg>; + vcc7-supply = <&charge_pump_5v0_reg>; vccio-supply = <&sys_3v3_reg>; regulators { @@ -674,5 +674,14 @@ regulator-max-microvolt = <3300000>; regulator-always-on; }; + + charge_pump_5v0_reg: regulator@101 { + compatible = "regulator-fixed"; + reg = <101>; + regulator-name = "5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; }; }; diff --git a/arch/arm/boot/dts/tegra30-colibri.dtsi b/arch/arm/boot/dts/tegra30-colibri.dtsi index bf16f8e..c4ed1be 100644 --- a/arch/arm/boot/dts/tegra30-colibri.dtsi +++ b/arch/arm/boot/dts/tegra30-colibri.dtsi @@ -201,7 +201,7 @@ vcc4-supply = <&sys_3v3_reg>; vcc5-supply = <&sys_3v3_reg>; vcc6-supply = <&vio_reg>; - vcc7-supply = <&sys_5v0_reg>; + vcc7-supply = <&charge_pump_5v0_reg>; vccio-supply = <&sys_3v3_reg>; regulators { @@ -373,5 +373,14 @@ regulator-max-microvolt = <3300000>; regulator-always-on; }; + + charge_pump_5v0_reg: regulator@101 { + compatible = "regulator-fixed"; + reg = <101>; + regulator-name = "5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; }; }; -- cgit v1.1 From 12266db732ff3845eaa9ba9354c4938249787aaf Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Aug 2014 07:19:10 +0900 Subject: ARM: shmobile: koelsch: Remove non-existent i2c6 pinmux On r8a7791, i2c6 (aka iic3) doesn't need pinmux, but the koelsch dts refers to non-existent pinmux configuration data: pinmux core: sh-pfc does not support function i2c6 sh-pfc e6060000.pfc: invalid function i2c6 in map table Remove it to fix this. Fixes: commit 1d41f36a68c0f4e9b01d563ce33bab5201858b54 ("ARM: shmobile: koelsch dts: Add VDD MPU regulator for DVFS") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Olof Johansson --- arch/arm/boot/dts/r8a7791-koelsch.dts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index 23486c0..be59014 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -275,11 +275,6 @@ renesas,function = "msiof0"; }; - i2c6_pins: i2c6 { - renesas,groups = "i2c6"; - renesas,function = "i2c6"; - }; - usb0_pins: usb0 { renesas,groups = "usb0"; renesas,function = "usb0"; @@ -420,8 +415,6 @@ }; &i2c6 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c6_pins>; status = "okay"; clock-frequency = <100000>; -- cgit v1.1 From bf87bb12bd7062bf577163f3f6d765debbae6200 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Mon, 18 Aug 2014 18:20:49 +0100 Subject: bus: arm-ccn: Fix warning message A message warning a user about wrong vc value was printing out port instead. Reported-by: Drew Richardson Signed-off-by: Pawel Moll Signed-off-by: Olof Johansson --- drivers/bus/arm-ccn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/arm-ccn.c b/drivers/bus/arm-ccn.c index 3266f8f..6f550d9 100644 --- a/drivers/bus/arm-ccn.c +++ b/drivers/bus/arm-ccn.c @@ -662,7 +662,7 @@ static int arm_ccn_pmu_event_init(struct perf_event *event) } if (e->num_vcs && vc >= e->num_vcs) { dev_warn(ccn->dev, "Invalid vc %d for node/XP %d!\n", - port, node_xp); + vc, node_xp); return -EINVAL; } valid = 1; -- cgit v1.1 From d856f32a86b2b015ab180ab7a55e455ed8d3ccc5 Mon Sep 17 00:00:00 2001 From: Benjamin LaHaise Date: Sun, 24 Aug 2014 13:14:05 -0400 Subject: aio: fix reqs_available handling As reported by Dan Aloni, commit f8567a3845ac ("aio: fix aio request leak when events are reaped by userspace") introduces a regression when user code attempts to perform io_submit() with more events than are available in the ring buffer. Reverting that commit would reintroduce a regression when user space event reaping is used. Fixing this bug is a bit more involved than the previous attempts to fix this regression. Since we do not have a single point at which we can count events as being reaped by user space and io_getevents(), we have to track event completion by looking at the number of events left in the event ring. So long as there are as many events in the ring buffer as there have been completion events generate, we cannot call put_reqs_available(). The code to check for this is now placed in refill_reqs_available(). A test program from Dan and modified by me for verifying this bug is available at http://www.kvack.org/~bcrl/20140824-aio_bug.c . Reported-by: Dan Aloni Signed-off-by: Benjamin LaHaise Acked-by: Dan Aloni Cc: Kent Overstreet Cc: Mateusz Guzik Cc: Petr Matousek Cc: stable@vger.kernel.org # v3.16 and anything that f8567a3845ac was backported to Signed-off-by: Linus Torvalds --- fs/aio.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index ae63587..97bc62c 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -141,6 +141,7 @@ struct kioctx { struct { unsigned tail; + unsigned completed_events; spinlock_t completion_lock; } ____cacheline_aligned_in_smp; @@ -857,6 +858,68 @@ out: return ret; } +/* refill_reqs_available + * Updates the reqs_available reference counts used for tracking the + * number of free slots in the completion ring. This can be called + * from aio_complete() (to optimistically update reqs_available) or + * from aio_get_req() (the we're out of events case). It must be + * called holding ctx->completion_lock. + */ +static void refill_reqs_available(struct kioctx *ctx, unsigned head, + unsigned tail) +{ + unsigned events_in_ring, completed; + + /* Clamp head since userland can write to it. */ + head %= ctx->nr_events; + if (head <= tail) + events_in_ring = tail - head; + else + events_in_ring = ctx->nr_events - (head - tail); + + completed = ctx->completed_events; + if (events_in_ring < completed) + completed -= events_in_ring; + else + completed = 0; + + if (!completed) + return; + + ctx->completed_events -= completed; + put_reqs_available(ctx, completed); +} + +/* user_refill_reqs_available + * Called to refill reqs_available when aio_get_req() encounters an + * out of space in the completion ring. + */ +static void user_refill_reqs_available(struct kioctx *ctx) +{ + spin_lock_irq(&ctx->completion_lock); + if (ctx->completed_events) { + struct aio_ring *ring; + unsigned head; + + /* Access of ring->head may race with aio_read_events_ring() + * here, but that's okay since whether we read the old version + * or the new version, and either will be valid. The important + * part is that head cannot pass tail since we prevent + * aio_complete() from updating tail by holding + * ctx->completion_lock. Even if head is invalid, the check + * against ctx->completed_events below will make sure we do the + * safe/right thing. + */ + ring = kmap_atomic(ctx->ring_pages[0]); + head = ring->head; + kunmap_atomic(ring); + + refill_reqs_available(ctx, head, ctx->tail); + } + + spin_unlock_irq(&ctx->completion_lock); +} + /* aio_get_req * Allocate a slot for an aio request. * Returns NULL if no requests are free. @@ -865,8 +928,11 @@ static inline struct kiocb *aio_get_req(struct kioctx *ctx) { struct kiocb *req; - if (!get_reqs_available(ctx)) - return NULL; + if (!get_reqs_available(ctx)) { + user_refill_reqs_available(ctx); + if (!get_reqs_available(ctx)) + return NULL; + } req = kmem_cache_alloc(kiocb_cachep, GFP_KERNEL|__GFP_ZERO); if (unlikely(!req)) @@ -925,8 +991,8 @@ void aio_complete(struct kiocb *iocb, long res, long res2) struct kioctx *ctx = iocb->ki_ctx; struct aio_ring *ring; struct io_event *ev_page, *event; + unsigned tail, pos, head; unsigned long flags; - unsigned tail, pos; /* * Special case handling for sync iocbs: @@ -987,10 +1053,14 @@ void aio_complete(struct kiocb *iocb, long res, long res2) ctx->tail = tail; ring = kmap_atomic(ctx->ring_pages[0]); + head = ring->head; ring->tail = tail; kunmap_atomic(ring); flush_dcache_page(ctx->ring_pages[0]); + ctx->completed_events++; + if (ctx->completed_events > 1) + refill_reqs_available(ctx, head, tail); spin_unlock_irqrestore(&ctx->completion_lock, flags); pr_debug("added to ring %p at [%u]\n", iocb, tail); @@ -1005,7 +1075,6 @@ void aio_complete(struct kiocb *iocb, long res, long res2) /* everything turned out well, dispose of the aiocb. */ kiocb_free(iocb); - put_reqs_available(ctx, 1); /* * We have to order our ring_info tail store above and test -- cgit v1.1 From 52addcf9d6669fa439387610bc65c92fa0980cef Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 25 Aug 2014 15:36:20 -0700 Subject: Linux 3.17-rc2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e432442..f64fc78 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 17 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Shuffling Zombie Juror # *DOCUMENTATION* -- cgit v1.1 From 257f8cce5d40b811d229ed71602882baa0012808 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 29 Aug 2014 15:32:29 +0200 Subject: ALSA: pcm: Allow nonatomic trigger operations Currently, many PCM operations are performed in a critical section protected by spinlock, typically the trigger and pointer callbacks are assumed to be atomic. This is basically because some trigger action (e.g. PCM stop after drain or xrun) is done in the interrupt handler. If a driver runs in a threaded irq, however, this doesn't have to be atomic. And many devices want to handle trigger in a non-atomic context due to lengthy communications. This patch tries all PCM calls operational in non-atomic context. What it does is very simple: replaces the substream spinlock with the corresponding substream mutex when pcm->nonatomic flag is set. The driver that wants to use the non-atomic PCM ops just needs to set the flag and keep the rest as is. (Of course, it must not handle any PCM ops in irq context.) Note that the code doesn't check whether it's atomic-safe or not, but trust in 100% that the driver sets pcm->nonatomic correctly. One possible problem is the case where linked PCM substreams have inconsistent nonatomic states. For avoiding this, snd_pcm_link() returns an error if one tries to link an inconsistent PCM substream. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 58 +++++++++++++++++++++++++++++-------- sound/core/pcm.c | 1 + sound/core/pcm_native.c | 76 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 116 insertions(+), 19 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 6f3e10c..bc79962 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -365,6 +365,7 @@ struct snd_pcm_runtime { struct snd_pcm_group { /* keep linked substreams */ spinlock_t lock; + struct mutex mutex; struct list_head substreams; int count; }; @@ -460,6 +461,7 @@ struct snd_pcm { void (*private_free) (struct snd_pcm *pcm); struct device *dev; /* actual hw device this belongs to */ bool internal; /* pcm is for internal use only */ + bool nonatomic; /* whole PCM operations are in non-atomic context */ #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) struct snd_pcm_oss oss; #endif @@ -493,6 +495,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree); */ extern rwlock_t snd_pcm_link_rwlock; +extern struct rw_semaphore snd_pcm_link_rwsem; int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info); int snd_pcm_info_user(struct snd_pcm_substream *substream, @@ -539,38 +542,69 @@ static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream) static inline void snd_pcm_stream_lock(struct snd_pcm_substream *substream) { - read_lock(&snd_pcm_link_rwlock); - spin_lock(&substream->self_group.lock); + if (substream->pcm->nonatomic) { + down_read(&snd_pcm_link_rwsem); + mutex_lock(&substream->self_group.mutex); + } else { + read_lock(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); + } } static inline void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) { - spin_unlock(&substream->self_group.lock); - read_unlock(&snd_pcm_link_rwlock); + if (substream->pcm->nonatomic) { + mutex_unlock(&substream->self_group.mutex); + up_read(&snd_pcm_link_rwsem); + } else { + spin_unlock(&substream->self_group.lock); + read_unlock(&snd_pcm_link_rwlock); + } } static inline void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) { - read_lock_irq(&snd_pcm_link_rwlock); - spin_lock(&substream->self_group.lock); + if (substream->pcm->nonatomic) { + down_read(&snd_pcm_link_rwsem); + mutex_lock(&substream->self_group.mutex); + } else { + read_lock_irq(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); + } } static inline void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) { - spin_unlock(&substream->self_group.lock); - read_unlock_irq(&snd_pcm_link_rwlock); + if (substream->pcm->nonatomic) { + mutex_unlock(&substream->self_group.mutex); + up_read(&snd_pcm_link_rwsem); + } else { + spin_unlock(&substream->self_group.lock); + read_unlock_irq(&snd_pcm_link_rwlock); + } } #define snd_pcm_stream_lock_irqsave(substream, flags) \ do { \ - read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \ - spin_lock(&substream->self_group.lock); \ + if ((substream)->pcm->nonatomic) { \ + (flags) = 0; /* XXX for avoid warning */ \ + down_read(&snd_pcm_link_rwsem); \ + mutex_lock(&(substream)->self_group.mutex); \ + } else { \ + read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \ + spin_lock(&(substream)->self_group.lock); \ + } \ } while (0) #define snd_pcm_stream_unlock_irqrestore(substream, flags) \ do { \ - spin_unlock(&substream->self_group.lock); \ - read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \ + if ((substream)->pcm->nonatomic) { \ + mutex_unlock(&(substream)->self_group.mutex); \ + up_read(&snd_pcm_link_rwsem); \ + } else { \ + spin_unlock(&(substream)->self_group.lock); \ + read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \ + } \ } while (0) #define snd_pcm_group_for_each_entry(s, substream) \ diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 43932e8..afccdc5 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -698,6 +698,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) } substream->group = &substream->self_group; spin_lock_init(&substream->self_group.lock); + mutex_init(&substream->self_group.mutex); INIT_LIST_HEAD(&substream->self_group.substreams); list_add_tail(&substream->link_list, &substream->self_group.substreams); atomic_set(&substream->mmap_count, 0); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8cd2f93..16d9b7e 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -77,7 +77,8 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); DEFINE_RWLOCK(snd_pcm_link_rwlock); EXPORT_SYMBOL(snd_pcm_link_rwlock); -static DECLARE_RWSEM(snd_pcm_link_rwsem); +DECLARE_RWSEM(snd_pcm_link_rwsem); +EXPORT_SYMBOL(snd_pcm_link_rwsem); static inline mm_segment_t snd_enter_user(void) { @@ -727,9 +728,14 @@ static int snd_pcm_action_group(struct action_ops *ops, int res = 0; snd_pcm_group_for_each_entry(s, substream) { - if (do_lock && s != substream) - spin_lock_nested(&s->self_group.lock, - SINGLE_DEPTH_NESTING); + if (do_lock && s != substream) { + if (s->pcm->nonatomic) + mutex_lock_nested(&s->self_group.mutex, + SINGLE_DEPTH_NESTING); + else + spin_lock_nested(&s->self_group.lock, + SINGLE_DEPTH_NESTING); + } res = ops->pre_action(s, state); if (res < 0) goto _unlock; @@ -755,8 +761,12 @@ static int snd_pcm_action_group(struct action_ops *ops, if (do_lock) { /* unlock streams */ snd_pcm_group_for_each_entry(s1, substream) { - if (s1 != substream) - spin_unlock(&s1->self_group.lock); + if (s1 != substream) { + if (s->pcm->nonatomic) + mutex_unlock(&s1->self_group.mutex); + else + spin_unlock(&s1->self_group.lock); + } if (s1 == s) /* end */ break; } @@ -784,6 +794,27 @@ static int snd_pcm_action_single(struct action_ops *ops, return res; } +/* call in mutex-protected context */ +static int snd_pcm_action_mutex(struct action_ops *ops, + struct snd_pcm_substream *substream, + int state) +{ + int res; + + if (snd_pcm_stream_linked(substream)) { + if (!mutex_trylock(&substream->group->mutex)) { + mutex_unlock(&substream->self_group.mutex); + mutex_lock(&substream->group->mutex); + mutex_lock(&substream->self_group.mutex); + } + res = snd_pcm_action_group(ops, substream, state, 1); + mutex_unlock(&substream->group->mutex); + } else { + res = snd_pcm_action_single(ops, substream, state); + } + return res; +} + /* * Note: call with stream lock */ @@ -793,6 +824,9 @@ static int snd_pcm_action(struct action_ops *ops, { int res; + if (substream->pcm->nonatomic) + return snd_pcm_action_mutex(ops, substream, state); + if (snd_pcm_stream_linked(substream)) { if (!spin_trylock(&substream->group->lock)) { spin_unlock(&substream->self_group.lock); @@ -807,6 +841,29 @@ static int snd_pcm_action(struct action_ops *ops, return res; } +static int snd_pcm_action_lock_mutex(struct action_ops *ops, + struct snd_pcm_substream *substream, + int state) +{ + int res; + + down_read(&snd_pcm_link_rwsem); + if (snd_pcm_stream_linked(substream)) { + mutex_lock(&substream->group->mutex); + mutex_lock_nested(&substream->self_group.mutex, + SINGLE_DEPTH_NESTING); + res = snd_pcm_action_group(ops, substream, state, 1); + mutex_unlock(&substream->self_group.mutex); + mutex_unlock(&substream->group->mutex); + } else { + mutex_lock(&substream->self_group.mutex); + res = snd_pcm_action_single(ops, substream, state); + mutex_unlock(&substream->self_group.mutex); + } + up_read(&snd_pcm_link_rwsem); + return res; +} + /* * Note: don't use any locks before */ @@ -816,6 +873,9 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops, { int res; + if (substream->pcm->nonatomic) + return snd_pcm_action_lock_mutex(ops, substream, state); + read_lock_irq(&snd_pcm_link_rwlock); if (snd_pcm_stream_linked(substream)) { spin_lock(&substream->group->lock); @@ -1634,7 +1694,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) down_write(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || - substream->runtime->status->state != substream1->runtime->status->state) { + substream->runtime->status->state != substream1->runtime->status->state || + substream->pcm->nonatomic != substream1->pcm->nonatomic) { res = -EBADFD; goto _end; } @@ -1646,6 +1707,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) substream->group = group; group = NULL; spin_lock_init(&substream->group->lock); + mutex_init(&substream->group->mutex); INIT_LIST_HEAD(&substream->group->substreams); list_add_tail(&substream->link_list, &substream->group->substreams); substream->group->count = 1; -- cgit v1.1 From 7af142f752116e86adbe2073f2922d8265a77709 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Sep 2014 11:19:37 +0200 Subject: ALSA: pcm: Uninline snd_pcm_stream_lock() and _unlock() The previous commit for the non-atomic PCM ops added more codes to snd_pcm_stream_lock() and its variants. Since they are inlined functions, it resulted in a significant code size bloat. For reducing the size bloat, this patch changes the inline functions to the normal function calls. The export of rwlock and rwsem are removed as well, since they are referred only in pcm_native.c now. Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 81 ++++++++----------------------------------------- sound/core/pcm_native.c | 64 +++++++++++++++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 73 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index bc79962..67e0bdb 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -494,9 +494,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree); * Native I/O */ -extern rwlock_t snd_pcm_link_rwlock; -extern struct rw_semaphore snd_pcm_link_rwsem; - int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info); int snd_pcm_info_user(struct snd_pcm_substream *substream, struct snd_pcm_info __user *info); @@ -540,72 +537,18 @@ static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream) return substream->group != &substream->self_group; } -static inline void snd_pcm_stream_lock(struct snd_pcm_substream *substream) -{ - if (substream->pcm->nonatomic) { - down_read(&snd_pcm_link_rwsem); - mutex_lock(&substream->self_group.mutex); - } else { - read_lock(&snd_pcm_link_rwlock); - spin_lock(&substream->self_group.lock); - } -} - -static inline void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) -{ - if (substream->pcm->nonatomic) { - mutex_unlock(&substream->self_group.mutex); - up_read(&snd_pcm_link_rwsem); - } else { - spin_unlock(&substream->self_group.lock); - read_unlock(&snd_pcm_link_rwlock); - } -} - -static inline void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) -{ - if (substream->pcm->nonatomic) { - down_read(&snd_pcm_link_rwsem); - mutex_lock(&substream->self_group.mutex); - } else { - read_lock_irq(&snd_pcm_link_rwlock); - spin_lock(&substream->self_group.lock); - } -} - -static inline void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) -{ - if (substream->pcm->nonatomic) { - mutex_unlock(&substream->self_group.mutex); - up_read(&snd_pcm_link_rwsem); - } else { - spin_unlock(&substream->self_group.lock); - read_unlock_irq(&snd_pcm_link_rwlock); - } -} - -#define snd_pcm_stream_lock_irqsave(substream, flags) \ -do { \ - if ((substream)->pcm->nonatomic) { \ - (flags) = 0; /* XXX for avoid warning */ \ - down_read(&snd_pcm_link_rwsem); \ - mutex_lock(&(substream)->self_group.mutex); \ - } else { \ - read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \ - spin_lock(&(substream)->self_group.lock); \ - } \ -} while (0) - -#define snd_pcm_stream_unlock_irqrestore(substream, flags) \ -do { \ - if ((substream)->pcm->nonatomic) { \ - mutex_unlock(&(substream)->self_group.mutex); \ - up_read(&snd_pcm_link_rwsem); \ - } else { \ - spin_unlock(&(substream)->self_group.lock); \ - read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \ - } \ -} while (0) +void snd_pcm_stream_lock(struct snd_pcm_substream *substream); +void snd_pcm_stream_unlock(struct snd_pcm_substream *substream); +void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream); +void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream); +unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream); +#define snd_pcm_stream_lock_irqsave(substream, flags) \ + do { \ + typecheck(unsigned long, flags); \ + flags = _snd_pcm_stream_lock_irqsave(substream); \ + } while (0) +void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, + unsigned long flags); #define snd_pcm_group_for_each_entry(s, substream) \ list_for_each_entry(s, &substream->group->substreams, link_list) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 16d9b7e..85fe1a2 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -74,11 +74,67 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); * */ -DEFINE_RWLOCK(snd_pcm_link_rwlock); -EXPORT_SYMBOL(snd_pcm_link_rwlock); +static DEFINE_RWLOCK(snd_pcm_link_rwlock); +static DECLARE_RWSEM(snd_pcm_link_rwsem); -DECLARE_RWSEM(snd_pcm_link_rwsem); -EXPORT_SYMBOL(snd_pcm_link_rwsem); +void snd_pcm_stream_lock(struct snd_pcm_substream *substream) +{ + if (substream->pcm->nonatomic) { + down_read(&snd_pcm_link_rwsem); + mutex_lock(&substream->self_group.mutex); + } else { + read_lock(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); + } +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); + +void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) +{ + if (substream->pcm->nonatomic) { + mutex_unlock(&substream->self_group.mutex); + up_read(&snd_pcm_link_rwsem); + } else { + spin_unlock(&substream->self_group.lock); + read_unlock(&snd_pcm_link_rwlock); + } +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); + +void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) +{ + if (!substream->pcm->nonatomic) + local_irq_disable(); + snd_pcm_stream_lock(substream); +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); + +void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) +{ + snd_pcm_stream_unlock(substream); + if (!substream->pcm->nonatomic) + local_irq_enable(); +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); + +unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) +{ + unsigned long flags = 0; + if (!substream->pcm->nonatomic) + local_irq_save(flags); + snd_pcm_stream_lock(substream); + return flags; +} +EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); + +void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, + unsigned long flags) +{ + snd_pcm_stream_unlock(substream); + if (!substream->pcm->nonatomic) + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); static inline mm_segment_t snd_enter_user(void) { -- cgit v1.1