diff options
Diffstat (limited to 'drivers')
708 files changed, 11443 insertions, 4280 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index ecb743bf05a5..536562c626a2 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -24,7 +24,7 @@ acpi-y += nvs.o # Power management related files acpi-y += wakeup.o acpi-y += sleep.o -acpi-$(CONFIG_PM) += device_pm.o +acpi-y += device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o @@ -38,7 +38,6 @@ acpi-y += processor_core.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o -acpi-y += csrt.o acpi-$(CONFIG_X86_INTEL_LPSS) += acpi_lpss.o acpi-y += acpi_platform.o acpi-y += power.o diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index b1c95422ce74..cab13f2fc28e 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -35,11 +35,16 @@ ACPI_MODULE_NAME("acpi_lpss"); struct lpss_device_desc { bool clk_required; - const char *clk_parent; + const char *clkdev_name; bool ltr_required; unsigned int prv_offset; }; +static struct lpss_device_desc lpss_dma_desc = { + .clk_required = true, + .clkdev_name = "hclk", +}; + struct lpss_private_data { void __iomem *mmio_base; resource_size_t mmio_size; @@ -49,7 +54,6 @@ struct lpss_private_data { static struct lpss_device_desc lpt_dev_desc = { .clk_required = true, - .clk_parent = "lpss_clk", .prv_offset = 0x800, .ltr_required = true, }; @@ -60,6 +64,9 @@ static struct lpss_device_desc lpt_sdio_dev_desc = { }; static const struct acpi_device_id acpi_lpss_device_ids[] = { + /* Generic LPSS devices */ + { "INTL9C60", (unsigned long)&lpss_dma_desc }, + /* Lynxpoint LPSS devices */ { "INT33C0", (unsigned long)&lpt_dev_desc }, { "INT33C1", (unsigned long)&lpt_dev_desc }, @@ -91,16 +98,27 @@ static int register_device_clock(struct acpi_device *adev, struct lpss_private_data *pdata) { const struct lpss_device_desc *dev_desc = pdata->dev_desc; + struct lpss_clk_data *clk_data; if (!lpss_clk_dev) lpt_register_clock_device(); - if (!dev_desc->clk_parent || !pdata->mmio_base + clk_data = platform_get_drvdata(lpss_clk_dev); + if (!clk_data) + return -ENODEV; + + if (dev_desc->clkdev_name) { + clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name, + dev_name(&adev->dev)); + return 0; + } + + if (!pdata->mmio_base || pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE) return -ENODATA; pdata->clk = clk_register_gate(NULL, dev_name(&adev->dev), - dev_desc->clk_parent, 0, + clk_data->name, 0, pdata->mmio_base + dev_desc->prv_offset, 0, 0, NULL); if (IS_ERR(pdata->clk)) @@ -146,15 +164,24 @@ static int acpi_lpss_create_device(struct acpi_device *adev, if (dev_desc->clk_required) { ret = register_device_clock(adev, pdata); if (ret) { - /* - * Skip the device, but don't terminate the namespace - * scan. - */ - kfree(pdata); - return 0; + /* Skip the device, but continue the namespace scan. */ + ret = 0; + goto err_out; } } + /* + * This works around a known issue in ACPI tables where LPSS devices + * have _PS0 and _PS3 without _PSC (and no power resources), so + * acpi_bus_init_power() will assume that the BIOS has put them into D0. + */ + ret = acpi_device_fix_up_power(adev); + if (ret) { + /* Skip the device, but continue the namespace scan. */ + ret = 0; + goto err_out; + } + adev->driver_data = pdata; ret = acpi_create_platform_device(adev, id); if (ret > 0) diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c index fefc2ca7cc3e..33dc6a004802 100644 --- a/drivers/acpi/apei/cper.c +++ b/drivers/acpi/apei/cper.c @@ -250,10 +250,6 @@ static const char *cper_pcie_port_type_strs[] = { static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, const struct acpi_hest_generic_data *gdata) { -#ifdef CONFIG_ACPI_APEI_PCIEAER - struct pci_dev *dev; -#endif - if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ? @@ -285,20 +281,6 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, printk( "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", pfx, pcie->bridge.secondary_status, pcie->bridge.control); -#ifdef CONFIG_ACPI_APEI_PCIEAER - dev = pci_get_domain_bus_and_slot(pcie->device_id.segment, - pcie->device_id.bus, pcie->device_id.function); - if (!dev) { - pr_err("PCI AER Cannot get PCI device %04x:%02x:%02x.%d\n", - pcie->device_id.segment, pcie->device_id.bus, - pcie->device_id.slot, pcie->device_id.function); - return; - } - if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) - cper_print_aer(pfx, dev, gdata->error_severity, - (struct aer_capability_regs *) pcie->aer_info); - pci_dev_put(dev); -#endif } static const char *apei_estatus_section_flag_strs[] = { diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index d668a8ae602b..fcd7d91cec34 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -454,7 +454,9 @@ static void ghes_do_proc(struct ghes *ghes, aer_severity = cper_severity_to_aer(sev); aer_recover_queue(pcie_err->device_id.segment, pcie_err->device_id.bus, - devfn, aer_severity); + devfn, aer_severity, + (struct aer_capability_regs *) + pcie_err->aer_info); } } @@ -917,13 +919,14 @@ static int ghes_probe(struct platform_device *ghes_dev) break; case ACPI_HEST_NOTIFY_EXTERNAL: /* External interrupt vector is GSI */ - if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) { + rc = acpi_gsi_to_irq(generic->notify.vector, &ghes->irq); + if (rc) { pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n", generic->header.source_id); goto err_edac_unreg; } - if (request_irq(ghes->irq, ghes_irq_func, - 0, "GHES IRQ", ghes)) { + rc = request_irq(ghes->irq, ghes_irq_func, 0, "GHES IRQ", ghes); + if (rc) { pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n", generic->header.source_id); goto err_edac_unreg; diff --git a/drivers/acpi/csrt.c b/drivers/acpi/csrt.c deleted file mode 100644 index 5c15a91faf0b..000000000000 --- a/drivers/acpi/csrt.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Support for Core System Resources Table (CSRT) - * - * Copyright (C) 2013, Intel Corporation - * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> - * Andy Shevchenko <andriy.shevchenko@linux.intel.com> - * - * 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. - */ - -#define pr_fmt(fmt) "ACPI: CSRT: " fmt - -#include <linux/acpi.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/sizes.h> - -ACPI_MODULE_NAME("CSRT"); - -static int __init acpi_csrt_parse_shared_info(struct platform_device *pdev, - const struct acpi_csrt_group *grp) -{ - const struct acpi_csrt_shared_info *si; - struct resource res[3]; - size_t nres; - int ret; - - memset(res, 0, sizeof(res)); - nres = 0; - - si = (const struct acpi_csrt_shared_info *)&grp[1]; - /* - * The peripherals that are listed on CSRT typically support only - * 32-bit addresses so we only use the low part of MMIO base for - * now. - */ - if (!si->mmio_base_high && si->mmio_base_low) { - /* - * There is no size of the memory resource in shared_info - * so we assume that it is 4k here. - */ - res[nres].start = si->mmio_base_low; - res[nres].end = res[0].start + SZ_4K - 1; - res[nres++].flags = IORESOURCE_MEM; - } - - if (si->gsi_interrupt) { - int irq = acpi_register_gsi(NULL, si->gsi_interrupt, - si->interrupt_mode, - si->interrupt_polarity); - res[nres].start = irq; - res[nres].end = irq; - res[nres++].flags = IORESOURCE_IRQ; - } - - if (si->base_request_line || si->num_handshake_signals) { - /* - * We pass the driver a DMA resource describing the range - * of request lines the device supports. - */ - res[nres].start = si->base_request_line; - res[nres].end = res[nres].start + si->num_handshake_signals - 1; - res[nres++].flags = IORESOURCE_DMA; - } - - ret = platform_device_add_resources(pdev, res, nres); - if (ret) { - if (si->gsi_interrupt) - acpi_unregister_gsi(si->gsi_interrupt); - return ret; - } - - return 0; -} - -static int __init -acpi_csrt_parse_resource_group(const struct acpi_csrt_group *grp) -{ - struct platform_device *pdev; - char vendor[5], name[16]; - int ret, i; - - vendor[0] = grp->vendor_id; - vendor[1] = grp->vendor_id >> 8; - vendor[2] = grp->vendor_id >> 16; - vendor[3] = grp->vendor_id >> 24; - vendor[4] = '\0'; - - if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info)) - return -ENODEV; - - snprintf(name, sizeof(name), "%s%04X", vendor, grp->device_id); - pdev = platform_device_alloc(name, PLATFORM_DEVID_AUTO); - if (!pdev) - return -ENOMEM; - - /* Add resources based on the shared info */ - ret = acpi_csrt_parse_shared_info(pdev, grp); - if (ret) - goto fail; - - ret = platform_device_add(pdev); - if (ret) - goto fail; - - for (i = 0; i < pdev->num_resources; i++) - dev_dbg(&pdev->dev, "%pR\n", &pdev->resource[i]); - - return 0; - -fail: - platform_device_put(pdev); - return ret; -} - -/* - * CSRT or Core System Resources Table is a proprietary ACPI table - * introduced by Microsoft. This table can contain devices that are not in - * the system DSDT table. In particular DMA controllers might be described - * here. - * - * We present these devices as normal platform devices that don't have ACPI - * IDs or handle. The platform device name will be something like - * <VENDOR><DEVID>.<n>.auto for example: INTL9C06.0.auto. - */ -void __init acpi_csrt_init(void) -{ - struct acpi_csrt_group *grp, *end; - struct acpi_table_csrt *csrt; - acpi_status status; - int ret; - - status = acpi_get_table(ACPI_SIG_CSRT, 0, - (struct acpi_table_header **)&csrt); - if (ACPI_FAILURE(status)) { - if (status != AE_NOT_FOUND) - pr_warn("failed to get the CSRT table\n"); - return; - } - - pr_debug("parsing CSRT table for devices\n"); - - grp = (struct acpi_csrt_group *)(csrt + 1); - end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length); - - while (grp < end) { - ret = acpi_csrt_parse_resource_group(grp); - if (ret) { - pr_warn("error in parsing resource group: %d\n", ret); - return; - } - - grp = (struct acpi_csrt_group *)((void *)grp + grp->length); - } -} diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 96de787e6104..31c217a42839 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -37,68 +37,6 @@ #define _COMPONENT ACPI_POWER_COMPONENT ACPI_MODULE_NAME("device_pm"); -static DEFINE_MUTEX(acpi_pm_notifier_lock); - -/** - * acpi_add_pm_notifier - Register PM notifier for given ACPI device. - * @adev: ACPI device to add the notifier for. - * @context: Context information to pass to the notifier routine. - * - * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of - * PM wakeup events. For example, wakeup events may be generated for bridges - * if one of the devices below the bridge is signaling wakeup, even if the - * bridge itself doesn't have a wakeup GPE associated with it. - */ -acpi_status acpi_add_pm_notifier(struct acpi_device *adev, - acpi_notify_handler handler, void *context) -{ - acpi_status status = AE_ALREADY_EXISTS; - - mutex_lock(&acpi_pm_notifier_lock); - - if (adev->wakeup.flags.notifier_present) - goto out; - - status = acpi_install_notify_handler(adev->handle, - ACPI_SYSTEM_NOTIFY, - handler, context); - if (ACPI_FAILURE(status)) - goto out; - - adev->wakeup.flags.notifier_present = true; - - out: - mutex_unlock(&acpi_pm_notifier_lock); - return status; -} - -/** - * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device. - * @adev: ACPI device to remove the notifier from. - */ -acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, - acpi_notify_handler handler) -{ - acpi_status status = AE_BAD_PARAMETER; - - mutex_lock(&acpi_pm_notifier_lock); - - if (!adev->wakeup.flags.notifier_present) - goto out; - - status = acpi_remove_notify_handler(adev->handle, - ACPI_SYSTEM_NOTIFY, - handler); - if (ACPI_FAILURE(status)) - goto out; - - adev->wakeup.flags.notifier_present = false; - - out: - mutex_unlock(&acpi_pm_notifier_lock); - return status; -} - /** * acpi_power_state_string - String representation of ACPI device power state. * @state: ACPI device power state to return the string representation of. @@ -340,16 +278,38 @@ int acpi_bus_init_power(struct acpi_device *device) if (result) return result; } else if (state == ACPI_STATE_UNKNOWN) { - /* No power resources and missing _PSC? Try to force D0. */ + /* + * No power resources and missing _PSC? Cross fingers and make + * it D0 in hope that this is what the BIOS put the device into. + * [We tried to force D0 here by executing _PS0, but that broke + * Toshiba P870-303 in a nasty way.] + */ state = ACPI_STATE_D0; - result = acpi_dev_pm_explicit_set(device, state); - if (result) - return result; } device->power.state = state; return 0; } +/** + * acpi_device_fix_up_power - Force device with missing _PSC into D0. + * @device: Device object whose power state is to be fixed up. + * + * Devices without power resources and _PSC, but having _PS0 and _PS3 defined, + * are assumed to be put into D0 by the BIOS. However, in some cases that may + * not be the case and this function should be used then. + */ +int acpi_device_fix_up_power(struct acpi_device *device) +{ + int ret = 0; + + if (!device->power.flags.power_resources + && !device->power.flags.explicit_get + && device->power.state == ACPI_STATE_D0) + ret = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0); + + return ret; +} + int acpi_bus_update_power(acpi_handle handle, int *state_p) { struct acpi_device *device; @@ -385,6 +345,69 @@ bool acpi_bus_power_manageable(acpi_handle handle) } EXPORT_SYMBOL(acpi_bus_power_manageable); +#ifdef CONFIG_PM +static DEFINE_MUTEX(acpi_pm_notifier_lock); + +/** + * acpi_add_pm_notifier - Register PM notifier for given ACPI device. + * @adev: ACPI device to add the notifier for. + * @context: Context information to pass to the notifier routine. + * + * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of + * PM wakeup events. For example, wakeup events may be generated for bridges + * if one of the devices below the bridge is signaling wakeup, even if the + * bridge itself doesn't have a wakeup GPE associated with it. + */ +acpi_status acpi_add_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler, void *context) +{ + acpi_status status = AE_ALREADY_EXISTS; + + mutex_lock(&acpi_pm_notifier_lock); + + if (adev->wakeup.flags.notifier_present) + goto out; + + status = acpi_install_notify_handler(adev->handle, + ACPI_SYSTEM_NOTIFY, + handler, context); + if (ACPI_FAILURE(status)) + goto out; + + adev->wakeup.flags.notifier_present = true; + + out: + mutex_unlock(&acpi_pm_notifier_lock); + return status; +} + +/** + * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device. + * @adev: ACPI device to remove the notifier from. + */ +acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler) +{ + acpi_status status = AE_BAD_PARAMETER; + + mutex_lock(&acpi_pm_notifier_lock); + + if (!adev->wakeup.flags.notifier_present) + goto out; + + status = acpi_remove_notify_handler(adev->handle, + ACPI_SYSTEM_NOTIFY, + handler); + if (ACPI_FAILURE(status)) + goto out; + + adev->wakeup.flags.notifier_present = false; + + out: + mutex_unlock(&acpi_pm_notifier_lock); + return status; +} + bool acpi_bus_can_wakeup(acpi_handle handle) { struct acpi_device *device; @@ -1023,3 +1046,4 @@ void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev) mutex_unlock(&adev->physical_node_lock); } EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent); +#endif /* CONFIG_PM */ diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 4fdea381ef21..ec117c6c996c 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -868,8 +868,10 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr, if (!count) return -EINVAL; + acpi_scan_lock_acquire(); begin_undock(dock_station); ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST); + acpi_scan_lock_release(); return ret ? ret: count; } static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 6f1afd9118c8..297cbf456f86 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -35,7 +35,6 @@ void acpi_pci_link_init(void); void acpi_pci_root_hp_init(void); void acpi_platform_init(void); int acpi_sysfs_init(void); -void acpi_csrt_init(void); #ifdef CONFIG_ACPI_CONTAINER void acpi_container_init(void); #else diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1dd6f6c85874..e427dc516c76 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -641,7 +641,9 @@ static void _handle_hotplug_event_root(struct work_struct *work) /* bus enumerate */ printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__, (char *)buffer.pointer); - if (!root) + if (root) + acpiphp_check_host_bridge(handle); + else handle_root_bridge_insertion(handle); break; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index f962047c6c85..288bb270f8ed 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -885,6 +885,7 @@ int acpi_add_power_resource(acpi_handle handle) ACPI_STA_DEFAULT); mutex_init(&resource->resource_lock); INIT_LIST_HEAD(&resource->dependent); + INIT_LIST_HEAD(&resource->list_node); resource->name = device->pnp.bus_id; strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_POWER_CLASS); diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index a3868f6c222a..3322b47ab7ca 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -304,7 +304,8 @@ static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) } static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, - u8 triggering, u8 polarity, u8 shareable) + u8 triggering, u8 polarity, u8 shareable, + bool legacy) { int irq, p, t; @@ -317,14 +318,19 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, * In IO-APIC mode, use overrided attribute. Two reasons: * 1. BIOS bug in DSDT * 2. BIOS uses IO-APIC mode Interrupt Source Override + * + * We do this only if we are dealing with IRQ() or IRQNoFlags() + * resource (the legacy ISA resources). With modern ACPI 5 devices + * using extended IRQ descriptors we take the IRQ configuration + * from _CRS directly. */ - if (!acpi_get_override_irq(gsi, &t, &p)) { + if (legacy && !acpi_get_override_irq(gsi, &t, &p)) { u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; if (triggering != trig || polarity != pol) { pr_warning("ACPI: IRQ %d override to %s, %s\n", gsi, - t ? "edge" : "level", p ? "low" : "high"); + t ? "level" : "edge", p ? "low" : "high"); triggering = trig; polarity = pol; } @@ -373,7 +379,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, } acpi_dev_get_irqresource(res, irq->interrupts[index], irq->triggering, irq->polarity, - irq->sharable); + irq->sharable, true); break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: ext_irq = &ares->data.extended_irq; @@ -383,7 +389,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, } acpi_dev_get_irqresource(res, ext_irq->interrupts[index], ext_irq->triggering, ext_irq->polarity, - ext_irq->sharable); + ext_irq->sharable, false); break; default: return false; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c1bc608339a6..b14ac46948c9 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1017,11 +1017,8 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) return -ENOSYS; result = driver->ops.add(device); - if (result) { - device->driver = NULL; - device->driver_data = NULL; + if (result) return result; - } device->driver = driver; @@ -2043,7 +2040,6 @@ int __init acpi_scan_init(void) acpi_pci_link_init(); acpi_platform_init(); acpi_lpss_init(); - acpi_csrt_init(); acpi_container_init(); acpi_memory_hotplug_init(); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5b32e15a65ce..440eadf2d32c 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -458,12 +458,28 @@ static struct dmi_system_id video_dmi_table[] __initdata = { }, { .callback = video_ignore_initial_backlight, + .ident = "HP Pavilion g6 Notebook PC", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion g6 Notebook PC"), + }, + }, + { + .callback = video_ignore_initial_backlight, .ident = "HP 1000 Notebook PC", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP 1000 Notebook PC"), }, }, + { + .callback = video_ignore_initial_backlight, + .ident = "HP Pavilion m4", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion m4 Notebook PC"), + }, + }, {} }; @@ -1706,6 +1722,9 @@ static int acpi_video_bus_add(struct acpi_device *device) int error; acpi_status status; + if (device->handler) + return -EINVAL; + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, device->parent->handle, 1, acpi_video_bus_match, NULL, diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 66f67626f02e..e6bd910bc6ed 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -161,6 +161,14 @@ static struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"), }, }, + { + .callback = video_detect_force_vendor, + .ident = "Asus UL30A", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"), + }, + }, { }, }; diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 4e94ba29cb8d..9d0cf019ce59 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -2,7 +2,7 @@ /* * acard-ahci.c - ACard AHCI SATA support * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 251e57d38942..2b50dfdf1cfc 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1,7 +1,7 @@ /* * ahci.c - AHCI SATA support * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * @@ -423,6 +423,8 @@ static const struct pci_device_id ahci_pci_tbl[] = { .driver_data = board_ahci_yes_fbs }, /* 88se9125 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a), .driver_data = board_ahci_yes_fbs }, /* 88se9172 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172), + .driver_data = board_ahci_yes_fbs }, /* 88se9172 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192), .driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3), diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index b830e6c9fe49..10b14d45cfd2 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -1,7 +1,7 @@ /* * ahci.h - Common AHCI SATA definitions and declarations * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 2f48123d74c4..9a8a674e8fac 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -1,7 +1,7 @@ /* * ata_piix.c - Intel PATA/SATA controllers * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * @@ -151,6 +151,7 @@ enum piix_controller_ids { piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */ ich8_sata_snb, ich8_2port_sata_snb, + ich8_2port_sata_byt, }; struct piix_map_db { @@ -334,6 +335,9 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x8d60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, /* SATA Controller IDE (Wellsburg) */ { 0x8086, 0x8d68, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (BayTrail) */ + { 0x8086, 0x0F20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt }, + { 0x8086, 0x0F21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt }, { } /* terminate list */ }; @@ -441,6 +445,7 @@ static const struct piix_map_db *piix_map_db_table[] = { [tolapai_sata] = &tolapai_map_db, [ich8_sata_snb] = &ich8_map_db, [ich8_2port_sata_snb] = &ich8_2port_map_db, + [ich8_2port_sata_byt] = &ich8_2port_map_db, }; static struct pci_bits piix_enable_bits[] = { @@ -1254,6 +1259,16 @@ static struct ata_port_info piix_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &piix_sata_ops, }, + + [ich8_2port_sata_byt] = + { + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR | PIIX_FLAG_PIO16, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, + .port_ops = &piix_sata_ops, + }, + }; #define AHCI_PCI_BAR 5 diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 34c82167b962..a70ff154f586 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1,7 +1,7 @@ /* * libahci.c - Common AHCI SATA low-level routines * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 63c743baf920..f2184276539d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1,7 +1,7 @@ /* * libata-core.c - helper library for ATA * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * @@ -1602,6 +1602,12 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, qc->tf = *tf; if (cdb) memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + + /* some SATA bridges need us to indicate data xfer direction */ + if (tf->protocol == ATAPI_PROT_DMA && (dev->flags & ATA_DFLAG_DMADIR) && + dma_dir == DMA_FROM_DEVICE) + qc->tf.feature |= ATAPI_DMADIR; + qc->flags |= ATA_QCFLAG_RESULT_TF; qc->dma_dir = dma_dir; if (dma_dir != DMA_NONE) { diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index f9476fb3ac43..c69fcce505c0 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1,7 +1,7 @@ /* * libata-eh.c - libata error handling * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index dd310b27b24c..0101af541436 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1,7 +1,7 @@ /* * libata-scsi.c - helper library for ATA * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index d8af325a6bda..b603720b877d 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1,7 +1,7 @@ /* * libata-sff.c - helper library for PCI IDE BMDMA * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 505333340ad5..8ea6e6afd041 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -1,7 +1,7 @@ /* * pdc_adma.c - Pacific Digital Corporation ADMA * - * Maintained by: Mark Lord <mlord@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * * Copyright 2005 Mark Lord * diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index fb0dd87f8893..958ba2a420c3 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -1,7 +1,7 @@ /* * sata_promise.c - Promise SATA * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Mikael Pettersson <mikpe@it.uu.se> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 4799868bd733..249c8a289bfd 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -549,6 +549,7 @@ static void sata_rcar_bmdma_start(struct ata_queued_cmd *qc) /* start host DMA transaction */ dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG); + dmactl &= ~ATAPI_CONTROL1_STOP; dmactl |= ATAPI_CONTROL1_START; iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG); } @@ -618,17 +619,16 @@ static struct ata_port_operations sata_rcar_port_ops = { .bmdma_status = sata_rcar_bmdma_status, }; -static int sata_rcar_serr_interrupt(struct ata_port *ap) +static void sata_rcar_serr_interrupt(struct ata_port *ap) { struct sata_rcar_priv *priv = ap->host->private_data; struct ata_eh_info *ehi = &ap->link.eh_info; int freeze = 0; - int handled = 0; u32 serror; serror = ioread32(priv->base + SCRSERR_REG); if (!serror) - return 0; + return; DPRINTK("SError @host_intr: 0x%x\n", serror); @@ -641,7 +641,6 @@ static int sata_rcar_serr_interrupt(struct ata_port *ap) ata_ehi_push_desc(ehi, "%s", "hotplug"); freeze = serror & SERR_COMM_WAKE ? 0 : 1; - handled = 1; } /* freeze or abort */ @@ -649,11 +648,9 @@ static int sata_rcar_serr_interrupt(struct ata_port *ap) ata_port_freeze(ap); else ata_port_abort(ap); - - return handled; } -static int sata_rcar_ata_interrupt(struct ata_port *ap) +static void sata_rcar_ata_interrupt(struct ata_port *ap) { struct ata_queued_cmd *qc; int handled = 0; @@ -662,7 +659,9 @@ static int sata_rcar_ata_interrupt(struct ata_port *ap) if (qc) handled |= ata_bmdma_port_intr(ap, qc); - return handled; + /* be sure to clear ATA interrupt */ + if (!handled) + sata_rcar_check_status(ap); } static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance) @@ -677,20 +676,21 @@ static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance) spin_lock_irqsave(&host->lock, flags); sataintstat = ioread32(priv->base + SATAINTSTAT_REG); + sataintstat &= SATA_RCAR_INT_MASK; if (!sataintstat) goto done; /* ack */ - iowrite32(sataintstat & ~SATA_RCAR_INT_MASK, - priv->base + SATAINTSTAT_REG); + iowrite32(~sataintstat & 0x7ff, priv->base + SATAINTSTAT_REG); ap = host->ports[0]; if (sataintstat & SATAINTSTAT_ATA) - handled |= sata_rcar_ata_interrupt(ap); + sata_rcar_ata_interrupt(ap); if (sataintstat & SATAINTSTAT_SERR) - handled |= sata_rcar_serr_interrupt(ap); + sata_rcar_serr_interrupt(ap); + handled = 1; done: spin_unlock_irqrestore(&host->lock, flags); diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index a7b31672c4b7..0ae3ca4bf5c0 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -1,7 +1,7 @@ /* * sata_sil.c - Silicon Image SATA * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 7b7127a58f51..9947010afc0f 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -1,7 +1,7 @@ /* * sata_sx4.c - Promise SATA * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 5913ea9d57b2..87f056e54a9d 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -1,7 +1,7 @@ /* * sata_via.c - VIA Serial ATA controllers * - * Maintained by: Jeff Garzik <jgarzik@pobox.com> + * Maintained by: Tejun Heo <tj@kernel.org> * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 1a68f947ded8..d414331b480e 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -1295,6 +1295,7 @@ int subsys_virtual_register(struct bus_type *subsys, return subsys_register(subsys, groups, virtual_dir); } +EXPORT_SYMBOL_GPL(subsys_virtual_register); int __init buses_init(void) { diff --git a/drivers/base/core.c b/drivers/base/core.c index 016312437577..2499cefdcdf2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -572,9 +572,11 @@ int device_create_file(struct device *dev, if (dev) { WARN(((attr->attr.mode & S_IWUGO) && !attr->store), - "Write permission without 'store'\n"); + "Attribute %s: write permission without 'store'\n", + attr->attr.name); WARN(((attr->attr.mode & S_IRUGO) && !attr->show), - "Read permission without 'show'\n"); + "Attribute %s: read permission without 'show'\n", + attr->attr.name); error = sysfs_create_file(&dev->kobj, &attr->attr); } diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 4b1f9265887f..01e21037d8fe 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -450,8 +450,18 @@ static void fw_load_abort(struct firmware_priv *fw_priv) { struct firmware_buf *buf = fw_priv->buf; + /* + * There is a small window in which user can write to 'loading' + * between loading done and disappearance of 'loading' + */ + if (test_bit(FW_STATUS_DONE, &buf->status)) + return; + set_bit(FW_STATUS_ABORT, &buf->status); complete_all(&buf->completion); + + /* avoid user action after loading abort */ + fw_priv->buf = NULL; } #define is_fw_load_aborted(buf) \ @@ -528,7 +538,12 @@ static ssize_t firmware_loading_show(struct device *dev, struct device_attribute *attr, char *buf) { struct firmware_priv *fw_priv = to_firmware_priv(dev); - int loading = test_bit(FW_STATUS_LOADING, &fw_priv->buf->status); + int loading = 0; + + mutex_lock(&fw_lock); + if (fw_priv->buf) + loading = test_bit(FW_STATUS_LOADING, &fw_priv->buf->status); + mutex_unlock(&fw_lock); return sprintf(buf, "%d\n", loading); } @@ -570,12 +585,12 @@ static ssize_t firmware_loading_store(struct device *dev, const char *buf, size_t count) { struct firmware_priv *fw_priv = to_firmware_priv(dev); - struct firmware_buf *fw_buf = fw_priv->buf; + struct firmware_buf *fw_buf; int loading = simple_strtol(buf, NULL, 10); int i; mutex_lock(&fw_lock); - + fw_buf = fw_priv->buf; if (!fw_buf) goto out; @@ -777,10 +792,6 @@ static void firmware_class_timeout_work(struct work_struct *work) struct firmware_priv, timeout_work.work); mutex_lock(&fw_lock); - if (test_bit(FW_STATUS_DONE, &(fw_priv->buf->status))) { - mutex_unlock(&fw_lock); - return; - } fw_load_abort(fw_priv); mutex_unlock(&fw_lock); } @@ -861,8 +872,6 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, cancel_delayed_work_sync(&fw_priv->timeout_work); - fw_priv->buf = NULL; - device_remove_file(f_dev, &dev_attr_loading); err_del_bin_attr: device_remove_bin_file(f_dev, &firmware_attr_data); diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index aa0875f6f1b7..02f490bad30f 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -143,7 +143,7 @@ static int rbtree_show(struct seq_file *s, void *ignored) int registers = 0; int this_registers, average; - map->lock(map); + map->lock(map->lock_arg); mem_size = sizeof(*rbtree_ctx); mem_size += BITS_TO_LONGS(map->cache_present_nbits) * sizeof(long); @@ -170,7 +170,7 @@ static int rbtree_show(struct seq_file *s, void *ignored) seq_printf(s, "%d nodes, %d registers, average %d registers, used %zu bytes\n", nodes, registers, average, mem_size); - map->unlock(map); + map->unlock(map->lock_arg); return 0; } @@ -391,8 +391,6 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min, for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { rbnode = rb_entry(node, struct regcache_rbtree_node, node); - if (rbnode->base_reg < min) - continue; if (rbnode->base_reg > max) break; if (rbnode->base_reg + rbnode->blklen < min) diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 75923f2396bd..507ee2da0f6e 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -270,7 +270,7 @@ int regcache_sync(struct regmap *map) BUG_ON(!map->cache_ops || !map->cache_ops->sync); - map->lock(map); + map->lock(map->lock_arg); /* Remember the initial bypass state */ bypass = map->cache_bypass; dev_dbg(map->dev, "Syncing %s cache\n", @@ -306,7 +306,7 @@ out: trace_regcache_sync(map->dev, name, "stop"); /* Restore the bypass state */ map->cache_bypass = bypass; - map->unlock(map); + map->unlock(map->lock_arg); return ret; } @@ -333,7 +333,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min, BUG_ON(!map->cache_ops || !map->cache_ops->sync); - map->lock(map); + map->lock(map->lock_arg); /* Remember the initial bypass state */ bypass = map->cache_bypass; @@ -352,7 +352,7 @@ out: trace_regcache_sync(map->dev, name, "stop region"); /* Restore the bypass state */ map->cache_bypass = bypass; - map->unlock(map); + map->unlock(map->lock_arg); return ret; } @@ -372,11 +372,11 @@ EXPORT_SYMBOL_GPL(regcache_sync_region); */ void regcache_cache_only(struct regmap *map, bool enable) { - map->lock(map); + map->lock(map->lock_arg); WARN_ON(map->cache_bypass && enable); map->cache_only = enable; trace_regmap_cache_only(map->dev, enable); - map->unlock(map); + map->unlock(map->lock_arg); } EXPORT_SYMBOL_GPL(regcache_cache_only); @@ -391,9 +391,9 @@ EXPORT_SYMBOL_GPL(regcache_cache_only); */ void regcache_mark_dirty(struct regmap *map) { - map->lock(map); + map->lock(map->lock_arg); map->cache_dirty = true; - map->unlock(map); + map->unlock(map->lock_arg); } EXPORT_SYMBOL_GPL(regcache_mark_dirty); @@ -410,11 +410,11 @@ EXPORT_SYMBOL_GPL(regcache_mark_dirty); */ void regcache_cache_bypass(struct regmap *map, bool enable) { - map->lock(map); + map->lock(map->lock_arg); WARN_ON(map->cache_only && enable); map->cache_bypass = enable; trace_regmap_cache_bypass(map->dev, enable); - map->unlock(map); + map->unlock(map->lock_arg); } EXPORT_SYMBOL_GPL(regcache_cache_bypass); diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 23b701f5fd2f..975719bc3450 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -265,6 +265,7 @@ static ssize_t regmap_map_write_file(struct file *file, char *start = buf; unsigned long reg, value; struct regmap *map = file->private_data; + int ret; buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) @@ -282,7 +283,9 @@ static ssize_t regmap_map_write_file(struct file *file, /* Userspace has been fiddling around behind the kernel's back */ add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE); - regmap_write(map, reg, value); + ret = regmap_write(map, reg, value); + if (ret < 0) + return ret; return buf_size; } #else diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index bca9c80056fe..8bffa5c9818c 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -84,6 +84,8 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = { { BCMA_CORE_I2S, "I2S" }, { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" }, { BCMA_CORE_SHIM, "SHIM" }, + { BCMA_CORE_PCIE2, "PCIe Gen2" }, + { BCMA_CORE_ARM_CR4, "ARM CR4" }, { BCMA_CORE_DEFAULT, "Default" }, }; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index f1a29f8e9d33..9bf4371755f2 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -117,13 +117,13 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector) spin_lock(&brd->brd_lock); idx = sector >> PAGE_SECTORS_SHIFT; + page->index = idx; if (radix_tree_insert(&brd->brd_pages, idx, page)) { __free_page(page); page = radix_tree_lookup(&brd->brd_pages, idx); BUG_ON(!page); BUG_ON(page->index != idx); - } else - page->index = idx; + } spin_unlock(&brd->brd_lock); radix_tree_preload_end(); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 6374dc103521..62b6c2cc80b5 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -168,8 +168,6 @@ static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id); static int cciss_open(struct block_device *bdev, fmode_t mode); static int cciss_unlocked_open(struct block_device *bdev, fmode_t mode); static void cciss_release(struct gendisk *disk, fmode_t mode); -static int do_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg); static int cciss_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg); static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo); @@ -235,7 +233,7 @@ static const struct block_device_operations cciss_fops = { .owner = THIS_MODULE, .open = cciss_unlocked_open, .release = cciss_release, - .ioctl = do_ioctl, + .ioctl = cciss_ioctl, .getgeo = cciss_getgeo, #ifdef CONFIG_COMPAT .compat_ioctl = cciss_compat_ioctl, @@ -1143,16 +1141,6 @@ static void cciss_release(struct gendisk *disk, fmode_t mode) mutex_unlock(&cciss_mutex); } -static int do_ioctl(struct block_device *bdev, fmode_t mode, - unsigned cmd, unsigned long arg) -{ - int ret; - mutex_lock(&cciss_mutex); - ret = cciss_ioctl(bdev, mode, cmd, arg); - mutex_unlock(&cciss_mutex); - return ret; -} - #ifdef CONFIG_COMPAT static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode, @@ -1179,7 +1167,7 @@ static int cciss_compat_ioctl(struct block_device *bdev, fmode_t mode, case CCISS_REGNEWD: case CCISS_RESCANDISK: case CCISS_GETLUNINFO: - return do_ioctl(bdev, mode, cmd, arg); + return cciss_ioctl(bdev, mode, cmd, arg); case CCISS_PASSTHRU32: return cciss_ioctl32_passthru(bdev, mode, cmd, arg); @@ -1219,7 +1207,7 @@ static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode, if (err) return -EFAULT; - err = do_ioctl(bdev, mode, CCISS_PASSTHRU, (unsigned long)p); + err = cciss_ioctl(bdev, mode, CCISS_PASSTHRU, (unsigned long)p); if (err) return err; err |= @@ -1261,7 +1249,7 @@ static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode, if (err) return -EFAULT; - err = do_ioctl(bdev, mode, CCISS_BIG_PASSTHRU, (unsigned long)p); + err = cciss_ioctl(bdev, mode, CCISS_BIG_PASSTHRU, (unsigned long)p); if (err) return err; err |= @@ -1311,11 +1299,14 @@ static int cciss_getpciinfo(ctlr_info_t *h, void __user *argp) static int cciss_getintinfo(ctlr_info_t *h, void __user *argp) { cciss_coalint_struct intinfo; + unsigned long flags; if (!argp) return -EINVAL; + spin_lock_irqsave(&h->lock, flags); intinfo.delay = readl(&h->cfgtable->HostWrite.CoalIntDelay); intinfo.count = readl(&h->cfgtable->HostWrite.CoalIntCount); + spin_unlock_irqrestore(&h->lock, flags); if (copy_to_user (argp, &intinfo, sizeof(cciss_coalint_struct))) return -EFAULT; @@ -1356,12 +1347,15 @@ static int cciss_setintinfo(ctlr_info_t *h, void __user *argp) static int cciss_getnodename(ctlr_info_t *h, void __user *argp) { NodeName_type NodeName; + unsigned long flags; int i; if (!argp) return -EINVAL; + spin_lock_irqsave(&h->lock, flags); for (i = 0; i < 16; i++) NodeName[i] = readb(&h->cfgtable->ServerName[i]); + spin_unlock_irqrestore(&h->lock, flags); if (copy_to_user(argp, NodeName, sizeof(NodeName_type))) return -EFAULT; return 0; @@ -1398,10 +1392,13 @@ static int cciss_setnodename(ctlr_info_t *h, void __user *argp) static int cciss_getheartbeat(ctlr_info_t *h, void __user *argp) { Heartbeat_type heartbeat; + unsigned long flags; if (!argp) return -EINVAL; + spin_lock_irqsave(&h->lock, flags); heartbeat = readl(&h->cfgtable->HeartBeat); + spin_unlock_irqrestore(&h->lock, flags); if (copy_to_user(argp, &heartbeat, sizeof(Heartbeat_type))) return -EFAULT; return 0; @@ -1410,10 +1407,13 @@ static int cciss_getheartbeat(ctlr_info_t *h, void __user *argp) static int cciss_getbustypes(ctlr_info_t *h, void __user *argp) { BusTypes_type BusTypes; + unsigned long flags; if (!argp) return -EINVAL; + spin_lock_irqsave(&h->lock, flags); BusTypes = readl(&h->cfgtable->BusTypes); + spin_unlock_irqrestore(&h->lock, flags); if (copy_to_user(argp, &BusTypes, sizeof(BusTypes_type))) return -EFAULT; return 0; diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 847107ef0cce..20dd52a2f92f 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3002,7 +3002,8 @@ static int mtip_hw_debugfs_init(struct driver_data *dd) static void mtip_hw_debugfs_exit(struct driver_data *dd) { - debugfs_remove_recursive(dd->dfs_node); + if (dd->dfs_node) + debugfs_remove_recursive(dd->dfs_node); } @@ -3863,7 +3864,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) struct driver_data *dd = queue->queuedata; struct scatterlist *sg; struct bio_vec *bvec; - int nents = 0; + int i, nents = 0; int tag = 0, unaligned = 0; if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) { @@ -3921,11 +3922,12 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) } /* Create the scatter list for this bio. */ - bio_for_each_segment(bvec, bio, nents) { + bio_for_each_segment(bvec, bio, i) { sg_set_page(&sg[nents], bvec->bv_page, bvec->bv_len, bvec->bv_offset); + nents++; } /* Issue the read/write. */ diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 8efdfaa44a59..ce79a590b45b 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -629,7 +629,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, struct nvme_command *cmnd; struct nvme_iod *iod; enum dma_data_direction dma_dir; - int cmdid, length, result = -ENOMEM; + int cmdid, length, result; u16 control; u32 dsmgmt; int psegs = bio_phys_segments(ns->queue, bio); @@ -640,6 +640,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, return result; } + result = -ENOMEM; iod = nvme_alloc_iod(psegs, bio->bi_size, GFP_ATOMIC); if (!iod) goto nomem; @@ -977,6 +978,8 @@ static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout) if (timeout && !time_after(now, info[cmdid].timeout)) continue; + if (info[cmdid].ctx == CMD_CTX_CANCELLED) + continue; dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid); ctx = cancel_cmdid(nvmeq, cmdid, &fn); fn(nvmeq->dev, ctx, &cqe); @@ -1206,7 +1209,7 @@ struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write, if (addr & 3) return ERR_PTR(-EINVAL); - if (!length) + if (!length || length > INT_MAX - PAGE_SIZE) return ERR_PTR(-EINVAL); offset = offset_in_page(addr); @@ -1227,7 +1230,8 @@ struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write, sg_init_table(sg, count); for (i = 0; i < count; i++) { sg_set_page(&sg[i], pages[i], - min_t(int, length, PAGE_SIZE - offset), offset); + min_t(unsigned, length, PAGE_SIZE - offset), + offset); length -= (PAGE_SIZE - offset); offset = 0; } @@ -1435,7 +1439,7 @@ static int nvme_user_admin_cmd(struct nvme_dev *dev, nvme_free_iod(dev, iod); } - if (!status && copy_to_user(&ucmd->result, &cmd.result, + if ((status >= 0) && copy_to_user(&ucmd->result, &cmd.result, sizeof(cmd.result))) status = -EFAULT; @@ -1633,7 +1637,8 @@ static int set_queue_count(struct nvme_dev *dev, int count) static int nvme_setup_io_queues(struct nvme_dev *dev) { - int result, cpu, i, nr_io_queues, db_bar_size, q_depth; + struct pci_dev *pdev = dev->pci_dev; + int result, cpu, i, nr_io_queues, db_bar_size, q_depth, q_count; nr_io_queues = num_online_cpus(); result = set_queue_count(dev, nr_io_queues); @@ -1642,14 +1647,14 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (result < nr_io_queues) nr_io_queues = result; + q_count = nr_io_queues; /* Deregister the admin queue's interrupt */ free_irq(dev->entry[0].vector, dev->queues[0]); db_bar_size = 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3)); if (db_bar_size > 8192) { iounmap(dev->bar); - dev->bar = ioremap(pci_resource_start(dev->pci_dev, 0), - db_bar_size); + dev->bar = ioremap(pci_resource_start(pdev, 0), db_bar_size); dev->dbs = ((void __iomem *)dev->bar) + 4096; dev->queues[0]->q_db = dev->dbs; } @@ -1657,19 +1662,36 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) for (i = 0; i < nr_io_queues; i++) dev->entry[i].entry = i; for (;;) { - result = pci_enable_msix(dev->pci_dev, dev->entry, - nr_io_queues); + result = pci_enable_msix(pdev, dev->entry, nr_io_queues); if (result == 0) { break; } else if (result > 0) { nr_io_queues = result; continue; } else { - nr_io_queues = 1; + nr_io_queues = 0; break; } } + if (nr_io_queues == 0) { + nr_io_queues = q_count; + for (;;) { + result = pci_enable_msi_block(pdev, nr_io_queues); + if (result == 0) { + for (i = 0; i < nr_io_queues; i++) + dev->entry[i].vector = i + pdev->irq; + break; + } else if (result > 0) { + nr_io_queues = result; + continue; + } else { + nr_io_queues = 1; + break; + } + } + } + result = queue_request_irq(dev, dev->queues[0], "nvme admin"); /* XXX: handle failure here */ @@ -1850,7 +1872,10 @@ static void nvme_free_dev(struct kref *kref) { struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref); nvme_dev_remove(dev); - pci_disable_msix(dev->pci_dev); + if (dev->pci_dev->msi_enabled) + pci_disable_msi(dev->pci_dev); + else if (dev->pci_dev->msix_enabled) + pci_disable_msix(dev->pci_dev); iounmap(dev->bar); nvme_release_instance(dev); nvme_release_prp_pools(dev); @@ -1923,8 +1948,14 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&dev->namespaces); dev->pci_dev = pdev; pci_set_drvdata(pdev, dev); - dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); + + if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); + else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + else + goto disable; + result = nvme_set_instance(dev); if (result) goto disable; @@ -1977,7 +2008,10 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) unmap: iounmap(dev->bar); disable_msix: - pci_disable_msix(pdev); + if (dev->pci_dev->msi_enabled) + pci_disable_msi(dev->pci_dev); + else if (dev->pci_dev->msix_enabled) + pci_disable_msix(dev->pci_dev); nvme_release_instance(dev); nvme_release_prp_pools(dev); disable: diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c index fed54b039893..102de2f52b5c 100644 --- a/drivers/block/nvme-scsi.c +++ b/drivers/block/nvme-scsi.c @@ -44,7 +44,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/version.h> #include <scsi/sg.h> #include <scsi/scsi.h> @@ -1654,7 +1653,7 @@ static void nvme_trans_modesel_save_bd(struct nvme_ns *ns, u8 *parm_list, } } -static u16 nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr, +static int nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr, u8 *mode_page, u8 page_code) { int res = SNTI_TRANSLATION_SUCCESS; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 3c08983e600a..f5d0ea11d9fd 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -83,7 +83,8 @@ #define MAX_SPEED 0xffff -#define ZONE(sector, pd) (((sector) + (pd)->offset) & ~((pd)->settings.size - 1)) +#define ZONE(sector, pd) (((sector) + (pd)->offset) & \ + ~(sector_t)((pd)->settings.size - 1)) static DEFINE_MUTEX(pktcdvd_mutex); static struct pktcdvd_device *pkt_devs[MAX_WRITERS]; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index d6d314027b5d..49394e3f31bc 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -519,8 +519,8 @@ static const struct block_device_operations rbd_bd_ops = { }; /* - * Initialize an rbd client instance. - * We own *ceph_opts. + * Initialize an rbd client instance. Success or not, this function + * consumes ceph_opts. */ static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts) { @@ -675,7 +675,8 @@ static int parse_rbd_opts_token(char *c, void *private) /* * Get a ceph client with specific addr and configuration, if one does - * not exist create it. + * not exist create it. Either way, ceph_opts is consumed by this + * function. */ static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts) { @@ -1035,12 +1036,16 @@ static const char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset) char *name; u64 segment; int ret; + char *name_format; name = kmem_cache_alloc(rbd_segment_name_cache, GFP_NOIO); if (!name) return NULL; segment = offset >> rbd_dev->header.obj_order; - ret = snprintf(name, MAX_OBJ_NAME_SIZE + 1, "%s.%012llx", + name_format = "%s.%012llx"; + if (rbd_dev->image_format == 2) + name_format = "%s.%016llx"; + ret = snprintf(name, MAX_OBJ_NAME_SIZE + 1, name_format, rbd_dev->header.object_prefix, segment); if (ret < 0 || ret > MAX_OBJ_NAME_SIZE) { pr_err("error formatting segment name for #%llu (%d)\n", @@ -4697,8 +4702,10 @@ out: return ret; } -/* Undo whatever state changes are made by v1 or v2 image probe */ - +/* + * Undo whatever state changes are made by v1 or v2 header info + * call. + */ static void rbd_dev_unprobe(struct rbd_device *rbd_dev) { struct rbd_image_header *header; @@ -4902,9 +4909,10 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping) int tmp; /* - * Get the id from the image id object. If it's not a - * format 2 image, we'll get ENOENT back, and we'll assume - * it's a format 1 image. + * Get the id from the image id object. Unless there's an + * error, rbd_dev->spec->image_id will be filled in with + * a dynamically-allocated string, and rbd_dev->image_format + * will be set to either 1 or 2. */ ret = rbd_dev_image_id(rbd_dev); if (ret) @@ -4992,7 +5000,6 @@ static ssize_t rbd_add(struct bus_type *bus, rc = PTR_ERR(rbdc); goto err_out_args; } - ceph_opts = NULL; /* rbd_dev client now owns this */ /* pick the pool */ osdc = &rbdc->client->osdc; @@ -5027,18 +5034,18 @@ static ssize_t rbd_add(struct bus_type *bus, rbd_dev->mapping.read_only = read_only; rc = rbd_dev_device_setup(rbd_dev); - if (!rc) - return count; + if (rc) { + rbd_dev_image_release(rbd_dev); + goto err_out_module; + } + + return count; - rbd_dev_image_release(rbd_dev); err_out_rbd_dev: rbd_dev_destroy(rbd_dev); err_out_client: rbd_put_client(rbdc); err_out_args: - if (ceph_opts) - ceph_destroy_options(ceph_opts); - kfree(rbd_opts); rbd_spec_put(spec); err_out_module: module_put(THIS_MODULE); diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index f8ef15f37c5e..3fd130fdfbc1 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1160,8 +1160,7 @@ static int ace_probe(struct platform_device *dev) dev_dbg(&dev->dev, "ace_probe(%p)\n", dev); /* device id and bus width */ - of_property_read_u32(dev->dev.of_node, "port-number", &id); - if (id < 0) + if (of_property_read_u32(dev->dev.of_node, "port-number", &id)) id = 0; if (of_find_property(dev->dev.of_node, "8-bit", NULL)) bus_width = ACE_BUS_WIDTH_8; diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index fdfd61a2d523..11a6104a1e4f 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -201,7 +201,7 @@ config BT_MRVL The core driver to support Marvell Bluetooth devices. This driver is required if you want to support - Marvell Bluetooth devices, such as 8688/8787/8797. + Marvell Bluetooth devices, such as 8688/8787/8797/8897. Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. @@ -214,7 +214,7 @@ config BT_MRVL_SDIO The driver for Marvell Bluetooth chipsets with SDIO interface. This driver is required if you want to use Marvell Bluetooth - devices with SDIO interface. Currently SD8688/SD8787/SD8797 + devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8897 chipsets are supported. Say Y here to compile support for Marvell BT-over-SDIO driver diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index c63488c54f4a..13693b7a0d5c 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -82,6 +82,23 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { .io_port_2 = 0x7a, }; +static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = { + .cfg = 0x00, + .host_int_mask = 0x02, + .host_intstatus = 0x03, + .card_status = 0x50, + .sq_read_base_addr_a0 = 0x60, + .sq_read_base_addr_a1 = 0x61, + .card_revision = 0xbc, + .card_fw_status0 = 0xc0, + .card_fw_status1 = 0xc1, + .card_rx_len = 0xc2, + .card_rx_unit = 0xc3, + .io_port_0 = 0xd8, + .io_port_1 = 0xd9, + .io_port_2 = 0xda, +}; + static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { .helper = "mrvl/sd8688_helper.bin", .firmware = "mrvl/sd8688.bin", @@ -103,6 +120,13 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { .sd_blksz_fw_dl = 256, }; +static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = { + .helper = NULL, + .firmware = "mrvl/sd8897_uapsta.bin", + .reg = &btmrvl_reg_88xx, + .sd_blksz_fw_dl = 256, +}; + static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8688 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), @@ -116,6 +140,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8797 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), .driver_data = (unsigned long) &btmrvl_sdio_sd8797 }, + /* Marvell SD8897 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E), + .driver_data = (unsigned long) &btmrvl_sdio_sd8897 }, { } /* Terminating entry */ }; @@ -1194,3 +1221,4 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin"); MODULE_FIRMWARE("mrvl/sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); +MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin"); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 0628d7b65c71..03c1dc1ab552 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -236,14 +236,14 @@ static int ati_configure(void) static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state) { pci_save_state(dev); - pci_set_power_state(dev, 3); + pci_set_power_state(dev, PCI_D3hot); return 0; } static int agp_ati_resume(struct pci_dev *dev) { - pci_set_power_state(dev, 0); + pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); return ati_configure(); diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 2e044338753c..1b192395a90c 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -603,7 +603,8 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_ops = kerninfo.vm_ops; } else if (io_remap_pfn_range(vma, vma->vm_start, (kerninfo.aper_base + offset) >> PAGE_SHIFT, - size, vma->vm_page_prot)) { + size, + pgprot_writecombine(vma->vm_page_prot))) { goto out_again; } mutex_unlock(&(agp_fe.agp_mutex)); @@ -618,8 +619,9 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma) if (kerninfo.vm_ops) { vma->vm_ops = kerninfo.vm_ops; } else if (io_remap_pfn_range(vma, vma->vm_start, - kerninfo.aper_base >> PAGE_SHIFT, - size, vma->vm_page_prot)) { + kerninfo.aper_base >> PAGE_SHIFT, + size, + pgprot_writecombine(vma->vm_page_prot))) { goto out_again; } mutex_unlock(&(agp_fe.agp_mutex)); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 62be3ec0da4b..be42a2312dc9 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -399,8 +399,8 @@ static void agp_nvidia_remove(struct pci_dev *pdev) #ifdef CONFIG_PM static int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state) { - pci_save_state (pdev); - pci_set_power_state (pdev, 3); + pci_save_state(pdev); + pci_set_power_state(pdev, PCI_D3hot); return 0; } @@ -408,7 +408,7 @@ static int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state) static int agp_nvidia_resume(struct pci_dev *pdev) { /* set power state 0 and restore PCI space */ - pci_set_power_state (pdev, 0); + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); /* reconfigure AGP hardware again */ diff --git a/drivers/char/lp.c b/drivers/char/lp.c index dafd9ac6428f..0913d79424d3 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -622,9 +622,12 @@ static int lp_do_ioctl(unsigned int minor, unsigned int cmd, return -EFAULT; break; case LPGETSTATUS: + if (mutex_lock_interruptible(&lp_table[minor].port_mutex)) + return -EINTR; lp_claim_parport_or_block (&lp_table[minor]); status = r_str(minor); lp_release_parport (&lp_table[minor]); + mutex_unlock(&lp_table[minor].port_mutex); if (copy_to_user(argp, &status, sizeof(int))) return -EFAULT; diff --git a/drivers/char/random.c b/drivers/char/random.c index cd9a6211dcad..35487e8ded59 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -865,16 +865,24 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, if (r->entropy_count / 8 < min + reserved) { nbytes = 0; } else { + int entropy_count, orig; +retry: + entropy_count = orig = ACCESS_ONCE(r->entropy_count); /* If limited, never pull more than available */ - if (r->limit && nbytes + reserved >= r->entropy_count / 8) - nbytes = r->entropy_count/8 - reserved; - - if (r->entropy_count / 8 >= nbytes + reserved) - r->entropy_count -= nbytes*8; - else - r->entropy_count = reserved; + if (r->limit && nbytes + reserved >= entropy_count / 8) + nbytes = entropy_count/8 - reserved; + + if (entropy_count / 8 >= nbytes + reserved) { + entropy_count -= nbytes*8; + if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) + goto retry; + } else { + entropy_count = reserved; + if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) + goto retry; + } - if (r->entropy_count < random_write_wakeup_thresh) + if (entropy_count < random_write_wakeup_thresh) wakeup_write = 1; } @@ -957,10 +965,23 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, { ssize_t ret = 0, i; __u8 tmp[EXTRACT_SIZE]; + unsigned long flags; /* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */ - if (fips_enabled && !r->last_data_init) - nbytes += EXTRACT_SIZE; + if (fips_enabled) { + spin_lock_irqsave(&r->lock, flags); + if (!r->last_data_init) { + r->last_data_init = true; + spin_unlock_irqrestore(&r->lock, flags); + trace_extract_entropy(r->name, EXTRACT_SIZE, + r->entropy_count, _RET_IP_); + xfer_secondary_pool(r, EXTRACT_SIZE); + extract_buf(r, tmp); + spin_lock_irqsave(&r->lock, flags); + memcpy(r->last_data, tmp, EXTRACT_SIZE); + } + spin_unlock_irqrestore(&r->lock, flags); + } trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_); xfer_secondary_pool(r, nbytes); @@ -970,19 +991,6 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, extract_buf(r, tmp); if (fips_enabled) { - unsigned long flags; - - - /* prime last_data value if need be, per fips 140-2 */ - if (!r->last_data_init) { - spin_lock_irqsave(&r->lock, flags); - memcpy(r->last_data, tmp, EXTRACT_SIZE); - r->last_data_init = true; - nbytes -= EXTRACT_SIZE; - spin_unlock_irqrestore(&r->lock, flags); - extract_buf(r, tmp); - } - spin_lock_irqsave(&r->lock, flags); if (!memcmp(tmp, r->last_data, EXTRACT_SIZE)) panic("Hardware RNG duplicated output!\n"); diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 4945bd3d18d0..d5d2e4a985aa 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -179,7 +179,6 @@ static int __init ttyprintk_init(void) { int ret = -ENOMEM; - tpk_port.port.ops = &null_ops; mutex_init(&tpk_port.port_write_mutex); ttyprintk_driver = tty_alloc_driver(1, @@ -190,6 +189,7 @@ static int __init ttyprintk_init(void) return PTR_ERR(ttyprintk_driver); tty_port_init(&tpk_port.port); + tpk_port.port.ops = &null_ops; ttyprintk_driver->driver_name = "ttyprintk"; ttyprintk_driver->name = "ttyprintk"; diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 892728412e9d..24f553673b72 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -932,7 +932,7 @@ static unsigned long si5351_clkout_recalc_rate(struct clk_hw *hw, unsigned char reg; unsigned char rdiv; - if (hwdata->num > 5) + if (hwdata->num <= 5) reg = si5351_msynth_params_address(hwdata->num) + 2; else reg = SI5351_CLK6_7_OUTPUT_DIVIDER; @@ -1477,6 +1477,16 @@ static int si5351_i2c_probe(struct i2c_client *client, return -EINVAL; } drvdata->onecell.clks[n] = clk; + + /* set initial clkout rate */ + if (pdata->clkout[n].rate != 0) { + int ret; + ret = clk_set_rate(clk, pdata->clkout[n].rate); + if (ret != 0) { + dev_err(&client->dev, "Cannot set rate : %d\n", + ret); + } + } } ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index debf688afa8e..553ac35bcc91 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c @@ -183,7 +183,7 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate, writel(divisor, cdev->div_reg); vt8500_pmc_wait_busy(); - spin_lock_irqsave(cdev->lock, flags); + spin_unlock_irqrestore(cdev->lock, flags); return 0; } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 934cfd18f72d..1144e8c7579d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1955,6 +1955,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) /* XXX the notifier code should handle this better */ if (!cn->notifier_head.head) { srcu_cleanup_notifier_head(&cn->notifier_head); + list_del(&cn->node); kfree(cn); } diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index d0e5eed146de..4faf0afc44cd 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c @@ -10,6 +10,7 @@ */ #include <linux/clk.h> +#include <linux/clk/mxs.h> #include <linux/clkdev.h> #include <linux/err.h> #include <linux/init.h> diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index d0940e69d034..3c1f88868f29 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -791,7 +791,8 @@ struct samsung_gate_clock exynos4210_gate_clks[] __initdata = { GATE(smmu_pcie, "smmu_pcie", "aclk133", GATE_IP_FSYS, 18, 0, 0), GATE(modemif, "modemif", "aclk100", GATE_IP_PERIL, 28, 0, 0), GATE(chipid, "chipid", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0), - GATE(sysreg, "sysreg", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0), + GATE(sysreg, "sysreg", "aclk100", E4210_GATE_IP_PERIR, 0, + CLK_IGNORE_UNUSED, 0), GATE(hdmi_cec, "hdmi_cec", "aclk100", E4210_GATE_IP_PERIR, 11, 0, 0), GATE(smmu_rotator, "smmu_rotator", "aclk200", E4210_GATE_IP_IMAGE, 4, 0, 0), @@ -819,7 +820,8 @@ struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = { GATE(smmu_mdma, "smmu_mdma", "aclk200", E4X12_GATE_IP_IMAGE, 5, 0, 0), GATE(mipi_hsi, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0), GATE(chipid, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, 0, 0), - GATE(sysreg, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1, 0, 0), + GATE(sysreg, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1, + CLK_IGNORE_UNUSED, 0), GATE(hdmi_cec, "hdmi_cec", "aclk100", E4X12_GATE_IP_PERIR, 11, 0, 0), GATE(sclk_mdnie0, "sclk_mdnie0", "div_mdnie0", SRC_MASK_LCD0, 4, CLK_SET_RATE_PARENT, 0), diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 5c97e75924a8..22d7699e7ced 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -155,7 +155,7 @@ static __initdata unsigned long exynos5250_clk_regs[] = { /* list of all parent clock list */ PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; -PNAME(mout_cpu_p) = { "mout_apll", "mout_mpll", }; +PNAME(mout_cpu_p) = { "mout_apll", "sclk_mpll", }; PNAME(mout_mpll_fout_p) = { "fout_mplldiv2", "fout_mpll" }; PNAME(mout_mpll_p) = { "fin_pll", "mout_mpll_fout" }; PNAME(mout_bpll_fout_p) = { "fout_bplldiv2", "fout_bpll" }; @@ -208,10 +208,10 @@ struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initdata = { }; struct samsung_mux_clock exynos5250_mux_clks[] __initdata = { - MUX(none, "mout_apll", mout_apll_p, SRC_CPU, 0, 1), - MUX(none, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1), + MUX_A(none, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, "mout_apll"), + MUX_A(none, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1, "mout_cpu"), MUX(none, "mout_mpll_fout", mout_mpll_fout_p, PLL_DIV2_SEL, 4, 1), - MUX(none, "sclk_mpll", mout_mpll_p, SRC_CORE1, 8, 1), + MUX_A(none, "sclk_mpll", mout_mpll_p, SRC_CORE1, 8, 1, "mout_mpll"), MUX(none, "mout_bpll_fout", mout_bpll_fout_p, PLL_DIV2_SEL, 0, 1), MUX(none, "sclk_bpll", mout_bpll_p, SRC_CDREX, 0, 1), MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP2, 0, 1), @@ -378,7 +378,7 @@ struct samsung_gate_clock exynos5250_gate_clks[] __initdata = { GATE(hsi2c3, "hsi2c3", "aclk66", GATE_IP_PERIC, 31, 0, 0), GATE(chipid, "chipid", "aclk66", GATE_IP_PERIS, 0, 0, 0), GATE(sysreg, "sysreg", "aclk66", GATE_IP_PERIS, 1, 0, 0), - GATE(pmu, "pmu", "aclk66", GATE_IP_PERIS, 2, 0, 0), + GATE(pmu, "pmu", "aclk66", GATE_IP_PERIS, 2, CLK_IGNORE_UNUSED, 0), GATE(tzpc0, "tzpc0", "aclk66", GATE_IP_PERIS, 6, 0, 0), GATE(tzpc1, "tzpc1", "aclk66", GATE_IP_PERIS, 7, 0, 0), GATE(tzpc2, "tzpc2", "aclk66", GATE_IP_PERIS, 8, 0, 0), diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 89135f6be116..362f12dcd944 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -111,7 +111,8 @@ static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw); - u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1; + u32 mdiv, pdiv, sdiv, pll_con0, pll_con1; + s16 kdiv; u64 fvco = parent_rate; pll_con0 = __raw_readl(pll->con_reg); @@ -119,7 +120,7 @@ static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw, mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK; pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK; sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK; - kdiv = pll_con1 & PLL36XX_KDIV_MASK; + kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK); fvco *= (mdiv << 16) + kdiv; do_div(fvco, (pdiv << sdiv)); diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c index f9ec43fd1320..080c3c5e33f6 100644 --- a/drivers/clk/spear/spear3xx_clock.c +++ b/drivers/clk/spear/spear3xx_clock.c @@ -369,7 +369,7 @@ static void __init spear320_clk_init(void __iomem *soc_config_base) clk_register_clkdev(clk, NULL, "60100000.serial"); } #else -static inline void spear320_clk_init(void) { } +static inline void spear320_clk_init(void __iomem *soc_config_base) { } #endif void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_base) diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 8292a00c3de9..075db0c99edb 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -872,6 +872,14 @@ static void __init tegra20_periph_clk_init(void) struct clk *clk; int i; + /* ac97 */ + clk = tegra_clk_register_periph_gate("ac97", "pll_a_out0", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 3, &periph_l_regs, + periph_clk_enb_refcnt); + clk_register_clkdev(clk, NULL, "tegra20-ac97"); + clks[ac97] = clk; + /* apbdma */ clk = tegra_clk_register_periph_gate("apbdma", "pclk", 0, clk_base, 0, 34, &periph_h_regs, @@ -1234,9 +1242,6 @@ static __initdata struct tegra_clk_init_table init_table[] = { {uartc, pll_p, 0, 0}, {uartd, pll_p, 0, 0}, {uarte, pll_p, 0, 0}, - {usbd, clk_max, 12000000, 0}, - {usb2, clk_max, 12000000, 0}, - {usb3, clk_max, 12000000, 0}, {pll_a, clk_max, 56448000, 1}, {pll_a_out0, clk_max, 11289600, 1}, {cdev1, clk_max, 0, 1}, diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index c6921f538e28..ba99e3844106 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -1598,6 +1598,12 @@ static void __init tegra30_periph_clk_init(void) clk_register_clkdev(clk, "afi", "tegra-pcie"); clks[afi] = clk; + /* pciex */ + clk = tegra_clk_register_periph_gate("pciex", "pll_e", 0, clk_base, 0, + 74, &periph_u_regs, periph_clk_enb_refcnt); + clk_register_clkdev(clk, "pciex", "tegra-pcie"); + clks[pciex] = clk; + /* kfuse */ clk = tegra_clk_register_periph_gate("kfuse", "clk_m", TEGRA_PERIPH_ON_APB, @@ -1716,11 +1722,6 @@ static void __init tegra30_fixed_clk_init(void) 1, 0, &cml_lock); clk_register_clkdev(clk, "cml1", NULL); clks[cml1] = clk; - - /* pciex */ - clk = clk_register_fixed_rate(NULL, "pciex", "pll_e", 0, 100000000); - clk_register_clkdev(clk, "pciex", NULL); - clks[pciex] = clk; } static void __init tegra30_osc_clk_init(void) diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c index bc7e9bde792b..e364c9d4aa60 100644 --- a/drivers/clk/ux500/clk-sysctrl.c +++ b/drivers/clk/ux500/clk-sysctrl.c @@ -145,7 +145,13 @@ static struct clk *clk_reg_sysctrl(struct device *dev, return ERR_PTR(-ENOMEM); } - for (i = 0; i < num_parents; i++) { + /* set main clock registers */ + clk->reg_sel[0] = reg_sel[0]; + clk->reg_bits[0] = reg_bits[0]; + clk->reg_mask[0] = reg_mask[0]; + + /* handle clocks with more than one parent */ + for (i = 1; i < num_parents; i++) { clk->reg_sel[i] = reg_sel[i]; clk->reg_bits[i] = reg_bits[i]; clk->reg_mask[i] = reg_mask[i]; diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c index 0b4f35a5ffc2..80069c370a47 100644 --- a/drivers/clk/ux500/u8500_clk.c +++ b/drivers/clk/ux500/u8500_clk.c @@ -325,7 +325,7 @@ void u8500_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base, clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", clkrst3_base, BIT(0), 0); clk_register_clkdev(clk, "fsmc", NULL); - clk_register_clkdev(clk, NULL, "smsc911x"); + clk_register_clkdev(clk, NULL, "smsc911x.0"); clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", clkrst3_base, BIT(1), 0); diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c index 5cf4f4686406..4f45eee9e33b 100644 --- a/drivers/clk/x86/clk-lpt.c +++ b/drivers/clk/x86/clk-lpt.c @@ -15,22 +15,29 @@ #include <linux/clk-provider.h> #include <linux/err.h> #include <linux/module.h> +#include <linux/platform_data/clk-lpss.h> #include <linux/platform_device.h> #define PRV_CLOCK_PARAMS 0x800 static int lpt_clk_probe(struct platform_device *pdev) { + struct lpss_clk_data *drvdata; struct clk *clk; + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + /* LPSS free running clock */ - clk = clk_register_fixed_rate(&pdev->dev, "lpss_clk", NULL, CLK_IS_ROOT, - 100000000); + drvdata->name = "lpss_clk"; + clk = clk_register_fixed_rate(&pdev->dev, drvdata->name, NULL, + CLK_IS_ROOT, 100000000); if (IS_ERR(clk)) return PTR_ERR(clk); - /* Shared DMA clock */ - clk_register_clkdev(clk, "hclk", "INTL9C60.0.auto"); + drvdata->clk = clk; + platform_set_drvdata(pdev, drvdata); return 0; } diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index 2b8a8c374548..6bd63d63d356 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -272,7 +272,7 @@ config X86_LONGHAUL config X86_E_POWERSAVER tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)" select CPU_FREQ_TABLE - depends on X86_32 + depends on X86_32 && ACPI_PROCESSOR help This adds the CPUFreq driver for VIA C7 processors. However, this driver does not have any safeguards to prevent operating the CPU out of spec diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 11b8b4b54ceb..edc089e9d0c4 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -347,11 +347,11 @@ static u32 get_cur_val(const struct cpumask *mask) switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) { case SYSTEM_INTEL_MSR_CAPABLE: cmd.type = SYSTEM_INTEL_MSR_CAPABLE; - cmd.addr.msr.reg = MSR_IA32_PERF_STATUS; + cmd.addr.msr.reg = MSR_IA32_PERF_CTL; break; case SYSTEM_AMD_MSR_CAPABLE: cmd.type = SYSTEM_AMD_MSR_CAPABLE; - cmd.addr.msr.reg = MSR_AMD_PERF_STATUS; + cmd.addr.msr.reg = MSR_AMD_PERF_CTL; break; case SYSTEM_IO_CAPABLE: cmd.type = SYSTEM_IO_CAPABLE; diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c index 173ed059d95f..fd9e3ea6a480 100644 --- a/drivers/cpufreq/arm_big_little_dt.c +++ b/drivers/cpufreq/arm_big_little_dt.c @@ -19,70 +19,75 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/cpu.h> #include <linux/cpufreq.h> #include <linux/device.h> #include <linux/export.h> #include <linux/module.h> #include <linux/of.h> #include <linux/opp.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/types.h> #include "arm_big_little.h" -static int dt_init_opp_table(struct device *cpu_dev) +/* get cpu node with valid operating-points */ +static struct device_node *get_cpu_node_with_valid_op(int cpu) { - struct device_node *np, *parent; - int count = 0, ret; + struct device_node *np = NULL, *parent; + int count = 0; parent = of_find_node_by_path("/cpus"); if (!parent) { pr_err("failed to find OF /cpus\n"); - return -ENOENT; + return NULL; } for_each_child_of_node(parent, np) { - if (count++ != cpu_dev->id) + if (count++ != cpu) continue; if (!of_get_property(np, "operating-points", NULL)) { - ret = -ENODATA; - } else { - cpu_dev->of_node = np; - ret = of_init_opp_table(cpu_dev); + of_node_put(np); + np = NULL; } - of_node_put(np); - of_node_put(parent); - return ret; + break; } - return -ENODEV; + of_node_put(parent); + return np; +} + +static int dt_init_opp_table(struct device *cpu_dev) +{ + struct device_node *np; + int ret; + + np = get_cpu_node_with_valid_op(cpu_dev->id); + if (!np) + return -ENODATA; + + cpu_dev->of_node = np; + ret = of_init_opp_table(cpu_dev); + of_node_put(np); + + return ret; } static int dt_get_transition_latency(struct device *cpu_dev) { - struct device_node *np, *parent; + struct device_node *np; u32 transition_latency = CPUFREQ_ETERNAL; - int count = 0; - parent = of_find_node_by_path("/cpus"); - if (!parent) { - pr_info("Failed to find OF /cpus. Use CPUFREQ_ETERNAL transition latency\n"); + np = get_cpu_node_with_valid_op(cpu_dev->id); + if (!np) return CPUFREQ_ETERNAL; - } - - for_each_child_of_node(parent, np) { - if (count++ != cpu_dev->id) - continue; - of_property_read_u32(np, "clock-latency", &transition_latency); - of_node_put(np); - of_node_put(parent); + of_property_read_u32(np, "clock-latency", &transition_latency); + of_node_put(np); - return transition_latency; - } - - pr_info("clock-latency isn't found, use CPUFREQ_ETERNAL transition latency\n"); - return CPUFREQ_ETERNAL; + pr_debug("%s: clock-latency: %d\n", __func__, transition_latency); + return transition_latency; } static struct cpufreq_arm_bL_ops dt_bL_ops = { @@ -91,17 +96,33 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = { .init_opp_table = dt_init_opp_table, }; -static int generic_bL_init(void) +static int generic_bL_probe(struct platform_device *pdev) { + struct device_node *np; + + np = get_cpu_node_with_valid_op(0); + if (!np) + return -ENODEV; + + of_node_put(np); return bL_cpufreq_register(&dt_bL_ops); } -module_init(generic_bL_init); -static void generic_bL_exit(void) +static int generic_bL_remove(struct platform_device *pdev) { - return bL_cpufreq_unregister(&dt_bL_ops); + bL_cpufreq_unregister(&dt_bL_ops); + return 0; } -module_exit(generic_bL_exit); + +static struct platform_driver generic_bL_platdrv = { + .driver = { + .name = "arm-bL-cpufreq-dt", + .owner = THIS_MODULE, + }, + .probe = generic_bL_probe, + .remove = generic_bL_remove, +}; +module_platform_driver(generic_bL_platdrv); MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>"); MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT"); diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index a64eb8b70444..ad1fde277661 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -45,7 +45,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, struct cpufreq_freqs freqs; struct opp *opp; unsigned long volt = 0, volt_old = 0, tol = 0; - long freq_Hz; + long freq_Hz, freq_exact; unsigned int index; int ret; @@ -60,6 +60,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); if (freq_Hz < 0) freq_Hz = freq_table[index].frequency * 1000; + freq_exact = freq_Hz; freqs.new = freq_Hz / 1000; freqs.old = clk_get_rate(cpu_clk) / 1000; @@ -98,7 +99,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, } } - ret = clk_set_rate(cpu_clk, freqs.new * 1000); + ret = clk_set_rate(cpu_clk, freq_exact); if (ret) { pr_err("failed to set clock rate: %d\n", ret); if (cpu_reg) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 4b8c7f297d74..2d53f47d1747 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1729,18 +1729,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, /* end old governor */ if (data->governor) { __cpufreq_governor(data, CPUFREQ_GOV_STOP); + unlock_policy_rwsem_write(policy->cpu); __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); + lock_policy_rwsem_write(policy->cpu); } /* start new governor */ data->governor = policy->governor; if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) { - if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) + if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) { failed = 0; - else + } else { + unlock_policy_rwsem_write(policy->cpu); __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); + lock_policy_rwsem_write(policy->cpu); + } } if (failed) { diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 5af40ad82d23..dc9b72e25c1a 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -26,6 +26,7 @@ #include <linux/tick.h> #include <linux/types.h> #include <linux/workqueue.h> +#include <linux/cpu.h> #include "cpufreq_governor.h" @@ -180,8 +181,10 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, if (!all_cpus) { __gov_queue_work(smp_processor_id(), dbs_data, delay); } else { + get_online_cpus(); for_each_cpu(i, policy->cpus) __gov_queue_work(i, dbs_data, delay); + put_online_cpus(); } } EXPORT_SYMBOL_GPL(gov_queue_work); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 9c36ace92a39..07f2840ad805 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -521,6 +521,7 @@ static void intel_pstate_timer_func(unsigned long __data) static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(0x2a, default_policy), ICPU(0x2d, default_policy), + ICPU(0x3a, default_policy), {} }; MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index 84889573b566..d53912768946 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -18,6 +18,7 @@ #include <linux/platform_device.h> #include <asm/clock.h> +#include <asm/idle.h> #include <asm/mach-loongson/loongson.h> @@ -200,6 +201,7 @@ static void loongson2_cpu_wait(void) LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */ LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */ spin_unlock_irqrestore(&loongson2_wait_lock, flags); + local_irq_enable(); } static int __init cpufreq_init(void) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 765fdf5ce579..bf416a8391a7 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1154,7 +1154,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, dst_nents = sg_count(req->dst, req->cryptlen, &dst_chained); sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, - DMA_BIDIRECTIONAL, assoc_chained); + DMA_TO_DEVICE, assoc_chained); if (likely(req->src == req->dst)) { sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, DMA_BIDIRECTIONAL, src_chained); @@ -1336,7 +1336,7 @@ static struct aead_edesc *aead_giv_edesc_alloc(struct aead_givcrypt_request dst_nents = sg_count(req->dst, req->cryptlen, &dst_chained); sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, - DMA_BIDIRECTIONAL, assoc_chained); + DMA_TO_DEVICE, assoc_chained); if (likely(req->src == req->dst)) { sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, DMA_BIDIRECTIONAL, src_chained); diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c index a76d4c4f29f5..35d483f8db66 100644 --- a/drivers/crypto/nx/nx-aes-cbc.c +++ b/drivers/crypto/nx/nx-aes-cbc.c @@ -126,6 +126,7 @@ struct crypto_alg nx_cbc_aes_alg = { .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, + .cra_alignmask = 0xf, .cra_module = THIS_MODULE, .cra_init = nx_crypto_ctx_aes_cbc_init, .cra_exit = nx_crypto_ctx_exit, diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c index ba5f1611336f..7bbc9a81da21 100644 --- a/drivers/crypto/nx/nx-aes-ecb.c +++ b/drivers/crypto/nx/nx-aes-ecb.c @@ -123,6 +123,7 @@ struct crypto_alg nx_ecb_aes_alg = { .cra_priority = 300, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = AES_BLOCK_SIZE, + .cra_alignmask = 0xf, .cra_ctxsize = sizeof(struct nx_crypto_ctx), .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c index c8109edc5cfb..6cca6c392b00 100644 --- a/drivers/crypto/nx/nx-aes-gcm.c +++ b/drivers/crypto/nx/nx-aes-gcm.c @@ -219,7 +219,7 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc) if (enc) NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT; else - nbytes -= AES_BLOCK_SIZE; + nbytes -= crypto_aead_authsize(crypto_aead_reqtfm(req)); csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8; diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c index 9767315f8c0b..67024f2f0b78 100644 --- a/drivers/crypto/nx/nx-sha256.c +++ b/drivers/crypto/nx/nx-sha256.c @@ -69,7 +69,7 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, * 1: <= SHA256_BLOCK_SIZE: copy into state, return 0 * 2: > SHA256_BLOCK_SIZE: process X blocks, copy in leftover */ - if (len + sctx->count <= SHA256_BLOCK_SIZE) { + if (len + sctx->count < SHA256_BLOCK_SIZE) { memcpy(sctx->buf + sctx->count, data, len); sctx->count += len; goto out; @@ -110,7 +110,8 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, atomic_inc(&(nx_ctx->stats->sha256_ops)); /* copy the leftover back into the state struct */ - memcpy(sctx->buf, data + len - leftover, leftover); + if (leftover) + memcpy(sctx->buf, data + len - leftover, leftover); sctx->count = leftover; csbcpb->cpb.sha256.message_bit_length += (u64) @@ -130,6 +131,7 @@ static int nx_sha256_final(struct shash_desc *desc, u8 *out) struct nx_sg *in_sg, *out_sg; int rc; + if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) { /* we've hit the nx chip previously, now we're finalizing, * so copy over the partial digest */ @@ -162,7 +164,7 @@ static int nx_sha256_final(struct shash_desc *desc, u8 *out) atomic_inc(&(nx_ctx->stats->sha256_ops)); - atomic64_add(csbcpb->cpb.sha256.message_bit_length, + atomic64_add(csbcpb->cpb.sha256.message_bit_length / 8, &(nx_ctx->stats->sha256_bytes)); memcpy(out, csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE); out: diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c index 3177b8c3d5f1..08eee1122349 100644 --- a/drivers/crypto/nx/nx-sha512.c +++ b/drivers/crypto/nx/nx-sha512.c @@ -69,7 +69,7 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, * 1: <= SHA512_BLOCK_SIZE: copy into state, return 0 * 2: > SHA512_BLOCK_SIZE: process X blocks, copy in leftover */ - if ((u64)len + sctx->count[0] <= SHA512_BLOCK_SIZE) { + if ((u64)len + sctx->count[0] < SHA512_BLOCK_SIZE) { memcpy(sctx->buf + sctx->count[0], data, len); sctx->count[0] += len; goto out; @@ -110,7 +110,8 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, atomic_inc(&(nx_ctx->stats->sha512_ops)); /* copy the leftover back into the state struct */ - memcpy(sctx->buf, data + len - leftover, leftover); + if (leftover) + memcpy(sctx->buf, data + len - leftover, leftover); sctx->count[0] = leftover; spbc_bits = csbcpb->cpb.sha512.spbc * 8; @@ -168,7 +169,7 @@ static int nx_sha512_final(struct shash_desc *desc, u8 *out) goto out; atomic_inc(&(nx_ctx->stats->sha512_ops)); - atomic64_add(csbcpb->cpb.sha512.message_bit_length_lo, + atomic64_add(csbcpb->cpb.sha512.message_bit_length_lo / 8, &(nx_ctx->stats->sha512_bytes)); memcpy(out, csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE); diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index c767f232e693..bbdab6e5ccf0 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -211,44 +211,20 @@ int nx_build_sg_lists(struct nx_crypto_ctx *nx_ctx, { struct nx_sg *nx_insg = nx_ctx->in_sg; struct nx_sg *nx_outsg = nx_ctx->out_sg; - struct blkcipher_walk walk; - int rc; - - blkcipher_walk_init(&walk, dst, src, nbytes); - rc = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); - if (rc) - goto out; if (iv) - memcpy(iv, walk.iv, AES_BLOCK_SIZE); + memcpy(iv, desc->info, AES_BLOCK_SIZE); - while (walk.nbytes) { - nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr, - walk.nbytes, nx_ctx->ap->sglen); - nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr, - walk.nbytes, nx_ctx->ap->sglen); - - rc = blkcipher_walk_done(desc, &walk, 0); - if (rc) - break; - } - - if (walk.nbytes) { - nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr, - walk.nbytes, nx_ctx->ap->sglen); - nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr, - walk.nbytes, nx_ctx->ap->sglen); - - rc = 0; - } + nx_insg = nx_walk_and_build(nx_insg, nx_ctx->ap->sglen, src, 0, nbytes); + nx_outsg = nx_walk_and_build(nx_outsg, nx_ctx->ap->sglen, dst, 0, nbytes); /* these lengths should be negative, which will indicate to phyp that * the input and output parameters are scatterlists, not linear * buffers */ nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) * sizeof(struct nx_sg); nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) * sizeof(struct nx_sg); -out: - return rc; + + return 0; } /** @@ -454,6 +430,8 @@ static int nx_register_algs(void) if (rc) goto out; + nx_driver.of.status = NX_OKAY; + rc = crypto_register_alg(&nx_ecb_aes_alg); if (rc) goto out; @@ -498,8 +476,6 @@ static int nx_register_algs(void) if (rc) goto out_unreg_s512; - nx_driver.of.status = NX_OKAY; - goto out; out_unreg_s512: diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index a97bb6c1596c..c3dc1c04a5df 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -863,7 +863,7 @@ static struct of_device_id sahara_dt_ids[] = { { .compatible = "fsl,imx27-sahara" }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(platform, sahara_dt_ids); +MODULE_DEVICE_TABLE(of, sahara_dt_ids); static int sahara_probe(struct platform_device *pdev) { diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index ba6fc62e9651..5a18f82f732a 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -4,7 +4,8 @@ * Based on of-dma.c * * Copyright (C) 2013, Intel Corporation - * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> + * Mika Westerberg <mika.westerberg@linux.intel.com> * * 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 @@ -16,6 +17,7 @@ #include <linux/list.h> #include <linux/mutex.h> #include <linux/slab.h> +#include <linux/ioport.h> #include <linux/acpi.h> #include <linux/acpi_dma.h> @@ -23,6 +25,117 @@ static LIST_HEAD(acpi_dma_list); static DEFINE_MUTEX(acpi_dma_lock); /** + * acpi_dma_parse_resource_group - match device and parse resource group + * @grp: CSRT resource group + * @adev: ACPI device to match with + * @adma: struct acpi_dma of the given DMA controller + * + * Returns 1 on success, 0 when no information is available, or appropriate + * errno value on error. + * + * In order to match a device from DSDT table to the corresponding CSRT device + * we use MMIO address and IRQ. + */ +static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, + struct acpi_device *adev, struct acpi_dma *adma) +{ + const struct acpi_csrt_shared_info *si; + struct list_head resource_list; + struct resource_list_entry *rentry; + resource_size_t mem = 0, irq = 0; + u32 vendor_id; + int ret; + + if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info)) + return -ENODEV; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); + if (ret <= 0) + return 0; + + list_for_each_entry(rentry, &resource_list, node) { + if (resource_type(&rentry->res) == IORESOURCE_MEM) + mem = rentry->res.start; + else if (resource_type(&rentry->res) == IORESOURCE_IRQ) + irq = rentry->res.start; + } + + acpi_dev_free_resource_list(&resource_list); + + /* Consider initial zero values as resource not found */ + if (mem == 0 && irq == 0) + return 0; + + si = (const struct acpi_csrt_shared_info *)&grp[1]; + + /* Match device by MMIO and IRQ */ + if (si->mmio_base_low != mem || si->gsi_interrupt != irq) + return 0; + + vendor_id = le32_to_cpu(grp->vendor_id); + dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n", + (char *)&vendor_id, grp->device_id, grp->revision); + + /* Check if the request line range is available */ + if (si->base_request_line == 0 && si->num_handshake_signals == 0) + return 0; + + adma->base_request_line = si->base_request_line; + adma->end_request_line = si->base_request_line + + si->num_handshake_signals - 1; + + dev_dbg(&adev->dev, "request line base: 0x%04x end: 0x%04x\n", + adma->base_request_line, adma->end_request_line); + + return 1; +} + +/** + * acpi_dma_parse_csrt - parse CSRT to exctract additional DMA resources + * @adev: ACPI device to match with + * @adma: struct acpi_dma of the given DMA controller + * + * CSRT or Core System Resources Table is a proprietary ACPI table + * introduced by Microsoft. This table can contain devices that are not in + * the system DSDT table. In particular DMA controllers might be described + * here. + * + * We are using this table to get the request line range of the specific DMA + * controller to be used later. + * + */ +static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma) +{ + struct acpi_csrt_group *grp, *end; + struct acpi_table_csrt *csrt; + acpi_status status; + int ret; + + status = acpi_get_table(ACPI_SIG_CSRT, 0, + (struct acpi_table_header **)&csrt); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) + dev_warn(&adev->dev, "failed to get the CSRT table\n"); + return; + } + + grp = (struct acpi_csrt_group *)(csrt + 1); + end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length); + + while (grp < end) { + ret = acpi_dma_parse_resource_group(grp, adev, adma); + if (ret < 0) { + dev_warn(&adev->dev, + "error in parsing resource group\n"); + return; + } + + grp = (struct acpi_csrt_group *)((void *)grp + grp->length); + } +} + +/** * acpi_dma_controller_register - Register a DMA controller to ACPI DMA helpers * @dev: struct device of DMA controller * @acpi_dma_xlate: translation function which converts a dma specifier @@ -61,6 +174,8 @@ int acpi_dma_controller_register(struct device *dev, adma->acpi_dma_xlate = acpi_dma_xlate; adma->data = data; + acpi_dma_parse_csrt(adev, adma); + /* Now queue acpi_dma controller structure in list */ mutex_lock(&acpi_dma_lock); list_add_tail(&adma->dma_controllers, &acpi_dma_list); @@ -149,6 +264,45 @@ void devm_acpi_dma_controller_free(struct device *dev) } EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free); +/** + * acpi_dma_update_dma_spec - prepare dma specifier to pass to translation function + * @adma: struct acpi_dma of DMA controller + * @dma_spec: dma specifier to update + * + * Returns 0, if no information is avaiable, -1 on mismatch, and 1 otherwise. + * + * Accordingly to ACPI 5.0 Specification Table 6-170 "Fixed DMA Resource + * Descriptor": + * DMA Request Line bits is a platform-relative number uniquely + * identifying the request line assigned. Request line-to-Controller + * mapping is done in a controller-specific OS driver. + * That's why we can safely adjust slave_id when the appropriate controller is + * found. + */ +static int acpi_dma_update_dma_spec(struct acpi_dma *adma, + struct acpi_dma_spec *dma_spec) +{ + /* Set link to the DMA controller device */ + dma_spec->dev = adma->dev; + + /* Check if the request line range is available */ + if (adma->base_request_line == 0 && adma->end_request_line == 0) + return 0; + + /* Check if slave_id falls to the range */ + if (dma_spec->slave_id < adma->base_request_line || + dma_spec->slave_id > adma->end_request_line) + return -1; + + /* + * Here we adjust slave_id. It should be a relative number to the base + * request line. + */ + dma_spec->slave_id -= adma->base_request_line; + + return 1; +} + struct acpi_dma_parser_data { struct acpi_dma_spec dma_spec; size_t index; @@ -193,6 +347,7 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev, struct acpi_device *adev; struct acpi_dma *adma; struct dma_chan *chan = NULL; + int found; /* Check if the device was enumerated by ACPI */ if (!dev || !ACPI_HANDLE(dev)) @@ -219,9 +374,20 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev, mutex_lock(&acpi_dma_lock); list_for_each_entry(adma, &acpi_dma_list, dma_controllers) { - dma_spec->dev = adma->dev; + /* + * We are not going to call translation function if slave_id + * doesn't fall to the request range. + */ + found = acpi_dma_update_dma_spec(adma, dma_spec); + if (found < 0) + continue; chan = adma->acpi_dma_xlate(dma_spec, adma); - if (chan) + /* + * Try to get a channel only from the DMA controller that + * matches the slave_id. See acpi_dma_update_dma_spec() + * description for the details. + */ + if (found > 0 || chan) break; } diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index d8ce4ecfef18..e88ded2c8d2f 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -716,8 +716,7 @@ static int dmatest_func(void *data) } dma_async_issue_pending(chan); - wait_event_freezable_timeout(done_wait, - done.done || kthread_should_stop(), + wait_event_freezable_timeout(done_wait, done.done, msecs_to_jiffies(params->timeout)); status = dma_async_is_tx_complete(chan, cookie, NULL, NULL); @@ -997,7 +996,6 @@ static void stop_threaded_test(struct dmatest_info *info) static int __restart_threaded_test(struct dmatest_info *info, bool run) { struct dmatest_params *params = &info->params; - int ret; /* Stop any running test first */ __stop_threaded_test(info); @@ -1012,13 +1010,23 @@ static int __restart_threaded_test(struct dmatest_info *info, bool run) memcpy(params, &info->dbgfs_params, sizeof(*params)); /* Run test with new parameters */ - ret = __run_threaded_test(info); - if (ret) { - __stop_threaded_test(info); - pr_err("dmatest: Can't run test\n"); + return __run_threaded_test(info); +} + +static bool __is_threaded_test_run(struct dmatest_info *info) +{ + struct dmatest_chan *dtc; + + list_for_each_entry(dtc, &info->channels, node) { + struct dmatest_thread *thread; + + list_for_each_entry(thread, &dtc->threads, node) { + if (!thread->done) + return true; + } } - return ret; + return false; } static ssize_t dtf_write_string(void *to, size_t available, loff_t *ppos, @@ -1091,22 +1099,10 @@ static ssize_t dtf_read_run(struct file *file, char __user *user_buf, { struct dmatest_info *info = file->private_data; char buf[3]; - struct dmatest_chan *dtc; - bool alive = false; mutex_lock(&info->lock); - list_for_each_entry(dtc, &info->channels, node) { - struct dmatest_thread *thread; - - list_for_each_entry(thread, &dtc->threads, node) { - if (!thread->done) { - alive = true; - break; - } - } - } - if (alive) { + if (__is_threaded_test_run(info)) { buf[0] = 'Y'; } else { __stop_threaded_test(info); @@ -1132,7 +1128,12 @@ static ssize_t dtf_write_run(struct file *file, const char __user *user_buf, if (strtobool(buf, &bv) == 0) { mutex_lock(&info->lock); - ret = __restart_threaded_test(info, bv); + + if (__is_threaded_test_run(info)) + ret = -EBUSY; + else + ret = __restart_threaded_test(info, bv); + mutex_unlock(&info->lock); } diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 1734feec47b1..71bf4ec300ea 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1566,10 +1566,12 @@ static void dma_tc_handle(struct d40_chan *d40c) return; } - if (d40_queue_start(d40c) == NULL) + if (d40_queue_start(d40c) == NULL) { d40c->busy = false; - pm_runtime_mark_last_busy(d40c->base->dev); - pm_runtime_put_autosuspend(d40c->base->dev); + + pm_runtime_mark_last_busy(d40c->base->dev); + pm_runtime_put_autosuspend(d40c->base->dev); + } d40_desc_remove(d40d); d40_desc_done(d40c, d40d); diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c index 8c171fa1cb9b..845f04786c2d 100644 --- a/drivers/edac/amd64_edac_inj.c +++ b/drivers/edac/amd64_edac_inj.c @@ -202,9 +202,9 @@ static DEVICE_ATTR(inject_word, S_IRUGO | S_IWUSR, amd64_inject_word_show, amd64_inject_word_store); static DEVICE_ATTR(inject_ecc_vector, S_IRUGO | S_IWUSR, amd64_inject_ecc_vector_show, amd64_inject_ecc_vector_store); -static DEVICE_ATTR(inject_write, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(inject_write, S_IWUSR, NULL, amd64_inject_write_store); -static DEVICE_ATTR(inject_read, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(inject_read, S_IWUSR, NULL, amd64_inject_read_store); diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index b623c599e572..8bd1bb6dbe47 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -523,13 +523,11 @@ static void efivar_update_sysfs_entries(struct work_struct *work) struct efivar_entry *entry; int err; - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return; - /* Add new sysfs entries */ while (1) { - memset(entry, 0, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return; err = efivar_init(efivar_update_sysfs_entry, entry, true, false, &efivar_sysfs_list); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 87d567089f13..573c449c49b9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -636,7 +636,7 @@ config GPIO_MAX7301 config GPIO_MCP23S08 tristate "Microchip MCP23xxx I/O expander" - depends on SPI_MASTER || I2C + depends on (SPI_MASTER && !I2C) || I2C help SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 I/O expanders. diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c index 634c3d37f7b5..62ef10a641c4 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c @@ -324,6 +324,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, resource_size_t start, len; struct lnw_gpio *lnw; u32 gpio_base; + u32 irq_base; int retval; int ngpio = id->driver_data; @@ -345,6 +346,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev, retval = -EFAULT; goto err_ioremap; } + irq_base = *(u32 *)base; gpio_base = *((u32 *)base + 1); /* release the IO mapping, since we already get the info from bar1 */ iounmap(base); @@ -365,13 +367,6 @@ static int lnw_gpio_probe(struct pci_dev *pdev, goto err_ioremap; } - lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio, - &lnw_gpio_irq_ops, lnw); - if (!lnw->domain) { - retval = -ENOMEM; - goto err_ioremap; - } - lnw->reg_base = base; lnw->chip.label = dev_name(&pdev->dev); lnw->chip.request = lnw_gpio_request; @@ -384,6 +379,14 @@ static int lnw_gpio_probe(struct pci_dev *pdev, lnw->chip.ngpio = ngpio; lnw->chip.can_sleep = 0; lnw->pdev = pdev; + + lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base, + &lnw_gpio_irq_ops, lnw); + if (!lnw->domain) { + retval = -ENOMEM; + goto err_ioremap; + } + pci_set_drvdata(pdev, lnw); retval = gpiochip_add(&lnw->chip); if (retval) { diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index b73366523fae..0966f2637ad2 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -496,8 +496,7 @@ err_irq_alloc_descs: err_gpiochip_add: while (--i >= 0) { chip--; - ret = gpiochip_remove(&chip->gpio); - if (ret) + if (gpiochip_remove(&chip->gpio)) dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i); } kfree(chip_save); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 25000b0f8453..f8e6af20dfbf 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -326,7 +326,8 @@ static int mxs_gpio_probe(struct platform_device *pdev) err = bgpio_init(&port->bgc, &pdev->dev, 4, port->base + PINCTRL_DIN(port), - port->base + PINCTRL_DOUT(port), NULL, + port->base + PINCTRL_DOUT(port) + MXS_SET, + port->base + PINCTRL_DOUT(port) + MXS_CLR, port->base + PINCTRL_DOE(port), NULL, 0); if (err) goto out_irqdesc_free; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 2050891d9c65..d3f7d2db870f 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -69,6 +69,7 @@ struct gpio_bank { bool is_mpuio; bool dbck_flag; bool loses_context; + bool context_valid; int stride; u32 width; int context_loss_count; @@ -1128,6 +1129,10 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->loses_context = true; } else { bank->loses_context = pdata->loses_context; + + if (bank->loses_context) + bank->get_context_loss_count = + pdata->get_context_loss_count; } @@ -1178,9 +1183,6 @@ static int omap_gpio_probe(struct platform_device *pdev) omap_gpio_chip_init(bank); omap_gpio_show_rev(bank); - if (bank->loses_context) - bank->get_context_loss_count = pdata->get_context_loss_count; - pm_runtime_put(bank->dev); list_add_tail(&bank->node, &omap_gpio_list); @@ -1259,6 +1261,8 @@ update_gpio_context_count: return 0; } +static void omap_gpio_init_context(struct gpio_bank *p); + static int omap_gpio_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -1268,6 +1272,20 @@ static int omap_gpio_runtime_resume(struct device *dev) int c; spin_lock_irqsave(&bank->lock, flags); + + /* + * On the first resume during the probe, the context has not + * been initialised and so initialise it now. Also initialise + * the context loss count. + */ + if (bank->loses_context && !bank->context_valid) { + omap_gpio_init_context(bank); + + if (bank->get_context_loss_count) + bank->context_loss_count = + bank->get_context_loss_count(bank->dev); + } + _gpio_dbck_enable(bank); /* @@ -1384,6 +1402,29 @@ void omap2_gpio_resume_after_idle(void) } #if defined(CONFIG_PM_RUNTIME) +static void omap_gpio_init_context(struct gpio_bank *p) +{ + struct omap_gpio_reg_offs *regs = p->regs; + void __iomem *base = p->base; + + p->context.ctrl = __raw_readl(base + regs->ctrl); + p->context.oe = __raw_readl(base + regs->direction); + p->context.wake_en = __raw_readl(base + regs->wkup_en); + p->context.leveldetect0 = __raw_readl(base + regs->leveldetect0); + p->context.leveldetect1 = __raw_readl(base + regs->leveldetect1); + p->context.risingdetect = __raw_readl(base + regs->risingdetect); + p->context.fallingdetect = __raw_readl(base + regs->fallingdetect); + p->context.irqenable1 = __raw_readl(base + regs->irqenable); + p->context.irqenable2 = __raw_readl(base + regs->irqenable2); + + if (regs->set_dataout && p->regs->clr_dataout) + p->context.dataout = __raw_readl(base + regs->set_dataout); + else + p->context.dataout = __raw_readl(base + regs->dataout); + + p->context_valid = true; +} + static void omap_gpio_restore_context(struct gpio_bank *bank) { __raw_writel(bank->context.wake_en, @@ -1421,6 +1462,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) #else #define omap_gpio_runtime_suspend NULL #define omap_gpio_runtime_resume NULL +static void omap_gpio_init_context(struct gpio_bank *p) {} #endif static const struct dev_pm_ops gpio_pm_ops = { diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index cdf599687cf7..0fec097e838d 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -424,8 +424,7 @@ end: err_request_irq: irq_free_descs(irq_base, gpio_pins[chip->ioh]); - ret = gpiochip_remove(&chip->gpio); - if (ret) + if (gpiochip_remove(&chip->gpio)) dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__); err_gpiochip_add: diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 1e4de16ceb41..5af65719b95d 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -272,10 +272,8 @@ static int sch_gpio_probe(struct platform_device *pdev) return 0; err_sch_gpio_resume: - err = gpiochip_remove(&sch_gpio_core); - if (err) - dev_err(&pdev->dev, "%s failed, %d\n", - "gpiochip_remove()", err); + if (gpiochip_remove(&sch_gpio_core)) + dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__); err_sch_gpio_core: release_region(res->start, resource_size(res)); diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index 095ab14cea4d..5ac2919197fe 100644 --- a/drivers/gpio/gpio-viperboard.c +++ b/drivers/gpio/gpio-viperboard.c @@ -446,7 +446,8 @@ static int vprbrd_gpio_probe(struct platform_device *pdev) return ret; err_gpiob: - ret = gpiochip_remove(&vb_gpio->gpioa); + if (gpiochip_remove(&vb_gpio->gpioa)) + dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__); err_gpioa: return ret; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index b16c50ee769c..71ca63b79a4f 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -213,6 +213,8 @@ source "drivers/gpu/drm/mgag200/Kconfig" source "drivers/gpu/drm/cirrus/Kconfig" +source "drivers/gpu/drm/rcar-du/Kconfig" + source "drivers/gpu/drm/shmobile/Kconfig" source "drivers/gpu/drm/omapdrm/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 1ecbe5b7312d..801bcafa3028 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_DRM_EXYNOS) +=exynos/ obj-$(CONFIG_DRM_GMA500) += gma500/ obj-$(CONFIG_DRM_UDL) += udl/ obj-$(CONFIG_DRM_AST) += ast/ +obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ obj-$(CONFIG_DRM_OMAP) += omapdrm/ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c index 09da3393c527..a5a1a034033d 100644 --- a/drivers/gpu/drm/ast/ast_ttm.c +++ b/drivers/gpu/drm/ast/ast_ttm.c @@ -271,26 +271,19 @@ int ast_mm_init(struct ast_private *ast) return ret; } - ast->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0), - DRM_MTRR_WC); + ast->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); return 0; } void ast_mm_fini(struct ast_private *ast) { - struct drm_device *dev = ast->dev; ttm_bo_device_release(&ast->ttm.bdev); ast_ttm_global_release(ast); - if (ast->fb_mtrr >= 0) { - drm_mtrr_del(ast->fb_mtrr, - pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0), DRM_MTRR_WC); - ast->fb_mtrr = -1; - } + arch_phys_wc_del(ast->fb_mtrr); } void ast_ttm_placement(struct ast_bo *bo, int domain) diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c index 2ed8cfc740c9..36b9b0bab1da 100644 --- a/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -271,9 +271,8 @@ int cirrus_mm_init(struct cirrus_device *cirrus) return ret; } - cirrus->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0), - DRM_MTRR_WC); + cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); cirrus->mm_inited = true; return 0; @@ -281,8 +280,6 @@ int cirrus_mm_init(struct cirrus_device *cirrus) void cirrus_mm_fini(struct cirrus_device *cirrus) { - struct drm_device *dev = cirrus->dev; - if (!cirrus->mm_inited) return; @@ -290,12 +287,8 @@ void cirrus_mm_fini(struct cirrus_device *cirrus) cirrus_ttm_global_release(cirrus); - if (cirrus->fb_mtrr >= 0) { - drm_mtrr_del(cirrus->fb_mtrr, - pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0), DRM_MTRR_WC); - cirrus->fb_mtrr = -1; - } + arch_phys_wc_del(cirrus->fb_mtrr); + cirrus->fb_mtrr = 0; } void cirrus_ttm_placement(struct cirrus_bo *bo, int domain) diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 0128147265f3..5a4dbb410b71 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -210,12 +210,16 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, if (drm_core_has_MTRR(dev)) { if (map->type == _DRM_FRAME_BUFFER || (map->flags & _DRM_WRITE_COMBINING)) { - map->mtrr = mtrr_add(map->offset, map->size, - MTRR_TYPE_WRCOMB, 1); + map->mtrr = + arch_phys_wc_add(map->offset, map->size); } } if (map->type == _DRM_REGISTERS) { - map->handle = ioremap(map->offset, map->size); + if (map->flags & _DRM_WRITE_COMBINING) + map->handle = ioremap_wc(map->offset, + map->size); + else + map->handle = ioremap(map->offset, map->size); if (!map->handle) { kfree(map); return -ENOMEM; @@ -410,6 +414,15 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data, /* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */ map->handle = (void *)(unsigned long)maplist->user_token; + + /* + * It appears that there are no users of this value whatsoever -- + * drmAddMap just discards it. Let's not encourage its use. + * (Keeping drm_addmap_core's returned mtrr value would be wrong -- + * it's not a real mtrr index anymore.) + */ + map->mtrr = -1; + return 0; } @@ -451,11 +464,8 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) iounmap(map->handle); /* FALLTHROUGH */ case _DRM_FRAME_BUFFER: - if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { - int retcode; - retcode = mtrr_del(map->mtrr, map->offset, map->size); - DRM_DEBUG("mtrr_del=%d\n", retcode); - } + if (drm_core_has_MTRR(dev)) + arch_phys_wc_del(map->mtrr); break; case _DRM_SHM: vfree(map->handle); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e7e92429d10f..fc83bb9eb514 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -29,6 +29,7 @@ * Dave Airlie <airlied@linux.ie> * Jesse Barnes <jesse.barnes@intel.com> */ +#include <linux/ctype.h> #include <linux/list.h> #include <linux/slab.h> #include <linux/export.h> @@ -91,7 +92,7 @@ EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); /* Avoid boilerplate. I'm tired of typing. */ #define DRM_ENUM_NAME_FN(fnname, list) \ - char *fnname(int val) \ + const char *fnname(int val) \ { \ int i; \ for (i = 0; i < ARRAY_SIZE(list); i++) { \ @@ -104,7 +105,7 @@ EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked); /* * Global properties */ -static struct drm_prop_enum_list drm_dpms_enum_list[] = +static const struct drm_prop_enum_list drm_dpms_enum_list[] = { { DRM_MODE_DPMS_ON, "On" }, { DRM_MODE_DPMS_STANDBY, "Standby" }, { DRM_MODE_DPMS_SUSPEND, "Suspend" }, @@ -116,7 +117,7 @@ DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) /* * Optional properties */ -static struct drm_prop_enum_list drm_scaling_mode_enum_list[] = +static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { { DRM_MODE_SCALE_NONE, "None" }, { DRM_MODE_SCALE_FULLSCREEN, "Full" }, @@ -124,7 +125,7 @@ static struct drm_prop_enum_list drm_scaling_mode_enum_list[] = { DRM_MODE_SCALE_ASPECT, "Full aspect" }, }; -static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = +static const struct drm_prop_enum_list drm_dithering_mode_enum_list[] = { { DRM_MODE_DITHERING_OFF, "Off" }, { DRM_MODE_DITHERING_ON, "On" }, @@ -134,7 +135,7 @@ static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = /* * Non-global properties, but "required" for certain connectors. */ -static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = +static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ @@ -143,7 +144,7 @@ static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) -static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = +static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ @@ -153,7 +154,7 @@ static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, drm_dvi_i_subconnector_enum_list) -static struct drm_prop_enum_list drm_tv_select_enum_list[] = +static const struct drm_prop_enum_list drm_tv_select_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ @@ -164,7 +165,7 @@ static struct drm_prop_enum_list drm_tv_select_enum_list[] = DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) -static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = +static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ @@ -176,7 +177,7 @@ static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, drm_tv_subconnector_enum_list) -static struct drm_prop_enum_list drm_dirty_info_enum_list[] = { +static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = { { DRM_MODE_DIRTY_OFF, "Off" }, { DRM_MODE_DIRTY_ON, "On" }, { DRM_MODE_DIRTY_ANNOTATE, "Annotate" }, @@ -184,7 +185,7 @@ static struct drm_prop_enum_list drm_dirty_info_enum_list[] = { struct drm_conn_prop_enum_list { int type; - char *name; + const char *name; int count; }; @@ -210,7 +211,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0}, }; -static struct drm_prop_enum_list drm_encoder_enum_list[] = +static const struct drm_prop_enum_list drm_encoder_enum_list[] = { { DRM_MODE_ENCODER_NONE, "None" }, { DRM_MODE_ENCODER_DAC, "DAC" }, { DRM_MODE_ENCODER_TMDS, "TMDS" }, @@ -219,7 +220,7 @@ static struct drm_prop_enum_list drm_encoder_enum_list[] = { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, }; -char *drm_get_encoder_name(struct drm_encoder *encoder) +const char *drm_get_encoder_name(const struct drm_encoder *encoder) { static char buf[32]; @@ -230,7 +231,7 @@ char *drm_get_encoder_name(struct drm_encoder *encoder) } EXPORT_SYMBOL(drm_get_encoder_name); -char *drm_get_connector_name(struct drm_connector *connector) +const char *drm_get_connector_name(const struct drm_connector *connector) { static char buf[32]; @@ -241,7 +242,7 @@ char *drm_get_connector_name(struct drm_connector *connector) } EXPORT_SYMBOL(drm_get_connector_name); -char *drm_get_connector_status_name(enum drm_connector_status status) +const char *drm_get_connector_status_name(enum drm_connector_status status) { if (status == connector_status_connected) return "connected"; @@ -252,6 +253,28 @@ char *drm_get_connector_status_name(enum drm_connector_status status) } EXPORT_SYMBOL(drm_get_connector_status_name); +static char printable_char(int c) +{ + return isascii(c) && isprint(c) ? c : '?'; +} + +const char *drm_get_format_name(uint32_t format) +{ + static char buf[32]; + + snprintf(buf, sizeof(buf), + "%c%c%c%c %s-endian (0x%08x)", + printable_char(format & 0xff), + printable_char((format >> 8) & 0xff), + printable_char((format >> 16) & 0xff), + printable_char((format >> 24) & 0x7f), + format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", + format); + + return buf; +} +EXPORT_SYMBOL(drm_get_format_name); + /** * drm_mode_object_get - allocate a new modeset identifier * @dev: DRM device @@ -569,16 +592,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) } list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - if (plane->fb == fb) { - /* should turn off the crtc */ - ret = plane->funcs->disable_plane(plane); - if (ret) - DRM_ERROR("failed to disable plane with busy fb\n"); - /* disconnect the plane from the fb and crtc: */ - __drm_framebuffer_unreference(plane->fb); - plane->fb = NULL; - plane->crtc = NULL; - } + if (plane->fb == fb) + drm_plane_force_disable(plane); } drm_modeset_unlock_all(dev); } @@ -593,7 +608,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove); * @crtc: CRTC object to init * @funcs: callbacks for the new CRTC * - * Inits a new object created as base part of an driver crtc object. + * Inits a new object created as base part of a driver crtc object. * * RETURNS: * Zero on success, error code on failure. @@ -628,11 +643,12 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, EXPORT_SYMBOL(drm_crtc_init); /** - * drm_crtc_cleanup - Cleans up the core crtc usage. + * drm_crtc_cleanup - Clean up the core crtc usage * @crtc: CRTC to cleanup * - * Cleanup @crtc. Removes from drm modesetting space - * does NOT free object, caller does that. + * This function cleans up @crtc and removes it from the DRM mode setting + * core. Note that the function does *not* free the crtc structure itself, + * this is the responsibility of the caller. */ void drm_crtc_cleanup(struct drm_crtc *crtc) { @@ -657,7 +673,7 @@ EXPORT_SYMBOL(drm_crtc_cleanup); void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode) { - list_add(&mode->head, &connector->probed_modes); + list_add_tail(&mode->head, &connector->probed_modes); } EXPORT_SYMBOL(drm_mode_probed_add); @@ -803,6 +819,21 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) } EXPORT_SYMBOL(drm_encoder_cleanup); +/** + * drm_plane_init - Initialise a new plane object + * @dev: DRM device + * @plane: plane object to init + * @possible_crtcs: bitmask of possible CRTCs + * @funcs: callbacks for the new plane + * @formats: array of supported formats (%DRM_FORMAT_*) + * @format_count: number of elements in @formats + * @priv: plane is private (hidden from userspace)? + * + * Inits a new object created as base part of a driver plane object. + * + * RETURNS: + * Zero on success, error code on failure. + */ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, unsigned long possible_crtcs, const struct drm_plane_funcs *funcs, @@ -851,6 +882,14 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, } EXPORT_SYMBOL(drm_plane_init); +/** + * drm_plane_cleanup - Clean up the core plane usage + * @plane: plane to cleanup + * + * This function cleans up @plane and removes it from the DRM mode setting + * core. Note that the function does *not* free the plane structure itself, + * this is the responsibility of the caller. + */ void drm_plane_cleanup(struct drm_plane *plane) { struct drm_device *dev = plane->dev; @@ -868,6 +907,32 @@ void drm_plane_cleanup(struct drm_plane *plane) EXPORT_SYMBOL(drm_plane_cleanup); /** + * drm_plane_force_disable - Forcibly disable a plane + * @plane: plane to disable + * + * Forces the plane to be disabled. + * + * Used when the plane's current framebuffer is destroyed, + * and when restoring fbdev mode. + */ +void drm_plane_force_disable(struct drm_plane *plane) +{ + int ret; + + if (!plane->fb) + return; + + ret = plane->funcs->disable_plane(plane); + if (ret) + DRM_ERROR("failed to disable plane with busy fb\n"); + /* disconnect the plane from the fb and crtc: */ + __drm_framebuffer_unreference(plane->fb); + plane->fb = NULL; + plane->crtc = NULL; +} +EXPORT_SYMBOL(drm_plane_force_disable); + +/** * drm_mode_create - create a new display mode * @dev: DRM device * @@ -1740,7 +1805,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data, plane_resp->plane_id = plane->base.id; plane_resp->possible_crtcs = plane->possible_crtcs; - plane_resp->gamma_size = plane->gamma_size; + plane_resp->gamma_size = 0; /* * This ioctl is called twice, once to determine how much space is @@ -1834,7 +1899,8 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (fb->pixel_format == plane->format_types[i]) break; if (i == plane->format_count) { - DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format); + DRM_DEBUG_KMS("Invalid pixel format %s\n", + drm_get_format_name(fb->pixel_format)); ret = -EINVAL; goto out; } @@ -1906,18 +1972,31 @@ out: int drm_mode_set_config_internal(struct drm_mode_set *set) { struct drm_crtc *crtc = set->crtc; - struct drm_framebuffer *fb, *old_fb; + struct drm_framebuffer *fb; + struct drm_crtc *tmp; int ret; - old_fb = crtc->fb; + /* + * NOTE: ->set_config can also disable other crtcs (if we steal all + * connectors from it), hence we need to refcount the fbs across all + * crtcs. Atomic modeset will have saner semantics ... + */ + list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) + tmp->old_fb = tmp->fb; + fb = set->fb; ret = crtc->funcs->set_config(set); if (ret == 0) { - if (old_fb) - drm_framebuffer_unreference(old_fb); - if (fb) - drm_framebuffer_reference(fb); + /* crtc->fb must be updated by ->set_config, enforces this. */ + WARN_ON(fb != crtc->fb); + } + + list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { + if (tmp->fb) + drm_framebuffer_reference(tmp->fb); + if (tmp->old_fb) + drm_framebuffer_unreference(tmp->old_fb); } return ret; @@ -2099,10 +2178,10 @@ out: return ret; } -int drm_mode_cursor_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) +static int drm_mode_cursor_common(struct drm_device *dev, + struct drm_mode_cursor2 *req, + struct drm_file *file_priv) { - struct drm_mode_cursor *req = data; struct drm_mode_object *obj; struct drm_crtc *crtc; int ret = 0; @@ -2122,13 +2201,17 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, mutex_lock(&crtc->mutex); if (req->flags & DRM_MODE_CURSOR_BO) { - if (!crtc->funcs->cursor_set) { + if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { ret = -ENXIO; goto out; } /* Turns off the cursor if handle is 0 */ - ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, - req->width, req->height); + if (crtc->funcs->cursor_set2) + ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle, + req->width, req->height, req->hot_x, req->hot_y); + else + ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, + req->width, req->height); } if (req->flags & DRM_MODE_CURSOR_MOVE) { @@ -2143,6 +2226,25 @@ out: mutex_unlock(&crtc->mutex); return ret; + +} +int drm_mode_cursor_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_cursor *req = data; + struct drm_mode_cursor2 new_req; + + memcpy(&new_req, req, sizeof(struct drm_mode_cursor)); + new_req.hot_x = new_req.hot_y = 0; + + return drm_mode_cursor_common(dev, &new_req, file_priv); +} + +int drm_mode_cursor2_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_cursor2 *req = data; + return drm_mode_cursor_common(dev, req, file_priv); } /* Original addfb only supported RGB formats, so figure out which one */ @@ -2312,7 +2414,8 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) ret = format_check(r); if (ret) { - DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format); + DRM_DEBUG_KMS("bad framebuffer format %s\n", + drm_get_format_name(r->pixel_format)); return ret; } diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index ed1334e27c33..f6829ba58e86 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -122,6 +122,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, int count = 0; int mode_flags = 0; bool verbose_prune = true; + enum drm_connector_status old_status; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); @@ -137,7 +138,32 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (connector->funcs->force) connector->funcs->force(connector); } else { + old_status = connector->status; + connector->status = connector->funcs->detect(connector, true); + + /* + * Normally either the driver's hpd code or the poll loop should + * pick up any changes and fire the hotplug event. But if + * userspace sneaks in a probe, we might miss a change. Hence + * check here, and if anything changed start the hotplug code. + */ + if (old_status != connector->status) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", + connector->base.id, + drm_get_connector_name(connector), + old_status, connector->status); + + /* + * The hotplug event code might call into the fb + * helpers, and so expects that we do not hold any + * locks. Fire up the poll struct instead, it will + * disable itself again. + */ + dev->mode_config.delayed_event = true; + schedule_delayed_work(&dev->mode_config.output_poll_work, + 0); + } } /* Re-enable polling in case the global poll config changed. */ @@ -189,13 +215,14 @@ prune: if (list_empty(&connector->modes)) return 0; + list_for_each_entry(mode, &connector->modes, head) + mode->vrefresh = drm_mode_vrefresh(mode); + drm_mode_sort(&connector->modes); DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, drm_get_connector_name(connector)); list_for_each_entry(mode, &connector->modes, head) { - mode->vrefresh = drm_mode_vrefresh(mode); - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); drm_mode_debug_printmodeline(mode); } @@ -564,14 +591,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) DRM_DEBUG_KMS("\n"); - if (!set) - return -EINVAL; + BUG_ON(!set); + BUG_ON(!set->crtc); + BUG_ON(!set->crtc->helper_private); - if (!set->crtc) - return -EINVAL; - - if (!set->crtc->helper_private) - return -EINVAL; + /* Enforce sane interface api - has been abused by the fb helper. */ + BUG_ON(!set->mode && set->fb); + BUG_ON(set->fb && set->num_connectors == 0); crtc_funcs = set->crtc->helper_private; @@ -645,11 +671,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) mode_changed = true; } else if (set->fb == NULL) { mode_changed = true; - } else if (set->fb->depth != set->crtc->fb->depth) { - mode_changed = true; - } else if (set->fb->bits_per_pixel != - set->crtc->fb->bits_per_pixel) { - mode_changed = true; } else if (set->fb->pixel_format != set->crtc->fb->pixel_format) { mode_changed = true; @@ -759,12 +780,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ret = -EINVAL; goto fail; } - DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); - for (i = 0; i < set->num_connectors; i++) { - DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, - drm_get_connector_name(set->connectors[i])); - set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); - } } drm_helper_disable_unused_functions(dev); } else if (fb_changed) { @@ -782,6 +797,22 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) } } + /* + * crtc set_config helpers implicit set the crtc and all connected + * encoders to DPMS on for a full mode set. But for just an fb update it + * doesn't do that. To not confuse userspace, do an explicit DPMS_ON + * unconditionally. This will also ensure driver internal dpms state is + * consistent again. + */ + if (set->crtc->enabled) { + DRM_DEBUG_KMS("Setting connector DPMS state to on\n"); + for (i = 0; i < set->num_connectors; i++) { + DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, + drm_get_connector_name(set->connectors[i])); + set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); + } + } + kfree(save_connectors); kfree(save_encoders); kfree(save_crtcs); @@ -980,7 +1011,11 @@ static void output_poll_execute(struct work_struct *work) struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); struct drm_connector *connector; enum drm_connector_status old_status; - bool repoll = false, changed = false; + bool repoll = false, changed; + + /* Pick up any changes detected by the probe functions. */ + changed = dev->mode_config.delayed_event; + dev->mode_config.delayed_event = false; if (!drm_kms_helper_poll) return; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 9cc247f55502..99fcd7c32ea2 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9e62bbedb5ad..2dc1a60a867d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1706,11 +1706,11 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, return NULL; if (pt->misc & DRM_EDID_PT_STEREO) { - printk(KERN_WARNING "stereo mode not supported\n"); + DRM_DEBUG_KMS("stereo mode not supported\n"); return NULL; } if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { - printk(KERN_WARNING "composite sync not supported\n"); + DRM_DEBUG_KMS("composite sync not supported\n"); } /* it is incorrect if hsync/vsync width is zero */ @@ -2321,6 +2321,31 @@ u8 *drm_find_cea_extension(struct edid *edid) } EXPORT_SYMBOL(drm_find_cea_extension); +/* + * Calculate the alternate clock for the CEA mode + * (60Hz vs. 59.94Hz etc.) + */ +static unsigned int +cea_mode_alternate_clock(const struct drm_display_mode *cea_mode) +{ + unsigned int clock = cea_mode->clock; + + if (cea_mode->vrefresh % 6 != 0) + return clock; + + /* + * edid_cea_modes contains the 59.94Hz + * variant for 240 and 480 line modes, + * and the 60Hz variant otherwise. + */ + if (cea_mode->vdisplay == 240 || cea_mode->vdisplay == 480) + clock = clock * 1001 / 1000; + else + clock = DIV_ROUND_UP(clock * 1000, 1001); + + return clock; +} + /** * drm_match_cea_mode - look for a CEA mode matching given mode * @to_match: display mode @@ -2339,21 +2364,9 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) const struct drm_display_mode *cea_mode = &edid_cea_modes[mode]; unsigned int clock1, clock2; - clock1 = clock2 = cea_mode->clock; - /* Check both 60Hz and 59.94Hz */ - if (cea_mode->vrefresh % 6 == 0) { - /* - * edid_cea_modes contains the 59.94Hz - * variant for 240 and 480 line modes, - * and the 60Hz variant otherwise. - */ - if (cea_mode->vdisplay == 240 || - cea_mode->vdisplay == 480) - clock1 = clock1 * 1001 / 1000; - else - clock2 = DIV_ROUND_UP(clock2 * 1000, 1001); - } + clock1 = cea_mode->clock; + clock2 = cea_mode_alternate_clock(cea_mode); if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && @@ -2364,6 +2377,66 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) } EXPORT_SYMBOL(drm_match_cea_mode); +static int +add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) +{ + struct drm_device *dev = connector->dev; + struct drm_display_mode *mode, *tmp; + LIST_HEAD(list); + int modes = 0; + + /* Don't add CEA modes if the CEA extension block is missing */ + if (!drm_find_cea_extension(edid)) + return 0; + + /* + * Go through all probed modes and create a new mode + * with the alternate clock for certain CEA modes. + */ + list_for_each_entry(mode, &connector->probed_modes, head) { + const struct drm_display_mode *cea_mode; + struct drm_display_mode *newmode; + u8 cea_mode_idx = drm_match_cea_mode(mode) - 1; + unsigned int clock1, clock2; + + if (cea_mode_idx >= ARRAY_SIZE(edid_cea_modes)) + continue; + + cea_mode = &edid_cea_modes[cea_mode_idx]; + + clock1 = cea_mode->clock; + clock2 = cea_mode_alternate_clock(cea_mode); + + if (clock1 == clock2) + continue; + + if (mode->clock != clock1 && mode->clock != clock2) + continue; + + newmode = drm_mode_duplicate(dev, cea_mode); + if (!newmode) + continue; + + /* + * The current mode could be either variant. Make + * sure to pick the "other" clock for the new mode. + */ + if (mode->clock != clock1) + newmode->clock = clock1; + else + newmode->clock = clock2; + + list_add_tail(&newmode->head, &list); + } + + list_for_each_entry_safe(mode, tmp, &list, head) { + list_del(&mode->head); + drm_mode_probed_add(connector, mode); + modes++; + } + + return modes; +} static int do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) @@ -2946,6 +3019,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) num_modes += add_inferred_modes(connector, edid); num_modes += add_cea_modes(connector, edid); + num_modes += add_alternate_cea_modes(connector, edid); if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) edid_fixup_preferred(connector, quirks); diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index fa445dd4dc00..a4f5ce14dc1c 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -186,12 +186,11 @@ static u8 *edid_load(struct drm_connector *connector, char *name, goto relfw_out; } - edid = kmalloc(fwsize, GFP_KERNEL); + edid = kmemdup(fwdata, fwsize, GFP_KERNEL); if (edid == NULL) { err = -ENOMEM; goto relfw_out; } - memcpy(edid, fwdata, fwsize); if (!drm_edid_block_valid(edid, 0, print_bad_edid)) { connector->bad_edid_counter++; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index b78cbe74dadf..3d13ca6e257f 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -168,6 +168,9 @@ static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_h uint16_t *r_base, *g_base, *b_base; int i; + if (helper->funcs->gamma_get == NULL) + return; + r_base = crtc->gamma_store; g_base = r_base + crtc->gamma_size; b_base = g_base + crtc->gamma_size; @@ -284,13 +287,27 @@ EXPORT_SYMBOL(drm_fb_helper_debug_leave); */ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) { + struct drm_device *dev = fb_helper->dev; + struct drm_plane *plane; bool error = false; - int i, ret; + int i; + + drm_warn_on_modeset_not_all_locked(dev); - drm_warn_on_modeset_not_all_locked(fb_helper->dev); + list_for_each_entry(plane, &dev->mode_config.plane_list, head) + drm_plane_force_disable(plane); for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; + struct drm_crtc *crtc = mode_set->crtc; + int ret; + + if (crtc->funcs->cursor_set) { + ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0); + if (ret) + error = true; + } + ret = drm_mode_set_config_internal(mode_set); if (ret) error = true; @@ -583,6 +600,14 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, return 0; } + /* + * The driver really shouldn't advertise pseudo/directcolor + * visuals if it can't deal with the palette. + */ + if (WARN_ON(!fb_helper->funcs->gamma_set || + !fb_helper->funcs->gamma_get)) + return -EINVAL; + pindex = regno; if (fb->bits_per_pixel == 16) { @@ -626,12 +651,19 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; + struct drm_device *dev = fb_helper->dev; struct drm_crtc_helper_funcs *crtc_funcs; u16 *red, *green, *blue, *transp; struct drm_crtc *crtc; int i, j, rc = 0; int start; + drm_modeset_lock_all(dev); + if (!drm_fb_helper_is_bound(fb_helper)) { + drm_modeset_unlock_all(dev); + return -EBUSY; + } + for (i = 0; i < fb_helper->crtc_count; i++) { crtc = fb_helper->crtc_info[i].mode_set.crtc; crtc_funcs = crtc->helper_private; @@ -654,10 +686,13 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) rc = setcolreg(crtc, hred, hgreen, hblue, start++, info); if (rc) - return rc; + goto out; } - crtc_funcs->load_lut(crtc); + if (crtc_funcs->load_lut) + crtc_funcs->load_lut(crtc); } + out: + drm_modeset_unlock_all(dev); return rc; } EXPORT_SYMBOL(drm_fb_helper_setcmap); diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index cf919e36e8ae..43217138816d 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -644,6 +644,55 @@ void drm_gem_vm_close(struct vm_area_struct *vma) } EXPORT_SYMBOL(drm_gem_vm_close); +/** + * drm_gem_mmap_obj - memory map a GEM object + * @obj: the GEM object to map + * @obj_size: the object size to be mapped, in bytes + * @vma: VMA for the area to be mapped + * + * Set up the VMA to prepare mapping of the GEM object using the gem_vm_ops + * provided by the driver. Depending on their requirements, drivers can either + * provide a fault handler in their gem_vm_ops (in which case any accesses to + * the object will be trapped, to perform migration, GTT binding, surface + * register allocation, or performance monitoring), or mmap the buffer memory + * synchronously after calling drm_gem_mmap_obj. + * + * This function is mainly intended to implement the DMABUF mmap operation, when + * the GEM object is not looked up based on its fake offset. To implement the + * DRM mmap operation, drivers should use the drm_gem_mmap() function. + * + * Return 0 or success or -EINVAL if the object size is smaller than the VMA + * size, or if no gem_vm_ops are provided. + */ +int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, + struct vm_area_struct *vma) +{ + struct drm_device *dev = obj->dev; + + /* Check for valid size. */ + if (obj_size < vma->vm_end - vma->vm_start) + return -EINVAL; + + if (!dev->driver->gem_vm_ops) + return -EINVAL; + + vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_ops = dev->driver->gem_vm_ops; + vma->vm_private_data = obj; + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + + /* Take a ref for this mapping of the object, so that the fault + * handler can dereference the mmap offset's pointer to the object. + * This reference is cleaned up by the corresponding vm_close + * (which should happen whether the vma was created by this call, or + * by a vm_open due to mremap or partial unmap or whatever). + */ + drm_gem_object_reference(obj); + + drm_vm_open_locked(dev, vma); + return 0; +} +EXPORT_SYMBOL(drm_gem_mmap_obj); /** * drm_gem_mmap - memory map routine for GEM objects @@ -653,11 +702,9 @@ EXPORT_SYMBOL(drm_gem_vm_close); * If a driver supports GEM object mapping, mmap calls on the DRM file * descriptor will end up here. * - * If we find the object based on the offset passed in (vma->vm_pgoff will + * Look up the GEM object based on the offset passed in (vma->vm_pgoff will * contain the fake offset we created when the GTT map ioctl was called on - * the object), we set up the driver fault handler so that any accesses - * to the object can be trapped, to perform migration, GTT binding, surface - * register allocation, or performance monitoring. + * the object) and map it with a call to drm_gem_mmap_obj(). */ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) { @@ -665,7 +712,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) struct drm_device *dev = priv->minor->dev; struct drm_gem_mm *mm = dev->mm_private; struct drm_local_map *map = NULL; - struct drm_gem_object *obj; struct drm_hash_item *hash; int ret = 0; @@ -686,32 +732,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) goto out_unlock; } - /* Check for valid size. */ - if (map->size < vma->vm_end - vma->vm_start) { - ret = -EINVAL; - goto out_unlock; - } - - obj = map->handle; - if (!obj->dev->driver->gem_vm_ops) { - ret = -EINVAL; - goto out_unlock; - } - - vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = obj->dev->driver->gem_vm_ops; - vma->vm_private_data = map->handle; - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); - - /* Take a ref for this mapping of the object, so that the fault - * handler can dereference the mmap offset's pointer to the object. - * This reference is cleaned up by the corresponding vm_close - * (which should happen whether the vma was created by this call, or - * by a vm_open due to mremap or partial unmap or whatever). - */ - drm_gem_object_reference(obj); - - drm_vm_open_locked(dev, vma); + ret = drm_gem_mmap_obj(map->handle, map->size, vma); out_unlock: mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index 0a7e011509bd..9efabceed42e 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/export.h> +#include <linux/dma-buf.h> #include <linux/dma-mapping.h> #include <drm/drmP.h> @@ -32,11 +33,44 @@ static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj) return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT; } -static void drm_gem_cma_buf_destroy(struct drm_device *drm, - struct drm_gem_cma_object *cma_obj) +/* + * __drm_gem_cma_create - Create a GEM CMA object without allocating memory + * @drm: The drm device + * @size: The GEM object size + * + * This function creates and initializes a GEM CMA object of the given size, but + * doesn't allocate any memory to back the object. + * + * Return a struct drm_gem_cma_object* on success or ERR_PTR values on failure. + */ +static struct drm_gem_cma_object * +__drm_gem_cma_create(struct drm_device *drm, unsigned int size) { - dma_free_writecombine(drm->dev, cma_obj->base.size, cma_obj->vaddr, - cma_obj->paddr); + struct drm_gem_cma_object *cma_obj; + struct drm_gem_object *gem_obj; + int ret; + + cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); + if (!cma_obj) + return ERR_PTR(-ENOMEM); + + gem_obj = &cma_obj->base; + + ret = drm_gem_object_init(drm, gem_obj, size); + if (ret) + goto error; + + ret = drm_gem_create_mmap_offset(gem_obj); + if (ret) { + drm_gem_object_release(gem_obj); + goto error; + } + + return cma_obj; + +error: + kfree(cma_obj); + return ERR_PTR(ret); } /* @@ -49,44 +83,42 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, unsigned int size) { struct drm_gem_cma_object *cma_obj; - struct drm_gem_object *gem_obj; + struct sg_table *sgt = NULL; int ret; size = round_up(size, PAGE_SIZE); - cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); - if (!cma_obj) - return ERR_PTR(-ENOMEM); + cma_obj = __drm_gem_cma_create(drm, size); + if (IS_ERR(cma_obj)) + return cma_obj; cma_obj->vaddr = dma_alloc_writecombine(drm->dev, size, &cma_obj->paddr, GFP_KERNEL | __GFP_NOWARN); if (!cma_obj->vaddr) { - dev_err(drm->dev, "failed to allocate buffer with size %d\n", size); + dev_err(drm->dev, "failed to allocate buffer with size %d\n", + size); ret = -ENOMEM; - goto err_dma_alloc; + goto error; } - gem_obj = &cma_obj->base; + sgt = kzalloc(sizeof(*cma_obj->sgt), GFP_KERNEL); + if (sgt == NULL) { + ret = -ENOMEM; + goto error; + } - ret = drm_gem_object_init(drm, gem_obj, size); - if (ret) - goto err_obj_init; + ret = dma_get_sgtable(drm->dev, sgt, cma_obj->vaddr, + cma_obj->paddr, size); + if (ret < 0) + goto error; - ret = drm_gem_create_mmap_offset(gem_obj); - if (ret) - goto err_create_mmap_offset; + cma_obj->sgt = sgt; return cma_obj; -err_create_mmap_offset: - drm_gem_object_release(gem_obj); - -err_obj_init: - drm_gem_cma_buf_destroy(drm, cma_obj); - -err_dma_alloc: - kfree(cma_obj); - +error: + kfree(sgt); + drm_gem_cma_free_object(&cma_obj->base); return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(drm_gem_cma_create); @@ -143,11 +175,20 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj) if (gem_obj->map_list.map) drm_gem_free_mmap_offset(gem_obj); - drm_gem_object_release(gem_obj); - cma_obj = to_drm_gem_cma_obj(gem_obj); - drm_gem_cma_buf_destroy(gem_obj->dev, cma_obj); + if (cma_obj->vaddr) { + dma_free_writecombine(gem_obj->dev->dev, cma_obj->base.size, + cma_obj->vaddr, cma_obj->paddr); + if (cma_obj->sgt) { + sg_free_table(cma_obj->sgt); + kfree(cma_obj->sgt); + } + } else if (gem_obj->import_attach) { + drm_prime_gem_destroy(gem_obj, cma_obj->sgt); + } + + drm_gem_object_release(gem_obj); kfree(cma_obj); } @@ -174,10 +215,7 @@ int drm_gem_cma_dumb_create(struct drm_file *file_priv, cma_obj = drm_gem_cma_create_with_handle(file_priv, dev, args->size, &args->handle); - if (IS_ERR(cma_obj)) - return PTR_ERR(cma_obj); - - return 0; + return PTR_RET(cma_obj); } EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create); @@ -215,13 +253,26 @@ const struct vm_operations_struct drm_gem_cma_vm_ops = { }; EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops); +static int drm_gem_cma_mmap_obj(struct drm_gem_cma_object *cma_obj, + struct vm_area_struct *vma) +{ + int ret; + + ret = remap_pfn_range(vma, vma->vm_start, cma_obj->paddr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); + if (ret) + drm_gem_vm_close(vma); + + return ret; +} + /* * drm_gem_cma_mmap - (struct file_operation)->mmap callback function */ int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma) { - struct drm_gem_object *gem_obj; struct drm_gem_cma_object *cma_obj; + struct drm_gem_object *gem_obj; int ret; ret = drm_gem_mmap(filp, vma); @@ -231,12 +282,7 @@ int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma) gem_obj = vma->vm_private_data; cma_obj = to_drm_gem_cma_obj(gem_obj); - ret = remap_pfn_range(vma, vma->vm_start, cma_obj->paddr >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); - if (ret) - drm_gem_vm_close(vma); - - return ret; + return drm_gem_cma_mmap_obj(cma_obj, vma); } EXPORT_SYMBOL_GPL(drm_gem_cma_mmap); @@ -270,3 +316,286 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m } EXPORT_SYMBOL_GPL(drm_gem_cma_describe); #endif + +/* ----------------------------------------------------------------------------- + * DMA-BUF + */ + +struct drm_gem_cma_dmabuf_attachment { + struct sg_table sgt; + enum dma_data_direction dir; +}; + +static int drm_gem_cma_dmabuf_attach(struct dma_buf *dmabuf, struct device *dev, + struct dma_buf_attachment *attach) +{ + struct drm_gem_cma_dmabuf_attachment *cma_attach; + + cma_attach = kzalloc(sizeof(*cma_attach), GFP_KERNEL); + if (!cma_attach) + return -ENOMEM; + + cma_attach->dir = DMA_NONE; + attach->priv = cma_attach; + + return 0; +} + +static void drm_gem_cma_dmabuf_detach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attach) +{ + struct drm_gem_cma_dmabuf_attachment *cma_attach = attach->priv; + struct sg_table *sgt; + + if (cma_attach == NULL) + return; + + sgt = &cma_attach->sgt; + + if (cma_attach->dir != DMA_NONE) + dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, + cma_attach->dir); + + sg_free_table(sgt); + kfree(cma_attach); + attach->priv = NULL; +} + +static struct sg_table * +drm_gem_cma_dmabuf_map(struct dma_buf_attachment *attach, + enum dma_data_direction dir) +{ + struct drm_gem_cma_dmabuf_attachment *cma_attach = attach->priv; + struct drm_gem_cma_object *cma_obj = attach->dmabuf->priv; + struct drm_device *drm = cma_obj->base.dev; + struct scatterlist *rd, *wr; + struct sg_table *sgt; + unsigned int i; + int nents, ret; + + DRM_DEBUG_PRIME("\n"); + + if (WARN_ON(dir == DMA_NONE)) + return ERR_PTR(-EINVAL); + + /* Return the cached mapping when possible. */ + if (cma_attach->dir == dir) + return &cma_attach->sgt; + + /* Two mappings with different directions for the same attachment are + * not allowed. + */ + if (WARN_ON(cma_attach->dir != DMA_NONE)) + return ERR_PTR(-EBUSY); + + sgt = &cma_attach->sgt; + + ret = sg_alloc_table(sgt, cma_obj->sgt->orig_nents, GFP_KERNEL); + if (ret) { + DRM_ERROR("failed to alloc sgt.\n"); + return ERR_PTR(-ENOMEM); + } + + mutex_lock(&drm->struct_mutex); + + rd = cma_obj->sgt->sgl; + wr = sgt->sgl; + for (i = 0; i < sgt->orig_nents; ++i) { + sg_set_page(wr, sg_page(rd), rd->length, rd->offset); + rd = sg_next(rd); + wr = sg_next(wr); + } + + nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir); + if (!nents) { + DRM_ERROR("failed to map sgl with iommu.\n"); + sg_free_table(sgt); + sgt = ERR_PTR(-EIO); + goto done; + } + + cma_attach->dir = dir; + attach->priv = cma_attach; + + DRM_DEBUG_PRIME("buffer size = %zu\n", cma_obj->base.size); + +done: + mutex_unlock(&drm->struct_mutex); + return sgt; +} + +static void drm_gem_cma_dmabuf_unmap(struct dma_buf_attachment *attach, + struct sg_table *sgt, + enum dma_data_direction dir) +{ + /* Nothing to do. */ +} + +static void drm_gem_cma_dmabuf_release(struct dma_buf *dmabuf) +{ + struct drm_gem_cma_object *cma_obj = dmabuf->priv; + + DRM_DEBUG_PRIME("%s\n", __FILE__); + + /* + * drm_gem_cma_dmabuf_release() call means that file object's + * f_count is 0 and it calls drm_gem_object_handle_unreference() + * to drop the references that these values had been increased + * at drm_prime_handle_to_fd() + */ + if (cma_obj->base.export_dma_buf == dmabuf) { + cma_obj->base.export_dma_buf = NULL; + + /* + * drop this gem object refcount to release allocated buffer + * and resources. + */ + drm_gem_object_unreference_unlocked(&cma_obj->base); + } +} + +static void *drm_gem_cma_dmabuf_kmap_atomic(struct dma_buf *dmabuf, + unsigned long page_num) +{ + /* TODO */ + + return NULL; +} + +static void drm_gem_cma_dmabuf_kunmap_atomic(struct dma_buf *dmabuf, + unsigned long page_num, void *addr) +{ + /* TODO */ +} + +static void *drm_gem_cma_dmabuf_kmap(struct dma_buf *dmabuf, + unsigned long page_num) +{ + /* TODO */ + + return NULL; +} + +static void drm_gem_cma_dmabuf_kunmap(struct dma_buf *dmabuf, + unsigned long page_num, void *addr) +{ + /* TODO */ +} + +static int drm_gem_cma_dmabuf_mmap(struct dma_buf *dmabuf, + struct vm_area_struct *vma) +{ + struct drm_gem_cma_object *cma_obj = dmabuf->priv; + struct drm_gem_object *gem_obj = &cma_obj->base; + int ret; + + ret = drm_gem_mmap_obj(gem_obj, gem_obj->size, vma); + if (ret < 0) + return ret; + + return drm_gem_cma_mmap_obj(cma_obj, vma); +} + +static void *drm_gem_cma_dmabuf_vmap(struct dma_buf *dmabuf) +{ + struct drm_gem_cma_object *cma_obj = dmabuf->priv; + + return cma_obj->vaddr; +} + +static struct dma_buf_ops drm_gem_cma_dmabuf_ops = { + .attach = drm_gem_cma_dmabuf_attach, + .detach = drm_gem_cma_dmabuf_detach, + .map_dma_buf = drm_gem_cma_dmabuf_map, + .unmap_dma_buf = drm_gem_cma_dmabuf_unmap, + .kmap = drm_gem_cma_dmabuf_kmap, + .kmap_atomic = drm_gem_cma_dmabuf_kmap_atomic, + .kunmap = drm_gem_cma_dmabuf_kunmap, + .kunmap_atomic = drm_gem_cma_dmabuf_kunmap_atomic, + .mmap = drm_gem_cma_dmabuf_mmap, + .vmap = drm_gem_cma_dmabuf_vmap, + .release = drm_gem_cma_dmabuf_release, +}; + +struct dma_buf *drm_gem_cma_dmabuf_export(struct drm_device *drm, + struct drm_gem_object *obj, int flags) +{ + struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj); + + return dma_buf_export(cma_obj, &drm_gem_cma_dmabuf_ops, + cma_obj->base.size, flags); +} +EXPORT_SYMBOL_GPL(drm_gem_cma_dmabuf_export); + +struct drm_gem_object *drm_gem_cma_dmabuf_import(struct drm_device *drm, + struct dma_buf *dma_buf) +{ + struct drm_gem_cma_object *cma_obj; + struct dma_buf_attachment *attach; + struct sg_table *sgt; + int ret; + + DRM_DEBUG_PRIME("%s\n", __FILE__); + + /* is this one of own objects? */ + if (dma_buf->ops == &drm_gem_cma_dmabuf_ops) { + struct drm_gem_object *obj; + + cma_obj = dma_buf->priv; + obj = &cma_obj->base; + + /* is it from our device? */ + if (obj->dev == drm) { + /* + * Importing dmabuf exported from out own gem increases + * refcount on gem itself instead of f_count of dmabuf. + */ + drm_gem_object_reference(obj); + dma_buf_put(dma_buf); + return obj; + } + } + + /* Create a CMA GEM buffer. */ + cma_obj = __drm_gem_cma_create(drm, dma_buf->size); + if (IS_ERR(cma_obj)) + return ERR_PTR(PTR_ERR(cma_obj)); + + /* Attach to the buffer and map it. Make sure the mapping is contiguous + * on the device memory bus, as that's all we support. + */ + attach = dma_buf_attach(dma_buf, drm->dev); + if (IS_ERR(attach)) { + ret = -EINVAL; + goto error_gem_free; + } + + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(sgt)) { + ret = sgt ? PTR_ERR(sgt) : -ENOMEM; + goto error_buf_detach; + } + + if (sgt->nents != 1) { + ret = -EINVAL; + goto error_buf_unmap; + } + + cma_obj->base.import_attach = attach; + cma_obj->paddr = sg_dma_address(sgt->sgl); + cma_obj->sgt = sgt; + + DRM_DEBUG_PRIME("dma_addr = 0x%x, size = %zu\n", cma_obj->paddr, + dma_buf->size); + + return &cma_obj->base; + +error_buf_unmap: + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); +error_buf_detach: + dma_buf_detach(dma_buf, attach); +error_gem_free: + drm_gem_cma_free_object(&cma_obj->base); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(drm_gem_cma_dmabuf_import); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index e77bd8b57df2..ffd7a7ba70d4 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -38,6 +38,9 @@ #include <linux/pci.h> #include <linux/export.h> +#ifdef CONFIG_X86 +#include <asm/mtrr.h> +#endif /** * Get the bus id. @@ -181,7 +184,17 @@ int drm_getmap(struct drm_device *dev, void *data, map->type = r_list->map->type; map->flags = r_list->map->flags; map->handle = (void *)(unsigned long) r_list->user_token; - map->mtrr = r_list->map->mtrr; + +#ifdef CONFIG_X86 + /* + * There appears to be exactly one user of the mtrr index: dritest. + * It's easy enough to keep it working on non-PAT systems. + */ + map->mtrr = phys_wc_to_mtrr_index(r_list->map->mtrr); +#else + map->mtrr = -1; +#endif + mutex_unlock(&dev->struct_mutex); return 0; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index a6a8643a6a77..8bcce7866d36 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1054,7 +1054,7 @@ EXPORT_SYMBOL(drm_vblank_off); */ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) { - /* vblank is not initialized (IRQ not installed ?) */ + /* vblank is not initialized (IRQ not installed ?), or has been freed */ if (!dev->num_crtcs) return; /* @@ -1076,6 +1076,10 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc) { unsigned long irqflags; + /* vblank is not initialized (IRQ not installed ?), or has been freed */ + if (!dev->num_crtcs) + return; + if (dev->vblank_inmodeset[crtc]) { spin_lock_irqsave(&dev->vbl_lock, irqflags); dev->vblank_disable_allowed = 1; diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index a371ff865a88..a6729bfe6860 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -535,6 +535,8 @@ int drm_display_mode_from_videomode(const struct videomode *vm, dmode->flags |= DRM_MODE_FLAG_INTERLACE; if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN) dmode->flags |= DRM_MODE_FLAG_DBLSCAN; + if (vm->flags & DISPLAY_FLAGS_DOUBLECLK) + dmode->flags |= DRM_MODE_FLAG_DBLCLK; drm_mode_set_name(dmode); return 0; @@ -787,16 +789,17 @@ EXPORT_SYMBOL(drm_mode_set_crtcinfo); * LOCKING: * None. * - * Copy an existing mode into another mode, preserving the object id - * of the destination mode. + * Copy an existing mode into another mode, preserving the object id and + * list head of the destination mode. */ void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src) { int id = dst->base.id; + struct list_head head = dst->head; *dst = *src; dst->base.id = id; - INIT_LIST_HEAD(&dst->head); + dst->head = head; } EXPORT_SYMBOL(drm_mode_copy); @@ -1017,6 +1020,11 @@ static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay; if (diff) return diff; + + diff = b->vrefresh - a->vrefresh; + if (diff) + return diff; + diff = b->clock - a->clock; return diff; } diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 14194b6ef644..80c0b2b29801 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -278,10 +278,10 @@ static int drm_pci_agp_init(struct drm_device *dev) } if (drm_core_has_MTRR(dev)) { if (dev->agp) - dev->agp->agp_mtrr = - mtrr_add(dev->agp->agp_info.aper_base, - dev->agp->agp_info.aper_size * - 1024 * 1024, MTRR_TYPE_WRCOMB, 1); + dev->agp->agp_mtrr = arch_phys_wc_add( + dev->agp->agp_info.aper_base, + dev->agp->agp_info.aper_size * + 1024 * 1024); } } return 0; diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index dcde35231e25..e57c675db840 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -64,6 +64,29 @@ struct drm_prime_member { }; static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); +static int drm_gem_map_attach(struct dma_buf *dma_buf, + struct device *target_dev, + struct dma_buf_attachment *attach) +{ + struct drm_gem_object *obj = dma_buf->priv; + struct drm_device *dev = obj->dev; + + if (!dev->driver->gem_prime_pin) + return 0; + + return dev->driver->gem_prime_pin(obj); +} + +static void drm_gem_map_detach(struct dma_buf *dma_buf, + struct dma_buf_attachment *attach) +{ + struct drm_gem_object *obj = dma_buf->priv; + struct drm_device *dev = obj->dev; + + if (dev->driver->gem_prime_unpin) + dev->driver->gem_prime_unpin(obj); +} + static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir) { @@ -146,6 +169,8 @@ static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf, } static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { + .attach = drm_gem_map_attach, + .detach = drm_gem_map_detach, .map_dma_buf = drm_gem_map_dma_buf, .unmap_dma_buf = drm_gem_unmap_dma_buf, .release = drm_gem_dmabuf_release, @@ -185,13 +210,7 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { struct dma_buf *drm_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags) { - if (dev->driver->gem_prime_pin) { - int ret = dev->driver->gem_prime_pin(obj); - if (ret) - return ERR_PTR(ret); - } - return dma_buf_export(obj, &drm_gem_prime_dmabuf_ops, obj->size, - 0600); + return dma_buf_export(obj, &drm_gem_prime_dmabuf_ops, obj->size, flags); } EXPORT_SYMBOL(drm_gem_prime_export); @@ -277,7 +296,7 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, attach = dma_buf_attach(dma_buf, dev->dev); if (IS_ERR(attach)) - return ERR_PTR(PTR_ERR(attach)); + return ERR_CAST(attach); get_dma_buf(dma_buf); diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 16f3ec579b3b..327ca19cda85 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -203,7 +203,7 @@ EXPORT_SYMBOL(drm_master_put); int drm_setmaster_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - int ret; + int ret = 0; if (file_priv->is_master) return 0; @@ -229,7 +229,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, } mutex_unlock(&dev->struct_mutex); - return 0; + return ret; } int drm_dropmaster_ioctl(struct drm_device *dev, void *data, @@ -451,14 +451,8 @@ void drm_put_dev(struct drm_device *dev) drm_lastclose(dev); - if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && - dev->agp && dev->agp->agp_mtrr >= 0) { - int retval; - retval = mtrr_del(dev->agp->agp_mtrr, - dev->agp->agp_info.aper_base, - dev->agp->agp_info.aper_size * 1024 * 1024); - DRM_DEBUG("mtrr_del=%d\n", retval); - } + if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && dev->agp) + arch_phys_wc_del(dev->agp->agp_mtrr); if (dev->driver->unload) dev->driver->unload(dev); diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 1d4f7c9fe661..feb20035b2c4 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -43,18 +43,19 @@ static void drm_vm_open(struct vm_area_struct *vma); static void drm_vm_close(struct vm_area_struct *vma); -static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) +static pgprot_t drm_io_prot(struct drm_local_map *map, + struct vm_area_struct *vma) { pgprot_t tmp = vm_get_page_prot(vma->vm_flags); #if defined(__i386__) || defined(__x86_64__) - if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) { - pgprot_val(tmp) |= _PAGE_PCD; - pgprot_val(tmp) &= ~_PAGE_PWT; - } + if (map->type == _DRM_REGISTERS && !(map->flags & _DRM_WRITE_COMBINING)) + tmp = pgprot_noncached(tmp); + else + tmp = pgprot_writecombine(tmp); #elif defined(__powerpc__) pgprot_val(tmp) |= _PAGE_NO_CACHE; - if (map_type == _DRM_REGISTERS) + if (map->type == _DRM_REGISTERS) pgprot_val(tmp) |= _PAGE_GUARDED; #elif defined(__ia64__) if (efi_range_is_wc(vma->vm_start, vma->vm_end - @@ -250,13 +251,8 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: - if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { - int retcode; - retcode = mtrr_del(map->mtrr, - map->offset, - map->size); - DRM_DEBUG("mtrr_del = %d\n", retcode); - } + if (drm_core_has_MTRR(dev)) + arch_phys_wc_del(map->mtrr); iounmap(map->handle); break; case _DRM_SHM: @@ -617,8 +613,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: offset = drm_core_get_reg_ofs(dev); - vma->vm_flags |= VM_IO; /* not in core dump */ - vma->vm_page_prot = drm_io_prot(map->type, vma); + vma->vm_page_prot = drm_io_prot(map, vma); if (io_remap_pfn_range(vma, vma->vm_start, (map->offset + offset) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index e8894bc9e6d5..073c10a35b2a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -48,6 +48,8 @@ struct exynos_drm_crtc { unsigned int pipe; unsigned int dpms; enum exynos_crtc_mode mode; + wait_queue_head_t pending_flip_queue; + atomic_t pending_flip; }; static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -61,6 +63,13 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) return; } + if (mode > DRM_MODE_DPMS_ON) { + /* wait for the completion of page flip. */ + wait_event(exynos_crtc->pending_flip_queue, + atomic_read(&exynos_crtc->pending_flip) == 0); + drm_vblank_off(crtc->dev, exynos_crtc->pipe); + } + exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); exynos_crtc->dpms = mode; } @@ -160,12 +169,6 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc) -{ - DRM_DEBUG_KMS("%s\n", __FILE__); - /* drm framework doesn't check NULL */ -} - static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); @@ -183,7 +186,6 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .mode_fixup = exynos_drm_crtc_mode_fixup, .mode_set = exynos_drm_crtc_mode_set, .mode_set_base = exynos_drm_crtc_mode_set_base, - .load_lut = exynos_drm_crtc_load_lut, .disable = exynos_drm_crtc_disable, }; @@ -217,7 +219,6 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, ret = drm_vblank_get(dev, exynos_crtc->pipe); if (ret) { DRM_DEBUG("failed to acquire vblank counter\n"); - list_del(&event->base.link); goto out; } @@ -225,6 +226,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, spin_lock_irq(&dev->event_lock); list_add_tail(&event->base.link, &dev_priv->pageflip_event_list); + atomic_set(&exynos_crtc->pending_flip, 1); spin_unlock_irq(&dev->event_lock); crtc->fb = fb; @@ -344,6 +346,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) exynos_crtc->pipe = nr; exynos_crtc->dpms = DRM_MODE_DPMS_OFF; + init_waitqueue_head(&exynos_crtc->pending_flip_queue); + atomic_set(&exynos_crtc->pending_flip, 0); exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true); if (!exynos_crtc->plane) { kfree(exynos_crtc); @@ -398,7 +402,8 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) { struct exynos_drm_private *dev_priv = dev->dev_private; struct drm_pending_vblank_event *e, *t; - struct timeval now; + struct drm_crtc *drm_crtc = dev_priv->crtc[crtc]; + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); unsigned long flags; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -411,14 +416,11 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) if (crtc != e->pipe) continue; - do_gettimeofday(&now); - e->event.sequence = 0; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; - - list_move_tail(&e->base.link, &e->base.file_priv->event_list); - wake_up_interruptible(&e->base.file_priv->event_wait); + list_del(&e->base.link); + drm_send_vblank_event(dev, -1, e); drm_vblank_put(dev, crtc); + atomic_set(&exynos_crtc->pending_flip, 0); + wake_up(&exynos_crtc->pending_flip_queue); } spin_unlock_irqrestore(&dev->event_lock, flags); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 68f0045f86b8..8f007aaeffc3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -182,7 +182,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &exynos_gem_obj->base); - if (IS_ERR_OR_NULL(helper->fb)) { + if (IS_ERR(helper->fb)) { DRM_ERROR("failed to create drm framebuffer.\n"); ret = PTR_ERR(helper->fb); goto err_destroy_gem; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 773f583fa964..4a1616a18ab7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -12,9 +12,9 @@ * */ #include <linux/kernel.h> -#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/mfd/syscon.h> #include <linux/regmap.h> #include <linux/clk.h> #include <linux/pm_runtime.h> @@ -1845,7 +1845,7 @@ static int fimc_probe(struct platform_device *pdev) } ctx->irq = res->start; - ret = request_threaded_irq(ctx->irq, NULL, fimc_irq_handler, + ret = devm_request_threaded_irq(dev, ctx->irq, NULL, fimc_irq_handler, IRQF_ONESHOT, "drm_fimc", ctx); if (ret < 0) { dev_err(dev, "failed to request irq.\n"); @@ -1854,7 +1854,7 @@ static int fimc_probe(struct platform_device *pdev) ret = fimc_setup_clocks(ctx); if (ret < 0) - goto err_free_irq; + return ret; ippdrv = &ctx->ippdrv; ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops; @@ -1884,7 +1884,7 @@ static int fimc_probe(struct platform_device *pdev) goto err_pm_dis; } - dev_info(&pdev->dev, "drm fimc registered successfully.\n"); + dev_info(dev, "drm fimc registered successfully.\n"); return 0; @@ -1892,8 +1892,6 @@ err_pm_dis: pm_runtime_disable(dev); err_put_clk: fimc_put_clocks(ctx); -err_free_irq: - free_irq(ctx->irq, ctx); return ret; } @@ -1911,8 +1909,6 @@ static int fimc_remove(struct platform_device *pdev) pm_runtime_set_suspended(dev); pm_runtime_disable(dev); - free_irq(ctx->irq, ctx); - return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 746b282b343a..97c61dbffd82 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -885,7 +885,7 @@ static int fimd_probe(struct platform_device *pdev) DRM_DEBUG_KMS("%s\n", __FILE__); - if (pdev->dev.of_node) { + if (dev->of_node) { pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { DRM_ERROR("memory allocation for pdata failed\n"); @@ -899,7 +899,7 @@ static int fimd_probe(struct platform_device *pdev) return ret; } } else { - pdata = pdev->dev.platform_data; + pdata = dev->platform_data; if (!pdata) { DRM_ERROR("no platform data specified\n"); return -EINVAL; @@ -912,7 +912,7 @@ static int fimd_probe(struct platform_device *pdev) return -EINVAL; } - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -930,7 +930,7 @@ static int fimd_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ctx->regs = devm_ioremap_resource(&pdev->dev, res); + ctx->regs = devm_ioremap_resource(dev, res); if (IS_ERR(ctx->regs)) return PTR_ERR(ctx->regs); @@ -942,7 +942,7 @@ static int fimd_probe(struct platform_device *pdev) ctx->irq = res->start; - ret = devm_request_irq(&pdev->dev, ctx->irq, fimd_irq_handler, + ret = devm_request_irq(dev, ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx); if (ret) { dev_err(dev, "irq request failed.\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 47a493c8a71f..af75434ee4d7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -1379,7 +1379,7 @@ static int g2d_probe(struct platform_device *pdev) struct exynos_drm_subdrv *subdrv; int ret; - g2d = devm_kzalloc(&pdev->dev, sizeof(*g2d), GFP_KERNEL); + g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL); if (!g2d) { dev_err(dev, "failed to allocate driver data\n"); return -ENOMEM; @@ -1417,7 +1417,7 @@ static int g2d_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - g2d->regs = devm_ioremap_resource(&pdev->dev, res); + g2d->regs = devm_ioremap_resource(dev, res); if (IS_ERR(g2d->regs)) { ret = PTR_ERR(g2d->regs); goto err_put_clk; @@ -1430,7 +1430,7 @@ static int g2d_probe(struct platform_device *pdev) goto err_put_clk; } - ret = devm_request_irq(&pdev->dev, g2d->irq, g2d_irq_handler, 0, + ret = devm_request_irq(dev, g2d->irq, g2d_irq_handler, 0, "drm_g2d", g2d); if (ret < 0) { dev_err(dev, "irq request failed\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 7841c3b8a20e..762f40d548b7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -1704,7 +1704,7 @@ static int gsc_probe(struct platform_device *pdev) } ctx->irq = res->start; - ret = request_threaded_irq(ctx->irq, NULL, gsc_irq_handler, + ret = devm_request_threaded_irq(dev, ctx->irq, NULL, gsc_irq_handler, IRQF_ONESHOT, "drm_gsc", ctx); if (ret < 0) { dev_err(dev, "failed to request irq.\n"); @@ -1725,7 +1725,7 @@ static int gsc_probe(struct platform_device *pdev) ret = gsc_init_prop_list(ippdrv); if (ret < 0) { dev_err(dev, "failed to init property list.\n"); - goto err_get_irq; + return ret; } DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id, @@ -1743,15 +1743,12 @@ static int gsc_probe(struct platform_device *pdev) goto err_ippdrv_register; } - dev_info(&pdev->dev, "drm gsc registered successfully.\n"); + dev_info(dev, "drm gsc registered successfully.\n"); return 0; err_ippdrv_register: - devm_kfree(dev, ippdrv->prop_list); pm_runtime_disable(dev); -err_get_irq: - free_irq(ctx->irq, ctx); return ret; } @@ -1761,15 +1758,12 @@ static int gsc_remove(struct platform_device *pdev) struct gsc_context *ctx = get_gsc_context(dev); struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; - devm_kfree(dev, ippdrv->prop_list); exynos_drm_ippdrv_unregister(ippdrv); mutex_destroy(&ctx->lock); pm_runtime_set_suspended(dev); pm_runtime_disable(dev); - free_irq(ctx->irq, ctx); - return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index ba2f0f1aa05f..437fb947e46d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -442,7 +442,7 @@ static int exynos_drm_hdmi_probe(struct platform_device *pdev) DRM_DEBUG_KMS("%s\n", __FILE__); - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) { DRM_LOG_KMS("failed to alloc common hdmi context.\n"); return -ENOMEM; diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 29d2ad314490..be1e88463466 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -222,7 +222,7 @@ static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx, /* find ipp driver using idr */ ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, ipp_id); - if (IS_ERR_OR_NULL(ippdrv)) { + if (IS_ERR(ippdrv)) { DRM_ERROR("not found ipp%d driver.\n", ipp_id); return ippdrv; } @@ -388,7 +388,7 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property) DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, prop_id); ippdrv = ipp_find_drv_by_handle(prop_id); - if (IS_ERR_OR_NULL(ippdrv)) { + if (IS_ERR(ippdrv)) { DRM_ERROR("failed to get ipp driver.\n"); return -EINVAL; } @@ -492,7 +492,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, /* find ipp driver using ipp id */ ippdrv = ipp_find_driver(ctx, property); - if (IS_ERR_OR_NULL(ippdrv)) { + if (IS_ERR(ippdrv)) { DRM_ERROR("failed to get ipp driver.\n"); return -EINVAL; } @@ -521,19 +521,19 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, c_node->state = IPP_STATE_IDLE; c_node->start_work = ipp_create_cmd_work(); - if (IS_ERR_OR_NULL(c_node->start_work)) { + if (IS_ERR(c_node->start_work)) { DRM_ERROR("failed to create start work.\n"); goto err_clear; } c_node->stop_work = ipp_create_cmd_work(); - if (IS_ERR_OR_NULL(c_node->stop_work)) { + if (IS_ERR(c_node->stop_work)) { DRM_ERROR("failed to create stop work.\n"); goto err_free_start; } c_node->event_work = ipp_create_event_work(); - if (IS_ERR_OR_NULL(c_node->event_work)) { + if (IS_ERR(c_node->event_work)) { DRM_ERROR("failed to create event work.\n"); goto err_free_stop; } @@ -915,7 +915,7 @@ static int ipp_queue_buf_with_run(struct device *dev, DRM_DEBUG_KMS("%s\n", __func__); ippdrv = ipp_find_drv_by_handle(qbuf->prop_id); - if (IS_ERR_OR_NULL(ippdrv)) { + if (IS_ERR(ippdrv)) { DRM_ERROR("failed to get ipp driver.\n"); return -EFAULT; } @@ -1909,7 +1909,7 @@ static int ipp_probe(struct platform_device *pdev) struct exynos_drm_subdrv *subdrv; int ret; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -1963,7 +1963,7 @@ static int ipp_probe(struct platform_device *pdev) goto err_cmd_workq; } - dev_info(&pdev->dev, "drm ipp registered successfully.\n"); + dev_info(dev, "drm ipp registered successfully.\n"); return 0; diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index 947f09f15ad1..9b6c70964d71 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c @@ -666,8 +666,8 @@ static int rotator_probe(struct platform_device *pdev) return rot->irq; } - ret = request_threaded_irq(rot->irq, NULL, rotator_irq_handler, - IRQF_ONESHOT, "drm_rotator", rot); + ret = devm_request_threaded_irq(dev, rot->irq, NULL, + rotator_irq_handler, IRQF_ONESHOT, "drm_rotator", rot); if (ret < 0) { dev_err(dev, "failed to request irq\n"); return ret; @@ -676,8 +676,7 @@ static int rotator_probe(struct platform_device *pdev) rot->clock = devm_clk_get(dev, "rotator"); if (IS_ERR(rot->clock)) { dev_err(dev, "failed to get clock\n"); - ret = PTR_ERR(rot->clock); - goto err_clk_get; + return PTR_ERR(rot->clock); } pm_runtime_enable(dev); @@ -709,10 +708,7 @@ static int rotator_probe(struct platform_device *pdev) return 0; err_ippdrv_register: - devm_kfree(dev, ippdrv->prop_list); pm_runtime_disable(dev); -err_clk_get: - free_irq(rot->irq, rot); return ret; } @@ -722,13 +718,10 @@ static int rotator_remove(struct platform_device *pdev) struct rot_context *rot = dev_get_drvdata(dev); struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv; - devm_kfree(dev, ippdrv->prop_list); exynos_drm_ippdrv_unregister(ippdrv); pm_runtime_disable(dev); - free_irq(rot->irq, rot); - return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 9504b0cd825a..24376c194a5e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -594,7 +594,7 @@ static int vidi_probe(struct platform_device *pdev) DRM_DEBUG_KMS("%s\n", __FILE__); - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -612,7 +612,7 @@ static int vidi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ret = device_create_file(&pdev->dev, &dev_attr_connection); + ret = device_create_file(dev, &dev_attr_connection); if (ret < 0) DRM_INFO("failed to create connection sysfs.\n"); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 6652597586a1..fd1426dca882 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1946,14 +1946,14 @@ static int hdmi_probe(struct platform_device *pdev) DRM_DEBUG_KMS("[%d]\n", __LINE__); - if (pdev->dev.of_node) { + if (dev->of_node) { pdata = drm_hdmi_dt_parse_pdata(dev); if (IS_ERR(pdata)) { DRM_ERROR("failed to parse dt\n"); return PTR_ERR(pdata); } } else { - pdata = pdev->dev.platform_data; + pdata = dev->platform_data; } if (!pdata) { @@ -1961,14 +1961,14 @@ static int hdmi_probe(struct platform_device *pdev) return -EINVAL; } - drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx), + drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL); if (!drm_hdmi_ctx) { DRM_ERROR("failed to allocate common hdmi context.\n"); return -ENOMEM; } - hdata = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_context), + hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); if (!hdata) { DRM_ERROR("out of memory\n"); @@ -1985,7 +1985,7 @@ static int hdmi_probe(struct platform_device *pdev) if (dev->of_node) { const struct of_device_id *match; match = of_match_node(of_match_ptr(hdmi_match_types), - pdev->dev.of_node); + dev->of_node); if (match == NULL) return -ENODEV; hdata->type = (enum hdmi_type)match->data; @@ -2005,11 +2005,11 @@ static int hdmi_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hdata->regs = devm_ioremap_resource(&pdev->dev, res); + hdata->regs = devm_ioremap_resource(dev, res); if (IS_ERR(hdata->regs)) return PTR_ERR(hdata->regs); - ret = devm_gpio_request(&pdev->dev, hdata->hpd_gpio, "HPD"); + ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD"); if (ret) { DRM_ERROR("failed to request HPD gpio\n"); return ret; @@ -2041,7 +2041,7 @@ static int hdmi_probe(struct platform_device *pdev) hdata->hpd = gpio_get_value(hdata->hpd_gpio); - ret = request_threaded_irq(hdata->irq, NULL, + ret = devm_request_threaded_irq(dev, hdata->irq, NULL, hdmi_irq_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "hdmi", drm_hdmi_ctx); @@ -2070,16 +2070,11 @@ err_ddc: static int hdmi_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev); - struct hdmi_context *hdata = ctx->ctx; DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); pm_runtime_disable(dev); - free_irq(hdata->irq, hdata); - - /* hdmiphy i2c driver */ i2c_del_driver(&hdmiphy_driver); /* DDC i2c driver */ diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index ec3e376b7e01..7c197d3820c5 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1061,7 +1061,7 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx, return -ENXIO; } - mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start, + mixer_res->mixer_regs = devm_ioremap(dev, res->start, resource_size(res)); if (mixer_res->mixer_regs == NULL) { dev_err(dev, "register mapping failed.\n"); @@ -1074,7 +1074,7 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx, return -ENXIO; } - ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler, + ret = devm_request_irq(dev, res->start, mixer_irq_handler, 0, "drm_mixer", ctx); if (ret) { dev_err(dev, "request interrupt failed.\n"); @@ -1118,7 +1118,7 @@ static int vp_resources_init(struct exynos_drm_hdmi_context *ctx, return -ENXIO; } - mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start, + mixer_res->vp_regs = devm_ioremap(dev, res->start, resource_size(res)); if (mixer_res->vp_regs == NULL) { dev_err(dev, "register mapping failed.\n"); @@ -1169,14 +1169,14 @@ static int mixer_probe(struct platform_device *pdev) dev_info(dev, "probe start\n"); - drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx), + drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL); if (!drm_hdmi_ctx) { DRM_ERROR("failed to allocate common hdmi context.\n"); return -ENOMEM; } - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) { DRM_ERROR("failed to alloc mixer context.\n"); return -ENOMEM; @@ -1187,14 +1187,14 @@ static int mixer_probe(struct platform_device *pdev) if (dev->of_node) { const struct of_device_id *match; match = of_match_node(of_match_ptr(mixer_match_types), - pdev->dev.of_node); + dev->of_node); drv = (struct mixer_drv_data *)match->data; } else { drv = (struct mixer_drv_data *) platform_get_device_id(pdev)->driver_data; } - ctx->dev = &pdev->dev; + ctx->dev = dev; ctx->parent_ctx = (void *)drm_hdmi_ctx; drm_hdmi_ctx->ctx = (void *)ctx; ctx->vp_enabled = drv->is_vp_enabled; diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c index 3cfd0931fbfb..82430ad8ba62 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_display.c +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c @@ -1462,7 +1462,7 @@ static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc, size_t addr = 0; struct gtt_range *gt; struct drm_gem_object *obj; - int ret; + int ret = 0; /* if we want to turn of the cursor ignore width and height */ if (!handle) { @@ -1499,7 +1499,8 @@ static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc, if (obj->size < width * height * 4) { dev_dbg(dev->dev, "buffer is to small\n"); - return -ENOMEM; + ret = -ENOMEM; + goto unref_cursor; } gt = container_of(obj, struct gtt_range, gem); @@ -1508,7 +1509,7 @@ static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc, ret = psb_gtt_pin(gt); if (ret) { dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle); - return ret; + goto unref_cursor; } addr = gt->offset; /* Or resource.start ??? */ @@ -1532,9 +1533,14 @@ static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc, struct gtt_range, gem); psb_gtt_unpin(gt); drm_gem_object_unreference(psb_intel_crtc->cursor_obj); - psb_intel_crtc->cursor_obj = obj; } - return 0; + + psb_intel_crtc->cursor_obj = obj; + return ret; + +unref_cursor: + drm_gem_object_unreference(obj); + return ret; } static int cdv_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) @@ -1750,6 +1756,19 @@ static void cdv_intel_crtc_destroy(struct drm_crtc *crtc) kfree(psb_intel_crtc); } +static void cdv_intel_crtc_disable(struct drm_crtc *crtc) +{ + struct gtt_range *gt; + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); + + if (crtc->fb) { + gt = to_psb_fb(crtc->fb)->gtt; + psb_gtt_unpin(gt); + } +} + const struct drm_crtc_helper_funcs cdv_intel_helper_funcs = { .dpms = cdv_intel_crtc_dpms, .mode_fixup = cdv_intel_crtc_mode_fixup, @@ -1757,6 +1776,7 @@ const struct drm_crtc_helper_funcs cdv_intel_helper_funcs = { .mode_set_base = cdv_intel_pipe_set_base, .prepare = cdv_intel_crtc_prepare, .commit = cdv_intel_crtc_commit, + .disable = cdv_intel_crtc_disable, }; const struct drm_crtc_funcs cdv_intel_crtc_funcs = { diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 1534e220097a..8b1b6d923abe 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -121,8 +121,8 @@ static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) unsigned long address; int ret; unsigned long pfn; - /* FIXME: assumes fb at stolen base which may not be true */ - unsigned long phys_addr = (unsigned long)dev_priv->stolen_base; + unsigned long phys_addr = (unsigned long)dev_priv->stolen_base + + psbfb->gtt->offset; page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; address = (unsigned long)vmf->virtual_address - (vmf->pgoff << PAGE_SHIFT); diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index 6e8f42b61ff6..6666493789d1 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -843,7 +843,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc, struct gtt_range *cursor_gt = psb_intel_crtc->cursor_gt; struct drm_gem_object *obj; void *tmp_dst, *tmp_src; - int ret, i, cursor_pages; + int ret = 0, i, cursor_pages; /* if we want to turn of the cursor ignore width and height */ if (!handle) { @@ -880,7 +880,8 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc, if (obj->size < width * height * 4) { dev_dbg(dev->dev, "buffer is to small\n"); - return -ENOMEM; + ret = -ENOMEM; + goto unref_cursor; } gt = container_of(obj, struct gtt_range, gem); @@ -889,13 +890,14 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc, ret = psb_gtt_pin(gt); if (ret) { dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle); - return ret; + goto unref_cursor; } if (dev_priv->ops->cursor_needs_phys) { if (cursor_gt == NULL) { dev_err(dev->dev, "No hardware cursor mem available"); - return -ENOMEM; + ret = -ENOMEM; + goto unref_cursor; } /* Prevent overflow */ @@ -936,9 +938,14 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc, struct gtt_range, gem); psb_gtt_unpin(gt); drm_gem_object_unreference(psb_intel_crtc->cursor_obj); - psb_intel_crtc->cursor_obj = obj; } - return 0; + + psb_intel_crtc->cursor_obj = obj; + return ret; + +unref_cursor: + drm_gem_object_unreference(obj); + return ret; } static int psb_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) @@ -1150,6 +1157,19 @@ static void psb_intel_crtc_destroy(struct drm_crtc *crtc) kfree(psb_intel_crtc); } +static void psb_intel_crtc_disable(struct drm_crtc *crtc) +{ + struct gtt_range *gt; + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); + + if (crtc->fb) { + gt = to_psb_fb(crtc->fb)->gtt; + psb_gtt_unpin(gt); + } +} + const struct drm_crtc_helper_funcs psb_intel_helper_funcs = { .dpms = psb_intel_crtc_dpms, .mode_fixup = psb_intel_crtc_mode_fixup, @@ -1157,6 +1177,7 @@ const struct drm_crtc_helper_funcs psb_intel_helper_funcs = { .mode_set_base = psb_intel_pipe_set_base, .prepare = psb_intel_crtc_prepare, .commit = psb_intel_crtc_commit, + .disable = psb_intel_crtc_disable, }; const struct drm_crtc_funcs psb_intel_crtc_funcs = { diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8e628dc43a5f..adb319b53ecd 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -42,7 +42,6 @@ #include <linux/vga_switcheroo.h> #include <linux/slab.h> #include <acpi/video.h> -#include <asm/pat.h> #define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS]) @@ -1401,29 +1400,6 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) master->driver_priv = NULL; } -static void -i915_mtrr_setup(struct drm_i915_private *dev_priv, unsigned long base, - unsigned long size) -{ - dev_priv->mm.gtt_mtrr = -1; - -#if defined(CONFIG_X86_PAT) - if (cpu_has_pat) - return; -#endif - - /* Set up a WC MTRR for non-PAT systems. This is more common than - * one would think, because the kernel disables PAT on first - * generation Core chips because WC PAT gets overridden by a UC - * MTRR if present. Even if a UC MTRR isn't present. - */ - dev_priv->mm.gtt_mtrr = mtrr_add(base, size, MTRR_TYPE_WRCOMB, 1); - if (dev_priv->mm.gtt_mtrr < 0) { - DRM_INFO("MTRR allocation failed. Graphics " - "performance may suffer.\n"); - } -} - static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) { struct apertures_struct *ap; @@ -1582,8 +1558,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_rmmap; } - i915_mtrr_setup(dev_priv, dev_priv->gtt.mappable_base, - aperture_size); + dev_priv->mm.gtt_mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base, + aperture_size); /* The i915 workqueue is primarily used for batched retirement of * requests (and thus managing bo) once the task has been completed @@ -1691,12 +1667,7 @@ out_gem_unload: intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->wq); out_mtrrfree: - if (dev_priv->mm.gtt_mtrr >= 0) { - mtrr_del(dev_priv->mm.gtt_mtrr, - dev_priv->gtt.mappable_base, - aperture_size); - dev_priv->mm.gtt_mtrr = -1; - } + arch_phys_wc_del(dev_priv->mm.gtt_mtrr); io_mapping_free(dev_priv->gtt.mappable); dev_priv->gtt.gtt_remove(dev); out_rmmap: @@ -1734,12 +1705,7 @@ int i915_driver_unload(struct drm_device *dev) cancel_delayed_work_sync(&dev_priv->mm.retire_work); io_mapping_free(dev_priv->gtt.mappable); - if (dev_priv->mm.gtt_mtrr >= 0) { - mtrr_del(dev_priv->mm.gtt_mtrr, - dev_priv->gtt.mappable_base, - dev_priv->gtt.mappable_end); - dev_priv->mm.gtt_mtrr = -1; - } + arch_phys_wc_del(dev_priv->mm.gtt_mtrr); acpi_video_unregister(); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c3e4f2915e5b..deaa32e8113b 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -376,40 +376,64 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */ INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */ INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */ - INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT2 desktop */ + INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT3 desktop */ INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */ INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */ - INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT2 server */ + INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT3 server */ INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */ INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */ INTEL_VGA_DEVICE(0x0426, &intel_haswell_m_info), /* GT2 mobile */ + INTEL_VGA_DEVICE(0x040B, &intel_haswell_d_info), /* GT1 reserved */ + INTEL_VGA_DEVICE(0x041B, &intel_haswell_d_info), /* GT2 reserved */ + INTEL_VGA_DEVICE(0x042B, &intel_haswell_d_info), /* GT3 reserved */ + INTEL_VGA_DEVICE(0x040E, &intel_haswell_d_info), /* GT1 reserved */ + INTEL_VGA_DEVICE(0x041E, &intel_haswell_d_info), /* GT2 reserved */ + INTEL_VGA_DEVICE(0x042E, &intel_haswell_d_info), /* GT3 reserved */ INTEL_VGA_DEVICE(0x0C02, &intel_haswell_d_info), /* SDV GT1 desktop */ INTEL_VGA_DEVICE(0x0C12, &intel_haswell_d_info), /* SDV GT2 desktop */ - INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT2 desktop */ + INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT3 desktop */ INTEL_VGA_DEVICE(0x0C0A, &intel_haswell_d_info), /* SDV GT1 server */ INTEL_VGA_DEVICE(0x0C1A, &intel_haswell_d_info), /* SDV GT2 server */ - INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT2 server */ + INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT3 server */ INTEL_VGA_DEVICE(0x0C06, &intel_haswell_m_info), /* SDV GT1 mobile */ INTEL_VGA_DEVICE(0x0C16, &intel_haswell_m_info), /* SDV GT2 mobile */ - INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT2 mobile */ + INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT3 mobile */ + INTEL_VGA_DEVICE(0x0C0B, &intel_haswell_d_info), /* SDV GT1 reserved */ + INTEL_VGA_DEVICE(0x0C1B, &intel_haswell_d_info), /* SDV GT2 reserved */ + INTEL_VGA_DEVICE(0x0C2B, &intel_haswell_d_info), /* SDV GT3 reserved */ + INTEL_VGA_DEVICE(0x0C0E, &intel_haswell_d_info), /* SDV GT1 reserved */ + INTEL_VGA_DEVICE(0x0C1E, &intel_haswell_d_info), /* SDV GT2 reserved */ + INTEL_VGA_DEVICE(0x0C2E, &intel_haswell_d_info), /* SDV GT3 reserved */ INTEL_VGA_DEVICE(0x0A02, &intel_haswell_d_info), /* ULT GT1 desktop */ INTEL_VGA_DEVICE(0x0A12, &intel_haswell_d_info), /* ULT GT2 desktop */ - INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT2 desktop */ + INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT3 desktop */ INTEL_VGA_DEVICE(0x0A0A, &intel_haswell_d_info), /* ULT GT1 server */ INTEL_VGA_DEVICE(0x0A1A, &intel_haswell_d_info), /* ULT GT2 server */ - INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT2 server */ + INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT3 server */ INTEL_VGA_DEVICE(0x0A06, &intel_haswell_m_info), /* ULT GT1 mobile */ INTEL_VGA_DEVICE(0x0A16, &intel_haswell_m_info), /* ULT GT2 mobile */ - INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT2 mobile */ + INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT3 mobile */ + INTEL_VGA_DEVICE(0x0A0B, &intel_haswell_d_info), /* ULT GT1 reserved */ + INTEL_VGA_DEVICE(0x0A1B, &intel_haswell_d_info), /* ULT GT2 reserved */ + INTEL_VGA_DEVICE(0x0A2B, &intel_haswell_d_info), /* ULT GT3 reserved */ + INTEL_VGA_DEVICE(0x0A0E, &intel_haswell_m_info), /* ULT GT1 reserved */ + INTEL_VGA_DEVICE(0x0A1E, &intel_haswell_m_info), /* ULT GT2 reserved */ + INTEL_VGA_DEVICE(0x0A2E, &intel_haswell_m_info), /* ULT GT3 reserved */ INTEL_VGA_DEVICE(0x0D02, &intel_haswell_d_info), /* CRW GT1 desktop */ INTEL_VGA_DEVICE(0x0D12, &intel_haswell_d_info), /* CRW GT2 desktop */ - INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT2 desktop */ + INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT3 desktop */ INTEL_VGA_DEVICE(0x0D0A, &intel_haswell_d_info), /* CRW GT1 server */ INTEL_VGA_DEVICE(0x0D1A, &intel_haswell_d_info), /* CRW GT2 server */ - INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT2 server */ + INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT3 server */ INTEL_VGA_DEVICE(0x0D06, &intel_haswell_m_info), /* CRW GT1 mobile */ INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */ - INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */ + INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT3 mobile */ + INTEL_VGA_DEVICE(0x0D0B, &intel_haswell_d_info), /* CRW GT1 reserved */ + INTEL_VGA_DEVICE(0x0D1B, &intel_haswell_d_info), /* CRW GT2 reserved */ + INTEL_VGA_DEVICE(0x0D2B, &intel_haswell_d_info), /* CRW GT3 reserved */ + INTEL_VGA_DEVICE(0x0D0E, &intel_haswell_d_info), /* CRW GT1 reserved */ + INTEL_VGA_DEVICE(0x0D1E, &intel_haswell_d_info), /* CRW GT2 reserved */ + INTEL_VGA_DEVICE(0x0D2E, &intel_haswell_d_info), /* CRW GT3 reserved */ INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0f31, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0f32, &intel_valleyview_m_info), diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4b5ee47b4995..9e1bf6dcbb2a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2080,4 +2080,19 @@ static inline void __user *to_user_ptr(u64 address) return (void __user *)(uintptr_t)address; } +static inline unsigned long msecs_to_jiffies_timeout(const unsigned int m) +{ + unsigned long j = msecs_to_jiffies(m); + + return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1); +} + +static inline unsigned long +timespec_to_jiffies_timeout(const struct timespec *value) +{ + unsigned long j = timespec_to_jiffies(value); + + return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1); +} + #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9b20fbbfd338..a6178baccb56 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -91,14 +91,11 @@ i915_gem_wait_for_error(struct i915_gpu_error *error) { int ret; -#define EXIT_COND (!i915_reset_in_progress(error)) +#define EXIT_COND (!i915_reset_in_progress(error) || \ + i915_terminally_wedged(error)) if (EXIT_COND) return 0; - /* GPU is already declared terminally dead, give up. */ - if (i915_terminally_wedged(error)) - return -EIO; - /* * Only wait 10 seconds for the gpu reset to complete to avoid hanging * userspace. If it takes that long something really bad is going on and @@ -1003,7 +1000,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, wait_forever = false; } - timeout_jiffies = timespec_to_jiffies(&wait_time); + timeout_jiffies = timespec_to_jiffies_timeout(&wait_time); if (WARN_ON(!ring->irq_get(ring))) return -ENODEV; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 218bc938936e..b08d1f9ce0de 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8264,6 +8264,11 @@ check_crtc_state(struct drm_device *dev) active = dev_priv->display.get_pipe_config(crtc, &pipe_config); + + /* hw state is inconsistent with the pipe A quirk */ + if (crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) + active = crtc->active; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) { if (encoder->base.crtc != &crtc->base) @@ -8534,6 +8539,21 @@ static void intel_set_config_restore_state(struct drm_device *dev, } } +static bool +is_crtc_connector_off(struct drm_crtc *crtc, struct drm_connector *connectors, + int num_connectors) +{ + int i; + + for (i = 0; i < num_connectors; i++) + if (connectors[i].encoder && + connectors[i].encoder->crtc == crtc && + connectors[i].dpms != DRM_MODE_DPMS_ON) + return true; + + return false; +} + static void intel_set_config_compute_mode_changes(struct drm_mode_set *set, struct intel_set_config *config) @@ -8541,7 +8561,11 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ - if (set->crtc->fb != set->fb) { + if (set->connectors != NULL && + is_crtc_connector_off(set->crtc, *set->connectors, + set->num_connectors)) { + config->mode_changed = true; + } else if (set->crtc->fb != set->fb) { /* If we have no fb then treat it as a full mode set */ if (set->crtc->fb == NULL) { DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); @@ -8551,8 +8575,9 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, } else if (set->fb->pixel_format != set->crtc->fb->pixel_format) { config->mode_changed = true; - } else + } else { config->fb_changed = true; + } } if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y)) @@ -8720,11 +8745,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (config->mode_changed) { ret = intel_set_mode(set->crtc, set->mode, set->x, set->y, set->fb); - if (ret) { - DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n", - set->crtc->base.id, ret); - goto fail; - } } else if (config->fb_changed) { intel_crtc_wait_for_pending_flips(set->crtc); @@ -8732,18 +8752,18 @@ static int intel_crtc_set_config(struct drm_mode_set *set) set->x, set->y, set->fb); } - intel_set_config_free(config); - - return 0; - + if (ret) { + DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n", + set->crtc->base.id, ret); fail: - intel_set_config_restore_state(dev, config); + intel_set_config_restore_state(dev, config); - /* Try to restore the config */ - if (config->mode_changed && - intel_set_mode(save_set.crtc, save_set.mode, - save_set.x, save_set.y, save_set.fb)) - DRM_ERROR("failed to restore config after modeset failure\n"); + /* Try to restore the config */ + if (config->mode_changed && + intel_set_mode(save_set.crtc, save_set.mode, + save_set.x, save_set.y, save_set.fb)) + DRM_ERROR("failed to restore config after modeset failure\n"); + } out_config: intel_set_config_free(config); @@ -9138,7 +9158,8 @@ int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_XRGB1555: case DRM_FORMAT_ARGB1555: if (INTEL_INFO(dev)->gen > 3) { - DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); return -EINVAL; } break; @@ -9149,7 +9170,8 @@ int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_XBGR2101010: case DRM_FORMAT_ABGR2101010: if (INTEL_INFO(dev)->gen < 4) { - DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); return -EINVAL; } break; @@ -9158,12 +9180,14 @@ int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_YVYU: case DRM_FORMAT_VYUY: if (INTEL_INFO(dev)->gen < 5) { - DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); return -EINVAL; } break; default: - DRM_DEBUG("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format)); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6d560755cf53..98686005dcf6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -260,7 +260,7 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) #define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) if (has_aux_irq) done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, - msecs_to_jiffies(10)); + msecs_to_jiffies_timeout(10)); else done = wait_for_atomic(C, 10) == 0; if (!done) diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 244060ad354b..dff669e2387f 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -293,8 +293,6 @@ void intel_fb_restore_mode(struct drm_device *dev) { int ret; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_mode_config *config = &dev->mode_config; - struct drm_plane *plane; if (INTEL_INFO(dev)->num_pipes == 0) return; @@ -305,10 +303,5 @@ void intel_fb_restore_mode(struct drm_device *dev) if (ret) DRM_DEBUG("failed to restore crtc mode\n"); - /* Be sure to shut off any planes that may be active */ - list_for_each_entry(plane, &config->plane_list, head) - if (plane->enabled) - plane->funcs->disable_plane(plane); - drm_modeset_unlock_all(dev); } diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 5d245031e391..639fe192997c 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -228,7 +228,7 @@ gmbus_wait_hw_status(struct drm_i915_private *dev_priv, * need to wake up periodically and check that ourselves. */ I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en); - for (i = 0; i < msecs_to_jiffies(50) + 1; i++) { + for (i = 0; i < msecs_to_jiffies_timeout(50); i++) { prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait, TASK_UNINTERRUPTIBLE); @@ -263,7 +263,8 @@ gmbus_wait_idle(struct drm_i915_private *dev_priv) /* Important: The hw handles only the first bit, so set only one! */ I915_WRITE(GMBUS4 + reg_offset, GMBUS_IDLE_EN); - ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10); + ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C, + msecs_to_jiffies_timeout(10)); I915_WRITE(GMBUS4 + reg_offset, 0); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index eeff28ec2ff4..2abb2d3c727b 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -636,10 +636,10 @@ static const struct dmi_system_id intel_no_lvds[] = { }, { .callback = intel_no_lvds_dmi_callback, - .ident = "Hewlett-Packard HP t5740e Thin Client", + .ident = "Hewlett-Packard HP t5740", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP t5740e Thin Client"), + DMI_MATCH(DMI_PRODUCT_NAME, " t5740"), }, }, { diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index b8e1623be30d..2628d5622449 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1886,15 +1886,9 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) struct drm_display_mode *newmode; /* - * Attempt to get the mode list from DDC. - * Assume that the preferred modes are - * arranged in priority order. + * Fetch modes from VBT. For SDVO prefer the VBT mode since some + * SDVO->LVDS transcoders can't cope with the EDID mode. */ - intel_ddc_get_modes(connector, intel_sdvo->i2c); - if (list_empty(&connector->probed_modes) == false) - goto end; - - /* Fetch modes from VBT */ if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) { newmode = drm_mode_duplicate(connector->dev, dev_priv->vbt.sdvo_lvds_vbt_mode); @@ -1906,7 +1900,13 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) } } -end: + /* + * Attempt to get the mode list from DDC. + * Assume that the preferred modes are + * arranged in priority order. + */ + intel_ddc_get_modes(connector, &intel_sdvo->ddc); + list_for_each_entry(newmode, &connector->probed_modes, head) { if (newmode->type & DRM_MODE_TYPE_PREFERRED) { intel_sdvo->sdvo_lvds_fixed_mode = @@ -2889,12 +2889,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) } } - /* Only enable the hotplug irq if we need it, to work around noisy - * hotplug lines. - */ - if (intel_sdvo->hotplug_active) - intel_encoder->hpd_pin = HPD_SDVO_B ? HPD_SDVO_B : HPD_SDVO_C; - intel_encoder->compute_config = intel_sdvo_compute_config; intel_encoder->disable = intel_disable_sdvo; intel_encoder->mode_set = intel_sdvo_mode_set; @@ -2914,6 +2908,14 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) goto err_output; } + /* Only enable the hotplug irq if we need it, to work around noisy + * hotplug lines. + */ + if (intel_sdvo->hotplug_active) { + intel_encoder->hpd_pin = + intel_sdvo->is_sdvob ? HPD_SDVO_B : HPD_SDVO_C; + } + /* * Cloning SDVO with anything is often impossible, since the SDVO * encoder can request a special input timing mode. And even if that's diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile index 7db592eedbf1..a9a0300f09fc 100644 --- a/drivers/gpu/drm/mgag200/Makefile +++ b/drivers/gpu/drm/mgag200/Makefile @@ -1,5 +1,5 @@ ccflags-y := -Iinclude/drm -mgag200-y := mgag200_main.o mgag200_mode.o \ +mgag200-y := mgag200_main.o mgag200_mode.o mgag200_cursor.o \ mgag200_drv.o mgag200_fb.o mgag200_i2c.o mgag200_ttm.o obj-$(CONFIG_DRM_MGAG200) += mgag200.o diff --git a/drivers/gpu/drm/mgag200/mgag200_cursor.c b/drivers/gpu/drm/mgag200/mgag200_cursor.c new file mode 100644 index 000000000000..801731aeab61 --- /dev/null +++ b/drivers/gpu/drm/mgag200/mgag200_cursor.c @@ -0,0 +1,275 @@ +/* + * Copyright 2013 Matrox Graphics + * + * This file is subject to the terms and conditions of the GNU General + * Public License version 2. See the file COPYING in the main + * directory of this archive for more details. + * + * Author: Christopher Harvey <charvey@matrox.com> + */ + +#include <drm/drmP.h> +#include "mgag200_drv.h" + +static bool warn_transparent = true; +static bool warn_palette = true; + +/* + Hide the cursor off screen. We can't disable the cursor hardware because it + takes too long to re-activate and causes momentary corruption +*/ +static void mga_hide_cursor(struct mga_device *mdev) +{ + WREG8(MGA_CURPOSXL, 0); + WREG8(MGA_CURPOSXH, 0); + mgag200_bo_unpin(mdev->cursor.pixels_1); + mgag200_bo_unpin(mdev->cursor.pixels_2); +} + +int mga_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height) +{ + struct drm_device *dev = (struct drm_device *)file_priv->minor->dev; + struct mga_device *mdev = (struct mga_device *)dev->dev_private; + struct mgag200_bo *pixels_1 = mdev->cursor.pixels_1; + struct mgag200_bo *pixels_2 = mdev->cursor.pixels_2; + struct mgag200_bo *pixels_current = mdev->cursor.pixels_current; + struct mgag200_bo *pixels_prev = mdev->cursor.pixels_prev; + struct drm_gem_object *obj; + struct mgag200_bo *bo = NULL; + int ret = 0; + unsigned int i, row, col; + uint32_t colour_set[16]; + uint32_t *next_space = &colour_set[0]; + uint32_t *palette_iter; + uint32_t this_colour; + bool found = false; + int colour_count = 0; + u64 gpu_addr; + u8 reg_index; + u8 this_row[48]; + + if (!pixels_1 || !pixels_2) { + WREG8(MGA_CURPOSXL, 0); + WREG8(MGA_CURPOSXH, 0); + return -ENOTSUPP; /* Didn't allocate space for cursors */ + } + + if ((width != 64 || height != 64) && handle) { + WREG8(MGA_CURPOSXL, 0); + WREG8(MGA_CURPOSXH, 0); + return -EINVAL; + } + + BUG_ON(pixels_1 != pixels_current && pixels_1 != pixels_prev); + BUG_ON(pixels_2 != pixels_current && pixels_2 != pixels_prev); + BUG_ON(pixels_current == pixels_prev); + + ret = mgag200_bo_reserve(pixels_1, true); + if (ret) { + WREG8(MGA_CURPOSXL, 0); + WREG8(MGA_CURPOSXH, 0); + return ret; + } + ret = mgag200_bo_reserve(pixels_2, true); + if (ret) { + WREG8(MGA_CURPOSXL, 0); + WREG8(MGA_CURPOSXH, 0); + mgag200_bo_unreserve(pixels_1); + return ret; + } + + if (!handle) { + mga_hide_cursor(mdev); + ret = 0; + goto out1; + } + + /* Move cursor buffers into VRAM if they aren't already */ + if (!pixels_1->pin_count) { + ret = mgag200_bo_pin(pixels_1, TTM_PL_FLAG_VRAM, + &mdev->cursor.pixels_1_gpu_addr); + if (ret) + goto out1; + } + if (!pixels_2->pin_count) { + ret = mgag200_bo_pin(pixels_2, TTM_PL_FLAG_VRAM, + &mdev->cursor.pixels_2_gpu_addr); + if (ret) { + mgag200_bo_unpin(pixels_1); + goto out1; + } + } + + mutex_lock(&dev->struct_mutex); + obj = drm_gem_object_lookup(dev, file_priv, handle); + if (!obj) { + mutex_unlock(&dev->struct_mutex); + ret = -ENOENT; + goto out1; + } + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + + bo = gem_to_mga_bo(obj); + ret = mgag200_bo_reserve(bo, true); + if (ret) { + dev_err(&dev->pdev->dev, "failed to reserve user bo\n"); + goto out1; + } + if (!bo->kmap.virtual) { + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap); + if (ret) { + dev_err(&dev->pdev->dev, "failed to kmap user buffer updates\n"); + goto out2; + } + } + + memset(&colour_set[0], 0, sizeof(uint32_t)*16); + /* width*height*4 = 16384 */ + for (i = 0; i < 16384; i += 4) { + this_colour = ioread32(bo->kmap.virtual + i); + /* No transparency */ + if (this_colour>>24 != 0xff && + this_colour>>24 != 0x0) { + if (warn_transparent) { + dev_info(&dev->pdev->dev, "Video card doesn't support cursors with partial transparency.\n"); + dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n"); + warn_transparent = false; /* Only tell the user once. */ + } + ret = -EINVAL; + goto out3; + } + /* Don't need to store transparent pixels as colours */ + if (this_colour>>24 == 0x0) + continue; + found = false; + for (palette_iter = &colour_set[0]; palette_iter != next_space; palette_iter++) { + if (*palette_iter == this_colour) { + found = true; + break; + } + } + if (found) + continue; + /* We only support 4bit paletted cursors */ + if (colour_count >= 16) { + if (warn_palette) { + dev_info(&dev->pdev->dev, "Video card only supports cursors with up to 16 colours.\n"); + dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n"); + warn_palette = false; /* Only tell the user once. */ + } + ret = -EINVAL; + goto out3; + } + *next_space = this_colour; + next_space++; + colour_count++; + } + + /* Program colours from cursor icon into palette */ + for (i = 0; i < colour_count; i++) { + if (i <= 2) + reg_index = 0x8 + i*0x4; + else + reg_index = 0x60 + i*0x3; + WREG_DAC(reg_index, colour_set[i] & 0xff); + WREG_DAC(reg_index+1, colour_set[i]>>8 & 0xff); + WREG_DAC(reg_index+2, colour_set[i]>>16 & 0xff); + BUG_ON((colour_set[i]>>24 & 0xff) != 0xff); + } + + /* Map up-coming buffer to write colour indices */ + if (!pixels_prev->kmap.virtual) { + ret = ttm_bo_kmap(&pixels_prev->bo, 0, + pixels_prev->bo.num_pages, + &pixels_prev->kmap); + if (ret) { + dev_err(&dev->pdev->dev, "failed to kmap cursor updates\n"); + goto out3; + } + } + + /* now write colour indices into hardware cursor buffer */ + for (row = 0; row < 64; row++) { + memset(&this_row[0], 0, 48); + for (col = 0; col < 64; col++) { + this_colour = ioread32(bo->kmap.virtual + 4*(col + 64*row)); + /* write transparent pixels */ + if (this_colour>>24 == 0x0) { + this_row[47 - col/8] |= 0x80>>(col%8); + continue; + } + + /* write colour index here */ + for (i = 0; i < colour_count; i++) { + if (colour_set[i] == this_colour) { + if (col % 2) + this_row[col/2] |= i<<4; + else + this_row[col/2] |= i; + break; + } + } + } + memcpy_toio(pixels_prev->kmap.virtual + row*48, &this_row[0], 48); + } + + /* Program gpu address of cursor buffer */ + if (pixels_prev == pixels_1) + gpu_addr = mdev->cursor.pixels_1_gpu_addr; + else + gpu_addr = mdev->cursor.pixels_2_gpu_addr; + WREG_DAC(MGA1064_CURSOR_BASE_ADR_LOW, (u8)((gpu_addr>>10) & 0xff)); + WREG_DAC(MGA1064_CURSOR_BASE_ADR_HI, (u8)((gpu_addr>>18) & 0x3f)); + + /* Adjust cursor control register to turn on the cursor */ + WREG_DAC(MGA1064_CURSOR_CTL, 4); /* 16-colour palletized cursor mode */ + + /* Now swap internal buffer pointers */ + if (mdev->cursor.pixels_1 == mdev->cursor.pixels_prev) { + mdev->cursor.pixels_prev = mdev->cursor.pixels_2; + mdev->cursor.pixels_current = mdev->cursor.pixels_1; + } else if (mdev->cursor.pixels_1 == mdev->cursor.pixels_current) { + mdev->cursor.pixels_prev = mdev->cursor.pixels_1; + mdev->cursor.pixels_current = mdev->cursor.pixels_2; + } else { + BUG(); + } + ret = 0; + + ttm_bo_kunmap(&pixels_prev->kmap); + out3: + ttm_bo_kunmap(&bo->kmap); + out2: + mgag200_bo_unreserve(bo); + out1: + if (ret) + mga_hide_cursor(mdev); + mgag200_bo_unreserve(pixels_1); + mgag200_bo_unreserve(pixels_2); + return ret; +} + +int mga_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ + struct mga_device *mdev = (struct mga_device *)crtc->dev->dev_private; + /* Our origin is at (64,64) */ + x += 64; + y += 64; + + BUG_ON(x <= 0); + BUG_ON(y <= 0); + BUG_ON(x & ~0xffff); + BUG_ON(y & ~0xffff); + + WREG8(MGA_CURPOSXL, x & 0xff); + WREG8(MGA_CURPOSXH, (x>>8) & 0xff); + + WREG8(MGA_CURPOSYL, y & 0xff); + WREG8(MGA_CURPOSYH, (y>>8) & 0xff); + return 0; +} diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index bf29b2f4d68d..d9737ef2d9a2 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -149,6 +149,21 @@ struct mga_connector { struct mga_i2c_chan *i2c; }; +struct mga_cursor { + /* + We have to have 2 buffers for the cursor to avoid occasional + corruption while switching cursor icons. + If either of these is NULL, then don't do hardware cursors, and + fall back to software. + */ + struct mgag200_bo *pixels_1; + struct mgag200_bo *pixels_2; + u64 pixels_1_gpu_addr, pixels_2_gpu_addr; + /* The currently displayed icon, this points to one of pixels_1, or pixels_2 */ + struct mgag200_bo *pixels_current; + /* The previously displayed icon */ + struct mgag200_bo *pixels_prev; +}; struct mga_mc { resource_size_t vram_size; @@ -181,6 +196,7 @@ struct mga_device { struct mga_mode_info mode_info; struct mga_fbdev *mfbdev; + struct mga_cursor cursor; bool suspended; int num_crtc; @@ -198,7 +214,8 @@ struct mga_device { struct ttm_bo_device bdev; } ttm; - u32 reg_1e24; /* SE model number */ + /* SE model number stored in reg 0x1e24 */ + u32 unique_rev_id; }; @@ -273,4 +290,9 @@ int mgag200_mmap(struct file *filp, struct vm_area_struct *vma); int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr); int mgag200_bo_unpin(struct mgag200_bo *bo); int mgag200_bo_push_sysram(struct mgag200_bo *bo); + /* mgag200_cursor.c */ +int mga_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, + uint32_t handle, uint32_t width, uint32_t height); +int mga_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); + #endif /* __MGAG200_DRV_H__ */ diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index 99059237da38..9fa5685baee0 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -176,7 +176,7 @@ static int mgag200_device_init(struct drm_device *dev, /* stash G200 SE model number for later use */ if (IS_G200_SE(mdev)) - mdev->reg_1e24 = RREG32(0x1e24); + mdev->unique_rev_id = RREG32(0x1e24); ret = mga_vram_init(mdev); if (ret) @@ -209,7 +209,7 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags) r = mgag200_device_init(dev, flags); if (r) { dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r); - goto out; + return r; } r = mgag200_mm_init(mdev); if (r) @@ -221,8 +221,27 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags) dev->mode_config.prefer_shadow = 1; r = mgag200_modeset_init(mdev); - if (r) + if (r) { dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r); + goto out; + } + + /* Make small buffers to store a hardware cursor (double buffered icon updates) */ + mgag200_bo_create(dev, roundup(48*64, PAGE_SIZE), 0, 0, + &mdev->cursor.pixels_1); + mgag200_bo_create(dev, roundup(48*64, PAGE_SIZE), 0, 0, + &mdev->cursor.pixels_2); + if (!mdev->cursor.pixels_2 || !mdev->cursor.pixels_1) + goto cursor_nospace; + mdev->cursor.pixels_current = mdev->cursor.pixels_1; + mdev->cursor.pixels_prev = mdev->cursor.pixels_2; + goto cursor_done; + cursor_nospace: + mdev->cursor.pixels_1 = NULL; + mdev->cursor.pixels_2 = NULL; + dev_warn(&dev->pdev->dev, "Could not allocate space for cursors. Not doing hardware cursors.\n"); + cursor_done: + out: if (r) mgag200_driver_unload(dev); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 77b8a45fb10a..251784aa2225 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1008,7 +1008,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, if (IS_G200_SE(mdev)) { - if (mdev->reg_1e24 >= 0x02) { + if (mdev->unique_rev_id >= 0x02) { u8 hi_pri_lvl; u32 bpp; u32 mb; @@ -1034,13 +1034,14 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, else hi_pri_lvl = 5; - WREG8(0x1fde, 0x06); - WREG8(0x1fdf, hi_pri_lvl); + WREG8(MGAREG_CRTCEXT_INDEX, 0x06); + WREG8(MGAREG_CRTCEXT_DATA, hi_pri_lvl); } else { - if (mdev->reg_1e24 >= 0x01) - WREG8(0x1fdf, 0x03); + WREG8(MGAREG_CRTCEXT_INDEX, 0x06); + if (mdev->unique_rev_id >= 0x01) + WREG8(MGAREG_CRTCEXT_DATA, 0x03); else - WREG8(0x1fdf, 0x04); + WREG8(MGAREG_CRTCEXT_DATA, 0x04); } } return 0; @@ -1252,6 +1253,8 @@ static void mga_crtc_destroy(struct drm_crtc *crtc) /* These provide the minimum set of functions required to handle a CRTC */ static const struct drm_crtc_funcs mga_crtc_funcs = { + .cursor_set = mga_crtc_cursor_set, + .cursor_move = mga_crtc_cursor_move, .gamma_set = mga_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, .destroy = mga_crtc_destroy, @@ -1409,6 +1412,32 @@ static int mga_vga_get_modes(struct drm_connector *connector) return ret; } +static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode, + int bits_per_pixel) +{ + uint32_t total_area, divisor; + int64_t active_area, pixels_per_second, bandwidth; + uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8; + + divisor = 1024; + + if (!mode->htotal || !mode->vtotal || !mode->clock) + return 0; + + active_area = mode->hdisplay * mode->vdisplay; + total_area = mode->htotal * mode->vtotal; + + pixels_per_second = active_area * mode->clock * 1000; + do_div(pixels_per_second, total_area); + + bandwidth = pixels_per_second * bytes_per_pixel * 100; + do_div(bandwidth, divisor); + + return (uint32_t)(bandwidth); +} + +#define MODE_BANDWIDTH MODE_BAD + static int mga_vga_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { @@ -1420,7 +1449,45 @@ static int mga_vga_mode_valid(struct drm_connector *connector, int bpp = 32; int i = 0; - /* FIXME: Add bandwidth and g200se limitations */ + if (IS_G200_SE(mdev)) { + if (mdev->unique_rev_id == 0x01) { + if (mode->hdisplay > 1600) + return MODE_VIRTUAL_X; + if (mode->vdisplay > 1200) + return MODE_VIRTUAL_Y; + if (mga_vga_calculate_mode_bandwidth(mode, bpp) + > (24400 * 1024)) + return MODE_BANDWIDTH; + } else if (mdev->unique_rev_id >= 0x02) { + if (mode->hdisplay > 1920) + return MODE_VIRTUAL_X; + if (mode->vdisplay > 1200) + return MODE_VIRTUAL_Y; + if (mga_vga_calculate_mode_bandwidth(mode, bpp) + > (30100 * 1024)) + return MODE_BANDWIDTH; + } + } else if (mdev->type == G200_WB) { + if (mode->hdisplay > 1280) + return MODE_VIRTUAL_X; + if (mode->vdisplay > 1024) + return MODE_VIRTUAL_Y; + if (mga_vga_calculate_mode_bandwidth(mode, + bpp > (31877 * 1024))) + return MODE_BANDWIDTH; + } else if (mdev->type == G200_EV && + (mga_vga_calculate_mode_bandwidth(mode, bpp) + > (32700 * 1024))) { + return MODE_BANDWIDTH; + } else if (mode->type == G200_EH && + (mga_vga_calculate_mode_bandwidth(mode, bpp) + > (37500 * 1024))) { + return MODE_BANDWIDTH; + } else if (mode->type == G200_ER && + (mga_vga_calculate_mode_bandwidth(mode, + bpp) > (55000 * 1024))) { + return MODE_BANDWIDTH; + } if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h index fb24d8655feb..3ae442a64bd6 100644 --- a/drivers/gpu/drm/mgag200/mgag200_reg.h +++ b/drivers/gpu/drm/mgag200/mgag200_reg.h @@ -235,7 +235,11 @@ #define MGAREG_CRTCEXT_INDEX 0x1fde #define MGAREG_CRTCEXT_DATA 0x1fdf - +/* Cursor X and Y position */ +#define MGA_CURPOSXL 0x3c0c +#define MGA_CURPOSXH 0x3c0d +#define MGA_CURPOSYL 0x3c0e +#define MGA_CURPOSYH 0x3c0f /* MGA bits for registers PCI_OPTION_REG */ #define MGA1064_OPT_SYS_CLK_PCI ( 0x00 << 0 ) diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index 401c9891d3a8..0004f7740b8e 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -270,26 +270,20 @@ int mgag200_mm_init(struct mga_device *mdev) return ret; } - mdev->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0), - DRM_MTRR_WC); + mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); return 0; } void mgag200_mm_fini(struct mga_device *mdev) { - struct drm_device *dev = mdev->dev; ttm_bo_device_release(&mdev->ttm.bdev); mgag200_ttm_global_release(mdev); - if (mdev->fb_mtrr >= 0) { - drm_mtrr_del(mdev->fb_mtrr, - pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0), DRM_MTRR_WC); - mdev->fb_mtrr = -1; - } + arch_phys_wc_del(mdev->fb_mtrr); + mdev->fb_mtrr = 0; } void mgag200_ttm_placement(struct mgag200_bo *bo, int domain) diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index 955af122c3a6..a36e64e98ef3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c @@ -138,7 +138,6 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; break; case 0xce: @@ -225,7 +224,6 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; break; case 0xc8: diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c index d0817d94454c..f02fd9f443ff 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c @@ -50,11 +50,16 @@ nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval) { const u32 doff = (or * 0x800); int load = -EINVAL; + nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000); + nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval); - udelay(9500); + mdelay(9); + udelay(500); nv_wr32(priv, 0x61a00c + doff, 0x80000000); load = (nv_rd32(priv, 0x61a00c + doff) & 0x38000000) >> 27; nv_wr32(priv, 0x61a00c + doff, 0x00000000); + nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000); + nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); return load; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c index 0d36bdc51417..7fdade6e604d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c @@ -55,6 +55,10 @@ nv84_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data) nv_wr32(priv, 0x616510 + hoff, 0x00000000); nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001); + nv_mask(priv, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ + nv_mask(priv, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ + nv_mask(priv, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ + /* ??? */ nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c index ddaeb5572903..e9b8217d0075 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c @@ -40,8 +40,8 @@ * FIFO channel objects ******************************************************************************/ -void -nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) +static void +nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv) { struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_gpuobj *cur; @@ -62,6 +62,14 @@ nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) nv_wr32(priv, 0x002500, 0x00000101); } +void +nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) +{ + mutex_lock(&nv_subdev(priv)->mutex); + nv50_fifo_playlist_update_locked(priv); + mutex_unlock(&nv_subdev(priv)->mutex); +} + static int nv50_fifo_context_attach(struct nouveau_object *parent, struct nouveau_object *object) @@ -487,7 +495,7 @@ nv50_fifo_init(struct nouveau_object *object) for (i = 0; i < 128; i++) nv_wr32(priv, 0x002600 + (i * 4), 0x00000000); - nv50_fifo_playlist_update(priv); + nv50_fifo_playlist_update_locked(priv); nv_wr32(priv, 0x003200, 0x00000001); nv_wr32(priv, 0x003250, 0x00000001); diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index 4d4a6b905370..46dfa68c47bb 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c @@ -71,6 +71,7 @@ nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv) struct nouveau_gpuobj *cur; int i, p; + mutex_lock(&nv_subdev(priv)->mutex); cur = priv->playlist[priv->cur_playlist]; priv->cur_playlist = !priv->cur_playlist; @@ -87,6 +88,7 @@ nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv) nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3)); if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000)) nv_error(priv, "playlist update failed\n"); + mutex_unlock(&nv_subdev(priv)->mutex); } static int @@ -248,9 +250,17 @@ nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend) struct nvc0_fifo_priv *priv = (void *)object->engine; struct nvc0_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; + u32 mask, engine; nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); nvc0_fifo_playlist_update(priv); + mask = nv_rd32(priv, 0x0025a4); + for (engine = 0; mask && engine < 16; engine++) { + if (!(mask & (1 << engine))) + continue; + nv_mask(priv, 0x0025a8 + (engine * 4), 0x00000000, 0x00000000); + mask &= ~(1 << engine); + } nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); return nouveau_fifo_channel_fini(&chan->base, suspend); diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index 9151919fb831..56192a7242ae 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -94,11 +94,13 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine) u32 match = (engine << 16) | 0x00000001; int i, p; + mutex_lock(&nv_subdev(priv)->mutex); cur = engn->playlist[engn->cur_playlist]; if (unlikely(cur == NULL)) { int ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, 0, &cur); if (ret) { + mutex_unlock(&nv_subdev(priv)->mutex); nv_error(priv, "playlist alloc failed\n"); return; } @@ -122,6 +124,7 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine) nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000)) nv_error(priv, "playlist %d update timeout\n", engine); + mutex_unlock(&nv_subdev(priv)->mutex); } static int diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index 0a393f7f055f..5a5961b6a6a3 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h @@ -218,7 +218,7 @@ struct nv04_display_class { #define NV50_DISP_DAC_PWR_STATE 0x00000040 #define NV50_DISP_DAC_PWR_STATE_ON 0x00000000 #define NV50_DISP_DAC_PWR_STATE_OFF 0x00000040 -#define NV50_DISP_DAC_LOAD 0x0002000c +#define NV50_DISP_DAC_LOAD 0x00020100 #define NV50_DISP_DAC_LOAD_VALUE 0x00000007 #define NV50_DISP_PIOR_MTHD 0x00030000 diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index c300b5e7b670..c434d398d16f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -1940,8 +1940,8 @@ init_zm_mask_add(struct nvbios_init *init) trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add); init->offset += 13; - data = init_rd32(init, addr) & mask; - data |= ((data + add) & ~mask); + data = init_rd32(init, addr); + data = (data & mask) | ((data + add) & ~mask); init_wr32(init, addr, data); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c index e4940fb166e8..fb794e997fbc 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c @@ -29,7 +29,6 @@ struct nvc0_ltcg_priv { struct nouveau_ltcg base; u32 part_nr; - u32 part_mask; u32 subp_nr; struct nouveau_mm tags; u32 num_tags; @@ -105,8 +104,6 @@ nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) /* wait until it's finished with clearing */ for (p = 0; p < priv->part_nr; ++p) { - if (!(priv->part_mask & (1 << p))) - continue; for (i = 0; i < priv->subp_nr; ++i) nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0); } @@ -121,6 +118,8 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) int ret; nv_wr32(priv, 0x17e8d8, priv->part_nr); + if (nv_device(pfb)->card_type >= NV_E0) + nv_wr32(priv, 0x17e000, priv->part_nr); /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ priv->num_tags = (pfb->ram.size >> 17) / 4; @@ -167,16 +166,20 @@ nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, { struct nvc0_ltcg_priv *priv; struct nouveau_fb *pfb = nouveau_fb(parent); - int ret; + u32 parts, mask; + int ret, i; ret = nouveau_ltcg_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->part_nr = nv_rd32(priv, 0x022438); - priv->part_mask = nv_rd32(priv, 0x022554); - + parts = nv_rd32(priv, 0x022438); + mask = nv_rd32(priv, 0x022554); + for (i = 0; i < parts; i++) { + if (!(mask & (1 << i))) + priv->part_nr++; + } priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28; nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 7bf22d4a3d96..f17dc2ab03ec 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -638,17 +638,8 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, } s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); - if (s->event) { - struct drm_pending_vblank_event *e = s->event; - struct timeval now; - - do_gettimeofday(&now); - e->event.sequence = 0; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; - list_add_tail(&e->base.link, &e->base.file_priv->event_list); - wake_up_interruptible(&e->base.file_priv->event_wait); - } + if (s->event) + drm_send_vblank_event(dev, -1, s->event); list_del(&s->head); if (ps) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 46c152ff0a80..383f4e6ea9d1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -453,18 +453,32 @@ nouveau_do_suspend(struct drm_device *dev) NV_INFO(drm, "evicting buffers...\n"); ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); + NV_INFO(drm, "waiting for kernel channels to go idle...\n"); + if (drm->cechan) { + ret = nouveau_channel_idle(drm->cechan); + if (ret) + return ret; + } + + if (drm->channel) { + ret = nouveau_channel_idle(drm->channel); + if (ret) + return ret; + } + + NV_INFO(drm, "suspending client object trees...\n"); if (drm->fence && nouveau_fence(drm)->suspend) { if (!nouveau_fence(drm)->suspend(drm)) return -ENOMEM; } - NV_INFO(drm, "suspending client object trees...\n"); list_for_each_entry(cli, &drm->clients, head) { ret = nouveau_client_fini(&cli->base, true); if (ret) goto fail_client; } + NV_INFO(drm, "suspending kernel object tree...\n"); ret = nouveau_client_fini(&drm->client.base, true); if (ret) goto fail_client; @@ -514,17 +528,18 @@ nouveau_do_resume(struct drm_device *dev) nouveau_agp_reset(drm); - NV_INFO(drm, "resuming client object trees...\n"); + NV_INFO(drm, "resuming kernel object tree...\n"); nouveau_client_init(&drm->client.base); nouveau_agp_init(drm); + NV_INFO(drm, "resuming client object trees...\n"); + if (drm->fence && nouveau_fence(drm)->resume) + nouveau_fence(drm)->resume(drm); + list_for_each_entry(cli, &drm->clients, head) { nouveau_client_init(&cli->base); } - if (drm->fence && nouveau_fence(drm)->resume) - nouveau_fence(drm)->resume(drm); - nouveau_run_vbios_init(dev); nouveau_pm_resume(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index f19a15a3bc03..3da985eb38cc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -396,9 +396,8 @@ nouveau_ttm_init(struct nouveau_drm *drm) return ret; } - drm->ttm.mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1), - pci_resource_len(dev->pdev, 1), - DRM_MTRR_WC); + drm->ttm.mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 1), + pci_resource_len(dev->pdev, 1)); /* GART init */ if (drm->agp.stat != ENABLED) { @@ -433,10 +432,6 @@ nouveau_ttm_fini(struct nouveau_drm *drm) nouveau_ttm_global_release(drm); - if (drm->ttm.mtrr >= 0) { - drm_mtrr_del(drm->ttm.mtrr, - pci_resource_start(drm->dev->pdev, 1), - pci_resource_len(drm->dev->pdev, 1), DRM_MTRR_WC); - drm->ttm.mtrr = -1; - } + arch_phys_wc_del(drm->ttm.mtrr); + drm->ttm.mtrr = 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index ebf0a683305e..dd5e01f89f28 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1554,7 +1554,9 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct nv50_disp *disp = nv50_disp(encoder->dev); int ret, or = nouveau_encoder(encoder)->or; - u32 load = 0; + u32 load = nouveau_drm(encoder->dev)->vbios.dactestval; + if (load == 0) + load = 340; ret = nv_exec(disp->core, NV50_DISP_DAC_LOAD + or, &load, sizeof(load)); if (ret || load != 7) diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig index 09f65dc3d2c8..45875a066bb9 100644 --- a/drivers/gpu/drm/omapdrm/Kconfig +++ b/drivers/gpu/drm/omapdrm/Kconfig @@ -1,7 +1,7 @@ config DRM_OMAP tristate "OMAP DRM" - depends on DRM && !CONFIG_FB_OMAP2 + depends on DRM && !FB_OMAP2 depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM depends on OMAP2_DSS select DRM_KMS_HELPER diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 79b200aee18a..ef161ea982e6 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -253,10 +253,6 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, NULL, NULL); } -static void omap_crtc_load_lut(struct drm_crtc *crtc) -{ -} - static void vblank_cb(void *arg) { struct drm_crtc *crtc = arg; @@ -366,7 +362,6 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { .prepare = omap_crtc_prepare, .commit = omap_crtc_commit, .mode_set_base = omap_crtc_mode_set_base, - .load_lut = omap_crtc_load_lut, }; const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 9c53c25e5201..826586ffbe83 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -649,6 +649,9 @@ static void pdev_shutdown(struct platform_device *device) static int pdev_probe(struct platform_device *device) { + if (omapdss_is_initialized() == false) + return -EPROBE_DEFER; + DBG("%s", device->name); return drm_platform_init(&omap_drm_driver, device); } diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index b11ce609fcc2..002988d09021 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -281,21 +281,7 @@ fail: return ret; } -static void omap_crtc_fb_gamma_set(struct drm_crtc *crtc, - u16 red, u16 green, u16 blue, int regno) -{ - DBG("fbdev: set gamma"); -} - -static void omap_crtc_fb_gamma_get(struct drm_crtc *crtc, - u16 *red, u16 *green, u16 *blue, int regno) -{ - DBG("fbdev: get gamma"); -} - static struct drm_fb_helper_funcs omap_fb_helper_funcs = { - .gamma_set = omap_crtc_fb_gamma_set, - .gamma_get = omap_crtc_fb_gamma_get, .fb_probe = omap_fbdev_create, }; diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index be7cd97a0db0..3256693de110 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -136,10 +136,6 @@ static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer, kunmap(pages[page_num]); } -/* - * TODO maybe we can split up drm_gem_mmap to avoid duplicating - * some here.. or at least have a drm_dmabuf_mmap helper. - */ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, struct vm_area_struct *vma) { @@ -149,31 +145,9 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, if (WARN_ON(!obj->filp)) return -EINVAL; - /* Check for valid size. */ - if (omap_gem_mmap_size(obj) < vma->vm_end - vma->vm_start) { - ret = -EINVAL; - goto out_unlock; - } - - if (!obj->dev->driver->gem_vm_ops) { - ret = -EINVAL; - goto out_unlock; - } - - vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = obj->dev->driver->gem_vm_ops; - vma->vm_private_data = obj; - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); - - /* Take a ref for this mapping of the object, so that the fault - * handler can dereference the mmap offset's pointer to the object. - * This reference is cleaned up by the corresponding vm_close - * (which should happen whether the vma was created by this call, or - * by a vm_open due to mremap or partial unmap or whatever). - */ - vma->vm_ops->open(vma); - -out_unlock: + ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma); + if (ret < 0) + return ret; return omap_gem_mmap_obj(obj, vma); } diff --git a/drivers/gpu/drm/qxl/Kconfig b/drivers/gpu/drm/qxl/Kconfig index 2f1a57e11140..d6c12796023c 100644 --- a/drivers/gpu/drm/qxl/Kconfig +++ b/drivers/gpu/drm/qxl/Kconfig @@ -4,6 +4,7 @@ config DRM_QXL select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT + select FB_DEFERRED_IO select DRM_KMS_HELPER select DRM_TTM help diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 823d29e926ec..686a937675cb 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -222,12 +222,6 @@ static int qxl_add_common_modes(struct drm_connector *connector) return i - 1; } -static void qxl_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, uint32_t start, uint32_t size) -{ - /* TODO */ -} - static void qxl_crtc_destroy(struct drm_crtc *crtc) { struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc); @@ -255,11 +249,11 @@ qxl_hide_cursor(struct qxl_device *qdev) qxl_release_unreserve(qdev, release); } -static int qxl_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height) +static int qxl_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height, int32_t hot_x, int32_t hot_y) { struct drm_device *dev = crtc->dev; struct qxl_device *qdev = dev->dev_private; @@ -315,8 +309,8 @@ static int qxl_crtc_cursor_set(struct drm_crtc *crtc, cursor->header.type = SPICE_CURSOR_TYPE_ALPHA; cursor->header.width = 64; cursor->header.height = 64; - cursor->header.hot_spot_x = 0; - cursor->header.hot_spot_y = 0; + cursor->header.hot_spot_x = hot_x; + cursor->header.hot_spot_y = hot_y; cursor->data_size = size; cursor->chunk.next_chunk = 0; cursor->chunk.prev_chunk = 0; @@ -397,9 +391,8 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc, static const struct drm_crtc_funcs qxl_crtc_funcs = { - .cursor_set = qxl_crtc_cursor_set, + .cursor_set2 = qxl_crtc_cursor_set2, .cursor_move = qxl_crtc_cursor_move, - .gamma_set = qxl_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, .destroy = qxl_crtc_destroy, }; @@ -619,18 +612,12 @@ static void qxl_crtc_commit(struct drm_crtc *crtc) DRM_DEBUG("\n"); } -static void qxl_crtc_load_lut(struct drm_crtc *crtc) -{ - DRM_DEBUG("\n"); -} - static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = { .dpms = qxl_crtc_dpms, .mode_fixup = qxl_crtc_mode_fixup, .mode_set = qxl_crtc_mode_set, .prepare = qxl_crtc_prepare, .commit = qxl_crtc_commit, - .load_lut = qxl_crtc_load_lut, }; static int qdev_crtc_init(struct drm_device *dev, int num_crtc) diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index b3c51275df5c..4b955b04ce1e 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -520,10 +520,6 @@ static int qxl_fbdev_destroy(struct drm_device *dev, struct qxl_fbdev *qfbdev) } static struct drm_fb_helper_funcs qxl_fb_helper_funcs = { - /* TODO - .gamma_set = qxl_crtc_fb_gamma_set, - .gamma_get = qxl_crtc_fb_gamma_get, - */ .fb_probe = qxl_fb_find_or_create_single, }; diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index 6db7370373ea..a4b71b25fa53 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -151,7 +151,7 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, struct qxl_bo *cmd_bo; int release_type; struct drm_qxl_command *commands = - (struct drm_qxl_command *)execbuffer->commands; + (struct drm_qxl_command *)(uintptr_t)execbuffer->commands; if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num], sizeof(user_cmd))) @@ -193,7 +193,7 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data, for (i = 0 ; i < user_cmd.relocs_num; ++i) { if (DRM_COPY_FROM_USER(&reloc, - &((struct drm_qxl_reloc *)user_cmd.relocs)[i], + &((struct drm_qxl_reloc *)(uintptr_t)user_cmd.relocs)[i], sizeof(reloc))) { qxl_bo_list_unreserve(&reloc_list, true); qxl_release_unreserve(qdev, release); diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index 85127ed24cfd..e27ce2a907cf 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -128,12 +128,13 @@ int qxl_device_init(struct qxl_device *qdev, qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0)); qdev->surface_mapping = io_mapping_create_wc(qdev->surfaceram_base, qdev->surfaceram_size); - DRM_DEBUG_KMS("qxl: vram %p-%p(%dM %dk), surface %p-%p(%dM %dk)\n", - (void *)qdev->vram_base, (void *)pci_resource_end(pdev, 0), + DRM_DEBUG_KMS("qxl: vram %llx-%llx(%dM %dk), surface %llx-%llx(%dM %dk)\n", + (unsigned long long)qdev->vram_base, + (unsigned long long)pci_resource_end(pdev, 0), (int)pci_resource_len(pdev, 0) / 1024 / 1024, (int)pci_resource_len(pdev, 0) / 1024, - (void *)qdev->surfaceram_base, - (void *)pci_resource_end(pdev, 1), + (unsigned long long)qdev->surfaceram_base, + (unsigned long long)pci_resource_end(pdev, 1), (int)qdev->surfaceram_size / 1024 / 1024, (int)qdev->surfaceram_size / 1024); diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 6d6fdb3ba0d0..d5df8fd10217 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1811,12 +1811,9 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, static void atombios_crtc_prepare(struct drm_crtc *crtc) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - radeon_crtc->in_mode_set = true; - /* disable crtc pair power gating before programming */ if (ASIC_IS_DCE6(rdev)) atombios_powergate_crtc(crtc, ATOM_DISABLE); @@ -1827,11 +1824,8 @@ static void atombios_crtc_prepare(struct drm_crtc *crtc) static void atombios_crtc_commit(struct drm_crtc *crtc) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); atombios_lock_crtc(crtc, ATOM_DISABLE); - radeon_crtc->in_mode_set = false; } static void atombios_crtc_disable(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 44a7da66e081..8406c8251fbf 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -667,6 +667,8 @@ atombios_digital_setup(struct drm_encoder *encoder, int action) int atombios_get_encoder_mode(struct drm_encoder *encoder) { + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_connector *connector; struct radeon_connector *radeon_connector; @@ -693,7 +695,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ if (drm_detect_hdmi_monitor(radeon_connector->edid) && - radeon_audio) + radeon_audio && + !ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */ return ATOM_ENCODER_MODE_HDMI; else if (radeon_connector->use_digital) return ATOM_ENCODER_MODE_DVI; @@ -704,7 +707,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) case DRM_MODE_CONNECTOR_HDMIA: default: if (drm_detect_hdmi_monitor(radeon_connector->edid) && - radeon_audio) + radeon_audio && + !ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */ return ATOM_ENCODER_MODE_HDMI; else return ATOM_ENCODER_MODE_DVI; @@ -718,7 +722,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder) (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) return ATOM_ENCODER_MODE_DP; else if (drm_detect_hdmi_monitor(radeon_connector->edid) && - radeon_audio) + radeon_audio && + !ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */ return ATOM_ENCODER_MODE_HDMI; else return ATOM_ENCODER_MODE_DVI; diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 105bafb6c29d..0f89ce3d02b9 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2343,11 +2343,13 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav u32 crtc_enabled, tmp, frame_count, blackout; int i, j; - save->vga_render_control = RREG32(VGA_RENDER_CONTROL); - save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); + if (!ASIC_IS_NODCE(rdev)) { + save->vga_render_control = RREG32(VGA_RENDER_CONTROL); + save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); - /* disable VGA render */ - WREG32(VGA_RENDER_CONTROL, 0); + /* disable VGA render */ + WREG32(VGA_RENDER_CONTROL, 0); + } /* blank the display controllers */ for (i = 0; i < rdev->num_crtc; i++) { crtc_enabled = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN; @@ -2438,8 +2440,11 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i], (u32)rdev->mc.vram_start); } - WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); + + if (!ASIC_IS_NODCE(rdev)) { + WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); + WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); + } /* unlock regs and wait for update */ for (i = 0; i < rdev->num_crtc; i++) { @@ -2499,10 +2504,12 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s } } } - /* Unlock vga access */ - WREG32(VGA_HDP_CONTROL, save->vga_hdp_control); - mdelay(1); - WREG32(VGA_RENDER_CONTROL, save->vga_render_control); + if (!ASIC_IS_NODCE(rdev)) { + /* Unlock vga access */ + WREG32(VGA_HDP_CONTROL, save->vga_hdp_control); + mdelay(1); + WREG32(VGA_RENDER_CONTROL, save->vga_render_control); + } } void evergreen_mc_program(struct radeon_device *rdev) @@ -3405,8 +3412,8 @@ int evergreen_mc_init(struct radeon_device *rdev) rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); } else { /* size in MB on evergreen/cayman/tn */ - rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; - rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; + rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL; + rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL; } rdev->mc.visible_vram_size = rdev->mc.aper_size; r700_vram_gtt_location(rdev, &rdev->mc); @@ -4747,6 +4754,12 @@ static int evergreen_startup(struct radeon_device *rdev) rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r = r600_irq_init(rdev); if (r) { DRM_ERROR("radeon: IH init failed (%d).\n", r); @@ -4916,10 +4929,6 @@ int evergreen_init(struct radeon_device *rdev) if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; - rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -4992,8 +5001,7 @@ void evergreen_fini(struct radeon_device *rdev) void evergreen_pcie_gen2_enable(struct radeon_device *rdev) { - u32 link_width_cntl, speed_cntl, mask; - int ret; + u32 link_width_cntl, speed_cntl; if (radeon_pcie_gen2 == 0) return; @@ -5008,11 +5016,8 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev) if (ASIC_IS_X2(rdev)) return; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret != 0) - return; - - if (!(mask & DRM_PCIE_SPEED_50)) + if ((rdev->pdev->bus->max_bus_speed != PCIE_SPEED_5_0GT) && + (rdev->pdev->bus->max_bus_speed != PCIE_SPEED_8_0GT)) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index b4ab8ceb1654..ed7c8a768092 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -154,19 +154,18 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock) struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - u32 base_rate = 48000; + u32 base_rate = 24000; if (!dig || !dig->afmt) return; - /* XXX: properly calculate this */ /* XXX two dtos; generally use dto0 for hdmi */ /* Express [24MHz / target pixel clock] as an exact rational * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator */ - WREG32(DCCG_AUDIO_DTO0_PHASE, (base_rate*50) & 0xffffff); - WREG32(DCCG_AUDIO_DTO0_MODULE, (clock*100) & 0xffffff); + WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100); + WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id)); } diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 7969c0c8ec20..84583302b081 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -2025,6 +2025,12 @@ static int cayman_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r = r600_irq_init(rdev); if (r) { DRM_ERROR("radeon: IH init failed (%d).\n", r); @@ -2190,10 +2196,6 @@ int cayman_init(struct radeon_device *rdev) if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; - ring->ring_obj = NULL; r600_ring_init(rdev, ring, 1024 * 1024); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 4973bff37fec..d0314ecbd7c1 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3869,6 +3869,12 @@ static int r100_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r100_irq_set(rdev); rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -4024,9 +4030,6 @@ int r100_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; /* Memory manager */ r = radeon_bo_init(rdev); if (r) diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index c60350e6872d..b9b776f1e582 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -1382,6 +1382,12 @@ static int r300_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r100_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -1516,9 +1522,6 @@ int r300_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; /* Memory manager */ r = radeon_bo_init(rdev); if (r) diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 6fce2eb4dd16..4e796ecf9ea4 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -265,6 +265,12 @@ static int r420_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r100_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -411,10 +417,6 @@ int r420_init(struct radeon_device *rdev) if (r) { return r; } - r = radeon_irq_kms_init(rdev); - if (r) { - return r; - } /* Memory manager */ r = radeon_bo_init(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index f795a4e092cb..e1aece73b370 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -194,6 +194,12 @@ static int r520_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + rs600_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -297,9 +303,6 @@ int r520_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; /* Memory manager */ r = radeon_bo_init(rdev); if (r) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1a08008c978b..6948eb88c2b7 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1046,6 +1046,24 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev) return -1; } +uint32_t rs780_mc_rreg(struct radeon_device *rdev, uint32_t reg) +{ + uint32_t r; + + WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg)); + r = RREG32(R_0028FC_MC_DATA); + WREG32(R_0028F8_MC_INDEX, ~C_0028F8_MC_IND_ADDR); + return r; +} + +void rs780_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) +{ + WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg) | + S_0028F8_MC_IND_WR_EN(1)); + WREG32(R_0028FC_MC_DATA, v); + WREG32(R_0028F8_MC_INDEX, 0x7F); +} + static void r600_mc_program(struct radeon_device *rdev) { struct rv515_mc_save save; @@ -1181,6 +1199,8 @@ static int r600_mc_init(struct radeon_device *rdev) { u32 tmp; int chansize, numchan; + uint32_t h_addr, l_addr; + unsigned long long k8_addr; /* Get VRAM informations */ rdev->mc.vram_is_ddr = true; @@ -1221,7 +1241,30 @@ static int r600_mc_init(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_IGP) { rs690_pm_info(rdev); rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); + + if (rdev->family == CHIP_RS780 || rdev->family == CHIP_RS880) { + /* Use K8 direct mapping for fast fb access. */ + rdev->fastfb_working = false; + h_addr = G_000012_K8_ADDR_EXT(RREG32_MC(R_000012_MC_MISC_UMA_CNTL)); + l_addr = RREG32_MC(R_000011_K8_FB_LOCATION); + k8_addr = ((unsigned long long)h_addr) << 32 | l_addr; +#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE) + if (k8_addr + rdev->mc.visible_vram_size < 0x100000000ULL) +#endif + { + /* FastFB shall be used with UMA memory. Here it is simply disabled when sideport + * memory is present. + */ + if (rdev->mc.igp_sideport_enabled == false && radeon_fastfb == 1) { + DRM_INFO("Direct mapping: aper base at 0x%llx, replaced by direct mapping base 0x%llx.\n", + (unsigned long long)rdev->mc.aper_base, k8_addr); + rdev->mc.aper_base = (resource_size_t)k8_addr; + rdev->fastfb_working = true; + } + } + } } + radeon_update_bandwidth_info(rdev); return 0; } @@ -2644,6 +2687,9 @@ void r600_uvd_rbc_stop(struct radeon_device *rdev) int r600_uvd_init(struct radeon_device *rdev) { int i, j, r; + /* disable byte swapping */ + u32 lmi_swap_cntl = 0; + u32 mp_swap_cntl = 0; /* raise clocks while booting up the VCPU */ radeon_set_uvd_clocks(rdev, 53300, 40000); @@ -2668,9 +2714,13 @@ int r600_uvd_init(struct radeon_device *rdev) WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) | (1 << 21) | (1 << 9) | (1 << 20)); - /* disable byte swapping */ - WREG32(UVD_LMI_SWAP_CNTL, 0); - WREG32(UVD_MP_SWAP_CNTL, 0); +#ifdef __BIG_ENDIAN + /* swap (8 in 32) RB and IB */ + lmi_swap_cntl = 0xa; + mp_swap_cntl = 0; +#endif + WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl); + WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl); WREG32(UVD_MPC_SET_MUXA0, 0x40c2040); WREG32(UVD_MPC_SET_MUXA1, 0x0); @@ -3202,6 +3252,12 @@ static int r600_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r = r600_irq_init(rdev); if (r) { DRM_ERROR("radeon: IH init failed (%d).\n", r); @@ -3356,10 +3412,6 @@ int r600_init(struct radeon_device *rdev) if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; - rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -4631,8 +4683,6 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev) { u32 link_width_cntl, lanes, speed_cntl, training_cntl, tmp; u16 link_cntl2; - u32 mask; - int ret; if (radeon_pcie_gen2 == 0) return; @@ -4651,11 +4701,8 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev) if (rdev->family <= CHIP_R600) return; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret != 0) - return; - - if (!(mask & DRM_PCIE_SPEED_50)) + if ((rdev->pdev->bus->max_bus_speed != PCIE_SPEED_5_0GT) && + (rdev->pdev->bus->max_bus_speed != PCIE_SPEED_8_0GT)) return; speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL); diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 47f180a79352..456750a0daa5 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -232,7 +232,7 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - u32 base_rate = 48000; + u32 base_rate = 24000; if (!dig || !dig->afmt) return; @@ -240,7 +240,6 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) /* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT. * doesn't matter which one you use. Just use the first one. */ - /* XXX: properly calculate this */ /* XXX two dtos; generally use dto0 for hdmi */ /* Express [24MHz / target pixel clock] as an exact rational * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE @@ -250,13 +249,13 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) /* according to the reg specs, this should DCE3.2 only, but in * practice it seems to cover DCE3.0 as well. */ - WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 50); + WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100); WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100); WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */ } else { /* according to the reg specs, this should be DCE2.0 and DCE3.0 */ - WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate * 50) | - AUDIO_DTO_MODULE(clock * 100)); + WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate / 10) | + AUDIO_DTO_MODULE(clock / 10)); } } diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index acb146c06973..79df558f8c40 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -1342,6 +1342,14 @@ #define PACKET3_STRMOUT_BASE_UPDATE 0x72 /* r7xx */ #define PACKET3_SURFACE_BASE_UPDATE 0x73 +#define R_000011_K8_FB_LOCATION 0x11 +#define R_000012_MC_MISC_UMA_CNTL 0x12 +#define G_000012_K8_ADDR_EXT(x) (((x) >> 0) & 0xFF) +#define R_0028F8_MC_INDEX 0x28F8 +#define S_0028F8_MC_IND_ADDR(x) (((x) & 0x1FF) << 0) +#define C_0028F8_MC_IND_ADDR 0xFFFFFE00 +#define S_0028F8_MC_IND_WR_EN(x) (((x) & 0x1) << 9) +#define R_0028FC_MC_DATA 0x28FC #define R_008020_GRBM_SOFT_RESET 0x8020 #define S_008020_SOFT_RESET_CP(x) (((x) & 1) << 0) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 1442ce765d48..142ce6cc69f5 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1694,6 +1694,7 @@ struct radeon_device { int num_crtc; /* number of crtcs */ struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */ bool audio_enabled; + bool has_uvd; struct r600_audio audio_status; /* audio stuff */ struct notifier_block acpi_nb; /* only one userspace can use Hyperz features or CMASK at a time */ @@ -1838,6 +1839,7 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); #define ASIC_IS_DCE61(rdev) ((rdev->family >= CHIP_ARUBA) && \ (rdev->flags & RADEON_IS_IGP)) #define ASIC_IS_DCE64(rdev) ((rdev->family == CHIP_OLAND)) +#define ASIC_IS_NODCE(rdev) ((rdev->family == CHIP_HAINAN)) /* * BIOS helpers. diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 6417132c50cf..a2802b47ee95 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -122,6 +122,10 @@ static void radeon_register_accessor_init(struct radeon_device *rdev) rdev->mc_rreg = &rs600_mc_rreg; rdev->mc_wreg = &rs600_mc_wreg; } + if (rdev->family == CHIP_RS780 || rdev->family == CHIP_RS880) { + rdev->mc_rreg = &rs780_mc_rreg; + rdev->mc_wreg = &rs780_mc_wreg; + } if (rdev->family >= CHIP_R600) { rdev->pciep_rreg = &r600_pciep_rreg; rdev->pciep_wreg = &r600_pciep_wreg; @@ -1935,6 +1939,8 @@ int radeon_asic_init(struct radeon_device *rdev) else rdev->num_crtc = 2; + rdev->has_uvd = false; + switch (rdev->family) { case CHIP_R100: case CHIP_RV100: @@ -1999,16 +2005,22 @@ int radeon_asic_init(struct radeon_device *rdev) case CHIP_RV635: case CHIP_RV670: rdev->asic = &r600_asic; + if (rdev->family == CHIP_R600) + rdev->has_uvd = false; + else + rdev->has_uvd = true; break; case CHIP_RS780: case CHIP_RS880: rdev->asic = &rs780_asic; + rdev->has_uvd = true; break; case CHIP_RV770: case CHIP_RV730: case CHIP_RV710: case CHIP_RV740: rdev->asic = &rv770_asic; + rdev->has_uvd = true; break; case CHIP_CEDAR: case CHIP_REDWOOD: @@ -2021,11 +2033,13 @@ int radeon_asic_init(struct radeon_device *rdev) else rdev->num_crtc = 6; rdev->asic = &evergreen_asic; + rdev->has_uvd = true; break; case CHIP_PALM: case CHIP_SUMO: case CHIP_SUMO2: rdev->asic = &sumo_asic; + rdev->has_uvd = true; break; case CHIP_BARTS: case CHIP_TURKS: @@ -2036,27 +2050,37 @@ int radeon_asic_init(struct radeon_device *rdev) else rdev->num_crtc = 6; rdev->asic = &btc_asic; + rdev->has_uvd = true; break; case CHIP_CAYMAN: rdev->asic = &cayman_asic; /* set num crtcs */ rdev->num_crtc = 6; + rdev->has_uvd = true; break; case CHIP_ARUBA: rdev->asic = &trinity_asic; /* set num crtcs */ rdev->num_crtc = 4; + rdev->has_uvd = true; break; case CHIP_TAHITI: case CHIP_PITCAIRN: case CHIP_VERDE: case CHIP_OLAND: + case CHIP_HAINAN: rdev->asic = &si_asic; /* set num crtcs */ - if (rdev->family == CHIP_OLAND) + if (rdev->family == CHIP_HAINAN) + rdev->num_crtc = 0; + else if (rdev->family == CHIP_OLAND) rdev->num_crtc = 2; else rdev->num_crtc = 6; + if (rdev->family == CHIP_HAINAN) + rdev->has_uvd = false; + else + rdev->has_uvd = true; break; default: /* FIXME: not supported yet */ diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 2c87365d345f..a72759ede753 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -347,6 +347,8 @@ extern bool r600_gui_idle(struct radeon_device *rdev); extern void r600_pm_misc(struct radeon_device *rdev); extern void r600_pm_init_profile(struct radeon_device *rdev); extern void rs780_pm_init_profile(struct radeon_device *rdev); +extern uint32_t rs780_mc_rreg(struct radeon_device *rdev, uint32_t reg); +extern void rs780_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); extern void r600_pm_get_dynpm_state(struct radeon_device *rdev); extern void r600_set_pcie_lanes(struct radeon_device *rdev, int lanes); extern int r600_get_pcie_lanes(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index fa3c56fba294..061b227dae0c 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -244,24 +244,28 @@ static bool ni_read_disabled_bios(struct radeon_device *rdev) /* enable the rom */ WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS)); - /* Disable VGA mode */ - WREG32(AVIVO_D1VGA_CONTROL, - (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | - AVIVO_DVGA_CONTROL_TIMING_SELECT))); - WREG32(AVIVO_D2VGA_CONTROL, - (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | - AVIVO_DVGA_CONTROL_TIMING_SELECT))); - WREG32(AVIVO_VGA_RENDER_CONTROL, - (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); + if (!ASIC_IS_NODCE(rdev)) { + /* Disable VGA mode */ + WREG32(AVIVO_D1VGA_CONTROL, + (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_D2VGA_CONTROL, + (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + WREG32(AVIVO_VGA_RENDER_CONTROL, + (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); + } WREG32(R600_ROM_CNTL, rom_cntl | R600_SCK_OVERWRITE); r = radeon_read_bios(rdev); /* restore regs */ WREG32(R600_BUS_CNTL, bus_cntl); - WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); - WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); - WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); + if (!ASIC_IS_NODCE(rdev)) { + WREG32(AVIVO_D1VGA_CONTROL, d1vga_control); + WREG32(AVIVO_D2VGA_CONTROL, d2vga_control); + WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control); + } WREG32(R600_ROM_CNTL, rom_cntl); return r; } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index a8f608903989..b0dc0b6cb4e0 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -94,6 +94,7 @@ static const char radeon_family_name[][16] = { "PITCAIRN", "VERDE", "OLAND", + "HAINAN", "LAST", }; @@ -243,16 +244,6 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg) */ void radeon_wb_disable(struct radeon_device *rdev) { - int r; - - if (rdev->wb.wb_obj) { - r = radeon_bo_reserve(rdev->wb.wb_obj, false); - if (unlikely(r != 0)) - return; - radeon_bo_kunmap(rdev->wb.wb_obj); - radeon_bo_unpin(rdev->wb.wb_obj); - radeon_bo_unreserve(rdev->wb.wb_obj); - } rdev->wb.enabled = false; } @@ -268,6 +259,11 @@ void radeon_wb_fini(struct radeon_device *rdev) { radeon_wb_disable(rdev); if (rdev->wb.wb_obj) { + if (!radeon_bo_reserve(rdev->wb.wb_obj, false)) { + radeon_bo_kunmap(rdev->wb.wb_obj); + radeon_bo_unpin(rdev->wb.wb_obj); + radeon_bo_unreserve(rdev->wb.wb_obj); + } radeon_bo_unref(&rdev->wb.wb_obj); rdev->wb.wb = NULL; rdev->wb.wb_obj = NULL; @@ -294,26 +290,26 @@ int radeon_wb_init(struct radeon_device *rdev) dev_warn(rdev->dev, "(%d) create WB bo failed\n", r); return r; } - } - r = radeon_bo_reserve(rdev->wb.wb_obj, false); - if (unlikely(r != 0)) { - radeon_wb_fini(rdev); - return r; - } - r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT, - &rdev->wb.gpu_addr); - if (r) { + r = radeon_bo_reserve(rdev->wb.wb_obj, false); + if (unlikely(r != 0)) { + radeon_wb_fini(rdev); + return r; + } + r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT, + &rdev->wb.gpu_addr); + if (r) { + radeon_bo_unreserve(rdev->wb.wb_obj); + dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r); + radeon_wb_fini(rdev); + return r; + } + r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb); radeon_bo_unreserve(rdev->wb.wb_obj); - dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r); - radeon_wb_fini(rdev); - return r; - } - r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb); - radeon_bo_unreserve(rdev->wb.wb_obj); - if (r) { - dev_warn(rdev->dev, "(%d) map WB bo failed\n", r); - radeon_wb_fini(rdev); - return r; + if (r) { + dev_warn(rdev->dev, "(%d) map WB bo failed\n", r); + radeon_wb_fini(rdev); + return r; + } } /* clear wb memory */ @@ -466,23 +462,27 @@ bool radeon_card_posted(struct radeon_device *rdev) { uint32_t reg; + /* required for EFI mode on macbook2,1 which uses an r5xx asic */ if (efi_enabled(EFI_BOOT) && - rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) + (rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) && + (rdev->family < CHIP_R600)) return false; + if (ASIC_IS_NODCE(rdev)) + goto check_memsize; + /* first check CRTCs */ - if (ASIC_IS_DCE41(rdev)) { + if (ASIC_IS_DCE4(rdev)) { reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); - if (reg & EVERGREEN_CRTC_MASTER_EN) - return true; - } else if (ASIC_IS_DCE4(rdev)) { - reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); + if (rdev->num_crtc >= 4) { + reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); + } + if (rdev->num_crtc >= 6) { + reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); + } if (reg & EVERGREEN_CRTC_MASTER_EN) return true; } else if (ASIC_IS_AVIVO(rdev)) { @@ -499,6 +499,7 @@ bool radeon_card_posted(struct radeon_device *rdev) } } +check_memsize: /* then check MEM_SIZE, in case the crtcs are off */ if (rdev->family >= CHIP_R600) reg = RREG32(R600_CONFIG_MEMSIZE); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index e38fd559f1ab..eb18bb7af1cc 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -271,8 +271,6 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; struct radeon_unpin_work *work; - struct drm_pending_vblank_event *e; - struct timeval now; unsigned long flags; u32 update_pending; int vpos, hpos; @@ -328,14 +326,9 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) radeon_crtc->unpin_work = NULL; /* wakeup userspace */ - if (work->event) { - e = work->event; - e->event.sequence = drm_vblank_count_and_time(rdev->ddev, crtc_id, &now); - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; - list_add_tail(&e->base.link, &e->base.file_priv->event_list); - wake_up_interruptible(&e->base.file_priv->event_wait); - } + if (work->event) + drm_send_vblank_event(rdev->ddev, crtc_id, work->event); + spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id); diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h index 2d91123f2759..36e9803b077d 100644 --- a/drivers/gpu/drm/radeon/radeon_family.h +++ b/drivers/gpu/drm/radeon/radeon_family.h @@ -92,6 +92,7 @@ enum radeon_family { CHIP_PITCAIRN, CHIP_VERDE, CHIP_OLAND, + CHIP_HAINAN, CHIP_LAST, }; diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 5b937dfe6f65..ddb8f8e04eb5 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -63,7 +63,9 @@ static void radeon_fence_write(struct radeon_device *rdev, u32 seq, int ring) { struct radeon_fence_driver *drv = &rdev->fence_drv[ring]; if (likely(rdev->wb.enabled || !drv->scratch_reg)) { - *drv->cpu_addr = cpu_to_le32(seq); + if (drv->cpu_addr) { + *drv->cpu_addr = cpu_to_le32(seq); + } } else { WREG32(drv->scratch_reg, seq); } @@ -84,7 +86,11 @@ static u32 radeon_fence_read(struct radeon_device *rdev, int ring) u32 seq = 0; if (likely(rdev->wb.enabled || !drv->scratch_reg)) { - seq = le32_to_cpu(*drv->cpu_addr); + if (drv->cpu_addr) { + seq = le32_to_cpu(*drv->cpu_addr); + } else { + seq = lower_32_bits(atomic64_read(&drv->last_seq)); + } } else { seq = RREG32(drv->scratch_reg); } diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 2c1341f63dc5..43ec4a401f07 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -1197,11 +1197,13 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev, int radeon_vm_bo_rmv(struct radeon_device *rdev, struct radeon_bo_va *bo_va) { - int r; + int r = 0; mutex_lock(&rdev->vm_manager.lock); mutex_lock(&bo_va->vm->mutex); - r = radeon_vm_bo_update_pte(rdev, bo_va->vm, bo_va->bo, NULL); + if (bo_va->soffset) { + r = radeon_vm_bo_update_pte(rdev, bo_va->vm, bo_va->bo, NULL); + } mutex_unlock(&rdev->vm_manager.lock); list_del(&bo_va->vm_list); mutex_unlock(&bo_va->vm->mutex); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 6857cb4efb76..7cb178a34a0f 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -1031,11 +1031,9 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc, static void radeon_crtc_prepare(struct drm_crtc *crtc) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_crtc *crtci; - radeon_crtc->in_mode_set = true; /* * The hardware wedges sometimes if you reconfigure one CRTC * whilst another is running (see fdo bug #24611). @@ -1046,7 +1044,6 @@ static void radeon_crtc_prepare(struct drm_crtc *crtc) static void radeon_crtc_commit(struct drm_crtc *crtc) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_crtc *crtci; @@ -1057,7 +1054,6 @@ static void radeon_crtc_commit(struct drm_crtc *crtc) if (crtci->enabled) radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON); } - radeon_crtc->in_mode_set = false; } static const struct drm_crtc_helper_funcs legacy_helper_funcs = { diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 44e579e75fd0..69ad4fe224c1 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -302,7 +302,6 @@ struct radeon_crtc { u16 lut_r[256], lut_g[256], lut_b[256]; bool enabled; bool can_tile; - bool in_mode_set; uint32_t crtc_offset; struct drm_gem_object *cursor_bo; uint64_t cursor_addr; diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 1424ccde2377..07af5a95bb62 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -322,8 +322,8 @@ int radeon_bo_init(struct radeon_device *rdev) { /* Add an MTRR for the VRAM */ if (!rdev->fastfb_working) { - rdev->mc.vram_mtrr = mtrr_add(rdev->mc.aper_base, rdev->mc.aper_size, - MTRR_TYPE_WRCOMB, 1); + rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base, + rdev->mc.aper_size); } DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n", rdev->mc.mc_vram_size >> 20, @@ -336,6 +336,7 @@ int radeon_bo_init(struct radeon_device *rdev) void radeon_bo_fini(struct radeon_device *rdev) { radeon_ttm_fini(rdev); + arch_phys_wc_del(rdev->mc.vram_mtrr); } void radeon_bo_list_add_object(struct radeon_bo_list *lobj, diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index e17faa7cf732..82434018cbe8 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -402,6 +402,13 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi return -ENOMEM; /* Align requested size with padding so unlock_commit can * pad safely */ + radeon_ring_free_size(rdev, ring); + if (ring->ring_free_dw == (ring->ring_size / 4)) { + /* This is an empty ring update lockup info to avoid + * false positive. + */ + radeon_ring_lockup_update(ring); + } ndw = (ndw + ring->align_mask) & ~ring->align_mask; while (ndw > (ring->ring_free_dw - 1)) { radeon_ring_free_size(rdev, ring); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 93f760e27a92..6c0ce8915fac 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -726,7 +726,7 @@ int radeon_ttm_init(struct radeon_device *rdev) return r; } DRM_INFO("radeon: %uM of VRAM memory ready\n", - (unsigned)rdev->mc.real_vram_size / (1024 * 1024)); + (unsigned) (rdev->mc.real_vram_size / (1024 * 1024))); r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT, rdev->mc.gtt_size >> PAGE_SHIFT); if (r) { diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 906e5c0ca3b9..cad735dd02c6 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -159,7 +159,17 @@ int radeon_uvd_suspend(struct radeon_device *rdev) if (!r) { radeon_bo_kunmap(rdev->uvd.vcpu_bo); radeon_bo_unpin(rdev->uvd.vcpu_bo); + rdev->uvd.cpu_addr = NULL; + if (!radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_CPU, NULL)) { + radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); + } radeon_bo_unreserve(rdev->uvd.vcpu_bo); + + if (rdev->uvd.cpu_addr) { + radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); + } else { + rdev->fence_drv[R600_RING_TYPE_UVD_INDEX].cpu_addr = NULL; + } } return r; } @@ -178,6 +188,10 @@ int radeon_uvd_resume(struct radeon_device *rdev) return r; } + /* Have been pin in cpu unmap unpin */ + radeon_bo_kunmap(rdev->uvd.vcpu_bo); + radeon_bo_unpin(rdev->uvd.vcpu_bo); + r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, &rdev->uvd.gpu_addr); if (r) { @@ -613,19 +627,19 @@ int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, } /* stitch together an UVD create msg */ - msg[0] = 0x00000de4; - msg[1] = 0x00000000; - msg[2] = handle; - msg[3] = 0x00000000; - msg[4] = 0x00000000; - msg[5] = 0x00000000; - msg[6] = 0x00000000; - msg[7] = 0x00000780; - msg[8] = 0x00000440; - msg[9] = 0x00000000; - msg[10] = 0x01b37000; + msg[0] = cpu_to_le32(0x00000de4); + msg[1] = cpu_to_le32(0x00000000); + msg[2] = cpu_to_le32(handle); + msg[3] = cpu_to_le32(0x00000000); + msg[4] = cpu_to_le32(0x00000000); + msg[5] = cpu_to_le32(0x00000000); + msg[6] = cpu_to_le32(0x00000000); + msg[7] = cpu_to_le32(0x00000780); + msg[8] = cpu_to_le32(0x00000440); + msg[9] = cpu_to_le32(0x00000000); + msg[10] = cpu_to_le32(0x01b37000); for (i = 11; i < 1024; ++i) - msg[i] = 0x0; + msg[i] = cpu_to_le32(0x0); radeon_bo_kunmap(bo); radeon_bo_unreserve(bo); @@ -659,12 +673,12 @@ int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, } /* stitch together an UVD destroy msg */ - msg[0] = 0x00000de4; - msg[1] = 0x00000002; - msg[2] = handle; - msg[3] = 0x00000000; + msg[0] = cpu_to_le32(0x00000de4); + msg[1] = cpu_to_le32(0x00000002); + msg[2] = cpu_to_le32(handle); + msg[3] = cpu_to_le32(0x00000000); for (i = 4; i < 1024; ++i) - msg[i] = 0x0; + msg[i] = cpu_to_le32(0x0); radeon_bo_kunmap(bo); radeon_bo_unreserve(bo); diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 73051ce3121e..233a9b9fa1f7 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -417,6 +417,12 @@ static int rs400_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r100_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -535,9 +541,6 @@ int rs400_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; /* Memory manager */ r = radeon_bo_init(rdev); if (r) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 46fa1b07c560..670b555d2ca2 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -923,6 +923,12 @@ static int rs600_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + rs600_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -1047,9 +1053,6 @@ int rs600_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; /* Memory manager */ r = radeon_bo_init(rdev); if (r) diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index ab4c86cfd552..55880d5962c3 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -651,6 +651,12 @@ static int rs690_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + rs600_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -776,9 +782,6 @@ int rs690_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; /* Memory manager */ r = radeon_bo_init(rdev); if (r) diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index ffcba730c57c..21c7d7b26e55 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -532,6 +532,12 @@ static int rv515_startup(struct radeon_device *rdev) } /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + rs600_irq_set(rdev); rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL); /* 1M ring buffer */ @@ -662,9 +668,6 @@ int rv515_init(struct radeon_device *rdev) r = radeon_fence_driver_init(rdev); if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; /* Memory manager */ r = radeon_bo_init(rdev); if (r) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 83f612a9500b..4a62ad2e5399 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -862,10 +862,8 @@ int rv770_uvd_resume(struct radeon_device *rdev) chip_id = 0x0100000b; break; case CHIP_SUMO: - chip_id = 0x0100000c; - break; case CHIP_SUMO2: - chip_id = 0x0100000d; + chip_id = 0x0100000c; break; case CHIP_PALM: chip_id = 0x0100000e; @@ -1889,6 +1887,12 @@ static int rv770_startup(struct radeon_device *rdev) rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r = r600_irq_init(rdev); if (r) { DRM_ERROR("radeon: IH init failed (%d).\n", r); @@ -2047,10 +2051,6 @@ int rv770_init(struct radeon_device *rdev) if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; - rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -2113,8 +2113,6 @@ static void rv770_pcie_gen2_enable(struct radeon_device *rdev) { u32 link_width_cntl, lanes, speed_cntl, tmp; u16 link_cntl2; - u32 mask; - int ret; if (radeon_pcie_gen2 == 0) return; @@ -2129,11 +2127,8 @@ static void rv770_pcie_gen2_enable(struct radeon_device *rdev) if (ASIC_IS_X2(rdev)) return; - ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask); - if (ret != 0) - return; - - if (!(mask & DRM_PCIE_SPEED_50)) + if ((rdev->pdev->bus->max_bus_speed != PCIE_SPEED_5_0GT) && + (rdev->pdev->bus->max_bus_speed != PCIE_SPEED_8_0GT)) return; DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n"); diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index f0b6c2f87c4d..a1b0da6b5808 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -60,6 +60,11 @@ MODULE_FIRMWARE("radeon/OLAND_me.bin"); MODULE_FIRMWARE("radeon/OLAND_ce.bin"); MODULE_FIRMWARE("radeon/OLAND_mc.bin"); MODULE_FIRMWARE("radeon/OLAND_rlc.bin"); +MODULE_FIRMWARE("radeon/HAINAN_pfp.bin"); +MODULE_FIRMWARE("radeon/HAINAN_me.bin"); +MODULE_FIRMWARE("radeon/HAINAN_ce.bin"); +MODULE_FIRMWARE("radeon/HAINAN_mc.bin"); +MODULE_FIRMWARE("radeon/HAINAN_rlc.bin"); extern int r600_ih_ring_alloc(struct radeon_device *rdev); extern void r600_ih_ring_fini(struct radeon_device *rdev); @@ -265,6 +270,40 @@ static const u32 oland_golden_registers[] = 0x15c0, 0x000c0fc0, 0x000c0400 }; +static const u32 hainan_golden_registers[] = +{ + 0x9a10, 0x00010000, 0x00018208, + 0x9830, 0xffffffff, 0x00000000, + 0x9834, 0xf00fffff, 0x00000400, + 0x9838, 0x0002021c, 0x00020200, + 0xd0c0, 0xff000fff, 0x00000100, + 0xd030, 0x000300c0, 0x00800040, + 0xd8c0, 0xff000fff, 0x00000100, + 0xd830, 0x000300c0, 0x00800040, + 0x2ae4, 0x00073ffe, 0x000022a2, + 0x240c, 0x000007ff, 0x00000000, + 0x8a14, 0xf000001f, 0x00000007, + 0x8b24, 0xffffffff, 0x00ffffff, + 0x8b10, 0x0000ff0f, 0x00000000, + 0x28a4c, 0x07ffffff, 0x4e000000, + 0x28350, 0x3f3f3fff, 0x00000000, + 0x30, 0x000000ff, 0x0040, + 0x34, 0x00000040, 0x00004040, + 0x9100, 0x03e00000, 0x03600000, + 0x9060, 0x0000007f, 0x00000020, + 0x9508, 0x00010000, 0x00010000, + 0xac14, 0x000003ff, 0x000000f1, + 0xac10, 0xffffffff, 0x00000000, + 0xac0c, 0xffffffff, 0x00003210, + 0x88d4, 0x0000001f, 0x00000010, + 0x15c0, 0x000c0fc0, 0x000c0400 +}; + +static const u32 hainan_golden_registers2[] = +{ + 0x98f8, 0xffffffff, 0x02010001 +}; + static const u32 tahiti_mgcg_cgcg_init[] = { 0xc400, 0xffffffff, 0xfffffffc, @@ -673,6 +712,83 @@ static const u32 oland_mgcg_cgcg_init[] = 0xd8c0, 0xfffffff0, 0x00000100 }; +static const u32 hainan_mgcg_cgcg_init[] = +{ + 0xc400, 0xffffffff, 0xfffffffc, + 0x802c, 0xffffffff, 0xe0000000, + 0x9a60, 0xffffffff, 0x00000100, + 0x92a4, 0xffffffff, 0x00000100, + 0xc164, 0xffffffff, 0x00000100, + 0x9774, 0xffffffff, 0x00000100, + 0x8984, 0xffffffff, 0x06000100, + 0x8a18, 0xffffffff, 0x00000100, + 0x92a0, 0xffffffff, 0x00000100, + 0xc380, 0xffffffff, 0x00000100, + 0x8b28, 0xffffffff, 0x00000100, + 0x9144, 0xffffffff, 0x00000100, + 0x8d88, 0xffffffff, 0x00000100, + 0x8d8c, 0xffffffff, 0x00000100, + 0x9030, 0xffffffff, 0x00000100, + 0x9034, 0xffffffff, 0x00000100, + 0x9038, 0xffffffff, 0x00000100, + 0x903c, 0xffffffff, 0x00000100, + 0xad80, 0xffffffff, 0x00000100, + 0xac54, 0xffffffff, 0x00000100, + 0x897c, 0xffffffff, 0x06000100, + 0x9868, 0xffffffff, 0x00000100, + 0x9510, 0xffffffff, 0x00000100, + 0xaf04, 0xffffffff, 0x00000100, + 0xae04, 0xffffffff, 0x00000100, + 0x949c, 0xffffffff, 0x00000100, + 0x802c, 0xffffffff, 0xe0000000, + 0x9160, 0xffffffff, 0x00010000, + 0x9164, 0xffffffff, 0x00030002, + 0x9168, 0xffffffff, 0x00040007, + 0x916c, 0xffffffff, 0x00060005, + 0x9170, 0xffffffff, 0x00090008, + 0x9174, 0xffffffff, 0x00020001, + 0x9178, 0xffffffff, 0x00040003, + 0x917c, 0xffffffff, 0x00000007, + 0x9180, 0xffffffff, 0x00060005, + 0x9184, 0xffffffff, 0x00090008, + 0x9188, 0xffffffff, 0x00030002, + 0x918c, 0xffffffff, 0x00050004, + 0x9190, 0xffffffff, 0x00000008, + 0x9194, 0xffffffff, 0x00070006, + 0x9198, 0xffffffff, 0x000a0009, + 0x919c, 0xffffffff, 0x00040003, + 0x91a0, 0xffffffff, 0x00060005, + 0x91a4, 0xffffffff, 0x00000009, + 0x91a8, 0xffffffff, 0x00080007, + 0x91ac, 0xffffffff, 0x000b000a, + 0x91b0, 0xffffffff, 0x00050004, + 0x91b4, 0xffffffff, 0x00070006, + 0x91b8, 0xffffffff, 0x0008000b, + 0x91bc, 0xffffffff, 0x000a0009, + 0x91c0, 0xffffffff, 0x000d000c, + 0x91c4, 0xffffffff, 0x00060005, + 0x91c8, 0xffffffff, 0x00080007, + 0x91cc, 0xffffffff, 0x0000000b, + 0x91d0, 0xffffffff, 0x000a0009, + 0x91d4, 0xffffffff, 0x000d000c, + 0x9150, 0xffffffff, 0x96940200, + 0x8708, 0xffffffff, 0x00900100, + 0xc478, 0xffffffff, 0x00000080, + 0xc404, 0xffffffff, 0x0020003f, + 0x30, 0xffffffff, 0x0000001c, + 0x34, 0x000f0000, 0x000f0000, + 0x160c, 0xffffffff, 0x00000100, + 0x1024, 0xffffffff, 0x00000100, + 0x20a8, 0xffffffff, 0x00000104, + 0x264c, 0x000c0000, 0x000c0000, + 0x2648, 0x000c0000, 0x000c0000, + 0x2f50, 0x00000001, 0x00000001, + 0x30cc, 0xc0000fff, 0x00000104, + 0xc1e4, 0x00000001, 0x00000001, + 0xd0c0, 0xfffffff0, 0x00000100, + 0xd8c0, 0xfffffff0, 0x00000100 +}; + static u32 verde_pg_init[] = { 0x353c, 0xffffffff, 0x40000, @@ -853,6 +969,17 @@ static void si_init_golden_registers(struct radeon_device *rdev) oland_mgcg_cgcg_init, (const u32)ARRAY_SIZE(oland_mgcg_cgcg_init)); break; + case CHIP_HAINAN: + radeon_program_register_sequence(rdev, + hainan_golden_registers, + (const u32)ARRAY_SIZE(hainan_golden_registers)); + radeon_program_register_sequence(rdev, + hainan_golden_registers2, + (const u32)ARRAY_SIZE(hainan_golden_registers2)); + radeon_program_register_sequence(rdev, + hainan_mgcg_cgcg_init, + (const u32)ARRAY_SIZE(hainan_mgcg_cgcg_init)); + break; default: break; } @@ -1062,6 +1189,45 @@ static const u32 oland_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = { {0x0000009f, 0x00a17730} }; +static const u32 hainan_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = { + {0x0000006f, 0x03044000}, + {0x00000070, 0x0480c018}, + {0x00000071, 0x00000040}, + {0x00000072, 0x01000000}, + {0x00000074, 0x000000ff}, + {0x00000075, 0x00143400}, + {0x00000076, 0x08ec0800}, + {0x00000077, 0x040000cc}, + {0x00000079, 0x00000000}, + {0x0000007a, 0x21000409}, + {0x0000007c, 0x00000000}, + {0x0000007d, 0xe8000000}, + {0x0000007e, 0x044408a8}, + {0x0000007f, 0x00000003}, + {0x00000080, 0x00000000}, + {0x00000081, 0x01000000}, + {0x00000082, 0x02000000}, + {0x00000083, 0x00000000}, + {0x00000084, 0xe3f3e4f4}, + {0x00000085, 0x00052024}, + {0x00000087, 0x00000000}, + {0x00000088, 0x66036603}, + {0x00000089, 0x01000000}, + {0x0000008b, 0x1c0a0000}, + {0x0000008c, 0xff010000}, + {0x0000008e, 0xffffefff}, + {0x0000008f, 0xfff3efff}, + {0x00000090, 0xfff3efbf}, + {0x00000094, 0x00101101}, + {0x00000095, 0x00000fff}, + {0x00000096, 0x00116fff}, + {0x00000097, 0x60010000}, + {0x00000098, 0x10010000}, + {0x00000099, 0x00006000}, + {0x0000009a, 0x00001000}, + {0x0000009f, 0x00a07730} +}; + /* ucode loading */ static int si_mc_load_microcode(struct radeon_device *rdev) { @@ -1095,6 +1261,11 @@ static int si_mc_load_microcode(struct radeon_device *rdev) ucode_size = OLAND_MC_UCODE_SIZE; regs_size = TAHITI_IO_MC_REGS_SIZE; break; + case CHIP_HAINAN: + io_mc_regs = (u32 *)&hainan_io_mc_regs; + ucode_size = OLAND_MC_UCODE_SIZE; + regs_size = TAHITI_IO_MC_REGS_SIZE; + break; } running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK; @@ -1198,6 +1369,15 @@ static int si_init_microcode(struct radeon_device *rdev) rlc_req_size = SI_RLC_UCODE_SIZE * 4; mc_req_size = OLAND_MC_UCODE_SIZE * 4; break; + case CHIP_HAINAN: + chip_name = "HAINAN"; + rlc_chip_name = "HAINAN"; + pfp_req_size = SI_PFP_UCODE_SIZE * 4; + me_req_size = SI_PM4_UCODE_SIZE * 4; + ce_req_size = SI_CE_UCODE_SIZE * 4; + rlc_req_size = SI_RLC_UCODE_SIZE * 4; + mc_req_size = OLAND_MC_UCODE_SIZE * 4; + break; default: BUG(); } @@ -2003,7 +2183,8 @@ static void si_tiling_mode_table_init(struct radeon_device *rdev) WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden); } } else if ((rdev->family == CHIP_VERDE) || - (rdev->family == CHIP_OLAND)) { + (rdev->family == CHIP_OLAND) || + (rdev->family == CHIP_HAINAN)) { for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { switch (reg_offset) { case 0: /* non-AA compressed depth or any compressed stencil */ @@ -2435,7 +2616,7 @@ static void si_gpu_init(struct radeon_device *rdev) default: rdev->config.si.max_shader_engines = 1; rdev->config.si.max_tile_pipes = 4; - rdev->config.si.max_cu_per_sh = 2; + rdev->config.si.max_cu_per_sh = 5; rdev->config.si.max_sh_per_se = 2; rdev->config.si.max_backends_per_se = 4; rdev->config.si.max_texture_channel_caches = 4; @@ -2466,6 +2647,23 @@ static void si_gpu_init(struct radeon_device *rdev) rdev->config.si.sc_earlyz_tile_fifo_size = 0x130; gb_addr_config = VERDE_GB_ADDR_CONFIG_GOLDEN; break; + case CHIP_HAINAN: + rdev->config.si.max_shader_engines = 1; + rdev->config.si.max_tile_pipes = 4; + rdev->config.si.max_cu_per_sh = 5; + rdev->config.si.max_sh_per_se = 1; + rdev->config.si.max_backends_per_se = 1; + rdev->config.si.max_texture_channel_caches = 2; + rdev->config.si.max_gprs = 256; + rdev->config.si.max_gs_threads = 16; + rdev->config.si.max_hw_contexts = 8; + + rdev->config.si.sc_prim_fifo_size_frontend = 0x20; + rdev->config.si.sc_prim_fifo_size_backend = 0x40; + rdev->config.si.sc_hiz_tile_fifo_size = 0x30; + rdev->config.si.sc_earlyz_tile_fifo_size = 0x130; + gb_addr_config = HAINAN_GB_ADDR_CONFIG_GOLDEN; + break; } /* Initialize HDP */ @@ -2559,9 +2757,11 @@ static void si_gpu_init(struct radeon_device *rdev) WREG32(HDP_ADDR_CONFIG, gb_addr_config); WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config); WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config); - WREG32(UVD_UDEC_ADDR_CONFIG, gb_addr_config); - WREG32(UVD_UDEC_DB_ADDR_CONFIG, gb_addr_config); - WREG32(UVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config); + if (rdev->has_uvd) { + WREG32(UVD_UDEC_ADDR_CONFIG, gb_addr_config); + WREG32(UVD_UDEC_DB_ADDR_CONFIG, gb_addr_config); + WREG32(UVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config); + } si_tiling_mode_table_init(rdev); @@ -3304,8 +3504,9 @@ static void si_mc_program(struct radeon_device *rdev) if (radeon_mc_wait_for_idle(rdev)) { dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); } - /* Lockout access through VGA aperture*/ - WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE); + if (!ASIC_IS_NODCE(rdev)) + /* Lockout access through VGA aperture*/ + WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE); /* Update configuration */ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.vram_start >> 12); @@ -3327,9 +3528,11 @@ static void si_mc_program(struct radeon_device *rdev) dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); } evergreen_mc_resume(rdev, &save); - /* we need to own VRAM, so turn off the VGA renderer here - * to stop it overwriting our objects */ - rv515_vga_render_disable(rdev); + if (!ASIC_IS_NODCE(rdev)) { + /* we need to own VRAM, so turn off the VGA renderer here + * to stop it overwriting our objects */ + rv515_vga_render_disable(rdev); + } } static void si_vram_gtt_location(struct radeon_device *rdev, @@ -3397,8 +3600,8 @@ static int si_mc_init(struct radeon_device *rdev) rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); /* size in MB on si */ - rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; - rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; + rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL; + rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL; rdev->mc.visible_vram_size = rdev->mc.aper_size; si_vram_gtt_location(rdev, &rdev->mc); radeon_update_bandwidth_info(rdev); @@ -4251,8 +4454,10 @@ static void si_disable_interrupt_state(struct radeon_device *rdev) tmp = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE; WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, tmp); WREG32(GRBM_INT_CNTL, 0); - WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); + if (rdev->num_crtc >= 2) { + WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); + WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); + } if (rdev->num_crtc >= 4) { WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); @@ -4262,8 +4467,10 @@ static void si_disable_interrupt_state(struct radeon_device *rdev) WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); } - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); + if (rdev->num_crtc >= 2) { + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); + } if (rdev->num_crtc >= 4) { WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); @@ -4273,21 +4480,22 @@ static void si_disable_interrupt_state(struct radeon_device *rdev) WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); } - WREG32(DACA_AUTODETECT_INT_CONTROL, 0); - - tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY; - WREG32(DC_HPD1_INT_CONTROL, tmp); - tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY; - WREG32(DC_HPD2_INT_CONTROL, tmp); - tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY; - WREG32(DC_HPD3_INT_CONTROL, tmp); - tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY; - WREG32(DC_HPD4_INT_CONTROL, tmp); - tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY; - WREG32(DC_HPD5_INT_CONTROL, tmp); - tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY; - WREG32(DC_HPD6_INT_CONTROL, tmp); + if (!ASIC_IS_NODCE(rdev)) { + WREG32(DACA_AUTODETECT_INT_CONTROL, 0); + tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD1_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD2_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD3_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD4_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD5_INT_CONTROL, tmp); + tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY; + WREG32(DC_HPD6_INT_CONTROL, tmp); + } } static int si_irq_init(struct radeon_device *rdev) @@ -4366,7 +4574,7 @@ int si_irq_set(struct radeon_device *rdev) u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE; u32 cp_int_cntl1 = 0, cp_int_cntl2 = 0; u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0; - u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; + u32 hpd1 = 0, hpd2 = 0, hpd3 = 0, hpd4 = 0, hpd5 = 0, hpd6 = 0; u32 grbm_int_cntl = 0; u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0; u32 dma_cntl, dma_cntl1; @@ -4383,12 +4591,14 @@ int si_irq_set(struct radeon_device *rdev) return 0; } - hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; - hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; + if (!ASIC_IS_NODCE(rdev)) { + hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN; + hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN; + } dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE; dma_cntl1 = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE; @@ -4479,8 +4689,10 @@ int si_irq_set(struct radeon_device *rdev) WREG32(GRBM_INT_CNTL, grbm_int_cntl); - WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); - WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); + if (rdev->num_crtc >= 2) { + WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); + WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); + } if (rdev->num_crtc >= 4) { WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3); WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4); @@ -4490,8 +4702,10 @@ int si_irq_set(struct radeon_device *rdev) WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6); } - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2); + if (rdev->num_crtc >= 2) { + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1); + WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2); + } if (rdev->num_crtc >= 4) { WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3); WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4); @@ -4501,12 +4715,14 @@ int si_irq_set(struct radeon_device *rdev) WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6); } - WREG32(DC_HPD1_INT_CONTROL, hpd1); - WREG32(DC_HPD2_INT_CONTROL, hpd2); - WREG32(DC_HPD3_INT_CONTROL, hpd3); - WREG32(DC_HPD4_INT_CONTROL, hpd4); - WREG32(DC_HPD5_INT_CONTROL, hpd5); - WREG32(DC_HPD6_INT_CONTROL, hpd6); + if (!ASIC_IS_NODCE(rdev)) { + WREG32(DC_HPD1_INT_CONTROL, hpd1); + WREG32(DC_HPD2_INT_CONTROL, hpd2); + WREG32(DC_HPD3_INT_CONTROL, hpd3); + WREG32(DC_HPD4_INT_CONTROL, hpd4); + WREG32(DC_HPD5_INT_CONTROL, hpd5); + WREG32(DC_HPD6_INT_CONTROL, hpd6); + } return 0; } @@ -4515,6 +4731,9 @@ static inline void si_irq_ack(struct radeon_device *rdev) { u32 tmp; + if (ASIC_IS_NODCE(rdev)) + return; + rdev->irq.stat_regs.evergreen.disp_int = RREG32(DISP_INTERRUPT_STATUS); rdev->irq.stat_regs.evergreen.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); rdev->irq.stat_regs.evergreen.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2); @@ -5118,17 +5337,25 @@ static int si_startup(struct radeon_device *rdev) return r; } - r = rv770_uvd_resume(rdev); - if (!r) { - r = radeon_fence_driver_start_ring(rdev, - R600_RING_TYPE_UVD_INDEX); + if (rdev->has_uvd) { + r = rv770_uvd_resume(rdev); + if (!r) { + r = radeon_fence_driver_start_ring(rdev, + R600_RING_TYPE_UVD_INDEX); + if (r) + dev_err(rdev->dev, "UVD fences init error (%d).\n", r); + } if (r) - dev_err(rdev->dev, "UVD fences init error (%d).\n", r); + rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; } - if (r) - rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; /* Enable IRQ */ + if (!rdev->irq.installed) { + r = radeon_irq_kms_init(rdev); + if (r) + return r; + } + r = si_irq_init(rdev); if (r) { DRM_ERROR("radeon: IH init failed (%d).\n", r); @@ -5185,16 +5412,18 @@ static int si_startup(struct radeon_device *rdev) if (r) return r; - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - if (ring->ring_size) { - r = radeon_ring_init(rdev, ring, ring->ring_size, - R600_WB_UVD_RPTR_OFFSET, - UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, - 0, 0xfffff, RADEON_CP_PACKET2); - if (!r) - r = r600_uvd_init(rdev); - if (r) - DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); + if (rdev->has_uvd) { + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + if (ring->ring_size) { + r = radeon_ring_init(rdev, ring, ring->ring_size, + R600_WB_UVD_RPTR_OFFSET, + UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, + 0, 0xfffff, RADEON_CP_PACKET2); + if (!r) + r = r600_uvd_init(rdev); + if (r) + DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); + } } r = radeon_ib_pool_init(rdev); @@ -5243,8 +5472,10 @@ int si_suspend(struct radeon_device *rdev) radeon_vm_manager_fini(rdev); si_cp_enable(rdev, false); cayman_dma_stop(rdev); - r600_uvd_rbc_stop(rdev); - radeon_uvd_suspend(rdev); + if (rdev->has_uvd) { + r600_uvd_rbc_stop(rdev); + radeon_uvd_suspend(rdev); + } si_irq_suspend(rdev); radeon_wb_disable(rdev); si_pcie_gart_disable(rdev); @@ -5308,10 +5539,6 @@ int si_init(struct radeon_device *rdev) if (r) return r; - r = radeon_irq_kms_init(rdev); - if (r) - return r; - ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; ring->ring_obj = NULL; r600_ring_init(rdev, ring, 1024 * 1024); @@ -5332,11 +5559,13 @@ int si_init(struct radeon_device *rdev) ring->ring_obj = NULL; r600_ring_init(rdev, ring, 64 * 1024); - r = radeon_uvd_init(rdev); - if (!r) { - ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; - ring->ring_obj = NULL; - r600_ring_init(rdev, ring, 4096); + if (rdev->has_uvd) { + r = radeon_uvd_init(rdev); + if (!r) { + ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; + ring->ring_obj = NULL; + r600_ring_init(rdev, ring, 4096); + } } rdev->ih.ring_obj = NULL; @@ -5384,7 +5613,8 @@ void si_fini(struct radeon_device *rdev) radeon_vm_manager_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); - radeon_uvd_fini(rdev); + if (rdev->has_uvd) + radeon_uvd_fini(rdev); si_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 222877ba6cf5..8f2d7d4f9b28 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -28,6 +28,7 @@ #define TAHITI_GB_ADDR_CONFIG_GOLDEN 0x12011003 #define VERDE_GB_ADDR_CONFIG_GOLDEN 0x12010002 +#define HAINAN_GB_ADDR_CONFIG_GOLDEN 0x02010001 /* discrete uvd clocks */ #define CG_UPLL_FUNC_CNTL 0x634 diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig new file mode 100644 index 000000000000..72887df8dd76 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -0,0 +1,9 @@ +config DRM_RCAR_DU + tristate "DRM Support for R-Car Display Unit" + depends on DRM && ARM + select DRM_KMS_HELPER + select DRM_KMS_CMA_HELPER + select DRM_GEM_CMA_HELPER + help + Choose this option if you have an R-Car chipset. + If M is selected the module will be called rcar-du-drm. diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile new file mode 100644 index 000000000000..7333c0094015 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -0,0 +1,8 @@ +rcar-du-drm-y := rcar_du_crtc.o \ + rcar_du_drv.o \ + rcar_du_kms.o \ + rcar_du_lvds.o \ + rcar_du_plane.o \ + rcar_du_vga.o + +obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c new file mode 100644 index 000000000000..24183fb93592 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -0,0 +1,595 @@ +/* + * rcar_du_crtc.c -- R-Car Display Unit CRTCs + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/clk.h> +#include <linux/mutex.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> + +#include "rcar_du_crtc.h" +#include "rcar_du_drv.h" +#include "rcar_du_kms.h" +#include "rcar_du_lvds.h" +#include "rcar_du_plane.h" +#include "rcar_du_regs.h" +#include "rcar_du_vga.h" + +#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) + +static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg) +{ + struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private; + + return rcar_du_read(rcdu, rcrtc->mmio_offset + reg); +} + +static void rcar_du_crtc_write(struct rcar_du_crtc *rcrtc, u32 reg, u32 data) +{ + struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private; + + rcar_du_write(rcdu, rcrtc->mmio_offset + reg, data); +} + +static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr) +{ + struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private; + + rcar_du_write(rcdu, rcrtc->mmio_offset + reg, + rcar_du_read(rcdu, rcrtc->mmio_offset + reg) & ~clr); +} + +static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set) +{ + struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private; + + rcar_du_write(rcdu, rcrtc->mmio_offset + reg, + rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set); +} + +static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg, + u32 clr, u32 set) +{ + struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private; + u32 value = rcar_du_read(rcdu, rcrtc->mmio_offset + reg); + + rcar_du_write(rcdu, rcrtc->mmio_offset + reg, (value & ~clr) | set); +} + +static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) +{ + struct drm_crtc *crtc = &rcrtc->crtc; + struct rcar_du_device *rcdu = crtc->dev->dev_private; + const struct drm_display_mode *mode = &crtc->mode; + unsigned long clk; + u32 value; + u32 div; + + /* Dot clock */ + clk = clk_get_rate(rcdu->clock); + div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000); + div = clamp(div, 1U, 64U) - 1; + + rcar_du_write(rcdu, rcrtc->index ? ESCR2 : ESCR, + ESCR_DCLKSEL_CLKS | div); + rcar_du_write(rcdu, rcrtc->index ? OTAR2 : OTAR, 0); + + /* Signal polarities */ + value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL) + | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL) + | DSMR_DIPM_DE; + rcar_du_crtc_write(rcrtc, DSMR, value); + + /* Display timings */ + rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19); + rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start + + mode->hdisplay - 19); + rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end - + mode->hsync_start - 1); + rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1); + + rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2); + rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end + + mode->vdisplay - 2); + rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end + + mode->vsync_start - 1); + rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1); + + rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start); + rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); +} + +static void rcar_du_crtc_set_routing(struct rcar_du_crtc *rcrtc) +{ + struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private; + u32 dorcr = rcar_du_read(rcdu, DORCR); + + dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK); + + /* Set the DU1 pins sources. Select CRTC 0 if explicitly requested and + * CRTC 1 in all other cases to avoid cloning CRTC 0 to DU0 and DU1 by + * default. + */ + if (rcrtc->outputs & (1 << 1) && rcrtc->index == 0) + dorcr |= DORCR_PG2D_DS1; + else + dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2; + + rcar_du_write(rcdu, DORCR, dorcr); +} + +static void __rcar_du_start_stop(struct rcar_du_device *rcdu, bool start) +{ + rcar_du_write(rcdu, DSYSR, + (rcar_du_read(rcdu, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) | + (start ? DSYSR_DEN : DSYSR_DRES)); +} + +static void rcar_du_start_stop(struct rcar_du_device *rcdu, bool start) +{ + /* Many of the configuration bits are only updated when the display + * reset (DRES) bit in DSYSR is set to 1, disabling *both* CRTCs. Some + * of those bits could be pre-configured, but others (especially the + * bits related to plane assignment to display timing controllers) need + * to be modified at runtime. + * + * Restart the display controller if a start is requested. Sorry for the + * flicker. It should be possible to move most of the "DRES-update" bits + * setup to driver initialization time and minimize the number of cases + * when the display controller will have to be restarted. + */ + if (start) { + if (rcdu->used_crtcs++ != 0) + __rcar_du_start_stop(rcdu, false); + __rcar_du_start_stop(rcdu, true); + } else { + if (--rcdu->used_crtcs == 0) + __rcar_du_start_stop(rcdu, false); + } +} + +void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output) +{ + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + + /* Store the route from the CRTC output to the DU output. The DU will be + * configured when starting the CRTC. + */ + rcrtc->outputs |= 1 << output; +} + +void rcar_du_crtc_update_planes(struct drm_crtc *crtc) +{ + struct rcar_du_device *rcdu = crtc->dev->dev_private; + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES]; + unsigned int num_planes = 0; + unsigned int prio = 0; + unsigned int i; + u32 dptsr = 0; + u32 dspr = 0; + + for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) { + struct rcar_du_plane *plane = &rcdu->planes.planes[i]; + unsigned int j; + + if (plane->crtc != &rcrtc->crtc || !plane->enabled) + continue; + + /* Insert the plane in the sorted planes array. */ + for (j = num_planes++; j > 0; --j) { + if (planes[j-1]->zpos <= plane->zpos) + break; + planes[j] = planes[j-1]; + } + + planes[j] = plane; + prio += plane->format->planes * 4; + } + + for (i = 0; i < num_planes; ++i) { + struct rcar_du_plane *plane = planes[i]; + unsigned int index = plane->hwindex; + + prio -= 4; + dspr |= (index + 1) << prio; + dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index); + + if (plane->format->planes == 2) { + index = (index + 1) % 8; + + prio -= 4; + dspr |= (index + 1) << prio; + dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index); + } + } + + /* Select display timing and dot clock generator 2 for planes associated + * with superposition controller 2. + */ + if (rcrtc->index) { + u32 value = rcar_du_read(rcdu, DPTSR); + + /* The DPTSR register is updated when the display controller is + * stopped. We thus need to restart the DU. Once again, sorry + * for the flicker. One way to mitigate the issue would be to + * pre-associate planes with CRTCs (either with a fixed 4/4 + * split, or through a module parameter). Flicker would then + * occur only if we need to break the pre-association. + */ + if (value != dptsr) { + rcar_du_write(rcdu, DPTSR, dptsr); + if (rcdu->used_crtcs) { + __rcar_du_start_stop(rcdu, false); + __rcar_du_start_stop(rcdu, true); + } + } + } + + rcar_du_write(rcdu, rcrtc->index ? DS2PR : DS1PR, dspr); +} + +static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) +{ + struct drm_crtc *crtc = &rcrtc->crtc; + struct rcar_du_device *rcdu = crtc->dev->dev_private; + unsigned int i; + + if (rcrtc->started) + return; + + if (WARN_ON(rcrtc->plane->format == NULL)) + return; + + /* Set display off and background to black */ + rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0)); + rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0)); + + /* Configure display timings and output routing */ + rcar_du_crtc_set_display_timing(rcrtc); + rcar_du_crtc_set_routing(rcrtc); + + mutex_lock(&rcdu->planes.lock); + rcrtc->plane->enabled = true; + rcar_du_crtc_update_planes(crtc); + mutex_unlock(&rcdu->planes.lock); + + /* Setup planes. */ + for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) { + struct rcar_du_plane *plane = &rcdu->planes.planes[i]; + + if (plane->crtc != crtc || !plane->enabled) + continue; + + rcar_du_plane_setup(plane); + } + + /* Select master sync mode. This enables display operation in master + * sync mode (with the HSYNC and VSYNC signals configured as outputs and + * actively driven). + */ + rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER); + + rcar_du_start_stop(rcdu, true); + + rcrtc->started = true; +} + +static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) +{ + struct drm_crtc *crtc = &rcrtc->crtc; + struct rcar_du_device *rcdu = crtc->dev->dev_private; + + if (!rcrtc->started) + return; + + mutex_lock(&rcdu->planes.lock); + rcrtc->plane->enabled = false; + rcar_du_crtc_update_planes(crtc); + mutex_unlock(&rcdu->planes.lock); + + /* Select switch sync mode. This stops display operation and configures + * the HSYNC and VSYNC signals as inputs. + */ + rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH); + + rcar_du_start_stop(rcdu, false); + + rcrtc->started = false; +} + +void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc) +{ + struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private; + + rcar_du_crtc_stop(rcrtc); + rcar_du_put(rcdu); +} + +void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc) +{ + struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private; + + if (rcrtc->dpms != DRM_MODE_DPMS_ON) + return; + + rcar_du_get(rcdu); + rcar_du_crtc_start(rcrtc); +} + +static void rcar_du_crtc_update_base(struct rcar_du_crtc *rcrtc) +{ + struct drm_crtc *crtc = &rcrtc->crtc; + + rcar_du_plane_compute_base(rcrtc->plane, crtc->fb); + rcar_du_plane_update_base(rcrtc->plane); +} + +static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct rcar_du_device *rcdu = crtc->dev->dev_private; + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + + if (rcrtc->dpms == mode) + return; + + if (mode == DRM_MODE_DPMS_ON) { + rcar_du_get(rcdu); + rcar_du_crtc_start(rcrtc); + } else { + rcar_du_crtc_stop(rcrtc); + rcar_du_put(rcdu); + } + + rcrtc->dpms = mode; +} + +static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* TODO Fixup modes */ + return true; +} + +static void rcar_du_crtc_mode_prepare(struct drm_crtc *crtc) +{ + struct rcar_du_device *rcdu = crtc->dev->dev_private; + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + + /* We need to access the hardware during mode set, acquire a reference + * to the DU. + */ + rcar_du_get(rcdu); + + /* Stop the CRTC and release the plane. Force the DPMS mode to off as a + * result. + */ + rcar_du_crtc_stop(rcrtc); + rcar_du_plane_release(rcrtc->plane); + + rcrtc->dpms = DRM_MODE_DPMS_OFF; +} + +static int rcar_du_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) +{ + struct rcar_du_device *rcdu = crtc->dev->dev_private; + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + const struct rcar_du_format_info *format; + int ret; + + format = rcar_du_format_info(crtc->fb->pixel_format); + if (format == NULL) { + dev_dbg(rcdu->dev, "mode_set: unsupported format %08x\n", + crtc->fb->pixel_format); + ret = -EINVAL; + goto error; + } + + ret = rcar_du_plane_reserve(rcrtc->plane, format); + if (ret < 0) + goto error; + + rcrtc->plane->format = format; + rcrtc->plane->pitch = crtc->fb->pitches[0]; + + rcrtc->plane->src_x = x; + rcrtc->plane->src_y = y; + rcrtc->plane->width = mode->hdisplay; + rcrtc->plane->height = mode->vdisplay; + + rcar_du_plane_compute_base(rcrtc->plane, crtc->fb); + + rcrtc->outputs = 0; + + return 0; + +error: + /* There's no rollback/abort operation to clean up in case of error. We + * thus need to release the reference to the DU acquired in prepare() + * here. + */ + rcar_du_put(rcdu); + return ret; +} + +static void rcar_du_crtc_mode_commit(struct drm_crtc *crtc) +{ + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + + /* We're done, restart the CRTC and set the DPMS mode to on. The + * reference to the DU acquired at prepare() time will thus be released + * by the DPMS handler (possibly called by the disable() handler). + */ + rcar_du_crtc_start(rcrtc); + rcrtc->dpms = DRM_MODE_DPMS_ON; +} + +static int rcar_du_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + + rcrtc->plane->src_x = x; + rcrtc->plane->src_y = y; + + rcar_du_crtc_update_base(to_rcar_crtc(crtc)); + + return 0; +} + +static void rcar_du_crtc_disable(struct drm_crtc *crtc) +{ + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + + rcar_du_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + rcar_du_plane_release(rcrtc->plane); +} + +static const struct drm_crtc_helper_funcs crtc_helper_funcs = { + .dpms = rcar_du_crtc_dpms, + .mode_fixup = rcar_du_crtc_mode_fixup, + .prepare = rcar_du_crtc_mode_prepare, + .commit = rcar_du_crtc_mode_commit, + .mode_set = rcar_du_crtc_mode_set, + .mode_set_base = rcar_du_crtc_mode_set_base, + .disable = rcar_du_crtc_disable, +}; + +void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc, + struct drm_file *file) +{ + struct drm_pending_vblank_event *event; + struct drm_device *dev = rcrtc->crtc.dev; + unsigned long flags; + + /* Destroy the pending vertical blanking event associated with the + * pending page flip, if any, and disable vertical blanking interrupts. + */ + spin_lock_irqsave(&dev->event_lock, flags); + event = rcrtc->event; + if (event && event->base.file_priv == file) { + rcrtc->event = NULL; + event->base.destroy(&event->base); + drm_vblank_put(dev, rcrtc->index); + } + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc) +{ + struct drm_pending_vblank_event *event; + struct drm_device *dev = rcrtc->crtc.dev; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + event = rcrtc->event; + rcrtc->event = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + if (event == NULL) + return; + + spin_lock_irqsave(&dev->event_lock, flags); + drm_send_vblank_event(dev, rcrtc->index, event); + spin_unlock_irqrestore(&dev->event_lock, flags); + + drm_vblank_put(dev, rcrtc->index); +} + +static int rcar_du_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event) +{ + struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); + struct drm_device *dev = rcrtc->crtc.dev; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + if (rcrtc->event != NULL) { + spin_unlock_irqrestore(&dev->event_lock, flags); + return -EBUSY; + } + spin_unlock_irqrestore(&dev->event_lock, flags); + + crtc->fb = fb; + rcar_du_crtc_update_base(rcrtc); + + if (event) { + event->pipe = rcrtc->index; + drm_vblank_get(dev, rcrtc->index); + spin_lock_irqsave(&dev->event_lock, flags); + rcrtc->event = event; + spin_unlock_irqrestore(&dev->event_lock, flags); + } + + return 0; +} + +static const struct drm_crtc_funcs crtc_funcs = { + .destroy = drm_crtc_cleanup, + .set_config = drm_crtc_helper_set_config, + .page_flip = rcar_du_crtc_page_flip, +}; + +int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index) +{ + struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index]; + struct drm_crtc *crtc = &rcrtc->crtc; + int ret; + + rcrtc->mmio_offset = index ? DISP2_REG_OFFSET : 0; + rcrtc->index = index; + rcrtc->dpms = DRM_MODE_DPMS_OFF; + rcrtc->plane = &rcdu->planes.planes[index]; + + rcrtc->plane->crtc = crtc; + + ret = drm_crtc_init(rcdu->ddev, crtc, &crtc_funcs); + if (ret < 0) + return ret; + + drm_crtc_helper_add(crtc, &crtc_helper_funcs); + + return 0; +} + +void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable) +{ + if (enable) { + rcar_du_crtc_write(rcrtc, DSRCR, DSRCR_VBCL); + rcar_du_crtc_set(rcrtc, DIER, DIER_VBE); + } else { + rcar_du_crtc_clr(rcrtc, DIER, DIER_VBE); + } +} + +void rcar_du_crtc_irq(struct rcar_du_crtc *rcrtc) +{ + u32 status; + + status = rcar_du_crtc_read(rcrtc, DSSR); + rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); + + if (status & DSSR_VBK) { + drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index); + rcar_du_crtc_finish_page_flip(rcrtc); + } +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h new file mode 100644 index 000000000000..2a0365bcbd14 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -0,0 +1,50 @@ +/* + * rcar_du_crtc.h -- R-Car Display Unit CRTCs + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_CRTC_H__ +#define __RCAR_DU_CRTC_H__ + +#include <linux/mutex.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> + +struct rcar_du_device; +struct rcar_du_plane; + +struct rcar_du_crtc { + struct drm_crtc crtc; + + unsigned int mmio_offset; + unsigned int index; + bool started; + + struct drm_pending_vblank_event *event; + unsigned int outputs; + int dpms; + + struct rcar_du_plane *plane; +}; + +int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index); +void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable); +void rcar_du_crtc_irq(struct rcar_du_crtc *rcrtc); +void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc, + struct drm_file *file); +void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc); +void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc); + +void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output); +void rcar_du_crtc_update_planes(struct drm_crtc *crtc); + +#endif /* __RCAR_DU_CRTC_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c new file mode 100644 index 000000000000..003b34ee38e3 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -0,0 +1,325 @@ +/* + * rcar_du_drv.c -- R-Car Display Unit DRM driver + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/slab.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_cma_helper.h> + +#include "rcar_du_crtc.h" +#include "rcar_du_drv.h" +#include "rcar_du_kms.h" +#include "rcar_du_regs.h" + +/* ----------------------------------------------------------------------------- + * Core device operations + */ + +/* + * rcar_du_get - Acquire a reference to the DU + * + * Acquiring a reference enables the device clock and setup core registers. A + * reference must be held before accessing any hardware registers. + * + * This function must be called with the DRM mode_config lock held. + * + * Return 0 in case of success or a negative error code otherwise. + */ +int rcar_du_get(struct rcar_du_device *rcdu) +{ + int ret; + + if (rcdu->use_count) + goto done; + + /* Enable clocks before accessing the hardware. */ + ret = clk_prepare_enable(rcdu->clock); + if (ret < 0) + return ret; + + /* Enable extended features */ + rcar_du_write(rcdu, DEFR, DEFR_CODE | DEFR_DEFE); + rcar_du_write(rcdu, DEFR2, DEFR2_CODE | DEFR2_DEFE2G); + rcar_du_write(rcdu, DEFR3, DEFR3_CODE | DEFR3_DEFE3); + rcar_du_write(rcdu, DEFR4, DEFR4_CODE); + rcar_du_write(rcdu, DEFR5, DEFR5_CODE | DEFR5_DEFE5); + + /* Use DS1PR and DS2PR to configure planes priorities and connects the + * superposition 0 to DU0 pins. DU1 pins will be configured dynamically. + */ + rcar_du_write(rcdu, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS); + +done: + rcdu->use_count++; + return 0; +} + +/* + * rcar_du_put - Release a reference to the DU + * + * Releasing the last reference disables the device clock. + * + * This function must be called with the DRM mode_config lock held. + */ +void rcar_du_put(struct rcar_du_device *rcdu) +{ + if (--rcdu->use_count) + return; + + clk_disable_unprepare(rcdu->clock); +} + +/* ----------------------------------------------------------------------------- + * DRM operations + */ + +static int rcar_du_unload(struct drm_device *dev) +{ + drm_kms_helper_poll_fini(dev); + drm_mode_config_cleanup(dev); + drm_vblank_cleanup(dev); + drm_irq_uninstall(dev); + + dev->dev_private = NULL; + + return 0; +} + +static int rcar_du_load(struct drm_device *dev, unsigned long flags) +{ + struct platform_device *pdev = dev->platformdev; + struct rcar_du_platform_data *pdata = pdev->dev.platform_data; + struct rcar_du_device *rcdu; + struct resource *ioarea; + struct resource *mem; + int ret; + + if (pdata == NULL) { + dev_err(dev->dev, "no platform data\n"); + return -ENODEV; + } + + rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL); + if (rcdu == NULL) { + dev_err(dev->dev, "failed to allocate private data\n"); + return -ENOMEM; + } + + rcdu->dev = &pdev->dev; + rcdu->pdata = pdata; + rcdu->ddev = dev; + dev->dev_private = rcdu; + + /* I/O resources and clocks */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mem == NULL) { + dev_err(&pdev->dev, "failed to get memory resource\n"); + return -EINVAL; + } + + ioarea = devm_request_mem_region(&pdev->dev, mem->start, + resource_size(mem), pdev->name); + if (ioarea == NULL) { + dev_err(&pdev->dev, "failed to request memory region\n"); + return -EBUSY; + } + + rcdu->mmio = devm_ioremap_nocache(&pdev->dev, ioarea->start, + resource_size(ioarea)); + if (rcdu->mmio == NULL) { + dev_err(&pdev->dev, "failed to remap memory resource\n"); + return -ENOMEM; + } + + rcdu->clock = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(rcdu->clock)) { + dev_err(&pdev->dev, "failed to get clock\n"); + return -ENOENT; + } + + /* DRM/KMS objects */ + ret = rcar_du_modeset_init(rcdu); + if (ret < 0) { + dev_err(&pdev->dev, "failed to initialize DRM/KMS\n"); + goto done; + } + + /* IRQ and vblank handling */ + ret = drm_vblank_init(dev, (1 << rcdu->num_crtcs) - 1); + if (ret < 0) { + dev_err(&pdev->dev, "failed to initialize vblank\n"); + goto done; + } + + ret = drm_irq_install(dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to install IRQ handler\n"); + goto done; + } + + platform_set_drvdata(pdev, rcdu); + +done: + if (ret) + rcar_du_unload(dev); + + return ret; +} + +static void rcar_du_preclose(struct drm_device *dev, struct drm_file *file) +{ + struct rcar_du_device *rcdu = dev->dev_private; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i) + rcar_du_crtc_cancel_page_flip(&rcdu->crtcs[i], file); +} + +static irqreturn_t rcar_du_irq(int irq, void *arg) +{ + struct drm_device *dev = arg; + struct rcar_du_device *rcdu = dev->dev_private; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i) + rcar_du_crtc_irq(&rcdu->crtcs[i]); + + return IRQ_HANDLED; +} + +static int rcar_du_enable_vblank(struct drm_device *dev, int crtc) +{ + struct rcar_du_device *rcdu = dev->dev_private; + + rcar_du_crtc_enable_vblank(&rcdu->crtcs[crtc], true); + + return 0; +} + +static void rcar_du_disable_vblank(struct drm_device *dev, int crtc) +{ + struct rcar_du_device *rcdu = dev->dev_private; + + rcar_du_crtc_enable_vblank(&rcdu->crtcs[crtc], false); +} + +static const struct file_operations rcar_du_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .poll = drm_poll, + .read = drm_read, + .fasync = drm_fasync, + .llseek = no_llseek, + .mmap = drm_gem_cma_mmap, +}; + +static struct drm_driver rcar_du_driver = { + .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET + | DRIVER_PRIME, + .load = rcar_du_load, + .unload = rcar_du_unload, + .preclose = rcar_du_preclose, + .irq_handler = rcar_du_irq, + .get_vblank_counter = drm_vblank_count, + .enable_vblank = rcar_du_enable_vblank, + .disable_vblank = rcar_du_disable_vblank, + .gem_free_object = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_cma_dmabuf_import, + .gem_prime_export = drm_gem_cma_dmabuf_export, + .dumb_create = drm_gem_cma_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_cma_dumb_destroy, + .fops = &rcar_du_fops, + .name = "rcar-du", + .desc = "Renesas R-Car Display Unit", + .date = "20130110", + .major = 1, + .minor = 0, +}; + +/* ----------------------------------------------------------------------------- + * Power management + */ + +#if CONFIG_PM_SLEEP +static int rcar_du_pm_suspend(struct device *dev) +{ + struct rcar_du_device *rcdu = dev_get_drvdata(dev); + + drm_kms_helper_poll_disable(rcdu->ddev); + /* TODO Suspend the CRTC */ + + return 0; +} + +static int rcar_du_pm_resume(struct device *dev) +{ + struct rcar_du_device *rcdu = dev_get_drvdata(dev); + + /* TODO Resume the CRTC */ + + drm_kms_helper_poll_enable(rcdu->ddev); + return 0; +} +#endif + +static const struct dev_pm_ops rcar_du_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume) +}; + +/* ----------------------------------------------------------------------------- + * Platform driver + */ + +static int rcar_du_probe(struct platform_device *pdev) +{ + return drm_platform_init(&rcar_du_driver, pdev); +} + +static int rcar_du_remove(struct platform_device *pdev) +{ + drm_platform_exit(&rcar_du_driver, pdev); + + return 0; +} + +static struct platform_driver rcar_du_platform_driver = { + .probe = rcar_du_probe, + .remove = rcar_du_remove, + .driver = { + .owner = THIS_MODULE, + .name = "rcar-du", + .pm = &rcar_du_pm_ops, + }, +}; + +module_platform_driver(rcar_du_platform_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h new file mode 100644 index 000000000000..193cc59d495c --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -0,0 +1,66 @@ +/* + * rcar_du_drv.h -- R-Car Display Unit DRM driver + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_DRV_H__ +#define __RCAR_DU_DRV_H__ + +#include <linux/kernel.h> +#include <linux/mutex.h> +#include <linux/platform_data/rcar-du.h> + +#include "rcar_du_crtc.h" +#include "rcar_du_plane.h" + +struct clk; +struct device; +struct drm_device; + +struct rcar_du_device { + struct device *dev; + const struct rcar_du_platform_data *pdata; + + void __iomem *mmio; + struct clk *clock; + unsigned int use_count; + + struct drm_device *ddev; + + struct rcar_du_crtc crtcs[2]; + unsigned int used_crtcs; + unsigned int num_crtcs; + + struct { + struct rcar_du_plane planes[RCAR_DU_NUM_SW_PLANES]; + unsigned int free; + struct mutex lock; + + struct drm_property *alpha; + struct drm_property *colorkey; + struct drm_property *zpos; + } planes; +}; + +int rcar_du_get(struct rcar_du_device *rcdu); +void rcar_du_put(struct rcar_du_device *rcdu); + +static inline u32 rcar_du_read(struct rcar_du_device *rcdu, u32 reg) +{ + return ioread32(rcdu->mmio + reg); +} + +static inline void rcar_du_write(struct rcar_du_device *rcdu, u32 reg, u32 data) +{ + iowrite32(data, rcdu->mmio + reg); +} + +#endif /* __RCAR_DU_DRV_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c new file mode 100644 index 000000000000..9c63f39658de --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -0,0 +1,245 @@ +/* + * rcar_du_kms.c -- R-Car Display Unit Mode Setting + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> + +#include "rcar_du_crtc.h" +#include "rcar_du_drv.h" +#include "rcar_du_kms.h" +#include "rcar_du_lvds.h" +#include "rcar_du_regs.h" +#include "rcar_du_vga.h" + +/* ----------------------------------------------------------------------------- + * Format helpers + */ + +static const struct rcar_du_format_info rcar_du_format_infos[] = { + { + .fourcc = DRM_FORMAT_RGB565, + .bpp = 16, + .planes = 1, + .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP, + .edf = PnDDCR4_EDF_NONE, + }, { + .fourcc = DRM_FORMAT_ARGB1555, + .bpp = 16, + .planes = 1, + .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB, + .edf = PnDDCR4_EDF_NONE, + }, { + .fourcc = DRM_FORMAT_XRGB1555, + .bpp = 16, + .planes = 1, + .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB, + .edf = PnDDCR4_EDF_NONE, + }, { + .fourcc = DRM_FORMAT_XRGB8888, + .bpp = 32, + .planes = 1, + .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP, + .edf = PnDDCR4_EDF_RGB888, + }, { + .fourcc = DRM_FORMAT_ARGB8888, + .bpp = 32, + .planes = 1, + .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP, + .edf = PnDDCR4_EDF_ARGB8888, + }, { + .fourcc = DRM_FORMAT_UYVY, + .bpp = 16, + .planes = 1, + .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, + .edf = PnDDCR4_EDF_NONE, + }, { + .fourcc = DRM_FORMAT_YUYV, + .bpp = 16, + .planes = 1, + .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, + .edf = PnDDCR4_EDF_NONE, + }, { + .fourcc = DRM_FORMAT_NV12, + .bpp = 12, + .planes = 2, + .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, + .edf = PnDDCR4_EDF_NONE, + }, { + .fourcc = DRM_FORMAT_NV21, + .bpp = 12, + .planes = 2, + .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, + .edf = PnDDCR4_EDF_NONE, + }, { + /* In YUV 4:2:2, only NV16 is supported (NV61 isn't) */ + .fourcc = DRM_FORMAT_NV16, + .bpp = 16, + .planes = 2, + .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, + .edf = PnDDCR4_EDF_NONE, + }, +}; + +const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rcar_du_format_infos); ++i) { + if (rcar_du_format_infos[i].fourcc == fourcc) + return &rcar_du_format_infos[i]; + } + + return NULL; +} + +/* ----------------------------------------------------------------------------- + * Common connector and encoder functions + */ + +struct drm_encoder * +rcar_du_connector_best_encoder(struct drm_connector *connector) +{ + struct rcar_du_connector *rcon = to_rcar_connector(connector); + + return &rcon->encoder->encoder; +} + +void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder) +{ +} + +void rcar_du_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct rcar_du_encoder *renc = to_rcar_encoder(encoder); + + rcar_du_crtc_route_output(encoder->crtc, renc->output); +} + +void rcar_du_encoder_mode_commit(struct drm_encoder *encoder) +{ +} + +/* ----------------------------------------------------------------------------- + * Frame buffer + */ + +static struct drm_framebuffer * +rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + const struct rcar_du_format_info *format; + + format = rcar_du_format_info(mode_cmd->pixel_format); + if (format == NULL) { + dev_dbg(dev->dev, "unsupported pixel format %08x\n", + mode_cmd->pixel_format); + return ERR_PTR(-EINVAL); + } + + if (mode_cmd->pitches[0] & 15 || mode_cmd->pitches[0] >= 8192) { + dev_dbg(dev->dev, "invalid pitch value %u\n", + mode_cmd->pitches[0]); + return ERR_PTR(-EINVAL); + } + + if (format->planes == 2) { + if (mode_cmd->pitches[1] != mode_cmd->pitches[0]) { + dev_dbg(dev->dev, + "luma and chroma pitches do not match\n"); + return ERR_PTR(-EINVAL); + } + } + + return drm_fb_cma_create(dev, file_priv, mode_cmd); +} + +static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { + .fb_create = rcar_du_fb_create, +}; + +int rcar_du_modeset_init(struct rcar_du_device *rcdu) +{ + struct drm_device *dev = rcdu->ddev; + struct drm_encoder *encoder; + unsigned int i; + int ret; + + drm_mode_config_init(rcdu->ddev); + + rcdu->ddev->mode_config.min_width = 0; + rcdu->ddev->mode_config.min_height = 0; + rcdu->ddev->mode_config.max_width = 4095; + rcdu->ddev->mode_config.max_height = 2047; + rcdu->ddev->mode_config.funcs = &rcar_du_mode_config_funcs; + + ret = rcar_du_plane_init(rcdu); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i) + rcar_du_crtc_create(rcdu, i); + + rcdu->used_crtcs = 0; + rcdu->num_crtcs = i; + + for (i = 0; i < rcdu->pdata->num_encoders; ++i) { + const struct rcar_du_encoder_data *pdata = + &rcdu->pdata->encoders[i]; + + if (pdata->output >= ARRAY_SIZE(rcdu->crtcs)) { + dev_warn(rcdu->dev, + "encoder %u references unexisting output %u, skipping\n", + i, pdata->output); + continue; + } + + switch (pdata->encoder) { + case RCAR_DU_ENCODER_VGA: + rcar_du_vga_init(rcdu, &pdata->u.vga, pdata->output); + break; + + case RCAR_DU_ENCODER_LVDS: + rcar_du_lvds_init(rcdu, &pdata->u.lvds, pdata->output); + break; + + default: + break; + } + } + + /* Set the possible CRTCs and possible clones. All encoders can be + * driven by the CRTC associated with the output they're connected to, + * as well as by CRTC 0. + */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct rcar_du_encoder *renc = to_rcar_encoder(encoder); + + encoder->possible_crtcs = (1 << 0) | (1 << renc->output); + encoder->possible_clones = 1 << 0; + } + + ret = rcar_du_plane_register(rcdu); + if (ret < 0) + return ret; + + drm_kms_helper_poll_init(rcdu->ddev); + + drm_helper_disable_unused_functions(rcdu->ddev); + + return 0; +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.h b/drivers/gpu/drm/rcar-du/rcar_du_kms.h new file mode 100644 index 000000000000..e4d8db069a06 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.h @@ -0,0 +1,59 @@ +/* + * rcar_du_kms.h -- R-Car Display Unit Mode Setting + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_KMS_H__ +#define __RCAR_DU_KMS_H__ + +#include <linux/types.h> + +#include <drm/drm_crtc.h> + +struct rcar_du_device; + +struct rcar_du_format_info { + u32 fourcc; + unsigned int bpp; + unsigned int planes; + unsigned int pnmr; + unsigned int edf; +}; + +struct rcar_du_encoder { + struct drm_encoder encoder; + unsigned int output; +}; + +#define to_rcar_encoder(e) \ + container_of(e, struct rcar_du_encoder, encoder) + +struct rcar_du_connector { + struct drm_connector connector; + struct rcar_du_encoder *encoder; +}; + +#define to_rcar_connector(c) \ + container_of(c, struct rcar_du_connector, connector) + +const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc); + +struct drm_encoder * +rcar_du_connector_best_encoder(struct drm_connector *connector); +void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder); +void rcar_du_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +void rcar_du_encoder_mode_commit(struct drm_encoder *encoder); + +int rcar_du_modeset_init(struct rcar_du_device *rcdu); + +#endif /* __RCAR_DU_KMS_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvds.c b/drivers/gpu/drm/rcar-du/rcar_du_lvds.c new file mode 100644 index 000000000000..7aefe7267e1d --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvds.c @@ -0,0 +1,216 @@ +/* + * rcar_du_lvds.c -- R-Car Display Unit LVDS Encoder and Connector + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> + +#include "rcar_du_drv.h" +#include "rcar_du_kms.h" +#include "rcar_du_lvds.h" + +struct rcar_du_lvds_connector { + struct rcar_du_connector connector; + + const struct rcar_du_panel_data *panel; +}; + +#define to_rcar_lvds_connector(c) \ + container_of(c, struct rcar_du_lvds_connector, connector.connector) + +/* ----------------------------------------------------------------------------- + * Connector + */ + +static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector) +{ + struct rcar_du_lvds_connector *lvdscon = to_rcar_lvds_connector(connector); + struct drm_display_mode *mode; + + mode = drm_mode_create(connector->dev); + if (mode == NULL) + return 0; + + mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; + mode->clock = lvdscon->panel->mode.clock; + mode->hdisplay = lvdscon->panel->mode.hdisplay; + mode->hsync_start = lvdscon->panel->mode.hsync_start; + mode->hsync_end = lvdscon->panel->mode.hsync_end; + mode->htotal = lvdscon->panel->mode.htotal; + mode->vdisplay = lvdscon->panel->mode.vdisplay; + mode->vsync_start = lvdscon->panel->mode.vsync_start; + mode->vsync_end = lvdscon->panel->mode.vsync_end; + mode->vtotal = lvdscon->panel->mode.vtotal; + mode->flags = lvdscon->panel->mode.flags; + + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + return 1; +} + +static int rcar_du_lvds_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static const struct drm_connector_helper_funcs connector_helper_funcs = { + .get_modes = rcar_du_lvds_connector_get_modes, + .mode_valid = rcar_du_lvds_connector_mode_valid, + .best_encoder = rcar_du_connector_best_encoder, +}; + +static void rcar_du_lvds_connector_destroy(struct drm_connector *connector) +{ + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); +} + +static enum drm_connector_status +rcar_du_lvds_connector_detect(struct drm_connector *connector, bool force) +{ + return connector_status_connected; +} + +static const struct drm_connector_funcs connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = rcar_du_lvds_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = rcar_du_lvds_connector_destroy, +}; + +static int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc, + const struct rcar_du_panel_data *panel) +{ + struct rcar_du_lvds_connector *lvdscon; + struct drm_connector *connector; + int ret; + + lvdscon = devm_kzalloc(rcdu->dev, sizeof(*lvdscon), GFP_KERNEL); + if (lvdscon == NULL) + return -ENOMEM; + + lvdscon->panel = panel; + + connector = &lvdscon->connector.connector; + connector->display_info.width_mm = panel->width_mm; + connector->display_info.height_mm = panel->height_mm; + + ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, + DRM_MODE_CONNECTOR_LVDS); + if (ret < 0) + return ret; + + drm_connector_helper_add(connector, &connector_helper_funcs); + ret = drm_sysfs_connector_add(connector); + if (ret < 0) + return ret; + + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_object_property_set_value(&connector->base, + rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); + + ret = drm_mode_connector_attach_encoder(connector, &renc->encoder); + if (ret < 0) + return ret; + + connector->encoder = &renc->encoder; + lvdscon->connector.encoder = renc; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Encoder + */ + +static void rcar_du_lvds_encoder_dpms(struct drm_encoder *encoder, int mode) +{ +} + +static bool rcar_du_lvds_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + const struct drm_display_mode *panel_mode; + struct drm_device *dev = encoder->dev; + struct drm_connector *connector; + bool found = false; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder == encoder) { + found = true; + break; + } + } + + if (!found) { + dev_dbg(dev->dev, "mode_fixup: no connector found\n"); + return false; + } + + if (list_empty(&connector->modes)) { + dev_dbg(dev->dev, "mode_fixup: empty modes list\n"); + return false; + } + + panel_mode = list_first_entry(&connector->modes, + struct drm_display_mode, head); + + /* We're not allowed to modify the resolution. */ + if (mode->hdisplay != panel_mode->hdisplay || + mode->vdisplay != panel_mode->vdisplay) + return false; + + /* The flat panel mode is fixed, just copy it to the adjusted mode. */ + drm_mode_copy(adjusted_mode, panel_mode); + + return true; +} + +static const struct drm_encoder_helper_funcs encoder_helper_funcs = { + .dpms = rcar_du_lvds_encoder_dpms, + .mode_fixup = rcar_du_lvds_encoder_mode_fixup, + .prepare = rcar_du_encoder_mode_prepare, + .commit = rcar_du_encoder_mode_commit, + .mode_set = rcar_du_encoder_mode_set, +}; + +static const struct drm_encoder_funcs encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +int rcar_du_lvds_init(struct rcar_du_device *rcdu, + const struct rcar_du_encoder_lvds_data *data, + unsigned int output) +{ + struct rcar_du_encoder *renc; + int ret; + + renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL); + if (renc == NULL) + return -ENOMEM; + + renc->output = output; + + ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs, + DRM_MODE_ENCODER_LVDS); + if (ret < 0) + return ret; + + drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs); + + return rcar_du_lvds_connector_init(rcdu, renc, &data->panel); +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvds.h b/drivers/gpu/drm/rcar-du/rcar_du_lvds.h new file mode 100644 index 000000000000..b47f8328e103 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvds.h @@ -0,0 +1,24 @@ +/* + * rcar_du_lvds.h -- R-Car Display Unit LVDS Encoder and Connector + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_LVDS_H__ +#define __RCAR_DU_LVDS_H__ + +struct rcar_du_device; +struct rcar_du_encoder_lvds_data; + +int rcar_du_lvds_init(struct rcar_du_device *rcdu, + const struct rcar_du_encoder_lvds_data *data, + unsigned int output); + +#endif /* __RCAR_DU_LVDS_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c new file mode 100644 index 000000000000..a65f81ddf51d --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -0,0 +1,507 @@ +/* + * rcar_du_plane.c -- R-Car Display Unit Planes + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_gem_cma_helper.h> + +#include "rcar_du_drv.h" +#include "rcar_du_kms.h" +#include "rcar_du_plane.h" +#include "rcar_du_regs.h" + +#define RCAR_DU_COLORKEY_NONE (0 << 24) +#define RCAR_DU_COLORKEY_SOURCE (1 << 24) +#define RCAR_DU_COLORKEY_MASK (1 << 24) + +struct rcar_du_kms_plane { + struct drm_plane plane; + struct rcar_du_plane *hwplane; +}; + +static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane) +{ + return container_of(plane, struct rcar_du_kms_plane, plane)->hwplane; +} + +static u32 rcar_du_plane_read(struct rcar_du_device *rcdu, + unsigned int index, u32 reg) +{ + return rcar_du_read(rcdu, index * PLANE_OFF + reg); +} + +static void rcar_du_plane_write(struct rcar_du_device *rcdu, + unsigned int index, u32 reg, u32 data) +{ + rcar_du_write(rcdu, index * PLANE_OFF + reg, data); +} + +int rcar_du_plane_reserve(struct rcar_du_plane *plane, + const struct rcar_du_format_info *format) +{ + struct rcar_du_device *rcdu = plane->dev; + unsigned int i; + int ret = -EBUSY; + + mutex_lock(&rcdu->planes.lock); + + for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) { + if (!(rcdu->planes.free & (1 << i))) + continue; + + if (format->planes == 1 || + rcdu->planes.free & (1 << ((i + 1) % 8))) + break; + } + + if (i == ARRAY_SIZE(rcdu->planes.planes)) + goto done; + + rcdu->planes.free &= ~(1 << i); + if (format->planes == 2) + rcdu->planes.free &= ~(1 << ((i + 1) % 8)); + + plane->hwindex = i; + + ret = 0; + +done: + mutex_unlock(&rcdu->planes.lock); + return ret; +} + +void rcar_du_plane_release(struct rcar_du_plane *plane) +{ + struct rcar_du_device *rcdu = plane->dev; + + if (plane->hwindex == -1) + return; + + mutex_lock(&rcdu->planes.lock); + rcdu->planes.free |= 1 << plane->hwindex; + if (plane->format->planes == 2) + rcdu->planes.free |= 1 << ((plane->hwindex + 1) % 8); + mutex_unlock(&rcdu->planes.lock); + + plane->hwindex = -1; +} + +void rcar_du_plane_update_base(struct rcar_du_plane *plane) +{ + struct rcar_du_device *rcdu = plane->dev; + unsigned int index = plane->hwindex; + + /* According to the datasheet the Y position is expressed in raster line + * units. However, 32bpp formats seem to require a doubled Y position + * value. Similarly, for the second plane, NV12 and NV21 formats seem to + * require a halved Y position value. + */ + rcar_du_plane_write(rcdu, index, PnSPXR, plane->src_x); + rcar_du_plane_write(rcdu, index, PnSPYR, plane->src_y * + (plane->format->bpp == 32 ? 2 : 1)); + rcar_du_plane_write(rcdu, index, PnDSA0R, plane->dma[0]); + + if (plane->format->planes == 2) { + index = (index + 1) % 8; + + rcar_du_plane_write(rcdu, index, PnSPXR, plane->src_x); + rcar_du_plane_write(rcdu, index, PnSPYR, plane->src_y * + (plane->format->bpp == 16 ? 2 : 1) / 2); + rcar_du_plane_write(rcdu, index, PnDSA0R, plane->dma[1]); + } +} + +void rcar_du_plane_compute_base(struct rcar_du_plane *plane, + struct drm_framebuffer *fb) +{ + struct drm_gem_cma_object *gem; + + gem = drm_fb_cma_get_gem_obj(fb, 0); + plane->dma[0] = gem->paddr + fb->offsets[0]; + + if (plane->format->planes == 2) { + gem = drm_fb_cma_get_gem_obj(fb, 1); + plane->dma[1] = gem->paddr + fb->offsets[1]; + } +} + +static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane, + unsigned int index) +{ + struct rcar_du_device *rcdu = plane->dev; + u32 colorkey; + u32 pnmr; + + /* The PnALPHAR register controls alpha-blending in 16bpp formats + * (ARGB1555 and XRGB1555). + * + * For ARGB, set the alpha value to 0, and enable alpha-blending when + * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255. + * + * For XRGB, set the alpha value to the plane-wide alpha value and + * enable alpha-blending regardless of the X bit value. + */ + if (plane->format->fourcc != DRM_FORMAT_XRGB1555) + rcar_du_plane_write(rcdu, index, PnALPHAR, PnALPHAR_ABIT_0); + else + rcar_du_plane_write(rcdu, index, PnALPHAR, + PnALPHAR_ABIT_X | plane->alpha); + + pnmr = PnMR_BM_MD | plane->format->pnmr; + + /* Disable color keying when requested. YUV formats have the + * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying + * automatically. + */ + if ((plane->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE) + pnmr |= PnMR_SPIM_TP_OFF; + + /* For packed YUV formats we need to select the U/V order. */ + if (plane->format->fourcc == DRM_FORMAT_YUYV) + pnmr |= PnMR_YCDF_YUYV; + + rcar_du_plane_write(rcdu, index, PnMR, pnmr); + + switch (plane->format->fourcc) { + case DRM_FORMAT_RGB565: + colorkey = ((plane->colorkey & 0xf80000) >> 8) + | ((plane->colorkey & 0x00fc00) >> 5) + | ((plane->colorkey & 0x0000f8) >> 3); + rcar_du_plane_write(rcdu, index, PnTC2R, colorkey); + break; + + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_XRGB1555: + colorkey = ((plane->colorkey & 0xf80000) >> 9) + | ((plane->colorkey & 0x00f800) >> 6) + | ((plane->colorkey & 0x0000f8) >> 3); + rcar_du_plane_write(rcdu, index, PnTC2R, colorkey); + break; + + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + rcar_du_plane_write(rcdu, index, PnTC3R, + PnTC3R_CODE | (plane->colorkey & 0xffffff)); + break; + } +} + +static void __rcar_du_plane_setup(struct rcar_du_plane *plane, + unsigned int index) +{ + struct rcar_du_device *rcdu = plane->dev; + u32 ddcr2 = PnDDCR2_CODE; + u32 ddcr4; + u32 mwr; + + /* Data format + * + * The data format is selected by the DDDF field in PnMR and the EDF + * field in DDCR4. + */ + ddcr4 = rcar_du_plane_read(rcdu, index, PnDDCR4); + ddcr4 &= ~PnDDCR4_EDF_MASK; + ddcr4 |= plane->format->edf | PnDDCR4_CODE; + + rcar_du_plane_setup_mode(plane, index); + + if (plane->format->planes == 2) { + if (plane->hwindex != index) { + if (plane->format->fourcc == DRM_FORMAT_NV12 || + plane->format->fourcc == DRM_FORMAT_NV21) + ddcr2 |= PnDDCR2_Y420; + + if (plane->format->fourcc == DRM_FORMAT_NV21) + ddcr2 |= PnDDCR2_NV21; + + ddcr2 |= PnDDCR2_DIVU; + } else { + ddcr2 |= PnDDCR2_DIVY; + } + } + + rcar_du_plane_write(rcdu, index, PnDDCR2, ddcr2); + rcar_du_plane_write(rcdu, index, PnDDCR4, ddcr4); + + /* Memory pitch (expressed in pixels) */ + if (plane->format->planes == 2) + mwr = plane->pitch; + else + mwr = plane->pitch * 8 / plane->format->bpp; + + rcar_du_plane_write(rcdu, index, PnMWR, mwr); + + /* Destination position and size */ + rcar_du_plane_write(rcdu, index, PnDSXR, plane->width); + rcar_du_plane_write(rcdu, index, PnDSYR, plane->height); + rcar_du_plane_write(rcdu, index, PnDPXR, plane->dst_x); + rcar_du_plane_write(rcdu, index, PnDPYR, plane->dst_y); + + /* Wrap-around and blinking, disabled */ + rcar_du_plane_write(rcdu, index, PnWASPR, 0); + rcar_du_plane_write(rcdu, index, PnWAMWR, 4095); + rcar_du_plane_write(rcdu, index, PnBTR, 0); + rcar_du_plane_write(rcdu, index, PnMLR, 0); +} + +void rcar_du_plane_setup(struct rcar_du_plane *plane) +{ + __rcar_du_plane_setup(plane, plane->hwindex); + if (plane->format->planes == 2) + __rcar_du_plane_setup(plane, (plane->hwindex + 1) % 8); + + rcar_du_plane_update_base(plane); +} + +static int +rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + struct rcar_du_plane *rplane = to_rcar_plane(plane); + struct rcar_du_device *rcdu = plane->dev->dev_private; + const struct rcar_du_format_info *format; + unsigned int nplanes; + int ret; + + format = rcar_du_format_info(fb->pixel_format); + if (format == NULL) { + dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__, + fb->pixel_format); + return -EINVAL; + } + + if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) { + dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__); + return -EINVAL; + } + + nplanes = rplane->format ? rplane->format->planes : 0; + + /* Reallocate hardware planes if the number of required planes has + * changed. + */ + if (format->planes != nplanes) { + rcar_du_plane_release(rplane); + ret = rcar_du_plane_reserve(rplane, format); + if (ret < 0) + return ret; + } + + rplane->crtc = crtc; + rplane->format = format; + rplane->pitch = fb->pitches[0]; + + rplane->src_x = src_x >> 16; + rplane->src_y = src_y >> 16; + rplane->dst_x = crtc_x; + rplane->dst_y = crtc_y; + rplane->width = crtc_w; + rplane->height = crtc_h; + + rcar_du_plane_compute_base(rplane, fb); + rcar_du_plane_setup(rplane); + + mutex_lock(&rcdu->planes.lock); + rplane->enabled = true; + rcar_du_crtc_update_planes(rplane->crtc); + mutex_unlock(&rcdu->planes.lock); + + return 0; +} + +static int rcar_du_plane_disable(struct drm_plane *plane) +{ + struct rcar_du_device *rcdu = plane->dev->dev_private; + struct rcar_du_plane *rplane = to_rcar_plane(plane); + + if (!rplane->enabled) + return 0; + + mutex_lock(&rcdu->planes.lock); + rplane->enabled = false; + rcar_du_crtc_update_planes(rplane->crtc); + mutex_unlock(&rcdu->planes.lock); + + rcar_du_plane_release(rplane); + + rplane->crtc = NULL; + rplane->format = NULL; + + return 0; +} + +/* Both the .set_property and the .update_plane operations are called with the + * mode_config lock held. There is this no need to explicitly protect access to + * the alpha and colorkey fields and the mode register. + */ +static void rcar_du_plane_set_alpha(struct rcar_du_plane *plane, u32 alpha) +{ + if (plane->alpha == alpha) + return; + + plane->alpha = alpha; + if (!plane->enabled || plane->format->fourcc != DRM_FORMAT_XRGB1555) + return; + + rcar_du_plane_setup_mode(plane, plane->hwindex); +} + +static void rcar_du_plane_set_colorkey(struct rcar_du_plane *plane, + u32 colorkey) +{ + if (plane->colorkey == colorkey) + return; + + plane->colorkey = colorkey; + if (!plane->enabled) + return; + + rcar_du_plane_setup_mode(plane, plane->hwindex); +} + +static void rcar_du_plane_set_zpos(struct rcar_du_plane *plane, + unsigned int zpos) +{ + struct rcar_du_device *rcdu = plane->dev; + + mutex_lock(&rcdu->planes.lock); + if (plane->zpos == zpos) + goto done; + + plane->zpos = zpos; + if (!plane->enabled) + goto done; + + rcar_du_crtc_update_planes(plane->crtc); + +done: + mutex_unlock(&rcdu->planes.lock); +} + +static int rcar_du_plane_set_property(struct drm_plane *plane, + struct drm_property *property, + uint64_t value) +{ + struct rcar_du_device *rcdu = plane->dev->dev_private; + struct rcar_du_plane *rplane = to_rcar_plane(plane); + + if (property == rcdu->planes.alpha) + rcar_du_plane_set_alpha(rplane, value); + else if (property == rcdu->planes.colorkey) + rcar_du_plane_set_colorkey(rplane, value); + else if (property == rcdu->planes.zpos) + rcar_du_plane_set_zpos(rplane, value); + else + return -EINVAL; + + return 0; +} + +static const struct drm_plane_funcs rcar_du_plane_funcs = { + .update_plane = rcar_du_plane_update, + .disable_plane = rcar_du_plane_disable, + .set_property = rcar_du_plane_set_property, + .destroy = drm_plane_cleanup, +}; + +static const uint32_t formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_UYVY, + DRM_FORMAT_YUYV, + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, + DRM_FORMAT_NV16, +}; + +int rcar_du_plane_init(struct rcar_du_device *rcdu) +{ + unsigned int i; + + mutex_init(&rcdu->planes.lock); + rcdu->planes.free = 0xff; + + rcdu->planes.alpha = + drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255); + if (rcdu->planes.alpha == NULL) + return -ENOMEM; + + /* The color key is expressed as an RGB888 triplet stored in a 32-bit + * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0) + * or enable source color keying (1). + */ + rcdu->planes.colorkey = + drm_property_create_range(rcdu->ddev, 0, "colorkey", + 0, 0x01ffffff); + if (rcdu->planes.colorkey == NULL) + return -ENOMEM; + + rcdu->planes.zpos = + drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7); + if (rcdu->planes.zpos == NULL) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) { + struct rcar_du_plane *plane = &rcdu->planes.planes[i]; + + plane->dev = rcdu; + plane->hwindex = -1; + plane->alpha = 255; + plane->colorkey = RCAR_DU_COLORKEY_NONE; + plane->zpos = 0; + } + + return 0; +} + +int rcar_du_plane_register(struct rcar_du_device *rcdu) +{ + unsigned int i; + int ret; + + for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) { + struct rcar_du_kms_plane *plane; + + plane = devm_kzalloc(rcdu->dev, sizeof(*plane), GFP_KERNEL); + if (plane == NULL) + return -ENOMEM; + + plane->hwplane = &rcdu->planes.planes[i + 2]; + plane->hwplane->zpos = 1; + + ret = drm_plane_init(rcdu->ddev, &plane->plane, + (1 << rcdu->num_crtcs) - 1, + &rcar_du_plane_funcs, formats, + ARRAY_SIZE(formats), false); + if (ret < 0) + return ret; + + drm_object_attach_property(&plane->plane.base, + rcdu->planes.alpha, 255); + drm_object_attach_property(&plane->plane.base, + rcdu->planes.colorkey, + RCAR_DU_COLORKEY_NONE); + drm_object_attach_property(&plane->plane.base, + rcdu->planes.zpos, 1); + } + + return 0; +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h new file mode 100644 index 000000000000..5397dba2fe57 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h @@ -0,0 +1,67 @@ +/* + * rcar_du_plane.h -- R-Car Display Unit Planes + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_PLANE_H__ +#define __RCAR_DU_PLANE_H__ + +struct drm_crtc; +struct drm_framebuffer; +struct rcar_du_device; +struct rcar_du_format_info; + +/* The RCAR DU has 8 hardware planes, shared between KMS planes and CRTCs. As + * using KMS planes requires at least one of the CRTCs being enabled, no more + * than 7 KMS planes can be available. We thus create 7 KMS planes and + * 9 software planes (one for each KMS planes and one for each CRTC). + */ + +#define RCAR_DU_NUM_KMS_PLANES 7 +#define RCAR_DU_NUM_HW_PLANES 8 +#define RCAR_DU_NUM_SW_PLANES 9 + +struct rcar_du_plane { + struct rcar_du_device *dev; + struct drm_crtc *crtc; + + bool enabled; + + int hwindex; /* 0-based, -1 means unused */ + unsigned int alpha; + unsigned int colorkey; + unsigned int zpos; + + const struct rcar_du_format_info *format; + + unsigned long dma[2]; + unsigned int pitch; + + unsigned int width; + unsigned int height; + + unsigned int src_x; + unsigned int src_y; + unsigned int dst_x; + unsigned int dst_y; +}; + +int rcar_du_plane_init(struct rcar_du_device *rcdu); +int rcar_du_plane_register(struct rcar_du_device *rcdu); +void rcar_du_plane_setup(struct rcar_du_plane *plane); +void rcar_du_plane_update_base(struct rcar_du_plane *plane); +void rcar_du_plane_compute_base(struct rcar_du_plane *plane, + struct drm_framebuffer *fb); +int rcar_du_plane_reserve(struct rcar_du_plane *plane, + const struct rcar_du_format_info *format); +void rcar_du_plane_release(struct rcar_du_plane *plane); + +#endif /* __RCAR_DU_PLANE_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h new file mode 100644 index 000000000000..69f21f19b51c --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h @@ -0,0 +1,445 @@ +/* + * rcar_du_regs.h -- R-Car Display Unit Registers Definitions + * + * Copyright (C) 2013 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * 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. + */ + +#ifndef __RCAR_DU_REGS_H__ +#define __RCAR_DU_REGS_H__ + +#define DISP2_REG_OFFSET 0x30000 + +/* ----------------------------------------------------------------------------- + * Display Control Registers + */ + +#define DSYSR 0x00000 /* display 1 */ +#define D2SYSR 0x30000 /* display 2 */ +#define DSYSR_ILTS (1 << 29) +#define DSYSR_DSEC (1 << 20) +#define DSYSR_IUPD (1 << 16) +#define DSYSR_DRES (1 << 9) +#define DSYSR_DEN (1 << 8) +#define DSYSR_TVM_MASTER (0 << 6) +#define DSYSR_TVM_SWITCH (1 << 6) +#define DSYSR_TVM_TVSYNC (2 << 6) +#define DSYSR_TVM_MASK (3 << 6) +#define DSYSR_SCM_INT_NONE (0 << 4) +#define DSYSR_SCM_INT_SYNC (2 << 4) +#define DSYSR_SCM_INT_VIDEO (3 << 4) + +#define DSMR 0x00004 +#define D2SMR 0x30004 +#define DSMR_VSPM (1 << 28) +#define DSMR_ODPM (1 << 27) +#define DSMR_DIPM_DISP (0 << 25) +#define DSMR_DIPM_CSYNC (1 << 25) +#define DSMR_DIPM_DE (3 << 25) +#define DSMR_DIPM_MASK (3 << 25) +#define DSMR_CSPM (1 << 24) +#define DSMR_DIL (1 << 19) +#define DSMR_VSL (1 << 18) +#define DSMR_HSL (1 << 17) +#define DSMR_DDIS (1 << 16) +#define DSMR_CDEL (1 << 15) +#define DSMR_CDEM_CDE (0 << 13) +#define DSMR_CDEM_LOW (2 << 13) +#define DSMR_CDEM_HIGH (3 << 13) +#define DSMR_CDEM_MASK (3 << 13) +#define DSMR_CDED (1 << 12) +#define DSMR_ODEV (1 << 8) +#define DSMR_CSY_VH_OR (0 << 6) +#define DSMR_CSY_333 (2 << 6) +#define DSMR_CSY_222 (3 << 6) +#define DSMR_CSY_MASK (3 << 6) + +#define DSSR 0x00008 +#define D2SSR 0x30008 +#define DSSR_VC1FB_DSA0 (0 << 30) +#define DSSR_VC1FB_DSA1 (1 << 30) +#define DSSR_VC1FB_DSA2 (2 << 30) +#define DSSR_VC1FB_INIT (3 << 30) +#define DSSR_VC1FB_MASK (3 << 30) +#define DSSR_VC0FB_DSA0 (0 << 28) +#define DSSR_VC0FB_DSA1 (1 << 28) +#define DSSR_VC0FB_DSA2 (2 << 28) +#define DSSR_VC0FB_INIT (3 << 28) +#define DSSR_VC0FB_MASK (3 << 28) +#define DSSR_DFB(n) (1 << ((n)+15)) +#define DSSR_TVR (1 << 15) +#define DSSR_FRM (1 << 14) +#define DSSR_VBK (1 << 11) +#define DSSR_RINT (1 << 9) +#define DSSR_HBK (1 << 8) +#define DSSR_ADC(n) (1 << ((n)-1)) + +#define DSRCR 0x0000c +#define D2SRCR 0x3000c +#define DSRCR_TVCL (1 << 15) +#define DSRCR_FRCL (1 << 14) +#define DSRCR_VBCL (1 << 11) +#define DSRCR_RICL (1 << 9) +#define DSRCR_HBCL (1 << 8) +#define DSRCR_ADCL(n) (1 << ((n)-1)) +#define DSRCR_MASK 0x0000cbff + +#define DIER 0x00010 +#define D2IER 0x30010 +#define DIER_TVE (1 << 15) +#define DIER_FRE (1 << 14) +#define DIER_VBE (1 << 11) +#define DIER_RIE (1 << 9) +#define DIER_HBE (1 << 8) +#define DIER_ADCE(n) (1 << ((n)-1)) + +#define CPCR 0x00014 +#define CPCR_CP4CE (1 << 19) +#define CPCR_CP3CE (1 << 18) +#define CPCR_CP2CE (1 << 17) +#define CPCR_CP1CE (1 << 16) + +#define DPPR 0x00018 +#define DPPR_DPE(n) (1 << ((n)*4-1)) +#define DPPR_DPS(n, p) (((p)-1) << DPPR_DPS_SHIFT(n)) +#define DPPR_DPS_SHIFT(n) (((n)-1)*4) +#define DPPR_BPP16 (DPPR_DPE(8) | DPPR_DPS(8, 1)) /* plane1 */ +#define DPPR_BPP32_P1 (DPPR_DPE(7) | DPPR_DPS(7, 1)) +#define DPPR_BPP32_P2 (DPPR_DPE(8) | DPPR_DPS(8, 2)) +#define DPPR_BPP32 (DPPR_BPP32_P1 | DPPR_BPP32_P2) /* plane1 & 2 */ + +#define DEFR 0x00020 +#define D2EFR 0x30020 +#define DEFR_CODE (0x7773 << 16) +#define DEFR_EXSL (1 << 12) +#define DEFR_EXVL (1 << 11) +#define DEFR_EXUP (1 << 5) +#define DEFR_VCUP (1 << 4) +#define DEFR_DEFE (1 << 0) + +#define DAPCR 0x00024 +#define DAPCR_CODE (0x7773 << 16) +#define DAPCR_AP2E (1 << 4) +#define DAPCR_AP1E (1 << 0) + +#define DCPCR 0x00028 +#define DCPCR_CODE (0x7773 << 16) +#define DCPCR_CA2B (1 << 13) +#define DCPCR_CD2F (1 << 12) +#define DCPCR_DC2E (1 << 8) +#define DCPCR_CAB (1 << 5) +#define DCPCR_CDF (1 << 4) +#define DCPCR_DCE (1 << 0) + +#define DEFR2 0x00034 +#define D2EFR2 0x30034 +#define DEFR2_CODE (0x7775 << 16) +#define DEFR2_DEFE2G (1 << 0) + +#define DEFR3 0x00038 +#define D2EFR3 0x30038 +#define DEFR3_CODE (0x7776 << 16) +#define DEFR3_EVDA (1 << 14) +#define DEFR3_EVDM_1 (1 << 12) +#define DEFR3_EVDM_2 (2 << 12) +#define DEFR3_EVDM_3 (3 << 12) +#define DEFR3_VMSM2_EMA (1 << 6) +#define DEFR3_VMSM1_ENA (1 << 4) +#define DEFR3_DEFE3 (1 << 0) + +#define DEFR4 0x0003c +#define D2EFR4 0x3003c +#define DEFR4_CODE (0x7777 << 16) +#define DEFR4_LRUO (1 << 5) +#define DEFR4_SPCE (1 << 4) + +#define DVCSR 0x000d0 +#define DVCSR_VCnFB2_DSA0(n) (0 << ((n)*2+16)) +#define DVCSR_VCnFB2_DSA1(n) (1 << ((n)*2+16)) +#define DVCSR_VCnFB2_DSA2(n) (2 << ((n)*2+16)) +#define DVCSR_VCnFB2_INIT(n) (3 << ((n)*2+16)) +#define DVCSR_VCnFB2_MASK(n) (3 << ((n)*2+16)) +#define DVCSR_VCnFB_DSA0(n) (0 << ((n)*2)) +#define DVCSR_VCnFB_DSA1(n) (1 << ((n)*2)) +#define DVCSR_VCnFB_DSA2(n) (2 << ((n)*2)) +#define DVCSR_VCnFB_INIT(n) (3 << ((n)*2)) +#define DVCSR_VCnFB_MASK(n) (3 << ((n)*2)) + +#define DEFR5 0x000e0 +#define DEFR5_CODE (0x66 << 24) +#define DEFR5_YCRGB2_DIS (0 << 14) +#define DEFR5_YCRGB2_PRI1 (1 << 14) +#define DEFR5_YCRGB2_PRI2 (2 << 14) +#define DEFR5_YCRGB2_PRI3 (3 << 14) +#define DEFR5_YCRGB2_MASK (3 << 14) +#define DEFR5_YCRGB1_DIS (0 << 12) +#define DEFR5_YCRGB1_PRI1 (1 << 12) +#define DEFR5_YCRGB1_PRI2 (2 << 12) +#define DEFR5_YCRGB1_PRI3 (3 << 12) +#define DEFR5_YCRGB1_MASK (3 << 12) +#define DEFR5_DEFE5 (1 << 0) + +#define DDLTR 0x000e4 +#define DDLTR_CODE (0x7766 << 16) +#define DDLTR_DLAR2 (1 << 6) +#define DDLTR_DLAY2 (1 << 5) +#define DDLTR_DLAY1 (1 << 1) + +#define DEFR6 0x000e8 +#define DEFR6_CODE (0x7778 << 16) +#define DEFR6_ODPM22_D2SMR (0 << 10) +#define DEFR6_ODPM22_DISP (2 << 10) +#define DEFR6_ODPM22_CDE (3 << 10) +#define DEFR6_ODPM22_MASK (3 << 10) +#define DEFR6_ODPM12_DSMR (0 << 8) +#define DEFR6_ODPM12_DISP (2 << 8) +#define DEFR6_ODPM12_CDE (3 << 8) +#define DEFR6_ODPM12_MASK (3 << 8) +#define DEFR6_TCNE2 (1 << 6) +#define DEFR6_MLOS1 (1 << 2) +#define DEFR6_DEFAULT (DEFR6_CODE | DEFR6_TCNE2) + +/* ----------------------------------------------------------------------------- + * Display Timing Generation Registers + */ + +#define HDSR 0x00040 +#define HDER 0x00044 +#define VDSR 0x00048 +#define VDER 0x0004c +#define HCR 0x00050 +#define HSWR 0x00054 +#define VCR 0x00058 +#define VSPR 0x0005c +#define EQWR 0x00060 +#define SPWR 0x00064 +#define CLAMPSR 0x00070 +#define CLAMPWR 0x00074 +#define DESR 0x00078 +#define DEWR 0x0007c + +/* ----------------------------------------------------------------------------- + * Display Attribute Registers + */ + +#define CP1TR 0x00080 +#define CP2TR 0x00084 +#define CP3TR 0x00088 +#define CP4TR 0x0008c + +#define DOOR 0x00090 +#define DOOR_RGB(r, g, b) (((r) << 18) | ((g) << 10) | ((b) << 2)) +#define CDER 0x00094 +#define CDER_RGB(r, g, b) (((r) << 18) | ((g) << 10) | ((b) << 2)) +#define BPOR 0x00098 +#define BPOR_RGB(r, g, b) (((r) << 18) | ((g) << 10) | ((b) << 2)) + +#define RINTOFSR 0x0009c + +#define DSHPR 0x000c8 +#define DSHPR_CODE (0x7776 << 16) +#define DSHPR_PRIH (0xa << 4) +#define DSHPR_PRIL_BPP16 (0x8 << 0) +#define DSHPR_PRIL_BPP32 (0x9 << 0) + +/* ----------------------------------------------------------------------------- + * Display Plane Registers + */ + +#define PLANE_OFF 0x00100 + +#define PnMR 0x00100 /* plane 1 */ +#define PnMR_VISL_VIN0 (0 << 26) /* use Video Input 0 */ +#define PnMR_VISL_VIN1 (1 << 26) /* use Video Input 1 */ +#define PnMR_VISL_VIN2 (2 << 26) /* use Video Input 2 */ +#define PnMR_VISL_VIN3 (3 << 26) /* use Video Input 3 */ +#define PnMR_YCDF_YUYV (1 << 20) /* YUYV format */ +#define PnMR_TC_R (0 << 17) /* Tranparent color is PnTC1R */ +#define PnMR_TC_CP (1 << 17) /* Tranparent color is color palette */ +#define PnMR_WAE (1 << 16) /* Wrap around Enable */ +#define PnMR_SPIM_TP (0 << 12) /* Transparent Color */ +#define PnMR_SPIM_ALP (1 << 12) /* Alpha Blending */ +#define PnMR_SPIM_EOR (2 << 12) /* EOR */ +#define PnMR_SPIM_TP_OFF (1 << 14) /* No Transparent Color */ +#define PnMR_CPSL_CP1 (0 << 8) /* Color Palette selected 1 */ +#define PnMR_CPSL_CP2 (1 << 8) /* Color Palette selected 2 */ +#define PnMR_CPSL_CP3 (2 << 8) /* Color Palette selected 3 */ +#define PnMR_CPSL_CP4 (3 << 8) /* Color Palette selected 4 */ +#define PnMR_DC (1 << 7) /* Display Area Change */ +#define PnMR_BM_MD (0 << 4) /* Manual Display Change Mode */ +#define PnMR_BM_AR (1 << 4) /* Auto Rendering Mode */ +#define PnMR_BM_AD (2 << 4) /* Auto Display Change Mode */ +#define PnMR_BM_VC (3 << 4) /* Video Capture Mode */ +#define PnMR_DDDF_8BPP (0 << 0) /* 8bit */ +#define PnMR_DDDF_16BPP (1 << 0) /* 16bit or 32bit */ +#define PnMR_DDDF_ARGB (2 << 0) /* ARGB */ +#define PnMR_DDDF_YC (3 << 0) /* YC */ +#define PnMR_DDDF_MASK (3 << 0) + +#define PnMWR 0x00104 + +#define PnALPHAR 0x00108 +#define PnALPHAR_ABIT_1 (0 << 12) +#define PnALPHAR_ABIT_0 (1 << 12) +#define PnALPHAR_ABIT_X (2 << 12) + +#define PnDSXR 0x00110 +#define PnDSYR 0x00114 +#define PnDPXR 0x00118 +#define PnDPYR 0x0011c + +#define PnDSA0R 0x00120 +#define PnDSA1R 0x00124 +#define PnDSA2R 0x00128 +#define PnDSA_MASK 0xfffffff0 + +#define PnSPXR 0x00130 +#define PnSPYR 0x00134 +#define PnWASPR 0x00138 +#define PnWAMWR 0x0013c + +#define PnBTR 0x00140 + +#define PnTC1R 0x00144 +#define PnTC2R 0x00148 +#define PnTC3R 0x0014c +#define PnTC3R_CODE (0x66 << 24) + +#define PnMLR 0x00150 + +#define PnSWAPR 0x00180 +#define PnSWAPR_DIGN (1 << 4) +#define PnSWAPR_SPQW (1 << 3) +#define PnSWAPR_SPLW (1 << 2) +#define PnSWAPR_SPWD (1 << 1) +#define PnSWAPR_SPBY (1 << 0) + +#define PnDDCR 0x00184 +#define PnDDCR_CODE (0x7775 << 16) +#define PnDDCR_LRGB1 (1 << 11) +#define PnDDCR_LRGB0 (1 << 10) + +#define PnDDCR2 0x00188 +#define PnDDCR2_CODE (0x7776 << 16) +#define PnDDCR2_NV21 (1 << 5) +#define PnDDCR2_Y420 (1 << 4) +#define PnDDCR2_DIVU (1 << 1) +#define PnDDCR2_DIVY (1 << 0) + +#define PnDDCR4 0x00190 +#define PnDDCR4_CODE (0x7766 << 16) +#define PnDDCR4_SDFS_RGB (0 << 4) +#define PnDDCR4_SDFS_YC (5 << 4) +#define PnDDCR4_SDFS_MASK (7 << 4) +#define PnDDCR4_EDF_NONE (0 << 0) +#define PnDDCR4_EDF_ARGB8888 (1 << 0) +#define PnDDCR4_EDF_RGB888 (2 << 0) +#define PnDDCR4_EDF_RGB666 (3 << 0) +#define PnDDCR4_EDF_MASK (7 << 0) + +#define APnMR 0x0a100 +#define APnMR_WAE (1 << 16) /* Wrap around Enable */ +#define APnMR_DC (1 << 7) /* Display Area Change */ +#define APnMR_BM_MD (0 << 4) /* Manual Display Change Mode */ +#define APnMR_BM_AD (2 << 4) /* Auto Display Change Mode */ + +#define APnMWR 0x0a104 +#define APnDSA0R 0x0a120 +#define APnDSA1R 0x0a124 +#define APnDSA2R 0x0a128 +#define APnMLR 0x0a150 + +/* ----------------------------------------------------------------------------- + * Display Capture Registers + */ + +#define DCMWR 0x0c104 +#define DC2MWR 0x0c204 +#define DCSAR 0x0c120 +#define DC2SAR 0x0c220 +#define DCMLR 0x0c150 +#define DC2MLR 0x0c250 + +/* ----------------------------------------------------------------------------- + * Color Palette Registers + */ + +#define CP1_000R 0x01000 +#define CP1_255R 0x013fc +#define CP2_000R 0x02000 +#define CP2_255R 0x023fc +#define CP3_000R 0x03000 +#define CP3_255R 0x033fc +#define CP4_000R 0x04000 +#define CP4_255R 0x043fc + +/* ----------------------------------------------------------------------------- + * External Synchronization Control Registers + */ + +#define ESCR 0x10000 +#define ESCR2 0x31000 +#define ESCR_DCLKOINV (1 << 25) +#define ESCR_DCLKSEL_DCLKIN (0 << 20) +#define ESCR_DCLKSEL_CLKS (1 << 20) +#define ESCR_DCLKSEL_MASK (1 << 20) +#define ESCR_DCLKDIS (1 << 16) +#define ESCR_SYNCSEL_OFF (0 << 8) +#define ESCR_SYNCSEL_EXVSYNC (2 << 8) +#define ESCR_SYNCSEL_EXHSYNC (3 << 8) +#define ESCR_FRQSEL_MASK (0x3f << 0) + +#define OTAR 0x10004 +#define OTAR2 0x31004 + +/* ----------------------------------------------------------------------------- + * Dual Display Output Control Registers + */ + +#define DORCR 0x11000 +#define DORCR_PG2T (1 << 30) +#define DORCR_DK2S (1 << 28) +#define DORCR_PG2D_DS1 (0 << 24) +#define DORCR_PG2D_DS2 (1 << 24) +#define DORCR_PG2D_FIX0 (2 << 24) +#define DORCR_PG2D_DOOR (3 << 24) +#define DORCR_PG2D_MASK (3 << 24) +#define DORCR_DR1D (1 << 21) +#define DORCR_PG1D_DS1 (0 << 16) +#define DORCR_PG1D_DS2 (1 << 16) +#define DORCR_PG1D_FIX0 (2 << 16) +#define DORCR_PG1D_DOOR (3 << 16) +#define DORCR_PG1D_MASK (3 << 16) +#define DORCR_RGPV (1 << 4) +#define DORCR_DPRS (1 << 0) + +#define DPTSR 0x11004 +#define DPTSR_PnDK(n) (1 << ((n) + 16)) +#define DPTSR_PnTS(n) (1 << (n)) + +#define DAPTSR 0x11008 +#define DAPTSR_APnDK(n) (1 << ((n) + 16)) +#define DAPTSR_APnTS(n) (1 << (n)) + +#define DS1PR 0x11020 +#define DS2PR 0x11024 + +/* ----------------------------------------------------------------------------- + * YC-RGB Conversion Coefficient Registers + */ + +#define YNCR 0x11080 +#define YNOR 0x11084 +#define CRNOR 0x11088 +#define CBNOR 0x1108c +#define RCRCR 0x11090 +#define GCRCR 0x11094 +#define GCBCR 0x11098 +#define BCBCR 0x1109c + +#endif /* __RCAR_DU_REGS_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vga.c b/drivers/gpu/drm/rcar-du/rcar_du_vga.c new file mode 100644 index 000000000000..327289ec380d --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_vga.c @@ -0,0 +1,149 @@ +/* + * rcar_du_vga.c -- R-Car Display Unit VGA DAC and Connector + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> + +#include "rcar_du_drv.h" +#include "rcar_du_kms.h" +#include "rcar_du_vga.h" + +/* ----------------------------------------------------------------------------- + * Connector + */ + +static int rcar_du_vga_connector_get_modes(struct drm_connector *connector) +{ + return 0; +} + +static int rcar_du_vga_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static const struct drm_connector_helper_funcs connector_helper_funcs = { + .get_modes = rcar_du_vga_connector_get_modes, + .mode_valid = rcar_du_vga_connector_mode_valid, + .best_encoder = rcar_du_connector_best_encoder, +}; + +static void rcar_du_vga_connector_destroy(struct drm_connector *connector) +{ + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); +} + +static enum drm_connector_status +rcar_du_vga_connector_detect(struct drm_connector *connector, bool force) +{ + return connector_status_unknown; +} + +static const struct drm_connector_funcs connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = rcar_du_vga_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = rcar_du_vga_connector_destroy, +}; + +static int rcar_du_vga_connector_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc) +{ + struct rcar_du_connector *rcon; + struct drm_connector *connector; + int ret; + + rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL); + if (rcon == NULL) + return -ENOMEM; + + connector = &rcon->connector; + connector->display_info.width_mm = 0; + connector->display_info.height_mm = 0; + + ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, + DRM_MODE_CONNECTOR_VGA); + if (ret < 0) + return ret; + + drm_connector_helper_add(connector, &connector_helper_funcs); + ret = drm_sysfs_connector_add(connector); + if (ret < 0) + return ret; + + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_object_property_set_value(&connector->base, + rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); + + ret = drm_mode_connector_attach_encoder(connector, &renc->encoder); + if (ret < 0) + return ret; + + connector->encoder = &renc->encoder; + rcon->encoder = renc; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Encoder + */ + +static void rcar_du_vga_encoder_dpms(struct drm_encoder *encoder, int mode) +{ +} + +static bool rcar_du_vga_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static const struct drm_encoder_helper_funcs encoder_helper_funcs = { + .dpms = rcar_du_vga_encoder_dpms, + .mode_fixup = rcar_du_vga_encoder_mode_fixup, + .prepare = rcar_du_encoder_mode_prepare, + .commit = rcar_du_encoder_mode_commit, + .mode_set = rcar_du_encoder_mode_set, +}; + +static const struct drm_encoder_funcs encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +int rcar_du_vga_init(struct rcar_du_device *rcdu, + const struct rcar_du_encoder_vga_data *data, + unsigned int output) +{ + struct rcar_du_encoder *renc; + int ret; + + renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL); + if (renc == NULL) + return -ENOMEM; + + renc->output = output; + + ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs, + DRM_MODE_ENCODER_DAC); + if (ret < 0) + return ret; + + drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs); + + return rcar_du_vga_connector_init(rcdu, renc); +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vga.h b/drivers/gpu/drm/rcar-du/rcar_du_vga.h new file mode 100644 index 000000000000..66b4d2d7190d --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_vga.h @@ -0,0 +1,24 @@ +/* + * rcar_du_vga.h -- R-Car Display Unit VGA DAC and Connector + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_VGA_H__ +#define __RCAR_DU_VGA_H__ + +struct rcar_du_device; +struct rcar_du_encoder_vga_data; + +int rcar_du_vga_init(struct rcar_du_device *rcdu, + const struct rcar_du_encoder_vga_data *data, + unsigned int output); + +#endif /* __RCAR_DU_VGA_H__ */ diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index b55c1d661147..bd6b2cf508d5 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -570,9 +570,6 @@ int savage_driver_firstopen(struct drm_device *dev) unsigned int fb_rsrc, aper_rsrc; int ret = 0; - dev_priv->mtrr[0].handle = -1; - dev_priv->mtrr[1].handle = -1; - dev_priv->mtrr[2].handle = -1; if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { fb_rsrc = 0; fb_base = pci_resource_start(dev->pdev, 0); @@ -584,21 +581,14 @@ int savage_driver_firstopen(struct drm_device *dev) if (pci_resource_len(dev->pdev, 0) == 0x08000000) { /* Don't make MMIO write-cobining! We need 3 * MTRRs. */ - dev_priv->mtrr[0].base = fb_base; - dev_priv->mtrr[0].size = 0x01000000; - dev_priv->mtrr[0].handle = - drm_mtrr_add(dev_priv->mtrr[0].base, - dev_priv->mtrr[0].size, DRM_MTRR_WC); - dev_priv->mtrr[1].base = fb_base + 0x02000000; - dev_priv->mtrr[1].size = 0x02000000; - dev_priv->mtrr[1].handle = - drm_mtrr_add(dev_priv->mtrr[1].base, - dev_priv->mtrr[1].size, DRM_MTRR_WC); - dev_priv->mtrr[2].base = fb_base + 0x04000000; - dev_priv->mtrr[2].size = 0x04000000; - dev_priv->mtrr[2].handle = - drm_mtrr_add(dev_priv->mtrr[2].base, - dev_priv->mtrr[2].size, DRM_MTRR_WC); + dev_priv->mtrr_handles[0] = + arch_phys_wc_add(fb_base, 0x01000000); + dev_priv->mtrr_handles[1] = + arch_phys_wc_add(fb_base + 0x02000000, + 0x02000000); + dev_priv->mtrr_handles[2] = + arch_phys_wc_add(fb_base + 0x04000000, + 0x04000000); } else { DRM_ERROR("strange pci_resource_len %08llx\n", (unsigned long long) @@ -616,11 +606,9 @@ int savage_driver_firstopen(struct drm_device *dev) if (pci_resource_len(dev->pdev, 1) == 0x08000000) { /* Can use one MTRR to cover both fb and * aperture. */ - dev_priv->mtrr[0].base = fb_base; - dev_priv->mtrr[0].size = 0x08000000; - dev_priv->mtrr[0].handle = - drm_mtrr_add(dev_priv->mtrr[0].base, - dev_priv->mtrr[0].size, DRM_MTRR_WC); + dev_priv->mtrr_handles[0] = + arch_phys_wc_add(fb_base, + 0x08000000); } else { DRM_ERROR("strange pci_resource_len %08llx\n", (unsigned long long) @@ -660,11 +648,10 @@ void savage_driver_lastclose(struct drm_device *dev) drm_savage_private_t *dev_priv = dev->dev_private; int i; - for (i = 0; i < 3; ++i) - if (dev_priv->mtrr[i].handle >= 0) - drm_mtrr_del(dev_priv->mtrr[i].handle, - dev_priv->mtrr[i].base, - dev_priv->mtrr[i].size, DRM_MTRR_WC); + for (i = 0; i < 3; ++i) { + arch_phys_wc_del(dev_priv->mtrr_handles[i]); + dev_priv->mtrr_handles[i] = 0; + } } int savage_driver_unload(struct drm_device *dev) diff --git a/drivers/gpu/drm/savage/savage_drv.h b/drivers/gpu/drm/savage/savage_drv.h index df2aac6636f7..c05082a59f6f 100644 --- a/drivers/gpu/drm/savage/savage_drv.h +++ b/drivers/gpu/drm/savage/savage_drv.h @@ -160,10 +160,7 @@ typedef struct drm_savage_private { drm_local_map_t *cmd_dma; drm_local_map_t fake_dma; - struct { - int handle; - unsigned long base, size; - } mtrr[3]; + int mtrr_handles[3]; /* BCI and status-related stuff */ volatile uint32_t *status_ptr, *bci_ptr; diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/shmobile/Kconfig index 7e7d52b2a2fc..ca498d151a76 100644 --- a/drivers/gpu/drm/shmobile/Kconfig +++ b/drivers/gpu/drm/shmobile/Kconfig @@ -1,6 +1,6 @@ config DRM_SHMOBILE tristate "DRM Support for SH Mobile" - depends on DRM && (SUPERH || ARCH_SHMOBILE) + depends on DRM && (ARM || SUPERH) select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER select DRM_GEM_CMA_HELPER diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 7dff49ed66e7..99e2034e49cc 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -451,27 +451,16 @@ void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc) { struct drm_pending_vblank_event *event; struct drm_device *dev = scrtc->crtc.dev; - struct timeval vblanktime; unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); event = scrtc->event; scrtc->event = NULL; + if (event) { + drm_send_vblank_event(dev, 0, event); + drm_vblank_put(dev, 0); + } spin_unlock_irqrestore(&dev->event_lock, flags); - - if (event == NULL) - return; - - event->event.sequence = drm_vblank_count_and_time(dev, 0, &vblanktime); - event->event.tv_sec = vblanktime.tv_sec; - event->event.tv_usec = vblanktime.tv_usec; - - spin_lock_irqsave(&dev->event_lock, flags); - list_add_tail(&event->base.link, &event->base.file_priv->event_list); - wake_up_interruptible(&event->base.file_priv->event_wait); - spin_unlock_irqrestore(&dev->event_lock, flags); - - drm_vblank_put(dev, 0); } static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index f6e0b5395051..edc10181f551 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -90,7 +90,7 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev, return -EINVAL; } - clk = clk_get(sdev->dev, clkname); + clk = devm_clk_get(sdev->dev, clkname); if (IS_ERR(clk)) { dev_err(sdev->dev, "cannot get dot clock %s\n", clkname); return PTR_ERR(clk); @@ -106,21 +106,12 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev, static int shmob_drm_unload(struct drm_device *dev) { - struct shmob_drm_device *sdev = dev->dev_private; - drm_kms_helper_poll_fini(dev); drm_mode_config_cleanup(dev); drm_vblank_cleanup(dev); drm_irq_uninstall(dev); - if (sdev->clock) - clk_put(sdev->clock); - - if (sdev->mmio) - iounmap(sdev->mmio); - dev->dev_private = NULL; - kfree(sdev); return 0; } @@ -139,7 +130,7 @@ static int shmob_drm_load(struct drm_device *dev, unsigned long flags) return -EINVAL; } - sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); + sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); if (sdev == NULL) { dev_err(dev->dev, "failed to allocate private data\n"); return -ENOMEM; @@ -156,29 +147,28 @@ static int shmob_drm_load(struct drm_device *dev, unsigned long flags) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "failed to get memory resource\n"); - ret = -EINVAL; - goto done; + return -EINVAL; } - sdev->mmio = ioremap_nocache(res->start, resource_size(res)); + sdev->mmio = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); if (sdev->mmio == NULL) { dev_err(&pdev->dev, "failed to remap memory resource\n"); - ret = -ENOMEM; - goto done; + return -ENOMEM; } ret = shmob_drm_setup_clocks(sdev, pdata->clk_source); if (ret < 0) - goto done; + return ret; ret = shmob_drm_init_interface(sdev); if (ret < 0) - goto done; + return ret; ret = shmob_drm_modeset_init(sdev); if (ret < 0) { dev_err(&pdev->dev, "failed to initialize mode setting\n"); - goto done; + return ret; } for (i = 0; i < 4; ++i) { @@ -273,7 +263,8 @@ static const struct file_operations shmob_drm_fops = { }; static struct drm_driver shmob_drm_driver = { - .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET, + .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET + | DRIVER_PRIME, .load = shmob_drm_load, .unload = shmob_drm_unload, .preclose = shmob_drm_preclose, @@ -283,6 +274,10 @@ static struct drm_driver shmob_drm_driver = { .disable_vblank = shmob_drm_disable_vblank, .gem_free_object = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_cma_dmabuf_import, + .gem_prime_export = drm_gem_cma_dmabuf_export, .dumb_create = drm_gem_cma_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_cma_dumb_destroy, diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c index c291ee385b4f..fc0ef0ca7d04 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.c @@ -116,7 +116,7 @@ shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv, } if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) { - dev_dbg(dev->dev, "valid pitch value %u\n", + dev_dbg(dev->dev, "invalid pitch value %u\n", mode_cmd->pitches[0]); return ERR_PTR(-EINVAL); } diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c index e1eb899b0288..060ae03e5f9b 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c @@ -166,7 +166,7 @@ void shmob_drm_plane_setup(struct drm_plane *plane) { struct shmob_drm_plane *splane = to_shmob_plane(plane); - if (plane->fb == NULL || !plane->enabled) + if (plane->fb == NULL) return; __shmob_drm_plane_setup(splane, plane->fb); @@ -221,11 +221,8 @@ static int shmob_drm_plane_disable(struct drm_plane *plane) static void shmob_drm_plane_destroy(struct drm_plane *plane) { - struct shmob_drm_plane *splane = to_shmob_plane(plane); - shmob_drm_plane_disable(plane); drm_plane_cleanup(plane); - kfree(splane); } static const struct drm_plane_funcs shmob_drm_plane_funcs = { @@ -251,7 +248,7 @@ int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index) struct shmob_drm_plane *splane; int ret; - splane = kzalloc(sizeof(*splane), GFP_KERNEL); + splane = devm_kzalloc(sdev->dev, sizeof(*splane), GFP_KERNEL); if (splane == NULL) return -ENOMEM; @@ -261,8 +258,6 @@ int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index) ret = drm_plane_init(sdev->ddev, &splane->plane, 1, &shmob_drm_plane_funcs, formats, ARRAY_SIZE(formats), false); - if (ret < 0) - kfree(splane); return ret; } diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig index e461e9972455..7a4d10106906 100644 --- a/drivers/gpu/drm/tilcdc/Kconfig +++ b/drivers/gpu/drm/tilcdc/Kconfig @@ -6,6 +6,7 @@ config DRM_TILCDC select DRM_GEM_CMA_HELPER select VIDEOMODE_HELPERS select BACKLIGHT_CLASS_DEVICE + select BACKLIGHT_LCD_SUPPORT help Choose this option if you have an TI SoC with LCDC display controller, for example AM33xx in beagle-bone, DA8xx, or diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 5dd3c7d031d5..7418dcd986d3 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -42,7 +42,8 @@ struct tilcdc_crtc { static void unref_worker(struct work_struct *work) { - struct tilcdc_crtc *tilcdc_crtc = container_of(work, struct tilcdc_crtc, work); + struct tilcdc_crtc *tilcdc_crtc = + container_of(work, struct tilcdc_crtc, work); struct drm_device *dev = tilcdc_crtc->base.dev; struct drm_framebuffer *fb; @@ -55,10 +56,12 @@ static void unref_worker(struct work_struct *work) static void set_scanout(struct drm_crtc *crtc, int n) { static const uint32_t base_reg[] = { - LCDC_DMA_FB_BASE_ADDR_0_REG, LCDC_DMA_FB_BASE_ADDR_1_REG, + LCDC_DMA_FB_BASE_ADDR_0_REG, + LCDC_DMA_FB_BASE_ADDR_1_REG, }; static const uint32_t ceil_reg[] = { - LCDC_DMA_FB_CEILING_ADDR_0_REG, LCDC_DMA_FB_CEILING_ADDR_1_REG, + LCDC_DMA_FB_CEILING_ADDR_0_REG, + LCDC_DMA_FB_CEILING_ADDR_1_REG, }; static const uint32_t stat[] = { LCDC_END_OF_FRAME0, LCDC_END_OF_FRAME1, @@ -194,7 +197,8 @@ static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode) tilcdc_crtc->frame_done = false; stop(crtc); - /* if necessary wait for framedone irq which will still come + /* + * if necessary wait for framedone irq which will still come * before putting things to sleep.. */ if (priv->rev == 2) { @@ -289,17 +293,24 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, reg = tilcdc_read(dev, LCDC_RASTER_TIMING_2_REG) & ~0x000fff00; reg |= LCDC_AC_BIAS_FREQUENCY(info->ac_bias) | LCDC_AC_BIAS_TRANSITIONS_PER_INT(info->ac_bias_intrpt); + + /* + * subtract one from hfp, hbp, hsw because the hardware uses + * a value of 0 as 1 + */ if (priv->rev == 2) { - reg |= (hfp & 0x300) >> 8; - reg |= (hbp & 0x300) >> 4; - reg |= (hsw & 0x3c0) << 21; + /* clear bits we're going to set */ + reg &= ~0x78000033; + reg |= ((hfp-1) & 0x300) >> 8; + reg |= ((hbp-1) & 0x300) >> 4; + reg |= ((hsw-1) & 0x3c0) << 21; } tilcdc_write(dev, LCDC_RASTER_TIMING_2_REG, reg); reg = (((mode->hdisplay >> 4) - 1) << 4) | - ((hbp & 0xff) << 24) | - ((hfp & 0xff) << 16) | - ((hsw & 0x3f) << 10); + (((hbp-1) & 0xff) << 24) | + (((hfp-1) & 0xff) << 16) | + (((hsw-1) & 0x3f) << 10); if (priv->rev == 2) reg |= (((mode->hdisplay >> 4) - 1) & 0x40) >> 3; tilcdc_write(dev, LCDC_RASTER_TIMING_0_REG, reg); @@ -307,9 +318,24 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, reg = ((mode->vdisplay - 1) & 0x3ff) | ((vbp & 0xff) << 24) | ((vfp & 0xff) << 16) | - ((vsw & 0x3f) << 10); + (((vsw-1) & 0x3f) << 10); tilcdc_write(dev, LCDC_RASTER_TIMING_1_REG, reg); + /* + * be sure to set Bit 10 for the V2 LCDC controller, + * otherwise limited to 1024 pixels width, stopping + * 1920x1080 being suppoted. + */ + if (priv->rev == 2) { + if ((mode->vdisplay - 1) & 0x400) { + tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, + LCDC_LPP_B10); + } else { + tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, + LCDC_LPP_B10); + } + } + /* Configure display type: */ reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG) & ~(LCDC_TFT_MODE | LCDC_MONO_8BIT_MODE | LCDC_MONOCHROME_MODE | @@ -384,10 +410,6 @@ static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, return 0; } -static void tilcdc_crtc_load_lut(struct drm_crtc *crtc) -{ -} - static const struct drm_crtc_funcs tilcdc_crtc_funcs = { .destroy = tilcdc_crtc_destroy, .set_config = drm_crtc_helper_set_config, @@ -401,7 +423,6 @@ static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = { .commit = tilcdc_crtc_commit, .mode_set = tilcdc_crtc_mode_set, .mode_set_base = tilcdc_crtc_mode_set_base, - .load_lut = tilcdc_crtc_load_lut, }; int tilcdc_crtc_max_width(struct drm_crtc *crtc) @@ -422,7 +443,12 @@ int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct tilcdc_drm_private *priv = crtc->dev->dev_private; unsigned int bandwidth; + uint32_t hbp, hfp, hsw, vbp, vfp, vsw; + /* + * check to see if the width is within the range that + * the LCD Controller physically supports + */ if (mode->hdisplay > tilcdc_crtc_max_width(crtc)) return MODE_VIRTUAL_X; @@ -433,10 +459,70 @@ int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode) if (mode->vdisplay > 2048) return MODE_VIRTUAL_Y; + DBG("Processing mode %dx%d@%d with pixel clock %d", + mode->hdisplay, mode->vdisplay, + drm_mode_vrefresh(mode), mode->clock); + + hbp = mode->htotal - mode->hsync_end; + hfp = mode->hsync_start - mode->hdisplay; + hsw = mode->hsync_end - mode->hsync_start; + vbp = mode->vtotal - mode->vsync_end; + vfp = mode->vsync_start - mode->vdisplay; + vsw = mode->vsync_end - mode->vsync_start; + + if ((hbp-1) & ~0x3ff) { + DBG("Pruning mode: Horizontal Back Porch out of range"); + return MODE_HBLANK_WIDE; + } + + if ((hfp-1) & ~0x3ff) { + DBG("Pruning mode: Horizontal Front Porch out of range"); + return MODE_HBLANK_WIDE; + } + + if ((hsw-1) & ~0x3ff) { + DBG("Pruning mode: Horizontal Sync Width out of range"); + return MODE_HSYNC_WIDE; + } + + if (vbp & ~0xff) { + DBG("Pruning mode: Vertical Back Porch out of range"); + return MODE_VBLANK_WIDE; + } + + if (vfp & ~0xff) { + DBG("Pruning mode: Vertical Front Porch out of range"); + return MODE_VBLANK_WIDE; + } + + if ((vsw-1) & ~0x3f) { + DBG("Pruning mode: Vertical Sync Width out of range"); + return MODE_VSYNC_WIDE; + } + + /* + * some devices have a maximum allowed pixel clock + * configured from the DT + */ + if (mode->clock > priv->max_pixelclock) { + DBG("Pruning mode: pixel clock too high"); + return MODE_CLOCK_HIGH; + } + + /* + * some devices further limit the max horizontal resolution + * configured from the DT + */ + if (mode->hdisplay > priv->max_width) + return MODE_BAD_WIDTH; + /* filter out modes that would require too much memory bandwidth: */ - bandwidth = mode->hdisplay * mode->vdisplay * drm_mode_vrefresh(mode); - if (bandwidth > priv->max_bandwidth) + bandwidth = mode->hdisplay * mode->vdisplay * + drm_mode_vrefresh(mode); + if (bandwidth > priv->max_bandwidth) { + DBG("Pruning mode: exceeds defined bandwidth limit"); return MODE_BAD; + } return MODE_OK; } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 2b5461bcd9fb..40b71da5a214 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -26,6 +26,7 @@ #include "drm_fb_helper.h" static LIST_HEAD(module_list); +static bool slave_probing; void tilcdc_module_init(struct tilcdc_module *mod, const char *name, const struct tilcdc_module_ops *funcs) @@ -41,6 +42,11 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) list_del(&mod->list); } +void tilcdc_slave_probedefer(bool defered) +{ + slave_probing = defered; +} + static struct of_device_id tilcdc_of_match[]; static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, @@ -157,7 +163,9 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) struct platform_device *pdev = dev->platformdev; struct device_node *node = pdev->dev.of_node; struct tilcdc_drm_private *priv; + struct tilcdc_module *mod; struct resource *res; + u32 bpp = 0; int ret; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -210,7 +218,20 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) #endif if (of_property_read_u32(node, "max-bandwidth", &priv->max_bandwidth)) - priv->max_bandwidth = 1280 * 1024 * 60; + priv->max_bandwidth = TILCDC_DEFAULT_MAX_BANDWIDTH; + + DBG("Maximum Bandwidth Value %d", priv->max_bandwidth); + + if (of_property_read_u32(node, "ti,max-width", &priv->max_width)) + priv->max_width = TILCDC_DEFAULT_MAX_WIDTH; + + DBG("Maximum Horizontal Pixel Width Value %dpixels", priv->max_width); + + if (of_property_read_u32(node, "ti,max-pixelclock", + &priv->max_pixelclock)) + priv->max_pixelclock = TILCDC_DEFAULT_MAX_PIXELCLOCK; + + DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); pm_runtime_enable(dev->dev); @@ -256,7 +277,15 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) platform_set_drvdata(pdev, dev); - priv->fbdev = drm_fbdev_cma_init(dev, 16, + + list_for_each_entry(mod, &module_list, list) { + DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp); + bpp = mod->preferred_bpp; + if (bpp > 0) + break; + } + + priv->fbdev = drm_fbdev_cma_init(dev, bpp, dev->mode_config.num_crtc, dev->mode_config.num_connector); @@ -557,6 +586,10 @@ static int tilcdc_pdev_probe(struct platform_device *pdev) return -ENXIO; } + /* defer probing if slave is in deferred probing */ + if (slave_probing == true) + return -EPROBE_DEFER; + return drm_platform_init(&tilcdc_driver, pdev); } diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 8242b5a4307b..093803683b25 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h @@ -34,6 +34,18 @@ #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> +/* Defaulting to pixel clock defined on AM335x */ +#define TILCDC_DEFAULT_MAX_PIXELCLOCK 126000 +/* Defaulting to max width as defined on AM335x */ +#define TILCDC_DEFAULT_MAX_WIDTH 2048 +/* + * This may need some tweaking, but want to allow at least 1280x1024@60 + * with optimized DDR & EMIF settings tweaked 1920x1080@24 appears to + * be supportable + */ +#define TILCDC_DEFAULT_MAX_BANDWIDTH (1280*1024*60) + + struct tilcdc_drm_private { void __iomem *mmio; @@ -43,6 +55,16 @@ struct tilcdc_drm_private { /* don't attempt resolutions w/ higher W * H * Hz: */ uint32_t max_bandwidth; + /* + * Pixel Clock will be restricted to some value as + * defined in the device datasheet measured in KHz + */ + uint32_t max_pixelclock; + /* + * Max allowable width is limited on a per device basis + * measured in pixels + */ + uint32_t max_width; /* register contents saved across suspend/resume: */ u32 saved_register[12]; @@ -89,12 +111,13 @@ struct tilcdc_module { const char *name; struct list_head list; const struct tilcdc_module_ops *funcs; + unsigned int preferred_bpp; }; void tilcdc_module_init(struct tilcdc_module *mod, const char *name, const struct tilcdc_module_ops *funcs); void tilcdc_module_cleanup(struct tilcdc_module *mod); - +void tilcdc_slave_probedefer(bool defered); /* Panel config that needs to be set in the crtc, but is not coming from * the mode timings. The display module is expected to call diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 09176654fddb..86c67329b605 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -393,6 +393,8 @@ static int panel_probe(struct platform_device *pdev) goto fail; } + mod->preferred_bpp = panel_mod->info->bpp; + panel_mod->backlight = of_find_backlight_by_node(node); if (panel_mod->backlight) dev_info(&pdev->dev, "found backlight\n"); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_regs.h b/drivers/gpu/drm/tilcdc/tilcdc_regs.h index 17fd1b45428a..1bf5e2553acc 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_regs.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_regs.h @@ -80,6 +80,7 @@ #define LCDC_INVERT_PIXEL_CLOCK BIT(22) #define LCDC_INVERT_HSYNC BIT(21) #define LCDC_INVERT_VSYNC BIT(20) +#define LCDC_LPP_B10 BIT(26) /* LCDC Block */ #define LCDC_PID_REG 0x0 diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c index db1d2fc9dfb5..dfffaf014022 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c @@ -298,6 +298,7 @@ static int slave_probe(struct platform_device *pdev) struct tilcdc_module *mod; struct pinctrl *pinctrl; uint32_t i2c_phandle; + struct i2c_adapter *slavei2c; int ret = -EINVAL; /* bail out early if no DT data: */ @@ -306,42 +307,48 @@ static int slave_probe(struct platform_device *pdev) return -ENXIO; } - slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL); - if (!slave_mod) - return -ENOMEM; - - mod = &slave_mod->base; - - tilcdc_module_init(mod, "slave", &slave_module_ops); - - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) - dev_warn(&pdev->dev, "pins are not configured\n"); - + /* Bail out early if i2c not specified */ if (of_property_read_u32(node, "i2c", &i2c_phandle)) { dev_err(&pdev->dev, "could not get i2c bus phandle\n"); - goto fail; + return ret; } i2c_node = of_find_node_by_phandle(i2c_phandle); if (!i2c_node) { dev_err(&pdev->dev, "could not get i2c bus node\n"); - goto fail; + return ret; } - slave_mod->i2c = of_find_i2c_adapter_by_node(i2c_node); - if (!slave_mod->i2c) { + /* but defer the probe if it can't be initialized it might come later */ + slavei2c = of_find_i2c_adapter_by_node(i2c_node); + of_node_put(i2c_node); + + if (!slavei2c) { + ret = -EPROBE_DEFER; + tilcdc_slave_probedefer(true); dev_err(&pdev->dev, "could not get i2c\n"); - goto fail; + return ret; } - of_node_put(i2c_node); + slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL); + if (!slave_mod) + return -ENOMEM; - return 0; + mod = &slave_mod->base; -fail: - slave_destroy(mod); - return ret; + mod->preferred_bpp = slave_info.bpp; + + slave_mod->i2c = slavei2c; + + tilcdc_module_init(mod, "slave", &slave_module_ops); + + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, "pins are not configured\n"); + + tilcdc_slave_probedefer(false); + + return 0; } static int slave_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c index a36788fbcd98..925c7cddeff9 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c @@ -354,6 +354,8 @@ static int tfp410_probe(struct platform_device *pdev) goto fail; } + mod->preferred_bpp = dvi_info.bpp; + i2c_node = of_find_node_by_phandle(i2c_phandle); if (!i2c_node) { dev_err(&pdev->dev, "could not get i2c bus node\n"); diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index dc0c065f8d39..97e9d614700f 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -393,19 +393,6 @@ static struct fb_ops udlfb_ops = { .fb_release = udl_fb_release, }; -static void udl_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, - u16 blue, int regno) -{ -} - -static void udl_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, int regno) -{ - *red = 0; - *green = 0; - *blue = 0; -} - static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb, struct drm_file *file, unsigned flags, unsigned color, @@ -558,8 +545,6 @@ out: } static struct drm_fb_helper_funcs udl_fb_helper_funcs = { - .gamma_set = udl_crtc_fb_gamma_set, - .gamma_get = udl_crtc_fb_gamma_get, .fb_probe = udlfb_create, }; diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index e96d2349bd54..2ae1eb7d1635 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -363,10 +363,6 @@ static void udl_crtc_destroy(struct drm_crtc *crtc) kfree(crtc); } -static void udl_load_lut(struct drm_crtc *crtc) -{ -} - static void udl_crtc_prepare(struct drm_crtc *crtc) { } @@ -383,7 +379,6 @@ static struct drm_crtc_helper_funcs udl_helper_funcs = { .prepare = udl_crtc_prepare, .commit = udl_crtc_commit, .disable = udl_crtc_disable, - .load_lut = udl_load_lut, }; static const struct drm_crtc_funcs udl_crtc_funcs = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 07dfd823cc30..78e21649d48a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -565,8 +565,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->has_gmr = false; } - dev_priv->mmio_mtrr = drm_mtrr_add(dev_priv->mmio_start, - dev_priv->mmio_size, DRM_MTRR_WC); + dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start, + dev_priv->mmio_size); dev_priv->mmio_virt = ioremap_wc(dev_priv->mmio_start, dev_priv->mmio_size); @@ -664,8 +664,7 @@ out_no_device: out_err4: iounmap(dev_priv->mmio_virt); out_err3: - drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start, - dev_priv->mmio_size, DRM_MTRR_WC); + arch_phys_wc_del(dev_priv->mmio_mtrr); if (dev_priv->has_gmr) (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); @@ -709,8 +708,7 @@ static int vmw_driver_unload(struct drm_device *dev) ttm_object_device_release(&dev_priv->tdev); iounmap(dev_priv->mmio_virt); - drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start, - dev_priv->mmio_size, DRM_MTRR_WC); + arch_phys_wc_del(dev_priv->mmio_mtrr); if (dev_priv->has_gmr) (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 3e3c7ab33ca2..d4607b2530d6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -174,7 +174,6 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); - struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; struct vmw_display_unit *du = vmw_crtc_to_du(crtc); struct vmw_surface *surface = NULL; struct vmw_dma_buffer *dmabuf = NULL; @@ -197,6 +196,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, } if (handle) { + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + ret = vmw_user_lookup_handle(dev_priv, tfile, handle, &surface, &dmabuf); if (ret) { diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index a1607d6e135b..790ddf114e58 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -73,7 +73,7 @@ struct host1x_syncpt_ops { void (*restore_wait_base)(struct host1x_syncpt *syncpt); void (*load_wait_base)(struct host1x_syncpt *syncpt); u32 (*load)(struct host1x_syncpt *syncpt); - void (*cpu_incr)(struct host1x_syncpt *syncpt); + int (*cpu_incr)(struct host1x_syncpt *syncpt); int (*patch_wait)(struct host1x_syncpt *syncpt, void *patch_addr); }; @@ -157,10 +157,10 @@ static inline u32 host1x_hw_syncpt_load(struct host1x *host, return host->syncpt_op->load(sp); } -static inline void host1x_hw_syncpt_cpu_incr(struct host1x *host, - struct host1x_syncpt *sp) +static inline int host1x_hw_syncpt_cpu_incr(struct host1x *host, + struct host1x_syncpt *sp) { - host->syncpt_op->cpu_incr(sp); + return host->syncpt_op->cpu_incr(sp); } static inline int host1x_hw_syncpt_patch_wait(struct host1x *host, diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c index 8c04943f82e3..5360e5a57ecc 100644 --- a/drivers/gpu/host1x/drm/dc.c +++ b/drivers/gpu/host1x/drm/dc.c @@ -79,6 +79,9 @@ static int tegra_plane_disable(struct drm_plane *plane) struct tegra_plane *p = to_tegra_plane(plane); unsigned long value; + if (!plane->crtc) + return 0; + value = WINDOW_A_SELECT << p->index; tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); @@ -140,6 +143,7 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, struct drm_framebuffer *fb) { + unsigned int format = tegra_dc_format(fb->pixel_format); struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); unsigned long value; @@ -150,6 +154,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR); tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE); + tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH); value = GENERAL_UPDATE | WIN_A_UPDATE; tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c index 2b561c9118c6..e184b00faacd 100644 --- a/drivers/gpu/host1x/drm/drm.c +++ b/drivers/gpu/host1x/drm/drm.c @@ -148,6 +148,7 @@ int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm) dev_err(host1x->dev, "DRM setup failed for %s: %d\n", dev_name(client->dev), err); + mutex_unlock(&host1x->clients_lock); return err; } } @@ -175,6 +176,7 @@ int host1x_drm_exit(struct host1x_drm *host1x) dev_err(host1x->dev, "DRM cleanup failed for %s: %d\n", dev_name(client->dev), err); + mutex_unlock(&host1x->clients_lock); return err; } } @@ -257,6 +259,13 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) if (err < 0) return err; + /* + * We don't use the drm_irq_install() helpers provided by the DRM + * core, so we need to set this manually in order to allow the + * DRM_IOCTL_WAIT_VBLANK to operate correctly. + */ + drm->irq_enabled = 1; + err = drm_vblank_init(drm, drm->mode_config.num_crtc); if (err < 0) return err; @@ -378,8 +387,7 @@ static int tegra_syncpt_incr(struct drm_device *drm, void *data, if (!sp) return -EINVAL; - host1x_syncpt_incr(sp); - return 0; + return host1x_syncpt_incr(sp); } static int tegra_syncpt_wait(struct drm_device *drm, void *data, @@ -605,7 +613,7 @@ static void tegra_debugfs_cleanup(struct drm_minor *minor) #endif struct drm_driver tegra_drm_driver = { - .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM, + .driver_features = DRIVER_MODESET | DRIVER_GEM, .load = tegra_drm_load, .unload = tegra_drm_unload, .open = tegra_drm_open, diff --git a/drivers/gpu/host1x/drm/gr2d.c b/drivers/gpu/host1x/drm/gr2d.c index 6a45ae090ee7..27ffcf15a4b4 100644 --- a/drivers/gpu/host1x/drm/gr2d.c +++ b/drivers/gpu/host1x/drm/gr2d.c @@ -84,7 +84,7 @@ static struct host1x_bo *host1x_bo_lookup(struct drm_device *drm, gem = drm_gem_object_lookup(drm, file, handle); if (!gem) - return 0; + return NULL; mutex_lock(&drm->struct_mutex); drm_gem_object_unreference(gem); @@ -135,8 +135,10 @@ static int gr2d_submit(struct host1x_drm_context *context, goto fail; bo = host1x_bo_lookup(drm, file, cmdbuf.handle); - if (!bo) + if (!bo) { + err = -ENOENT; goto fail; + } host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset); num_cmdbufs--; @@ -158,8 +160,10 @@ static int gr2d_submit(struct host1x_drm_context *context, reloc->cmdbuf = cmdbuf; reloc->target = target; - if (!reloc->target || !reloc->cmdbuf) + if (!reloc->target || !reloc->cmdbuf) { + err = -ENOENT; goto fail; + } } err = copy_from_user(job->waitchk, waitchks, @@ -281,7 +285,7 @@ static int gr2d_probe(struct platform_device *pdev) if (!gr2d->channel) return -ENOMEM; - *syncpts = host1x_syncpt_request(dev, 0); + *syncpts = host1x_syncpt_request(dev, false); if (!(*syncpts)) { host1x_channel_free(gr2d->channel); return -ENOMEM; diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c index 590b69d91dab..2ee4ad55c4db 100644 --- a/drivers/gpu/host1x/hw/cdma_hw.c +++ b/drivers/gpu/host1x/hw/cdma_hw.c @@ -44,7 +44,7 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr, u32 i; for (i = 0; i < syncpt_incrs; i++) - host1x_syncpt_cpu_incr(cdma->timeout.syncpt); + host1x_syncpt_incr(cdma->timeout.syncpt); /* after CPU incr, ensure shadow is up to date */ host1x_syncpt_load(cdma->timeout.syncpt); diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c index 61174990102a..0cf6095d3367 100644 --- a/drivers/gpu/host1x/hw/syncpt_hw.c +++ b/drivers/gpu/host1x/hw/syncpt_hw.c @@ -77,21 +77,19 @@ static u32 syncpt_load(struct host1x_syncpt *sp) * Write a cpu syncpoint increment to the hardware, without touching * the cache. */ -static void syncpt_cpu_incr(struct host1x_syncpt *sp) +static int syncpt_cpu_incr(struct host1x_syncpt *sp) { struct host1x *host = sp->host; u32 reg_offset = sp->id / 32; if (!host1x_syncpt_client_managed(sp) && - host1x_syncpt_idle(sp)) { - dev_err(host->dev, "Trying to increment syncpoint id %d beyond max\n", - sp->id); - host1x_debug_dump(sp->host); - return; - } + host1x_syncpt_idle(sp)) + return -EINVAL; host1x_sync_writel(host, BIT_MASK(sp->id), HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); wmb(); + + return 0; } /* remove a wait pointed to by patch_addr */ diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index f665d679031c..cc807667d8f1 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c @@ -228,17 +228,15 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf) void *cmdbuf_page_addr = NULL; /* pin & patch the relocs for one gather */ - while (i < job->num_relocs) { + for (i = 0; i < job->num_relocs; i++) { struct host1x_reloc *reloc = &job->relocarray[i]; u32 reloc_addr = (job->reloc_addr_phys[i] + reloc->target_offset) >> reloc->shift; u32 *target; /* skip all other gathers */ - if (!(reloc->cmdbuf && cmdbuf == reloc->cmdbuf)) { - i++; + if (cmdbuf != reloc->cmdbuf) continue; - } if (last_page != reloc->cmdbuf_offset >> PAGE_SHIFT) { if (cmdbuf_page_addr) @@ -257,9 +255,6 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf) target = cmdbuf_page_addr + (reloc->cmdbuf_offset & ~PAGE_MASK); *target = reloc_addr; - - /* mark this gather as handled */ - reloc->cmdbuf = 0; } if (cmdbuf_page_addr) @@ -268,15 +263,15 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf) return 0; } -static int check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf, +static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf, unsigned int offset) { offset *= sizeof(u32); if (reloc->cmdbuf != cmdbuf || reloc->cmdbuf_offset != offset) - return -EINVAL; + return false; - return 0; + return true; } struct host1x_firewall { @@ -307,10 +302,10 @@ static int check_mask(struct host1x_firewall *fw) if (mask & 1) { if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) { - bool bad_reloc = check_reloc(fw->reloc, - fw->cmdbuf_id, - fw->offset); - if (!fw->num_relocs || bad_reloc) + if (!fw->num_relocs) + return -EINVAL; + if (!check_reloc(fw->reloc, fw->cmdbuf_id, + fw->offset)) return -EINVAL; fw->reloc++; fw->num_relocs--; @@ -330,14 +325,14 @@ static int check_incr(struct host1x_firewall *fw) u32 count = fw->count; u32 reg = fw->reg; - while (fw) { + while (count) { if (fw->words == 0) return -EINVAL; if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) { - bool bad_reloc = check_reloc(fw->reloc, fw->cmdbuf_id, - fw->offset); - if (!fw->num_relocs || bad_reloc) + if (!fw->num_relocs) + return -EINVAL; + if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset)) return -EINVAL; fw->reloc++; fw->num_relocs--; @@ -361,9 +356,9 @@ static int check_nonincr(struct host1x_firewall *fw) return -EINVAL; if (is_addr_reg) { - bool bad_reloc = check_reloc(fw->reloc, fw->cmdbuf_id, - fw->offset); - if (!fw->num_relocs || bad_reloc) + if (!fw->num_relocs) + return -EINVAL; + if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset)) return -EINVAL; fw->reloc++; fw->num_relocs--; @@ -376,69 +371,58 @@ static int check_nonincr(struct host1x_firewall *fw) return 0; } -static int validate(struct host1x_job *job, struct device *dev, - struct host1x_job_gather *g) +static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g) { - u32 *cmdbuf_base; + u32 *cmdbuf_base = (u32 *)fw->job->gather_copy_mapped + + (g->offset / sizeof(u32)); int err = 0; - struct host1x_firewall fw; - fw.job = job; - fw.dev = dev; - fw.reloc = job->relocarray; - fw.num_relocs = job->num_relocs; - fw.cmdbuf_id = g->bo; - - fw.offset = 0; - fw.class = 0; - - if (!job->is_addr_reg) + if (!fw->job->is_addr_reg) return 0; - cmdbuf_base = host1x_bo_mmap(g->bo); - if (!cmdbuf_base) - return -ENOMEM; + fw->words = g->words; + fw->cmdbuf_id = g->bo; + fw->offset = 0; - fw.words = g->words; - while (fw.words && !err) { - u32 word = cmdbuf_base[fw.offset]; + while (fw->words && !err) { + u32 word = cmdbuf_base[fw->offset]; u32 opcode = (word & 0xf0000000) >> 28; - fw.mask = 0; - fw.reg = 0; - fw.count = 0; - fw.words--; - fw.offset++; + fw->mask = 0; + fw->reg = 0; + fw->count = 0; + fw->words--; + fw->offset++; switch (opcode) { case 0: - fw.class = word >> 6 & 0x3ff; - fw.mask = word & 0x3f; - fw.reg = word >> 16 & 0xfff; - err = check_mask(&fw); + fw->class = word >> 6 & 0x3ff; + fw->mask = word & 0x3f; + fw->reg = word >> 16 & 0xfff; + err = check_mask(fw); if (err) goto out; break; case 1: - fw.reg = word >> 16 & 0xfff; - fw.count = word & 0xffff; - err = check_incr(&fw); + fw->reg = word >> 16 & 0xfff; + fw->count = word & 0xffff; + err = check_incr(fw); if (err) goto out; break; case 2: - fw.reg = word >> 16 & 0xfff; - fw.count = word & 0xffff; - err = check_nonincr(&fw); + fw->reg = word >> 16 & 0xfff; + fw->count = word & 0xffff; + err = check_nonincr(fw); if (err) goto out; break; case 3: - fw.mask = word & 0xffff; - fw.reg = word >> 16 & 0xfff; - err = check_mask(&fw); + fw->mask = word & 0xffff; + fw->reg = word >> 16 & 0xfff; + err = check_mask(fw); if (err) goto out; break; @@ -453,21 +437,26 @@ static int validate(struct host1x_job *job, struct device *dev, } /* No relocs should remain at this point */ - if (fw.num_relocs) + if (fw->num_relocs) err = -EINVAL; out: - host1x_bo_munmap(g->bo, cmdbuf_base); - return err; } static inline int copy_gathers(struct host1x_job *job, struct device *dev) { + struct host1x_firewall fw; size_t size = 0; size_t offset = 0; int i; + fw.job = job; + fw.dev = dev; + fw.reloc = job->relocarray; + fw.num_relocs = job->num_relocs; + fw.class = 0; + for (i = 0; i < job->num_gathers; i++) { struct host1x_job_gather *g = &job->gathers[i]; size += g->words * sizeof(u32); @@ -488,14 +477,19 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev) struct host1x_job_gather *g = &job->gathers[i]; void *gather; + /* Copy the gather */ gather = host1x_bo_mmap(g->bo); memcpy(job->gather_copy_mapped + offset, gather + g->offset, g->words * sizeof(u32)); host1x_bo_munmap(g->bo, gather); + /* Store the location in the buffer */ g->base = job->gather_copy; g->offset = offset; - g->bo = NULL; + + /* Validate the job */ + if (validate(&fw, g)) + return -EINVAL; offset += g->words * sizeof(u32); } @@ -540,20 +534,11 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev) if (job->gathers[j].bo == g->bo) job->gathers[j].handled = true; - err = 0; - - if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) - err = validate(job, dev, g); - + err = do_relocs(job, g->bo); if (err) - dev_err(dev, "Job invalid (err=%d)\n", err); - - if (!err) - err = do_relocs(job, g->bo); - - if (!err) - err = do_waitchks(job, host, g->bo); + break; + err = do_waitchks(job, host, g->bo); if (err) break; } diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index 4b493453e805..409745b949db 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -32,7 +32,7 @@ static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host, struct device *dev, - int client_managed) + bool client_managed) { int i; struct host1x_syncpt *sp = host->syncpt; @@ -40,7 +40,8 @@ static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host, for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++) ; - if (sp->dev) + + if (i >= host->info->nb_pts) return NULL; name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id, @@ -128,22 +129,11 @@ u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp) } /* - * Write a cpu syncpoint increment to the hardware, without touching - * the cache. Caller is responsible for host being powered. - */ -void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp) -{ - host1x_hw_syncpt_cpu_incr(sp->host, sp); -} - -/* * Increment syncpoint value from cpu, updating cache */ -void host1x_syncpt_incr(struct host1x_syncpt *sp) +int host1x_syncpt_incr(struct host1x_syncpt *sp) { - if (host1x_syncpt_client_managed(sp)) - host1x_syncpt_incr_max(sp, 1); - host1x_syncpt_cpu_incr(sp); + return host1x_hw_syncpt_cpu_incr(sp->host, sp); } /* @@ -331,7 +321,7 @@ int host1x_syncpt_init(struct host1x *host) host1x_syncpt_restore(host); /* Allocate sync point to use for clearing waits for expired fences */ - host->nop_sp = _host1x_syncpt_alloc(host, NULL, 0); + host->nop_sp = _host1x_syncpt_alloc(host, NULL, false); if (!host->nop_sp) return -ENOMEM; @@ -339,7 +329,7 @@ int host1x_syncpt_init(struct host1x *host) } struct host1x_syncpt *host1x_syncpt_request(struct device *dev, - int client_managed) + bool client_managed) { struct host1x *host = dev_get_drvdata(dev->parent); return _host1x_syncpt_alloc(host, dev, client_managed); @@ -353,7 +343,7 @@ void host1x_syncpt_free(struct host1x_syncpt *sp) kfree(sp->name); sp->dev = NULL; sp->name = NULL; - sp->client_managed = 0; + sp->client_managed = false; } void host1x_syncpt_deinit(struct host1x *host) diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h index c99806130f2e..267c0b9d3647 100644 --- a/drivers/gpu/host1x/syncpt.h +++ b/drivers/gpu/host1x/syncpt.h @@ -36,7 +36,7 @@ struct host1x_syncpt { atomic_t max_val; u32 base_val; const char *name; - int client_managed; + bool client_managed; struct host1x *host; struct device *dev; @@ -94,7 +94,7 @@ static inline bool host1x_syncpt_check_max(struct host1x_syncpt *sp, u32 real) } /* Return true if sync point is client managed. */ -static inline int host1x_syncpt_client_managed(struct host1x_syncpt *sp) +static inline bool host1x_syncpt_client_managed(struct host1x_syncpt *sp) { return sp->client_managed; } @@ -115,9 +115,6 @@ static inline bool host1x_syncpt_idle(struct host1x_syncpt *sp) /* Return pointer to struct denoting sync point id. */ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id); -/* Request incrementing a sync point. */ -void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp); - /* Load current value from hardware to the shadow register. */ u32 host1x_syncpt_load(struct host1x_syncpt *sp); @@ -133,8 +130,8 @@ void host1x_syncpt_restore(struct host1x *host); /* Read current wait base value into shadow register and return it. */ u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp); -/* Increment sync point and its max. */ -void host1x_syncpt_incr(struct host1x_syncpt *sp); +/* Request incrementing a sync point. */ +int host1x_syncpt_incr(struct host1x_syncpt *sp); /* Indicate future operations by incrementing the sync point max. */ u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs); @@ -157,7 +154,7 @@ u32 host1x_syncpt_id(struct host1x_syncpt *sp); /* Allocate a sync point for a device. */ struct host1x_syncpt *host1x_syncpt_request(struct device *dev, - int client_managed); + bool client_managed); /* Free a sync point. */ void host1x_syncpt_free(struct host1x_syncpt *sp); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index dc3ae5c56f56..d39a5cede0b0 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -264,9 +264,12 @@ static struct mt_class mt_classes[] = { static void mt_free_input_name(struct hid_input *hi) { struct hid_device *hdev = hi->report->device; + const char *name = hi->input->name; - if (hi->input->name != hdev->name) - kfree(hi->input->name); + if (name != hdev->name) { + hi->input->name = hdev->name; + kfree(name); + } } static ssize_t mt_show_quirks(struct device *dev, @@ -1040,11 +1043,11 @@ static void mt_remove(struct hid_device *hdev) struct hid_input *hi; sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); - hid_hw_stop(hdev); - list_for_each_entry(hi, &hdev->inputs, list) mt_free_input_name(hi); + hid_hw_stop(hdev); + kfree(td); hid_set_drvdata(hdev, NULL); } diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index bad8128b283a..21ef68934a20 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -329,7 +329,7 @@ static u32 get_vp_index(uuid_le *type_guid) return 0; } cur_cpu = (++next_vp % max_cpus); - return cur_cpu; + return hv_context.vp_index[cur_cpu]; } /* diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 7e76922a4ba9..f920619cd6da 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -331,26 +331,68 @@ static int adm1021_detect(struct i2c_client *client, man_id = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID); dev_id = i2c_smbus_read_byte_data(client, ADM1021_REG_DEV_ID); + if (man_id < 0 || dev_id < 0) + return -ENODEV; + if (man_id == 0x4d && dev_id == 0x01) type_name = "max1617a"; else if (man_id == 0x41) { if ((dev_id & 0xF0) == 0x30) type_name = "adm1023"; - else + else if ((dev_id & 0xF0) == 0x00) type_name = "adm1021"; + else + return -ENODEV; } else if (man_id == 0x49) type_name = "thmc10"; else if (man_id == 0x23) type_name = "gl523sm"; else if (man_id == 0x54) type_name = "mc1066"; - /* LM84 Mfr ID in a different place, and it has more unused bits */ - else if (conv_rate == 0x00 - && (config & 0x7F) == 0x00 - && (status & 0xAB) == 0x00) - type_name = "lm84"; - else - type_name = "max1617"; + else { + int lte, rte, lhi, rhi, llo, rlo; + + /* extra checks for LM84 and MAX1617 to avoid misdetections */ + + llo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(0)); + rlo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(1)); + + /* fail if any of the additional register reads failed */ + if (llo < 0 || rlo < 0) + return -ENODEV; + + lte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(0)); + rte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(1)); + lhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(0)); + rhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(1)); + + /* + * Fail for negative temperatures and negative high limits. + * This check also catches read errors on the tested registers. + */ + if ((s8)lte < 0 || (s8)rte < 0 || (s8)lhi < 0 || (s8)rhi < 0) + return -ENODEV; + + /* fail if all registers hold the same value */ + if (lte == rte && lte == lhi && lte == rhi && lte == llo + && lte == rlo) + return -ENODEV; + + /* + * LM84 Mfr ID is in a different place, + * and it has more unused bits. + */ + if (conv_rate == 0x00 + && (config & 0x7F) == 0x00 + && (status & 0xAB) == 0x00) { + type_name = "lm84"; + } else { + /* fail if low limits are larger than high limits */ + if ((s8)llo > lhi || (s8)rlo > rhi) + return -ENODEV; + type_name = "max1617"; + } + } pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n", type_name, i2c_adapter_id(adapter), client->addr); diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 21fbb340ad66..c41ca6354fc5 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -383,7 +383,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) /* Enable the adapter */ __i2c_dw_enable(dev, true); - /* Enable interrupts */ + /* Clear and enable interrupts */ + i2c_dw_clear_int(dev); dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK); } @@ -448,8 +449,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) cmd |= BIT(9); if (msgs[dev->msg_write_idx].flags & I2C_M_RD) { + + /* avoid rx buffer overrun */ + if (rx_limit - dev->rx_outstanding <= 0) + break; + dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD); rx_limit--; + dev->rx_outstanding++; } else dw_writel(dev, cmd | *buf++, DW_IC_DATA_CMD); tx_limit--; buf_len--; @@ -502,8 +509,10 @@ i2c_dw_read(struct dw_i2c_dev *dev) rx_valid = dw_readl(dev, DW_IC_RXFLR); - for (; len > 0 && rx_valid > 0; len--, rx_valid--) + for (; len > 0 && rx_valid > 0; len--, rx_valid--) { *buf++ = dw_readl(dev, DW_IC_DATA_CMD); + dev->rx_outstanding--; + } if (len > 0) { dev->status |= STATUS_READ_IN_PROGRESS; @@ -561,6 +570,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev->msg_err = 0; dev->status = STATUS_IDLE; dev->abort_source = 0; + dev->rx_outstanding = 0; ret = i2c_dw_wait_bus_not_busy(dev); if (ret < 0) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 9c1840ee09c7..e761ad18dd61 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -60,6 +60,7 @@ * @adapter: i2c subsystem adapter node * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo + * @rx_outstanding: current master-rx elements in tx fifo */ struct dw_i2c_dev { struct device *dev; @@ -88,6 +89,7 @@ struct dw_i2c_dev { u32 master_cfg; unsigned int tx_fifo_depth; unsigned int rx_fifo_depth; + int rx_outstanding; }; #define ACCESS_SWAP 0x00000001 diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 8ec91335d95a..35b70a1edf57 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -69,6 +69,7 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) static const struct acpi_device_id dw_i2c_acpi_match[] = { { "INT33C2", 0 }, { "INT33C3", 0 }, + { "80860F41", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e1cf2e0e1f23..3a6903f63913 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -231,7 +231,11 @@ static const char *i801_feature_names[] = { static unsigned int disable_features; module_param(disable_features, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(disable_features, "Disable selected driver features"); +MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" + "\t\t 0x01 disable SMBus PEC\n" + "\t\t 0x02 disable the block buffer\n" + "\t\t 0x08 disable the I2C block read functionality\n" + "\t\t 0x10 don't use interrupts "); /* Make sure the SMBus host is ready to start transmitting. Return 0 if it is, -EBUSY if it is not. */ diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 3bbd65d35a5e..1a3abd6a0bfc 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -252,7 +252,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) writel(drv_data->cntl_bits, drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); drv_data->block = 0; - wake_up_interruptible(&drv_data->waitq); + wake_up(&drv_data->waitq); break; case MV64XXX_I2C_ACTION_CONTINUE: @@ -300,7 +300,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); drv_data->block = 0; - wake_up_interruptible(&drv_data->waitq); + wake_up(&drv_data->waitq); break; case MV64XXX_I2C_ACTION_INVALID: @@ -315,7 +315,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); drv_data->block = 0; - wake_up_interruptible(&drv_data->waitq); + wake_up(&drv_data->waitq); break; } } @@ -381,7 +381,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) unsigned long flags; char abort = 0; - time_left = wait_event_interruptible_timeout(drv_data->waitq, + time_left = wait_event_timeout(drv_data->waitq, !drv_data->block, drv_data->adapter.timeout); spin_lock_irqsave(&drv_data->lock, flags); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 6b63cc7eb71e..48e31ed69dbf 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -892,7 +892,8 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device); -static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device); +static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL, + i2c_sysfs_delete_device); static struct attribute *i2c_adapter_attrs[] = { &dev_attr_name.attr, diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 9f3a8ef1fb3e..b3d03d335948 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -390,8 +390,8 @@ static int exynos_adc_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int exynos_adc_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct exynos_adc *info = platform_get_drvdata(pdev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct exynos_adc *info = iio_priv(indio_dev); u32 con; if (info->version == ADC_V2) { @@ -413,8 +413,8 @@ static int exynos_adc_suspend(struct device *dev) static int exynos_adc_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct exynos_adc *info = platform_get_drvdata(pdev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct exynos_adc *info = iio_priv(indio_dev); int ret; ret = regulator_enable(info->vdd); diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c index 9201022945e9..9d19ba74f22b 100644 --- a/drivers/iio/buffer_cb.c +++ b/drivers/iio/buffer_cb.c @@ -64,7 +64,7 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, while (chan->indio_dev) { if (chan->indio_dev != indio_dev) { ret = -EINVAL; - goto error_release_channels; + goto error_free_scan_mask; } set_bit(chan->channel->scan_index, cb_buff->buffer.scan_mask); @@ -73,6 +73,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, return cb_buff; +error_free_scan_mask: + kfree(cb_buff->buffer.scan_mask); error_release_channels: iio_channel_release_all(cb_buff->channels); error_free_cb_buff: @@ -100,6 +102,7 @@ EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb); void iio_channel_release_all_cb(struct iio_cb_buffer *cb_buff) { + kfree(cb_buff->buffer.scan_mask); iio_channel_release_all(cb_buff->channels); kfree(cb_buff); } diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index bd33473f8e38..ed9bc8ae9330 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -312,6 +312,8 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, goto read_error; *val = *val >> ch->scan_type.shift; + + err = st_sensors_set_enable(indio_dev, false); } mutex_unlock(&indio_dev->mlock); diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index f4a6f0838327..b61160bd935e 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -5,7 +5,7 @@ menu "Digital to analog converters" config AD5064 tristate "Analog Devices AD5064 and similar multi-channel DAC driver" - depends on (SPI_MASTER || I2C) + depends on (SPI_MASTER && I2C!=m) || I2C help Say yes here to build support for Analog Devices AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5629R, AD5648, AD5666, AD5668, @@ -27,7 +27,7 @@ config AD5360 config AD5380 tristate "Analog Devices AD5380/81/82/83/84/90/91/92 DAC driver" - depends on (SPI_MASTER || I2C) + depends on (SPI_MASTER && I2C!=m) || I2C select REGMAP_I2C if I2C select REGMAP_SPI if SPI_MASTER help @@ -57,7 +57,7 @@ config AD5624R_SPI config AD5446 tristate "Analog Devices AD5446 and similar single channel DACs driver" - depends on (SPI_MASTER || I2C) + depends on (SPI_MASTER && I2C!=m) || I2C help Say yes here to build support for Analog Devices AD5300, AD5301, AD5310, AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453, diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index a884252ac66b..e76d4ace53ff 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -212,7 +212,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq) (pdata->r2_user_settings & (ADF4350_REG2_PD_POLARITY_POS | ADF4350_REG2_LDP_6ns | ADF4350_REG2_LDF_INT_N | ADF4350_REG2_CHARGE_PUMP_CURR_uA(5000) | - ADF4350_REG2_MUXOUT(0x7) | ADF4350_REG2_NOISE_MODE(0x9))); + ADF4350_REG2_MUXOUT(0x7) | ADF4350_REG2_NOISE_MODE(0x3))); st->regs[ADF4350_REG3] = pdata->r3_user_settings & (ADF4350_REG3_12BIT_CLKDIV(0xFFF) | diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 795d100b4c36..98ddc323add0 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -124,7 +124,7 @@ static int __of_iio_channel_get(struct iio_channel *channel, channel->indio_dev = indio_dev; index = iiospec.args_count ? iiospec.args[0] : 0; if (index >= indio_dev->num_channels) { - return -EINVAL; + err = -EINVAL; goto err_put; } channel->channel = &indio_dev->channels[index]; @@ -450,7 +450,7 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, s64 raw64 = raw; int ret; - ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_SCALE); + ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET); if (ret == 0) raw64 += offset; diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c index 81c7b73695d2..3b9afccaaade 100644 --- a/drivers/infiniband/hw/qib/qib_keys.c +++ b/drivers/infiniband/hw/qib/qib_keys.c @@ -61,7 +61,7 @@ int qib_alloc_lkey(struct qib_mregion *mr, int dma_region) if (dma_region) { struct qib_mregion *tmr; - tmr = rcu_dereference(dev->dma_mr); + tmr = rcu_access_pointer(dev->dma_mr); if (!tmr) { qib_get_mr(mr); rcu_assign_pointer(dev->dma_mr, mr); diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index f19b0998a53c..2e84ef859c5b 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -5,6 +5,7 @@ * Copyright (C) 2004 Alex Aizman * Copyright (C) 2005 Mike Christie * Copyright (c) 2005, 2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2013 Mellanox Technologies. All rights reserved. * maintained by openib-general@openib.org * * This software is available to you under a choice of one of two diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 06f578cde75b..4f069c0d4c04 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -8,6 +8,7 @@ * * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved. * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2013 Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index a00ccd1ca333..b6d81a86c976 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2013 Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 68ebb7fe072a..7827baf455a1 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2013 Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 5278916c3103..2c4941d0656b 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved. * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2013 Mellanox Technologies. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -292,10 +293,10 @@ out_err: } /** - * releases the FMR pool, QP and CMA ID objects, returns 0 on success, + * releases the FMR pool and QP objects, returns 0 on success, * -1 on failure */ -static int iser_free_ib_conn_res(struct iser_conn *ib_conn, int can_destroy_id) +static int iser_free_ib_conn_res(struct iser_conn *ib_conn) { int cq_index; BUG_ON(ib_conn == NULL); @@ -314,13 +315,9 @@ static int iser_free_ib_conn_res(struct iser_conn *ib_conn, int can_destroy_id) rdma_destroy_qp(ib_conn->cma_id); } - /* if cma handler context, the caller acts s.t the cma destroy the id */ - if (ib_conn->cma_id != NULL && can_destroy_id) - rdma_destroy_id(ib_conn->cma_id); ib_conn->fmr_pool = NULL; ib_conn->qp = NULL; - ib_conn->cma_id = NULL; kfree(ib_conn->page_vec); if (ib_conn->login_buf) { @@ -415,11 +412,16 @@ static void iser_conn_release(struct iser_conn *ib_conn, int can_destroy_id) list_del(&ib_conn->conn_list); mutex_unlock(&ig.connlist_mutex); iser_free_rx_descriptors(ib_conn); - iser_free_ib_conn_res(ib_conn, can_destroy_id); + iser_free_ib_conn_res(ib_conn); ib_conn->device = NULL; /* on EVENT_ADDR_ERROR there's no device yet for this conn */ if (device != NULL) iser_device_try_release(device); + /* if cma handler context, the caller actually destroy the id */ + if (ib_conn->cma_id != NULL && can_destroy_id) { + rdma_destroy_id(ib_conn->cma_id); + ib_conn->cma_id = NULL; + } iscsi_destroy_endpoint(ib_conn->ep); } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index b08ca7a9f76b..3f3f0416fbdd 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2227,6 +2227,27 @@ static void srpt_close_ch(struct srpt_rdma_ch *ch) } /** + * srpt_shutdown_session() - Whether or not a session may be shut down. + */ +static int srpt_shutdown_session(struct se_session *se_sess) +{ + struct srpt_rdma_ch *ch = se_sess->fabric_sess_ptr; + unsigned long flags; + + spin_lock_irqsave(&ch->spinlock, flags); + if (ch->in_shutdown) { + spin_unlock_irqrestore(&ch->spinlock, flags); + return true; + } + + ch->in_shutdown = true; + target_sess_cmd_list_set_waiting(se_sess); + spin_unlock_irqrestore(&ch->spinlock, flags); + + return true; +} + +/** * srpt_drain_channel() - Drain a channel by resetting the IB queue pair. * @cm_id: Pointer to the CM ID of the channel to be drained. * @@ -2264,6 +2285,9 @@ static void srpt_drain_channel(struct ib_cm_id *cm_id) spin_unlock_irq(&sdev->spinlock); if (do_reset) { + if (ch->sess) + srpt_shutdown_session(ch->sess); + ret = srpt_ch_qp_err(ch); if (ret < 0) printk(KERN_ERR "Setting queue pair in error state" @@ -2328,7 +2352,7 @@ static void srpt_release_channel_work(struct work_struct *w) se_sess = ch->sess; BUG_ON(!se_sess); - target_wait_for_sess_cmds(se_sess, 0); + target_wait_for_sess_cmds(se_sess); transport_deregister_session_configfs(se_sess); transport_deregister_session(se_sess); @@ -3467,14 +3491,6 @@ static void srpt_release_cmd(struct se_cmd *se_cmd) } /** - * srpt_shutdown_session() - Whether or not a session may be shut down. - */ -static int srpt_shutdown_session(struct se_session *se_sess) -{ - return true; -} - -/** * srpt_close_session() - Forcibly close a session. * * Callback function invoked by the TCM core to clean up sessions associated diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 4caf55cda7b1..3dae156905de 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -325,6 +325,7 @@ struct srpt_rdma_ch { u8 sess_name[36]; struct work_struct release_work; struct completion *release_done; + bool in_shutdown; }; /** diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index d6cbfe9df218..fa061d46527f 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -137,7 +137,7 @@ static const struct xpad_device { { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX }, { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, - { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", XTYPE_XBOX360 }, + { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 62a2c0e4cc99..7ac9c9818d55 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -431,6 +431,7 @@ config KEYBOARD_TEGRA config KEYBOARD_OPENCORES tristate "OpenCores Keyboard Controller" + depends on HAS_IOMEM help Say Y here if you want to use the OpenCores Keyboard Controller http://www.opencores.org/project,keyboardcontroller diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 2f78538e09d0..b2420ae19e14 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -1379,6 +1379,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; struct synaptics_data old_priv = *priv; + unsigned char param[2]; int retry = 0; int error; @@ -1394,6 +1395,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) */ ssleep(1); } + ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETID); error = synaptics_detect(psmouse, 0); } while (error && ++retry < 3); diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index aebfe3ecb945..1bda828f4b55 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -205,6 +205,7 @@ config SERIO_XILINX_XPS_PS2 config SERIO_ALTERA_PS2 tristate "Altera UP PS/2 controller" + depends on HAS_IOMEM help Say Y here if you have Altera University Program PS/2 ports. diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 0bfd8cf25200..384fbcd0cee0 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -342,10 +342,10 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) wacom->id[idx] = (data[2] << 4) | (data[3] >> 4) | ((data[7] & 0x0f) << 20) | ((data[8] & 0xf0) << 12); - switch (wacom->id[idx] & 0xfffff) { + switch (wacom->id[idx]) { case 0x812: /* Inking pen */ case 0x801: /* Intuos3 Inking pen */ - case 0x20802: /* Intuos4 Inking Pen */ + case 0x120802: /* Intuos4/5 Inking Pen */ case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL; break; @@ -356,11 +356,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) case 0x823: /* Intuos3 Grip Pen */ case 0x813: /* Intuos3 Classic Pen */ case 0x885: /* Intuos3 Marker Pen */ - case 0x802: /* Intuos4 General Pen */ - case 0x804: /* Intuos4 Marker Pen */ - case 0x40802: /* Intuos4 Classic Pen */ - case 0x18802: /* DTH2242 Grip Pen */ + case 0x802: /* Intuos4/5 13HD/24HD General Pen */ + case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */ case 0x022: + case 0x100804: /* Intuos4/5 13HD/24HD Art Pen */ + case 0x140802: /* Intuos4/5 13HD/24HD Classic Pen */ + case 0x160802: /* Cintiq 13HD Pro Pen */ + case 0x180802: /* DTH2242 Pen */ + case 0x100802: /* Intuos4/5 13HD/24HD General Pen */ wacom->tool[idx] = BTN_TOOL_PEN; break; @@ -391,10 +394,15 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) case 0x82b: /* Intuos3 Grip Pen Eraser */ case 0x81b: /* Intuos3 Classic Pen Eraser */ case 0x91b: /* Intuos3 Airbrush Eraser */ - case 0x80c: /* Intuos4 Marker Pen Eraser */ - case 0x80a: /* Intuos4 General Pen Eraser */ - case 0x4080a: /* Intuos4 Classic Pen Eraser */ - case 0x90a: /* Intuos4 Airbrush Eraser */ + case 0x80c: /* Intuos4/5 13HD/24HD Marker Pen Eraser */ + case 0x80a: /* Intuos4/5 13HD/24HD General Pen Eraser */ + case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */ + case 0x14080a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */ + case 0x10090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */ + case 0x10080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */ + case 0x16080a: /* Cintiq 13HD Pro Pen Eraser */ + case 0x18080a: /* DTH2242 Eraser */ + case 0x10080a: /* Intuos4/5 13HD/24HD General Pen Eraser */ wacom->tool[idx] = BTN_TOOL_RUBBER; break; @@ -402,7 +410,8 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) case 0x912: case 0x112: case 0x913: /* Intuos3 Airbrush */ - case 0x902: /* Intuos4 Airbrush */ + case 0x902: /* Intuos4/5 13HD/24HD Airbrush */ + case 0x100902: /* Intuos4/5 13HD/24HD Airbrush */ wacom->tool[idx] = BTN_TOOL_AIRBRUSH; break; @@ -533,10 +542,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) input_report_key(input, BTN_8, (data[3] & 0x80)); } if (data[1] | (data[2] & 0x01) | data[3]) { - input_report_key(input, wacom->tool[1], 1); input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); } else { - input_report_key(input, wacom->tool[1], 0); input_report_abs(input, ABS_MISC, 0); } } else if (features->type == DTK) { @@ -546,6 +553,26 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) input_report_key(input, BTN_3, (data[6] & 0x08)); input_report_key(input, BTN_4, (data[6] & 0x10)); input_report_key(input, BTN_5, (data[6] & 0x20)); + if (data[6] & 0x3f) { + input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); + } else { + input_report_abs(input, ABS_MISC, 0); + } + } else if (features->type == WACOM_13HD) { + input_report_key(input, BTN_0, (data[3] & 0x01)); + input_report_key(input, BTN_1, (data[4] & 0x01)); + input_report_key(input, BTN_2, (data[4] & 0x02)); + input_report_key(input, BTN_3, (data[4] & 0x04)); + input_report_key(input, BTN_4, (data[4] & 0x08)); + input_report_key(input, BTN_5, (data[4] & 0x10)); + input_report_key(input, BTN_6, (data[4] & 0x20)); + input_report_key(input, BTN_7, (data[4] & 0x40)); + input_report_key(input, BTN_8, (data[4] & 0x80)); + if ((data[3] & 0x01) | data[4]) { + input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); + } else { + input_report_abs(input, ABS_MISC, 0); + } } else if (features->type == WACOM_24HD) { input_report_key(input, BTN_0, (data[6] & 0x01)); input_report_key(input, BTN_1, (data[6] & 0x02)); @@ -590,10 +617,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) } if (data[1] | data[2] | (data[3] & 0x1f) | data[4] | data[6] | data[8]) { - input_report_key(input, wacom->tool[1], 1); input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); } else { - input_report_key(input, wacom->tool[1], 0); input_report_abs(input, ABS_MISC, 0); } } else if (features->type >= INTUOS5S && features->type <= INTUOS5L) { @@ -618,10 +643,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) } if (data[2] | (data[3] & 0x01) | data[4] | data[5]) { - input_report_key(input, wacom->tool[1], 1); input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); } else { - input_report_key(input, wacom->tool[1], 0); input_report_abs(input, ABS_MISC, 0); } } else { @@ -668,10 +691,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) if ((data[5] & 0x1f) | data[6] | (data[1] & 0x1f) | data[2] | (data[3] & 0x1f) | data[4] | data[8] | (data[7] & 0x01)) { - input_report_key(input, wacom->tool[1], 1); input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); } else { - input_report_key(input, wacom->tool[1], 0); input_report_abs(input, ABS_MISC, 0); } } @@ -1301,6 +1322,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) case INTUOS4L: case CINTIQ: case WACOM_BEE: + case WACOM_13HD: case WACOM_21UX2: case WACOM_22HD: case WACOM_24HD: @@ -1530,15 +1552,15 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, __set_bit(KEY_PROG1, input_dev->keybit); __set_bit(KEY_PROG2, input_dev->keybit); __set_bit(KEY_PROG3, input_dev->keybit); + + input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); + input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); /* fall through */ case DTK: for (i = 0; i < 6; i++) __set_bit(BTN_0 + i, input_dev->keybit); - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); wacom_setup_cintiq(wacom_wac); @@ -1579,6 +1601,15 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, wacom_setup_cintiq(wacom_wac); break; + case WACOM_13HD: + for (i = 0; i < 9; i++) + __set_bit(BTN_0 + i, input_dev->keybit); + + input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + wacom_setup_cintiq(wacom_wac); + break; + case INTUOS3: case INTUOS3L: __set_bit(BTN_4, input_dev->keybit); @@ -1937,7 +1968,8 @@ static const struct wacom_features wacom_features_0xF4 = 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xF8 = { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, /* Pen */ - 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 }; + 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 }; static const struct wacom_features wacom_features_0xF6 = { "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10 }; @@ -1950,6 +1982,9 @@ static const struct wacom_features wacom_features_0xC5 = static const struct wacom_features wacom_features_0xC6 = { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +static const struct wacom_features wacom_features_0x304 = + { "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 59552, 33848, 1023, + 63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xC7 = { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1959,6 +1994,9 @@ static const struct wacom_features wacom_features_0xCE = static const struct wacom_features wacom_features_0xF0 = { "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, 0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0x57 = + { "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047, + 63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES}; static const struct wacom_features wacom_features_0x59 = /* Pen */ { "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047, 63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, @@ -1972,6 +2010,13 @@ static const struct wacom_features wacom_features_0xCC = static const struct wacom_features wacom_features_0xFA = { "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047, 63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +static const struct wacom_features wacom_features_0x5B = + { "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047, + 63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e }; +static const struct wacom_features wacom_features_0x5E = + { "Wacom Cintiq 22HDT", .type = WACOM_24HDT, + .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5b, .touch_max = 10 }; static const struct wacom_features wacom_features_0x90 = { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -2001,7 +2046,7 @@ static const struct wacom_features wacom_features_0xE5 = static const struct wacom_features wacom_features_0xE6 = { "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES, - .touch_max = 2 }; + .touch_max = 2 }; static const struct wacom_features wacom_features_0xEC = { "Wacom ISDv4 EC", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -2143,8 +2188,11 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x43) }, { USB_DEVICE_WACOM(0x44) }, { USB_DEVICE_WACOM(0x45) }, + { USB_DEVICE_WACOM(0x57) }, { USB_DEVICE_WACOM(0x59) }, { USB_DEVICE_DETAILED(0x5D, USB_CLASS_HID, 0, 0) }, + { USB_DEVICE_WACOM(0x5B) }, + { USB_DEVICE_DETAILED(0x5E, USB_CLASS_HID, 0, 0) }, { USB_DEVICE_WACOM(0xB0) }, { USB_DEVICE_WACOM(0xB1) }, { USB_DEVICE_WACOM(0xB2) }, @@ -2205,6 +2253,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x100) }, { USB_DEVICE_WACOM(0x101) }, { USB_DEVICE_WACOM(0x10D) }, + { USB_DEVICE_WACOM(0x304) }, { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x47) }, { USB_DEVICE_WACOM(0xF4) }, diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index 5f9a7721e16c..dfc9e08e7f70 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -82,6 +82,7 @@ enum { WACOM_24HD, CINTIQ, WACOM_BEE, + WACOM_13HD, WACOM_MO, WIRELESS, BAMBOO_PT, diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index 8e60437ac85b..ae89d2609ab0 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c @@ -116,6 +116,15 @@ static int ttsp_send_command(struct cyttsp *ts, u8 cmd) return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd); } +static int cyttsp_handshake(struct cyttsp *ts) +{ + if (ts->pdata->use_hndshk) + return ttsp_send_command(ts, + ts->xy_data.hst_mode ^ CY_HNDSHK_BIT); + + return 0; +} + static int cyttsp_load_bl_regs(struct cyttsp *ts) { memset(&ts->bl_data, 0, sizeof(ts->bl_data)); @@ -133,7 +142,7 @@ static int cyttsp_exit_bl_mode(struct cyttsp *ts) memcpy(bl_cmd, bl_command, sizeof(bl_command)); if (ts->pdata->bl_keys) memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS], - ts->pdata->bl_keys, sizeof(bl_command)); + ts->pdata->bl_keys, CY_NUM_BL_KEYS); error = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(bl_cmd), bl_cmd); @@ -167,6 +176,10 @@ static int cyttsp_set_operational_mode(struct cyttsp *ts) if (error) return error; + error = cyttsp_handshake(ts); + if (error) + return error; + return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0; } @@ -188,6 +201,10 @@ static int cyttsp_set_sysinfo_mode(struct cyttsp *ts) if (error) return error; + error = cyttsp_handshake(ts); + if (error) + return error; + if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl) return -EIO; @@ -344,12 +361,9 @@ static irqreturn_t cyttsp_irq(int irq, void *handle) goto out; /* provide flow control handshake */ - if (ts->pdata->use_hndshk) { - error = ttsp_send_command(ts, - ts->xy_data.hst_mode ^ CY_HNDSHK_BIT); - if (error) - goto out; - } + error = cyttsp_handshake(ts); + if (error) + goto out; if (unlikely(ts->state == CY_IDLE_STATE)) goto out; diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h index 1aa3c6967e70..f1ebde369f86 100644 --- a/drivers/input/touchscreen/cyttsp_core.h +++ b/drivers/input/touchscreen/cyttsp_core.h @@ -67,8 +67,8 @@ struct cyttsp_xydata { /* TTSP System Information interface definition */ struct cyttsp_sysinfo_data { u8 hst_mode; - u8 mfg_cmd; u8 mfg_stat; + u8 mfg_cmd; u8 cid[3]; u8 tt_undef1; u8 uid[8]; diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 17c9097f3b5d..39f3df8670c3 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -216,7 +216,7 @@ static int egalax_ts_probe(struct i2c_client *client, input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0); input_set_abs_params(input_dev, - ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0); + ABS_MT_POSITION_Y, 0, EGALAX_MAX_Y, 0, 0); input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0); input_set_drvdata(input_dev, ts); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 1760ceb68b7b..19ceaa60e0f4 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -705,7 +705,7 @@ static int gic_irq_domain_xlate(struct irq_domain *d, static int __cpuinit gic_secondary_init(struct notifier_block *nfb, unsigned long action, void *hcpu) { - if (action == CPU_STARTING) + if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) gic_cpu_init(&gic_data[0]); return NOTIFY_OK; } diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index 29889bbdcc6d..63b3d4eb0ef7 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -76,16 +76,10 @@ asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs) { u32 irqnr; - do { - irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET); - if (irqnr != 0x7f) { - __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR); - irqnr = irq_find_mapping(icoll_domain, irqnr); - handle_IRQ(irqnr, regs); - continue; - } - break; - } while (1); + irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET); + __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR); + irqnr = irq_find_mapping(icoll_domain, irqnr); + handle_IRQ(irqnr, regs); } static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq, diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 065b7a31a478..47a52ab580d8 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -119,7 +119,7 @@ static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq, /* Skip invalid IRQs, only register handlers for the real ones */ if (!(f->valid & BIT(hwirq))) - return -ENOTSUPP; + return -EPERM; irq_set_chip_data(irq, f); irq_set_chip_and_handler(irq, &f->chip, handle_level_irq); diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 884d11c7355f..2bbb00404cf5 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -197,7 +197,7 @@ static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq, /* Skip invalid IRQs, only register handlers for the real ones */ if (!(v->valid_sources & (1 << hwirq))) - return -ENOTSUPP; + return -EPERM; irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq); irq_set_chip_data(irq, v->base); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 9b1b274c7d25..c123709acf82 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -93,7 +93,7 @@ capi_ctr_put(struct capi_ctr *ctr) static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr) { - if (contr - 1 >= CAPI_MAXCONTR) + if (contr < 1 || contr - 1 >= CAPI_MAXCONTR) return NULL; return capi_controller[contr - 1]; @@ -103,7 +103,7 @@ static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid) { lockdep_assert_held(&capi_controller_lock); - if (applid - 1 >= CAPI_MAXAPPL) + if (applid < 1 || applid - 1 >= CAPI_MAXAPPL) return NULL; return capi_applications[applid - 1]; @@ -111,7 +111,7 @@ static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid) static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid) { - if (applid - 1 >= CAPI_MAXAPPL) + if (applid < 1 || applid - 1 >= CAPI_MAXAPPL) return NULL; return rcu_dereference(capi_applications[applid - 1]); diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index a0d931bcb37c..b02b679abf31 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -107,6 +107,10 @@ static int create_gpio_led(const struct gpio_led *template, return 0; } + ret = devm_gpio_request(parent, template->gpio, template->name); + if (ret < 0) + return ret; + led_dat->cdev.name = template->name; led_dat->cdev.default_trigger = template->default_trigger; led_dat->gpio = template->gpio; @@ -126,10 +130,7 @@ static int create_gpio_led(const struct gpio_led *template, if (!template->retain_state_suspended) led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; - ret = devm_gpio_request_one(parent, template->gpio, - (led_dat->active_low ^ state) ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, - template->name); + ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state); if (ret < 0) return ret; diff --git a/drivers/leds/leds-ot200.c b/drivers/leds/leds-ot200.c index ee14662ed5ce..98cae529373f 100644 --- a/drivers/leds/leds-ot200.c +++ b/drivers/leds/leds-ot200.c @@ -47,37 +47,37 @@ static struct ot200_led leds[] = { { .name = "led_1", .port = 0x49, - .mask = BIT(7), + .mask = BIT(6), }, { .name = "led_2", .port = 0x49, - .mask = BIT(6), + .mask = BIT(5), }, { .name = "led_3", .port = 0x49, - .mask = BIT(5), + .mask = BIT(4), }, { .name = "led_4", .port = 0x49, - .mask = BIT(4), + .mask = BIT(3), }, { .name = "led_5", .port = 0x49, - .mask = BIT(3), + .mask = BIT(2), }, { .name = "led_6", .port = 0x49, - .mask = BIT(2), + .mask = BIT(1), }, { .name = "led_7", .port = 0x49, - .mask = BIT(1), + .mask = BIT(0), } }; diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig index 05c220d05e23..f950c9d29f3e 100644 --- a/drivers/md/bcache/Kconfig +++ b/drivers/md/bcache/Kconfig @@ -1,7 +1,6 @@ config BCACHE tristate "Block device as cache" - select CLOSURES ---help--- Allows a block device to be used as cache for other devices; uses a btree for indexing and the layout is optimized for SSDs. diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 340146d7c17f..d3e15b42a4ab 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -1241,7 +1241,7 @@ void bch_cache_set_stop(struct cache_set *); struct cache_set *bch_cache_set_alloc(struct cache_sb *); void bch_btree_cache_free(struct cache_set *); int bch_btree_cache_alloc(struct cache_set *); -void bch_writeback_init_cached_dev(struct cached_dev *); +void bch_cached_dev_writeback_init(struct cached_dev *); void bch_moving_init_cache_set(struct cache_set *); void bch_cache_allocator_exit(struct cache *ca); diff --git a/drivers/md/bcache/stats.c b/drivers/md/bcache/stats.c index 64e679449c2a..b8730e714d69 100644 --- a/drivers/md/bcache/stats.c +++ b/drivers/md/bcache/stats.c @@ -93,24 +93,6 @@ static struct attribute *bch_stats_files[] = { }; static KTYPE(bch_stats); -static void scale_accounting(unsigned long data); - -void bch_cache_accounting_init(struct cache_accounting *acc, - struct closure *parent) -{ - kobject_init(&acc->total.kobj, &bch_stats_ktype); - kobject_init(&acc->five_minute.kobj, &bch_stats_ktype); - kobject_init(&acc->hour.kobj, &bch_stats_ktype); - kobject_init(&acc->day.kobj, &bch_stats_ktype); - - closure_init(&acc->cl, parent); - init_timer(&acc->timer); - acc->timer.expires = jiffies + accounting_delay; - acc->timer.data = (unsigned long) acc; - acc->timer.function = scale_accounting; - add_timer(&acc->timer); -} - int bch_cache_accounting_add_kobjs(struct cache_accounting *acc, struct kobject *parent) { @@ -244,3 +226,19 @@ void bch_mark_sectors_bypassed(struct search *s, int sectors) atomic_add(sectors, &dc->accounting.collector.sectors_bypassed); atomic_add(sectors, &s->op.c->accounting.collector.sectors_bypassed); } + +void bch_cache_accounting_init(struct cache_accounting *acc, + struct closure *parent) +{ + kobject_init(&acc->total.kobj, &bch_stats_ktype); + kobject_init(&acc->five_minute.kobj, &bch_stats_ktype); + kobject_init(&acc->hour.kobj, &bch_stats_ktype); + kobject_init(&acc->day.kobj, &bch_stats_ktype); + + closure_init(&acc->cl, parent); + init_timer(&acc->timer); + acc->timer.expires = jiffies + accounting_delay; + acc->timer.data = (unsigned long) acc; + acc->timer.function = scale_accounting; + add_timer(&acc->timer); +} diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index c8046bc4aa57..f88e2b653a3f 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -634,11 +634,10 @@ static int open_dev(struct block_device *b, fmode_t mode) return 0; } -static int release_dev(struct gendisk *b, fmode_t mode) +static void release_dev(struct gendisk *b, fmode_t mode) { struct bcache_device *d = b->private_data; closure_put(&d->cl); - return 0; } static int ioctl_dev(struct block_device *b, fmode_t mode, @@ -732,8 +731,7 @@ static void bcache_device_free(struct bcache_device *d) if (d->c) bcache_device_detach(d); - - if (d->disk) + if (d->disk && d->disk->flags & GENHD_FL_UP) del_gendisk(d->disk); if (d->disk && d->disk->queue) blk_cleanup_queue(d->disk->queue); @@ -756,12 +754,9 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size) if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio))) || !(d->unaligned_bvec = mempool_create_kmalloc_pool(1, sizeof(struct bio_vec) * BIO_MAX_PAGES)) || - bio_split_pool_init(&d->bio_split_hook)) - - return -ENOMEM; - - d->disk = alloc_disk(1); - if (!d->disk) + bio_split_pool_init(&d->bio_split_hook) || + !(d->disk = alloc_disk(1)) || + !(q = blk_alloc_queue(GFP_KERNEL))) return -ENOMEM; snprintf(d->disk->disk_name, DISK_NAME_LEN, "bcache%i", bcache_minor); @@ -771,10 +766,6 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size) d->disk->fops = &bcache_ops; d->disk->private_data = d; - q = blk_alloc_queue(GFP_KERNEL); - if (!q) - return -ENOMEM; - blk_queue_make_request(q, NULL); d->disk->queue = q; q->queuedata = d; @@ -999,14 +990,17 @@ static void cached_dev_free(struct closure *cl) mutex_lock(&bch_register_lock); - bd_unlink_disk_holder(dc->bdev, dc->disk.disk); + if (atomic_read(&dc->running)) + bd_unlink_disk_holder(dc->bdev, dc->disk.disk); bcache_device_free(&dc->disk); list_del(&dc->list); mutex_unlock(&bch_register_lock); if (!IS_ERR_OR_NULL(dc->bdev)) { - blk_sync_queue(bdev_get_queue(dc->bdev)); + if (dc->bdev->bd_disk) + blk_sync_queue(bdev_get_queue(dc->bdev)); + blkdev_put(dc->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); } @@ -1028,73 +1022,67 @@ static void cached_dev_flush(struct closure *cl) static int cached_dev_init(struct cached_dev *dc, unsigned block_size) { - int err; + int ret; struct io *io; - - closure_init(&dc->disk.cl, NULL); - set_closure_fn(&dc->disk.cl, cached_dev_flush, system_wq); + struct request_queue *q = bdev_get_queue(dc->bdev); __module_get(THIS_MODULE); INIT_LIST_HEAD(&dc->list); + closure_init(&dc->disk.cl, NULL); + set_closure_fn(&dc->disk.cl, cached_dev_flush, system_wq); kobject_init(&dc->disk.kobj, &bch_cached_dev_ktype); - - bch_cache_accounting_init(&dc->accounting, &dc->disk.cl); - - err = bcache_device_init(&dc->disk, block_size); - if (err) - goto err; - - spin_lock_init(&dc->io_lock); - closure_init_unlocked(&dc->sb_write); INIT_WORK(&dc->detach, cached_dev_detach_finish); + closure_init_unlocked(&dc->sb_write); + INIT_LIST_HEAD(&dc->io_lru); + spin_lock_init(&dc->io_lock); + bch_cache_accounting_init(&dc->accounting, &dc->disk.cl); dc->sequential_merge = true; dc->sequential_cutoff = 4 << 20; - INIT_LIST_HEAD(&dc->io_lru); - dc->sb_bio.bi_max_vecs = 1; - dc->sb_bio.bi_io_vec = dc->sb_bio.bi_inline_vecs; - for (io = dc->io; io < dc->io + RECENT_IO; io++) { list_add(&io->lru, &dc->io_lru); hlist_add_head(&io->hash, dc->io_hash + RECENT_IO); } - bch_writeback_init_cached_dev(dc); + ret = bcache_device_init(&dc->disk, block_size); + if (ret) + return ret; + + set_capacity(dc->disk.disk, + dc->bdev->bd_part->nr_sects - dc->sb.data_offset); + + dc->disk.disk->queue->backing_dev_info.ra_pages = + max(dc->disk.disk->queue->backing_dev_info.ra_pages, + q->backing_dev_info.ra_pages); + + bch_cached_dev_request_init(dc); + bch_cached_dev_writeback_init(dc); return 0; -err: - bcache_device_stop(&dc->disk); - return err; } /* Cached device - bcache superblock */ -static const char *register_bdev(struct cache_sb *sb, struct page *sb_page, +static void register_bdev(struct cache_sb *sb, struct page *sb_page, struct block_device *bdev, struct cached_dev *dc) { char name[BDEVNAME_SIZE]; const char *err = "cannot allocate memory"; - struct gendisk *g; struct cache_set *c; - if (!dc || cached_dev_init(dc, sb->block_size << 9) != 0) - return err; - memcpy(&dc->sb, sb, sizeof(struct cache_sb)); - dc->sb_bio.bi_io_vec[0].bv_page = sb_page; dc->bdev = bdev; dc->bdev->bd_holder = dc; - g = dc->disk.disk; - - set_capacity(g, dc->bdev->bd_part->nr_sects - dc->sb.data_offset); - - g->queue->backing_dev_info.ra_pages = - max(g->queue->backing_dev_info.ra_pages, - bdev->bd_queue->backing_dev_info.ra_pages); + bio_init(&dc->sb_bio); + dc->sb_bio.bi_max_vecs = 1; + dc->sb_bio.bi_io_vec = dc->sb_bio.bi_inline_vecs; + dc->sb_bio.bi_io_vec[0].bv_page = sb_page; + get_page(sb_page); - bch_cached_dev_request_init(dc); + if (cached_dev_init(dc, sb->block_size << 9)) + goto err; err = "error creating kobject"; if (kobject_add(&dc->disk.kobj, &part_to_dev(bdev->bd_part)->kobj, @@ -1103,6 +1091,8 @@ static const char *register_bdev(struct cache_sb *sb, struct page *sb_page, if (bch_cache_accounting_add_kobjs(&dc->accounting, &dc->disk.kobj)) goto err; + pr_info("registered backing device %s", bdevname(bdev, name)); + list_add(&dc->list, &uncached_devices); list_for_each_entry(c, &bch_cache_sets, list) bch_cached_dev_attach(dc, c); @@ -1111,15 +1101,10 @@ static const char *register_bdev(struct cache_sb *sb, struct page *sb_page, BDEV_STATE(&dc->sb) == BDEV_STATE_STALE) bch_cached_dev_run(dc); - return NULL; + return; err: - kobject_put(&dc->disk.kobj); pr_notice("error opening %s: %s", bdevname(bdev, name), err); - /* - * Return NULL instead of an error because kobject_put() cleans - * everything up - */ - return NULL; + bcache_device_stop(&dc->disk); } /* Flash only volumes */ @@ -1717,20 +1702,11 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca) size_t free; struct bucket *b; - if (!ca) - return -ENOMEM; - __module_get(THIS_MODULE); kobject_init(&ca->kobj, &bch_cache_ktype); - memcpy(&ca->sb, sb, sizeof(struct cache_sb)); - INIT_LIST_HEAD(&ca->discards); - bio_init(&ca->sb_bio); - ca->sb_bio.bi_max_vecs = 1; - ca->sb_bio.bi_io_vec = ca->sb_bio.bi_inline_vecs; - bio_init(&ca->journal.bio); ca->journal.bio.bi_max_vecs = 8; ca->journal.bio.bi_io_vec = ca->journal.bio.bi_inline_vecs; @@ -1742,18 +1718,17 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca) !init_fifo(&ca->free_inc, free << 2, GFP_KERNEL) || !init_fifo(&ca->unused, free << 2, GFP_KERNEL) || !init_heap(&ca->heap, free << 3, GFP_KERNEL) || - !(ca->buckets = vmalloc(sizeof(struct bucket) * + !(ca->buckets = vzalloc(sizeof(struct bucket) * ca->sb.nbuckets)) || !(ca->prio_buckets = kzalloc(sizeof(uint64_t) * prio_buckets(ca) * 2, GFP_KERNEL)) || !(ca->disk_buckets = alloc_bucket_pages(GFP_KERNEL, ca)) || !(ca->alloc_workqueue = alloc_workqueue("bch_allocator", 0, 1)) || bio_split_pool_init(&ca->bio_split_hook)) - goto err; + return -ENOMEM; ca->prio_last_buckets = ca->prio_buckets + prio_buckets(ca); - memset(ca->buckets, 0, ca->sb.nbuckets * sizeof(struct bucket)); for_each_bucket(b, ca) atomic_set(&b->pin, 0); @@ -1766,22 +1741,28 @@ err: return -ENOMEM; } -static const char *register_cache(struct cache_sb *sb, struct page *sb_page, +static void register_cache(struct cache_sb *sb, struct page *sb_page, struct block_device *bdev, struct cache *ca) { char name[BDEVNAME_SIZE]; const char *err = "cannot allocate memory"; - if (cache_alloc(sb, ca) != 0) - return err; - - ca->sb_bio.bi_io_vec[0].bv_page = sb_page; + memcpy(&ca->sb, sb, sizeof(struct cache_sb)); ca->bdev = bdev; ca->bdev->bd_holder = ca; + bio_init(&ca->sb_bio); + ca->sb_bio.bi_max_vecs = 1; + ca->sb_bio.bi_io_vec = ca->sb_bio.bi_inline_vecs; + ca->sb_bio.bi_io_vec[0].bv_page = sb_page; + get_page(sb_page); + if (blk_queue_discard(bdev_get_queue(ca->bdev))) ca->discard = CACHE_DISCARD(&ca->sb); + if (cache_alloc(sb, ca) != 0) + goto err; + err = "error creating kobject"; if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache")) goto err; @@ -1791,15 +1772,10 @@ static const char *register_cache(struct cache_sb *sb, struct page *sb_page, goto err; pr_info("registered cache device %s", bdevname(bdev, name)); - - return NULL; + return; err: + pr_notice("error opening %s: %s", bdevname(bdev, name), err); kobject_put(&ca->kobj); - pr_info("error opening %s: %s", bdevname(bdev, name), err); - /* Return NULL instead of an error because kobject_put() cleans - * everything up - */ - return NULL; } /* Global interfaces/init */ @@ -1833,12 +1809,15 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, bdev = blkdev_get_by_path(strim(path), FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); - if (bdev == ERR_PTR(-EBUSY)) - err = "device busy"; - - if (IS_ERR(bdev) || - set_blocksize(bdev, 4096)) + if (IS_ERR(bdev)) { + if (bdev == ERR_PTR(-EBUSY)) + err = "device busy"; goto err; + } + + err = "failed to set blocksize"; + if (set_blocksize(bdev, 4096)) + goto err_close; err = read_super(sb, bdev, &sb_page); if (err) @@ -1846,33 +1825,33 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, if (SB_IS_BDEV(sb)) { struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL); + if (!dc) + goto err_close; - err = register_bdev(sb, sb_page, bdev, dc); + register_bdev(sb, sb_page, bdev, dc); } else { struct cache *ca = kzalloc(sizeof(*ca), GFP_KERNEL); + if (!ca) + goto err_close; - err = register_cache(sb, sb_page, bdev, ca); + register_cache(sb, sb_page, bdev, ca); } - - if (err) { - /* register_(bdev|cache) will only return an error if they - * didn't get far enough to create the kobject - if they did, - * the kobject destructor will do this cleanup. - */ +out: + if (sb_page) put_page(sb_page); -err_close: - blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); -err: - if (attr != &ksysfs_register_quiet) - pr_info("error opening %s: %s", path, err); - ret = -EINVAL; - } - kfree(sb); kfree(path); mutex_unlock(&bch_register_lock); module_put(THIS_MODULE); return ret; + +err_close: + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); +err: + if (attr != &ksysfs_register_quiet) + pr_info("error opening %s: %s", path, err); + ret = -EINVAL; + goto out; } static int bcache_reboot(struct notifier_block *n, unsigned long code, void *x) diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 93e7e31a4bd3..2714ed3991d1 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -375,7 +375,7 @@ err: refill_dirty(cl); } -void bch_writeback_init_cached_dev(struct cached_dev *dc) +void bch_cached_dev_writeback_init(struct cached_dev *dc) { closure_init_unlocked(&dc->writeback); init_rwsem(&dc->writeback_lock); diff --git a/drivers/md/md.c b/drivers/md/md.c index 681d1099a2d5..9b82377a833b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5268,8 +5268,8 @@ static void md_clean(struct mddev *mddev) static void __md_stop_writes(struct mddev *mddev) { + set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); if (mddev->sync_thread) { - set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); set_bit(MD_RECOVERY_INTR, &mddev->recovery); md_reap_sync_thread(mddev); } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 55951182af73..6e17f8181c4b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -417,7 +417,17 @@ static void raid1_end_write_request(struct bio *bio, int error) r1_bio->bios[mirror] = NULL; to_put = bio; - set_bit(R1BIO_Uptodate, &r1_bio->state); + /* + * Do not set R1BIO_Uptodate if the current device is + * rebuilding or Faulty. This is because we cannot use + * such device for properly reading the data back (we could + * potentially use it, if the current write would have felt + * before rdev->recovery_offset, but for simplicity we don't + * check this here. + */ + if (test_bit(In_sync, &conf->mirrors[mirror].rdev->flags) && + !test_bit(Faulty, &conf->mirrors[mirror].rdev->flags)) + set_bit(R1BIO_Uptodate, &r1_bio->state); /* Maybe we can clear some bad blocks. */ if (is_badblock(conf->mirrors[mirror].rdev, @@ -870,17 +880,17 @@ static void allow_barrier(struct r1conf *conf) wake_up(&conf->wait_barrier); } -static void freeze_array(struct r1conf *conf) +static void freeze_array(struct r1conf *conf, int extra) { /* stop syncio and normal IO and wait for everything to * go quite. * We increment barrier and nr_waiting, and then - * wait until nr_pending match nr_queued+1 + * wait until nr_pending match nr_queued+extra * This is called in the context of one normal IO request * that has failed. Thus any sync request that might be pending * will be blocked by nr_pending, and we need to wait for * pending IO requests to complete or be queued for re-try. - * Thus the number queued (nr_queued) plus this request (1) + * Thus the number queued (nr_queued) plus this request (extra) * must match the number of pending IOs (nr_pending) before * we continue. */ @@ -888,7 +898,7 @@ static void freeze_array(struct r1conf *conf) conf->barrier++; conf->nr_waiting++; wait_event_lock_irq_cmd(conf->wait_barrier, - conf->nr_pending == conf->nr_queued+1, + conf->nr_pending == conf->nr_queued+extra, conf->resync_lock, flush_pending_writes(conf)); spin_unlock_irq(&conf->resync_lock); @@ -1544,8 +1554,8 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) * we wait for all outstanding requests to complete. */ synchronize_sched(); - raise_barrier(conf); - lower_barrier(conf); + freeze_array(conf, 0); + unfreeze_array(conf); clear_bit(Unmerged, &rdev->flags); } md_integrity_add_rdev(rdev, mddev); @@ -1595,11 +1605,11 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) */ struct md_rdev *repl = conf->mirrors[conf->raid_disks + number].rdev; - raise_barrier(conf); + freeze_array(conf, 0); clear_bit(Replacement, &repl->flags); p->rdev = repl; conf->mirrors[conf->raid_disks + number].rdev = NULL; - lower_barrier(conf); + unfreeze_array(conf); clear_bit(WantReplacement, &rdev->flags); } else clear_bit(WantReplacement, &rdev->flags); @@ -2195,7 +2205,7 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio) * frozen */ if (mddev->ro == 0) { - freeze_array(conf); + freeze_array(conf, 1); fix_read_error(conf, r1_bio->read_disk, r1_bio->sector, r1_bio->sectors); unfreeze_array(conf); @@ -2780,8 +2790,8 @@ static int run(struct mddev *mddev) return PTR_ERR(conf); if (mddev->queue) - blk_queue_max_write_same_sectors(mddev->queue, - mddev->chunk_sectors); + blk_queue_max_write_same_sectors(mddev->queue, 0); + rdev_for_each(rdev, mddev) { if (!mddev->gendisk) continue; @@ -2963,7 +2973,7 @@ static int raid1_reshape(struct mddev *mddev) return -ENOMEM; } - raise_barrier(conf); + freeze_array(conf, 0); /* ok, everything is stopped */ oldpool = conf->r1bio_pool; @@ -2994,7 +3004,7 @@ static int raid1_reshape(struct mddev *mddev) conf->raid_disks = mddev->raid_disks = raid_disks; mddev->delta_disks = 0; - lower_barrier(conf); + unfreeze_array(conf); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 59d4daa5f4c7..6ddae2501b9a 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -490,7 +490,17 @@ static void raid10_end_write_request(struct bio *bio, int error) sector_t first_bad; int bad_sectors; - set_bit(R10BIO_Uptodate, &r10_bio->state); + /* + * Do not set R10BIO_Uptodate if the current device is + * rebuilding or Faulty. This is because we cannot use + * such device for properly reading the data back (we could + * potentially use it, if the current write would have felt + * before rdev->recovery_offset, but for simplicity we don't + * check this here. + */ + if (test_bit(In_sync, &rdev->flags) && + !test_bit(Faulty, &rdev->flags)) + set_bit(R10BIO_Uptodate, &r10_bio->state); /* Maybe we can clear some bad blocks. */ if (is_badblock(rdev, @@ -1055,17 +1065,17 @@ static void allow_barrier(struct r10conf *conf) wake_up(&conf->wait_barrier); } -static void freeze_array(struct r10conf *conf) +static void freeze_array(struct r10conf *conf, int extra) { /* stop syncio and normal IO and wait for everything to * go quiet. * We increment barrier and nr_waiting, and then - * wait until nr_pending match nr_queued+1 + * wait until nr_pending match nr_queued+extra * This is called in the context of one normal IO request * that has failed. Thus any sync request that might be pending * will be blocked by nr_pending, and we need to wait for * pending IO requests to complete or be queued for re-try. - * Thus the number queued (nr_queued) plus this request (1) + * Thus the number queued (nr_queued) plus this request (extra) * must match the number of pending IOs (nr_pending) before * we continue. */ @@ -1073,7 +1083,7 @@ static void freeze_array(struct r10conf *conf) conf->barrier++; conf->nr_waiting++; wait_event_lock_irq_cmd(conf->wait_barrier, - conf->nr_pending == conf->nr_queued+1, + conf->nr_pending == conf->nr_queued+extra, conf->resync_lock, flush_pending_writes(conf)); @@ -1837,8 +1847,8 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) * we wait for all outstanding requests to complete. */ synchronize_sched(); - raise_barrier(conf, 0); - lower_barrier(conf); + freeze_array(conf, 0); + unfreeze_array(conf); clear_bit(Unmerged, &rdev->flags); } md_integrity_add_rdev(rdev, mddev); @@ -2612,7 +2622,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio) r10_bio->devs[slot].bio = NULL; if (mddev->ro == 0) { - freeze_array(conf); + freeze_array(conf, 1); fix_read_error(conf, mddev, r10_bio); unfreeze_array(conf); } else @@ -3609,8 +3619,7 @@ static int run(struct mddev *mddev) if (mddev->queue) { blk_queue_max_discard_sectors(mddev->queue, mddev->chunk_sectors); - blk_queue_max_write_same_sectors(mddev->queue, - mddev->chunk_sectors); + blk_queue_max_write_same_sectors(mddev->queue, 0); blk_queue_io_min(mddev->queue, chunk_size); if (conf->geo.raid_disks % conf->geo.near_copies) blk_queue_io_opt(mddev->queue, chunk_size * conf->geo.raid_disks); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 9359828ffe26..05e4a105b9c7 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -664,6 +664,7 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) bi->bi_rw |= REQ_FLUSH; + bi->bi_vcnt = 1; bi->bi_io_vec[0].bv_len = STRIPE_SIZE; bi->bi_io_vec[0].bv_offset = 0; bi->bi_size = STRIPE_SIZE; @@ -701,6 +702,7 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) else rbi->bi_sector = (sh->sector + rrdev->data_offset); + rbi->bi_vcnt = 1; rbi->bi_io_vec[0].bv_len = STRIPE_SIZE; rbi->bi_io_vec[0].bv_offset = 0; rbi->bi_size = STRIPE_SIZE; @@ -5464,7 +5466,7 @@ static int run(struct mddev *mddev) if (mddev->major_version == 0 && mddev->minor_version > 90) rdev->recovery_offset = reshape_offset; - + if (rdev->recovery_offset < reshape_offset) { /* We need to check old and new layout */ if (!only_parity(rdev->raid_disk, @@ -5587,6 +5589,8 @@ static int run(struct mddev *mddev) */ mddev->queue->limits.discard_zeroes_data = 0; + blk_queue_max_write_same_sectors(mddev->queue, 0); + rdev_for_each(rdev, mddev) { disk_stack_limits(mddev->gendisk, rdev->bdev, rdev->data_offset << 9); diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 7f5a7cac6dc7..8270388e2a0d 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -136,9 +136,9 @@ config DVB_NET # This Kconfig option is used by both PCI and USB drivers config TTPCI_EEPROM - tristate - depends on I2C - default n + tristate + depends on I2C + default n source "drivers/media/dvb-core/Kconfig" @@ -189,6 +189,12 @@ config MEDIA_SUBDRV_AUTOSELECT If unsure say Y. +config MEDIA_ATTACH + bool + depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT + depends on MODULES + default MODULES + source "drivers/media/i2c/Kconfig" source "drivers/media/tuners/Kconfig" source "drivers/media/dvb-frontends/Kconfig" diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index cb52438e53ac..9eac5310942f 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -956,7 +956,7 @@ static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd, if (fie->pad != OIF_SOURCE_PAD) return -EINVAL; - if (fie->index > ARRAY_SIZE(s5c73m3_intervals)) + if (fie->index >= ARRAY_SIZE(s5c73m3_intervals)) return -EINVAL; mutex_lock(&state->lock); diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 27d62623274b..aba5b1c649e6 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -615,7 +615,7 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, int changed = 0; u32 old; - if (core->board.audio_chip == V4L2_IDENT_WM8775) + if (core->sd_wm8775) snd_cx88_wm8775_volume_put(kcontrol, value); left = value->value.integer.value[0] & 0x3f; @@ -682,8 +682,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, vol ^= bit; cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol); /* Pass mute onto any WM8775 */ - if ((core->board.audio_chip == V4L2_IDENT_WM8775) && - ((1<<6) == bit)) + if (core->sd_wm8775 && ((1<<6) == bit)) wm8775_s_ctrl(core, V4L2_CID_AUDIO_MUTE, 0 != (vol & bit)); ret = 1; } @@ -903,7 +902,7 @@ static int cx88_audio_initdev(struct pci_dev *pci, goto error; /* If there's a wm8775 then add a Line-In ALC switch */ - if (core->board.audio_chip == V4L2_IDENT_WM8775) + if (core->sd_wm8775) snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip)); strcpy (card->driver, "CX88x"); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 1b00615fd395..c7a9be1065c0 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -385,8 +385,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) /* The wm8775 module has the "2" route hardwired into the initialization. Some boards may use different routes for different inputs. HVR-1300 surely does */ - if (core->board.audio_chip && - core->board.audio_chip == V4L2_IDENT_WM8775) { + if (core->sd_wm8775) { call_all(core, audio, s_routing, INPUT(input).audioroute, 0, 0); } @@ -771,8 +770,7 @@ static int video_open(struct file *file) cx_write(MO_GP1_IO, core->board.radio.gpio1); cx_write(MO_GP2_IO, core->board.radio.gpio2); if (core->board.radio.audioroute) { - if(core->board.audio_chip && - core->board.audio_chip == V4L2_IDENT_WM8775) { + if (core->sd_wm8775) { call_all(core, audio, s_routing, core->board.radio.audioroute, 0, 0); } @@ -959,7 +957,7 @@ static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl) u32 value,mask; /* Pass changes onto any WM8775 */ - if (core->board.audio_chip == V4L2_IDENT_WM8775) { + if (core->sd_wm8775) { switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: wm8775_s_ctrl(core, ctrl->id, ctrl->val); diff --git a/drivers/media/pci/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h index ca2754a3cd63..5e040085c2ff 100644 --- a/drivers/media/pci/zoran/zoran.h +++ b/drivers/media/pci/zoran/zoran.h @@ -176,7 +176,7 @@ struct zoran_fh; struct zoran_mapping { struct zoran_fh *fh; - int count; + atomic_t count; }; struct zoran_buffer { diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 1168a84a737d..d133c30c3fdc 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -2803,8 +2803,7 @@ static void zoran_vm_open (struct vm_area_struct *vma) { struct zoran_mapping *map = vma->vm_private_data; - - map->count++; + atomic_inc(&map->count); } static void @@ -2815,7 +2814,7 @@ zoran_vm_close (struct vm_area_struct *vma) struct zoran *zr = fh->zr; int i; - if (--map->count > 0) + if (!atomic_dec_and_mutex_lock(&map->count, &zr->resource_lock)) return; dprintk(3, KERN_INFO "%s: %s - munmap(%s)\n", ZR_DEVNAME(zr), @@ -2828,14 +2827,16 @@ zoran_vm_close (struct vm_area_struct *vma) kfree(map); /* Any buffers still mapped? */ - for (i = 0; i < fh->buffers.num_buffers; i++) - if (fh->buffers.buffer[i].map) + for (i = 0; i < fh->buffers.num_buffers; i++) { + if (fh->buffers.buffer[i].map) { + mutex_unlock(&zr->resource_lock); return; + } + } dprintk(3, KERN_INFO "%s: %s - free %s buffers\n", ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode)); - mutex_lock(&zr->resource_lock); if (fh->map_mode == ZORAN_MAP_MODE_RAW) { if (fh->buffers.active != ZORAN_FREE) { @@ -2939,7 +2940,7 @@ zoran_mmap (struct file *file, goto mmap_unlock_and_return; } map->fh = fh; - map->count = 1; + atomic_set(&map->count, 1); vma->vm_ops = &zoran_vm_ops; vma->vm_flags |= VM_DONTEXPAND; diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 48b8d7af386d..9d1481a60bd9 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -576,6 +576,14 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); } +static int vidioc_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *create) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + + return v4l2_m2m_create_bufs(file, ctx->m2m_ctx, create); +} + static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { @@ -610,6 +618,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_create_bufs = vidioc_create_bufs, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 1802f11e939f..d0b375cf565f 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -916,6 +916,21 @@ static int vpbe_display_s_fmt(struct file *file, void *priv, other video window */ layer->pix_fmt = *pixfmt; + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) { + struct vpbe_layer *otherlayer; + + otherlayer = _vpbe_display_get_other_win_layer(disp_dev, layer); + /* if other layer is available, only + * claim it, do not configure it + */ + ret = osd_device->ops.request_layer(osd_device, + otherlayer->layer_info.id); + if (ret < 0) { + v4l2_err(&vpbe_dev->v4l2_dev, + "Display Manager failed to allocate layer\n"); + return -EBUSY; + } + } /* Get osd layer config */ osd_device->ops.get_layer_config(osd_device, diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 8c50d3074866..93609091cb23 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1837,7 +1837,7 @@ static int vpfe_probe(struct platform_device *pdev) if (NULL == ccdc_cfg) { v4l2_err(pdev->dev.driver, "Memory allocation failed for ccdc_cfg\n"); - goto probe_free_lock; + goto probe_free_dev_mem; } mutex_lock(&ccdc_lock); @@ -1991,7 +1991,6 @@ probe_out_release_irq: free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); probe_free_ccdc_cfg_mem: kfree(ccdc_cfg); -probe_free_lock: mutex_unlock(&ccdc_lock); probe_free_dev_mem: kfree(vpfe_dev); diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index b0ff67bc1b05..d05eaa2c8490 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -174,7 +174,7 @@ int fimc_is_hw_change_mode(struct fimc_is *is) HIC_CAPTURE_STILL, HIC_CAPTURE_VIDEO, }; - if (WARN_ON(is->config_index > ARRAY_SIZE(cmd))) + if (WARN_ON(is->config_index >= ARRAY_SIZE(cmd))) return -EINVAL; mcuctl_write(cmd[is->config_index], is, MCUCTL_REG_ISSR(0)); diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 47c6363d04e2..0741945b79ed 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -48,7 +48,6 @@ static char *fimc_is_clocks[ISS_CLKS_MAX] = { [ISS_CLK_LITE0] = "lite0", [ISS_CLK_LITE1] = "lite1", [ISS_CLK_MPLL] = "mpll", - [ISS_CLK_SYSREG] = "sysreg", [ISS_CLK_ISP] = "isp", [ISS_CLK_DRC] = "drc", [ISS_CLK_FD] = "fd", @@ -71,7 +70,6 @@ static void fimc_is_put_clocks(struct fimc_is *is) for (i = 0; i < ISS_CLKS_MAX; i++) { if (IS_ERR(is->clocks[i])) continue; - clk_unprepare(is->clocks[i]); clk_put(is->clocks[i]); is->clocks[i] = ERR_PTR(-EINVAL); } @@ -90,12 +88,6 @@ static int fimc_is_get_clocks(struct fimc_is *is) ret = PTR_ERR(is->clocks[i]); goto err; } - ret = clk_prepare(is->clocks[i]); - if (ret < 0) { - clk_put(is->clocks[i]); - is->clocks[i] = ERR_PTR(-EINVAL); - goto err; - } } return 0; @@ -103,7 +95,7 @@ err: fimc_is_put_clocks(is); dev_err(&is->pdev->dev, "failed to get clock: %s\n", fimc_is_clocks[i]); - return -ENXIO; + return ret; } static int fimc_is_setup_clocks(struct fimc_is *is) @@ -144,7 +136,7 @@ int fimc_is_enable_clocks(struct fimc_is *is) for (i = 0; i < ISS_GATE_CLKS_MAX; i++) { if (IS_ERR(is->clocks[i])) continue; - ret = clk_enable(is->clocks[i]); + ret = clk_prepare_enable(is->clocks[i]); if (ret < 0) { dev_err(&is->pdev->dev, "clock %s enable failed\n", fimc_is_clocks[i]); @@ -163,7 +155,7 @@ void fimc_is_disable_clocks(struct fimc_is *is) for (i = 0; i < ISS_GATE_CLKS_MAX; i++) { if (!IS_ERR(is->clocks[i])) { - clk_disable(is->clocks[i]); + clk_disable_unprepare(is->clocks[i]); pr_debug("disabled clock: %s\n", fimc_is_clocks[i]); } } @@ -326,6 +318,11 @@ int fimc_is_start_firmware(struct fimc_is *is) struct device *dev = &is->pdev->dev; int ret; + if (is->fw.f_w == NULL) { + dev_err(dev, "firmware is not loaded\n"); + return -EINVAL; + } + memcpy(is->memory.vaddr, is->fw.f_w->data, is->fw.f_w->size); wmb(); @@ -837,23 +834,11 @@ static int fimc_is_probe(struct platform_device *pdev) goto err_clk; } pm_runtime_enable(dev); - /* - * Enable only the ISP power domain, keep FIMC-IS clocks off until - * the whole clock tree is configured. The ISP power domain needs - * be active in order to acces any CMU_ISP clock registers. - */ - ret = pm_runtime_get_sync(dev); - if (ret < 0) - goto err_irq; - - ret = fimc_is_setup_clocks(is); - pm_runtime_put_sync(dev); + ret = pm_runtime_get_sync(dev); if (ret < 0) goto err_irq; - is->clk_init = true; - is->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(is->alloc_ctx)) { ret = PTR_ERR(is->alloc_ctx); @@ -875,6 +860,8 @@ static int fimc_is_probe(struct platform_device *pdev) if (ret < 0) goto err_dfs; + pm_runtime_put_sync(dev); + dev_dbg(dev, "FIMC-IS registered successfully\n"); return 0; @@ -894,9 +881,11 @@ err_clk: static int fimc_is_runtime_resume(struct device *dev) { struct fimc_is *is = dev_get_drvdata(dev); + int ret; - if (!is->clk_init) - return 0; + ret = fimc_is_setup_clocks(is); + if (ret) + return ret; return fimc_is_enable_clocks(is); } @@ -905,9 +894,7 @@ static int fimc_is_runtime_suspend(struct device *dev) { struct fimc_is *is = dev_get_drvdata(dev); - if (is->clk_init) - fimc_is_disable_clocks(is); - + fimc_is_disable_clocks(is); return 0; } @@ -941,7 +928,8 @@ static int fimc_is_remove(struct platform_device *pdev) vb2_dma_contig_cleanup_ctx(is->alloc_ctx); fimc_is_put_clocks(is); fimc_is_debugfs_remove(is); - release_firmware(is->fw.f_w); + if (is->fw.f_w) + release_firmware(is->fw.f_w); fimc_is_free_cpu_memory(is); return 0; diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h index f5275a5b0156..d7db133b493f 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.h +++ b/drivers/media/platform/exynos4-is/fimc-is.h @@ -73,7 +73,6 @@ enum { ISS_CLK_LITE0, ISS_CLK_LITE1, ISS_CLK_MPLL, - ISS_CLK_SYSREG, ISS_CLK_ISP, ISS_CLK_DRC, ISS_CLK_FD, @@ -265,7 +264,6 @@ struct fimc_is { spinlock_t slock; struct clk *clocks[ISS_CLKS_MAX]; - bool clk_init; void __iomem *regs; void __iomem *pmu_regs; int irq; diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index d63947f7b302..7ede30b5910f 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -138,7 +138,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, return 0; } - mf->colorspace = V4L2_COLORSPACE_JPEG; + mf->colorspace = V4L2_COLORSPACE_SRGB; mutex_lock(&isp->subdev_lock); __is_get_frame_size(is, &cur_fmt); @@ -194,7 +194,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s: pad%d: code: 0x%x, %dx%d\n", __func__, fmt->pad, mf->code, mf->width, mf->height); - mf->colorspace = V4L2_COLORSPACE_JPEG; + mf->colorspace = V4L2_COLORSPACE_SRGB; mutex_lock(&isp->subdev_lock); __isp_subdev_try_format(isp, fmt); diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index a2eda9d5ac87..254d70fe762a 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -746,7 +746,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, node = v4l2_of_get_next_endpoint(node, NULL); if (!node) { dev_err(&pdev->dev, "No port node at %s\n", - node->full_name); + pdev->dev.of_node->full_name); return -EINVAL; } /* Get port node and validate MIPI-CSI channel id. */ diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 477268a2415f..d338b19da544 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -2150,6 +2150,9 @@ static int __init omap_vout_probe(struct platform_device *pdev) struct omap_dss_device *def_display; struct omap2video_device *vid_dev = NULL; + if (omapdss_is_initialized() == false) + return -EPROBE_DEFER; + ret = omapdss_compat_init(); if (ret) { dev_err(&pdev->dev, "failed to init dss\n"); diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h index 261134baa655..35d2fcdc0036 100644 --- a/drivers/media/platform/s3c-camif/camif-core.h +++ b/drivers/media/platform/s3c-camif/camif-core.h @@ -229,7 +229,7 @@ struct camif_vp { unsigned int state; u16 fmt_flags; u8 id; - u8 rotation; + u16 rotation; u8 hflip; u8 vflip; unsigned int offset; diff --git a/drivers/media/platform/s5p-jpeg/Makefile b/drivers/media/platform/s5p-jpeg/Makefile index ddc2900d88a2..d18cb5edd2d5 100644 --- a/drivers/media/platform/s5p-jpeg/Makefile +++ b/drivers/media/platform/s5p-jpeg/Makefile @@ -1,2 +1,2 @@ s5p-jpeg-objs := jpeg-core.o -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) := s5p-jpeg.o +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg.o diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile index 379008c6d09a..15f59b324fef 100644 --- a/drivers/media/platform/s5p-mfc/Makefile +++ b/drivers/media/platform/s5p-mfc/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc.o s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_pm.o diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 01f9ae0dadb0..d12faa691af8 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -397,7 +397,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, leave_handle_frame: spin_unlock_irqrestore(&dev->irqlock, flags); if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) - || ctx->dst_queue_cnt < ctx->dpb_count) + || ctx->dst_queue_cnt < ctx->pb_count) clear_work_bit(ctx); s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); @@ -473,7 +473,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx); - ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, + ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, dev); ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, dev); @@ -562,7 +562,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx, struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *mb_entry; - mfc_debug(2, "Stream completed"); + mfc_debug(2, "Stream completed\n"); s5p_mfc_clear_int_flags(dev); ctx->int_type = reason; @@ -1362,7 +1362,6 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { .port_num = MFC_NUM_PORTS, .buf_size = &buf_size_v5, .buf_align = &mfc_buf_align_v5, - .mclk_name = "sclk_mfc", .fw_name = "s5p-mfc.fw", }; @@ -1389,7 +1388,6 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = { .port_num = MFC_NUM_PORTS_V6, .buf_size = &buf_size_v6, .buf_align = &mfc_buf_align_v6, - .mclk_name = "aclk_333", .fw_name = "s5p-mfc-v6.fw", }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 202d1d7a37a8..ef4074cd5316 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -138,6 +138,7 @@ enum s5p_mfc_inst_state { MFCINST_INIT = 100, MFCINST_GOT_INST, MFCINST_HEAD_PARSED, + MFCINST_HEAD_PRODUCED, MFCINST_BUFS_SET, MFCINST_RUNNING, MFCINST_FINISHING, @@ -231,7 +232,6 @@ struct s5p_mfc_variant { unsigned int port_num; struct s5p_mfc_buf_size *buf_size; struct s5p_mfc_buf_align *buf_align; - char *mclk_name; char *fw_name; }; @@ -438,7 +438,7 @@ struct s5p_mfc_enc_params { u32 rc_framerate_num; u32 rc_framerate_denom; - union { + struct { struct s5p_mfc_h264_enc_params h264; struct s5p_mfc_mpeg4_enc_params mpeg4; } codec; @@ -602,7 +602,7 @@ struct s5p_mfc_ctx { int after_packed_pb; int sei_fp_parse; - int dpb_count; + int pb_count; int total_dpb_count; int mv_count; /* Buffers */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 2e5f30b40dea..dc1fc94a488d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -38,7 +38,7 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) dev->fw_virt_addr = dma_alloc_coherent(dev->mem_dev_l, dev->fw_size, &dev->bank1, GFP_KERNEL); - if (IS_ERR(dev->fw_virt_addr)) { + if (IS_ERR_OR_NULL(dev->fw_virt_addr)) { dev->fw_virt_addr = NULL; mfc_err("Allocating bitprocessor buffer failed\n"); return -ENOMEM; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h index bd5cd4ae993c..8e608f5aa0d7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h @@ -30,8 +30,8 @@ extern int debug; #define mfc_debug(level, fmt, args...) #endif -#define mfc_debug_enter() mfc_debug(5, "enter") -#define mfc_debug_leave() mfc_debug(5, "leave") +#define mfc_debug_enter() mfc_debug(5, "enter\n") +#define mfc_debug_leave() mfc_debug(5, "leave\n") #define mfc_err(fmt, args...) \ do { \ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 4af53bd2f182..00b07032f4f0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -210,11 +210,11 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) /* Context is to decode a frame */ if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_RUNNING && - ctx->dst_queue_cnt >= ctx->dpb_count) + ctx->dst_queue_cnt >= ctx->pb_count) return 1; /* Context is to return last frame */ if (ctx->state == MFCINST_FINISHING && - ctx->dst_queue_cnt >= ctx->dpb_count) + ctx->dst_queue_cnt >= ctx->pb_count) return 1; /* Context is to set buffers */ if (ctx->src_queue_cnt >= 1 && @@ -224,7 +224,7 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) /* Resolution change */ if ((ctx->state == MFCINST_RES_CHANGE_INIT || ctx->state == MFCINST_RES_CHANGE_FLUSH) && - ctx->dst_queue_cnt >= ctx->dpb_count) + ctx->dst_queue_cnt >= ctx->pb_count) return 1; if (ctx->state == MFCINST_RES_CHANGE_END && ctx->src_queue_cnt >= 1) @@ -537,7 +537,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, mfc_err("vb2_reqbufs on capture failed\n"); return ret; } - if (reqbufs->count < ctx->dpb_count) { + if (reqbufs->count < ctx->pb_count) { mfc_err("Not enough buffers allocated\n"); reqbufs->count = 0; s5p_mfc_clock_on(); @@ -751,7 +751,7 @@ static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: if (ctx->state >= MFCINST_HEAD_PARSED && ctx->state < MFCINST_ABORT) { - ctrl->val = ctx->dpb_count; + ctrl->val = ctx->pb_count; break; } else if (ctx->state != MFCINST_INIT) { v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); @@ -763,7 +763,7 @@ static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); if (ctx->state >= MFCINST_HEAD_PARSED && ctx->state < MFCINST_ABORT) { - ctrl->val = ctx->dpb_count; + ctrl->val = ctx->pb_count; } else { v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); return -EINVAL; @@ -924,10 +924,10 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, /* Output plane count is 2 - one for Y and one for CbCr */ *plane_count = 2; /* Setup buffer count */ - if (*buf_count < ctx->dpb_count) - *buf_count = ctx->dpb_count; - if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB) - *buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB; + if (*buf_count < ctx->pb_count) + *buf_count = ctx->pb_count; + if (*buf_count > ctx->pb_count + MFC_MAX_EXTRA_DPB) + *buf_count = ctx->pb_count + MFC_MAX_EXTRA_DPB; if (*buf_count > MFC_MAX_BUFFERS) *buf_count = MFC_MAX_BUFFERS; } else { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 4f6b553c4b2d..2549967b2f85 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -592,7 +592,7 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) return 1; /* context is ready to encode a frame */ if ((ctx->state == MFCINST_RUNNING || - ctx->state == MFCINST_HEAD_PARSED) && + ctx->state == MFCINST_HEAD_PRODUCED) && ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) return 1; /* context is ready to encode remaining frames */ @@ -649,6 +649,7 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) struct s5p_mfc_enc_params *p = &ctx->enc_params; struct s5p_mfc_buf *dst_mb; unsigned long flags; + unsigned int enc_pb_count; if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) { spin_lock_irqsave(&dev->irqlock, flags); @@ -661,18 +662,19 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE); spin_unlock_irqrestore(&dev->irqlock, flags); } - if (IS_MFCV6(dev)) { - ctx->state = MFCINST_HEAD_PARSED; /* for INIT_BUFFER cmd */ - } else { + + if (!IS_MFCV6(dev)) { ctx->state = MFCINST_RUNNING; if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - } - - if (IS_MFCV6(dev)) - ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, + } else { + enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_enc_dpb_count, dev); + if (ctx->pb_count < enc_pb_count) + ctx->pb_count = enc_pb_count; + ctx->state = MFCINST_HEAD_PRODUCED; + } return 0; } @@ -717,9 +719,9 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev); strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev); - mfc_debug(2, "Encoded slice type: %d", slice_type); - mfc_debug(2, "Encoded stream size: %d", strm_size); - mfc_debug(2, "Display order: %d", + mfc_debug(2, "Encoded slice type: %d\n", slice_type); + mfc_debug(2, "Encoded stream size: %d\n", strm_size); + mfc_debug(2, "Display order: %d\n", mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); spin_lock_irqsave(&dev->irqlock, flags); if (slice_type >= 0) { @@ -1055,15 +1057,13 @@ static int vidioc_reqbufs(struct file *file, void *priv, } ctx->capture_state = QUEUE_BUFS_REQUESTED; - if (!IS_MFCV6(dev)) { - ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, - alloc_codec_buffers, ctx); - if (ret) { - mfc_err("Failed to allocate encoding buffers\n"); - reqbufs->count = 0; - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - return -ENOMEM; - } + ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, + alloc_codec_buffers, ctx); + if (ret) { + mfc_err("Failed to allocate encoding buffers\n"); + reqbufs->count = 0; + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + return -ENOMEM; } } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (ctx->output_state != QUEUE_FREE) { @@ -1071,6 +1071,19 @@ static int vidioc_reqbufs(struct file *file, void *priv, ctx->output_state); return -EINVAL; } + + if (IS_MFCV6(dev)) { + /* Check for min encoder buffers */ + if (ctx->pb_count && + (reqbufs->count < ctx->pb_count)) { + reqbufs->count = ctx->pb_count; + mfc_debug(2, "Minimum %d output buffers needed\n", + ctx->pb_count); + } else { + ctx->pb_count = reqbufs->count; + } + } + ret = vb2_reqbufs(&ctx->vq_src, reqbufs); if (ret != 0) { mfc_err("error in vb2_reqbufs() for E(S)\n"); @@ -1533,14 +1546,14 @@ int vidioc_encoder_cmd(struct file *file, void *priv, spin_lock_irqsave(&dev->irqlock, flags); if (list_empty(&ctx->src_queue)) { - mfc_debug(2, "EOS: empty src queue, entering finishing state"); + mfc_debug(2, "EOS: empty src queue, entering finishing state\n"); ctx->state = MFCINST_FINISHING; if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); spin_unlock_irqrestore(&dev->irqlock, flags); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { - mfc_debug(2, "EOS: marking last buffer of stream"); + mfc_debug(2, "EOS: marking last buffer of stream\n"); buf = list_entry(ctx->src_queue.prev, struct s5p_mfc_buf, list); if (buf->flags & MFC_BUF_FLAG_USED) @@ -1609,9 +1622,9 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) mfc_err("failed to get plane cookie\n"); return -EINVAL; } - mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx", - vb->v4l2_buf.index, i, - vb2_dma_contig_plane_dma_addr(vb, i)); + mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx\n", + vb->v4l2_buf.index, i, + vb2_dma_contig_plane_dma_addr(vb, i)); } return 0; } @@ -1760,11 +1773,27 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); struct s5p_mfc_dev *dev = ctx->dev; - v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + if (IS_MFCV6(dev) && (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) { + + if ((ctx->state == MFCINST_GOT_INST) && + (dev->curr_ctx == ctx->num) && dev->hw_lock) { + s5p_mfc_wait_for_done_ctx(ctx, + S5P_MFC_R2H_CMD_SEQ_DONE_RET, + 0); + } + + if (ctx->src_bufs_cnt < ctx->pb_count) { + mfc_err("Need minimum %d OUTPUT buffers\n", + ctx->pb_count); + return -EINVAL; + } + } + /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + return 0; } @@ -1920,6 +1949,7 @@ int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx) if (controls[i].is_volatile && ctx->ctrls[i]) ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; } + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); return 0; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 0af05a2d1cd4..368582b091bf 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1275,8 +1275,8 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); - mfc_debug(2, "encoding buffer with index=%d state=%d", - src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); + mfc_debug(2, "encoding buffer with index=%d state=%d\n", + src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); s5p_mfc_encode_one_frame_v5(ctx); return 0; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 7e76fce2e524..66f0d042357f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -62,12 +62,6 @@ static void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) /* NOP */ } -static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) -{ - /* NOP */ - return -1; -} - /* Allocate codec buffers */ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) { @@ -167,7 +161,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size + ctx->tmv_buffer_size + - (ctx->dpb_count * (ctx->luma_dpb_size + + (ctx->pb_count * (ctx->luma_dpb_size + ctx->chroma_dpb_size + ctx->me_buffer_size)); ctx->bank2.size = 0; break; @@ -181,7 +175,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size + ctx->tmv_buffer_size + - (ctx->dpb_count * (ctx->luma_dpb_size + + (ctx->pb_count * (ctx->luma_dpb_size + ctx->chroma_dpb_size + ctx->me_buffer_size)); ctx->bank2.size = 0; break; @@ -198,7 +192,6 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) } BUG_ON(ctx->bank1.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); } - return 0; } @@ -449,8 +442,8 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, WRITEL(addr, S5P_FIMV_E_STREAM_BUFFER_ADDR_V6); /* 16B align */ WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE_V6); - mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d", - addr, size); + mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d\n", + addr, size); return 0; } @@ -463,8 +456,8 @@ static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, WRITEL(y_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6); /* 256B align */ WRITEL(c_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6); - mfc_debug(2, "enc src y buf addr: 0x%08lx", y_addr); - mfc_debug(2, "enc src c buf addr: 0x%08lx", c_addr); + mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr); + mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr); } static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, @@ -479,8 +472,8 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, enc_recon_y_addr = READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6); enc_recon_c_addr = READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6); - mfc_debug(2, "recon y addr: 0x%08lx", enc_recon_y_addr); - mfc_debug(2, "recon c addr: 0x%08lx", enc_recon_c_addr); + mfc_debug(2, "recon y addr: 0x%08lx\n", enc_recon_y_addr); + mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr); } /* Set encoding ref & codec buffer */ @@ -497,7 +490,7 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); - for (i = 0; i < ctx->dpb_count; i++) { + for (i = 0; i < ctx->pb_count; i++) { WRITEL(buf_addr1, S5P_FIMV_E_LUMA_DPB_V6 + (4 * i)); buf_addr1 += ctx->luma_dpb_size; WRITEL(buf_addr1, S5P_FIMV_E_CHROMA_DPB_V6 + (4 * i)); @@ -520,7 +513,7 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) buf_size1 -= ctx->tmv_buffer_size; mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n", - buf_addr1, buf_size1, ctx->dpb_count); + buf_addr1, buf_size1, ctx->pb_count); if (buf_size1 < 0) { mfc_debug(2, "Not enough memory has been allocated.\n"); return -ENOMEM; @@ -1431,8 +1424,8 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); - mfc_debug(2, "enc src y addr: 0x%08lx", src_y_addr); - mfc_debug(2, "enc src c addr: 0x%08lx", src_c_addr); + mfc_debug(2, "enc src y addr: 0x%08lx\n", src_y_addr); + mfc_debug(2, "enc src c addr: 0x%08lx\n", src_c_addr); s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr); @@ -1522,22 +1515,6 @@ static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx) struct s5p_mfc_dev *dev = ctx->dev; int ret; - ret = s5p_mfc_alloc_codec_buffers_v6(ctx); - if (ret) { - mfc_err("Failed to allocate encoding buffers.\n"); - return -ENOMEM; - } - - /* Header was generated now starting processing - * First set the reference frame buffers - */ - if (ctx->capture_state != QUEUE_BUFS_REQUESTED) { - mfc_err("It seems that destionation buffers were not\n" - "requested.MFC requires that header should be generated\n" - "before allocating codec buffer.\n"); - return -EAGAIN; - } - dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); ret = s5p_mfc_set_enc_ref_buffer_v6(ctx); @@ -1582,7 +1559,7 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) mfc_debug(1, "Seting new context to %p\n", ctx); /* Got context to run in ctx */ mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n", - ctx->dst_queue_cnt, ctx->dpb_count, ctx->src_queue_cnt); + ctx->dst_queue_cnt, ctx->pb_count, ctx->src_queue_cnt); mfc_debug(1, "ctx->state=%d\n", ctx->state); /* Last frame has already been sent to MFC * Now obtaining frames from MFC buffer */ @@ -1647,7 +1624,7 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) case MFCINST_GOT_INST: s5p_mfc_run_init_enc(ctx); break; - case MFCINST_HEAD_PARSED: /* Only for MFC6.x */ + case MFCINST_HEAD_PRODUCED: ret = s5p_mfc_run_init_enc_buffers(ctx); break; default: @@ -1730,7 +1707,7 @@ static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) return mfc_read(dev, S5P_FIMV_D_DISPLAY_STATUS_V6); } -static int s5p_mfc_get_decoded_status_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_DECODED_STATUS_V6); } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 6aa38a56aaf2..11d5f1dada32 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -50,19 +50,6 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) goto err_p_ip_clk; } - pm->clock = clk_get(&dev->plat_dev->dev, dev->variant->mclk_name); - if (IS_ERR(pm->clock)) { - mfc_err("Failed to get MFC clock\n"); - ret = PTR_ERR(pm->clock); - goto err_g_ip_clk_2; - } - - ret = clk_prepare(pm->clock); - if (ret) { - mfc_err("Failed to prepare MFC clock\n"); - goto err_p_ip_clk_2; - } - atomic_set(&pm->power, 0); #ifdef CONFIG_PM_RUNTIME pm->device = &dev->plat_dev->dev; @@ -72,10 +59,6 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) atomic_set(&clk_ref, 0); #endif return 0; -err_p_ip_clk_2: - clk_put(pm->clock); -err_g_ip_clk_2: - clk_unprepare(pm->clock_gate); err_p_ip_clk: clk_put(pm->clock_gate); err_g_ip_clk: @@ -86,8 +69,6 @@ void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) { clk_unprepare(pm->clock_gate); clk_put(pm->clock_gate); - clk_unprepare(pm->clock); - clk_put(pm->clock); #ifdef CONFIG_PM_RUNTIME pm_runtime_disable(pm->device); #endif @@ -98,7 +79,7 @@ int s5p_mfc_clock_on(void) int ret; #ifdef CLK_DEBUG atomic_inc(&clk_ref); - mfc_debug(3, "+ %d", atomic_read(&clk_ref)); + mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); #endif ret = clk_enable(pm->clock_gate); return ret; @@ -108,7 +89,7 @@ void s5p_mfc_clock_off(void) { #ifdef CLK_DEBUG atomic_dec(&clk_ref); - mfc_debug(3, "- %d", atomic_read(&clk_ref)); + mfc_debug(3, "- %d\n", atomic_read(&clk_ref)); #endif clk_disable(pm->clock_gate); } diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 0b32cc3f6a47..59a9deefb242 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -905,11 +905,11 @@ static int sh_veu_queue_setup(struct vb2_queue *vq, if (ftmp.fmt.pix.width != pix->width || ftmp.fmt.pix.height != pix->height) return -EINVAL; - size = pix->bytesperline ? pix->bytesperline * pix->height : - pix->width * pix->height * fmt->depth >> 3; + size = pix->bytesperline ? pix->bytesperline * pix->height * fmt->depth / fmt->ydepth : + pix->width * pix->height * fmt->depth / fmt->ydepth; } else { vfmt = sh_veu_get_vfmt(veu, vq->type); - size = vfmt->bytesperline * vfmt->frame.height; + size = vfmt->bytesperline * vfmt->frame.height * vfmt->fmt->depth / vfmt->fmt->ydepth; } if (count < 2) @@ -1033,8 +1033,6 @@ static int sh_veu_release(struct file *file) dev_dbg(veu->dev, "Releasing instance %p\n", veu_file); - pm_runtime_put(veu->dev); - if (veu_file == veu->capture) { veu->capture = NULL; vb2_queue_release(v4l2_m2m_get_vq(veu->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)); @@ -1050,6 +1048,8 @@ static int sh_veu_release(struct file *file) veu->m2m_ctx = NULL; } + pm_runtime_put(veu->dev); + kfree(veu_file); return 0; @@ -1138,10 +1138,7 @@ static irqreturn_t sh_veu_isr(int irq, void *dev_id) veu->xaction++; - if (!veu->aborting) - return IRQ_WAKE_THREAD; - - return IRQ_HANDLED; + return IRQ_WAKE_THREAD; } static int sh_veu_probe(struct platform_device *pdev) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index eea832c5fd01..3a4efbdc7668 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -643,9 +643,9 @@ static int soc_camera_close(struct file *file) if (ici->ops->init_videobuf2) vb2_queue_release(&icd->vb2_vidq); - ici->ops->remove(icd); - __soc_camera_power_off(icd); + + ici->ops->remove(icd); } if (icd->streamer == file) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index c0beee2fa37c..d529ba788f41 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -22,6 +22,7 @@ config RADIO_SI476X tristate "Silicon Laboratories Si476x I2C FM Radio" depends on I2C && VIDEO_V4L2 depends on MFD_SI476X_CORE + depends on SND_SOC select SND_SOC_SI476X ---help--- Choose Y here if you have this FM radio chip. diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 9430c6a29937..9dc8bafe6486 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -44,7 +44,7 @@ #define FREQ_MUL (10000000 / 625) -#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status)) +#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0x80 & (status)) #define DRIVER_NAME "si476x-radio" #define DRIVER_CARD "SI476x AM/FM Receiver" diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index f6768cad001a..15665debc572 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -1,23 +1,3 @@ -config MEDIA_ATTACH - bool "Load and attach frontend and tuner driver modules as needed" - depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT - depends on MODULES - default y if !EXPERT - help - Remove the static dependency of DVB card drivers on all - frontend modules for all possible card variants. Instead, - allow the card drivers to only load the frontend modules - they require. - - Also, tuner module will automatically load a tuner driver - when needed, for analog mode. - - This saves several KBytes of memory. - - Note: You will need module-init-tools v3.2 or later for this feature. - - If unsure say Y. - # Analog TV tuners, auto-loaded via tuner.ko config MEDIA_TUNER tristate diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 22015fe1a0f3..2cc8ec70e3b6 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -376,7 +376,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf}; - struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 5, buf}; + struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 1, buf}; dev_dbg(&d->udev->dev, "%s:\n", __func__); @@ -481,9 +481,9 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) goto found; } - /* check R820T by reading tuner stats at I2C addr 0x1a */ + /* check R820T ID register; reg=00 val=69 */ ret = rtl28xxu_ctrl_msg(d, &req_r820t); - if (ret == 0) { + if (ret == 0 && buf[0] == 0x69) { priv->tuner = TUNER_RTL2832_R820T; priv->tuner_name = "R820T"; goto found; diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index 3fe207e038c7..d7ff3b9687c5 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c @@ -1159,6 +1159,13 @@ static int sd_start(struct gspca_dev *gspca_dev) regs[0x01] = 0x44; /* Select 24 Mhz clock */ regs[0x12] = 0x02; /* Set hstart to 2 */ } + break; + case SENSOR_PAS202: + /* For some unknown reason we need to increase hstart by 1 on + the sn9c103, otherwise we get wrong colors (bayer shift). */ + if (sd->bridge == BRIDGE_103) + regs[0x12] += 1; + break; } /* Disable compression when the raw bayer format has been selected */ if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) diff --git a/drivers/media/usb/pwc/pwc.h b/drivers/media/usb/pwc/pwc.h index 7a6a0d39c2c6..81b017a554bc 100644 --- a/drivers/media/usb/pwc/pwc.h +++ b/drivers/media/usb/pwc/pwc.h @@ -226,7 +226,7 @@ struct pwc_device struct list_head queued_bufs; spinlock_t queued_bufs_lock; /* Protects queued_bufs */ - /* Note if taking both locks v4l2_lock must always be locked first! */ + /* If taking both locks vb_queue_lock must always be locked first! */ struct mutex v4l2_lock; /* Protects everything else */ struct mutex vb_queue_lock; /* Protects vb_queue and capt_file */ diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index ebb8e48619a2..fccd08b66d1a 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1835,6 +1835,8 @@ bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl) { if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_TX) return true; + if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_RX) + return true; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_VOLUME: diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index f81bda1a48ec..7658586fe5f4 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -243,7 +243,6 @@ static void v4l_print_format(const void *arg, bool write_only) const struct v4l2_vbi_format *vbi; const struct v4l2_sliced_vbi_format *sliced; const struct v4l2_window *win; - const struct v4l2_clip *clip; unsigned i; pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); @@ -253,7 +252,7 @@ static void v4l_print_format(const void *arg, bool write_only) pix = &p->fmt.pix; pr_cont(", width=%u, height=%u, " "pixelformat=%c%c%c%c, field=%s, " - "bytesperline=%u sizeimage=%u, colorspace=%d\n", + "bytesperline=%u, sizeimage=%u, colorspace=%d\n", pix->width, pix->height, (pix->pixelformat & 0xff), (pix->pixelformat >> 8) & 0xff, @@ -284,20 +283,14 @@ static void v4l_print_format(const void *arg, bool write_only) case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: win = &p->fmt.win; - pr_cont(", wxh=%dx%d, x,y=%d,%d, field=%s, " - "chromakey=0x%08x, bitmap=%p, " - "global_alpha=0x%02x\n", - win->w.width, win->w.height, - win->w.left, win->w.top, + /* Note: we can't print the clip list here since the clips + * pointer is a userspace pointer, not a kernelspace + * pointer. */ + pr_cont(", wxh=%dx%d, x,y=%d,%d, field=%s, chromakey=0x%08x, clipcount=%u, clips=%p, bitmap=%p, global_alpha=0x%02x\n", + win->w.width, win->w.height, win->w.left, win->w.top, prt_names(win->field, v4l2_field_names), - win->chromakey, win->bitmap, win->global_alpha); - clip = win->clips; - for (i = 0; i < win->clipcount; i++) { - printk(KERN_DEBUG "clip %u: wxh=%dx%d, x,y=%d,%d\n", - i, clip->c.width, clip->c.height, - clip->c.left, clip->c.top); - clip = clip->next; - } + win->chromakey, win->clipcount, win->clips, + win->bitmap, win->global_alpha); break; case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: @@ -332,7 +325,7 @@ static void v4l_print_framebuffer(const void *arg, bool write_only) pr_cont("capability=0x%x, flags=0x%x, base=0x%p, width=%u, " "height=%u, pixelformat=%c%c%c%c, " - "bytesperline=%u sizeimage=%u, colorspace=%d\n", + "bytesperline=%u, sizeimage=%u, colorspace=%d\n", p->capability, p->flags, p->base, p->fmt.width, p->fmt.height, (p->fmt.pixelformat & 0xff), @@ -353,7 +346,7 @@ static void v4l_print_modulator(const void *arg, bool write_only) const struct v4l2_modulator *p = arg; if (write_only) - pr_cont("index=%u, txsubchans=0x%x", p->index, p->txsubchans); + pr_cont("index=%u, txsubchans=0x%x\n", p->index, p->txsubchans); else pr_cont("index=%u, name=%.*s, capability=0x%x, " "rangelow=%u, rangehigh=%u, txsubchans=0x%x\n", @@ -445,13 +438,13 @@ static void v4l_print_buffer(const void *arg, bool write_only) for (i = 0; i < p->length; ++i) { plane = &p->m.planes[i]; printk(KERN_DEBUG - "plane %d: bytesused=%d, data_offset=0x%08x " + "plane %d: bytesused=%d, data_offset=0x%08x, " "offset/userptr=0x%lx, length=%d\n", i, plane->bytesused, plane->data_offset, plane->m.userptr, plane->length); } } else { - pr_cont("bytesused=%d, offset/userptr=0x%lx, length=%d\n", + pr_cont(", bytesused=%d, offset/userptr=0x%lx, length=%d\n", p->bytesused, p->m.userptr, p->length); } @@ -504,6 +497,8 @@ static void v4l_print_streamparm(const void *arg, bool write_only) c->capability, c->outputmode, c->timeperframe.numerator, c->timeperframe.denominator, c->extendedmode, c->writebuffers); + } else { + pr_cont("\n"); } } @@ -734,11 +729,11 @@ static void v4l_print_frmsizeenum(const void *arg, bool write_only) p->type); switch (p->type) { case V4L2_FRMSIZE_TYPE_DISCRETE: - pr_cont(" wxh=%ux%u\n", + pr_cont(", wxh=%ux%u\n", p->discrete.width, p->discrete.height); break; case V4L2_FRMSIZE_TYPE_STEPWISE: - pr_cont(" min=%ux%u, max=%ux%u, step=%ux%u\n", + pr_cont(", min=%ux%u, max=%ux%u, step=%ux%u\n", p->stepwise.min_width, p->stepwise.min_height, p->stepwise.step_width, p->stepwise.step_height, p->stepwise.max_width, p->stepwise.max_height); @@ -764,12 +759,12 @@ static void v4l_print_frmivalenum(const void *arg, bool write_only) p->width, p->height, p->type); switch (p->type) { case V4L2_FRMIVAL_TYPE_DISCRETE: - pr_cont(" fps=%d/%d\n", + pr_cont(", fps=%d/%d\n", p->discrete.numerator, p->discrete.denominator); break; case V4L2_FRMIVAL_TYPE_STEPWISE: - pr_cont(" min=%d/%d, max=%d/%d, step=%d/%d\n", + pr_cont(", min=%d/%d, max=%d/%d, step=%d/%d\n", p->stepwise.min.numerator, p->stepwise.min.denominator, p->stepwise.max.numerator, @@ -807,8 +802,8 @@ static void v4l_print_event(const void *arg, bool write_only) pr_cont("value64=%lld, ", c->value64); else pr_cont("value=%d, ", c->value); - pr_cont("flags=0x%x, minimum=%d, maximum=%d, step=%d," - " default_value=%d\n", + pr_cont("flags=0x%x, minimum=%d, maximum=%d, step=%d, " + "default_value=%d\n", c->flags, c->minimum, c->maximum, c->step, c->default_value); break; @@ -845,7 +840,7 @@ static void v4l_print_freq_band(const void *arg, bool write_only) const struct v4l2_frequency_band *p = arg; pr_cont("tuner=%u, type=%u, index=%u, capability=0x%x, " - "rangelow=%u, rangehigh=%u, modulation=0x%x\n", + "rangelow=%u, rangehigh=%u, modulation=0x%x\n", p->tuner, p->type, p->index, p->capability, p->rangelow, p->rangehigh, p->modulation); diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 66f599fcb829..e96497f7c3ed 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -205,7 +205,7 @@ static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev) static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx) { struct v4l2_m2m_dev *m2m_dev; - unsigned long flags_job, flags; + unsigned long flags_job, flags_out, flags_cap; m2m_dev = m2m_ctx->m2m_dev; dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx); @@ -223,23 +223,26 @@ static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx) return; } - spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); + spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out); if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)) { - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); + spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, + flags_out); spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("No input buffers available\n"); return; } - spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags); + spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap); if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)) { - spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags); - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); + spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, + flags_cap); + spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, + flags_out); spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("No output buffers available\n"); return; } - spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags); - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); + spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap); + spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out); if (m2m_dev->m2m_ops->job_ready && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) { @@ -372,6 +375,20 @@ int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf); /** + * v4l2_m2m_create_bufs() - create a source or destination buffer, depending + * on the type + */ +int v4l2_m2m_create_bufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + struct v4l2_create_buffers *create) +{ + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(m2m_ctx, create->format.type); + return vb2_create_bufs(vq, create); +} +EXPORT_SYMBOL_GPL(v4l2_m2m_create_bufs); + +/** * v4l2_m2m_expbuf() - export a source or destination buffer, depending on * the type */ @@ -486,8 +503,10 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, if (m2m_ctx->m2m_dev->m2m_ops->unlock) m2m_ctx->m2m_dev->m2m_ops->unlock(m2m_ctx->priv); - poll_wait(file, &src_q->done_wq, wait); - poll_wait(file, &dst_q->done_wq, wait); + if (list_empty(&src_q->done_list)) + poll_wait(file, &src_q->done_wq, wait); + if (list_empty(&dst_q->done_list)) + poll_wait(file, &dst_q->done_wq, wait); if (m2m_ctx->m2m_dev->m2m_ops->lock) m2m_ctx->m2m_dev->m2m_ops->lock(m2m_ctx->priv); diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 7d833eefaf4e..e3bdc3be91e1 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -2014,7 +2014,8 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) if (list_empty(&q->queued_list)) return res | POLLERR; - poll_wait(file, &q->done_wq, wait); + if (list_empty(&q->done_list)) + poll_wait(file, &q->done_wq, wait); /* * Take first buffer available for dequeuing. diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d9aed1593e5d..d54e985748b7 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -579,7 +579,7 @@ config AB8500_CORE config AB8500_DEBUG bool "Enable debug info via debugfs" - depends on AB8500_CORE && DEBUG_FS + depends on AB8500_GPADC && DEBUG_FS default y if DEBUG_FS help Select this option if you want debug information using the debug @@ -818,6 +818,7 @@ config MFD_TPS65910 config MFD_TPS65912 bool "TI TPS65912 Power Management chip" depends on GPIOLIB + select MFD_CORE help If you say yes here you get support for the TPS65912 series of PM chips. diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 8e8a016effe9..258b367e3989 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -868,6 +868,15 @@ static struct resource ab8500_chargalg_resources[] = {}; #ifdef CONFIG_DEBUG_FS static struct resource ab8500_debug_resources[] = { { + .name = "IRQ_AB8500", + /* + * Number will be filled in. NOTE: this is deliberately + * not flagged as an IRQ in ordet to avoid remapping using + * the irqdomain in the MFD core, so that this IRQ passes + * unremapped to the debug code. + */ + }, + { .name = "IRQ_FIRST", .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, .end = AB8500_INT_MAIN_EXT_CH_NOT_OK, @@ -1051,6 +1060,7 @@ static struct mfd_cell ab8500_devs[] = { }, { .name = "ab8500-gpadc", + .of_compatible = "stericsson,ab8500-gpadc", .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), .resources = ab8500_gpadc_resources, }, @@ -1097,7 +1107,7 @@ static struct mfd_cell ab8500_devs[] = { .of_compatible = "stericsson,ab8500-denc", }, { - .name = "ab8500-gpio", + .name = "pinctrl-ab8500", .of_compatible = "stericsson,ab8500-gpio", }, { @@ -1208,6 +1218,7 @@ static struct mfd_cell ab8505_devs[] = { }, { .name = "ab8500-gpadc", + .of_compatible = "stericsson,ab8500-gpadc", .num_resources = ARRAY_SIZE(ab8505_gpadc_resources), .resources = ab8505_gpadc_resources, }, @@ -1234,7 +1245,7 @@ static struct mfd_cell ab8505_devs[] = { .name = "ab8500-leds", }, { - .name = "ab8500-gpio", + .name = "pinctrl-ab8505", }, { .name = "ab8500-usb", @@ -1271,6 +1282,7 @@ static struct mfd_cell ab8540_devs[] = { }, { .name = "ab8500-gpadc", + .of_compatible = "stericsson,ab8500-gpadc", .num_resources = ARRAY_SIZE(ab8505_gpadc_resources), .resources = ab8505_gpadc_resources, }, @@ -1302,7 +1314,7 @@ static struct mfd_cell ab8540_devs[] = { .resources = ab8500_temp_resources, }, { - .name = "ab8500-gpio", + .name = "pinctrl-ab8540", }, { .name = "ab8540-usb", @@ -1712,6 +1724,12 @@ static int ab8500_probe(struct platform_device *pdev) if (ret) return ret; +#if CONFIG_DEBUG_FS + /* Pass to debugfs */ + ab8500_debug_resources[0].start = ab8500->irq; + ab8500_debug_resources[0].end = ab8500->irq; +#endif + if (is_ab9540(ab8500)) ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, ARRAY_SIZE(ab9540_devs), NULL, diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index b88bbbc15f1e..37b7ce4c7c3b 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -91,12 +91,10 @@ #include <linux/ctype.h> #endif -/* TODO: this file should not reference IRQ_DB8500_AB8500! */ -#include <mach/irqs.h> - static u32 debug_bank; static u32 debug_address; +static int irq_ab8500; static int irq_first; static int irq_last; static u32 *irq_count; @@ -1589,7 +1587,7 @@ void ab8500_debug_register_interrupt(int line) { if (line < num_interrupt_lines) { num_interrupts[line]++; - if (suspend_test_wake_cause_interrupt_is_mine(IRQ_DB8500_AB8500)) + if (suspend_test_wake_cause_interrupt_is_mine(irq_ab8500)) num_wake_interrupts[line]++; } } @@ -2941,6 +2939,7 @@ static int ab8500_debug_probe(struct platform_device *plf) struct dentry *file; int ret = -ENOMEM; struct ab8500 *ab8500; + struct resource *res; debug_bank = AB8500_MISC; debug_address = AB8500_REV_REG & 0x00FF; @@ -2959,6 +2958,15 @@ static int ab8500_debug_probe(struct platform_device *plf) if (!event_name) goto out_freedev_attr; + res = platform_get_resource_byname(plf, 0, "IRQ_AB8500"); + if (!res) { + dev_err(&plf->dev, "AB8500 irq not found, err %d\n", + irq_first); + ret = -ENXIO; + goto out_freeevent_name; + } + irq_ab8500 = res->start; + irq_first = platform_get_irq_byname(plf, "IRQ_FIRST"); if (irq_first < 0) { dev_err(&plf->dev, "First irq not found, err %d\n", diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 5e65b28a5d09..13f7866de46e 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -907,14 +907,17 @@ static int ab8500_gpadc_suspend(struct device *dev) static int ab8500_gpadc_resume(struct device *dev) { struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); + int ret; - regulator_enable(gpadc->regu); + ret = regulator_enable(gpadc->regu); + if (ret) + dev_err(dev, "Failed to enable vtvout LDO: %d\n", ret); pm_runtime_mark_last_busy(gpadc->dev); pm_runtime_put_autosuspend(gpadc->dev); mutex_unlock(&gpadc->ab8500_gpadc_lock); - return 0; + return ret; } static int ab8500_gpadc_probe(struct platform_device *pdev) diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index fbca1ced49fa..8e0dae59844d 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c @@ -23,7 +23,7 @@ static struct device *sysctrl_dev; -void ab8500_power_off(void) +static void ab8500_power_off(void) { sigset_t old; sigset_t all; @@ -104,7 +104,7 @@ void ab8500_restart(char mode, const char *cmd) plat = dev_get_platdata(sysctrl_dev->parent); pdata = plat->sysctrl; - if (pdata->reboot_reason_code) + if (pdata && pdata->reboot_reason_code) reason = pdata->reboot_reason_code(cmd); else pr_warn("[%s] No reboot reason set. Default reason %d\n", @@ -188,14 +188,15 @@ static int ab8500_sysctrl_probe(struct platform_device *pdev) plat = dev_get_platdata(pdev->dev.parent); - if (!(plat && plat->sysctrl)) + if (!plat) return -EINVAL; - if (plat->pm_power_off) + sysctrl_dev = &pdev->dev; + + if (!pm_power_off) pm_power_off = ab8500_power_off; pdata = plat->sysctrl; - if (pdata) { int last, ret, i, j; @@ -226,6 +227,10 @@ static int ab8500_sysctrl_probe(struct platform_device *pdev) static int ab8500_sysctrl_remove(struct platform_device *pdev) { sysctrl_dev = NULL; + + if (pm_power_off == ab8500_power_off) + pm_power_off = NULL; + return 0; } diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c index 9818afba2515..3714acb61458 100644 --- a/drivers/mfd/abx500-core.c +++ b/drivers/mfd/abx500-core.c @@ -156,7 +156,7 @@ EXPORT_SYMBOL(abx500_startup_irq_enabled); void abx500_dump_all_banks(void) { struct abx500_ops *ops; - struct device dummy_child = {0}; + struct device dummy_child = {NULL}; struct abx500_device_entry *dev_entry; list_for_each_entry(dev_entry, &abx500_list, list) { diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index 19193cf1e7a1..367ccb58ecb1 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -120,7 +120,7 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { if (*ptr == EC_MSG_HEADER) { - dev_dbg(ec_dev->dev, "msg found at %ld\n", + dev_dbg(ec_dev->dev, "msg found at %zd\n", ptr - ec_dev->din); break; } @@ -154,7 +154,7 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, * maximum-supported transfer size. */ todo = min(need_len, 256); - dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%ld\n", + dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n", todo, need_len, ptr - ec_dev->din); memset(&trans, '\0', sizeof(trans)); @@ -178,7 +178,7 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, need_len -= todo; } - dev_dbg(ec_dev->dev, "loop done, ptr=%ld\n", ptr - ec_dev->din); + dev_dbg(ec_dev->dev, "loop done, ptr=%zd\n", ptr - ec_dev->din); return 0; } diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 319b8abe742b..66f80973596b 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -1613,6 +1613,8 @@ static unsigned long dsiclk_rate(u8 n) if (divsel == PRCM_DSI_PLLOUT_SEL_OFF) divsel = dsiclk[n].divsel; + else + dsiclk[n].divsel = divsel; switch (divsel) { case PRCM_DSI_PLLOUT_SEL_PHI_4: @@ -3095,6 +3097,7 @@ static struct mfd_cell db8500_prcmu_devs[] = { .num_resources = ARRAY_SIZE(db8500_thsens_resources), .resources = db8500_thsens_resources, .platform_data = &db8500_thsens_data, + .pdata_size = sizeof(db8500_thsens_data), }, }; diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c index de48b4e88450..6f1ef63086c9 100644 --- a/drivers/mfd/si476x-cmd.c +++ b/drivers/mfd/si476x-cmd.c @@ -29,6 +29,8 @@ #include <linux/mfd/si476x-core.h> +#include <asm/unaligned.h> + #define msb(x) ((u8)((u16) x >> 8)) #define lsb(x) ((u8)((u16) x & 0x00FF)) @@ -150,7 +152,7 @@ enum si476x_acf_status_report_bits { SI476X_ACF_SOFTMUTE_INT = (1 << 0), SI476X_ACF_SMUTE = (1 << 0), - SI476X_ACF_SMATTN = 0b11111, + SI476X_ACF_SMATTN = 0x1f, SI476X_ACF_PILOT = (1 << 7), SI476X_ACF_STBLEND = ~SI476X_ACF_PILOT, }; @@ -483,7 +485,7 @@ int si476x_core_cmd_get_property(struct si476x_core *core, u16 property) if (err < 0) return err; else - return be16_to_cpup((__be16 *)(resp + 2)); + return get_unaligned_be16(resp + 2); } EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property); @@ -772,18 +774,18 @@ int si476x_core_cmd_am_rsq_status(struct si476x_core *core, if (!report) return err; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; + report->snrhint = 0x08 & resp[1]; + report->snrlint = 0x04 & resp[1]; + report->rssihint = 0x02 & resp[1]; + report->rssilint = 0x01 & resp[1]; - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; + report->bltf = 0x80 & resp[2]; + report->snr_ready = 0x20 & resp[2]; + report->rssiready = 0x08 & resp[2]; + report->afcrl = 0x02 & resp[2]; + report->valid = 0x01 & resp[2]; - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); + report->readfreq = get_unaligned_be16(resp + 3); report->freqoff = resp[5]; report->rssi = resp[6]; report->snr = resp[7]; @@ -931,26 +933,26 @@ int si476x_core_cmd_fm_rds_status(struct si476x_core *core, if (err < 0 || report == NULL) return err; - report->rdstpptyint = 0b00010000 & resp[1]; - report->rdspiint = 0b00001000 & resp[1]; - report->rdssyncint = 0b00000010 & resp[1]; - report->rdsfifoint = 0b00000001 & resp[1]; + report->rdstpptyint = 0x10 & resp[1]; + report->rdspiint = 0x08 & resp[1]; + report->rdssyncint = 0x02 & resp[1]; + report->rdsfifoint = 0x01 & resp[1]; - report->tpptyvalid = 0b00010000 & resp[2]; - report->pivalid = 0b00001000 & resp[2]; - report->rdssync = 0b00000010 & resp[2]; - report->rdsfifolost = 0b00000001 & resp[2]; + report->tpptyvalid = 0x10 & resp[2]; + report->pivalid = 0x08 & resp[2]; + report->rdssync = 0x02 & resp[2]; + report->rdsfifolost = 0x01 & resp[2]; - report->tp = 0b00100000 & resp[3]; - report->pty = 0b00011111 & resp[3]; + report->tp = 0x20 & resp[3]; + report->pty = 0x1f & resp[3]; - report->pi = be16_to_cpup((__be16 *)(resp + 4)); + report->pi = get_unaligned_be16(resp + 4); report->rdsfifoused = resp[6]; - report->ble[V4L2_RDS_BLOCK_A] = 0b11000000 & resp[7]; - report->ble[V4L2_RDS_BLOCK_B] = 0b00110000 & resp[7]; - report->ble[V4L2_RDS_BLOCK_C] = 0b00001100 & resp[7]; - report->ble[V4L2_RDS_BLOCK_D] = 0b00000011 & resp[7]; + report->ble[V4L2_RDS_BLOCK_A] = 0xc0 & resp[7]; + report->ble[V4L2_RDS_BLOCK_B] = 0x30 & resp[7]; + report->ble[V4L2_RDS_BLOCK_C] = 0x0c & resp[7]; + report->ble[V4L2_RDS_BLOCK_D] = 0x03 & resp[7]; report->rds[V4L2_RDS_BLOCK_A].block = V4L2_RDS_BLOCK_A; report->rds[V4L2_RDS_BLOCK_A].msb = resp[8]; @@ -991,9 +993,9 @@ int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *core, SI476X_DEFAULT_TIMEOUT); if (!err) { - report->expected = be16_to_cpup((__be16 *)(resp + 2)); - report->received = be16_to_cpup((__be16 *)(resp + 4)); - report->uncorrectable = be16_to_cpup((__be16 *)(resp + 6)); + report->expected = get_unaligned_be16(resp + 2); + report->received = get_unaligned_be16(resp + 4); + report->uncorrectable = get_unaligned_be16(resp + 6); } return err; @@ -1005,7 +1007,7 @@ int si476x_core_cmd_fm_phase_diversity(struct si476x_core *core, { u8 resp[CMD_FM_PHASE_DIVERSITY_NRESP]; const u8 args[CMD_FM_PHASE_DIVERSITY_NARGS] = { - mode & 0b111, + mode & 0x07, }; return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY, @@ -1162,7 +1164,7 @@ static int si476x_core_cmd_am_tune_freq_a20(struct si476x_core *core, const int am_freq = tuneargs->freq; u8 resp[CMD_AM_TUNE_FREQ_NRESP]; const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { - (tuneargs->zifsr << 6) | (tuneargs->injside & 0b11), + (tuneargs->zifsr << 6) | (tuneargs->injside & 0x03), msb(am_freq), lsb(am_freq), }; @@ -1197,20 +1199,20 @@ static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core, if (err < 0 || report == NULL) return err; - report->multhint = 0b10000000 & resp[1]; - report->multlint = 0b01000000 & resp[1]; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; + report->multhint = 0x80 & resp[1]; + report->multlint = 0x40 & resp[1]; + report->snrhint = 0x08 & resp[1]; + report->snrlint = 0x04 & resp[1]; + report->rssihint = 0x02 & resp[1]; + report->rssilint = 0x01 & resp[1]; - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; + report->bltf = 0x80 & resp[2]; + report->snr_ready = 0x20 & resp[2]; + report->rssiready = 0x08 & resp[2]; + report->afcrl = 0x02 & resp[2]; + report->valid = 0x01 & resp[2]; - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); + report->readfreq = get_unaligned_be16(resp + 3); report->freqoff = resp[5]; report->rssi = resp[6]; report->snr = resp[7]; @@ -1218,7 +1220,7 @@ static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core, report->hassi = resp[10]; report->mult = resp[11]; report->dev = resp[12]; - report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); + report->readantcap = get_unaligned_be16(resp + 13); report->assi = resp[15]; report->usn = resp[16]; @@ -1251,20 +1253,20 @@ static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core, if (err < 0 || report == NULL) return err; - report->multhint = 0b10000000 & resp[1]; - report->multlint = 0b01000000 & resp[1]; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; + report->multhint = 0x80 & resp[1]; + report->multlint = 0x40 & resp[1]; + report->snrhint = 0x08 & resp[1]; + report->snrlint = 0x04 & resp[1]; + report->rssihint = 0x02 & resp[1]; + report->rssilint = 0x01 & resp[1]; - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; + report->bltf = 0x80 & resp[2]; + report->snr_ready = 0x20 & resp[2]; + report->rssiready = 0x08 & resp[2]; + report->afcrl = 0x02 & resp[2]; + report->valid = 0x01 & resp[2]; - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); + report->readfreq = get_unaligned_be16(resp + 3); report->freqoff = resp[5]; report->rssi = resp[6]; report->snr = resp[7]; @@ -1272,7 +1274,7 @@ static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core, report->hassi = resp[10]; report->mult = resp[11]; report->dev = resp[12]; - report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); + report->readantcap = get_unaligned_be16(resp + 13); report->assi = resp[15]; report->usn = resp[16]; @@ -1306,21 +1308,21 @@ static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core, if (err < 0 || report == NULL) return err; - report->multhint = 0b10000000 & resp[1]; - report->multlint = 0b01000000 & resp[1]; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; - - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->injside = 0b00000100 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; - - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); + report->multhint = 0x80 & resp[1]; + report->multlint = 0x40 & resp[1]; + report->snrhint = 0x08 & resp[1]; + report->snrlint = 0x04 & resp[1]; + report->rssihint = 0x02 & resp[1]; + report->rssilint = 0x01 & resp[1]; + + report->bltf = 0x80 & resp[2]; + report->snr_ready = 0x20 & resp[2]; + report->rssiready = 0x08 & resp[2]; + report->injside = 0x04 & resp[2]; + report->afcrl = 0x02 & resp[2]; + report->valid = 0x01 & resp[2]; + + report->readfreq = get_unaligned_be16(resp + 3); report->freqoff = resp[5]; report->rssi = resp[6]; report->snr = resp[7]; @@ -1329,7 +1331,7 @@ static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core, report->hassi = resp[10]; report->mult = resp[11]; report->dev = resp[12]; - report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); + report->readantcap = get_unaligned_be16(resp + 13); report->assi = resp[15]; report->usn = resp[16]; @@ -1337,7 +1339,7 @@ static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core, report->rdsdev = resp[18]; report->assidev = resp[19]; report->strongdev = resp[20]; - report->rdspi = be16_to_cpup((__be16 *)(resp + 21)); + report->rdspi = get_unaligned_be16(resp + 21); return err; } diff --git a/drivers/misc/dummy-irq.c b/drivers/misc/dummy-irq.c index 7014167e2c61..c37eeedfe215 100644 --- a/drivers/misc/dummy-irq.c +++ b/drivers/misc/dummy-irq.c @@ -19,7 +19,7 @@ #include <linux/irq.h> #include <linux/interrupt.h> -static int irq; +static int irq = -1; static irqreturn_t dummy_interrupt(int irq, void *dev_id) { @@ -36,6 +36,10 @@ static irqreturn_t dummy_interrupt(int irq, void *dev_id) static int __init dummy_irq_init(void) { + if (irq < 0) { + printk(KERN_ERR "dummy-irq: no IRQ given. Use irq=N\n"); + return -EIO; + } if (request_irq(irq, &dummy_interrupt, IRQF_SHARED, "dummy_irq", &irq)) { printk(KERN_ERR "dummy-irq: cannot register IRQ %d\n", irq); return -EIO; diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 1e935eacaa7f..9ecd49a7be1b 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -496,6 +496,8 @@ int mei_cl_disable_device(struct mei_cl_device *device) } } + device->event_cb = NULL; + mutex_unlock(&dev->device_lock); if (!device->ops || !device->ops->disable) diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 713d89fedc46..f580d30bb784 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -197,6 +197,8 @@ void mei_stop(struct mei_device *dev) { dev_dbg(&dev->pdev->dev, "stopping the device.\n"); + flush_scheduled_work(); + mutex_lock(&dev->device_lock); cancel_delayed_work(&dev->timer_work); @@ -210,8 +212,6 @@ void mei_stop(struct mei_device *dev) mutex_unlock(&dev->device_lock); - flush_scheduled_work(); - mei_watchdog_unregister(dev); } EXPORT_SYMBOL_GPL(mei_stop); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 7c44c8dbae42..053139f61086 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -489,11 +489,16 @@ static int mei_ioctl_connect_client(struct file *file, /* find ME client we're trying to connect to */ i = mei_me_cl_by_uuid(dev, &data->in_client_uuid); - if (i >= 0 && !dev->me_clients[i].props.fixed_address) { - cl->me_client_id = dev->me_clients[i].client_id; - cl->state = MEI_FILE_CONNECTING; + if (i < 0 || dev->me_clients[i].props.fixed_address) { + dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n", + &data->in_client_uuid); + rets = -ENODEV; + goto end; } + cl->me_client_id = dev->me_clients[i].client_id; + cl->state = MEI_FILE_CONNECTING; + dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", cl->me_client_id); dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n", @@ -527,11 +532,6 @@ static int mei_ioctl_connect_client(struct file *file, goto end; } - if (cl->state != MEI_FILE_CONNECTING) { - rets = -ENODEV; - goto end; - } - /* prepare the output buffer */ client = &data->out_client_properties; @@ -543,7 +543,6 @@ static int mei_ioctl_connect_client(struct file *file, rets = mei_cl_connect(cl, file); end: - dev_dbg(&dev->pdev->dev, "free connect cb memory."); return rets; } diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index 3adf8a70f26e..d0c6907dfd92 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c @@ -142,6 +142,8 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev) mei_cl_unlink(ndev->cl_info); kfree(ndev->cl_info); } + + memset(ndev, 0, sizeof(struct mei_nfc_dev)); } static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index a727464e9c3f..0f268329bd3a 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -325,6 +325,7 @@ static int mei_me_pci_resume(struct device *device) mutex_lock(&dev->device_lock); dev->dev_state = MEI_DEV_POWER_UP; + mei_clear_interrupts(dev); mei_reset(dev, 1); mutex_unlock(&dev->device_lock); diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index 44d273c5e19d..0535d1e0bc78 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -172,6 +172,7 @@ static long gru_get_config_info(unsigned long arg) nodesperblade = 2; else nodesperblade = 1; + memset(&info, 0, sizeof(info)); info.cpus = num_online_cpus(); info.nodes = num_online_nodes(); info.blades = info.nodes / nodesperblade; diff --git a/drivers/misc/vmw_vmci/Kconfig b/drivers/misc/vmw_vmci/Kconfig index ea98f7e9ccd1..39c2ecadb273 100644 --- a/drivers/misc/vmw_vmci/Kconfig +++ b/drivers/misc/vmw_vmci/Kconfig @@ -4,7 +4,7 @@ config VMWARE_VMCI tristate "VMware VMCI Driver" - depends on X86 && PCI && NET + depends on X86 && PCI help This is VMware's Virtual Machine Communication Interface. It enables high-speed communication between host and guest in a virtual diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c index d94245dbd765..8ff2e5ee8fb8 100644 --- a/drivers/misc/vmw_vmci/vmci_queue_pair.c +++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c @@ -23,7 +23,7 @@ #include <linux/pagemap.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/socket.h> +#include <linux/uio.h> #include <linux/wait.h> #include <linux/vmalloc.h> diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index e75774f72606..aca59d93d5a9 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2230,10 +2230,15 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_free_host(slot->mmc); } -static bool atmci_filter(struct dma_chan *chan, void *slave) +static bool atmci_filter(struct dma_chan *chan, void *pdata) { - struct mci_dma_data *sl = slave; + struct mci_platform_data *sl_pdata = pdata; + struct mci_dma_data *sl; + if (!sl_pdata) + return false; + + sl = sl_pdata->dma_slave; if (sl && find_slave_dev(sl) == chan->device->dev) { chan->private = slave_data_ptr(sl); return true; @@ -2245,24 +2250,18 @@ static bool atmci_filter(struct dma_chan *chan, void *slave) static bool atmci_configure_dma(struct atmel_mci *host) { struct mci_platform_data *pdata; + dma_cap_mask_t mask; if (host == NULL) return false; pdata = host->pdev->dev.platform_data; - if (!pdata) - return false; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); - if (pdata->dma_slave && find_slave_dev(pdata->dma_slave)) { - dma_cap_mask_t mask; - - /* Try to grab a DMA channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma.chan = - dma_request_channel(mask, atmci_filter, pdata->dma_slave); - } + host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata, + &host->pdev->dev, "rxtx"); if (!host->dma.chan) { dev_warn(&host->pdev->dev, "no DMA channel available\n"); return false; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 6e44025acf01..eccedc7d06a4 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -161,6 +161,7 @@ struct omap_hsmmc_host { */ struct regulator *vcc; struct regulator *vcc_aux; + int pbias_disable; void __iomem *base; resource_size_t mapbase; spinlock_t irq_lock; /* Prevent races with irq handler */ @@ -255,11 +256,11 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, if (!host->vcc) return 0; /* - * With DT, never turn OFF the regulator. This is because + * With DT, never turn OFF the regulator for MMC1. This is because * the pbias cell programming support is still missing when * booting with Device tree */ - if (dev->of_node && !vdd) + if (host->pbias_disable && !vdd) return 0; if (mmc_slot(host).before_set_reg) @@ -1520,10 +1521,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) (ios->vdd == DUAL_VOLT_OCR_BIT) && /* * With pbias cell programming missing, this - * can't be allowed when booting with device + * can't be allowed on MMC1 when booting with device * tree. */ - !host->dev->of_node) { + !host->pbias_disable) { /* * The mmc_select_voltage fn of the core does * not seem to set the power_mode to @@ -1871,6 +1872,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_context_save(host); + /* This can be removed once we support PBIAS with DT */ + if (host->dev->of_node && host->mapbase == 0x4809c000) + host->pbias_disable = 1; + host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); /* * MMC can still work without debounce clock. @@ -1906,33 +1911,41 @@ static int omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_conf_bus_power(host); - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!res) { - dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); - ret = -ENXIO; - goto err_irq; - } - tx_req = res->start; + if (!pdev->dev.of_node) { + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); + if (!res) { + dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); + ret = -ENXIO; + goto err_irq; + } + tx_req = res->start; - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!res) { - dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); - ret = -ENXIO; - goto err_irq; + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); + if (!res) { + dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); + ret = -ENXIO; + goto err_irq; + } + rx_req = res->start; } - rx_req = res->start; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &rx_req); + host->rx_chan = + dma_request_slave_channel_compat(mask, omap_dma_filter_fn, + &rx_req, &pdev->dev, "rx"); + if (!host->rx_chan) { dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); ret = -ENXIO; goto err_irq; } - host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &tx_req); + host->tx_chan = + dma_request_slave_channel_compat(mask, omap_dma_filter_fn, + &tx_req, &pdev->dev, "tx"); + if (!host->tx_chan) { dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req); ret = -ENXIO; diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 7bcf74b1a5cd..706d9cb1a49e 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -87,6 +87,12 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = { .enable_dma = sdhci_acpi_enable_dma, }; +static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = { + .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE, + .caps2 = MMC_CAP2_HC_ERASE_SZ, + .flags = SDHCI_ACPI_RUNTIME_PM, +}; + static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, @@ -94,23 +100,67 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { .pm_caps = MMC_PM_KEEP_POWER, }; +static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { +}; + +struct sdhci_acpi_uid_slot { + const char *hid; + const char *uid; + const struct sdhci_acpi_slot *slot; +}; + +static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = { + { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc }, + { "80860F14" , "3" , &sdhci_acpi_slot_int_sd }, + { "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio }, + { "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio }, + { "PNP0D40" }, + { }, +}; + static const struct acpi_device_id sdhci_acpi_ids[] = { - { "INT33C6", (kernel_ulong_t)&sdhci_acpi_slot_int_sdio }, - { "PNP0D40" }, + { "80860F14" }, + { "INT33BB" }, + { "INT33C6" }, + { "PNP0D40" }, { }, }; MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); -static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid) +static const struct sdhci_acpi_slot *sdhci_acpi_get_slot_by_ids(const char *hid, + const char *uid) { - const struct acpi_device_id *id; - - for (id = sdhci_acpi_ids; id->id[0]; id++) - if (!strcmp(id->id, hid)) - return (const struct sdhci_acpi_slot *)id->driver_data; + const struct sdhci_acpi_uid_slot *u; + + for (u = sdhci_acpi_uids; u->hid; u++) { + if (strcmp(u->hid, hid)) + continue; + if (!u->uid) + return u->slot; + if (uid && !strcmp(u->uid, uid)) + return u->slot; + } return NULL; } +static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle, + const char *hid) +{ + const struct sdhci_acpi_slot *slot; + struct acpi_device_info *info; + const char *uid = NULL; + acpi_status status; + + status = acpi_get_object_info(handle, &info); + if (!ACPI_FAILURE(status) && (info->valid & ACPI_VALID_UID)) + uid = info->unique_id.string; + + slot = sdhci_acpi_get_slot_by_ids(hid, uid); + + kfree(info); + return slot; +} + static int sdhci_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -148,7 +198,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev) c = sdhci_priv(host); c->host = host; - c->slot = sdhci_acpi_get_slot(hid); + c->slot = sdhci_acpi_get_slot(handle, hid); c->pdev = pdev; c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); @@ -202,6 +252,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev) goto err_free; if (c->use_runtime_pm) { + pm_runtime_set_active(dev); pm_suspend_ignore_children(dev, 1); pm_runtime_set_autosuspend_delay(dev, 50); pm_runtime_use_autosuspend(dev); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 67d6dde2ff19..d5f0d59e1310 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -85,6 +85,12 @@ struct pltfm_imx_data { struct clk *clk_ipg; struct clk *clk_ahb; struct clk *clk_per; + enum { + NO_CMD_PENDING, /* no multiblock command pending*/ + MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */ + WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ + } multiblock_status; + }; static struct platform_device_id imx_esdhc_devtype[] = { @@ -154,6 +160,8 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i static u32 esdhc_readl_le(struct sdhci_host *host, int reg) { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = pltfm_host->priv; u32 val = readl(host->ioaddr + reg); if (unlikely(reg == SDHCI_CAPABILITIES)) { @@ -175,6 +183,18 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR; val |= SDHCI_INT_ADMA_ERROR; } + + /* + * mask off the interrupt we get in response to the manually + * sent CMD12 + */ + if ((imx_data->multiblock_status == WAIT_FOR_INT) && + ((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) { + val &= ~SDHCI_INT_RESPONSE; + writel(SDHCI_INT_RESPONSE, host->ioaddr + + SDHCI_INT_STATUS); + imx_data->multiblock_status = NO_CMD_PENDING; + } } return val; @@ -211,6 +231,15 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK; writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); + + if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS) + { + /* send a manual CMD12 with RESPTYP=none */ + data = MMC_STOP_TRANSMISSION << 24 | + SDHCI_CMD_ABORTCMD << 16; + writel(data, host->ioaddr + SDHCI_TRANSFER_MODE); + imx_data->multiblock_status = WAIT_FOR_INT; + } } if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { @@ -277,11 +306,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) } return; case SDHCI_COMMAND: - if ((host->cmd->opcode == MMC_STOP_TRANSMISSION || - host->cmd->opcode == MMC_SET_BLOCK_COUNT) && - (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) + if (host->cmd->opcode == MMC_STOP_TRANSMISSION) val |= SDHCI_CMD_ABORTCMD; + if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) && + (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) + imx_data->multiblock_status = MULTIBLK_IN_PROCESS; + if (is_imx6q_usdhc(imx_data)) writel(val << 16, host->ioaddr + SDHCI_TRANSFER_MODE); @@ -324,8 +355,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) /* * Do not touch buswidth bits here. This is done in * esdhc_pltfm_bus_width. + * Do not touch the D3CD bit either which is used for the + * SDIO interrupt errata workaround. */ - mask = 0xffff & ~ESDHC_CTRL_BUSWIDTH_MASK; + mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD); esdhc_clrset_le(host, mask, new_val, reg); return; diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 0012d3fdc999..701d06d0e1fb 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -33,6 +33,9 @@ */ #define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 #define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a +#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14 +#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15 +#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16 /* * PCI registers @@ -304,6 +307,33 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = { .probe_slot = pch_hc_probe_slot, }; +static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; + slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ; + return 0; +} + +static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) +{ + slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE; + return 0; +} + +static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = { + .allow_runtime_pm = true, + .probe_slot = byt_emmc_probe_slot, +}; + +static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { + .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, + .allow_runtime_pm = true, + .probe_slot = byt_sdio_probe_slot, +}; + +static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { +}; + /* O2Micro extra registers */ #define O2_SD_LOCK_WP 0xD3 #define O2_SD_MULTI_VCC3V 0xEE @@ -856,6 +886,30 @@ static const struct pci_device_id pci_ids[] = { }, { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BYT_EMMC, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, + }, + + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BYT_SDIO, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio, + }, + + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BYT_SD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd, + }, + + { .vendor = PCI_VENDOR_ID_O2, .device = PCI_DEVICE_ID_O2_8120, .subvendor = PCI_ANY_ID, diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index fc58d118d844..390061d09693 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2360,14 +2360,15 @@ int bond_3ad_set_carrier(struct bonding *bond) } /** - * bond_3ad_get_active_agg_info - get information of the active aggregator + * __bond_3ad_get_active_agg_info - get information of the active aggregator * @bond: bonding struct to work on * @ad_info: ad_info struct to fill with the bond's info * * Returns: 0 on success * < 0 on error */ -int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) +int __bond_3ad_get_active_agg_info(struct bonding *bond, + struct ad_info *ad_info) { struct aggregator *aggregator = NULL; struct port *port; @@ -2391,6 +2392,18 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) return -1; } +/* Wrapper used to hold bond->lock so no slave manipulation can occur */ +int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) +{ + int ret; + + read_lock(&bond->lock); + ret = __bond_3ad_get_active_agg_info(bond, ad_info); + read_unlock(&bond->lock); + + return ret; +} + int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) { struct slave *slave, *start_at; @@ -2402,8 +2415,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) struct ad_info ad_info; int res = 1; - if (bond_3ad_get_active_agg_info(bond, &ad_info)) { - pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n", + if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { + pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n", dev->name); goto out; } diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 0cfaa4afdece..5d91ad0cc041 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -273,6 +273,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave); void bond_3ad_adapter_duplex_changed(struct slave *slave); void bond_3ad_handle_link_change(struct slave *slave, char link); int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); +int __bond_3ad_get_active_agg_info(struct bonding *bond, + struct ad_info *ad_info); int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d0aade04e49a..02d9ae7d527e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -764,8 +764,8 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) struct net_device *bond_dev, *vlan_dev, *upper_dev; struct vlan_entry *vlan; - rcu_read_lock(); read_lock(&bond->lock); + rcu_read_lock(); bond_dev = bond->dev; @@ -787,12 +787,19 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) if (vlan_dev) __bond_resend_igmp_join_requests(vlan_dev); } + rcu_read_unlock(); - if (--bond->igmp_retrans > 0) + /* We use curr_slave_lock to protect against concurrent access to + * igmp_retrans from multiple running instances of this function and + * bond_change_active_slave + */ + write_lock_bh(&bond->curr_slave_lock); + if (bond->igmp_retrans > 1) { + bond->igmp_retrans--; queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5); - + } + write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); - rcu_read_unlock(); } static void bond_resend_igmp_join_requests_delayed(struct work_struct *work) @@ -1362,6 +1369,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, slave->dev->features, mask); } + features = netdev_add_tso_features(features, mask); out: read_unlock(&bond->lock); @@ -1956,6 +1964,10 @@ err_free: err_undo_flags: bond_compute_features(bond); + /* Enslave of first slave has failed and we need to fix master's mac */ + if (bond->slave_cnt == 0 && + ether_addr_equal(bond_dev->dev_addr, slave_dev->dev_addr)) + eth_hw_addr_random(bond_dev); return res; } @@ -2555,8 +2567,8 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ { struct sk_buff *skb; - pr_debug("arp %d on slave %s: dst %x src %x vid %d\n", arp_op, - slave_dev->name, dest_ip, src_ip, vlan_id); + pr_debug("arp %d on slave %s: dst %pI4 src %pI4 vid %d\n", arp_op, + slave_dev->name, &dest_ip, &src_ip, vlan_id); skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, NULL, slave_dev->dev_addr, NULL); @@ -2588,7 +2600,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) __be32 addr; if (!targets[i]) break; - pr_debug("basa: target %x\n", targets[i]); + pr_debug("basa: target %pI4\n", &targets[i]); if (!bond_vlan_used(bond)) { pr_debug("basa: empty vlan: arp_send\n"); addr = bond_confirm_addr(bond->dev, targets[i], 0); @@ -4470,7 +4482,7 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) static int bond_check_params(struct bond_params *params) { - int arp_validate_value, fail_over_mac_value, primary_reselect_value; + int arp_validate_value, fail_over_mac_value, primary_reselect_value, i; /* * Convert string parameters. @@ -4650,19 +4662,18 @@ static int bond_check_params(struct bond_params *params) arp_interval = BOND_LINK_ARP_INTERV; } - for (arp_ip_count = 0; - (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[arp_ip_count]; - arp_ip_count++) { + for (arp_ip_count = 0, i = 0; + (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) { /* not complete check, but should be good enough to catch mistakes */ - __be32 ip = in_aton(arp_ip_target[arp_ip_count]); - if (!isdigit(arp_ip_target[arp_ip_count][0]) || - ip == 0 || ip == htonl(INADDR_BROADCAST)) { + __be32 ip = in_aton(arp_ip_target[i]); + if (!isdigit(arp_ip_target[i][0]) || ip == 0 || + ip == htonl(INADDR_BROADCAST)) { pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n", - arp_ip_target[arp_ip_count]); + arp_ip_target[i]); arp_interval = 0; } else { - arp_target[arp_ip_count] = ip; + arp_target[arp_ip_count++] = ip; } } @@ -4696,8 +4707,6 @@ static int bond_check_params(struct bond_params *params) if (miimon) { pr_info("MII link monitoring set to %d ms\n", miimon); } else if (arp_interval) { - int i; - pr_info("ARP monitoring set to %d ms, validate %s, with %d target(s):", arp_interval, arp_validate_tbl[arp_validate_value].modename, diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 94d06f1307b8..4060d41f0ee7 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -130,7 +130,7 @@ static void bond_info_show_master(struct seq_file *seq) seq_printf(seq, "Aggregator selection policy (ad_select): %s\n", ad_select_tbl[bond->params.ad_select].modename); - if (bond_3ad_get_active_agg_info(bond, &ad_info)) { + if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { seq_printf(seq, "bond %s has no active aggregator\n", bond->dev->name); } else { diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ea7a388f4843..d7434e0a610e 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -316,6 +316,9 @@ static ssize_t bonding_store_mode(struct device *d, int new_value, ret = count; struct bonding *bond = to_bond(d); + if (!rtnl_trylock()) + return restart_syscall(); + if (bond->dev->flags & IFF_UP) { pr_err("unable to update mode of %s because interface is up.\n", bond->dev->name); @@ -352,6 +355,7 @@ static ssize_t bonding_store_mode(struct device *d, bond->dev->name, bond_mode_tbl[new_value].modename, new_value); out: + rtnl_unlock(); return ret; } static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, @@ -1315,7 +1319,6 @@ static ssize_t bonding_show_mii_status(struct device *d, } static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); - /* * Show current 802.3ad aggregator ID. */ @@ -1329,7 +1332,7 @@ static ssize_t bonding_show_ad_aggregator(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; count = sprintf(buf, "%d\n", - (bond_3ad_get_active_agg_info(bond, &ad_info)) + bond_3ad_get_active_agg_info(bond, &ad_info) ? 0 : ad_info.aggregator_id); } @@ -1351,7 +1354,7 @@ static ssize_t bonding_show_ad_num_ports(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; count = sprintf(buf, "%d\n", - (bond_3ad_get_active_agg_info(bond, &ad_info)) + bond_3ad_get_active_agg_info(bond, &ad_info) ? 0 : ad_info.ports); } @@ -1373,7 +1376,7 @@ static ssize_t bonding_show_ad_actor_key(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; count = sprintf(buf, "%d\n", - (bond_3ad_get_active_agg_info(bond, &ad_info)) + bond_3ad_get_active_agg_info(bond, &ad_info) ? 0 : ad_info.actor_key); } @@ -1395,7 +1398,7 @@ static ssize_t bonding_show_ad_partner_key(struct device *d, if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; count = sprintf(buf, "%d\n", - (bond_3ad_get_active_agg_info(bond, &ad_info)) + bond_3ad_get_active_agg_info(bond, &ad_info) ? 0 : ad_info.partner_key); } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 2baec24388b1..f989e1529a29 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -225,7 +225,7 @@ struct bonding { rwlock_t curr_slave_lock; u8 send_peer_notif; s8 setup_by_slave; - s8 igmp_retrans; + u8 igmp_retrans; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_entry; char proc_file_name[IFNAMSIZ]; diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 9b74d1e3ad44..6aa7b3266c80 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -612,9 +612,15 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv) { struct esd_usb2 *dev = priv->usb2; struct net_device *netdev = priv->netdev; - struct esd_usb2_msg msg; + struct esd_usb2_msg *msg; int err, i; + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) { + err = -ENOMEM; + goto out; + } + /* * Enable all IDs * The IDADD message takes up to 64 32 bit bitmasks (2048 bits). @@ -628,33 +634,32 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv) * the number of the starting bitmask (0..64) to the filter.option * field followed by only some bitmasks. */ - msg.msg.hdr.cmd = CMD_IDADD; - msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; - msg.msg.filter.net = priv->index; - msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ + msg->msg.hdr.cmd = CMD_IDADD; + msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; + msg->msg.filter.net = priv->index; + msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ for (i = 0; i < ESD_MAX_ID_SEGMENT; i++) - msg.msg.filter.mask[i] = cpu_to_le32(0xffffffff); + msg->msg.filter.mask[i] = cpu_to_le32(0xffffffff); /* enable 29bit extended IDs */ - msg.msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001); + msg->msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001); - err = esd_usb2_send_msg(dev, &msg); + err = esd_usb2_send_msg(dev, msg); if (err) - goto failed; + goto out; err = esd_usb2_setup_rx_urbs(dev); if (err) - goto failed; + goto out; priv->can.state = CAN_STATE_ERROR_ACTIVE; - return 0; - -failed: +out: if (err == -ENODEV) netif_device_detach(netdev); + if (err) + netdev_err(netdev, "couldn't start device: %d\n", err); - netdev_err(netdev, "couldn't start device: %d\n", err); - + kfree(msg); return err; } @@ -833,26 +838,30 @@ nourbmem: static int esd_usb2_close(struct net_device *netdev) { struct esd_usb2_net_priv *priv = netdev_priv(netdev); - struct esd_usb2_msg msg; + struct esd_usb2_msg *msg; int i; + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + /* Disable all IDs (see esd_usb2_start()) */ - msg.msg.hdr.cmd = CMD_IDADD; - msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; - msg.msg.filter.net = priv->index; - msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ + msg->msg.hdr.cmd = CMD_IDADD; + msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT; + msg->msg.filter.net = priv->index; + msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */ for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++) - msg.msg.filter.mask[i] = 0; - if (esd_usb2_send_msg(priv->usb2, &msg) < 0) + msg->msg.filter.mask[i] = 0; + if (esd_usb2_send_msg(priv->usb2, msg) < 0) netdev_err(netdev, "sending idadd message failed\n"); /* set CAN controller to reset mode */ - msg.msg.hdr.len = 2; - msg.msg.hdr.cmd = CMD_SETBAUD; - msg.msg.setbaud.net = priv->index; - msg.msg.setbaud.rsvd = 0; - msg.msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE); - if (esd_usb2_send_msg(priv->usb2, &msg) < 0) + msg->msg.hdr.len = 2; + msg->msg.hdr.cmd = CMD_SETBAUD; + msg->msg.setbaud.net = priv->index; + msg->msg.setbaud.rsvd = 0; + msg->msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE); + if (esd_usb2_send_msg(priv->usb2, msg) < 0) netdev_err(netdev, "sending setbaud message failed\n"); priv->can.state = CAN_STATE_STOPPED; @@ -861,6 +870,8 @@ static int esd_usb2_close(struct net_device *netdev) close_candev(netdev); + kfree(msg); + return 0; } @@ -886,7 +897,8 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) { struct esd_usb2_net_priv *priv = netdev_priv(netdev); struct can_bittiming *bt = &priv->can.bittiming; - struct esd_usb2_msg msg; + struct esd_usb2_msg *msg; + int err; u32 canbtr; int sjw_shift; @@ -912,15 +924,22 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) canbtr |= ESD_USB2_3_SAMPLES; - msg.msg.hdr.len = 2; - msg.msg.hdr.cmd = CMD_SETBAUD; - msg.msg.setbaud.net = priv->index; - msg.msg.setbaud.rsvd = 0; - msg.msg.setbaud.baud = cpu_to_le32(canbtr); + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->msg.hdr.len = 2; + msg->msg.hdr.cmd = CMD_SETBAUD; + msg->msg.setbaud.net = priv->index; + msg->msg.setbaud.rsvd = 0; + msg->msg.setbaud.baud = cpu_to_le32(canbtr); netdev_info(netdev, "setting BTR=%#x\n", canbtr); - return esd_usb2_send_msg(priv->usb2, &msg); + err = esd_usb2_send_msg(priv->usb2, msg); + + kfree(msg); + return err; } static int esd_usb2_get_berr_counter(const struct net_device *netdev, @@ -1022,7 +1041,7 @@ static int esd_usb2_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct esd_usb2 *dev; - struct esd_usb2_msg msg; + struct esd_usb2_msg *msg; int i, err; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -1037,27 +1056,33 @@ static int esd_usb2_probe(struct usb_interface *intf, usb_set_intfdata(intf, dev); + msg = kmalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) { + err = -ENOMEM; + goto free_msg; + } + /* query number of CAN interfaces (nets) */ - msg.msg.hdr.cmd = CMD_VERSION; - msg.msg.hdr.len = 2; - msg.msg.version.rsvd = 0; - msg.msg.version.flags = 0; - msg.msg.version.drv_version = 0; + msg->msg.hdr.cmd = CMD_VERSION; + msg->msg.hdr.len = 2; + msg->msg.version.rsvd = 0; + msg->msg.version.flags = 0; + msg->msg.version.drv_version = 0; - err = esd_usb2_send_msg(dev, &msg); + err = esd_usb2_send_msg(dev, msg); if (err < 0) { dev_err(&intf->dev, "sending version message failed\n"); - goto free_dev; + goto free_msg; } - err = esd_usb2_wait_msg(dev, &msg); + err = esd_usb2_wait_msg(dev, msg); if (err < 0) { dev_err(&intf->dev, "no version message answer\n"); - goto free_dev; + goto free_msg; } - dev->net_count = (int)msg.msg.version_reply.nets; - dev->version = le32_to_cpu(msg.msg.version_reply.version); + dev->net_count = (int)msg->msg.version_reply.nets; + dev->version = le32_to_cpu(msg->msg.version_reply.version); if (device_create_file(&intf->dev, &dev_attr_firmware)) dev_err(&intf->dev, @@ -1075,10 +1100,10 @@ static int esd_usb2_probe(struct usb_interface *intf, for (i = 0; i < dev->net_count; i++) esd_usb2_probe_one_net(intf, i); - return 0; - -free_dev: - kfree(dev); +free_msg: + kfree(msg); + if (err) + kfree(dev); done: return err; } diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 45cb9f3c1324..3b9546588240 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -136,6 +136,9 @@ #define KVASER_CTRL_MODE_SELFRECEPTION 3 #define KVASER_CTRL_MODE_OFF 4 +/* log message */ +#define KVASER_EXTENDED_FRAME BIT(31) + struct kvaser_msg_simple { u8 tid; u8 channel; @@ -817,8 +820,13 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, priv = dev->nets[channel]; stats = &priv->netdev->stats; - if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | MSG_FLAG_NERR | - MSG_FLAG_OVERRUN)) { + if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) && + (msg->id == CMD_LOG_MESSAGE)) { + kvaser_usb_rx_error(dev, msg); + return; + } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | + MSG_FLAG_NERR | + MSG_FLAG_OVERRUN)) { kvaser_usb_rx_can_err(priv, msg); return; } else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) { @@ -834,22 +842,40 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev, return; } - cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) | - (msg->u.rx_can.msg[1] & 0x3f); - cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]); + if (msg->id == CMD_LOG_MESSAGE) { + cf->can_id = le32_to_cpu(msg->u.log_message.id); + if (cf->can_id & KVASER_EXTENDED_FRAME) + cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG; + else + cf->can_id &= CAN_SFF_MASK; - if (msg->id == CMD_RX_EXT_MESSAGE) { - cf->can_id <<= 18; - cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) | - ((msg->u.rx_can.msg[3] & 0xff) << 6) | - (msg->u.rx_can.msg[4] & 0x3f); - cf->can_id |= CAN_EFF_FLAG; - } + cf->can_dlc = get_can_dlc(msg->u.log_message.dlc); - if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) - cf->can_id |= CAN_RTR_FLAG; - else - memcpy(cf->data, &msg->u.rx_can.msg[6], cf->can_dlc); + if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME) + cf->can_id |= CAN_RTR_FLAG; + else + memcpy(cf->data, &msg->u.log_message.data, + cf->can_dlc); + } else { + cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) | + (msg->u.rx_can.msg[1] & 0x3f); + + if (msg->id == CMD_RX_EXT_MESSAGE) { + cf->can_id <<= 18; + cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) | + ((msg->u.rx_can.msg[3] & 0xff) << 6) | + (msg->u.rx_can.msg[4] & 0x3f); + cf->can_id |= CAN_EFF_FLAG; + } + + cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]); + + if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) + cf->can_id |= CAN_RTR_FLAG; + else + memcpy(cf->data, &msg->u.rx_can.msg[6], + cf->can_dlc); + } netif_rx(skb); @@ -911,6 +937,7 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev, case CMD_RX_STD_MESSAGE: case CMD_RX_EXT_MESSAGE: + case CMD_LOG_MESSAGE: kvaser_usb_rx_can_msg(dev, msg); break; @@ -919,11 +946,6 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev, kvaser_usb_rx_error(dev, msg); break; - case CMD_LOG_MESSAGE: - if (msg->u.log_message.flags & MSG_FLAG_ERROR_FRAME) - kvaser_usb_rx_error(dev, msg); - break; - case CMD_TX_ACKNOWLEDGE: kvaser_usb_tx_acknowledge(dev, msg); break; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 30d79bfa5b10..8ee9d1556e6e 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -504,15 +504,24 @@ static int pcan_usb_pro_restart_async(struct peak_usb_device *dev, return usb_submit_urb(urb, GFP_ATOMIC); } -static void pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded) +static int pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded) { - u8 buffer[16]; + u8 *buffer; + int err; + + buffer = kmalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL); + if (!buffer) + return -ENOMEM; buffer[0] = 0; buffer[1] = !!loaded; - pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT, - PCAN_USBPRO_FCT_DRVLD, buffer, sizeof(buffer)); + err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT, + PCAN_USBPRO_FCT_DRVLD, buffer, + PCAN_USBPRO_FCT_DRVLD_REQ_LEN); + kfree(buffer); + + return err; } static inline @@ -851,21 +860,24 @@ static int pcan_usb_pro_stop(struct peak_usb_device *dev) */ static int pcan_usb_pro_init(struct peak_usb_device *dev) { - struct pcan_usb_pro_interface *usb_if; struct pcan_usb_pro_device *pdev = container_of(dev, struct pcan_usb_pro_device, dev); + struct pcan_usb_pro_interface *usb_if = NULL; + struct pcan_usb_pro_fwinfo *fi = NULL; + struct pcan_usb_pro_blinfo *bi = NULL; + int err; /* do this for 1st channel only */ if (!dev->prev_siblings) { - struct pcan_usb_pro_fwinfo fi; - struct pcan_usb_pro_blinfo bi; - int err; - /* allocate netdevices common structure attached to first one */ usb_if = kzalloc(sizeof(struct pcan_usb_pro_interface), GFP_KERNEL); - if (!usb_if) - return -ENOMEM; + fi = kmalloc(sizeof(struct pcan_usb_pro_fwinfo), GFP_KERNEL); + bi = kmalloc(sizeof(struct pcan_usb_pro_blinfo), GFP_KERNEL); + if (!usb_if || !fi || !bi) { + err = -ENOMEM; + goto err_out; + } /* number of ts msgs to ignore before taking one into account */ usb_if->cm_ignore_count = 5; @@ -877,34 +889,34 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev) */ err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, PCAN_USBPRO_INFO_FW, - &fi, sizeof(fi)); + fi, sizeof(*fi)); if (err) { - kfree(usb_if); dev_err(dev->netdev->dev.parent, "unable to read %s firmware info (err %d)\n", pcan_usb_pro.name, err); - return err; + goto err_out; } err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, PCAN_USBPRO_INFO_BL, - &bi, sizeof(bi)); + bi, sizeof(*bi)); if (err) { - kfree(usb_if); dev_err(dev->netdev->dev.parent, "unable to read %s bootloader info (err %d)\n", pcan_usb_pro.name, err); - return err; + goto err_out; } + /* tell the device the can driver is running */ + err = pcan_usb_pro_drv_loaded(dev, 1); + if (err) + goto err_out; + dev_info(dev->netdev->dev.parent, "PEAK-System %s hwrev %u serial %08X.%08X (%u channels)\n", pcan_usb_pro.name, - bi.hw_rev, bi.serial_num_hi, bi.serial_num_lo, + bi->hw_rev, bi->serial_num_hi, bi->serial_num_lo, pcan_usb_pro.ctrl_count); - - /* tell the device the can driver is running */ - pcan_usb_pro_drv_loaded(dev, 1); } else { usb_if = pcan_usb_pro_dev_if(dev->prev_siblings); } @@ -916,6 +928,13 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev) pcan_usb_pro_set_led(dev, 0, 1); return 0; + + err_out: + kfree(bi); + kfree(fi); + kfree(usb_if); + + return err; } static void pcan_usb_pro_exit(struct peak_usb_device *dev) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h index a869918c5620..32275af547e0 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h @@ -29,6 +29,7 @@ /* Vendor Request value for XXX_FCT */ #define PCAN_USBPRO_FCT_DRVLD 5 /* tell device driver is loaded */ +#define PCAN_USBPRO_FCT_DRVLD_REQ_LEN 16 /* PCAN_USBPRO_INFO_BL vendor request record type */ struct __packed pcan_usb_pro_blinfo { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index b8fbe266ab68..638e55435b04 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3192,11 +3192,11 @@ static u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb) rc |= XMIT_CSUM_TCP; if (skb_is_gso_v6(skb)) { - rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6); + rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP); if (rc & XMIT_CSUM_ENC) rc |= XMIT_GSO_ENC_V6; } else if (skb_is_gso(skb)) { - rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP); + rc |= (XMIT_GSO_V4 | XMIT_CSUM_TCP); if (rc & XMIT_CSUM_ENC) rc |= XMIT_GSO_ENC_V4; } @@ -3313,6 +3313,7 @@ static void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data, */ static void bnx2x_set_pbd_gso(struct sk_buff *skb, struct eth_tx_parse_bd_e1x *pbd, + struct eth_tx_start_bd *tx_start_bd, u32 xmit_type) { pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size); @@ -3326,11 +3327,14 @@ static void bnx2x_set_pbd_gso(struct sk_buff *skb, ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0)); - } else + /* GSO on 57710/57711 needs FW to calculate IP checksum */ + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM; + } else { pbd->tcp_pseudo_csum = bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0)); + } pbd->global_data |= cpu_to_le16(ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN); @@ -3479,19 +3483,18 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb, { u16 hlen_w = 0; u8 outerip_off, outerip_len = 0; + /* from outer IP to transport */ hlen_w = (skb_inner_transport_header(skb) - skb_network_header(skb)) >> 1; /* transport len */ - if (xmit_type & XMIT_CSUM_TCP) - hlen_w += inner_tcp_hdrlen(skb) >> 1; - else - hlen_w += sizeof(struct udphdr) >> 1; + hlen_w += inner_tcp_hdrlen(skb) >> 1; pbd2->fw_ip_hdr_to_payload_w = hlen_w; - if (xmit_type & XMIT_CSUM_ENC_V4) { + /* outer IP header info */ + if (xmit_type & XMIT_CSUM_V4) { struct iphdr *iph = ip_hdr(skb); pbd2->fw_ip_csum_wo_len_flags_frag = bswab16(csum_fold((~iph->check) - @@ -3814,7 +3817,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data, xmit_type); else - bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type); + bnx2x_set_pbd_gso(skb, pbd_e1x, first_bd, xmit_type); } /* Set the PBD's parsing_data field if not zero diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 728d42ab2a76..c777b9013164 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -94,10 +94,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 131 +#define TG3_MIN_NUM 132 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "April 09, 2013" +#define DRV_MODULE_RELDATE "May 21, 2013" #define RESET_KIND_SHUTDOWN 0 #define RESET_KIND_INIT 1 @@ -1800,6 +1800,9 @@ static int tg3_poll_fw(struct tg3 *tp) int i; u32 val; + if (tg3_flag(tp, NO_FWARE_REPORTED)) + return 0; + if (tg3_flag(tp, IS_SSB_CORE)) { /* We don't use firmware. */ return 0; @@ -2957,6 +2960,31 @@ static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed) return 0; } +static bool tg3_phy_power_bug(struct tg3 *tp) +{ + switch (tg3_asic_rev(tp)) { + case ASIC_REV_5700: + case ASIC_REV_5704: + return true; + case ASIC_REV_5780: + if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) + return true; + return false; + case ASIC_REV_5717: + if (!tp->pci_fn) + return true; + return false; + case ASIC_REV_5719: + case ASIC_REV_5720: + if ((tp->phy_flags & TG3_PHYFLG_PHY_SERDES) && + !tp->pci_fn) + return true; + return false; + } + + return false; +} + static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) { u32 val; @@ -3016,12 +3044,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) /* The PHY should not be powered down on some chips because * of bugs. */ - if (tg3_asic_rev(tp) == ASIC_REV_5700 || - tg3_asic_rev(tp) == ASIC_REV_5704 || - (tg3_asic_rev(tp) == ASIC_REV_5780 && - (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) || - (tg3_asic_rev(tp) == ASIC_REV_5717 && - !tp->pci_fn)) + if (tg3_phy_power_bug(tp)) return; if (tg3_chip_rev(tp) == CHIPREV_5784_AX || @@ -7428,6 +7451,20 @@ static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) return (base > 0xffffdcc0) && (base + len + 8 < base); } +/* Test for TSO DMA buffers that cross into regions which are within MSS bytes + * of any 4GB boundaries: 4G, 8G, etc + */ +static inline int tg3_4g_tso_overflow_test(struct tg3 *tp, dma_addr_t mapping, + u32 len, u32 mss) +{ + if (tg3_asic_rev(tp) == ASIC_REV_5762 && mss) { + u32 base = (u32) mapping & 0xffffffff; + + return ((base + len + (mss & 0x3fff)) < base); + } + return 0; +} + /* Test for DMA addresses > 40-bit */ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, int len) @@ -7464,6 +7501,9 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget, if (tg3_4g_overflow_test(map, len)) hwbug = true; + if (tg3_4g_tso_overflow_test(tp, map, len, mss)) + hwbug = true; + if (tg3_40bit_overflow_test(tp, map, len)) hwbug = true; @@ -8874,6 +8914,10 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_halt_cpu(tp, RX_CPU_BASE); } + err = tg3_poll_fw(tp); + if (err) + return err; + tw32(GRC_MODE, tp->grc_mode); if (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A0) { @@ -8904,10 +8948,6 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_ape_unlock(tp, TG3_APE_LOCK_GRC); - err = tg3_poll_fw(tp); - if (err) - return err; - tg3_mdio_start(tp); if (tg3_flag(tp, PCI_EXPRESS) && @@ -9431,6 +9471,14 @@ static void tg3_rss_write_indir_tbl(struct tg3 *tp) } } +static inline u32 tg3_lso_rd_dma_workaround_bit(struct tg3 *tp) +{ + if (tg3_asic_rev(tp) == ASIC_REV_5719) + return TG3_LSO_RD_DMA_TX_LENGTH_WA_5719; + else + return TG3_LSO_RD_DMA_TX_LENGTH_WA_5720; +} + /* tp->lock is held. */ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) { @@ -10116,16 +10164,17 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) tw32_f(RDMAC_MODE, rdmac_mode); udelay(40); - if (tg3_asic_rev(tp) == ASIC_REV_5719) { + if (tg3_asic_rev(tp) == ASIC_REV_5719 || + tg3_asic_rev(tp) == ASIC_REV_5720) { for (i = 0; i < TG3_NUM_RDMA_CHANNELS; i++) { if (tr32(TG3_RDMA_LENGTH + (i << 2)) > TG3_MAX_MTU(tp)) break; } if (i < TG3_NUM_RDMA_CHANNELS) { val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL); - val |= TG3_LSO_RD_DMA_TX_LENGTH_WA; + val |= tg3_lso_rd_dma_workaround_bit(tp); tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val); - tg3_flag_set(tp, 5719_RDMA_BUG); + tg3_flag_set(tp, 5719_5720_RDMA_BUG); } } @@ -10358,6 +10407,13 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) */ static int tg3_init_hw(struct tg3 *tp, bool reset_phy) { + /* Chip may have been just powered on. If so, the boot code may still + * be running initialization. Wait for it to finish to avoid races in + * accessing the hardware. + */ + tg3_enable_register_access(tp); + tg3_poll_fw(tp); + tg3_switch_clocks(tp); tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0); @@ -10489,15 +10545,15 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp) TG3_STAT_ADD32(&sp->tx_ucast_packets, MAC_TX_STATS_UCAST); TG3_STAT_ADD32(&sp->tx_mcast_packets, MAC_TX_STATS_MCAST); TG3_STAT_ADD32(&sp->tx_bcast_packets, MAC_TX_STATS_BCAST); - if (unlikely(tg3_flag(tp, 5719_RDMA_BUG) && + if (unlikely(tg3_flag(tp, 5719_5720_RDMA_BUG) && (sp->tx_ucast_packets.low + sp->tx_mcast_packets.low + sp->tx_bcast_packets.low) > TG3_NUM_RDMA_CHANNELS)) { u32 val; val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL); - val &= ~TG3_LSO_RD_DMA_TX_LENGTH_WA; + val &= ~tg3_lso_rd_dma_workaround_bit(tp); tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val); - tg3_flag_clear(tp, 5719_RDMA_BUG); + tg3_flag_clear(tp, 5719_5720_RDMA_BUG); } TG3_STAT_ADD32(&sp->rx_octets, MAC_RX_STATS_OCTETS); diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 9b2d3ac2474a..ff6e30eeae35 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -1422,7 +1422,8 @@ #define TG3_LSO_RD_DMA_CRPTEN_CTRL 0x00004910 #define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K 0x00030000 #define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K 0x000c0000 -#define TG3_LSO_RD_DMA_TX_LENGTH_WA 0x02000000 +#define TG3_LSO_RD_DMA_TX_LENGTH_WA_5719 0x02000000 +#define TG3_LSO_RD_DMA_TX_LENGTH_WA_5720 0x00200000 /* 0x4914 --> 0x4be0 unused */ #define TG3_NUM_RDMA_CHANNELS 4 @@ -3059,7 +3060,7 @@ enum TG3_FLAGS { TG3_FLAG_APE_HAS_NCSI, TG3_FLAG_TX_TSTAMP_EN, TG3_FLAG_4K_FIFO_LIMIT, - TG3_FLAG_5719_RDMA_BUG, + TG3_FLAG_5719_5720_RDMA_BUG, TG3_FLAG_RESET_TASK_PENDING, TG3_FLAG_PTP_CAPABLE, TG3_FLAG_5705_PLUS, diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c index 6e8bc9d88c41..94d957d203a6 100644 --- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c +++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c @@ -244,7 +244,7 @@ bnad_debugfs_lseek(struct file *file, loff_t offset, int orig) file->f_pos += offset; break; case 2: - file->f_pos = debug->buffer_len - offset; + file->f_pos = debug->buffer_len + offset; break; default: return -EINVAL; diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 6be513deb17f..c89aa41dd448 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -485,7 +485,8 @@ static void macb_tx_interrupt(struct macb *bp) status = macb_readl(bp, TSR); macb_writel(bp, TSR, status); - macb_writel(bp, ISR, MACB_BIT(TCOMP)); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + macb_writel(bp, ISR, MACB_BIT(TCOMP)); netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n", (unsigned long)status); @@ -738,7 +739,8 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) * now. */ macb_writel(bp, IDR, MACB_RX_INT_FLAGS); - macb_writel(bp, ISR, MACB_BIT(RCOMP)); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + macb_writel(bp, ISR, MACB_BIT(RCOMP)); if (napi_schedule_prep(&bp->napi)) { netdev_vdbg(bp->dev, "scheduling RX softirq\n"); @@ -1062,6 +1064,17 @@ static void macb_configure_dma(struct macb *bp) } } +/* + * Configure peripheral capacities according to integration options used + */ +static void macb_configure_caps(struct macb *bp) +{ + if (macb_is_gem(bp)) { + if (GEM_BF(IRQCOR, gem_readl(bp, DCFG1)) == 0) + bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE; + } +} + static void macb_init_hw(struct macb *bp) { u32 config; @@ -1084,6 +1097,7 @@ static void macb_init_hw(struct macb *bp) bp->duplex = DUPLEX_HALF; macb_configure_dma(bp); + macb_configure_caps(bp); /* Initialize TX and RX buffers */ macb_writel(bp, RBQP, bp->rx_ring_dma); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 993d70380688..548c0ecae869 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -300,6 +300,8 @@ #define MACB_REV_SIZE 16 /* Bitfields in DCFG1. */ +#define GEM_IRQCOR_OFFSET 23 +#define GEM_IRQCOR_SIZE 1 #define GEM_DBWDEF_OFFSET 25 #define GEM_DBWDEF_SIZE 3 @@ -323,6 +325,9 @@ #define MACB_MAN_READ 2 #define MACB_MAN_CODE 2 +/* Capability mask bits */ +#define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x1 + /* Bit manipulation macros */ #define MACB_BIT(name) \ (1 << MACB_##name##_OFFSET) @@ -574,6 +579,8 @@ struct macb { unsigned int speed; unsigned int duplex; + u32 caps; + phy_interface_t phy_interface; /* AT91RM9200 transmit */ diff --git a/drivers/net/ethernet/dec/tulip/interrupt.c b/drivers/net/ethernet/dec/tulip/interrupt.c index 28a5e425fecf..92306b320840 100644 --- a/drivers/net/ethernet/dec/tulip/interrupt.c +++ b/drivers/net/ethernet/dec/tulip/interrupt.c @@ -76,6 +76,12 @@ int tulip_refill_rx(struct net_device *dev) mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + if (dma_mapping_error(&tp->pdev->dev, mapping)) { + dev_kfree_skb(skb); + tp->rx_buffers[entry].skb = NULL; + break; + } + tp->rx_buffers[entry].mapping = mapping; tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping); diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index f544b297c9ab..0a510684e468 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -262,6 +262,7 @@ struct be_rx_compl_info { u8 ipv6; u8 vtm; u8 pkt_type; + u8 ip_frag; }; struct be_rx_obj { diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index fd7b547698ab..1db2df61b8af 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -562,7 +562,7 @@ int lancer_test_and_set_rdy_state(struct be_adapter *adapter) resource_error = lancer_provisioning_error(adapter); if (resource_error) - return -1; + return -EAGAIN; status = lancer_wait_ready(adapter); if (!status) { @@ -590,8 +590,8 @@ int lancer_test_and_set_rdy_state(struct be_adapter *adapter) * when PF provisions resources. */ resource_error = lancer_provisioning_error(adapter); - if (status == -1 && !resource_error) - adapter->eeh_error = true; + if (resource_error) + status = -EAGAIN; return status; } @@ -2976,22 +2976,17 @@ static struct be_nic_resource_desc *be_get_nic_desc(u8 *buf, u32 desc_count, for (i = 0; i < desc_count; i++) { desc->desc_len = desc->desc_len ? : RESOURCE_DESC_SIZE; if (((void *)desc + desc->desc_len) > - (void *)(buf + max_buf_size)) { - desc = NULL; - break; - } + (void *)(buf + max_buf_size)) + return NULL; if (desc->desc_type == NIC_RESOURCE_DESC_TYPE_V0 || desc->desc_type == NIC_RESOURCE_DESC_TYPE_V1) - break; + return desc; desc = (void *)desc + desc->desc_len; } - if (!desc || i == MAX_RESOURCE_DESC) - return NULL; - - return desc; + return NULL; } /* Uses Mbox */ diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index 3c1099b47f2a..8780183c6d1c 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -356,7 +356,7 @@ struct amap_eth_rx_compl_v0 { u8 ip_version; /* dword 1 */ u8 macdst[6]; /* dword 1 */ u8 vtp; /* dword 1 */ - u8 rsvd0; /* dword 1 */ + u8 ip_frag; /* dword 1 */ u8 fragndx[10]; /* dword 1 */ u8 ct[2]; /* dword 1 */ u8 sw; /* dword 1 */ diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index a444110b060f..a0b4be51f0d1 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -780,26 +780,18 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter, if (unlikely(!skb)) return skb; - if (vlan_tx_tag_present(skb)) { + if (vlan_tx_tag_present(skb)) vlan_tag = be_get_tx_vlan_tag(adapter, skb); - skb = __vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); - if (skb) - skb->vlan_tci = 0; - } - - if (qnq_async_evt_rcvd(adapter) && adapter->pvid) { - if (!vlan_tag) - vlan_tag = adapter->pvid; - if (skip_hw_vlan) - *skip_hw_vlan = true; - } + else if (qnq_async_evt_rcvd(adapter) && adapter->pvid) + vlan_tag = adapter->pvid; if (vlan_tag) { skb = __vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); if (unlikely(!skb)) return skb; - skb->vlan_tci = 0; + if (skip_hw_vlan) + *skip_hw_vlan = true; } /* Insert the outer VLAN, if any */ @@ -1607,6 +1599,8 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl, compl); } rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, port, compl); + rxcp->ip_frag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, + ip_frag, compl); } static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) @@ -1628,6 +1622,9 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) else be_parse_rx_compl_v0(compl, rxcp); + if (rxcp->ip_frag) + rxcp->l4_csum = 0; + if (rxcp->vlanf) { /* vlanf could be wrongly set in some cards. * ignore if vtm is not set */ @@ -2176,7 +2173,7 @@ static irqreturn_t be_msix(int irq, void *dev) static inline bool do_gro(struct be_rx_compl_info *rxcp) { - return (rxcp->tcpf && !rxcp->err) ? true : false; + return (rxcp->tcpf && !rxcp->err && rxcp->l4_csum) ? true : false; } static int be_process_rx(struct be_rx_obj *rxo, struct napi_struct *napi, @@ -4101,6 +4098,7 @@ static int be_get_initial_config(struct be_adapter *adapter) static int lancer_recover_func(struct be_adapter *adapter) { + struct device *dev = &adapter->pdev->dev; int status; status = lancer_test_and_set_rdy_state(adapter); @@ -4112,8 +4110,7 @@ static int lancer_recover_func(struct be_adapter *adapter) be_clear(adapter); - adapter->hw_error = false; - adapter->fw_timeout = false; + be_clear_all_error(adapter); status = be_setup(adapter); if (status) @@ -4125,13 +4122,13 @@ static int lancer_recover_func(struct be_adapter *adapter) goto err; } - dev_err(&adapter->pdev->dev, - "Adapter SLIPORT recovery succeeded\n"); + dev_err(dev, "Error recovery successful\n"); return 0; err: - if (adapter->eeh_error) - dev_err(&adapter->pdev->dev, - "Adapter SLIPORT recovery failed\n"); + if (status == -EAGAIN) + dev_err(dev, "Waiting for resource provisioning\n"); + else + dev_err(dev, "Error recovery failed\n"); return status; } @@ -4140,28 +4137,27 @@ static void be_func_recovery_task(struct work_struct *work) { struct be_adapter *adapter = container_of(work, struct be_adapter, func_recovery_work.work); - int status; + int status = 0; be_detect_error(adapter); if (adapter->hw_error && lancer_chip(adapter)) { - if (adapter->eeh_error) - goto out; - rtnl_lock(); netif_device_detach(adapter->netdev); rtnl_unlock(); status = lancer_recover_func(adapter); - if (!status) netif_device_attach(adapter->netdev); } -out: - schedule_delayed_work(&adapter->func_recovery_work, - msecs_to_jiffies(1000)); + /* In Lancer, for all errors other than provisioning error (-EAGAIN), + * no need to attempt further recovery. + */ + if (!status || status == -EAGAIN) + schedule_delayed_work(&adapter->func_recovery_work, + msecs_to_jiffies(1000)); } static void be_worker(struct work_struct *work) @@ -4266,6 +4262,9 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id) netdev->features |= NETIF_F_HIGHDMA; } else { status = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (!status) + status = dma_set_coherent_mask(&pdev->dev, + DMA_BIT_MASK(32)); if (status) { dev_err(&pdev->dev, "Could not set PCI DMA Mask\n"); goto free_netdev; @@ -4444,20 +4443,19 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev, dev_err(&adapter->pdev->dev, "EEH error detected\n"); - adapter->eeh_error = true; + if (!adapter->eeh_error) { + adapter->eeh_error = true; - cancel_delayed_work_sync(&adapter->func_recovery_work); + cancel_delayed_work_sync(&adapter->func_recovery_work); - rtnl_lock(); - netif_device_detach(netdev); - rtnl_unlock(); - - if (netif_running(netdev)) { rtnl_lock(); - be_close(netdev); + netif_device_detach(netdev); + if (netif_running(netdev)) + be_close(netdev); rtnl_unlock(); + + be_clear(adapter); } - be_clear(adapter); if (state == pci_channel_io_perm_failure) return PCI_ERS_RESULT_DISCONNECT; @@ -4482,7 +4480,6 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) int status; dev_info(&adapter->pdev->dev, "EEH reset\n"); - be_clear_all_error(adapter); status = pci_enable_device(pdev); if (status) @@ -4500,6 +4497,7 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; pci_cleanup_aer_uncorrect_error_status(pdev); + be_clear_all_error(adapter); return PCI_ERS_RESULT_RECOVERED; } diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index ca9825ca88c9..a667015be22a 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -109,7 +109,7 @@ static struct platform_device_id fec_devtype[] = { .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM, }, { - .name = "mvf-fec", + .name = "mvf600-fec", .driver_data = FEC_QUIRK_ENET_MAC, }, { /* sentinel */ @@ -122,7 +122,7 @@ enum imx_fec_type { IMX27_FEC, /* runs on i.mx27/35/51 */ IMX28_FEC, IMX6Q_FEC, - MVF_FEC, + MVF600_FEC, }; static const struct of_device_id fec_dt_ids[] = { @@ -130,7 +130,7 @@ static const struct of_device_id fec_dt_ids[] = { { .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], }, { .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], }, { .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], }, - { .compatible = "fsl,mvf-fec", .data = &fec_devtype[MVF_FEC], }, + { .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fec_dt_ids); @@ -451,7 +451,7 @@ fec_restart(struct net_device *ndev, int duplex) netif_device_detach(ndev); napi_disable(&fep->napi); netif_stop_queue(ndev); - netif_tx_lock(ndev); + netif_tx_lock_bh(ndev); } /* Whack a reset. We should wait for this. */ @@ -616,10 +616,10 @@ fec_restart(struct net_device *ndev, int duplex) writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); if (netif_running(ndev)) { - netif_device_attach(ndev); - napi_enable(&fep->napi); + netif_tx_unlock_bh(ndev); netif_wake_queue(ndev); - netif_tx_unlock(ndev); + napi_enable(&fep->napi); + netif_device_attach(ndev); } } @@ -1038,6 +1038,18 @@ static void fec_get_mac(struct net_device *ndev) iap = &tmpaddr[0]; } + /* + * 5) random mac address + */ + if (!is_valid_ether_addr(iap)) { + /* Report it and use a random ethernet address instead */ + netdev_err(ndev, "Invalid MAC address: %pM\n", iap); + eth_hw_addr_random(ndev); + netdev_info(ndev, "Using random MAC address: %pM\n", + ndev->dev_addr); + return; + } + memcpy(ndev->dev_addr, iap, ETH_ALEN); /* Adjust MAC if using macaddr */ diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index 576e4b858fce..083ea2b4d20a 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -524,6 +524,7 @@ static int gianfar_ptp_probe(struct platform_device *dev) return 0; no_clock: + iounmap(etsects->regs); no_ioremap: release_resource(etsects->rsrc); no_resource: diff --git a/drivers/net/ethernet/icplus/ipg.h b/drivers/net/ethernet/icplus/ipg.h index 6ce027355fcf..abb300a31912 100644 --- a/drivers/net/ethernet/icplus/ipg.h +++ b/drivers/net/ethernet/icplus/ipg.h @@ -195,57 +195,57 @@ enum ipg_regs { /* TFD data structure masks. */ /* TFDList, TFC */ -#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFF -#define IPG_TFC_FRAMEID 0x000000000000FFFF -#define IPG_TFC_WORDALIGN 0x0000000000030000 -#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000 -#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000 -#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000 -#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000 -#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000 -#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000 -#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000 -#define IPG_TFC_TXINDICATE 0x0000000000400000 -#define IPG_TFC_TXDMAINDICATE 0x0000000000800000 -#define IPG_TFC_FRAGCOUNT 0x000000000F000000 -#define IPG_TFC_VLANTAGINSERT 0x0000000010000000 -#define IPG_TFC_TFDDONE 0x0000000080000000 -#define IPG_TFC_VID 0x00000FFF00000000 -#define IPG_TFC_CFI 0x0000100000000000 -#define IPG_TFC_USERPRIORITY 0x0000E00000000000 +#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFFULL +#define IPG_TFC_FRAMEID 0x000000000000FFFFULL +#define IPG_TFC_WORDALIGN 0x0000000000030000ULL +#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000ULL +#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000ULL +#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000ULL +#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000ULL +#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000ULL +#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000ULL +#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000ULL +#define IPG_TFC_TXINDICATE 0x0000000000400000ULL +#define IPG_TFC_TXDMAINDICATE 0x0000000000800000ULL +#define IPG_TFC_FRAGCOUNT 0x000000000F000000ULL +#define IPG_TFC_VLANTAGINSERT 0x0000000010000000ULL +#define IPG_TFC_TFDDONE 0x0000000080000000ULL +#define IPG_TFC_VID 0x00000FFF00000000ULL +#define IPG_TFC_CFI 0x0000100000000000ULL +#define IPG_TFC_USERPRIORITY 0x0000E00000000000ULL /* TFDList, FragInfo */ -#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFF -#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFF -#define IPG_TFI_FRAGLEN 0xFFFF000000000000LL +#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL +#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFFULL +#define IPG_TFI_FRAGLEN 0xFFFF000000000000ULL /* RFD data structure masks. */ /* RFDList, RFS */ -#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFF -#define IPG_RFS_RXFRAMELEN 0x000000000000FFFF -#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000 -#define IPG_RFS_RXRUNTFRAME 0x0000000000020000 -#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000 -#define IPG_RFS_RXFCSERROR 0x0000000000080000 -#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000 -#define IPG_RFS_RXLENGTHERROR 0x0000000000200000 -#define IPG_RFS_VLANDETECTED 0x0000000000400000 -#define IPG_RFS_TCPDETECTED 0x0000000000800000 -#define IPG_RFS_TCPERROR 0x0000000001000000 -#define IPG_RFS_UDPDETECTED 0x0000000002000000 -#define IPG_RFS_UDPERROR 0x0000000004000000 -#define IPG_RFS_IPDETECTED 0x0000000008000000 -#define IPG_RFS_IPERROR 0x0000000010000000 -#define IPG_RFS_FRAMESTART 0x0000000020000000 -#define IPG_RFS_FRAMEEND 0x0000000040000000 -#define IPG_RFS_RFDDONE 0x0000000080000000 -#define IPG_RFS_TCI 0x0000FFFF00000000 +#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFFULL +#define IPG_RFS_RXFRAMELEN 0x000000000000FFFFULL +#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000ULL +#define IPG_RFS_RXRUNTFRAME 0x0000000000020000ULL +#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000ULL +#define IPG_RFS_RXFCSERROR 0x0000000000080000ULL +#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000ULL +#define IPG_RFS_RXLENGTHERROR 0x0000000000200000ULL +#define IPG_RFS_VLANDETECTED 0x0000000000400000ULL +#define IPG_RFS_TCPDETECTED 0x0000000000800000ULL +#define IPG_RFS_TCPERROR 0x0000000001000000ULL +#define IPG_RFS_UDPDETECTED 0x0000000002000000ULL +#define IPG_RFS_UDPERROR 0x0000000004000000ULL +#define IPG_RFS_IPDETECTED 0x0000000008000000ULL +#define IPG_RFS_IPERROR 0x0000000010000000ULL +#define IPG_RFS_FRAMESTART 0x0000000020000000ULL +#define IPG_RFS_FRAMEEND 0x0000000040000000ULL +#define IPG_RFS_RFDDONE 0x0000000080000000ULL +#define IPG_RFS_TCI 0x0000FFFF00000000ULL /* RFDList, FragInfo */ -#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFF -#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFF -#define IPG_RFI_FRAGLEN 0xFFFF000000000000LL +#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL +#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFFULL +#define IPG_RFI_FRAGLEN 0xFFFF000000000000ULL /* I/O Register masks. */ diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index d0afeea181fb..2ad1494efbb3 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -867,7 +867,7 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force) struct netdev_queue *nq = netdev_get_tx_queue(mp->dev, txq->index); int reclaimed; - __netif_tx_lock(nq, smp_processor_id()); + __netif_tx_lock_bh(nq); reclaimed = 0; while (reclaimed < budget && txq->tx_desc_count > 0) { @@ -913,7 +913,7 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force) dev_kfree_skb(skb); } - __netif_tx_unlock(nq); + __netif_tx_unlock_bh(nq); if (reclaimed < budget) mp->work_tx &= ~(1 << txq->index); @@ -2745,7 +2745,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) INIT_WORK(&mp->tx_timeout_task, tx_timeout_task); - netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 128); + netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, NAPI_POLL_WEIGHT); init_timer(&mp->rx_oom); mp->rx_oom.data = (unsigned long)mp; diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 1df56cc50ee9..0e572a527154 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -222,8 +222,6 @@ static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, * FLR process. The only non-zero result in the RESET command * is MLX4_DELAY_RESET_SLAVE*/ if ((MLX4_COMM_CMD_RESET == cmd)) { - mlx4_warn(dev, "Got slave FLRed from Communication" - " channel (ret:0x%x)\n", ret_from_pending); err = MLX4_DELAY_RESET_SLAVE; } else { mlx4_warn(dev, "Communication channel timed out\n"); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index b35f94700093..89c47ea84b50 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1323,6 +1323,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) priv->last_moder_time[ring] = moder_time; cq = &priv->rx_cq[ring]; cq->moder_time = moder_time; + cq->moder_cnt = priv->rx_frames; err = mlx4_en_set_cq_moder(priv, cq); if (err) en_err(priv, "Failed modifying moderation for cq:%d\n", @@ -2118,6 +2119,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, struct mlx4_en_priv *priv; int i; int err; + u64 mac_u64; dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv), MAX_TX_RINGS, MAX_RX_RINGS); @@ -2191,10 +2193,17 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, dev->addr_len = ETH_ALEN; mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]); if (!is_valid_ether_addr(dev->dev_addr)) { - en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n", - priv->port, dev->dev_addr); - err = -EINVAL; - goto out; + if (mlx4_is_slave(priv->mdev->dev)) { + eth_hw_addr_random(dev); + en_warn(priv, "Assigned random MAC address %pM\n", dev->dev_addr); + mac_u64 = mlx4_en_mac_to_u64(dev->dev_addr); + mdev->dev->caps.def_mac[priv->port] = mac_u64; + } else { + en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n", + priv->port, dev->dev_addr); + err = -EINVAL; + goto out; + } } memcpy(priv->prev_mac, dev->dev_addr, sizeof(priv->prev_mac)); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 58a8e535d698..2c97901c6a6d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -840,12 +840,16 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, MLX4_CMD_NATIVE); if (!err && dev->caps.function != slave) { - /* set slave default_mac address */ - MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET); - def_mac += slave << 8; /* if config MAC in DB use it */ if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac) def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac; + else { + /* set slave default_mac address */ + MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET); + def_mac += slave << 8; + priv->mfunc.master.vf_admin[slave].vport[vhcr->in_modifier].mac = def_mac; + } + MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET); /* get port type - currently only eth is enabled */ diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 0d32a82458bf..2f4a26039e80 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1290,7 +1290,6 @@ static int mlx4_init_slave(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); u64 dma = (u64) priv->mfunc.vhcr_dma; - int num_of_reset_retries = NUM_OF_RESET_RETRIES; int ret_from_reset = 0; u32 slave_read; u32 cmd_channel_ver; @@ -1304,18 +1303,10 @@ static int mlx4_init_slave(struct mlx4_dev *dev) * NUM_OF_RESET_RETRIES times before leaving.*/ if (ret_from_reset) { if (MLX4_DELAY_RESET_SLAVE == ret_from_reset) { - msleep(SLEEP_TIME_IN_RESET); - while (ret_from_reset && num_of_reset_retries) { - mlx4_warn(dev, "slave is currently in the" - "middle of FLR. retrying..." - "(try num:%d)\n", - (NUM_OF_RESET_RETRIES - - num_of_reset_retries + 1)); - ret_from_reset = - mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, - 0, MLX4_COMM_TIME); - num_of_reset_retries = num_of_reset_retries - 1; - } + mlx4_warn(dev, "slave is currently in the " + "middle of FLR. Deferring probe.\n"); + mutex_unlock(&priv->cmd.slave_cmd_mutex); + return -EPROBE_DEFER; } else goto err; } @@ -1526,7 +1517,8 @@ static int mlx4_init_hca(struct mlx4_dev *dev) } else { err = mlx4_init_slave(dev); if (err) { - mlx4_err(dev, "Failed to initialize slave\n"); + if (err != -EPROBE_DEFER) + mlx4_err(dev, "Failed to initialize slave\n"); return err; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 019c5f78732e..c1b693cb3df3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -907,8 +907,11 @@ struct qlcnic_ipaddr { #define QLCNIC_FW_HANG 0x4000 #define QLCNIC_FW_LRO_MSS_CAP 0x8000 #define QLCNIC_TX_INTR_SHARED 0x10000 +#define QLCNIC_APP_CHANGED_FLAGS 0x20000 #define QLCNIC_IS_MSI_FAMILY(adapter) \ ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) +#define QLCNIC_IS_TSO_CAPABLE(adapter) \ + ((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO) #define QLCNIC_DEF_NUM_STS_DESC_RINGS 4 #define QLCNIC_MSIX_TBL_SPACE 8192 @@ -1034,6 +1037,7 @@ struct qlcnic_adapter { spinlock_t rx_mac_learn_lock; u32 file_prd_off; /*File fw product offset*/ u32 fw_version; + u32 offload_flags; const struct firmware *fw; }; @@ -1542,6 +1546,8 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, u16); int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter); int qlcnic_read_mac_addr(struct qlcnic_adapter *); int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int); +void qlcnic_set_netdev_features(struct qlcnic_adapter *, + struct qlcnic_esw_func_cfg *); void qlcnic_sriov_vf_schedule_multi(struct net_device *); void qlcnic_vf_add_mc_list(struct net_device *, u16); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index c67d1eb35e8f..5e7fb1dfb97b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -382,8 +382,6 @@ static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter) clear_bit(__QLCNIC_RESETTING, &adapter->state); dev_err(&adapter->pdev->dev, "%s:\n", __func__); - adapter->netdev->trans_start = jiffies; - return 0; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 6a6512ba9f38..106a12f2a02f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -973,16 +973,57 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu) return rc; } +static netdev_features_t qlcnic_process_flags(struct qlcnic_adapter *adapter, + netdev_features_t features) +{ + u32 offload_flags = adapter->offload_flags; + + if (offload_flags & BIT_0) { + features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM; + adapter->rx_csum = 1; + if (QLCNIC_IS_TSO_CAPABLE(adapter)) { + if (!(offload_flags & BIT_1)) + features &= ~NETIF_F_TSO; + else + features |= NETIF_F_TSO; + + if (!(offload_flags & BIT_2)) + features &= ~NETIF_F_TSO6; + else + features |= NETIF_F_TSO6; + } + } else { + features &= ~(NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM); + + if (QLCNIC_IS_TSO_CAPABLE(adapter)) + features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + adapter->rx_csum = 0; + } + + return features; +} netdev_features_t qlcnic_fix_features(struct net_device *netdev, netdev_features_t features) { struct qlcnic_adapter *adapter = netdev_priv(netdev); + netdev_features_t changed; - if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) && - qlcnic_82xx_check(adapter)) { - netdev_features_t changed = features ^ netdev->features; - features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); + if (qlcnic_82xx_check(adapter) && + (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { + if (adapter->flags & QLCNIC_APP_CHANGED_FLAGS) { + features = qlcnic_process_flags(adapter, features); + } else { + changed = features ^ netdev->features; + features ^= changed & (NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | + NETIF_F_TSO | + NETIF_F_TSO6); + } } if (!(features & NETIF_F_RXCSUM)) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 8fb836d4129f..aeb26a850679 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -84,14 +84,9 @@ static int qlcnic_start_firmware(struct qlcnic_adapter *); static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter); static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *); static int qlcnicvf_start_firmware(struct qlcnic_adapter *); -static void qlcnic_set_netdev_features(struct qlcnic_adapter *, - struct qlcnic_esw_func_cfg *); static int qlcnic_vlan_rx_add(struct net_device *, __be16, u16); static int qlcnic_vlan_rx_del(struct net_device *, __be16, u16); -#define QLCNIC_IS_TSO_CAPABLE(adapter) \ - ((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO) - static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; @@ -1074,8 +1069,6 @@ void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter, if (!esw_cfg->promisc_mode) adapter->flags |= QLCNIC_PROMISC_DISABLED; - - qlcnic_set_netdev_features(adapter, esw_cfg); } int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter) @@ -1090,51 +1083,23 @@ int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter) return -EIO; qlcnic_set_vlan_config(adapter, &esw_cfg); qlcnic_set_eswitch_port_features(adapter, &esw_cfg); + qlcnic_set_netdev_features(adapter, &esw_cfg); return 0; } -static void -qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, - struct qlcnic_esw_func_cfg *esw_cfg) +void qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, + struct qlcnic_esw_func_cfg *esw_cfg) { struct net_device *netdev = adapter->netdev; - unsigned long features, vlan_features; if (qlcnic_83xx_check(adapter)) return; - features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | - NETIF_F_IPV6_CSUM | NETIF_F_GRO); - vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM); - - if (QLCNIC_IS_TSO_CAPABLE(adapter)) { - features |= (NETIF_F_TSO | NETIF_F_TSO6); - vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6); - } - - if (netdev->features & NETIF_F_LRO) - features |= NETIF_F_LRO; - - if (esw_cfg->offload_flags & BIT_0) { - netdev->features |= features; - adapter->rx_csum = 1; - if (!(esw_cfg->offload_flags & BIT_1)) { - netdev->features &= ~NETIF_F_TSO; - features &= ~NETIF_F_TSO; - } - if (!(esw_cfg->offload_flags & BIT_2)) { - netdev->features &= ~NETIF_F_TSO6; - features &= ~NETIF_F_TSO6; - } - } else { - netdev->features &= ~features; - features &= ~features; - adapter->rx_csum = 0; - } - - netdev->vlan_features = (features & vlan_features); + adapter->offload_flags = esw_cfg->offload_flags; + adapter->flags |= QLCNIC_APP_CHANGED_FLAGS; + netdev_update_features(netdev); + adapter->flags &= ~QLCNIC_APP_CHANGED_FLAGS; } static int @@ -2016,8 +1981,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_enable_pcie_error_reporting(pdev); ahw = kzalloc(sizeof(struct qlcnic_hardware_context), GFP_KERNEL); - if (!ahw) + if (!ahw) { + err = -ENOMEM; goto err_out_free_res; + } switch (ent->device) { case PCI_DEVICE_ID_QLOGIC_QLE824X: @@ -2053,6 +2020,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->qlcnic_wq = create_singlethread_workqueue("qlcnic"); if (adapter->qlcnic_wq == NULL) { + err = -ENOMEM; dev_err(&pdev->dev, "Failed to create workqueue\n"); goto err_out_free_netdev; } @@ -2133,6 +2101,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_disable_msi; } + err = qlcnic_get_act_pci_func(adapter); + if (err) + goto err_out_disable_mbx_intr; + err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac); if (err) goto err_out_disable_mbx_intr; @@ -2162,9 +2134,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; } - if (qlcnic_get_act_pci_func(adapter)) - goto err_out_disable_mbx_intr; - if (adapter->drv_mac_learn) qlcnic_alloc_lb_filters_mem(adapter); @@ -3149,10 +3118,8 @@ qlcnic_check_health(struct qlcnic_adapter *adapter) if (adapter->need_fw_reset) goto detach; - if (adapter->ahw->reset_context && qlcnic_auto_fw_reset) { + if (adapter->ahw->reset_context && qlcnic_auto_fw_reset) qlcnic_reset_hw_context(adapter); - adapter->netdev->trans_start = jiffies; - } return 0; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 3869c3864deb..196b2d100407 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -1734,7 +1734,6 @@ static int qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter *adapter) if (!qlcnic_sriov_vf_reinit_driver(adapter)) { qlcnic_sriov_vf_attach(adapter); - adapter->netdev->trans_start = jiffies; adapter->tx_timeo_cnt = 0; adapter->reset_ctx_cnt = 0; adapter->fw_fail_cnt = 0; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 4e22e794a186..e7a2fe21b649 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -544,6 +544,9 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file, switch (esw_cfg[i].op_mode) { case QLCNIC_PORT_DEFAULTS: qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]); + rtnl_lock(); + qlcnic_set_netdev_features(adapter, &esw_cfg[i]); + rtnl_unlock(); break; case QLCNIC_ADD_VLAN: qlcnic_set_vlan_config(adapter, &esw_cfg[i]); diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 50235d201592..f87cc216045b 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -4717,6 +4717,7 @@ static int qlge_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "net device registration failed.\n"); ql_release_all(pdev); pci_disable_device(pdev); + free_netdev(ndev); return err; } /* Start up the timer to trigger EEH if diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 7d1fb9ad1296..03523459c406 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -1136,6 +1136,7 @@ static void cp_clean_rings (struct cp_private *cp) cp->dev->stats.tx_dropped++; } } + netdev_reset_queue(cp->dev); memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE); memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE); diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 79c520b64fdd..393f961a013c 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5856,7 +5856,20 @@ err_out: return -EIO; } -static inline void rtl8169_tso_csum(struct rtl8169_private *tp, +static bool rtl_skb_pad(struct sk_buff *skb) +{ + if (skb_padto(skb, ETH_ZLEN)) + return false; + skb_put(skb, ETH_ZLEN - skb->len); + return true; +} + +static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp, struct sk_buff *skb) +{ + return skb->len < ETH_ZLEN && tp->mac_version == RTL_GIGA_MAC_VER_34; +} + +static inline bool rtl8169_tso_csum(struct rtl8169_private *tp, struct sk_buff *skb, u32 *opts) { const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version; @@ -5869,13 +5882,20 @@ static inline void rtl8169_tso_csum(struct rtl8169_private *tp, } else if (skb->ip_summed == CHECKSUM_PARTIAL) { const struct iphdr *ip = ip_hdr(skb); + if (unlikely(rtl_test_hw_pad_bug(tp, skb))) + return skb_checksum_help(skb) == 0 && rtl_skb_pad(skb); + if (ip->protocol == IPPROTO_TCP) opts[offset] |= info->checksum.tcp; else if (ip->protocol == IPPROTO_UDP) opts[offset] |= info->checksum.udp; else WARN_ON_ONCE(1); + } else { + if (unlikely(rtl_test_hw_pad_bug(tp, skb))) + return rtl_skb_pad(skb); } + return true; } static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, @@ -5896,17 +5916,15 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, goto err_stop_0; } - /* 8168evl does not automatically pad to minimum length. */ - if (unlikely(tp->mac_version == RTL_GIGA_MAC_VER_34 && - skb->len < ETH_ZLEN)) { - if (skb_padto(skb, ETH_ZLEN)) - goto err_update_stats; - skb_put(skb, ETH_ZLEN - skb->len); - } - if (unlikely(le32_to_cpu(txd->opts1) & DescOwn)) goto err_stop_0; + opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb)); + opts[0] = DescOwn; + + if (!rtl8169_tso_csum(tp, skb, opts)) + goto err_update_stats; + len = skb_headlen(skb); mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(d, mapping))) { @@ -5918,11 +5936,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, tp->tx_skb[entry].len = len; txd->addr = cpu_to_le64(mapping); - opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb)); - opts[0] = DescOwn; - - rtl8169_tso_csum(tp, skb, opts); - frags = rtl8169_xmit_frags(tp, skb, opts); if (frags < 0) goto err_dma_1; diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 42e9dd05c936..5e3982fc5398 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -897,8 +897,8 @@ static int sh_eth_check_reset(struct net_device *ndev) mdelay(1); cnt--; } - if (cnt < 0) { - pr_err("Device reset fail\n"); + if (cnt <= 0) { + pr_err("Device reset failed\n"); ret = -ETIMEDOUT; } return ret; @@ -1401,16 +1401,23 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status) desc_status = edmac_to_cpu(mdp, rxdesc->status); pkt_len = rxdesc->frame_length; -#if defined(CONFIG_ARCH_R8A7740) - desc_status >>= 16; -#endif - if (--boguscnt < 0) break; if (!(desc_status & RDFEND)) ndev->stats.rx_length_errors++; +#if defined(CONFIG_ARCH_R8A7740) + /* + * In case of almost all GETHER/ETHERs, the Receive Frame State + * (RFS) bits in the Receive Descriptor 0 are from bit 9 to + * bit 0. However, in case of the R8A7740's GETHER, the RFS + * bits are from bit 25 to bit 16. So, the driver needs right + * shifting by 16. + */ + desc_status >>= 16; +#endif + if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 | RD_RFS5 | RD_RFS6 | RD_RFS10)) { ndev->stats.rx_errors++; diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 01b99206139a..39e4cb39de29 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -638,14 +638,16 @@ static void efx_start_datapath(struct efx_nic *efx) EFX_MAX_FRAME_LEN(efx->net_dev->mtu) + efx->type->rx_buffer_padding); rx_buf_len = (sizeof(struct efx_rx_page_state) + - EFX_PAGE_IP_ALIGN + efx->rx_dma_len); + NET_IP_ALIGN + efx->rx_dma_len); if (rx_buf_len <= PAGE_SIZE) { efx->rx_scatter = false; efx->rx_buffer_order = 0; } else if (efx->type->can_rx_scatter) { + BUILD_BUG_ON(EFX_RX_USR_BUF_SIZE % L1_CACHE_BYTES); BUILD_BUG_ON(sizeof(struct efx_rx_page_state) + - EFX_PAGE_IP_ALIGN + EFX_RX_USR_BUF_SIZE > - PAGE_SIZE / 2); + 2 * ALIGN(NET_IP_ALIGN + EFX_RX_USR_BUF_SIZE, + EFX_RX_BUF_ALIGNMENT) > + PAGE_SIZE); efx->rx_scatter = true; efx->rx_dma_len = EFX_RX_USR_BUF_SIZE; efx->rx_buffer_order = 0; diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 9bd433a095c5..39d6bd77f015 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -72,8 +72,20 @@ /* Maximum possible MTU the driver supports */ #define EFX_MAX_MTU (9 * 1024) -/* Size of an RX scatter buffer. Small enough to pack 2 into a 4K page. */ -#define EFX_RX_USR_BUF_SIZE 1824 +/* Size of an RX scatter buffer. Small enough to pack 2 into a 4K page, + * and should be a multiple of the cache line size. + */ +#define EFX_RX_USR_BUF_SIZE (2048 - 256) + +/* If possible, we should ensure cache line alignment at start and end + * of every buffer. Otherwise, we just need to ensure 4-byte + * alignment of the network header. + */ +#if NET_IP_ALIGN == 0 +#define EFX_RX_BUF_ALIGNMENT L1_CACHE_BYTES +#else +#define EFX_RX_BUF_ALIGNMENT 4 +#endif /* Forward declare Precision Time Protocol (PTP) support structure. */ struct efx_ptp_data; @@ -468,24 +480,11 @@ enum nic_state { }; /* - * Alignment of page-allocated RX buffers - * - * Controls the number of bytes inserted at the start of an RX buffer. - * This is the equivalent of NET_IP_ALIGN [which controls the alignment - * of the skb->head for hardware DMA]. - */ -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS -#define EFX_PAGE_IP_ALIGN 0 -#else -#define EFX_PAGE_IP_ALIGN NET_IP_ALIGN -#endif - -/* * Alignment of the skb->head which wraps a page-allocated RX buffer * * The skb allocated to wrap an rx_buffer can have this alignment. Since * the data is memcpy'd from the rx_buf, it does not need to be equal to - * EFX_PAGE_IP_ALIGN. + * NET_IP_ALIGN. */ #define EFX_PAGE_SKB_ALIGN 2 diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index e73e30bac10e..a7dfe36cabf4 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -93,8 +93,8 @@ static inline void efx_sync_rx_buffer(struct efx_nic *efx, void efx_rx_config_page_split(struct efx_nic *efx) { - efx->rx_page_buf_step = ALIGN(efx->rx_dma_len + EFX_PAGE_IP_ALIGN, - L1_CACHE_BYTES); + efx->rx_page_buf_step = ALIGN(efx->rx_dma_len + NET_IP_ALIGN, + EFX_RX_BUF_ALIGNMENT); efx->rx_bufs_per_page = efx->rx_buffer_order ? 1 : ((PAGE_SIZE - sizeof(struct efx_rx_page_state)) / efx->rx_page_buf_step); @@ -188,9 +188,9 @@ static int efx_init_rx_buffers(struct efx_rx_queue *rx_queue) do { index = rx_queue->added_count & rx_queue->ptr_mask; rx_buf = efx_rx_buffer(rx_queue, index); - rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN; + rx_buf->dma_addr = dma_addr + NET_IP_ALIGN; rx_buf->page = page; - rx_buf->page_offset = page_offset + EFX_PAGE_IP_ALIGN; + rx_buf->page_offset = page_offset + NET_IP_ALIGN; rx_buf->len = efx->rx_dma_len; rx_buf->flags = 0; ++rx_queue->added_count; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 618446ae1ec1..ee919ca8b8a0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1899,7 +1899,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef STMMAC_XMIT_DEBUG if (netif_msg_pktdata(priv)) { - pr_info("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d" + pr_info("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d", __func__, (priv->cur_tx % txsize), (priv->dirty_tx % txsize), entry, first, nfrags); if (priv->extend_desc) diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 12aec173564c..c47f0dbcebb5 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -449,10 +449,9 @@ static int davinci_mdio_suspend(struct device *dev) __raw_writel(ctrl, &data->regs->control); wait_for_idle(data); - pm_runtime_put_sync(data->dev); - data->suspended = true; spin_unlock(&data->lock); + pm_runtime_put_sync(data->dev); return 0; } @@ -460,15 +459,12 @@ static int davinci_mdio_suspend(struct device *dev) static int davinci_mdio_resume(struct device *dev) { struct davinci_mdio_data *data = dev_get_drvdata(dev); - u32 ctrl; - spin_lock(&data->lock); pm_runtime_get_sync(data->dev); + spin_lock(&data->lock); /* restart the scan state machine */ - ctrl = __raw_readl(&data->regs->control); - ctrl |= CONTROL_ENABLE; - __raw_writel(ctrl, &data->regs->control); + __davinci_mdio_reset(data); data->suspended = false; spin_unlock(&data->lock); @@ -477,8 +473,8 @@ static int davinci_mdio_resume(struct device *dev) } static const struct dev_pm_ops davinci_mdio_pm_ops = { - .suspend = davinci_mdio_suspend, - .resume = davinci_mdio_resume, + .suspend_late = davinci_mdio_suspend, + .resume_early = davinci_mdio_resume, }; static const struct of_device_id davinci_mdio_of_mtable[] = { diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 919b983114e9..b7268b3dae77 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -946,7 +946,8 @@ static int xemaclite_open(struct net_device *dev) phy_write(lp->phy_dev, MII_CTRL1000, 0); /* Advertise only 10 and 100mbps full/half duplex speeds */ - phy_write(lp->phy_dev, MII_ADVERTISE, ADVERTISE_ALL); + phy_write(lp->phy_dev, MII_ADVERTISE, ADVERTISE_ALL | + ADVERTISE_CSMA); /* Restart auto negotiation */ bmcr = phy_read(lp->phy_dev, MII_BMCR); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 088c55496191..ab2307b5d9a7 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -31,6 +31,7 @@ #include <linux/inetdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/if_vlan.h> #include <linux/in.h> #include <linux/slab.h> #include <net/arp.h> @@ -284,7 +285,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, skb->protocol = eth_type_trans(skb, net); skb->ip_summed = CHECKSUM_NONE; - skb->vlan_tci = packet->vlan_tci; + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), packet->vlan_tci); net->stats.rx_packets++; net->stats.rx_bytes += packet->total_data_buflen; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 1c502bb0c916..6e91931a1c2c 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -853,18 +853,24 @@ static int macvlan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct macvlan_dev *vlan = netdev_priv(dev); - if (data && data[IFLA_MACVLAN_MODE]) - vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + if (data && data[IFLA_MACVLAN_FLAGS]) { __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC; - - if (promisc && (flags & MACVLAN_FLAG_NOPROMISC)) - dev_set_promiscuity(vlan->lowerdev, -1); - else if (promisc && !(flags & MACVLAN_FLAG_NOPROMISC)) - dev_set_promiscuity(vlan->lowerdev, 1); + if (vlan->port->passthru && promisc) { + int err; + + if (flags & MACVLAN_FLAG_NOPROMISC) + err = dev_set_promiscuity(vlan->lowerdev, -1); + else + err = dev_set_promiscuity(vlan->lowerdev, 1); + if (err < 0) + return err; + } vlan->flags = flags; } + if (data && data[IFLA_MACVLAN_MODE]) + vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); return 0; } diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index c14f14741b3f..38f0b312ff85 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1044,7 +1044,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv); lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp); idx = phy_find_setting(phydev->speed, phydev->duplex); - if ((lp & adv & settings[idx].setting)) + if (!(lp & adv & settings[idx].setting)) goto eee_exit; if (clk_stop_enable) { diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 7c43261975bd..b3051052f3ad 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1092,8 +1092,8 @@ static int team_port_add(struct team *team, struct net_device *port_dev) } port->index = -1; - team_port_enable(team, port); list_add_tail_rcu(&port->list, &team->port_list); + team_port_enable(team, port); __team_compute_features(team); __team_port_change_port_added(port, !!netif_carrier_ok(port_dev)); __team_options_change_check(team); @@ -2374,7 +2374,8 @@ static int team_nl_send_port_list_get(struct team *team, u32 portid, u32 seq, bool incomplete; int i; - port = list_first_entry(&team->port_list, struct team_port, list); + port = list_first_entry_or_null(&team->port_list, + struct team_port, list); start_again: err = __send_and_alloc_skb(&skb, team, portid, send_func); @@ -2402,8 +2403,8 @@ start_again: err = team_nl_fill_one_port_get(skb, one_port); if (err) goto errout; - } else { - list_for_each_entry(port, &team->port_list, list) { + } else if (port) { + list_for_each_entry_from(port, &team->port_list, list) { err = team_nl_fill_one_port_get(skb, port); if (err) { if (err == -EMSGSIZE) { diff --git a/drivers/net/team/team_mode_random.c b/drivers/net/team/team_mode_random.c index 5ca14d463ba7..7f032e211343 100644 --- a/drivers/net/team/team_mode_random.c +++ b/drivers/net/team/team_mode_random.c @@ -28,6 +28,8 @@ static bool rnd_transmit(struct team *team, struct sk_buff *skb) port_index = random_N(team->en_port_count); port = team_get_port_by_index_rcu(team, port_index); + if (unlikely(!port)) + goto drop; port = team_get_first_port_txable_rcu(team, port); if (unlikely(!port)) goto drop; diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c index d268e4de781b..472623f8ce3d 100644 --- a/drivers/net/team/team_mode_roundrobin.c +++ b/drivers/net/team/team_mode_roundrobin.c @@ -32,6 +32,8 @@ static bool rr_transmit(struct team *team, struct sk_buff *skb) port_index = rr_priv(team)->sent_packets++ % team->en_port_count; port = team_get_port_by_index_rcu(team, port_index); + if (unlikely(!port)) + goto drop; port = team_get_first_port_txable_rcu(team, port); if (unlikely(!port)) goto drop; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index f042b0373e5d..bfa9bb48e42d 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -352,7 +352,7 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb) u32 numqueues = 0; rcu_read_lock(); - numqueues = tun->numqueues; + numqueues = ACCESS_ONCE(tun->numqueues); txq = skb_get_rxhash(skb); if (txq) { @@ -1585,6 +1585,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) else return -EINVAL; + if (!!(ifr->ifr_flags & IFF_MULTI_QUEUE) != + !!(tun->flags & TUN_TAP_MQ)) + return -EINVAL; + if (tun_not_capable(tun)) return -EPERM; err = security_tun_dev_open(tun->security); @@ -2155,6 +2159,8 @@ static int tun_chr_open(struct inode *inode, struct file * file) set_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags); INIT_LIST_HEAD(&tfile->next); + sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); + return 0; } diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 078795fe6e31..04ee044dde51 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -627,6 +627,12 @@ static const struct usb_device_id products [] = { .driver_info = 0, }, +/* Huawei E1820 - handled by qmi_wwan */ +{ + USB_DEVICE_INTERFACE_NUMBER(HUAWEI_VENDOR_ID, 0x14ac, 1), + .driver_info = 0, +}, + /* Realtek RTL8152 Based USB 2.0 Ethernet Adapters */ #if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE) { diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index cf887c2384e9..d095d0d3056b 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -519,6 +519,7 @@ static const struct usb_device_id products[] = { /* 3. Combined interface devices matching on interface number */ {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ + {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ {QMI_FIXED_INTF(0x19d2, 0x0002, 1)}, {QMI_FIXED_INTF(0x19d2, 0x0012, 1)}, {QMI_FIXED_INTF(0x19d2, 0x0017, 3)}, @@ -582,6 +583,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ + {QMI_FIXED_INTF(0x1e2d, 0x12d1, 4)}, /* Cinterion PLxx */ /* 4. Gobi 1000 devices */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index a491d3a95393..6cbdac67f3a0 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -130,19 +130,23 @@ struct rtl8150 { struct usb_device *udev; struct tasklet_struct tl; struct net_device *netdev; - struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb; + struct urb *rx_urb, *tx_urb, *intr_urb; struct sk_buff *tx_skb, *rx_skb; struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE]; spinlock_t rx_pool_lock; struct usb_ctrlrequest dr; int intr_interval; - __le16 rx_creg; u8 *intr_buff; u8 phy; }; typedef struct rtl8150 rtl8150_t; +struct async_req { + struct usb_ctrlrequest dr; + u16 rx_creg; +}; + static const char driver_name [] = "rtl8150"; /* @@ -164,51 +168,47 @@ static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) indx, 0, data, size, 500); } -static void ctrl_callback(struct urb *urb) +static void async_set_reg_cb(struct urb *urb) { - rtl8150_t *dev; + struct async_req *req = (struct async_req *)urb->context; int status = urb->status; - switch (status) { - case 0: - break; - case -EINPROGRESS: - break; - case -ENOENT: - break; - default: - if (printk_ratelimit()) - dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status); - } - dev = urb->context; - clear_bit(RX_REG_SET, &dev->flags); + if (status < 0) + dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status); + kfree(req); + usb_free_urb(urb); } -static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size) +static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, u16 reg) { - int ret; - - if (test_bit(RX_REG_SET, &dev->flags)) - return -EAGAIN; + int res = -ENOMEM; + struct urb *async_urb; + struct async_req *req; - dev->dr.bRequestType = RTL8150_REQT_WRITE; - dev->dr.bRequest = RTL8150_REQ_SET_REGS; - dev->dr.wValue = cpu_to_le16(indx); - dev->dr.wIndex = 0; - dev->dr.wLength = cpu_to_le16(size); - dev->ctrl_urb->transfer_buffer_length = size; - usb_fill_control_urb(dev->ctrl_urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr, - &dev->rx_creg, size, ctrl_callback, dev); - if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) { - if (ret == -ENODEV) + req = kmalloc(sizeof(struct async_req), GFP_ATOMIC); + if (req == NULL) + return res; + async_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (async_urb == NULL) { + kfree(req); + return res; + } + req->rx_creg = cpu_to_le16(reg); + req->dr.bRequestType = RTL8150_REQT_WRITE; + req->dr.bRequest = RTL8150_REQ_SET_REGS; + req->dr.wIndex = 0; + req->dr.wValue = cpu_to_le16(indx); + req->dr.wLength = cpu_to_le16(size); + usb_fill_control_urb(async_urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), (void *)&req->dr, + &req->rx_creg, size, async_set_reg_cb, req); + res = usb_submit_urb(async_urb, GFP_ATOMIC); + if (res) { + if (res == -ENODEV) netif_device_detach(dev->netdev); - dev_err(&dev->udev->dev, - "control request submission failed: %d\n", ret); - } else - set_bit(RX_REG_SET, &dev->flags); - - return ret; + dev_err(&dev->udev->dev, "%s failed with %d\n", __func__, res); + } + return res; } static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg) @@ -330,13 +330,6 @@ static int alloc_all_urbs(rtl8150_t * dev) usb_free_urb(dev->tx_urb); return 0; } - dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->ctrl_urb) { - usb_free_urb(dev->rx_urb); - usb_free_urb(dev->tx_urb); - usb_free_urb(dev->intr_urb); - return 0; - } return 1; } @@ -346,7 +339,6 @@ static void free_all_urbs(rtl8150_t * dev) usb_free_urb(dev->rx_urb); usb_free_urb(dev->tx_urb); usb_free_urb(dev->intr_urb); - usb_free_urb(dev->ctrl_urb); } static void unlink_all_urbs(rtl8150_t * dev) @@ -354,7 +346,6 @@ static void unlink_all_urbs(rtl8150_t * dev) usb_kill_urb(dev->rx_urb); usb_kill_urb(dev->tx_urb); usb_kill_urb(dev->intr_urb); - usb_kill_urb(dev->ctrl_urb); } static inline struct sk_buff *pull_skb(rtl8150_t *dev) @@ -629,7 +620,6 @@ static int enable_net_traffic(rtl8150_t * dev) } /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */ rcr = 0x9e; - dev->rx_creg = cpu_to_le16(rcr); tcr = 0xd8; cr = 0x0c; if (!(rcr & 0x80)) @@ -662,20 +652,22 @@ static void rtl8150_tx_timeout(struct net_device *netdev) static void rtl8150_set_multicast(struct net_device *netdev) { rtl8150_t *dev = netdev_priv(netdev); + u16 rx_creg = 0x9e; + netif_stop_queue(netdev); if (netdev->flags & IFF_PROMISC) { - dev->rx_creg |= cpu_to_le16(0x0001); + rx_creg |= 0x0001; dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name); } else if (!netdev_mc_empty(netdev) || (netdev->flags & IFF_ALLMULTI)) { - dev->rx_creg &= cpu_to_le16(0xfffe); - dev->rx_creg |= cpu_to_le16(0x0002); + rx_creg &= 0xfffe; + rx_creg |= 0x0002; dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name); } else { /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ - dev->rx_creg &= cpu_to_le16(0x00fc); + rx_creg &= 0x00fc; } - async_set_registers(dev, RCR, 2); + async_set_registers(dev, RCR, sizeof(rx_creg), rx_creg); netif_wake_queue(netdev); } diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index f95cb032394b..06ee82f557d4 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1477,7 +1477,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) /* usbnet already took usb runtime pm, so have to enable the feature * for usb interface, otherwise usb_autopm_get_interface may return - * failure if USB_SUSPEND(RUNTIME_PM) is enabled. + * failure if RUNTIME_PM is enabled. */ if (!driver->supports_autosuspend) { driver->supports_autosuspend = 1; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 655bb25eed2b..c9e00387d999 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -636,10 +636,11 @@ static int virtnet_open(struct net_device *dev) struct virtnet_info *vi = netdev_priv(dev); int i; - for (i = 0; i < vi->curr_queue_pairs; i++) { - /* Make sure we have some buffers: if oom use wq. */ - if (!try_fill_recv(&vi->rq[i], GFP_KERNEL)) - schedule_delayed_work(&vi->refill, 0); + for (i = 0; i < vi->max_queue_pairs; i++) { + if (i < vi->curr_queue_pairs) + /* Make sure we have some buffers: if oom use wq. */ + if (!try_fill_recv(&vi->rq[i], GFP_KERNEL)) + schedule_delayed_work(&vi->refill, 0); virtnet_napi_enable(&vi->rq[i]); } diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index ba81f3c39a83..3b1d2ee7156b 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -301,7 +301,7 @@ static inline struct hlist_head *vxlan_fdb_head(struct vxlan_dev *vxlan, } /* Look up Ethernet address in forwarding table */ -static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan, +static struct vxlan_fdb *__vxlan_find_mac(struct vxlan_dev *vxlan, const u8 *mac) { @@ -316,6 +316,18 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan, return NULL; } +static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan, + const u8 *mac) +{ + struct vxlan_fdb *f; + + f = __vxlan_find_mac(vxlan, mac); + if (f) + f->used = jiffies; + + return f; +} + /* Add/update destinations for multicast */ static int vxlan_fdb_append(struct vxlan_fdb *f, __be32 ip, __be16 port, __u32 vni, __u32 ifindex) @@ -353,7 +365,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, struct vxlan_fdb *f; int notify = 0; - f = vxlan_find_mac(vxlan, mac); + f = __vxlan_find_mac(vxlan, mac); if (f) { if (flags & NLM_F_EXCL) { netdev_dbg(vxlan->dev, @@ -563,7 +575,6 @@ static void vxlan_snoop(struct net_device *dev, f = vxlan_find_mac(vxlan, src_mac); if (likely(f)) { - f->used = jiffies; if (likely(f->remote.remote_ip == src_ip)) return; diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index f3dc124c60c7..3c2cbc9d6295 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -92,13 +92,17 @@ config ATH9K_MAC_DEBUG This option enables collection of statistics for Rx/Tx status data and some other MAC related statistics -config ATH9K_RATE_CONTROL +config ATH9K_LEGACY_RATE_CONTROL bool "Atheros ath9k rate control" depends on ATH9K - default y + default n ---help--- Say Y, if you want to use the ath9k specific rate control - module instead of minstrel_ht. + module instead of minstrel_ht. Be warned that there are various + issues with the ath9k RC and minstrel is a more robust algorithm. + Note that even if this option is selected, "ath9k_rate_control" + has to be passed to mac80211 using the module parameter, + ieee80211_default_rc_algo. config ATH9K_HTC tristate "Atheros HTC based wireless cards support" diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 2ad8f9474ba1..75ee9e7704ce 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -8,7 +8,7 @@ ath9k-y += beacon.o \ antenna.o ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o -ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o +ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o ath9k-$(CONFIG_ATH9K_PCI) += pci.o ath9k-$(CONFIG_ATH9K_AHB) += ahb.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index db5ffada2217..7546b9a7dcbf 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -958,11 +958,11 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = { {0x0000a074, 0x00000000}, {0x0000a078, 0x00000000}, {0x0000a07c, 0x00000000}, - {0x0000a080, 0x1a1a1a1a}, - {0x0000a084, 0x1a1a1a1a}, - {0x0000a088, 0x1a1a1a1a}, - {0x0000a08c, 0x1a1a1a1a}, - {0x0000a090, 0x171a1a1a}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, {0x0000a094, 0x11111717}, {0x0000a098, 0x00030311}, {0x0000a09c, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 639ba7d18ea4..6988e1d081f2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -965,7 +965,7 @@ static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah, { int i; - if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah)) + if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah)) return; for (i = 0; i < AR9300_MAX_CHAINS; i++) { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 54ba42f4108a..874f6570bd1c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -68,13 +68,16 @@ #define AR9300_BASE_ADDR 0x3ff #define AR9300_BASE_ADDR_512 0x1ff -#define AR9300_OTP_BASE (AR_SREV_9340(ah) ? 0x30000 : 0x14000) -#define AR9300_OTP_STATUS (AR_SREV_9340(ah) ? 0x30018 : 0x15f18) +#define AR9300_OTP_BASE \ + ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000) +#define AR9300_OTP_STATUS \ + ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18) #define AR9300_OTP_STATUS_TYPE 0x7 #define AR9300_OTP_STATUS_VALID 0x4 #define AR9300_OTP_STATUS_ACCESS_BUSY 0x2 #define AR9300_OTP_STATUS_SM_BUSY 0x1 -#define AR9300_OTP_READ_DATA (AR_SREV_9340(ah) ? 0x3001c : 0x15f1c) +#define AR9300_OTP_READ_DATA \ + ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c) enum targetPowerHTRates { HT_TARGET_RATE_0_8_16, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 2bf6548dd143..e1714d7c9eeb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -334,7 +334,8 @@ static void ar9003_hw_spur_ofdm(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1); - if (REG_READ_FIELD(ah, AR_PHY_MODE, + if (!AR_SREV_9340(ah) && + REG_READ_FIELD(ah, AR_PHY_MODE, AR_PHY_MODE_DYNAMIC) == 0x1) REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1); diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 712f415b8c08..88ff1d7b53ab 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -1020,7 +1020,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = { {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18}, {0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982}, {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8a1888d02070..42b03dc39d14 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -251,9 +251,9 @@ struct ath_atx_tid { int tidno; int baw_head; /* first un-acked tx buffer */ int baw_tail; /* next unused tx buffer slot */ - int sched; - int paused; - u8 state; + bool sched; + bool paused; + bool active; }; struct ath_node { @@ -274,10 +274,6 @@ struct ath_node { #endif }; -#define AGGR_CLEANUP BIT(1) -#define AGGR_ADDBA_COMPLETE BIT(2) -#define AGGR_ADDBA_PROGRESS BIT(3) - struct ath_tx_control { struct ath_txq *txq; struct ath_node *an; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index e6307b86363a..b37eb8d38811 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -2008,6 +2008,14 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw, WARN_ON(i != ATH9K_SSTATS_LEN); } +void ath9k_deinit_debug(struct ath_softc *sc) +{ + if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { + relay_close(sc->rfs_chan_spec_scan); + sc->rfs_chan_spec_scan = NULL; + } +} + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 794a7ec83a24..9d49aab8b989 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -304,6 +304,7 @@ struct ath9k_debug { }; int ath9k_init_debug(struct ath_hw *ah); +void ath9k_deinit_debug(struct ath_softc *sc); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, @@ -339,6 +340,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah) return 0; } +static inline void ath9k_deinit_debug(struct ath_softc *sc) +{ +} + static inline void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7f25da8444fe..15dfefcf2d0f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1172,6 +1172,7 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan) static inline void ath9k_hw_set_dma(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); + int txbuf_size; ENABLE_REGWRITE_BUFFER(ah); @@ -1225,13 +1226,17 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah) * So set the usable tx buf size also to half to * avoid data/delimiter underruns */ - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); - } else if (!AR_SREV_9271(ah)) { - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_PCU_TXBUF_CTRL_USABLE_SIZE); + txbuf_size = AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE; + } else if (AR_SREV_9340_13_OR_LATER(ah)) { + /* Uses fewer entries for AR934x v1.3+ to prevent rx overruns */ + txbuf_size = AR_9340_PCU_TXBUF_CTRL_USABLE_SIZE; + } else { + txbuf_size = AR_PCU_TXBUF_CTRL_USABLE_SIZE; } + if (!AR_SREV_9271(ah)) + REG_WRITE(ah, AR_PCU_TXBUF_CTRL, txbuf_size); + REGWRITE_BUFFER_FLUSH(ah); if (AR_SREV_9300_20_OR_LATER(ah)) @@ -1306,9 +1311,13 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; } else { tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); - if (tmpReg & - (AR_INTR_SYNC_LOCAL_TIMEOUT | - AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { + if (AR_SREV_9340(ah)) + tmpReg &= AR9340_INTR_SYNC_LOCAL_TIMEOUT; + else + tmpReg &= AR_INTR_SYNC_LOCAL_TIMEOUT | + AR_INTR_SYNC_RADM_CPL_TIMEOUT; + + if (tmpReg) { u32 val; REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 0237b2868961..2ba494567777 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -787,8 +787,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->iface_combinations = if_comb; hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); - if (AR_SREV_5416(sc->sc_ah)) - hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; @@ -830,10 +829,6 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) sc->ant_rx = hw->wiphy->available_antennas_rx; sc->ant_tx = hw->wiphy->available_antennas_tx; -#ifdef CONFIG_ATH9K_RATE_CONTROL - hw->rate_control_algorithm = "ath9k_rate_control"; -#endif - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; @@ -906,7 +901,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, if (!ath_is_world_regd(reg)) { error = regulatory_hint(hw->wiphy, reg->alpha2); if (error) - goto unregister; + goto debug_cleanup; } ath_init_leds(sc); @@ -914,6 +909,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, return 0; +debug_cleanup: + ath9k_deinit_debug(sc); unregister: ieee80211_unregister_hw(hw); rx_cleanup: @@ -942,11 +939,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc) sc->dfs_detector->exit(sc->dfs_detector); ath9k_eeprom_release(sc); - - if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { - relay_close(sc->rfs_chan_spec_scan); - sc->rfs_chan_spec_scan = NULL; - } } void ath9k_deinit_device(struct ath_softc *sc) @@ -960,6 +952,7 @@ void ath9k_deinit_device(struct ath_softc *sc) ath9k_ps_restore(sc); + ath9k_deinit_debug(sc); ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); ath9k_deinit_softc(sc); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 498fee04afa0..566109a40fb3 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -410,7 +410,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); - if (AR_SREV_9340(ah)) + if (AR_SREV_9340(ah) && !AR_SREV_9340_13_OR_LATER(ah)) REG_WRITE(ah, AR_DMISC(q), AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1); else diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a18414b5948b..5092ecae7706 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1687,6 +1687,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, u16 tid, u16 *ssn, u8 buf_size) { struct ath_softc *sc = hw->priv; + bool flush = false; int ret = 0; local_bh_disable(); @@ -1703,12 +1704,14 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); ath9k_ps_restore(sc); break; - case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + flush = true; + case IEEE80211_AMPDU_TX_STOP_CONT: ath9k_ps_wakeup(sc); ath_tx_aggr_stop(sc, sta, tid); - ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + if (!flush) + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_OPERATIONAL: diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index aa4d368d8d3d..7eb1f4b458e4 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1227,10 +1227,7 @@ static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta, return false; txtid = ATH_AN_2_TID(an, tidno); - - if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS))) - return true; - return false; + return !txtid->active; } diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 267dbfcfaa96..b9a87383cb43 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -231,7 +231,7 @@ static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, } #endif -#ifdef CONFIG_ATH9K_RATE_CONTROL +#ifdef CONFIG_ATH9K_LEGACY_RATE_CONTROL int ath_rate_control_register(void); void ath_rate_control_unregister(void); #else diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 5c4ab5026dca..f7c90cc58d56 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -798,6 +798,10 @@ #define AR_SREV_REVISION_9485_10 0 #define AR_SREV_REVISION_9485_11 1 #define AR_SREV_VERSION_9340 0x300 +#define AR_SREV_REVISION_9340_10 0 +#define AR_SREV_REVISION_9340_11 1 +#define AR_SREV_REVISION_9340_12 2 +#define AR_SREV_REVISION_9340_13 3 #define AR_SREV_VERSION_9580 0x1C0 #define AR_SREV_REVISION_9580_10 4 /* AR9580 1.0 */ #define AR_SREV_VERSION_9462 0x280 @@ -897,6 +901,10 @@ #define AR_SREV_9340(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340)) +#define AR_SREV_9340_13_OR_LATER(_ah) \ + (AR_SREV_9340((_ah)) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9340_13)) + #define AR_SREV_9285E_20(_ah) \ (AR_SREV_9285_12_OR_LATER(_ah) && \ ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) @@ -1007,6 +1015,8 @@ enum { AR_INTR_SYNC_LOCAL_TIMEOUT | AR_INTR_SYNC_MAC_SLEEP_ACCESS), + AR9340_INTR_SYNC_LOCAL_TIMEOUT = 0x00000010, + AR_INTR_SYNC_SPURIOUS = 0xFFFFFFFF, }; @@ -1881,6 +1891,7 @@ enum { #define AR_PCU_TXBUF_CTRL_SIZE_MASK 0x7FF #define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700 #define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE 0x380 +#define AR_9340_PCU_TXBUF_CTRL_USABLE_SIZE 0x500 #define AR_PCU_MISC_MODE2 0x8344 #define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index eab0fcb7ded6..1c9b1bac8b0d 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -125,24 +125,6 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) list_add_tail(&ac->list, &txq->axq_acq); } -static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) -{ - struct ath_txq *txq = tid->ac->txq; - - WARN_ON(!tid->paused); - - ath_txq_lock(sc, txq); - tid->paused = false; - - if (skb_queue_empty(&tid->buf_q)) - goto unlock; - - ath_tx_queue_tid(txq, tid); - ath_txq_schedule(sc, txq); -unlock: - ath_txq_unlock_complete(sc, txq); -} - static struct ath_frame_info *get_frame_info(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -201,11 +183,6 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) } } - if (tid->baw_head == tid->baw_tail) { - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->state &= ~AGGR_CLEANUP; - } - if (sendbar) { ath_txq_unlock(sc, txq); ath_send_bar(tid, tid->seq_start); @@ -277,9 +254,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, list_add_tail(&bf->list, &bf_head); - if (fi->retries) - ath_tx_update_baw(sc, tid, bf->bf_state.seqno); - + ath_tx_update_baw(sc, tid, bf->bf_state.seqno); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); } @@ -491,19 +466,19 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, tx_info = IEEE80211_SKB_CB(skb); fi = get_frame_info(skb); - if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { + /* + * Outside of the current BlockAck window, + * maybe part of a previous session + */ + txfail = 1; + } else if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { /* transmit completion, subframe is * acked by block ack */ acked_cnt++; } else if (!isaggr && txok) { /* transmit completion */ acked_cnt++; - } else if (tid->state & AGGR_CLEANUP) { - /* - * cleanup in progress, just fail - * the un-acked sub-frames - */ - txfail = 1; } else if (flush) { txpending = 1; } else if (fi->retries < ATH_MAX_SW_RETRIES) { @@ -527,7 +502,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, if (bf_next != NULL || !bf_last->bf_stale) list_move_tail(&bf->list, &bf_head); - if (!txpending || (tid->state & AGGR_CLEANUP)) { + if (!txpending) { /* * complete the acked-ones/xretried ones; update * block-ack window @@ -601,9 +576,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_txq_lock(sc, txq); } - if (tid->state & AGGR_CLEANUP) - ath_tx_flush_tid(sc, tid); - rcu_read_unlock(); if (needreset) @@ -620,6 +592,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_tx_status *ts, struct ath_buf *bf, struct list_head *bf_head) { + struct ieee80211_tx_info *info; bool txok, flush; txok = !(ts->ts_status & ATH9K_TXERR_MASK); @@ -631,8 +604,12 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, txq->axq_ampdu_depth--; if (!bf_isampdu(bf)) { - if (!flush) + if (!flush) { + info = IEEE80211_SKB_CB(bf->bf_mpdu); + memcpy(info->control.rates, bf->rates, + sizeof(info->control.rates)); ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); + } ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); } else ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); @@ -676,7 +653,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, skb = bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - rates = tx_info->control.rates; + rates = bf->rates; /* * Find the lowest frame length among the rate series that will have a @@ -1231,9 +1208,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, an = (struct ath_node *)sta->drv_priv; txtid = ATH_AN_2_TID(an, tid); - if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE)) - return -EAGAIN; - /* update ampdu factor/density, they may have changed. This may happen * in HT IBSS when a beacon with HT-info is received after the station * has already been added. @@ -1245,7 +1219,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, an->mpdudensity = density; } - txtid->state |= AGGR_ADDBA_PROGRESS; + txtid->active = true; txtid->paused = true; *ssn = txtid->seq_start = txtid->seq_next; txtid->bar_index = -1; @@ -1262,28 +1236,9 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); struct ath_txq *txq = txtid->ac->txq; - if (txtid->state & AGGR_CLEANUP) - return; - - if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { - txtid->state &= ~AGGR_ADDBA_PROGRESS; - return; - } - ath_txq_lock(sc, txq); + txtid->active = false; txtid->paused = true; - - /* - * If frames are still being transmitted for this TID, they will be - * cleaned up during tx completion. To prevent race conditions, this - * TID can only be reused after all in-progress subframes have been - * completed. - */ - if (txtid->baw_head != txtid->baw_tail) - txtid->state |= AGGR_CLEANUP; - else - txtid->state &= ~AGGR_ADDBA_COMPLETE; - ath_tx_flush_tid(sc, txtid); ath_txq_unlock_complete(sc, txq); } @@ -1349,18 +1304,28 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) } } -void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tidno) { - struct ath_atx_tid *txtid; + struct ath_atx_tid *tid; struct ath_node *an; + struct ath_txq *txq; an = (struct ath_node *)sta->drv_priv; + tid = ATH_AN_2_TID(an, tidno); + txq = tid->ac->txq; - txtid = ATH_AN_2_TID(an, tid); - txtid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; - txtid->state |= AGGR_ADDBA_COMPLETE; - txtid->state &= ~AGGR_ADDBA_PROGRESS; - ath_tx_resume_tid(sc, txtid); + ath_txq_lock(sc, txq); + + tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; + tid->paused = false; + + if (!skb_queue_empty(&tid->buf_q)) { + ath_tx_queue_tid(txq, tid); + ath_txq_schedule(sc, txq); + } + + ath_txq_unlock_complete(sc, txq); } /********************/ @@ -2409,12 +2374,10 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->baw_head = tid->baw_tail = 0; tid->sched = false; tid->paused = false; - tid->state &= ~AGGR_CLEANUP; + tid->active = false; __skb_queue_head_init(&tid->buf_q); acno = TID_TO_WME_AC(tidno); tid->ac = &an->ac[acno]; - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->state &= ~AGGR_ADDBA_PROGRESS; } for (acno = 0, ac = &an->ac[acno]; @@ -2451,8 +2414,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) } ath_tid_drain(sc, txq, tid); - tid->state &= ~AGGR_ADDBA_COMPLETE; - tid->state &= ~AGGR_CLEANUP; + tid->active = false; ath_txq_unlock(sc, txq); } diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 830bb1d1f957..b827d51c30a3 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1624,7 +1624,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, netif_carrier_off(dev); - if (!proc_create_data("driver/atmel", 0, NULL, &atmel_proc_fops, priv)); + if (!proc_create_data("driver/atmel", 0, NULL, &atmel_proc_fops, priv)) printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6dd07e2ec595..a95b77ab360e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2458,7 +2458,7 @@ static void b43_request_firmware(struct work_struct *work) for (i = 0; i < B43_NR_FWTYPES; i++) { errmsg = ctx->errors[i]; if (strlen(errmsg)) - b43err(dev->wl, errmsg); + b43err(dev->wl, "%s", errmsg); } b43_print_fw_helptext(dev->wl, 1); goto out; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index be0787cab24f..9431af2465f3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -27,7 +27,6 @@ #include "tracepoint.h" #define PKTFILTER_BUF_SIZE 128 -#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */ #define BRCMF_DEFAULT_BCN_TIMEOUT 3 #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40 #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40 @@ -338,23 +337,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) goto done; } - /* Try to set and enable ARP offload feature, this may fail */ - err = brcmf_fil_iovar_int_set(ifp, "arp_ol", BRCMF_ARPOL_MODE); - if (err) { - brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n", - BRCMF_ARPOL_MODE, err); - err = 0; - } else { - err = brcmf_fil_iovar_int_set(ifp, "arpoe", 1); - if (err) { - brcmf_dbg(TRACE, "failed to enable ARP offload err = %d\n", - err); - err = 0; - } else - brcmf_dbg(TRACE, "successfully enabled ARP offload to 0x%x\n", - BRCMF_ARPOL_MODE); - } - /* Setup packet filter */ brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER); brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 59c25463e428..b98f2235978e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -653,10 +653,13 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); + ndev->destructor = free_netdev; return 0; fail: + drvr->iflist[ifp->bssidx] = NULL; ndev->netdev_ops = NULL; + free_netdev(ndev); return -EBADE; } @@ -720,6 +723,9 @@ static int brcmf_net_p2p_attach(struct brcmf_if *ifp) return 0; fail: + ifp->drvr->iflist[ifp->bssidx] = NULL; + ndev->netdev_ops = NULL; + free_netdev(ndev); return -EBADE; } @@ -788,6 +794,7 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) struct brcmf_if *ifp; ifp = drvr->iflist[bssidx]; + drvr->iflist[bssidx] = NULL; if (!ifp) { brcmf_err("Null interface, idx=%d\n", bssidx); return; @@ -808,15 +815,13 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) cancel_work_sync(&ifp->setmacaddr_work); cancel_work_sync(&ifp->multicast_work); } - + /* unregister will take care of freeing it */ unregister_netdev(ifp->ndev); if (bssidx == 0) brcmf_cfg80211_detach(drvr->config); - free_netdev(ifp->ndev); } else { kfree(ifp); } - drvr->iflist[bssidx] = NULL; } int brcmf_attach(uint bus_hdrlen, struct device *dev) @@ -925,8 +930,6 @@ fail: brcmf_fws_del_interface(ifp); brcmf_fws_deinit(drvr); } - free_netdev(ifp->ndev); - drvr->iflist[0] = NULL; if (p2p_ifp) { free_netdev(p2p_ifp->ndev); drvr->iflist[1] = NULL; @@ -934,7 +937,8 @@ fail: return ret; } if ((brcmf_p2p_enable) && (p2p_ifp)) - brcmf_net_p2p_attach(p2p_ifp); + if (brcmf_net_p2p_attach(p2p_ifp) < 0) + brcmf_p2p_enable = 0; return 0; } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index 5a64280e6485..83ee53a7c76e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c @@ -202,7 +202,8 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, return; brcmf_fws_add_interface(ifp); if (!drvr->fweh.evt_handler[BRCMF_E_IF]) - err = brcmf_net_attach(ifp, false); + if (brcmf_net_attach(ifp, false) < 0) + return; } if (ifevent->action == BRCMF_E_IF_CHANGE) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index 0f2c83bc95dc..665ef69e974b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -23,6 +23,12 @@ #define BRCMF_FIL_ACTION_FRAME_SIZE 1800 +/* ARP Offload feature flags for arp_ol iovar */ +#define BRCMF_ARP_OL_AGENT 0x00000001 +#define BRCMF_ARP_OL_SNOOP 0x00000002 +#define BRCMF_ARP_OL_HOST_AUTO_REPLY 0x00000004 +#define BRCMF_ARP_OL_PEER_AUTO_REPLY 0x00000008 + enum brcmf_fil_p2p_if_types { BRCMF_FIL_P2P_IF_CLIENT, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index e7a1a4770996..79555f006d53 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -47,6 +47,7 @@ #define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ (channel == SOCIAL_CHAN_2) || \ (channel == SOCIAL_CHAN_3)) +#define BRCMF_P2P_TEMP_CHAN SOCIAL_CHAN_3 #define SOCIAL_CHAN_CNT 3 #define AF_PEER_SEARCH_CNT 2 @@ -1954,21 +1955,21 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg) err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); if (err < 0) { brcmf_err("set p2p_disc error\n"); - brcmf_free_vif(p2p_vif); + brcmf_free_vif(cfg, p2p_vif); goto exit; } /* obtain bsscfg index for P2P discovery */ err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); if (err < 0) { brcmf_err("retrieving discover bsscfg index failed\n"); - brcmf_free_vif(p2p_vif); + brcmf_free_vif(cfg, p2p_vif); goto exit; } /* Verify that firmware uses same bssidx as driver !! */ if (p2p_ifp->bssidx != bssidx) { brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n", bssidx, p2p_ifp->bssidx); - brcmf_free_vif(p2p_vif); + brcmf_free_vif(cfg, p2p_vif); goto exit; } @@ -1996,7 +1997,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) brcmf_p2p_cancel_remain_on_channel(vif->ifp); brcmf_p2p_deinit_discovery(p2p); /* remove discovery interface */ - brcmf_free_vif(vif); + brcmf_free_vif(p2p->cfg, vif); p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; } /* just set it all to zero */ @@ -2013,17 +2014,30 @@ static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p, u16 *chanspec) { struct brcmf_if *ifp; - struct brcmf_fil_chan_info_le ci; + u8 mac_addr[ETH_ALEN]; struct brcmu_chan ch; - s32 err; + struct brcmf_bss_info_le *bi; + u8 *buf; ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; - ch.chnum = 11; - - err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci)); - if (!err) - ch.chnum = le32_to_cpu(ci.hw_channel); + if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mac_addr, + ETH_ALEN) == 0) { + buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (buf != NULL) { + *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); + if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO, + buf, WL_BSS_INFO_MAX) == 0) { + bi = (struct brcmf_bss_info_le *)(buf + 4); + *chanspec = le16_to_cpu(bi->chanspec); + kfree(buf); + return; + } + kfree(buf); + } + } + /* Use default channel for P2P */ + ch.chnum = BRCMF_P2P_TEMP_CHAN; ch.bw = BRCMU_CHAN_BW_20; p2p->cfg->d11inf.encchspec(&ch); *chanspec = ch.chspec; @@ -2208,7 +2222,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, return &p2p_vif->wdev; fail: - brcmf_free_vif(p2p_vif); + brcmf_free_vif(p2p->cfg, p2p_vif); return ERR_PTR(err); } @@ -2217,13 +2231,31 @@ fail: * * @vif: virtual interface object to delete. */ -static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_vif *vif) +static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_info *cfg, + struct brcmf_cfg80211_vif *vif) { - struct brcmf_p2p_info *p2p = &vif->ifp->drvr->config->p2p; - cfg80211_unregister_wdev(&vif->wdev); - p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; - brcmf_free_vif(vif); + cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; + brcmf_free_vif(cfg, vif); +} + +/** + * brcmf_p2p_free_p2p_if() - free up net device related data. + * + * @ndev: net device that needs to be freed. + */ +static void brcmf_p2p_free_p2p_if(struct net_device *ndev) +{ + struct brcmf_cfg80211_info *cfg; + struct brcmf_cfg80211_vif *vif; + struct brcmf_if *ifp; + + ifp = netdev_priv(ndev); + cfg = ifp->drvr->config; + vif = ifp->vif; + + brcmf_free_vif(cfg, vif); + free_netdev(ifp->ndev); } /** @@ -2303,6 +2335,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, brcmf_err("Registering netdevice failed\n"); goto fail; } + /* override destructor */ + ifp->ndev->destructor = brcmf_p2p_free_p2p_if; + cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif; /* Disable firmware roaming for P2P interface */ brcmf_fil_iovar_int_set(ifp, "roam_off", 1); @@ -2314,7 +2349,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, return &ifp->vif->wdev; fail: - brcmf_free_vif(vif); + brcmf_free_vif(cfg, vif); return ERR_PTR(err); } @@ -2350,7 +2385,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) break; case NL80211_IFTYPE_P2P_DEVICE: - brcmf_p2p_delete_p2pdev(vif); + brcmf_p2p_delete_p2pdev(cfg, vif); return 0; default: return -ENOTSUPP; @@ -2378,7 +2413,6 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) err = 0; } brcmf_cfg80211_arm_vif_event(cfg, NULL); - brcmf_free_vif(vif); p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL; return err; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 6d758f285352..301e572e8923 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -459,6 +459,38 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key) return err; } +static s32 +brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable) +{ + s32 err; + u32 mode; + + if (enable) + mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY; + else + mode = 0; + + /* Try to set and enable ARP offload feature, this may fail, then it */ + /* is simply not supported and err 0 will be returned */ + err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode); + if (err) { + brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n", + mode, err); + err = 0; + } else { + err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable); + if (err) { + brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n", + enable, err); + err = 0; + } else + brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n", + enable, mode); + } + + return err; +} + static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, const char *name, enum nl80211_iftype type, @@ -2216,6 +2248,11 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, } pm = enabled ? PM_FAST : PM_OFF; + /* Do not enable the power save after assoc if it is a p2p interface */ + if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) { + brcmf_dbg(INFO, "Do not enable power save for P2P clients\n"); + pm = PM_OFF; + } brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled")); err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm); @@ -3640,10 +3677,28 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif, } static s32 +brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg, + struct brcmf_if *ifp, + struct ieee80211_channel *channel) +{ + u16 chanspec; + s32 err; + + brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band, + channel->center_freq); + + chanspec = channel_to_chanspec(&cfg->d11inf, channel); + err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); + + return err; +} + +static s32 brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *settings) { s32 ie_offset; + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_tlv *ssid_ie; struct brcmf_ssid_le ssid_le; @@ -3683,6 +3738,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, } brcmf_set_mpc(ifp, 0); + brcmf_configure_arp_offload(ifp, false); /* find the RSN_IE */ rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, @@ -3713,6 +3769,12 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); + err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan); + if (err < 0) { + brcmf_err("Set Channel failed, %d\n", err); + goto exit; + } + if (settings->beacon_interval) { err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, settings->beacon_interval); @@ -3789,8 +3851,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); exit: - if (err) + if (err) { brcmf_set_mpc(ifp, 1); + brcmf_configure_arp_offload(ifp, true); + } return err; } @@ -3831,6 +3895,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) brcmf_err("bss_enable config failed %d\n", err); } brcmf_set_mpc(ifp, 1); + brcmf_configure_arp_offload(ifp, true); set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); @@ -4140,11 +4205,15 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = { .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE) + } }; static const struct ieee80211_iface_combination brcmf_iface_combos[] = { { .max_interfaces = BRCMF_IFACE_MAX_CNT, - .num_different_channels = 1, /* no multi-channel for now */ + .num_different_channels = 2, .n_limits = ARRAY_SIZE(brcmf_iface_limits), .limits = brcmf_iface_limits } @@ -4197,7 +4266,8 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO); + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_DEVICE); wiphy->iface_combinations = brcmf_iface_combos; wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; @@ -4251,20 +4321,16 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, return vif; } -void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) +void brcmf_free_vif(struct brcmf_cfg80211_info *cfg, + struct brcmf_cfg80211_vif *vif) { - struct brcmf_cfg80211_info *cfg; - struct wiphy *wiphy; - - wiphy = vif->wdev.wiphy; - cfg = wiphy_priv(wiphy); list_del(&vif->list); cfg->vif_cnt--; kfree(vif); if (!cfg->vif_cnt) { - wiphy_unregister(wiphy); - wiphy_free(wiphy); + wiphy_unregister(cfg->wiphy); + wiphy_free(cfg->wiphy); } } @@ -4641,7 +4707,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, return 0; case BRCMF_E_IF_DEL: - ifp->vif = NULL; mutex_unlock(&event->vif_event_lock); /* event may not be upon user request */ if (brcmf_cfg80211_vif_event_armed(cfg)) @@ -4847,8 +4912,7 @@ cfg80211_p2p_attach_out: wl_deinit_priv(cfg); cfg80211_attach_out: - brcmf_free_vif(vif); - wiphy_free(wiphy); + brcmf_free_vif(cfg, vif); return NULL; } @@ -4860,7 +4924,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) wl_deinit_priv(cfg); brcmf_btcoex_detach(cfg); list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) { - brcmf_free_vif(vif); + brcmf_free_vif(cfg, vif); } } @@ -5224,6 +5288,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) if (err) goto default_conf_out; + brcmf_configure_arp_offload(ifp, true); + cfg->dongle_up = true; default_conf_out: diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index a71cff84cdcf..d9bdaf9a72d0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -487,7 +487,8 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp); struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, enum nl80211_iftype type, bool pm_block); -void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); +void brcmf_free_vif(struct brcmf_cfg80211_info *cfg, + struct brcmf_cfg80211_vif *vif); s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, const u8 *vndr_ie_buf, u32 vndr_ie_len); diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 592d0aa634a8..e9a3cbc409ae 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -1423,7 +1423,7 @@ il_setup_rx_scan_handlers(struct il_priv *il) } EXPORT_SYMBOL(il_setup_rx_scan_handlers); -inline u16 +u16 il_get_active_dwell_time(struct il_priv *il, enum ieee80211_band band, u8 n_probes) { diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h index f8246f2d88f9..4caaf52986a4 100644 --- a/drivers/net/wireless/iwlegacy/common.h +++ b/drivers/net/wireless/iwlegacy/common.h @@ -1832,16 +1832,16 @@ u32 il_usecs_to_beacons(struct il_priv *il, u32 usec, u32 beacon_interval); __le32 il_add_beacon_time(struct il_priv *il, u32 base, u32 addon, u32 beacon_interval); -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops il_pm_ops; #define IL_LEGACY_PM_OPS (&il_pm_ops) -#else /* !CONFIG_PM */ +#else /* !CONFIG_PM_SLEEP */ #define IL_LEGACY_PM_OPS NULL -#endif /* !CONFIG_PM */ +#endif /* !CONFIG_PM_SLEEP */ /***************************************************** * Error Handling Debugging diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index db183b44e038..c3c13ce96eb0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -735,7 +735,7 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) memcpy(&lq, priv->stations[i].lq, sizeof(struct iwl_link_quality_cmd)); - if (!memcmp(&lq, &zero_lq, sizeof(lq))) + if (memcmp(&lq, &zero_lq, sizeof(lq))) send_lq = true; } spin_unlock_bh(&priv->sta_lock); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 191dcae8ba47..c6384555aab4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -173,6 +173,8 @@ enum { REPLY_DEBUG_CMD = 0xf0, DEBUG_LOG_MSG = 0xf7, + MCAST_FILTER_CMD = 0xd0, + /* D3 commands/notifications */ D3_CONFIG_CMD = 0xd3, PROT_OFFLOAD_CONFIG_CMD = 0xd4, @@ -948,4 +950,29 @@ struct iwl_set_calib_default_cmd { u8 data[0]; } __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ +#define MAX_PORT_ID_NUM 2 + +/** + * struct iwl_mcast_filter_cmd - configure multicast filter. + * @filter_own: Set 1 to filter out multicast packets sent by station itself + * @port_id: Multicast MAC addresses array specifier. This is a strange way + * to identify network interface adopted in host-device IF. + * It is used by FW as index in array of addresses. This array has + * MAX_PORT_ID_NUM members. + * @count: Number of MAC addresses in the array + * @pass_all: Set 1 to pass all multicast packets. + * @bssid: current association BSSID. + * @addr_list: Place holder for array of MAC addresses. + * IMPORTANT: add padding if necessary to ensure DWORD alignment. + */ +struct iwl_mcast_filter_cmd { + u8 filter_own; + u8 port_id; + u8 count; + u8 pass_all; + u8 bssid[6]; + u8 reserved[2]; + u8 addr_list[0]; +} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ + #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index e6eca4d66f6c..b2cc3d98e0f7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -586,10 +586,12 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm, */ static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mac_data_sta *ctxt_sta) + struct iwl_mac_data_sta *ctxt_sta, + bool force_assoc_off) { /* We need the dtim_period to set the MAC as associated */ - if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) { + if (vif->bss_conf.assoc && vif->bss_conf.dtim_period && + !force_assoc_off) { u32 dtim_offs; /* @@ -659,7 +661,8 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm, cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON); /* Fill the data specific for station mode */ - iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta); + iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta, + action == FW_CTXT_ACTION_ADD); return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); } @@ -677,7 +680,8 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm, iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); /* Fill the data specific for station mode */ - iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta); + iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta, + action == FW_CTXT_ACTION_ADD); cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow & IEEE80211_P2P_OPPPS_CTWINDOW_MASK); diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index dd158ec571fb..a5eb8c82f16a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -701,6 +701,20 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw, *total_flags = 0; } +static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mcast_filter_cmd mcast_filter_cmd = { + .pass_all = 1, + }; + + memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN); + + return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC, + sizeof(mcast_filter_cmd), + &mcast_filter_cmd); +} + static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -722,6 +736,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, return; } iwl_mvm_bt_coex_vif_assoc(mvm, vif); + iwl_mvm_configure_mcast_filter(mvm, vif); } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { /* remove AP station now that the MAC is unassoc */ ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); @@ -931,7 +946,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, switch (cmd) { case STA_NOTIFY_SLEEP: - if (atomic_read(&mvmsta->pending_frames) > 0) + if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) ieee80211_sta_block_awake(hw, sta, true); /* * The fw updates the STA to be asleep. Tx packets on the Tx diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 8269bc562951..9f46b23801bc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -292,6 +292,7 @@ struct iwl_mvm { struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT]; struct work_struct sta_drained_wk; unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; + atomic_t pending_frames[IWL_MVM_STATION_COUNT]; /* configured by mac80211 */ u32 rts_threshold; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index fe031d304d1e..b29c31a41594 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -292,6 +292,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(BT_COEX_PROT_ENV), CMD(BT_PROFILE_NOTIFICATION), CMD(BT_CONFIG), + CMD(MCAST_FILTER_CMD), }; #undef CMD diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 2157b0f8ced5..2476e43799d5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -298,6 +298,12 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, else cmd->type = cpu_to_le32(SCAN_TYPE_FORCED); + /* + * TODO: This is a WA due to a bug in the FW AUX framework that does not + * properly handle time events that fail to be scheduled + */ + cmd->type = cpu_to_le32(SCAN_TYPE_FORCED); + cmd->repeats = cpu_to_le32(1); /* diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 0fd96e4da461..5c664ed54400 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -219,7 +219,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; /* HW restart, don't assume the memory has been zeroed */ - atomic_set(&mvm_sta->pending_frames, 0); + atomic_set(&mvm->pending_frames[sta_id], 0); mvm_sta->tid_disable_agg = 0; mvm_sta->tfd_queue_msk = 0; for (i = 0; i < IEEE80211_NUM_ACS; i++) @@ -407,14 +407,21 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, } /* + * Make sure that the tx response code sees the station as -EBUSY and + * calls the drain worker. + */ + spin_lock_bh(&mvm_sta->lock); + /* * There are frames pending on the AC queues for this station. * We need to wait until all the frames are drained... */ - if (atomic_read(&mvm_sta->pending_frames)) { - ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); + if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) { rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], ERR_PTR(-EBUSY)); + spin_unlock_bh(&mvm_sta->lock); + ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); } else { + spin_unlock_bh(&mvm_sta->lock); ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); } diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 12abd2d71835..a4ddce77aaae 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -274,7 +274,6 @@ struct iwl_mvm_tid_data { * @bt_reduced_txpower: is reduced tx power enabled for this station * @lock: lock to protect the whole struct. Since %tid_data is access from Tx * and from Tx response flow, it needs a spinlock. - * @pending_frames: number of frames for this STA on the shared Tx queues. * @tid_data: per tid data. Look at %iwl_mvm_tid_data. * * When mac80211 creates a station it reserves some space (hw->sta_data_size) @@ -290,7 +289,6 @@ struct iwl_mvm_sta { u8 max_agg_bufsize; bool bt_reduced_txpower; spinlock_t lock; - atomic_t pending_frames; struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; struct iwl_lq_sta lq_sta; struct ieee80211_vif *vif; diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 479074303bd7..f212f16502ff 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -416,9 +416,8 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, spin_unlock(&mvmsta->lock); - if (mvmsta->vif->type == NL80211_IFTYPE_AP && - txq_id < IWL_MVM_FIRST_AGG_QUEUE) - atomic_inc(&mvmsta->pending_frames); + if (txq_id < IWL_MVM_FIRST_AGG_QUEUE) + atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); return 0; @@ -680,16 +679,41 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, /* * If the txq is not an AMPDU queue, there is no chance we freed * several skbs. Check that out... - * If there are no pending frames for this STA, notify mac80211 that - * this station can go to sleep in its STA table. */ - if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta && - !WARN_ON(skb_freed > 1) && - mvmsta->vif->type == NL80211_IFTYPE_AP && - atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) { - ieee80211_sta_block_awake(mvm->hw, sta, false); - set_bit(sta_id, mvm->sta_drained); - schedule_work(&mvm->sta_drained_wk); + if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && !WARN_ON(skb_freed > 1) && + atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) { + if (mvmsta) { + /* + * If there are no pending frames for this STA, notify + * mac80211 that this station can go to sleep in its + * STA table. + */ + if (mvmsta->vif->type == NL80211_IFTYPE_AP) + ieee80211_sta_block_awake(mvm->hw, sta, false); + /* + * We might very well have taken mvmsta pointer while + * the station was being removed. The remove flow might + * have seen a pending_frame (because we didn't take + * the lock) even if now the queues are drained. So make + * really sure now that this the station is not being + * removed. If it is, run the drain worker to remove it. + */ + spin_lock_bh(&mvmsta->lock); + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + if (IS_ERR_OR_NULL(sta)) { + /* + * Station disappeared in the meantime: + * so we are draining. + */ + set_bit(sta_id, mvm->sta_drained); + schedule_work(&mvm->sta_drained_wk); + } + spin_unlock_bh(&mvmsta->lock); + } else if (!mvmsta) { + /* Tx response without STA, so we are draining */ + set_bit(sta_id, mvm->sta_drained); + schedule_work(&mvm->sta_drained_wk); + } } rcu_read_unlock(); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index b878a32e7a98..cb34c7895f2a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1723,11 +1723,11 @@ static void mac80211_hwsim_free(void) class_destroy(hwsim_class); } - -static struct device_driver mac80211_hwsim_driver = { - .name = "mac80211_hwsim", - .bus = &platform_bus_type, - .owner = THIS_MODULE, +static struct platform_driver mac80211_hwsim_driver = { + .driver = { + .name = "mac80211_hwsim", + .owner = THIS_MODULE, + }, }; static const struct net_device_ops hwsim_netdev_ops = { @@ -2219,7 +2219,7 @@ static int __init init_mac80211_hwsim(void) spin_lock_init(&hwsim_radio_lock); INIT_LIST_HEAD(&hwsim_radios); - err = driver_register(&mac80211_hwsim_driver); + err = platform_driver_register(&mac80211_hwsim_driver); if (err) return err; @@ -2254,7 +2254,7 @@ static int __init init_mac80211_hwsim(void) err = -ENOMEM; goto failed_drvdata; } - data->dev->driver = &mac80211_hwsim_driver; + data->dev->driver = &mac80211_hwsim_driver.driver; err = device_bind_driver(data->dev); if (err != 0) { printk(KERN_DEBUG @@ -2564,7 +2564,7 @@ failed_drvdata: failed: mac80211_hwsim_free(); failed_unregister_driver: - driver_unregister(&mac80211_hwsim_driver); + platform_driver_unregister(&mac80211_hwsim_driver); return err; } module_init(init_mac80211_hwsim); @@ -2577,6 +2577,6 @@ static void __exit exit_mac80211_hwsim(void) mac80211_hwsim_free(); unregister_netdev(hwsim_mon); - driver_unregister(&mac80211_hwsim_driver); + platform_driver_unregister(&mac80211_hwsim_driver); } module_exit(exit_mac80211_hwsim); diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c index 753b5682d53f..a5f9875cfd6e 100644 --- a/drivers/net/wireless/mwifiex/debugfs.c +++ b/drivers/net/wireless/mwifiex/debugfs.c @@ -26,10 +26,17 @@ static struct dentry *mwifiex_dfs_dir; static char *bss_modes[] = { - "Unknown", - "Ad-hoc", - "Managed", - "Auto" + "UNSPECIFIED", + "ADHOC", + "STATION", + "AP", + "AP_VLAN", + "WDS", + "MONITOR", + "MESH_POINT", + "P2P_CLIENT", + "P2P_GO", + "P2P_DEVICE", }; /* size/addr for mwifiex_debug_info */ @@ -200,7 +207,12 @@ mwifiex_info_read(struct file *file, char __user *ubuf, p += sprintf(p, "driver_version = %s", fmt); p += sprintf(p, "\nverext = %s", priv->version_str); p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); - p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); + + if (info.bss_mode >= ARRAY_SIZE(bss_modes)) + p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode); + else + p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); + p += sprintf(p, "media_state=\"%s\"\n", (!priv->media_connected ? "Disconnected" : "Connected")); p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 999ffc12578b..c97e9d327331 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -764,6 +764,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) "can't alloc skb for rx\n"); goto done; } + kmemleak_not_leak(new_skb); pci_unmap_single(rtlpci->pdev, *((dma_addr_t *) skb->cb), diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h index d3a02e73f53a..21ca33a7c770 100644 --- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h @@ -550,7 +550,7 @@ do { \ rxmcs == DESC92C_RATE11M) struct phy_rx_agc_info_t { - #if __LITTLE_ENDIAN + #ifdef __LITTLE_ENDIAN u8 gain:7, trsw:1; #else u8 trsw:1, gain:7; @@ -574,7 +574,7 @@ struct phy_status_rpt { u8 stream_target_csi[2]; u8 sig_evm; u8 rsvd_3; -#if __LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/ u8 sgi_en:1; u8 rxsc:2; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 3d0498e69c8c..189ba124a8c6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -1973,26 +1973,35 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) } } -void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, - u8 rssi_level) +static void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u32 ratr_value = (u32) mac->basic_rates; - u8 *mcsrate = mac->mcs; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; u8 ratr_index = 0; u8 nmode = mac->ht_enable; - u8 mimo_ps = 1; - u16 shortgi_rate = 0; - u32 tmp_ratr_value = 0; + u8 mimo_ps = IEEE80211_SMPS_OFF; + u16 shortgi_rate; + u32 tmp_ratr_value; u8 curtxbw_40mhz = mac->bw_40; - u8 curshortgi_40mhz = mac->sgi_40; - u8 curshortgi_20mhz = mac->sgi_20; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; enum wireless_mode wirelessmode = mac->mode; - ratr_value |= ((*(u16 *) (mcsrate))) << 12; + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + if (mac->opmode == NL80211_IFTYPE_ADHOC) + ratr_value = 0xfff; + + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); switch (wirelessmode) { case WIRELESS_MODE_B: if (ratr_value & 0x0000000c) @@ -2006,7 +2015,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, case WIRELESS_MODE_N_24G: case WIRELESS_MODE_N_5G: nmode = 1; - if (mimo_ps == 0) { + if (mimo_ps == IEEE80211_SMPS_STATIC) { ratr_value &= 0x0007F005; } else { u32 ratr_mask; @@ -2016,8 +2025,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, ratr_mask = 0x000ff005; else ratr_mask = 0x0f0ff005; - if (curtxbw_40mhz) - ratr_mask |= 0x00000010; + ratr_value &= ratr_mask; } break; @@ -2026,41 +2034,74 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, ratr_value &= 0x000ff0ff; else ratr_value &= 0x0f0ff0ff; + break; } + ratr_value &= 0x0FFFFFFF; - if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || - (!curtxbw_40mhz && curshortgi_20mhz))) { + + if (nmode && ((curtxbw_40mhz && + curshortgi_40mhz) || (!curtxbw_40mhz && + curshortgi_20mhz))) { + ratr_value |= 0x10000000; tmp_ratr_value = (ratr_value >> 12); + for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) { if ((1 << shortgi_rate) & tmp_ratr_value) break; } + shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) | - (shortgi_rate << 4) | (shortgi_rate); + (shortgi_rate << 4) | (shortgi_rate); } + rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value); + + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n", + rtl_read_dword(rtlpriv, REG_ARFR0)); } -void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) +static void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u32 ratr_bitmap = (u32) mac->basic_rates; - u8 *p_mcsrate = mac->mcs; - u8 ratr_index = 0; - u8 curtxbw_40mhz = mac->bw_40; - u8 curshortgi_40mhz = mac->sgi_40; - u8 curshortgi_20mhz = mac->sgi_20; - enum wireless_mode wirelessmode = mac->mode; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; + u8 ratr_index; + u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; + u8 curshortgi_40mhz = curtxbw_40mhz && + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; bool shortgi = false; u8 rate_mask[5]; u8 macid = 0; - u8 mimops = 1; - - ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12); + u8 mimo_ps = IEEE80211_SMPS_OFF; + + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION || + mac->opmode == NL80211_IFTYPE_MESH_POINT) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + if (mac->opmode == NL80211_IFTYPE_ADHOC) + ratr_bitmap = 0xfff; + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); switch (wirelessmode) { case WIRELESS_MODE_B: ratr_index = RATR_INX_WIRELESS_B; @@ -2071,6 +2112,7 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) break; case WIRELESS_MODE_G: ratr_index = RATR_INX_WIRELESS_GB; + if (rssi_level == 1) ratr_bitmap &= 0x00000f00; else if (rssi_level == 2) @@ -2085,7 +2127,8 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) case WIRELESS_MODE_N_24G: case WIRELESS_MODE_N_5G: ratr_index = RATR_INX_WIRELESS_NGB; - if (mimops == 0) { + + if (mimo_ps == IEEE80211_SMPS_STATIC) { if (rssi_level == 1) ratr_bitmap &= 0x00070000; else if (rssi_level == 2) @@ -2128,8 +2171,10 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) } } } + if ((curtxbw_40mhz && curshortgi_40mhz) || (!curtxbw_40mhz && curshortgi_20mhz)) { + if (macid == 0) shortgi = true; else if (macid == 1) @@ -2138,21 +2183,42 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) break; default: ratr_index = RATR_INX_WIRELESS_NGB; + if (rtlphy->rf_type == RF_1T2R) ratr_bitmap &= 0x000ff0ff; else ratr_bitmap &= 0x0f0ff0ff; break; } - RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "ratr_bitmap :%x\n", - ratr_bitmap); - *(u32 *)&rate_mask = ((ratr_bitmap & 0x0fffffff) | - ratr_index << 28); + sta_entry->ratr_index = ratr_index; + + RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, + "ratr_bitmap :%x\n", ratr_bitmap); + *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | + (ratr_index << 28); rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80; RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "Rate_index:%x, ratr_val:%x, %5phC\n", ratr_index, ratr_bitmap, rate_mask); - rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); + memcpy(rtlpriv->rate_mask, rate_mask, 5); + /* rtl92c_fill_h2c_cmd() does USB I/O and will result in a + * "scheduled while atomic" if called directly */ + schedule_work(&rtlpriv->works.fill_h2c_cmd); + + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm.useramask) + rtl92cu_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92cu_update_hal_rate_table(hw, sta); } void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h index f41a3aa4a26f..8e3ec1e25644 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h @@ -98,10 +98,6 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, u32 rm_msr); void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); -void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, - u8 rssi_level); -void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw); bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 85b6bdb163c0..da4f587199ee 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -289,14 +289,30 @@ void rtl92c_set_key(struct ieee80211_hw *hw, u32 key_index, macaddr = cam_const_broad; entry_id = key_index; } else { + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_MESH_POINT) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, COMP_SEC, + DBG_EMERG, + "Can not find free hw security cam entry\n"); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + key_index = PAIRWISE_KEYIDX; - entry_id = CAM_PAIRWISE_KEY_POSITION; is_pairwise = true; } } if (rtlpriv->sec.key_len[key_index] == 0) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "delete one entry\n"); + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_MESH_POINT) + rtl_cam_del_entry(hw, p_macaddr); rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); } else { RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 23d640a4debd..826f085c29dd 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -106,8 +106,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { .update_interrupt_mask = rtl92cu_update_interrupt_mask, .get_hw_reg = rtl92cu_get_hw_reg, .set_hw_reg = rtl92cu_set_hw_reg, - .update_rate_tbl = rtl92cu_update_hal_rate_table, - .update_rate_mask = rtl92cu_update_hal_rate_mask, + .update_rate_tbl = rtl92cu_update_hal_rate_tbl, .fill_tx_desc = rtl92cu_tx_fill_desc, .fill_fake_txdesc = rtl92cu_fill_fake_txdesc, .fill_tx_cmddesc = rtl92cu_tx_fill_cmddesc, @@ -137,6 +136,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { .phy_lc_calibrate = _rtl92cu_phy_lc_calibrate, .phy_set_bw_mode_callback = rtl92cu_phy_set_bw_mode_callback, .dm_dynamic_txpower = rtl92cu_dm_dynamic_txpower, + .fill_h2c_cmd = rtl92c_fill_h2c_cmd, }; static struct rtl_mod_params rtl92cu_mod_params = { @@ -349,6 +349,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x07aa, 0x0056, rtl92cu_hal_cfg)}, /*ATKK-Gemtek*/ {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/ + {RTL_USB_DEVICE(0x0846, 0xf001, rtl92cu_hal_cfg)}, /*On Netwrks N300MA*/ {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/ {RTL_USB_DEVICE(0x0bda, 0x8186, rtl92cu_hal_cfg)}, /*Realtek 92CE-VAU*/ {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/ diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h index a1310abd0d54..262e1e4c6e5b 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.h @@ -49,5 +49,8 @@ bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask); void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level); #endif diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 76732b0cd221..a3532e077871 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -824,6 +824,7 @@ static void rtl_usb_stop(struct ieee80211_hw *hw) /* should after adapter start and interrupt enable. */ set_hal_stop(rtlhal); + cancel_work_sync(&rtlpriv->works.fill_h2c_cmd); /* Enable software */ SET_USB_STOP(rtlusb); rtl_usb_deinit(hw); @@ -1026,6 +1027,16 @@ static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw, return false; } +static void rtl_fill_h2c_cmd_work_callback(struct work_struct *work) +{ + struct rtl_works *rtlworks = + container_of(work, struct rtl_works, fill_h2c_cmd); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->fill_h2c_cmd(hw, H2C_RA_MASK, 5, rtlpriv->rate_mask); +} + static struct rtl_intf_ops rtl_usb_ops = { .adapter_start = rtl_usb_start, .adapter_stop = rtl_usb_stop, @@ -1057,6 +1068,8 @@ int rtl_usb_probe(struct usb_interface *intf, /* this spin lock must be initialized early */ spin_lock_init(&rtlpriv->locks.usb_lock); + INIT_WORK(&rtlpriv->works.fill_h2c_cmd, + rtl_fill_h2c_cmd_work_callback); rtlpriv->usb_data_index = 0; init_completion(&rtlpriv->firmware_loading_complete); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 44328baa6389..cc03e7c87cbe 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1736,6 +1736,8 @@ struct rtl_hal_ops { void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw, bool mstate); void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw); + void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id, + u32 cmd_len, u8 *p_cmdbuffer); }; struct rtl_intf_ops { @@ -1869,6 +1871,7 @@ struct rtl_works { struct delayed_work fwevt_wq; struct work_struct lps_change_work; + struct work_struct fill_h2c_cmd; }; struct rtl_debug { @@ -2048,6 +2051,7 @@ struct rtl_priv { }; }; bool enter_ps; /* true when entering PS */ + u8 rate_mask[5]; /*This must be the last item so that it points to the data allocated diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c index affdb3ec6225..4a0bbb13806b 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.c +++ b/drivers/net/wireless/ti/wl12xx/scan.c @@ -310,7 +310,7 @@ static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd, memcpy(cmd->channels_2, cmd_channels->channels_2, sizeof(cmd->channels_2)); memcpy(cmd->channels_5, cmd_channels->channels_5, - sizeof(cmd->channels_2)); + sizeof(cmd->channels_5)); /* channels_4 are not supported, so no need to copy them */ } diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h index 222d03540200..9e5484a73667 100644 --- a/drivers/net/wireless/ti/wl12xx/wl12xx.h +++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h @@ -36,12 +36,12 @@ #define WL127X_IFTYPE_SR_VER 3 #define WL127X_MAJOR_SR_VER 10 #define WL127X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE -#define WL127X_MINOR_SR_VER 115 +#define WL127X_MINOR_SR_VER 133 /* minimum multi-role FW version for wl127x */ #define WL127X_IFTYPE_MR_VER 5 #define WL127X_MAJOR_MR_VER 7 #define WL127X_SUBTYPE_MR_VER WLCORE_FW_VER_IGNORE -#define WL127X_MINOR_MR_VER 115 +#define WL127X_MINOR_MR_VER 42 /* FW chip version for wl128x */ #define WL128X_CHIP_VER 7 @@ -49,7 +49,7 @@ #define WL128X_IFTYPE_SR_VER 3 #define WL128X_MAJOR_SR_VER 10 #define WL128X_SUBTYPE_SR_VER WLCORE_FW_VER_IGNORE -#define WL128X_MINOR_SR_VER 115 +#define WL128X_MINOR_SR_VER 133 /* minimum multi-role FW version for wl128x */ #define WL128X_IFTYPE_MR_VER 5 #define WL128X_MAJOR_MR_VER 7 diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c index 09d944505ac0..2b642f8c9266 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.c +++ b/drivers/net/wireless/ti/wl18xx/scan.c @@ -34,7 +34,7 @@ static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd, memcpy(cmd->channels_2, cmd_channels->channels_2, sizeof(cmd->channels_2)); memcpy(cmd->channels_5, cmd_channels->channels_5, - sizeof(cmd->channels_2)); + sizeof(cmd->channels_5)); /* channels_4 are not supported, so no need to copy them */ } diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 37984e6d4e99..8c20935d72c9 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -662,7 +662,7 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk) { struct xenvif *vif = NULL, *tmp; s8 status; - u16 irq, flags; + u16 flags; struct xen_netif_rx_response *resp; struct sk_buff_head rxq; struct sk_buff *skb; @@ -771,13 +771,13 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk) sco->meta_slots_used); RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret); - irq = vif->irq; - if (ret && list_empty(&vif->notify_list)) - list_add_tail(&vif->notify_list, ¬ify); xenvif_notify_tx_completion(vif); - xenvif_put(vif); + if (ret && list_empty(&vif->notify_list)) + list_add_tail(&vif->notify_list, ¬ify); + else + xenvif_put(vif); npo.meta_cons += sco->meta_slots_used; dev_kfree_skb(skb); } @@ -785,6 +785,7 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk) list_for_each_entry_safe(vif, tmp, ¬ify, notify_list) { notify_remote_via_irq(vif->irq); list_del_init(&vif->notify_list); + xenvif_put(vif); } /* More work to do? */ diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 4775d4e61b88..74a852e4e41f 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -28,7 +28,7 @@ config NFC_WILINK config NFC_MEI_PHY tristate "MEI bus NFC device support" - depends on INTEL_MEI_BUS_NFC && NFC_HCI + depends on INTEL_MEI && NFC_HCI help This adds support to use an mei bus nfc device. Select this if you will use an HCI NFC driver for an NFC chip connected behind an diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c index b8f8abc422f0..1201bdbfb791 100644 --- a/drivers/nfc/mei_phy.c +++ b/drivers/nfc/mei_phy.c @@ -64,6 +64,15 @@ int nfc_mei_phy_enable(void *phy_id) return r; } + r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy); + if (r) { + pr_err("MEY_PHY: Event cb registration failed\n"); + mei_cl_disable_device(phy->device); + phy->powered = 0; + + return r; + } + phy->powered = 1; return 0; diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c index 1ad044dce7b6..cdf1bc53b257 100644 --- a/drivers/nfc/microread/mei.c +++ b/drivers/nfc/microread/mei.c @@ -43,24 +43,16 @@ static int microread_mei_probe(struct mei_cl_device *device, return -ENOMEM; } - r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy); - if (r) { - pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n"); - goto err_out; - } - r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME, MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, &phy->hdev); - if (r < 0) - goto err_out; - - return 0; + if (r < 0) { + nfc_mei_phy_free(phy); -err_out: - nfc_mei_phy_free(phy); + return r; + } - return r; + return 0; } static int microread_mei_remove(struct mei_cl_device *device) @@ -71,8 +63,6 @@ static int microread_mei_remove(struct mei_cl_device *device) microread_remove(phy->hdev); - nfc_mei_phy_disable(phy); - nfc_mei_phy_free(phy); return 0; diff --git a/drivers/nfc/pn544/mei.c b/drivers/nfc/pn544/mei.c index 1eb48848a35a..b5d3d18179eb 100644 --- a/drivers/nfc/pn544/mei.c +++ b/drivers/nfc/pn544/mei.c @@ -43,24 +43,16 @@ static int pn544_mei_probe(struct mei_cl_device *device, return -ENOMEM; } - r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy); - if (r) { - pr_err(PN544_DRIVER_NAME ": event cb registration failed\n"); - goto err_out; - } - r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME, MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD, &phy->hdev); - if (r < 0) - goto err_out; - - return 0; + if (r < 0) { + nfc_mei_phy_free(phy); -err_out: - nfc_mei_phy_free(phy); + return r; + } - return r; + return 0; } static int pn544_mei_remove(struct mei_cl_device *device) @@ -71,8 +63,6 @@ static int pn544_mei_remove(struct mei_cl_device *device) pn544_hci_remove(phy->hdev); - nfc_mei_phy_disable(phy); - nfc_mei_phy_free(phy); return 0; diff --git a/drivers/of/base.c b/drivers/of/base.c index f53b992f060a..a6f584a7f4a1 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -192,14 +192,15 @@ EXPORT_SYMBOL(of_find_property); struct device_node *of_find_all_nodes(struct device_node *prev) { struct device_node *np; + unsigned long flags; - raw_spin_lock(&devtree_lock); + raw_spin_lock_irqsave(&devtree_lock, flags); np = prev ? prev->allnext : of_allnodes; for (; np != NULL; np = np->allnext) if (of_node_get(np)) break; of_node_put(prev); - raw_spin_unlock(&devtree_lock); + raw_spin_unlock_irqrestore(&devtree_lock, flags); return np; } EXPORT_SYMBOL(of_find_all_nodes); @@ -421,8 +422,9 @@ struct device_node *of_get_next_available_child(const struct device_node *node, struct device_node *prev) { struct device_node *next; + unsigned long flags; - raw_spin_lock(&devtree_lock); + raw_spin_lock_irqsave(&devtree_lock, flags); next = prev ? prev->sibling : node->child; for (; next; next = next->sibling) { if (!__of_device_is_available(next)) @@ -431,7 +433,7 @@ struct device_node *of_get_next_available_child(const struct device_node *node, break; } of_node_put(prev); - raw_spin_unlock(&devtree_lock); + raw_spin_unlock_irqrestore(&devtree_lock, flags); return next; } EXPORT_SYMBOL(of_get_next_available_child); @@ -735,13 +737,14 @@ EXPORT_SYMBOL_GPL(of_modalias_node); struct device_node *of_find_node_by_phandle(phandle handle) { struct device_node *np; + unsigned long flags; - raw_spin_lock(&devtree_lock); + raw_spin_lock_irqsave(&devtree_lock, flags); for (np = of_allnodes; np; np = np->allnext) if (np->phandle == handle) break; of_node_get(np); - raw_spin_unlock(&devtree_lock); + raw_spin_unlock_irqrestore(&devtree_lock, flags); return np; } EXPORT_SYMBOL(of_find_node_by_phandle); diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 9544cdc0d1af..e79e006eb9ab 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -811,6 +811,70 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) return pcidev->irq; } +static struct iosapic_info *first_isi = NULL; + +#ifdef CONFIG_64BIT +int iosapic_serial_irq(int num) +{ + struct iosapic_info *isi = first_isi; + struct irt_entry *irte = NULL; /* only used if PAT PDC */ + struct vector_info *vi; + int isi_line; /* line used by device */ + + /* lookup IRT entry for isi/slot/pin set */ + irte = &irt_cell[num]; + + DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n", + irte, + irte->entry_type, + irte->entry_length, + irte->polarity_trigger, + irte->src_bus_irq_devno, + irte->src_bus_id, + irte->src_seg_id, + irte->dest_iosapic_intin, + (u32) irte->dest_iosapic_addr); + isi_line = irte->dest_iosapic_intin; + + /* get vector info for this input line */ + vi = isi->isi_vector + isi_line; + DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", isi_line, vi); + + /* If this IRQ line has already been setup, skip it */ + if (vi->irte) + goto out; + + vi->irte = irte; + + /* + * Allocate processor IRQ + * + * XXX/FIXME The txn_alloc_irq() code and related code should be + * moved to enable_irq(). That way we only allocate processor IRQ + * bits for devices that actually have drivers claiming them. + * Right now we assign an IRQ to every PCI device present, + * regardless of whether it's used or not. + */ + vi->txn_irq = txn_alloc_irq(8); + + if (vi->txn_irq < 0) + panic("I/O sapic: couldn't get TXN IRQ\n"); + + /* enable_irq() will use txn_* to program IRdT */ + vi->txn_addr = txn_alloc_addr(vi->txn_irq); + vi->txn_data = txn_alloc_data(vi->txn_irq); + + vi->eoi_addr = isi->addr + IOSAPIC_REG_EOI; + vi->eoi_data = cpu_to_le32(vi->txn_data); + + cpu_claim_irq(vi->txn_irq, &iosapic_interrupt_type, vi); + + out: + + return vi->txn_irq; +} +#endif + /* ** squirrel away the I/O Sapic Version @@ -877,6 +941,8 @@ void *iosapic_register(unsigned long hpa) vip->irqline = (unsigned char) cnt; vip->iosapic = isi; } + if (!first_isi) + first_isi = isi; return isi; } diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 2ef7103270bb..1f05913ae677 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -668,7 +668,7 @@ lba_fixup_bus(struct pci_bus *bus) BUG(); } - if (ldev->hba.elmmio_space.start) { + if (ldev->hba.elmmio_space.flags) { err = request_resource(&iomem_resource, &(ldev->hba.elmmio_space)); if (err < 0) { @@ -993,7 +993,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) case PAT_LMMIO: /* used to fix up pre-initialized MEM BARs */ - if (!lba_dev->hba.lmmio_space.start) { + if (!lba_dev->hba.lmmio_space.flags) { sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO", (int)lba_dev->hba.bus_num.start); @@ -1001,7 +1001,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) io->start; r = &lba_dev->hba.lmmio_space; r->name = lba_dev->hba.lmmio_name; - } else if (!lba_dev->hba.elmmio_space.start) { + } else if (!lba_dev->hba.elmmio_space.flags) { sprintf(lba_dev->hba.elmmio_name, "PCI%02x ELMMIO", (int)lba_dev->hba.bus_num.start); @@ -1096,6 +1096,7 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) r->name = "LBA PCI Busses"; r->start = lba_num & 0xff; r->end = (lba_num>>8) & 0xff; + r->flags = IORESOURCE_BUS; /* Set up local PCI Bus resources - we don't need them for ** Legacy boxes but it's nice to see in /proc/iomem. @@ -1494,7 +1495,7 @@ lba_driver_probe(struct parisc_device *dev) pci_add_resource_offset(&resources, &lba_dev->hba.io_space, HBA_PORT_BASE(lba_dev->hba.hba_num)); - if (lba_dev->hba.elmmio_space.start) + if (lba_dev->hba.elmmio_space.flags) pci_add_resource_offset(&resources, &lba_dev->hba.elmmio_space, lba_dev->hba.lmmio_space_offset); if (lba_dev->hba.lmmio_space.flags) diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index ac6e8e7a02df..a042d065a0c7 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -494,15 +494,4 @@ static struct pci_driver superio_driver = { .probe = superio_probe, }; -static int __init superio_modinit(void) -{ - return pci_register_driver(&superio_driver); -} - -static void __exit superio_exit(void) -{ - pci_unregister_driver(&superio_driver); -} - -module_init(superio_modinit); -module_exit(superio_exit); +module_pci_driver(superio_driver); diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 24e12d4d1769..a50576081b34 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -71,7 +71,7 @@ config PARPORT_PC_FIFO config PARPORT_PC_SUPERIO bool "SuperIO chipset support" - depends on PARPORT_PC + depends on PARPORT_PC && !PARISC help Saying Y here enables some probes for Super-IO chipsets in order to find out things like base addresses, IRQ lines and DMA channels. It diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index a5251cb5fb0c..6e3a60c78873 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -234,7 +234,7 @@ static int parport_PS2_supported(struct parport *pb) struct parport *parport_gsc_probe_port(unsigned long base, unsigned long base_hi, int irq, - int dma, struct pci_dev *dev) + int dma, struct parisc_device *padev) { struct parport_gsc_private *priv; struct parport_operations *ops; @@ -258,7 +258,6 @@ struct parport *parport_gsc_probe_port(unsigned long base, priv->ctr_writable = 0xff; priv->dma_buf = 0; priv->dma_handle = 0; - priv->dev = dev; p->base = base; p->base_hi = base_hi; p->irq = irq; @@ -282,6 +281,7 @@ struct parport *parport_gsc_probe_port(unsigned long base, return NULL; } + p->dev = &padev->dev; p->base_hi = base_hi; p->modes = tmp.modes; p->size = (p->modes & PARPORT_MODE_EPP)?8:3; @@ -373,7 +373,7 @@ static int parport_init_chip(struct parisc_device *dev) } p = parport_gsc_probe_port(port, 0, dev->irq, - /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, NULL); + /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, dev); if (p) parport_count++; dev_set_drvdata(&dev->dev, p); diff --git a/drivers/parport/parport_gsc.h b/drivers/parport/parport_gsc.h index fc9c37c54022..812214768d27 100644 --- a/drivers/parport/parport_gsc.h +++ b/drivers/parport/parport_gsc.h @@ -217,6 +217,6 @@ extern void parport_gsc_dec_use_count(void); extern struct parport *parport_gsc_probe_port(unsigned long base, unsigned long base_hi, int irq, int dma, - struct pci_dev *dev); + struct parisc_device *padev); #endif /* __DRIVERS_PARPORT_PARPORT_GSC_H */ diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 96fed19c6d90..716aa93fff76 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -950,6 +950,20 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK ; } +void acpiphp_check_host_bridge(acpi_handle handle) +{ + struct acpiphp_bridge *bridge; + + bridge = acpiphp_handle_to_bridge(handle); + if (bridge) { + acpiphp_check_bridge(bridge); + put_bridge(bridge); + } + + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); +} + static void _handle_hotplug_event_bridge(struct work_struct *work) { struct acpiphp_bridge *bridge; diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 8ec8b4f48560..0f4554e48cc5 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -580,6 +580,7 @@ struct aer_recover_entry u8 devfn; u16 domain; int severity; + struct aer_capability_regs *regs; }; static DEFINE_KFIFO(aer_recover_ring, struct aer_recover_entry, @@ -593,7 +594,7 @@ static DEFINE_SPINLOCK(aer_recover_ring_lock); static DECLARE_WORK(aer_recover_work, aer_recover_work_func); void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, - int severity) + int severity, struct aer_capability_regs *aer_regs) { unsigned long flags; struct aer_recover_entry entry = { @@ -601,6 +602,7 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, .devfn = devfn, .domain = domain, .severity = severity, + .regs = aer_regs, }; spin_lock_irqsave(&aer_recover_ring_lock, flags); @@ -627,6 +629,7 @@ static void aer_recover_work_func(struct work_struct *work) PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn)); continue; } + cper_print_aer(pdev, entry.severity, entry.regs); do_recovery(pdev, entry.severity); pci_dev_put(pdev); } diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 5ab14251839d..2c7c9f5f592c 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c @@ -220,7 +220,7 @@ int cper_severity_to_aer(int cper_severity) } EXPORT_SYMBOL_GPL(cper_severity_to_aer); -void cper_print_aer(const char *prefix, struct pci_dev *dev, int cper_severity, +void cper_print_aer(struct pci_dev *dev, int cper_severity, struct aer_capability_regs *aer) { int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0; @@ -244,7 +244,7 @@ void cper_print_aer(const char *prefix, struct pci_dev *dev, int cper_severity, agent = AER_GET_AGENT(aer_severity, status); dev_err(&dev->dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask); - cper_print_bits(prefix, status, status_strs, status_strs_size); + cper_print_bits("", status, status_strs, status_strs_size); dev_err(&dev->dev, "aer_layer=%s, aer_agent=%s\n", aer_error_layer[layer], aer_agent_string[agent]); if (aer_severity != AER_CORRECTABLE) diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index c67c37e23dd7..694c3ace4520 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -610,7 +610,7 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) bool found = false; unsigned long config; - mutex_lock(&pctldev->mutex); + mutex_lock(&pinctrl_maps_mutex); /* Parse the pinctrl map and look for the elected pin/state */ for_each_maps(maps_node, i, map) { @@ -659,7 +659,7 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) confops->pin_config_config_dbg_show(pctldev, s, config); exit: - mutex_unlock(&pctldev->mutex); + mutex_unlock(&pinctrl_maps_mutex); return 0; } diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index a67af419f531..d6b41747d687 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -830,7 +830,8 @@ static int __init u300_gpio_probe(struct platform_device *pdev) return 0; err_no_range: - err = gpiochip_remove(&gpio->chip); + if (gpiochip_remove(&gpio->chip)) + dev_err(&pdev->dev, "failed to remove gpio chip\n"); err_no_chip: err_no_domain: err_no_port: diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index ac742817ebce..2d76f66a2e0b 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -196,6 +196,12 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) return IRQ_HANDLED; } +struct exynos_eint_gpio_save { + u32 eint_con; + u32 eint_fltcon0; + u32 eint_fltcon1; +}; + /* * exynos_eint_gpio_init() - setup handling of external gpio interrupts. * @d: driver data of samsung pinctrl driver. @@ -204,8 +210,8 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) { struct samsung_pin_bank *bank; struct device *dev = d->dev; - unsigned int ret; - unsigned int i; + int ret; + int i; if (!d->irq) { dev_err(dev, "irq number not available\n"); @@ -227,11 +233,29 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) bank->nr_pins, &exynos_gpio_irqd_ops, bank); if (!bank->irq_domain) { dev_err(dev, "gpio irq domain add failed\n"); - return -ENXIO; + ret = -ENXIO; + goto err_domains; + } + + bank->soc_priv = devm_kzalloc(d->dev, + sizeof(struct exynos_eint_gpio_save), GFP_KERNEL); + if (!bank->soc_priv) { + irq_domain_remove(bank->irq_domain); + ret = -ENOMEM; + goto err_domains; } } return 0; + +err_domains: + for (--i, --bank; i >= 0; --i, --bank) { + if (bank->eint_type != EINT_TYPE_GPIO) + continue; + irq_domain_remove(bank->irq_domain); + } + + return ret; } static void exynos_wkup_irq_unmask(struct irq_data *irqd) @@ -326,6 +350,28 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) return 0; } +static u32 exynos_eint_wake_mask = 0xffffffff; + +u32 exynos_get_eint_wake_mask(void) +{ + return exynos_eint_wake_mask; +} + +static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on) +{ + struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); + unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq); + + pr_info("wake %s for irq %d\n", on ? "enabled" : "disabled", irqd->irq); + + if (!on) + exynos_eint_wake_mask |= bit; + else + exynos_eint_wake_mask &= ~bit; + + return 0; +} + /* * irq_chip for wakeup interrupts */ @@ -335,6 +381,7 @@ static struct irq_chip exynos_wkup_irq_chip = { .irq_mask = exynos_wkup_irq_mask, .irq_ack = exynos_wkup_irq_ack, .irq_set_type = exynos_wkup_irq_set_type, + .irq_set_wake = exynos_wkup_irq_set_wake, }; /* interrupt handler for wakeup interrupts 0..15 */ @@ -505,6 +552,72 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) return 0; } +static void exynos_pinctrl_suspend_bank( + struct samsung_pinctrl_drv_data *drvdata, + struct samsung_pin_bank *bank) +{ + struct exynos_eint_gpio_save *save = bank->soc_priv; + void __iomem *regs = drvdata->virt_base; + + save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET + + bank->eint_offset); + save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET + + 2 * bank->eint_offset); + save->eint_fltcon1 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET + + 2 * bank->eint_offset + 4); + + pr_debug("%s: save con %#010x\n", bank->name, save->eint_con); + pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0); + pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1); +} + +static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata) +{ + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + struct samsung_pin_bank *bank = ctrl->pin_banks; + int i; + + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) + if (bank->eint_type == EINT_TYPE_GPIO) + exynos_pinctrl_suspend_bank(drvdata, bank); +} + +static void exynos_pinctrl_resume_bank( + struct samsung_pinctrl_drv_data *drvdata, + struct samsung_pin_bank *bank) +{ + struct exynos_eint_gpio_save *save = bank->soc_priv; + void __iomem *regs = drvdata->virt_base; + + pr_debug("%s: con %#010x => %#010x\n", bank->name, + readl(regs + EXYNOS_GPIO_ECON_OFFSET + + bank->eint_offset), save->eint_con); + pr_debug("%s: fltcon0 %#010x => %#010x\n", bank->name, + readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET + + 2 * bank->eint_offset), save->eint_fltcon0); + pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name, + readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET + + 2 * bank->eint_offset + 4), save->eint_fltcon1); + + writel(save->eint_con, regs + EXYNOS_GPIO_ECON_OFFSET + + bank->eint_offset); + writel(save->eint_fltcon0, regs + EXYNOS_GPIO_EFLTCON_OFFSET + + 2 * bank->eint_offset); + writel(save->eint_fltcon1, regs + EXYNOS_GPIO_EFLTCON_OFFSET + + 2 * bank->eint_offset + 4); +} + +static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata) +{ + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + struct samsung_pin_bank *bank = ctrl->pin_banks; + int i; + + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) + if (bank->eint_type == EINT_TYPE_GPIO) + exynos_pinctrl_resume_bank(drvdata, bank); +} + /* pin banks of exynos4210 pin-controller 0 */ static struct samsung_pin_bank exynos4210_pin_banks0[] = { EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), @@ -568,6 +681,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos4210-gpio-ctrl0", }, { /* pin-controller instance 1 data */ @@ -582,6 +697,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos4210-gpio-ctrl1", }, { /* pin-controller instance 2 data */ @@ -663,6 +780,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos4x12-gpio-ctrl0", }, { /* pin-controller instance 1 data */ @@ -677,6 +796,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos4x12-gpio-ctrl1", }, { /* pin-controller instance 2 data */ @@ -687,6 +808,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos4x12-gpio-ctrl2", }, { /* pin-controller instance 3 data */ @@ -697,6 +820,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos4x12-gpio-ctrl3", }, }; @@ -775,6 +900,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos5250-gpio-ctrl0", }, { /* pin-controller instance 1 data */ @@ -785,6 +912,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos5250-gpio-ctrl1", }, { /* pin-controller instance 2 data */ @@ -795,6 +924,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos5250-gpio-ctrl2", }, { /* pin-controller instance 3 data */ @@ -805,6 +936,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .svc = EXYNOS_SVC_OFFSET, .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, .label = "exynos5250-gpio-ctrl3", }, }; diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h index 9b1f77a5bf0f..3c91c357792f 100644 --- a/drivers/pinctrl/pinctrl-exynos.h +++ b/drivers/pinctrl/pinctrl-exynos.h @@ -19,6 +19,7 @@ /* External GPIO and wakeup interrupt related definitions */ #define EXYNOS_GPIO_ECON_OFFSET 0x700 +#define EXYNOS_GPIO_EFLTCON_OFFSET 0x800 #define EXYNOS_GPIO_EMASK_OFFSET 0x900 #define EXYNOS_GPIO_EPEND_OFFSET 0xA00 #define EXYNOS_WKUP_ECON_OFFSET 0xE00 diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 055d0162098b..63ac22e89678 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -28,6 +28,7 @@ #include <linux/gpio.h> #include <linux/irqdomain.h> #include <linux/spinlock.h> +#include <linux/syscore_ops.h> #include "core.h" #include "pinctrl-samsung.h" @@ -48,6 +49,9 @@ static struct pin_config { { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, }; +/* Global list of devices (struct samsung_pinctrl_drv_data) */ +LIST_HEAD(drvdata_list); + static unsigned int pin_base; static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) @@ -956,9 +960,151 @@ static int samsung_pinctrl_probe(struct platform_device *pdev) ctrl->eint_wkup_init(drvdata); platform_set_drvdata(pdev, drvdata); + + /* Add to the global list */ + list_add_tail(&drvdata->node, &drvdata_list); + return 0; } +#ifdef CONFIG_PM + +/** + * samsung_pinctrl_suspend_dev - save pinctrl state for suspend for a device + * + * Save data for all banks handled by this device. + */ +static void samsung_pinctrl_suspend_dev( + struct samsung_pinctrl_drv_data *drvdata) +{ + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + void __iomem *virt_base = drvdata->virt_base; + int i; + + for (i = 0; i < ctrl->nr_banks; i++) { + struct samsung_pin_bank *bank = &ctrl->pin_banks[i]; + void __iomem *reg = virt_base + bank->pctl_offset; + + u8 *offs = bank->type->reg_offset; + u8 *widths = bank->type->fld_width; + enum pincfg_type type; + + /* Registers without a powerdown config aren't lost */ + if (!widths[PINCFG_TYPE_CON_PDN]) + continue; + + for (type = 0; type < PINCFG_TYPE_NUM; type++) + if (widths[type]) + bank->pm_save[type] = readl(reg + offs[type]); + + if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) { + /* Some banks have two config registers */ + bank->pm_save[PINCFG_TYPE_NUM] = + readl(reg + offs[PINCFG_TYPE_FUNC] + 4); + pr_debug("Save %s @ %p (con %#010x %08x)\n", + bank->name, reg, + bank->pm_save[PINCFG_TYPE_FUNC], + bank->pm_save[PINCFG_TYPE_NUM]); + } else { + pr_debug("Save %s @ %p (con %#010x)\n", bank->name, + reg, bank->pm_save[PINCFG_TYPE_FUNC]); + } + } + + if (ctrl->suspend) + ctrl->suspend(drvdata); +} + +/** + * samsung_pinctrl_resume_dev - restore pinctrl state from suspend for a device + * + * Restore one of the banks that was saved during suspend. + * + * We don't bother doing anything complicated to avoid glitching lines since + * we're called before pad retention is turned off. + */ +static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata) +{ + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; + void __iomem *virt_base = drvdata->virt_base; + int i; + + if (ctrl->resume) + ctrl->resume(drvdata); + + for (i = 0; i < ctrl->nr_banks; i++) { + struct samsung_pin_bank *bank = &ctrl->pin_banks[i]; + void __iomem *reg = virt_base + bank->pctl_offset; + + u8 *offs = bank->type->reg_offset; + u8 *widths = bank->type->fld_width; + enum pincfg_type type; + + /* Registers without a powerdown config aren't lost */ + if (!widths[PINCFG_TYPE_CON_PDN]) + continue; + + if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) { + /* Some banks have two config registers */ + pr_debug("%s @ %p (con %#010x %08x => %#010x %08x)\n", + bank->name, reg, + readl(reg + offs[PINCFG_TYPE_FUNC]), + readl(reg + offs[PINCFG_TYPE_FUNC] + 4), + bank->pm_save[PINCFG_TYPE_FUNC], + bank->pm_save[PINCFG_TYPE_NUM]); + writel(bank->pm_save[PINCFG_TYPE_NUM], + reg + offs[PINCFG_TYPE_FUNC] + 4); + } else { + pr_debug("%s @ %p (con %#010x => %#010x)\n", bank->name, + reg, readl(reg + offs[PINCFG_TYPE_FUNC]), + bank->pm_save[PINCFG_TYPE_FUNC]); + } + for (type = 0; type < PINCFG_TYPE_NUM; type++) + if (widths[type]) + writel(bank->pm_save[type], reg + offs[type]); + } +} + +/** + * samsung_pinctrl_suspend - save pinctrl state for suspend + * + * Save data for all banks across all devices. + */ +static int samsung_pinctrl_suspend(void) +{ + struct samsung_pinctrl_drv_data *drvdata; + + list_for_each_entry(drvdata, &drvdata_list, node) { + samsung_pinctrl_suspend_dev(drvdata); + } + + return 0; +} + +/** + * samsung_pinctrl_resume - restore pinctrl state for suspend + * + * Restore data for all banks across all devices. + */ +static void samsung_pinctrl_resume(void) +{ + struct samsung_pinctrl_drv_data *drvdata; + + list_for_each_entry_reverse(drvdata, &drvdata_list, node) { + samsung_pinctrl_resume_dev(drvdata); + } +} + +#else +#define samsung_pinctrl_suspend NULL +#define samsung_pinctrl_resume NULL +#endif + +static struct syscore_ops samsung_pinctrl_syscore_ops = { + .suspend = samsung_pinctrl_suspend, + .resume = samsung_pinctrl_resume, +}; + static const struct of_device_id samsung_pinctrl_dt_match[] = { #ifdef CONFIG_PINCTRL_EXYNOS { .compatible = "samsung,exynos4210-pinctrl", @@ -987,6 +1133,14 @@ static struct platform_driver samsung_pinctrl_driver = { static int __init samsung_pinctrl_drv_register(void) { + /* + * Register syscore ops for save/restore of registers across suspend. + * It's important to ensure that this driver is running at an earlier + * initcall level than any arch-specific init calls that install syscore + * ops that turn off pad retention (like exynos_pm_resume). + */ + register_syscore_ops(&samsung_pinctrl_syscore_ops); + return platform_driver_register(&samsung_pinctrl_driver); } postcore_initcall(samsung_pinctrl_drv_register); diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index 7c7f9ebcd05b..26d3519240c9 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h @@ -127,6 +127,7 @@ struct samsung_pin_bank_type { * @gpio_chip: GPIO chip of the bank. * @grange: linux gpio pin range supported by this bank. * @slock: spinlock protecting bank registers + * @pm_save: saved register values during suspend */ struct samsung_pin_bank { struct samsung_pin_bank_type *type; @@ -138,12 +139,15 @@ struct samsung_pin_bank { u32 eint_mask; u32 eint_offset; char *name; + void *soc_priv; struct device_node *of_node; struct samsung_pinctrl_drv_data *drvdata; struct irq_domain *irq_domain; struct gpio_chip gpio_chip; struct pinctrl_gpio_range grange; spinlock_t slock; + + u32 pm_save[PINCFG_TYPE_NUM + 1]; /* +1 to handle double CON registers*/ }; /** @@ -184,11 +188,15 @@ struct samsung_pin_ctrl { int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *); int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *); + void (*suspend)(struct samsung_pinctrl_drv_data *); + void (*resume)(struct samsung_pinctrl_drv_data *); + char *label; }; /** * struct samsung_pinctrl_drv_data: wrapper for holding driver data together. + * @node: global list node * @virt_base: register base address of the controller. * @dev: device instance representing the controller. * @irq: interrpt number used by the controller to notify gpio interrupts. @@ -201,6 +209,7 @@ struct samsung_pin_ctrl { * @nr_function: number of such pin functions. */ struct samsung_pinctrl_drv_data { + struct list_head node; void __iomem *virt_base; struct device *dev; int irq; diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c index c52fc2c08732..b7d8c890514c 100644 --- a/drivers/pinctrl/pinctrl-sunxi.c +++ b/drivers/pinctrl/pinctrl-sunxi.c @@ -1990,8 +1990,10 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) } clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); goto gpiochip_error; + } clk_prepare_enable(clk); @@ -2000,7 +2002,8 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) return 0; gpiochip_error: - ret = gpiochip_remove(pctl->chip); + if (gpiochip_remove(pctl->chip)) + dev_err(&pdev->dev, "failed to remove gpio chip\n"); pinctrl_error: pinctrl_unregister(pctl->pctl_dev); return ret; diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c index 791a6719d8a9..8cd90e7e945a 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c @@ -2357,27 +2357,48 @@ static const unsigned int sdhi3_wp_mux[] = { }; /* - USB0 ------------------------------------------------------------------- */ static const unsigned int usb0_pins[] = { - /* OVC */ - 150, 154, + /* PENC */ + 154, }; static const unsigned int usb0_mux[] = { - USB_OVC0_MARK, USB_PENC0_MARK, + USB_PENC0_MARK, +}; +static const unsigned int usb0_ovc_pins[] = { + /* USB_OVC */ + 150 +}; +static const unsigned int usb0_ovc_mux[] = { + USB_OVC0_MARK, }; /* - USB1 ------------------------------------------------------------------- */ static const unsigned int usb1_pins[] = { - /* OVC */ - 152, 155, + /* PENC */ + 155, }; static const unsigned int usb1_mux[] = { - USB_OVC1_MARK, USB_PENC1_MARK, + USB_PENC1_MARK, +}; +static const unsigned int usb1_ovc_pins[] = { + /* USB_OVC */ + 152, +}; +static const unsigned int usb1_ovc_mux[] = { + USB_OVC1_MARK, }; /* - USB2 ------------------------------------------------------------------- */ static const unsigned int usb2_pins[] = { - /* OVC, PENC */ - 125, 156, + /* PENC */ + 156, }; static const unsigned int usb2_mux[] = { - USB_OVC2_MARK, USB_PENC2_MARK, + USB_PENC2_MARK, +}; +static const unsigned int usb2_ovc_pins[] = { + /* USB_OVC */ + 125, +}; +static const unsigned int usb2_ovc_mux[] = { + USB_OVC2_MARK, }; static const struct sh_pfc_pin_group pinmux_groups[] = { @@ -2501,8 +2522,11 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(sdhi3_cd), SH_PFC_PIN_GROUP(sdhi3_wp), SH_PFC_PIN_GROUP(usb0), + SH_PFC_PIN_GROUP(usb0_ovc), SH_PFC_PIN_GROUP(usb1), + SH_PFC_PIN_GROUP(usb1_ovc), SH_PFC_PIN_GROUP(usb2), + SH_PFC_PIN_GROUP(usb2_ovc), }; static const char * const du0_groups[] = { @@ -2683,14 +2707,17 @@ static const char * const sdhi3_groups[] = { static const char * const usb0_groups[] = { "usb0", + "usb0_ovc", }; static const char * const usb1_groups[] = { "usb1", + "usb1_ovc", }; static const char * const usb2_groups[] = { "usb2", + "usb2_ovc", }; static const struct sh_pfc_function pinmux_functions[] = { diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c index ab63104e8dc9..70d986e04afb 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wmt.c +++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c @@ -609,8 +609,7 @@ int wmt_pinctrl_probe(struct platform_device *pdev, return 0; fail_range: - err = gpiochip_remove(&data->gpio_chip); - if (err) + if (gpiochip_remove(&data->gpio_chip)) dev_err(&pdev->dev, "failed to remove gpio chip\n"); fail_gpio: pinctrl_unregister(data->pctl_dev); diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 8df0c5a21be2..d111c8687f9b 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -703,7 +703,7 @@ static int hp_wmi_rfkill_setup(struct platform_device *device) } rfkill_init_sw_state(gps_rfkill, hp_wmi_get_sw_state(HPWMI_GPS)); - rfkill_set_hw_state(bluetooth_rfkill, + rfkill_set_hw_state(gps_rfkill, hp_wmi_get_hw_state(HPWMI_GPS)); err = rfkill_register(gps_rfkill); if (err) diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 0d0b5d7d19d0..7b8979c63f48 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -152,6 +152,7 @@ config BATTERY_SBS config BATTERY_BQ27x00 tristate "BQ27x00 battery driver" + depends on I2C || I2C=n help Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips. @@ -284,6 +285,7 @@ config CHARGER_LP8788 tristate "TI LP8788 charger driver" depends on MFD_LP8788 depends on LP8788_ADC + depends on IIO help Say Y to enable support for the LP8788 linear charger. diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c index a44175139bbf..fef56e2041b3 100644 --- a/drivers/power/pm2301_charger.c +++ b/drivers/power/pm2301_charger.c @@ -1269,5 +1269,5 @@ module_exit(pm2xxx_charger_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay"); -MODULE_ALIAS("platform:pm2xxx-charger"); +MODULE_ALIAS("i2c:pm2xxx-charger"); MODULE_DESCRIPTION("PM2xxx charger management driver"); diff --git a/drivers/power/wm831x_backup.c b/drivers/power/wm831x_backup.c index 58cbb009b74f..56fb509f4be0 100644 --- a/drivers/power/wm831x_backup.c +++ b/drivers/power/wm831x_backup.c @@ -207,7 +207,6 @@ static int wm831x_backup_remove(struct platform_device *pdev) struct wm831x_backup *devdata = platform_get_drvdata(pdev); power_supply_unregister(&devdata->backup); - kfree(devdata->backup.name); return 0; } diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c index bea94510ad2d..71a2559278d7 100644 --- a/drivers/ptp/ptp_pch.c +++ b/drivers/ptp/ptp_pch.c @@ -628,9 +628,10 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id) chip->caps = ptp_pch_caps; chip->ptp_clock = ptp_clock_register(&chip->caps, &pdev->dev); - - if (IS_ERR(chip->ptp_clock)) - return PTR_ERR(chip->ptp_clock); + if (IS_ERR(chip->ptp_clock)) { + ret = PTR_ERR(chip->ptp_clock); + goto err_ptp_clock_reg; + } spin_lock_init(&chip->register_lock); @@ -669,6 +670,7 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id) err_req_irq: ptp_clock_unregister(chip->ptp_clock); +err_ptp_clock_reg: iounmap(chip->regs); chip->regs = NULL; diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig index 6194d35ebb97..5ab056494bbe 100644 --- a/drivers/rapidio/Kconfig +++ b/drivers/rapidio/Kconfig @@ -47,4 +47,24 @@ config RAPIDIO_DEBUG If you are unsure about this, say N here. +choice + prompt "Enumeration method" + depends on RAPIDIO + default RAPIDIO_ENUM_BASIC + help + There are different enumeration and discovery mechanisms offered + for RapidIO subsystem. You may select single built-in method or + or any number of methods to be built as modules. + Selecting a built-in method disables use of loadable methods. + + If unsure, select Basic built-in. + +config RAPIDIO_ENUM_BASIC + tristate "Basic" + help + This option includes basic RapidIO fabric enumeration and discovery + mechanism similar to one described in RapidIO specification Annex 1. + +endchoice + source "drivers/rapidio/switches/Kconfig" diff --git a/drivers/rapidio/Makefile b/drivers/rapidio/Makefile index ec3fb8121004..3036702ffe8b 100644 --- a/drivers/rapidio/Makefile +++ b/drivers/rapidio/Makefile @@ -1,7 +1,8 @@ # # Makefile for RapidIO interconnect services # -obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o +obj-y += rio.o rio-access.o rio-driver.o rio-sysfs.o +obj-$(CONFIG_RAPIDIO_ENUM_BASIC) += rio-scan.o obj-$(CONFIG_RAPIDIO) += switches/ obj-$(CONFIG_RAPIDIO) += devices/ diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index 6faba406b6e9..a8b2c23a7ef4 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c @@ -471,6 +471,10 @@ static irqreturn_t tsi721_irqhandler(int irq, void *ptr) u32 intval; u32 ch_inte; + /* For MSI mode disable all device-level interrupts */ + if (priv->flags & TSI721_USING_MSI) + iowrite32(0, priv->regs + TSI721_DEV_INTE); + dev_int = ioread32(priv->regs + TSI721_DEV_INT); if (!dev_int) return IRQ_NONE; @@ -560,6 +564,14 @@ static irqreturn_t tsi721_irqhandler(int irq, void *ptr) } } #endif + + /* For MSI mode re-enable device-level interrupts */ + if (priv->flags & TSI721_USING_MSI) { + dev_int = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO | + TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH; + iowrite32(dev_int, priv->regs + TSI721_DEV_INTE); + } + return IRQ_HANDLED; } diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c index 0f4a53bdaa3c..a0c875563d76 100644 --- a/drivers/rapidio/rio-driver.c +++ b/drivers/rapidio/rio-driver.c @@ -164,6 +164,13 @@ void rio_unregister_driver(struct rio_driver *rdrv) driver_unregister(&rdrv->driver); } +void rio_attach_device(struct rio_dev *rdev) +{ + rdev->dev.bus = &rio_bus_type; + rdev->dev.parent = &rio_bus; +} +EXPORT_SYMBOL_GPL(rio_attach_device); + /** * rio_match_bus - Tell if a RIO device structure has a matching RIO driver device id structure * @dev: the standard device structure to match against @@ -200,6 +207,7 @@ struct bus_type rio_bus_type = { .name = "rapidio", .match = rio_match_bus, .dev_attrs = rio_dev_attrs, + .bus_attrs = rio_bus_attrs, .probe = rio_device_probe, .remove = rio_device_remove, }; diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index a965acd3c0e4..4c15dbf81087 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -37,12 +37,8 @@ #include "rio.h" -LIST_HEAD(rio_devices); - static void rio_init_em(struct rio_dev *rdev); -DEFINE_SPINLOCK(rio_global_list_lock); - static int next_destid = 0; static int next_comptag = 1; @@ -327,127 +323,6 @@ static int rio_is_switch(struct rio_dev *rdev) } /** - * rio_switch_init - Sets switch operations for a particular vendor switch - * @rdev: RIO device - * @do_enum: Enumeration/Discovery mode flag - * - * Searches the RIO switch ops table for known switch types. If the vid - * and did match a switch table entry, then call switch initialization - * routine to setup switch-specific routines. - */ -static void rio_switch_init(struct rio_dev *rdev, int do_enum) -{ - struct rio_switch_ops *cur = __start_rio_switch_ops; - struct rio_switch_ops *end = __end_rio_switch_ops; - - while (cur < end) { - if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { - pr_debug("RIO: calling init routine for %s\n", - rio_name(rdev)); - cur->init_hook(rdev, do_enum); - break; - } - cur++; - } - - if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) { - pr_debug("RIO: adding STD routing ops for %s\n", - rio_name(rdev)); - rdev->rswitch->add_entry = rio_std_route_add_entry; - rdev->rswitch->get_entry = rio_std_route_get_entry; - rdev->rswitch->clr_table = rio_std_route_clr_table; - } - - if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry) - printk(KERN_ERR "RIO: missing routing ops for %s\n", - rio_name(rdev)); -} - -/** - * rio_add_device- Adds a RIO device to the device model - * @rdev: RIO device - * - * Adds the RIO device to the global device list and adds the RIO - * device to the RIO device list. Creates the generic sysfs nodes - * for an RIO device. - */ -static int rio_add_device(struct rio_dev *rdev) -{ - int err; - - err = device_add(&rdev->dev); - if (err) - return err; - - spin_lock(&rio_global_list_lock); - list_add_tail(&rdev->global_list, &rio_devices); - spin_unlock(&rio_global_list_lock); - - rio_create_sysfs_dev_files(rdev); - - return 0; -} - -/** - * rio_enable_rx_tx_port - enable input receiver and output transmitter of - * given port - * @port: Master port associated with the RIO network - * @local: local=1 select local port otherwise a far device is reached - * @destid: Destination ID of the device to check host bit - * @hopcount: Number of hops to reach the target - * @port_num: Port (-number on switch) to enable on a far end device - * - * Returns 0 or 1 from on General Control Command and Status Register - * (EXT_PTR+0x3C) - */ -inline int rio_enable_rx_tx_port(struct rio_mport *port, - int local, u16 destid, - u8 hopcount, u8 port_num) { -#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS - u32 regval; - u32 ext_ftr_ptr; - - /* - * enable rx input tx output port - */ - pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = " - "%d, port_num = %d)\n", local, destid, hopcount, port_num); - - ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount); - - if (local) { - rio_local_read_config_32(port, ext_ftr_ptr + - RIO_PORT_N_CTL_CSR(0), - ®val); - } else { - if (rio_mport_read_config_32(port, destid, hopcount, - ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), ®val) < 0) - return -EIO; - } - - if (regval & RIO_PORT_N_CTL_P_TYP_SER) { - /* serial */ - regval = regval | RIO_PORT_N_CTL_EN_RX_SER - | RIO_PORT_N_CTL_EN_TX_SER; - } else { - /* parallel */ - regval = regval | RIO_PORT_N_CTL_EN_RX_PAR - | RIO_PORT_N_CTL_EN_TX_PAR; - } - - if (local) { - rio_local_write_config_32(port, ext_ftr_ptr + - RIO_PORT_N_CTL_CSR(0), regval); - } else { - if (rio_mport_write_config_32(port, destid, hopcount, - ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0) - return -EIO; - } -#endif - return 0; -} - -/** * rio_setup_device- Allocates and sets up a RIO device * @net: RIO network * @port: Master port to send transactions @@ -587,8 +462,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, rdev->destid); } - rdev->dev.bus = &rio_bus_type; - rdev->dev.parent = &rio_bus; + rio_attach_device(rdev); device_initialize(&rdev->dev); rdev->dev.release = rio_release_dev; @@ -1260,19 +1134,30 @@ static void rio_pw_enable(struct rio_mport *port, int enable) /** * rio_enum_mport- Start enumeration through a master port * @mport: Master port to send transactions + * @flags: Enumeration control flags * * Starts the enumeration process. If somebody has enumerated our * master port device, then give up. If not and we have an active * link, then start recursive peer enumeration. Returns %0 if * enumeration succeeds or %-EBUSY if enumeration fails. */ -int rio_enum_mport(struct rio_mport *mport) +int rio_enum_mport(struct rio_mport *mport, u32 flags) { struct rio_net *net = NULL; int rc = 0; printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id, mport->name); + + /* + * To avoid multiple start requests (repeat enumeration is not supported + * by this method) check if enumeration/discovery was performed for this + * mport: if mport was added into the list of mports for a net exit + * with error. + */ + if (mport->nnode.next || mport->nnode.prev) + return -EBUSY; + /* If somebody else enumerated our master port device, bail. */ if (rio_enum_host(mport) < 0) { printk(KERN_INFO @@ -1362,14 +1247,16 @@ static void rio_build_route_tables(struct rio_net *net) /** * rio_disc_mport- Start discovery through a master port * @mport: Master port to send transactions + * @flags: discovery control flags * * Starts the discovery process. If we have an active link, - * then wait for the signal that enumeration is complete. + * then wait for the signal that enumeration is complete (if wait + * is allowed). * When enumeration completion is signaled, start recursive * peer discovery. Returns %0 if discovery succeeds or %-EBUSY * on failure. */ -int rio_disc_mport(struct rio_mport *mport) +int rio_disc_mport(struct rio_mport *mport, u32 flags) { struct rio_net *net = NULL; unsigned long to_end; @@ -1379,6 +1266,11 @@ int rio_disc_mport(struct rio_mport *mport) /* If master port has an active link, allocate net and discover peers */ if (rio_mport_is_active(mport)) { + if (rio_enum_complete(mport)) + goto enum_done; + else if (flags & RIO_SCAN_ENUM_NO_WAIT) + return -EAGAIN; + pr_debug("RIO: wait for enumeration to complete...\n"); to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; @@ -1421,3 +1313,41 @@ enum_done: bail: return -EBUSY; } + +static struct rio_scan rio_scan_ops = { + .enumerate = rio_enum_mport, + .discover = rio_disc_mport, +}; + +static bool scan; +module_param(scan, bool, 0); +MODULE_PARM_DESC(scan, "Start RapidIO network enumeration/discovery " + "(default = 0)"); + +/** + * rio_basic_attach: + * + * When this enumeration/discovery method is loaded as a module this function + * registers its specific enumeration and discover routines for all available + * RapidIO mport devices. The "scan" command line parameter controls ability of + * the module to start RapidIO enumeration/discovery automatically. + * + * Returns 0 for success or -EIO if unable to register itself. + * + * This enumeration/discovery method cannot be unloaded and therefore does not + * provide a matching cleanup_module routine. + */ + +static int __init rio_basic_attach(void) +{ + if (rio_register_scan(RIO_MPORT_ANY, &rio_scan_ops)) + return -EIO; + if (scan) + rio_init_mports(); + return 0; +} + +late_initcall(rio_basic_attach); + +MODULE_DESCRIPTION("Basic RapidIO enumeration/discovery"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 4dbe360989be..66d4acd5e18f 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -285,3 +285,48 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev) rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE); } } + +static ssize_t bus_scan_store(struct bus_type *bus, const char *buf, + size_t count) +{ + long val; + struct rio_mport *port = NULL; + int rc; + + if (kstrtol(buf, 0, &val) < 0) + return -EINVAL; + + if (val == RIO_MPORT_ANY) { + rc = rio_init_mports(); + goto exit; + } + + if (val < 0 || val >= RIO_MAX_MPORTS) + return -EINVAL; + + port = rio_find_mport((int)val); + + if (!port) { + pr_debug("RIO: %s: mport_%d not available\n", + __func__, (int)val); + return -EINVAL; + } + + if (!port->nscan) + return -EINVAL; + + if (port->host_deviceid >= 0) + rc = port->nscan->enumerate(port, 0); + else + rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT); +exit: + if (!rc) + rc = count; + + return rc; +} + +struct bus_attribute rio_bus_attrs[] = { + __ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store), + __ATTR_NULL +}; diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index d553b5d13722..cb1c08996fbb 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -31,7 +31,11 @@ #include "rio.h" +static LIST_HEAD(rio_devices); +static DEFINE_SPINLOCK(rio_global_list_lock); + static LIST_HEAD(rio_mports); +static DEFINE_MUTEX(rio_mport_list_lock); static unsigned char next_portid; static DEFINE_SPINLOCK(rio_mmap_lock); @@ -53,6 +57,32 @@ u16 rio_local_get_device_id(struct rio_mport *port) } /** + * rio_add_device- Adds a RIO device to the device model + * @rdev: RIO device + * + * Adds the RIO device to the global device list and adds the RIO + * device to the RIO device list. Creates the generic sysfs nodes + * for an RIO device. + */ +int rio_add_device(struct rio_dev *rdev) +{ + int err; + + err = device_add(&rdev->dev); + if (err) + return err; + + spin_lock(&rio_global_list_lock); + list_add_tail(&rdev->global_list, &rio_devices); + spin_unlock(&rio_global_list_lock); + + rio_create_sysfs_dev_files(rdev); + + return 0; +} +EXPORT_SYMBOL_GPL(rio_add_device); + +/** * rio_request_inb_mbox - request inbound mailbox service * @mport: RIO master port from which to allocate the mailbox resource * @dev_id: Device specific pointer to pass on event @@ -489,6 +519,7 @@ rio_mport_get_physefb(struct rio_mport *port, int local, return ext_ftr_ptr; } +EXPORT_SYMBOL_GPL(rio_mport_get_physefb); /** * rio_get_comptag - Begin or continue searching for a RIO device by component tag @@ -521,6 +552,7 @@ exit: spin_unlock(&rio_global_list_lock); return rdev; } +EXPORT_SYMBOL_GPL(rio_get_comptag); /** * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port. @@ -545,6 +577,107 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) regval); return 0; } +EXPORT_SYMBOL_GPL(rio_set_port_lockout); + +/** + * rio_switch_init - Sets switch operations for a particular vendor switch + * @rdev: RIO device + * @do_enum: Enumeration/Discovery mode flag + * + * Searches the RIO switch ops table for known switch types. If the vid + * and did match a switch table entry, then call switch initialization + * routine to setup switch-specific routines. + */ +void rio_switch_init(struct rio_dev *rdev, int do_enum) +{ + struct rio_switch_ops *cur = __start_rio_switch_ops; + struct rio_switch_ops *end = __end_rio_switch_ops; + + while (cur < end) { + if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { + pr_debug("RIO: calling init routine for %s\n", + rio_name(rdev)); + cur->init_hook(rdev, do_enum); + break; + } + cur++; + } + + if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) { + pr_debug("RIO: adding STD routing ops for %s\n", + rio_name(rdev)); + rdev->rswitch->add_entry = rio_std_route_add_entry; + rdev->rswitch->get_entry = rio_std_route_get_entry; + rdev->rswitch->clr_table = rio_std_route_clr_table; + } + + if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry) + printk(KERN_ERR "RIO: missing routing ops for %s\n", + rio_name(rdev)); +} +EXPORT_SYMBOL_GPL(rio_switch_init); + +/** + * rio_enable_rx_tx_port - enable input receiver and output transmitter of + * given port + * @port: Master port associated with the RIO network + * @local: local=1 select local port otherwise a far device is reached + * @destid: Destination ID of the device to check host bit + * @hopcount: Number of hops to reach the target + * @port_num: Port (-number on switch) to enable on a far end device + * + * Returns 0 or 1 from on General Control Command and Status Register + * (EXT_PTR+0x3C) + */ +int rio_enable_rx_tx_port(struct rio_mport *port, + int local, u16 destid, + u8 hopcount, u8 port_num) +{ +#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS + u32 regval; + u32 ext_ftr_ptr; + + /* + * enable rx input tx output port + */ + pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = " + "%d, port_num = %d)\n", local, destid, hopcount, port_num); + + ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount); + + if (local) { + rio_local_read_config_32(port, ext_ftr_ptr + + RIO_PORT_N_CTL_CSR(0), + ®val); + } else { + if (rio_mport_read_config_32(port, destid, hopcount, + ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), ®val) < 0) + return -EIO; + } + + if (regval & RIO_PORT_N_CTL_P_TYP_SER) { + /* serial */ + regval = regval | RIO_PORT_N_CTL_EN_RX_SER + | RIO_PORT_N_CTL_EN_TX_SER; + } else { + /* parallel */ + regval = regval | RIO_PORT_N_CTL_EN_RX_PAR + | RIO_PORT_N_CTL_EN_TX_PAR; + } + + if (local) { + rio_local_write_config_32(port, ext_ftr_ptr + + RIO_PORT_N_CTL_CSR(0), regval); + } else { + if (rio_mport_write_config_32(port, destid, hopcount, + ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0) + return -EIO; + } +#endif + return 0; +} +EXPORT_SYMBOL_GPL(rio_enable_rx_tx_port); + /** * rio_chk_dev_route - Validate route to the specified device. @@ -610,6 +743,7 @@ rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) return 0; } +EXPORT_SYMBOL_GPL(rio_mport_chk_dev_access); /** * rio_chk_dev_access - Validate access to the specified device. @@ -941,6 +1075,7 @@ rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, return RIO_GET_BLOCK_ID(reg_val); } } +EXPORT_SYMBOL_GPL(rio_mport_get_efb); /** * rio_mport_get_feature - query for devices' extended features @@ -997,6 +1132,7 @@ rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, return 0; } +EXPORT_SYMBOL_GPL(rio_mport_get_feature); /** * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did @@ -1246,6 +1382,95 @@ EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg); #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ +/** + * rio_find_mport - find RIO mport by its ID + * @mport_id: number (ID) of mport device + * + * Given a RIO mport number, the desired mport is located + * in the global list of mports. If the mport is found, a pointer to its + * data structure is returned. If no mport is found, %NULL is returned. + */ +struct rio_mport *rio_find_mport(int mport_id) +{ + struct rio_mport *port; + + mutex_lock(&rio_mport_list_lock); + list_for_each_entry(port, &rio_mports, node) { + if (port->id == mport_id) + goto found; + } + port = NULL; +found: + mutex_unlock(&rio_mport_list_lock); + + return port; +} + +/** + * rio_register_scan - enumeration/discovery method registration interface + * @mport_id: mport device ID for which fabric scan routine has to be set + * (RIO_MPORT_ANY = set for all available mports) + * @scan_ops: enumeration/discovery control structure + * + * Assigns enumeration or discovery method to the specified mport device (or all + * available mports if RIO_MPORT_ANY is specified). + * Returns error if the mport already has an enumerator attached to it. + * In case of RIO_MPORT_ANY ignores ports with valid scan routines and returns + * an error if was unable to find at least one available mport. + */ +int rio_register_scan(int mport_id, struct rio_scan *scan_ops) +{ + struct rio_mport *port; + int rc = -EBUSY; + + mutex_lock(&rio_mport_list_lock); + list_for_each_entry(port, &rio_mports, node) { + if (port->id == mport_id || mport_id == RIO_MPORT_ANY) { + if (port->nscan && mport_id == RIO_MPORT_ANY) + continue; + else if (port->nscan) + break; + + port->nscan = scan_ops; + rc = 0; + + if (mport_id != RIO_MPORT_ANY) + break; + } + } + mutex_unlock(&rio_mport_list_lock); + + return rc; +} +EXPORT_SYMBOL_GPL(rio_register_scan); + +/** + * rio_unregister_scan - removes enumeration/discovery method from mport + * @mport_id: mport device ID for which fabric scan routine has to be + * unregistered (RIO_MPORT_ANY = set for all available mports) + * + * Removes enumeration or discovery method assigned to the specified mport + * device (or all available mports if RIO_MPORT_ANY is specified). + */ +int rio_unregister_scan(int mport_id) +{ + struct rio_mport *port; + + mutex_lock(&rio_mport_list_lock); + list_for_each_entry(port, &rio_mports, node) { + if (port->id == mport_id || mport_id == RIO_MPORT_ANY) { + if (port->nscan) + port->nscan = NULL; + if (mport_id != RIO_MPORT_ANY) + break; + } + } + mutex_unlock(&rio_mport_list_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(rio_unregister_scan); + static void rio_fixup_device(struct rio_dev *dev) { } @@ -1274,7 +1499,7 @@ static void disc_work_handler(struct work_struct *_work) work = container_of(_work, struct rio_disc_work, work); pr_debug("RIO: discovery work for mport %d %s\n", work->mport->id, work->mport->name); - rio_disc_mport(work->mport); + work->mport->nscan->discover(work->mport, 0); } int rio_init_mports(void) @@ -1290,12 +1515,15 @@ int rio_init_mports(void) * First, run enumerations and check if we need to perform discovery * on any of the registered mports. */ + mutex_lock(&rio_mport_list_lock); list_for_each_entry(port, &rio_mports, node) { - if (port->host_deviceid >= 0) - rio_enum_mport(port); - else + if (port->host_deviceid >= 0) { + if (port->nscan) + port->nscan->enumerate(port, 0); + } else n++; } + mutex_unlock(&rio_mport_list_lock); if (!n) goto no_disc; @@ -1322,14 +1550,16 @@ int rio_init_mports(void) } n = 0; + mutex_lock(&rio_mport_list_lock); list_for_each_entry(port, &rio_mports, node) { - if (port->host_deviceid < 0) { + if (port->host_deviceid < 0 && port->nscan) { work[n].mport = port; INIT_WORK(&work[n].work, disc_work_handler); queue_work(rio_wq, &work[n].work); n++; } } + mutex_unlock(&rio_mport_list_lock); flush_workqueue(rio_wq); pr_debug("RIO: destroy discovery workqueue\n"); @@ -1342,8 +1572,6 @@ no_disc: return 0; } -device_initcall_sync(rio_init_mports); - static int hdids[RIO_MAX_MPORTS + 1]; static int rio_get_hdid(int index) @@ -1371,7 +1599,10 @@ int rio_register_mport(struct rio_mport *port) port->id = next_portid++; port->host_deviceid = rio_get_hdid(port->id); + port->nscan = NULL; + mutex_lock(&rio_mport_list_lock); list_add_tail(&port->node, &rio_mports); + mutex_unlock(&rio_mport_list_lock); return 0; } @@ -1386,3 +1617,4 @@ EXPORT_SYMBOL_GPL(rio_request_inb_mbox); EXPORT_SYMBOL_GPL(rio_release_inb_mbox); EXPORT_SYMBOL_GPL(rio_request_outb_mbox); EXPORT_SYMBOL_GPL(rio_release_outb_mbox); +EXPORT_SYMBOL_GPL(rio_init_mports); diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index b1af414f15e6..c14f864dea5c 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h @@ -15,6 +15,7 @@ #include <linux/rio.h> #define RIO_MAX_CHK_RETRY 3 +#define RIO_MPORT_ANY (-1) /* Functions internal to the RIO core code */ @@ -27,8 +28,6 @@ extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount); extern int rio_create_sysfs_dev_files(struct rio_dev *rdev); -extern int rio_enum_mport(struct rio_mport *mport); -extern int rio_disc_mport(struct rio_mport *mport); extern int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 route_port); @@ -39,10 +38,18 @@ extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table); extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock); extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from); +extern int rio_add_device(struct rio_dev *rdev); +extern void rio_switch_init(struct rio_dev *rdev, int do_enum); +extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid, + u8 hopcount, u8 port_num); +extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops); +extern int rio_unregister_scan(int mport_id); +extern void rio_attach_device(struct rio_dev *rdev); +extern struct rio_mport *rio_find_mport(int mport_id); /* Structures internal to the RIO core code */ extern struct device_attribute rio_dev_attrs[]; -extern spinlock_t rio_global_list_lock; +extern struct bus_attribute rio_bus_attrs[]; extern struct rio_switch_ops __start_rio_switch_ops[]; extern struct rio_switch_ops __end_rio_switch_ops[]; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6e5017841582..815d6df8bd5f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1539,7 +1539,10 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev) } /** - * Balance enable_count of each GPIO and actual GPIO pin control. + * regulator_ena_gpio_ctrl - balance enable_count of each GPIO and actual GPIO pin control + * @rdev: regulator_dev structure + * @enable: enable GPIO at initial use? + * * GPIO is enabled in case of initial use. (enable_count is 0) * GPIO is disabled when it is not shared any more. (enable_count <= 1) */ @@ -2702,7 +2705,7 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage); /** * regulator_set_current_limit - set regulator output current limit * @regulator: regulator source - * @min_uA: Minimuum supported current in uA + * @min_uA: Minimum supported current in uA * @max_uA: Maximum supported current in uA * * Sets current sink to the desired output current. This can be set during diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index 89bd2faaef8c..ce89f7848a57 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -24,18 +24,6 @@ static int power_state_active_cnt; /* will initialize to zero */ static DEFINE_SPINLOCK(power_state_active_lock); -int power_state_active_get(void) -{ - unsigned long flags; - int cnt; - - spin_lock_irqsave(&power_state_active_lock, flags); - cnt = power_state_active_cnt; - spin_unlock_irqrestore(&power_state_active_lock, flags); - - return cnt; -} - void power_state_active_enable(void) { unsigned long flags; @@ -65,6 +53,18 @@ out: #ifdef CONFIG_REGULATOR_DEBUG +static int power_state_active_get(void) +{ + unsigned long flags; + int cnt; + + spin_lock_irqsave(&power_state_active_lock, flags); + cnt = power_state_active_cnt; + spin_unlock_irqrestore(&power_state_active_lock, flags); + + return cnt; +} + static struct ux500_regulator_debug { struct dentry *dir; struct dentry *status_file; diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 92ceed0fc65e..3ae44ac12a94 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -840,7 +840,7 @@ static int palmas_regulators_probe(struct platform_device *pdev) break; } - if ((id == PALMAS_REG_SMPS6) && (id == PALMAS_REG_SMPS8)) + if ((id == PALMAS_REG_SMPS6) || (id == PALMAS_REG_SMPS8)) ramp_delay_support = true; if (ramp_delay_support) { @@ -878,7 +878,7 @@ static int palmas_regulators_probe(struct platform_device *pdev) pmic->desc[id].vsel_mask = SMPS10_VSEL; pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE, - PALMAS_SMPS10_STATUS); + PALMAS_SMPS10_CTRL); pmic->desc[id].enable_mask = SMPS10_BOOST_EN; pmic->desc[id].min_uV = 3750000; pmic->desc[id].uV_step = 1250000; diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 0eab77b22340..f296f3f7db9b 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -25,6 +25,7 @@ #include <linux/rtc.h> #include <linux/bcd.h> #include <linux/interrupt.h> +#include <linux/spinlock.h> #include <linux/ioctl.h> #include <linux/completion.h> #include <linux/io.h> @@ -42,10 +43,65 @@ #define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */ +struct at91_rtc_config { + bool use_shadow_imr; +}; + +static const struct at91_rtc_config *at91_rtc_config; static DECLARE_COMPLETION(at91_rtc_updated); static unsigned int at91_alarm_year = AT91_RTC_EPOCH; static void __iomem *at91_rtc_regs; static int irq; +static DEFINE_SPINLOCK(at91_rtc_lock); +static u32 at91_rtc_shadow_imr; + +static void at91_rtc_write_ier(u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&at91_rtc_lock, flags); + at91_rtc_shadow_imr |= mask; + at91_rtc_write(AT91_RTC_IER, mask); + spin_unlock_irqrestore(&at91_rtc_lock, flags); +} + +static void at91_rtc_write_idr(u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&at91_rtc_lock, flags); + at91_rtc_write(AT91_RTC_IDR, mask); + /* + * Register read back (of any RTC-register) needed to make sure + * IDR-register write has reached the peripheral before updating + * shadow mask. + * + * Note that there is still a possibility that the mask is updated + * before interrupts have actually been disabled in hardware. The only + * way to be certain would be to poll the IMR-register, which is is + * the very register we are trying to emulate. The register read back + * is a reasonable heuristic. + */ + at91_rtc_read(AT91_RTC_SR); + at91_rtc_shadow_imr &= ~mask; + spin_unlock_irqrestore(&at91_rtc_lock, flags); +} + +static u32 at91_rtc_read_imr(void) +{ + unsigned long flags; + u32 mask; + + if (at91_rtc_config->use_shadow_imr) { + spin_lock_irqsave(&at91_rtc_lock, flags); + mask = at91_rtc_shadow_imr; + spin_unlock_irqrestore(&at91_rtc_lock, flags); + } else { + mask = at91_rtc_read(AT91_RTC_IMR); + } + + return mask; +} /* * Decode time/date into rtc_time structure @@ -110,9 +166,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) cr = at91_rtc_read(AT91_RTC_CR); at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM); - at91_rtc_write(AT91_RTC_IER, AT91_RTC_ACKUPD); + at91_rtc_write_ier(AT91_RTC_ACKUPD); wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */ - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD); + at91_rtc_write_idr(AT91_RTC_ACKUPD); at91_rtc_write(AT91_RTC_TIMR, bin2bcd(tm->tm_sec) << 0 @@ -144,7 +200,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_year = at91_alarm_year - 1900; - alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM) + alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM) ? 1 : 0; dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, @@ -169,7 +225,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) tm.tm_min = alrm->time.tm_min; tm.tm_sec = alrm->time.tm_sec; - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM); + at91_rtc_write_idr(AT91_RTC_ALARM); at91_rtc_write(AT91_RTC_TIMALR, bin2bcd(tm.tm_sec) << 0 | bin2bcd(tm.tm_min) << 8 @@ -182,7 +238,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alrm->enabled) { at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM); - at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM); + at91_rtc_write_ier(AT91_RTC_ALARM); } dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, @@ -198,9 +254,9 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) if (enabled) { at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM); - at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM); + at91_rtc_write_ier(AT91_RTC_ALARM); } else - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM); + at91_rtc_write_idr(AT91_RTC_ALARM); return 0; } @@ -209,7 +265,7 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) */ static int at91_rtc_proc(struct device *dev, struct seq_file *seq) { - unsigned long imr = at91_rtc_read(AT91_RTC_IMR); + unsigned long imr = at91_rtc_read_imr(); seq_printf(seq, "update_IRQ\t: %s\n", (imr & AT91_RTC_ACKUPD) ? "yes" : "no"); @@ -229,7 +285,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) unsigned int rtsr; unsigned long events = 0; - rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read(AT91_RTC_IMR); + rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read_imr(); if (rtsr) { /* this interrupt is shared! Is it ours? */ if (rtsr & AT91_RTC_ALARM) events |= (RTC_AF | RTC_IRQF); @@ -250,6 +306,43 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id) return IRQ_NONE; /* not handled */ } +static const struct at91_rtc_config at91rm9200_config = { +}; + +static const struct at91_rtc_config at91sam9x5_config = { + .use_shadow_imr = true, +}; + +#ifdef CONFIG_OF +static const struct of_device_id at91_rtc_dt_ids[] = { + { + .compatible = "atmel,at91rm9200-rtc", + .data = &at91rm9200_config, + }, { + .compatible = "atmel,at91sam9x5-rtc", + .data = &at91sam9x5_config, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); +#endif + +static const struct at91_rtc_config * +at91_rtc_get_config(struct platform_device *pdev) +{ + const struct of_device_id *match; + + if (pdev->dev.of_node) { + match = of_match_node(at91_rtc_dt_ids, pdev->dev.of_node); + if (!match) + return NULL; + return (const struct at91_rtc_config *)match->data; + } + + return &at91rm9200_config; +} + static const struct rtc_class_ops at91_rtc_ops = { .read_time = at91_rtc_readtime, .set_time = at91_rtc_settime, @@ -268,6 +361,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev) struct resource *regs; int ret = 0; + at91_rtc_config = at91_rtc_get_config(pdev); + if (!at91_rtc_config) + return -ENODEV; + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { dev_err(&pdev->dev, "no mmio resource defined\n"); @@ -290,7 +387,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) at91_rtc_write(AT91_RTC_MR, 0); /* 24 hour mode */ /* Disable all interrupts */ - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM | + at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM | AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); @@ -335,7 +432,7 @@ static int __exit at91_rtc_remove(struct platform_device *pdev) struct rtc_device *rtc = platform_get_drvdata(pdev); /* Disable all interrupts */ - at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM | + at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM | AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); free_irq(irq, pdev); @@ -358,13 +455,13 @@ static int at91_rtc_suspend(struct device *dev) /* this IRQ is shared with DBGU and other hardware which isn't * necessarily doing PM like we are... */ - at91_rtc_imr = at91_rtc_read(AT91_RTC_IMR) + at91_rtc_imr = at91_rtc_read_imr() & (AT91_RTC_ALARM|AT91_RTC_SECEV); if (at91_rtc_imr) { if (device_may_wakeup(dev)) enable_irq_wake(irq); else - at91_rtc_write(AT91_RTC_IDR, at91_rtc_imr); + at91_rtc_write_idr(at91_rtc_imr); } return 0; } @@ -375,7 +472,7 @@ static int at91_rtc_resume(struct device *dev) if (device_may_wakeup(dev)) disable_irq_wake(irq); else - at91_rtc_write(AT91_RTC_IER, at91_rtc_imr); + at91_rtc_write_ier(at91_rtc_imr); } return 0; } @@ -383,12 +480,6 @@ static int at91_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); -static const struct of_device_id at91_rtc_dt_ids[] = { - { .compatible = "atmel,at91rm9200-rtc" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); - static struct platform_driver at91_rtc_driver = { .remove = __exit_p(at91_rtc_remove), .driver = { diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index cc5bea9c4b1c..f1cb706445c7 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -854,6 +854,9 @@ static int cmos_resume(struct device *dev) } spin_lock_irq(&rtc_lock); + if (device_may_wakeup(dev)) + hpet_rtc_timer_init(); + do { CMOS_WRITE(tmp, RTC_CONTROL); hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK); @@ -869,7 +872,6 @@ static int cmos_resume(struct device *dev) rtc_update_irq(cmos->rtc, 1, mask); tmp &= ~RTC_AIE; hpet_mask_rtc_irq_bit(RTC_AIE); - hpet_rtc_timer_init(); } while (mask & RTC_AIE); spin_unlock_irq(&rtc_lock); } diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index 48b6612fae7f..d5af7baa48b5 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -285,7 +285,7 @@ static int max8998_rtc_probe(struct platform_device *pdev) info->irq, ret); dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name); - if (pdata->rtc_delay) { + if (pdata && pdata->rtc_delay) { info->lp3974_bug_workaround = true; dev_warn(&pdev->dev, "LP3974 with RTC REGERR option." " RTC updates will be extremely slow.\n"); diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 8900ea784817..0f0609b1aa2c 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -306,7 +306,7 @@ static int pl031_remove(struct amba_device *adev) struct pl031_local *ldata = dev_get_drvdata(&adev->dev); amba_set_drvdata(adev, NULL); - free_irq(adev->irq[0], ldata->rtc); + free_irq(adev->irq[0], ldata); rtc_device_unregister(ldata->rtc); iounmap(ldata->base); kfree(ldata); diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 459c2ffc95a6..426901cef14f 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -273,6 +273,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) return ret; } + device_init_wakeup(&pdev->dev, 1); + platform_set_drvdata(pdev, rtc); rtc->rtc = devm_rtc_device_register(&pdev->dev, dev_name(&pdev->dev), &tps6586x_rtc_ops, THIS_MODULE); @@ -292,7 +294,6 @@ static int tps6586x_rtc_probe(struct platform_device *pdev) goto fail_rtc_register; } disable_irq(rtc->irq); - device_set_wakeup_capable(&pdev->dev, 1); return 0; fail_rtc_register: diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 8751a5240c99..b2eab34f38d9 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -524,6 +524,7 @@ static int twl_rtc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, rtc); + device_init_wakeup(&pdev->dev, 1); return 0; out2: diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4361d9772c42..d72a9216ee2e 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -3440,8 +3440,16 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) device->path_data.opm &= ~eventlpm; device->path_data.ppm &= ~eventlpm; device->path_data.npm &= ~eventlpm; - if (oldopm && !device->path_data.opm) - dasd_generic_last_path_gone(device); + if (oldopm && !device->path_data.opm) { + dev_warn(&device->cdev->dev, + "No verified channel paths remain " + "for the device\n"); + DBF_DEV_EVENT(DBF_WARNING, device, + "%s", "last verified path gone"); + dasd_eer_write(device, NULL, DASD_EER_NOPATH); + dasd_device_set_stop_bits(device, + DASD_STOPPED_DC_WAIT); + } } if (path_event[chp] & PE_PATH_AVAILABLE) { device->path_data.opm &= ~eventlpm; diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 690c3338a8ae..464dd29d06c0 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -343,6 +343,7 @@ static int __init xpram_setup_blkdev(void) put_disk(xpram_disks[i]); goto out; } + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, xpram_queues[i]); blk_queue_make_request(xpram_queues[i], xpram_make_request); blk_queue_logical_block_size(xpram_queues[i], 4096); } diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 21fabc6d5a9c..6c440d4349d4 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -352,12 +352,48 @@ static ssize_t chp_shared_show(struct device *dev, static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); +static ssize_t chp_chid_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct channel_path *chp = to_channelpath(dev); + ssize_t rc; + + mutex_lock(&chp->lock); + if (chp->desc_fmt1.flags & 0x10) + rc = sprintf(buf, "%04x\n", chp->desc_fmt1.chid); + else + rc = 0; + mutex_unlock(&chp->lock); + + return rc; +} +static DEVICE_ATTR(chid, 0444, chp_chid_show, NULL); + +static ssize_t chp_chid_external_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct channel_path *chp = to_channelpath(dev); + ssize_t rc; + + mutex_lock(&chp->lock); + if (chp->desc_fmt1.flags & 0x10) + rc = sprintf(buf, "%x\n", chp->desc_fmt1.flags & 0x8 ? 1 : 0); + else + rc = 0; + mutex_unlock(&chp->lock); + + return rc; +} +static DEVICE_ATTR(chid_external, 0444, chp_chid_external_show, NULL); + static struct attribute *chp_attrs[] = { &dev_attr_status.attr, &dev_attr_configure.attr, &dev_attr_type.attr, &dev_attr_cmg.attr, &dev_attr_shared.attr, + &dev_attr_chid.attr, + &dev_attr_chid_external.attr, NULL, }; static struct attribute_group chp_attr_group = { diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 349d5fc47196..e7ef2a683b8f 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -43,7 +43,9 @@ struct channel_path_desc_fmt1 { u8 chpid; u32:24; u8 chpp; - u32 unused[3]; + u32 unused[2]; + u16 chid; + u32:16; u16 mdc; u16:13; u8 r:1; diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 4ffa66c87ea5..9ca3996f65b2 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -2040,6 +2040,7 @@ static struct net_device *netiucv_init_netdevice(char *username, char *userdata) netiucv_setup_netdevice); if (!dev) return NULL; + rtnl_lock(); if (dev_alloc_name(dev, dev->name) < 0) goto out_netdev; @@ -2061,6 +2062,7 @@ static struct net_device *netiucv_init_netdevice(char *username, char *userdata) out_fsm: kfree_fsm(privptr->fsm); out_netdev: + rtnl_unlock(); free_netdev(dev); return NULL; } @@ -2100,6 +2102,7 @@ static ssize_t conn_write(struct device_driver *drv, rc = netiucv_register_device(dev); if (rc) { + rtnl_unlock(); IUCV_DBF_TEXT_(setup, 2, "ret %d from netiucv_register_device\n", rc); goto out_free_ndev; @@ -2109,7 +2112,8 @@ static ssize_t conn_write(struct device_driver *drv, priv = netdev_priv(dev); SET_NETDEV_DEV(dev, priv->dev); - rc = register_netdev(dev); + rc = register_netdevice(dev); + rtnl_unlock(); if (rc) goto out_unreg; diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c index 439c012be763..b63d534192e3 100644 --- a/drivers/scsi/bfa/bfad_debugfs.c +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -186,7 +186,7 @@ bfad_debugfs_lseek(struct file *file, loff_t offset, int orig) file->f_pos += offset; break; case 2: - file->f_pos = debug->buffer_len - offset; + file->f_pos = debug->buffer_len + offset; break; default: return -EINVAL; diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c index adc1f7f471f5..85e1ffd0e5c5 100644 --- a/drivers/scsi/fnic/fnic_debugfs.c +++ b/drivers/scsi/fnic/fnic_debugfs.c @@ -174,7 +174,7 @@ static loff_t fnic_trace_debugfs_lseek(struct file *file, pos = file->f_pos + offset; break; case 2: - pos = fnic_dbg_prt->buffer_len - offset; + pos = fnic_dbg_prt->buffer_len + offset; } return (pos < 0 || pos > fnic_dbg_prt->buffer_len) ? -EINVAL : (file->f_pos = pos); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index f63f5ff7f274..f525ecb7a9c6 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1178,7 +1178,7 @@ lpfc_debugfs_lseek(struct file *file, loff_t off, int whence) pos = file->f_pos + off; break; case 2: - pos = debug->len - off; + pos = debug->len + off; } return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos); } diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index d182c96e17ea..66b0b26a1381 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -688,8 +688,12 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd) * For FCP_READ with CHECK_CONDITION status, clear cmd->bufflen * for qla_tgt_xmit_response LLD code */ + if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { + se_cmd->se_cmd_flags &= ~SCF_OVERFLOW_BIT; + se_cmd->residual_count = 0; + } se_cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; - se_cmd->residual_count = se_cmd->data_length; + se_cmd->residual_count += se_cmd->data_length; cmd->bufflen = 0; } @@ -1370,7 +1374,7 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) dump_stack(); return; } - target_wait_for_sess_cmds(se_sess, 0); + target_wait_for_sess_cmds(se_sess); transport_deregister_session_configfs(sess->se_sess); transport_deregister_session(sess->se_sess); diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index db66357211ed..86f0c5d5c116 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -84,6 +84,7 @@ static int proc_scsi_host_open(struct inode *inode, struct file *file) static const struct file_operations proc_scsi_fops = { .open = proc_scsi_host_open, + .release = single_release, .read = seq_read, .llseek = seq_lseek, .write = proc_scsi_host_write diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index c735c5a008a2..6427600b5bbe 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -59,7 +59,7 @@ static int pxa2xx_spi_map_dma_buffer(struct driver_data *drv_data, int ret; sg_free_table(sgt); - ret = sg_alloc_table(sgt, nents, GFP_KERNEL); + ret = sg_alloc_table(sgt, nents, GFP_ATOMIC); if (ret) return ret; } diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index f5d84d6f8222..48b396fced0a 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1075,7 +1075,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev)) return NULL; - pdata = devm_kzalloc(&pdev->dev, sizeof(*ssp), GFP_KERNEL); + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { dev_err(&pdev->dev, "failed to allocate memory for platform data\n"); diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 5000586cb98d..71cc3e6ef47c 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -444,7 +444,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) } ret = pm_runtime_get_sync(&sdd->pdev->dev); - if (ret != 0) { + if (ret < 0) { dev_err(dev, "Failed to enable device: %d\n", ret); goto out_tx; } diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 60cfae51c713..eab593eaaafa 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -89,7 +89,7 @@ static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val) if ((mask & hspi_read(hspi, SPSR)) == val) return 0; - msleep(20); + udelay(10); } dev_err(hspi->dev, "timeout\n"); diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 35f60bd252dd..637d728fbeb5 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1487,7 +1487,7 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev) return 0; err_spi_register_master: - free_irq(board_dat->pdev->irq, board_dat); + free_irq(board_dat->pdev->irq, data); err_request_irq: pch_spi_free_resources(board_dat, data); err_spi_get_resources: @@ -1667,6 +1667,7 @@ static int pch_spi_probe(struct pci_dev *pdev, pd_dev = platform_device_alloc("pch-spi", i); if (!pd_dev) { dev_err(&pdev->dev, "platform_device_alloc failed\n"); + retval = -ENOMEM; goto err_platform_device; } pd_dev_save->pd_save[i] = pd_dev; diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index e1d769607425..34d18dcfa0db 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -267,7 +267,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) { struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); u32 ipif_ier; - u16 cr; /* We get here with transmitter inhibited */ @@ -276,7 +275,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xspi->remaining_bytes = t->len; INIT_COMPLETION(xspi->done); - xilinx_spi_fill_tx_fifo(xspi); /* Enable the transmit empty interrupt, which we use to determine * progress on the transmission. @@ -285,12 +283,41 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY, xspi->regs + XIPIF_V123B_IIER_OFFSET); - /* Start the transfer by not inhibiting the transmitter any longer */ - cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & - ~XSPI_CR_TRANS_INHIBIT; - xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); + for (;;) { + u16 cr; + u8 sr; + + xilinx_spi_fill_tx_fifo(xspi); + + /* Start the transfer by not inhibiting the transmitter any + * longer + */ + cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & + ~XSPI_CR_TRANS_INHIBIT; + xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); + + wait_for_completion(&xspi->done); + + /* A transmit has just completed. Process received data and + * check for more data to transmit. Always inhibit the + * transmitter while the Isr refills the transmit register/FIFO, + * or make sure it is stopped if we're done. + */ + cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); + xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, + xspi->regs + XSPI_CR_OFFSET); + + /* Read out all the data from the Rx FIFO */ + sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); + while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) { + xspi->rx_fn(xspi); + sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); + } - wait_for_completion(&xspi->done); + /* See if there is more data to send */ + if (!xspi->remaining_bytes > 0) + break; + } /* Disable the transmit empty interrupt */ xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET); @@ -314,38 +341,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET); if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */ - u16 cr; - u8 sr; - - /* A transmit has just completed. Process received data and - * check for more data to transmit. Always inhibit the - * transmitter while the Isr refills the transmit register/FIFO, - * or make sure it is stopped if we're done. - */ - cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); - xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, - xspi->regs + XSPI_CR_OFFSET); - - /* Read out all the data from the Rx FIFO */ - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) { - xspi->rx_fn(xspi); - sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); - } - - /* See if there is more data to send */ - if (xspi->remaining_bytes > 0) { - xilinx_spi_fill_tx_fifo(xspi); - /* Start the transfer by not inhibiting the - * transmitter any longer - */ - xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); - } else { - /* No more data to send. - * Indicate the transfer is completed. - */ - complete(&xspi->done); - } + complete(&xspi->done); } return IRQ_HANDLED; diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 4e8a1794f50a..aefe820a8005 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -72,10 +72,10 @@ source "drivers/staging/sep/Kconfig" source "drivers/staging/iio/Kconfig" -source "drivers/staging/zram/Kconfig" - source "drivers/staging/zsmalloc/Kconfig" +source "drivers/staging/zram/Kconfig" + source "drivers/staging/wlags49_h2/Kconfig" source "drivers/staging/wlags49_h25/Kconfig" diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c index ceb1c643753d..6dc27dac679d 100644 --- a/drivers/staging/android/alarm-dev.c +++ b/drivers/staging/android/alarm-dev.c @@ -264,6 +264,8 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } rv = alarm_do_ioctl(file, cmd, &ts); + if (rv) + return rv; switch (ANDROID_ALARM_BASE_CMD(cmd)) { case ANDROID_ALARM_GET_TIME(0): @@ -272,7 +274,7 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } - return rv; + return 0; } #ifdef CONFIG_COMPAT static long alarm_compat_ioctl(struct file *file, unsigned int cmd, @@ -295,6 +297,8 @@ static long alarm_compat_ioctl(struct file *file, unsigned int cmd, } rv = alarm_do_ioctl(file, cmd, &ts); + if (rv) + return rv; switch (ANDROID_ALARM_BASE_CMD(cmd)) { case ANDROID_ALARM_GET_TIME(0): /* NOTE: we modified cmd above */ @@ -303,7 +307,7 @@ static long alarm_compat_ioctl(struct file *file, unsigned int cmd, break; } - return rv; + return 0; } #endif diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c index b040200a5a55..9bd874789ce5 100644 --- a/drivers/staging/android/logger.c +++ b/drivers/staging/android/logger.c @@ -242,7 +242,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log, * 'log->buffer' which contains the first entry readable by 'euid' */ static size_t get_next_entry_by_uid(struct logger_log *log, - size_t off, uid_t euid) + size_t off, kuid_t euid) { while (off != log->w_off) { struct logger_entry *entry; @@ -251,7 +251,7 @@ static size_t get_next_entry_by_uid(struct logger_log *log, entry = get_entry_header(log, off, &scratch); - if (entry->euid == euid) + if (uid_eq(entry->euid, euid)) return off; next_len = sizeof(struct logger_entry) + entry->len; diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h index cc6bbd99c8e0..70af7d805dff 100644 --- a/drivers/staging/android/logger.h +++ b/drivers/staging/android/logger.h @@ -66,7 +66,7 @@ struct logger_entry { __s32 tid; __s32 sec; __s32 nsec; - uid_t euid; + kuid_t euid; char msg[0]; }; diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 7871579bb83d..87e852a0ef49 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -981,6 +981,7 @@ config COMEDI_ME_DAQ config COMEDI_NI_6527 tristate "NI 6527 support" + depends on HAS_DMA select COMEDI_MITE ---help--- Enable support for the National Instruments 6527 PCI card @@ -990,6 +991,7 @@ config COMEDI_NI_6527 config COMEDI_NI_65XX tristate "NI 65xx static dio PCI card support" + depends on HAS_DMA select COMEDI_MITE ---help--- Enable support for National Instruments 65xx static dio boards. @@ -1003,6 +1005,7 @@ config COMEDI_NI_65XX config COMEDI_NI_660X tristate "NI 660x counter/timer PCI card support" + depends on HAS_DMA select COMEDI_NI_TIOCMD ---help--- Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602, @@ -1013,6 +1016,7 @@ config COMEDI_NI_660X config COMEDI_NI_670X tristate "NI 670x PCI card support" + depends on HAS_DMA select COMEDI_MITE ---help--- Enable support for National Instruments PCI-6703 and PCI-6704 @@ -1022,6 +1026,7 @@ config COMEDI_NI_670X config COMEDI_NI_LABPC_PCI tristate "NI Lab-PC PCI-1200 support" + depends on HAS_DMA select COMEDI_NI_LABPC select COMEDI_MITE ---help--- @@ -1032,6 +1037,7 @@ config COMEDI_NI_LABPC_PCI config COMEDI_NI_PCIDIO tristate "NI PCI-DIO32HS, PCI-6533, PCI-6534 support" + depends on HAS_DMA select COMEDI_MITE select COMEDI_8255 ---help--- @@ -1043,6 +1049,7 @@ config COMEDI_NI_PCIDIO config COMEDI_NI_PCIMIO tristate "NI PCI-MIO-E series and M series support" + depends on HAS_DMA select COMEDI_NI_TIOCMD select COMEDI_8255 select COMEDI_FC @@ -1095,10 +1102,12 @@ config COMEDI_SSV_DNP called ssv_dnp. config COMEDI_MITE + depends on HAS_DMA tristate config COMEDI_NI_TIOCMD tristate + depends on HAS_DMA select COMEDI_NI_TIO select COMEDI_MITE diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index ca709901fb3e..d4be0e68509b 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -51,10 +51,12 @@ static void __comedi_buf_free(struct comedi_device *dev, clear_bit(PG_reserved, &(virt_to_page(buf->virt_addr)->flags)); if (s->async_dma_dir != DMA_NONE) { +#ifdef CONFIG_HAS_DMA dma_free_coherent(dev->hw_dev, PAGE_SIZE, buf->virt_addr, buf->dma_addr); +#endif } else { free_page((unsigned long)buf->virt_addr); } @@ -74,6 +76,12 @@ static void __comedi_buf_alloc(struct comedi_device *dev, struct comedi_buf_page *buf; unsigned i; + if (!IS_ENABLED(CONFIG_HAS_DMA) && s->async_dma_dir != DMA_NONE) { + dev_err(dev->class_dev, + "dma buffer allocation not supported\n"); + return; + } + async->buf_page_list = vzalloc(sizeof(*buf) * n_pages); if (async->buf_page_list) pages = vmalloc(sizeof(struct page *) * n_pages); @@ -84,11 +92,15 @@ static void __comedi_buf_alloc(struct comedi_device *dev, for (i = 0; i < n_pages; i++) { buf = &async->buf_page_list[i]; if (s->async_dma_dir != DMA_NONE) +#ifdef CONFIG_HAS_DMA buf->virt_addr = dma_alloc_coherent(dev->hw_dev, PAGE_SIZE, &buf->dma_addr, GFP_KERNEL | __GFP_COMP); +#else + break; +#endif else buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL); if (!buf->virt_addr) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 00f2547024ec..924c54c9c31f 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -246,9 +246,6 @@ static int resize_async_buffer(struct comedi_device *dev, return -EBUSY; } - if (!async->prealloc_buf) - return -EINVAL; - /* make sure buffer is an integral number of pages * (we round up) */ new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 3d978f34d212..77a7bb632580 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -976,8 +976,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* clear flip-flop to make sure 2-byte registers for * count and address get set correctly */ clear_dma_ff(devpriv->dma_chan); - set_dma_addr(devpriv->dma_chan, - virt_to_bus(devpriv->dma_buffer)); + set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); /* set appropriate size of transfer */ devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd); if (cmd->stop_src == TRIG_COUNT && @@ -1089,7 +1088,7 @@ static void labpc_drain_dma(struct comedi_device *dev) devpriv->count -= num_points; /* set address and count for next transfer */ - set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer)); + set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); set_dma_count(devpriv->dma_chan, leftover * sample_size); release_dma_lock(flags); @@ -1741,6 +1740,9 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) unsigned long dma_flags; devpriv->dma_chan = dma_chan; + devpriv->dma_addr = + virt_to_bus(devpriv->dma_buffer); + dma_flags = claim_dma_lock(); disable_dma(devpriv->dma_chan); set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h index 615f16f271c0..4b691f5a9965 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.h +++ b/drivers/staging/comedi/drivers/ni_labpc.h @@ -82,6 +82,7 @@ struct labpc_private { unsigned int divisor_b1; unsigned int dma_chan; /* dma channel to use */ u16 *dma_buffer; /* buffer ai will dma into */ + phys_addr_t dma_addr; /* transfer size in bytes for current transfer */ unsigned int dma_transfer_size; /* we are using dma/fifo-half-full/etc. */ diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index a46d579016d9..8c5dee9b3b05 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -310,9 +310,11 @@ static int ni_gpct_insn_read(struct comedi_device *dev, static int ni_gpct_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); +#ifdef PCIDMA static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s); static int ni_gpct_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); +#endif static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static void handle_gpct_interrupt(struct comedi_device *dev, @@ -4617,9 +4619,7 @@ static int ni_E_init(struct comedi_device *dev) for (j = 0; j < NUM_GPCT; ++j) { s = &dev->subdevices[NI_GPCT_SUBDEV(j)]; s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = - SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_CMD_READ - /* | SDF_CMD_WRITE */ ; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; s->n_chan = 3; if (board->reg_type & ni_reg_m_series_mask) s->maxdata = 0xffffffff; @@ -4628,11 +4628,14 @@ static int ni_E_init(struct comedi_device *dev) s->insn_read = &ni_gpct_insn_read; s->insn_write = &ni_gpct_insn_write; s->insn_config = &ni_gpct_insn_config; +#ifdef PCIDMA + s->subdev_flags |= SDF_CMD_READ /* | SDF_CMD_WRITE */; s->do_cmd = &ni_gpct_cmd; s->len_chanlist = 1; s->do_cmdtest = &ni_gpct_cmdtest; s->cancel = &ni_gpct_cancel; s->async_dma_dir = DMA_BIDIRECTIONAL; +#endif s->private = &devpriv->counter_dev->counters[j]; devpriv->counter_dev->counters[j].chip_index = 0; @@ -5216,10 +5219,10 @@ static int ni_gpct_insn_write(struct comedi_device *dev, return ni_tio_winsn(counter, insn, data); } +#ifdef PCIDMA static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { int retval; -#ifdef PCIDMA struct ni_gpct *counter = s->private; /* const struct comedi_cmd *cmd = &s->async->cmd; */ @@ -5233,23 +5236,20 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL); ni_e_series_enable_second_irq(dev, counter->counter_index, 1); retval = ni_tio_cmd(counter, s->async); -#else - retval = -ENOTSUPP; -#endif return retval; } +#endif +#ifdef PCIDMA static int ni_gpct_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { -#ifdef PCIDMA struct ni_gpct *counter = s->private; return ni_tio_cmdtest(counter, cmd); -#else return -ENOTSUPP; -#endif } +#endif static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { diff --git a/drivers/staging/dwc2/Kconfig b/drivers/staging/dwc2/Kconfig index f0b4739c65a1..d15d9d58e5ac 100644 --- a/drivers/staging/dwc2/Kconfig +++ b/drivers/staging/dwc2/Kconfig @@ -2,7 +2,6 @@ config USB_DWC2 tristate "DesignWare USB2 DRD Core Support" depends on USB depends on VIRT_TO_BUS - select USB_OTG_UTILS help Say Y or M here if your system has a Dual Role HighSpeed USB controller based on the DesignWare HSOTG IP Core. @@ -39,6 +38,7 @@ config USB_DWC2_TRACK_MISSED_SOFS bool "Enable Missed SOF Tracking" help Say Y here to enable logging of missed SOF events to the dmesg log. + WARNING: This feature is still experimental. If in doubt, say N. config USB_DWC2_DEBUG_PERIODIC diff --git a/drivers/staging/dwc2/hcd.c b/drivers/staging/dwc2/hcd.c index 827ab781ae9b..8551ccedf037 100644 --- a/drivers/staging/dwc2/hcd.c +++ b/drivers/staging/dwc2/hcd.c @@ -2804,9 +2804,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq, /* Set device flags indicating whether the HCD supports DMA */ if (hsotg->core_params->dma_enable > 0) { - if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(31)) < 0) - dev_warn(hsotg->dev, - "can't enable workaround for >2GB RAM\n"); + if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0) + dev_warn(hsotg->dev, "can't set DMA mask\n"); if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(31)) < 0) dev_warn(hsotg->dev, "can't enable workaround for >2GB RAM\n"); diff --git a/drivers/staging/dwc2/hcd_intr.c b/drivers/staging/dwc2/hcd_intr.c index 6e5dbed6ccec..e24062f0a49e 100644 --- a/drivers/staging/dwc2/hcd_intr.c +++ b/drivers/staging/dwc2/hcd_intr.c @@ -56,8 +56,6 @@ static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg) { #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS -#warning Compiling code to track missed SOFs - u16 curr_frame_number = hsotg->frame_number; if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) { diff --git a/drivers/staging/dwc2/platform.c b/drivers/staging/dwc2/platform.c index b610960e93d3..44cce2fa6361 100644 --- a/drivers/staging/dwc2/platform.c +++ b/drivers/staging/dwc2/platform.c @@ -95,6 +95,14 @@ static int dwc2_driver_probe(struct platform_device *dev) hsotg->dev = &dev->dev; + /* + * Use reasonable defaults so platforms don't have to provide these. + */ + if (!dev->dev.dma_mask) + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; + if (!dev->dev.coherent_dma_mask) + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + irq = platform_get_irq(dev, 0); if (irq < 0) { dev_err(&dev->dev, "missing IRQ resource\n"); diff --git a/drivers/staging/gdm72xx/Kconfig b/drivers/staging/gdm72xx/Kconfig index 3c18efe31365..69059138de4a 100644 --- a/drivers/staging/gdm72xx/Kconfig +++ b/drivers/staging/gdm72xx/Kconfig @@ -39,7 +39,7 @@ if WIMAX_GDM72XX_USB config WIMAX_GDM72XX_USB_PM bool "Enable power managerment support" - depends on USB_SUSPEND + depends on PM_RUNTIME endif # WIMAX_GDM72XX_USB diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 2856b8fd44ad..163c638e4095 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -690,7 +690,6 @@ static void mxs_lradc_trigger_remove(struct iio_dev *iio) static int mxs_lradc_buffer_preenable(struct iio_dev *iio) { struct mxs_lradc *lradc = iio_priv(iio); - struct iio_buffer *buffer = iio->buffer; int ret = 0, chan, ofs = 0; unsigned long enable = 0; uint32_t ctrl4_set = 0; @@ -698,7 +697,7 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) uint32_t ctrl1_irq = 0; const uint32_t chan_value = LRADC_CH_ACCUMULATE | ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); - const int len = bitmap_weight(buffer->scan_mask, LRADC_MAX_TOTAL_CHANS); + const int len = bitmap_weight(iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS); if (!len) return -EINVAL; @@ -725,7 +724,7 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio) lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); - for_each_set_bit(chan, buffer->scan_mask, LRADC_MAX_TOTAL_CHANS) { + for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) { ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs); ctrl4_clr |= LRADC_CTRL4_LRADCSELECT_MASK(ofs); ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs); diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index d060f2572512..c99f890cc6c6 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -1869,6 +1869,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp, dev_info(&chip->client->dev, "%s: i2c device found does not match expected id\n", __func__); + ret = -EINVAL; goto fail1; } @@ -1907,7 +1908,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp, if (ret) { dev_err(&clientp->dev, "%s: irq request failed", __func__); - goto fail2; + goto fail1; } } @@ -1920,17 +1921,17 @@ static int tsl2x7x_probe(struct i2c_client *clientp, if (ret) { dev_err(&clientp->dev, "%s: iio registration failed\n", __func__); - goto fail1; + goto fail2; } dev_info(&clientp->dev, "%s Light sensor found.\n", id->name); return 0; -fail1: +fail2: if (clientp->irq) free_irq(clientp->irq, indio_dev); -fail2: +fail1: iio_device_free(indio_dev); return ret; diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig index 8c9e40390f42..ef699f753186 100644 --- a/drivers/staging/imx-drm/Kconfig +++ b/drivers/staging/imx-drm/Kconfig @@ -1,6 +1,7 @@ config DRM_IMX tristate "DRM Support for Freescale i.MX" select DRM_KMS_HELPER + select VIDEOMODE_HELPERS select DRM_GEM_CMA_HELPER select DRM_KMS_CMA_HELPER depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM) @@ -19,10 +20,12 @@ config DRM_IMX_FB_HELPER config DRM_IMX_PARALLEL_DISPLAY tristate "Support for parallel displays" depends on DRM_IMX + select VIDEOMODE_HELPERS config DRM_IMX_TVE tristate "Support for TV and VGA displays" depends on DRM_IMX + select REGMAP_MMIO help Choose this to enable the internal Television Encoder (TVe) found on i.MX53 processors. @@ -30,6 +33,7 @@ config DRM_IMX_TVE config DRM_IMX_IPUV3_CORE tristate "IPUv3 core support" depends on DRM_IMX + depends on RESET_CONTROLLER help Choose this if you have a i.MX5/6 system and want to use the IPU. This option only enables IPU base @@ -38,5 +42,6 @@ config DRM_IMX_IPUV3_CORE config DRM_IMX_IPUV3 tristate "DRM Support for i.MX IPUv3" depends on DRM_IMX + depends on DRM_IMX_IPUV3_CORE help Choose this if you have a i.MX5 or i.MX6 processor. diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c index ac1634464407..03892de9bd7e 100644 --- a/drivers/staging/imx-drm/imx-tve.c +++ b/drivers/staging/imx-drm/imx-tve.c @@ -670,7 +670,9 @@ static int imx_tve_probe(struct platform_device *pdev) tve->dac_reg = devm_regulator_get(&pdev->dev, "dac"); if (!IS_ERR(tve->dac_reg)) { regulator_set_voltage(tve->dac_reg, 2750000, 2750000); - regulator_enable(tve->dac_reg); + ret = regulator_enable(tve->dac_reg); + if (ret) + return ret; } tve->clk = devm_clk_get(&pdev->dev, "tve"); diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index ea61c869110f..b2730b1af5b4 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c @@ -316,31 +316,14 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) { - struct drm_pending_vblank_event *e; - struct timeval now; unsigned long flags; struct drm_device *drm = ipu_crtc->base.dev; spin_lock_irqsave(&drm->event_lock, flags); - - e = ipu_crtc->page_flip_event; - if (!e) { - spin_unlock_irqrestore(&drm->event_lock, flags); - return; - } - - do_gettimeofday(&now); - e->event.sequence = 0; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; + if (ipu_crtc->page_flip_event) + drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event); ipu_crtc->page_flip_event = NULL; - imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); - - list_add_tail(&e->base.link, &e->base.file_priv->event_list); - - wake_up_interruptible(&e->base.file_priv->event_wait); - spin_unlock_irqrestore(&drm->event_lock, flags); } @@ -381,17 +364,12 @@ static void ipu_crtc_commit(struct drm_crtc *crtc) ipu_fb_enable(ipu_crtc); } -static void ipu_crtc_load_lut(struct drm_crtc *crtc) -{ -} - static struct drm_crtc_helper_funcs ipu_helper_funcs = { .dpms = ipu_crtc_dpms, .mode_fixup = ipu_crtc_mode_fixup, .mode_set = ipu_crtc_mode_set, .prepare = ipu_crtc_prepare, .commit = ipu_crtc_commit, - .load_lut = ipu_crtc_load_lut, }; static int ipu_enable_vblank(struct drm_crtc *crtc) diff --git a/drivers/staging/media/davinci_vpfe/Kconfig b/drivers/staging/media/davinci_vpfe/Kconfig index 2e4a28b018e8..12f321dd2399 100644 --- a/drivers/staging/media/davinci_vpfe/Kconfig +++ b/drivers/staging/media/davinci_vpfe/Kconfig @@ -1,6 +1,6 @@ config VIDEO_DM365_VPFE tristate "DM365 VPFE Media Controller Capture Driver" - depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_VPFE_CAPTURE + depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF select VIDEOBUF2_DMA_CONTIG help Support for DM365 VPFE based Media Controller Capture driver. diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c index b88e1ddce229..d8ce20d2fbda 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c @@ -639,7 +639,8 @@ static int vpfe_probe(struct platform_device *pdev) if (ret) goto probe_free_dev_mem; - if (vpfe_initialize_modules(vpfe_dev, pdev)) + ret = vpfe_initialize_modules(vpfe_dev, pdev); + if (ret) goto probe_disable_clock; vpfe_dev->media_dev.dev = vpfe_dev->pdev; @@ -663,7 +664,8 @@ static int vpfe_probe(struct platform_device *pdev) /* set the driver data in platform device */ platform_set_drvdata(pdev, vpfe_dev); /* register subdevs/entities */ - if (vpfe_register_entities(vpfe_dev)) + ret = vpfe_register_entities(vpfe_dev); + if (ret) goto probe_out_v4l2_unregister; ret = vpfe_attach_irq(vpfe_dev); diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig index ec32776ff547..34f3b6d02d2a 100644 --- a/drivers/staging/media/solo6x10/Kconfig +++ b/drivers/staging/media/solo6x10/Kconfig @@ -1,9 +1,11 @@ config SOLO6X10 tristate "Softlogic 6x10 MPEG codec cards" depends on PCI && VIDEO_DEV && SND && I2C + depends on FONTS select VIDEOBUF2_DMA_SG select VIDEOBUF2_DMA_CONTIG select SND_PCM + select FONT_8x16 ---help--- This driver supports the Softlogic based MPEG-4 and h.264 codec cards. diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 863b22e51b45..197c393c4ca7 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -124,6 +124,20 @@ int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb, EXPORT_SYMBOL_GPL(nvec_register_notifier); /** + * nvec_unregister_notifier - Unregister a notifier with nvec + * @nvec: A &struct nvec_chip + * @nb: The notifier block to unregister + * + * Unregisters a notifier with @nvec. The notifier will be removed from the + * atomic notifier chain. + */ +int nvec_unregister_notifier(struct nvec_chip *nvec, struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&nvec->notifier_list, nb); +} +EXPORT_SYMBOL_GPL(nvec_unregister_notifier); + +/** * nvec_status_notifier - The final notifier * * Prints a message about control events not handled in the notifier @@ -185,7 +199,7 @@ static struct nvec_msg *nvec_msg_alloc(struct nvec_chip *nvec, * * Free the given message */ -inline void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg) +void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg) { if (msg != &nvec->tx_scratch) dev_vdbg(nvec->dev, "INFO: Free %ti\n", msg - nvec->msg_pool); @@ -810,7 +824,7 @@ static int tegra_nvec_probe(struct platform_device *pdev) return -ENODEV; } - i2c_clk = clk_get(&pdev->dev, "div-clk"); + i2c_clk = devm_clk_get(&pdev->dev, "div-clk"); if (IS_ERR(i2c_clk)) { dev_err(nvec->dev, "failed to get controller clock\n"); return -ENODEV; @@ -897,8 +911,11 @@ static int tegra_nvec_remove(struct platform_device *pdev) nvec_toggle_global_events(nvec, false); mfd_remove_devices(nvec->dev); + nvec_unregister_notifier(nvec, &nvec->nvec_status_notifier); cancel_work_sync(&nvec->rx_work); cancel_work_sync(&nvec->tx_work); + /* FIXME: needs check wether nvec is responsible for power off */ + pm_power_off = NULL; return 0; } diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h index b7a14bc0ab91..2b1316d87470 100644 --- a/drivers/staging/nvec/nvec.h +++ b/drivers/staging/nvec/nvec.h @@ -197,9 +197,8 @@ extern int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb, unsigned int events); -extern int nvec_unregister_notifier(struct device *dev, - struct notifier_block *nb, - unsigned int events); +extern int nvec_unregister_notifier(struct nvec_chip *dev, + struct notifier_block *nb); extern void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg); diff --git a/drivers/staging/nvec/nvec_kbd.c b/drivers/staging/nvec/nvec_kbd.c index 7445ce6422bb..a0ec52a4114f 100644 --- a/drivers/staging/nvec/nvec_kbd.c +++ b/drivers/staging/nvec/nvec_kbd.c @@ -169,8 +169,15 @@ fail: static int nvec_kbd_remove(struct platform_device *pdev) { + struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent); + char disable_kbd[] = { NVEC_KBD, DISABLE_KBD }, + uncnfg_wake_key_reporting[] = { NVEC_KBD, CNFG_WAKE_KEY_REPORTING, + false }; + nvec_write_async(nvec, uncnfg_wake_key_reporting, 3); + nvec_write_async(nvec, disable_kbd, 2); + nvec_unregister_notifier(nvec, &keys_dev.notifier); + input_unregister_device(keys_dev.input); - input_free_device(keys_dev.input); return 0; } @@ -188,4 +195,5 @@ module_platform_driver(nvec_kbd_driver); MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>"); MODULE_DESCRIPTION("NVEC keyboard driver"); +MODULE_ALIAS("platform:nvec-kbd"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/nvec/nvec_power.c b/drivers/staging/nvec/nvec_power.c index 296f7b9a8c8c..aacfcd6954a3 100644 --- a/drivers/staging/nvec/nvec_power.c +++ b/drivers/staging/nvec/nvec_power.c @@ -414,6 +414,7 @@ static int nvec_power_remove(struct platform_device *pdev) struct nvec_power *power = platform_get_drvdata(pdev); cancel_delayed_work_sync(&power->poller); + nvec_unregister_notifier(power->nvec, &power->notifier); switch (pdev->id) { case AC: power_supply_unregister(&nvec_psy); diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c index aff6b9b9f9aa..06dbb02085a9 100644 --- a/drivers/staging/nvec/nvec_ps2.c +++ b/drivers/staging/nvec/nvec_ps2.c @@ -106,7 +106,7 @@ static int nvec_mouse_probe(struct platform_device *pdev) struct serio *ser_dev; char mouse_reset[] = { NVEC_PS2, SEND_COMMAND, PSMOUSE_RST, 3 }; - ser_dev = devm_kzalloc(&pdev->dev, sizeof(struct serio), GFP_KERNEL); + ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL); if (ser_dev == NULL) return -ENOMEM; @@ -133,6 +133,11 @@ static int nvec_mouse_probe(struct platform_device *pdev) static int nvec_mouse_remove(struct platform_device *pdev) { + struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent); + + ps2_sendcommand(ps2_dev.ser_dev, DISABLE_MOUSE); + ps2_stopstreaming(ps2_dev.ser_dev); + nvec_unregister_notifier(nvec, &ps2_dev.notifier); serio_unregister_port(ps2_dev.ser_dev); return 0; @@ -179,4 +184,5 @@ module_platform_driver(nvec_mouse_driver); MODULE_DESCRIPTION("NVEC mouse driver"); MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>"); +MODULE_ALIAS("platform:nvec-mouse"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/sep/Kconfig b/drivers/staging/sep/Kconfig index 185b676d858a..aab945a316ea 100644 --- a/drivers/staging/sep/Kconfig +++ b/drivers/staging/sep/Kconfig @@ -1,6 +1,6 @@ config DX_SEP tristate "Discretix SEP driver" - depends on PCI + depends on PCI && CRYPTO help Discretix SEP driver; used for the security processor subsystem on board the Intel Mobile Internet Device and adds SEP availability diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c index fe667dde43ce..386362c9964f 100644 --- a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c +++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c @@ -1087,7 +1087,11 @@ static int synaptics_rmi4_resume(struct device *dev) unsigned char intr_status; struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); - regulator_enable(rmi4_data->regulator); + retval = regulator_enable(rmi4_data->regulator); + if (retval) { + dev_err(dev, "Regulator enable failed (%d)\n", retval); + return retval; + } enable_irq(rmi4_data->i2c_client->irq); rmi4_data->touch_stopped = false; diff --git a/drivers/staging/vt6656/hostap.c b/drivers/staging/vt6656/hostap.c index f4f1bf7a30fd..c699a3058b39 100644 --- a/drivers/staging/vt6656/hostap.c +++ b/drivers/staging/vt6656/hostap.c @@ -133,7 +133,7 @@ static int hostap_disable_hostapd(struct vnt_private *pDevice, int rtnl_locked) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n", pDevice->dev->name, pDevice->apdev->name); } - kfree(pDevice->apdev); + free_netdev(pDevice->apdev); pDevice->apdev = NULL; pDevice->bEnable8021x = false; pDevice->bEnableHostWEP = false; diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c index c335808211ee..d0cf7d8a20e5 100644 --- a/drivers/staging/vt6656/iwctl.c +++ b/drivers/staging/vt6656/iwctl.c @@ -1345,9 +1345,12 @@ int iwctl_siwpower(struct net_device *dev, struct iw_request_info *info, return rc; } + spin_lock_irq(&pDevice->lock); + if (wrq->disabled) { pDevice->ePSMode = WMAC_POWER_CAM; PSvDisablePowerSaving(pDevice); + spin_unlock_irq(&pDevice->lock); return rc; } if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { @@ -1358,6 +1361,9 @@ int iwctl_siwpower(struct net_device *dev, struct iw_request_info *info, pDevice->ePSMode = WMAC_POWER_FAST; PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval); } + + spin_unlock_irq(&pDevice->lock); + switch (wrq->flags & IW_POWER_MODE) { case IW_POWER_UNICAST_R: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_UNICAST_R \n"); diff --git a/drivers/staging/zcache/ramster.h b/drivers/staging/zcache/ramster.h index e1f91d5a0f6a..a858666eae68 100644 --- a/drivers/staging/zcache/ramster.h +++ b/drivers/staging/zcache/ramster.h @@ -11,10 +11,6 @@ #ifndef _ZCACHE_RAMSTER_H_ #define _ZCACHE_RAMSTER_H_ -#ifdef CONFIG_RAMSTER_MODULE -#define CONFIG_RAMSTER -#endif - #ifdef CONFIG_RAMSTER #include "ramster/ramster.h" #else diff --git a/drivers/staging/zcache/ramster/debug.c b/drivers/staging/zcache/ramster/debug.c index 327e4f0d98e1..5b26ee977c2f 100644 --- a/drivers/staging/zcache/ramster/debug.c +++ b/drivers/staging/zcache/ramster/debug.c @@ -1,6 +1,8 @@ #include <linux/atomic.h> #include "debug.h" +ssize_t ramster_foreign_eph_pages; +ssize_t ramster_foreign_pers_pages; #ifdef CONFIG_DEBUG_FS #include <linux/debugfs.h> diff --git a/drivers/staging/zcache/ramster/ramster-howto.txt b/drivers/staging/zcache/ramster/ramster-howto.txt new file mode 100644 index 000000000000..7b1ee3bbfdd5 --- /dev/null +++ b/drivers/staging/zcache/ramster/ramster-howto.txt @@ -0,0 +1,366 @@ + RAMSTER HOW-TO + +Author: Dan Magenheimer +Ramster maintainer: Konrad Wilk <konrad.wilk@oracle.com> + +This is a HOWTO document for ramster which, as of this writing, is in +the kernel as a subdirectory of zcache in drivers/staging, called ramster. +(Zcache can be built with or without ramster functionality.) If enabled +and properly configured, ramster allows memory capacity load balancing +across multiple machines in a cluster. Further, the ramster code serves +as an example of asynchronous access for zcache (as well as cleancache and +frontswap) that may prove useful for future transcendent memory +implementations, such as KVM and NVRAM. While ramster works today on +any network connection that supports kernel sockets, its features may +become more interesting on future high-speed fabrics/interconnects. + +Ramster requires both kernel and userland support. The userland support, +called ramster-tools, is known to work with EL6-based distros, but is a +set of poorly-hacked slightly-modified cluster tools based on ocfs2, which +includes an init file, a config file, and a userland binary that interfaces +to the kernel. This state of userland support reflects the abysmal userland +skills of this suitably-embarrassed author; any help/patches to turn +ramster-tools into more distributable rpms/debs useful for a wider range +of distros would be appreciated. The source RPM that can be used as a +starting point is available at: + http://oss.oracle.com/projects/tmem/files/RAMster/ + +As a result of this author's ignorance, userland setup described in this +HOWTO assumes an EL6 distro and is described in EL6 syntax. Apologies +if this offends anyone! + +Kernel support has only been tested on x86_64. Systems with an active +ocfs2 filesystem should work, but since ramster leverages a lot of +code from ocfs2, there may be latent issues. A kernel configuration that +includes CONFIG_OCFS2_FS should build OK, and should certainly run OK +if no ocfs2 filesystem is mounted. + +This HOWTO demonstrates memory capacity load balancing for a two-node +cluster, where one node called the "local" node becomes overcommitted +and the other node called the "remote" node provides additional RAM +capacity for use by the local node. Ramster is capable of more complex +topologies; see the last section titled "ADVANCED RAMSTER TOPOLOGIES". + +If you find any terms in this HOWTO unfamiliar or don't understand the +motivation for ramster, the following LWN reading is recommended: +-- Transcendent Memory in a Nutshell (lwn.net/Articles/454795) +-- The future calculus of memory management (lwn.net/Articles/475681) +And since ramster is built on top of zcache, this article may be helpful: +-- In-kernel memory compression (lwn.net/Articles/545244) + +Now that you've memorized the contents of those articles, let's get started! + +A. PRELIMINARY + +1) Install two x86_64 Linux systems that are known to work when + upgraded to a recent upstream Linux kernel version. + +On each system: + +2) Configure, build and install, then boot Linux, just to ensure it + can be done with an unmodified upstream kernel. Confirm you booted + the upstream kernel with "uname -a". + +3) If you plan to do any performance testing or unless you plan to + test only swapping, the "WasActive" patch is also highly recommended. + (Search lkml.org for WasActive, apply the patch, rebuild your kernel.) + For a demo or simple testing, the patch can be ignored. + +4) Install ramster-tools as root. An x86_64 rpm for EL6-based systems + can be found at: + http://oss.oracle.com/projects/tmem/files/RAMster/ + (Sorry but for now, non-EL6 users must recreate ramster-tools on + their own from source. See above.) + +5) Ensure that debugfs is mounted at each boot. Examples below assume it + is mounted at /sys/kernel/debug. + +B. BUILDING RAMSTER INTO THE KERNEL + +Do the following on each system: + +1) Using the kernel configuration mechanism of your choice, change + your config to include: + + CONFIG_CLEANCACHE=y + CONFIG_FRONTSWAP=y + CONFIG_STAGING=y + CONFIG_CONFIGFS_FS=y # NOTE: MUST BE y, not m + CONFIG_ZCACHE=y + CONFIG_RAMSTER=y + + For a linux-3.10 or later kernel, you should also set: + + CONFIG_ZCACHE_DEBUG=y + CONFIG_RAMSTER_DEBUG=y + + Before building the kernel please doublecheck your kernel config + file to ensure all of the settings are correct. + +2) Build this kernel and change your boot file (e.g. /etc/grub.conf) + so that the new kernel will boot. + +3) Add "zcache" and "ramster" as kernel boot parameters for the new kernel. + +4) Reboot each system approximately simultaneously. + +5) Check dmesg to ensure there are some messages from ramster, prefixed + by "ramster:" + + # dmesg | grep ramster + + You should also see a lot of files in: + + # ls /sys/kernel/debug/zcache + # ls /sys/kernel/debug/ramster + + These are mostly counters for various zcache and ramster activities. + You should also see files in: + + # ls /sys/kernel/mm/ramster + + These are sysfs files that control ramster as we shall see. + + Ramster now will act as a single-system zcache on each system + but doesn't yet know anything about the cluster so can't yet do + anything remotely. + +C. CONFIGURING THE RAMSTER CLUSTER + +This part can be error prone unless you are familiar with clustering +filesystems. We need to describe the cluster in a /etc/ramster.conf +file and the init scripts that parse it are extremely picky about +the syntax. + +1) Create a /etc/ramster.conf file and ensure it is identical on both + systems. This file mimics the ocfs2 format and there is a good amount + of documentation that can be searched for ocfs2.conf, but you can use: + + cluster: + name = ramster + node_count = 2 + node: + name = system1 + cluster = ramster + number = 0 + ip_address = my.ip.ad.r1 + ip_port = 7777 + node: + name = system2 + cluster = ramster + number = 1 + ip_address = my.ip.ad.r2 + ip_port = 7777 + + You must ensure that the "name" field in the file exactly matches + the output of "hostname" on each system; if "hostname" shows a + fully-qualified hostname, ensure the name is fully qualified in + /etc/ramster.conf. Obviously, substitute my.ip.ad.rx with proper + ip addresses. + +2) Enable the ramster service and configure it. If you used the + EL6 ramster-tools, this would be: + + # chkconfig --add ramster + # service ramster configure + + Set "load on boot" to "y", cluster to start is "ramster" (or whatever + name you chose in ramster.conf), heartbeat dead threshold as "500", + network idle timeout as "1000000". Leave the others as default. + +3) Reboot both systems. After reboot, try (assuming EL6 ramster-tools): + + # service ramster status + + You should see "Checking RAMSTER cluster "ramster": Online". If you do + not, something is wrong and ramster will not work. Note that you + should also see that the driver for "configfs" is loaded and mounted, + the driver for ocfs2_dlmfs is not loaded, and some numbers for network + parameters. You will also see "Checking RAMSTER heartbeat: Not active". + That's all OK. + +4) Now you need to start the cluster heartbeat; the cluster is not "up" + until all nodes detect a heartbeat. In a real cluster, heartbeat detection + is done via a cluster filesystem, but ramster doesn't require one. Some + hack-y kernel code in ramster can start the heartbeat for you though if + you tell it what nodes are "up". To enable the heartbeat, do: + + # echo 0 > /sys/kernel/mm/ramster/manual_node_up + # echo 1 > /sys/kernel/mm/ramster/manual_node_up + + This must be done on BOTH nodes and, to avoid timeouts, must be done + approximately concurrently on both nodes. On an EL6 system, it is + convenient to put these lines in /etc/rc.local. To confirm that the + cluster is now up, on both systems do: + + # dmesg | grep ramster + + You should see ramster "Accepted connection" messages in dmesg on both + nodes after this. Note that if you check userland status again with + + # service ramster status + + you will still see "Checking RAMSTER heartbeat: Not active". That's + still OK... the ramster kernel heartbeat hack doesn't communicate to + userland. + +5) You now must tell each node the node to which it should "remotify" pages. + On this two node cluster, we will assume the "local" node, node 0, has + memory overcommitted and will use ramster to utilize RAM capacity on + the "remote node", node 1. To configure this, on node 0, you do: + + # echo 1 > /sys/kernel/mm/ramster/remote_target_nodenum + + You should see "ramster: node 1 set as remotification target" in dmesg + on node 0. Again, on EL6, /etc/rc.local is a good place to put this + on node 0 so you don't forget to do it at each boot. + +6) One more step: By default, the ramster code does not "remotify" any + pages; this is primarily for testing purposes, but sometimes it is + useful. This may change in the future, but for now, on node 0, you do: + + # echo 1 > /sys/kernel/mm/ramster/pers_remotify_enable + # echo 1 > /sys/kernel/mm/ramster/eph_remotify_enable + + The first enables remotifying swap (persistent, aka frontswap) pages, + the second enables remotifying of page cache (ephemeral, cleancache) + pages. + + On EL6, these lines can also be put in /etc/rc.local (AFTER the + node_up lines), or at the beginning of a script that runs a workload. + +7) Note that most testing has been done with both/all machines booted + roughly simultaneously to avoid cluster timeouts. Ideally, you should + do this too unless you are trying to break ramster rather than just + use it. ;-) + +D. TESTING RAMSTER + +1) Note that ramster has no value unless pages get "remotified". For + swap/frontswap/persistent pages, this doesn't happen unless/until + the workload would cause swapping to occur, at which point pages + are put into frontswap/zcache, and the remotification thread starts + working. To get to the point where the system swaps, you either + need a workload for which the working set exceeds the RAM in the + system; or you need to somehow reduce the amount of RAM one of + the system sees. This latter is easy when testing in a VM, but + harder on physical systems. In some cases, "mem=xxxM" on the + kernel command line restricts memory, but for some values of xxx + the kernel may fail to boot. One may also try creating a fixed + RAMdisk, doing nothing with it, but ensuring that it eats up a fixed + amount of RAM. + +2) To see if ramster is working, on the "remote node", node 1, try: + + # grep . /sys/kernel/debug/ramster/foreign_* + # # note, that is space-dot-space between grep and the pathname + + to monitor the number (and max) ephemeral and persistent pages + that ramster has sent. If these stay at zero, ramster is not working + either because the workload on the local node (node 0) isn't creating + enough memory pressure or because "remotifying" isn't working. On the + local system, node 0, you can watch lots of useful information also. + Try: + + grep . /sys/kernel/debug/zcache/*pageframes* \ + /sys/kernel/debug/zcache/*zbytes* \ + /sys/kernel/debug/zcache/*zpages* \ + /sys/kernel/debug/ramster/*remote* + + Of particular note are the remote_*_pages_succ_get counters. These + show how many disk reads and/or disk writes have been avoided on the + overcommitted local system by storing pages remotely using ramster. + + At the risk of information overload, you can also grep: + + /sys/kernel/debug/cleancache/* and /sys/kernel/debug/frontswap/* + + These show, for example, how many disk reads and/or disk writes have + been avoided by using zcache to optimize RAM on the local system. + + +AUTOMATIC SWAP REPATRIATION + +You may notice that while the systems are idle, the foreign persistent +page count on the remote machine slowly decreases. This is because +ramster implements "frontswap selfshrinking": When possible, swap +pages that have been remotified are slowly repatriated to the local +machine. This is so that local RAM can be used when possible and +so that, in case of remote machine crash, the probability of loss +of data is reduced. + +REBOOTING / POWEROFF + +If a system is shut down while some of its swap pages still reside +on a remote system, the system may lock up during the shutdown +sequence. This will occur if the network is shut down before the +swap mechansim is shut down, which is the default ordering on many +distros. To avoid this annoying problem, simply shut off the swap +subsystem before starting the shutdown sequence, e.g.: + + # swapoff -a + # reboot + +Ideally, this swapoff-before-ifdown ordering should be enforced permanently +using shutdown scripts. + +KNOWN PROBLEMS + +1) You may periodically see messages such as: + + ramster_r2net, message length problem + + This is harmless but indicates that a node is sending messages + containing compressed pages that exceed the maximum for zcache + (PAGE_SIZE*15/16). The sender side needs to be fixed. + +2) If you see a "No longer connected to node..." message or a "No connection + established with node X after N seconds", it is possible you may + be in an unrecoverable state. If you are certain all of the + appropriate cluster configuration steps described above have been + performed, try rebooting the two servers concurrently to see if + the cluster starts. + + Note that "Connection to node... shutdown, state 7" is an intermediate + connection state. As long as you later see "Accepted connection", the + intermediate states are harmless. + +3) There are known issues in counting certain values. As a result + you may see periodic warnings from the kernel. Almost always you + will see "ramster: bad accounting for XXX". There are also "WARN_ONCE" + messages. If you see kernel warnings with a tombstone, please report + them. They are harmless but reflect bugs that need to be eventually fixed. + +ADVANCED RAMSTER TOPOLOGIES + +The kernel code for ramster can support up to eight nodes in a cluster, +but no testing has been done with more than three nodes. + +In the example described above, the "remote" node serves as a RAM +overflow for the "local" node. This can be made symmetric by appropriate +settings of the sysfs remote_target_nodenum file. For example, by setting: + + # echo 1 > /sys/kernel/mm/ramster/remote_target_nodenum + +on node 0, and + + # echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum + +on node 1, each node can serve as a RAM overflow for the other. + +For more than two nodes, a "RAM server" can be configured. For a +three node system, set: + + # echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum + +on node 1, and + + # echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum + +on node 2. Then node 0 is a RAM server for node 1 and node 2. + +In this implementation of ramster, any remote node is potentially a single +point of failure (SPOF). Though the probability of failure is reduced +by automatic swap repatriation (see above), a proposed future enhancement +to ramster improves high-availability for the cluster by sending a copy +of each page of date to two other nodes. Patches welcome! diff --git a/drivers/staging/zcache/ramster/ramster.c b/drivers/staging/zcache/ramster/ramster.c index b18b887db79f..a937ce1fa27a 100644 --- a/drivers/staging/zcache/ramster/ramster.c +++ b/drivers/staging/zcache/ramster/ramster.c @@ -66,8 +66,6 @@ static int ramster_remote_target_nodenum __read_mostly = -1; /* Used by this code. */ long ramster_flnodes; -ssize_t ramster_foreign_eph_pages; -ssize_t ramster_foreign_pers_pages; /* FIXME frontswap selfshrinking knobs in debugfs? */ static LIST_HEAD(ramster_rem_op_list); @@ -399,14 +397,18 @@ void ramster_count_foreign_pages(bool eph, int count) inc_ramster_foreign_eph_pages(); } else { dec_ramster_foreign_eph_pages(); +#ifdef CONFIG_RAMSTER_DEBUG WARN_ON_ONCE(ramster_foreign_eph_pages < 0); +#endif } } else { if (count > 0) { inc_ramster_foreign_pers_pages(); } else { dec_ramster_foreign_pers_pages(); +#ifdef CONFIG_RAMSTER_DEBUG WARN_ON_ONCE(ramster_foreign_pers_pages < 0); +#endif } } } diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index 522cb8e55142..dcceed29d31a 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c @@ -1922,15 +1922,15 @@ out: #ifdef CONFIG_ZCACHE_MODULE #ifdef CONFIG_RAMSTER -module_param(ramster_enabled, int, S_IRUGO); +module_param(ramster_enabled, bool, S_IRUGO); module_param(disable_frontswap_selfshrink, int, S_IRUGO); #endif -module_param(disable_cleancache, int, S_IRUGO); -module_param(disable_frontswap, int, S_IRUGO); +module_param(disable_cleancache, bool, S_IRUGO); +module_param(disable_frontswap, bool, S_IRUGO); #ifdef FRONTSWAP_HAS_EXCLUSIVE_GETS module_param(frontswap_has_exclusive_gets, bool, S_IRUGO); #endif -module_param(disable_frontswap_ignore_nonactive, int, S_IRUGO); +module_param(disable_frontswap_ignore_nonactive, bool, S_IRUGO); module_param(zcache_comp_name, charp, S_IRUGO); module_init(zcache_init); MODULE_LICENSE("GPL"); diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 262ef1f23b38..d7705e5824fb 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -651,7 +651,7 @@ static int iscsit_add_reject( cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL); if (!cmd->buf_ptr) { pr_err("Unable to allocate memory for cmd->buf_ptr\n"); - iscsit_release_cmd(cmd); + iscsit_free_cmd(cmd, false); return -1; } @@ -697,7 +697,7 @@ int iscsit_add_reject_from_cmd( cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL); if (!cmd->buf_ptr) { pr_err("Unable to allocate memory for cmd->buf_ptr\n"); - iscsit_release_cmd(cmd); + iscsit_free_cmd(cmd, false); return -1; } @@ -1743,7 +1743,7 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, return 0; out: if (cmd) - iscsit_release_cmd(cmd); + iscsit_free_cmd(cmd, false); ping_out: kfree(ping_data); return ret; @@ -2251,7 +2251,7 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) { pr_err("Received logout request on connection that" " is not in logged in state, ignoring request.\n"); - iscsit_release_cmd(cmd); + iscsit_free_cmd(cmd, false); return 0; } @@ -3665,7 +3665,7 @@ iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); - iscsit_free_cmd(cmd); + iscsit_free_cmd(cmd, false); break; case ISTATE_SEND_NOPIN_WANT_RESPONSE: iscsit_mod_nopin_response_timer(conn); @@ -4122,7 +4122,7 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn) iscsit_increment_maxcmdsn(cmd, sess); - iscsit_free_cmd(cmd); + iscsit_free_cmd(cmd, true); spin_lock_bh(&conn->cmd_lock); } diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 13e9e715ad2e..8d8b3ff68490 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -155,7 +155,7 @@ static ssize_t lio_target_np_store_iser( struct iscsi_tpg_np *tpg_np_iser = NULL; char *endptr; u32 op; - int rc; + int rc = 0; op = simple_strtoul(page, &endptr, 0); if ((op != 1) && (op != 0)) { @@ -174,31 +174,32 @@ static ssize_t lio_target_np_store_iser( return -EINVAL; if (op) { - int rc = request_module("ib_isert"); - if (rc != 0) + rc = request_module("ib_isert"); + if (rc != 0) { pr_warn("Unable to request_module for ib_isert\n"); + rc = 0; + } tpg_np_iser = iscsit_tpg_add_network_portal(tpg, &np->np_sockaddr, np->np_ip, tpg_np, ISCSI_INFINIBAND); - if (!tpg_np_iser || IS_ERR(tpg_np_iser)) + if (IS_ERR(tpg_np_iser)) { + rc = PTR_ERR(tpg_np_iser); goto out; + } } else { tpg_np_iser = iscsit_tpg_locate_child_np(tpg_np, ISCSI_INFINIBAND); - if (!tpg_np_iser) - goto out; - - rc = iscsit_tpg_del_network_portal(tpg, tpg_np_iser); - if (rc < 0) - goto out; + if (tpg_np_iser) { + rc = iscsit_tpg_del_network_portal(tpg, tpg_np_iser); + if (rc < 0) + goto out; + } } - printk("lio_target_np_store_iser() done, op: %d\n", op); - iscsit_put_tpg(tpg); return count; out: iscsit_put_tpg(tpg); - return -EINVAL; + return rc; } TF_NP_BASE_ATTR(lio_target, iser, S_IRUGO | S_IWUSR); diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 8e6298cc8839..dcb199da06b9 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -842,11 +842,11 @@ int iscsit_stop_time2retain_timer(struct iscsi_session *sess) return 0; sess->time2retain_timer_flags |= ISCSI_TF_STOP; - spin_unlock_bh(&se_tpg->session_lock); + spin_unlock(&se_tpg->session_lock); del_timer_sync(&sess->time2retain_timer); - spin_lock_bh(&se_tpg->session_lock); + spin_lock(&se_tpg->session_lock); sess->time2retain_timer_flags &= ~ISCSI_TF_RUNNING; pr_debug("Stopped Time2Retain Timer for SID: %u\n", sess->sid); diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index ba6091bf93fc..45a5afd5ea13 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c @@ -143,7 +143,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) list_del(&cmd->i_conn_node); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); - iscsit_free_cmd(cmd); + iscsit_free_cmd(cmd, true); spin_lock(&cr->conn_recovery_cmd_lock); } spin_unlock(&cr->conn_recovery_cmd_lock); @@ -165,7 +165,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) list_del(&cmd->i_conn_node); cmd->conn = NULL; spin_unlock(&cr->conn_recovery_cmd_lock); - iscsit_free_cmd(cmd); + iscsit_free_cmd(cmd, true); spin_lock(&cr->conn_recovery_cmd_lock); } spin_unlock(&cr->conn_recovery_cmd_lock); @@ -248,7 +248,7 @@ void iscsit_discard_cr_cmds_by_expstatsn( iscsit_remove_cmd_from_connection_recovery(cmd, sess); spin_unlock(&cr->conn_recovery_cmd_lock); - iscsit_free_cmd(cmd); + iscsit_free_cmd(cmd, true); spin_lock(&cr->conn_recovery_cmd_lock); } spin_unlock(&cr->conn_recovery_cmd_lock); @@ -302,7 +302,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn) list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); - iscsit_free_cmd(cmd); + iscsit_free_cmd(cmd, true); spin_lock_bh(&conn->cmd_lock); } spin_unlock_bh(&conn->cmd_lock); @@ -355,7 +355,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); - iscsit_free_cmd(cmd); + iscsit_free_cmd(cmd, true); spin_lock_bh(&conn->cmd_lock); continue; } @@ -375,7 +375,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) { list_del(&cmd->i_conn_node); spin_unlock_bh(&conn->cmd_lock); - iscsit_free_cmd(cmd); + iscsit_free_cmd(cmd, true); spin_lock_bh(&conn->cmd_lock); continue; } diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index bb5d5c5bce65..3402241be87c 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -984,8 +984,6 @@ int iscsi_target_setup_login_socket( } np->np_transport = t; - printk("Set np->np_transport to %p -> %s\n", np->np_transport, - np->np_transport->name); return 0; } @@ -1002,7 +1000,6 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) conn->sock = new_sock; conn->login_family = np->np_sockaddr.ss_family; - printk("iSCSI/TCP: Setup conn->sock from new_sock: %p\n", new_sock); if (np->np_sockaddr.ss_family == AF_INET6) { memset(&sock_in6, 0, sizeof(struct sockaddr_in6)); diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 7ad912060e21..cd5018ff9cd7 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -721,9 +721,6 @@ int iscsi_target_locate_portal( start += strlen(key) + strlen(value) + 2; } - - printk("i_buf: %s, s_buf: %s, t_buf: %s\n", i_buf, s_buf, t_buf); - /* * See 5.3. Login Phase. */ diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index c2185fc31136..e38222191a33 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -758,9 +758,9 @@ static int iscsi_add_notunderstood_response( } INIT_LIST_HEAD(&extra_response->er_list); - strncpy(extra_response->key, key, strlen(key) + 1); - strncpy(extra_response->value, NOTUNDERSTOOD, - strlen(NOTUNDERSTOOD) + 1); + strlcpy(extra_response->key, key, sizeof(extra_response->key)); + strlcpy(extra_response->value, NOTUNDERSTOOD, + sizeof(extra_response->value)); list_add_tail(&extra_response->er_list, ¶m_list->extra_response_list); @@ -1629,8 +1629,6 @@ int iscsi_decode_text_input( if (phase & PHASE_SECURITY) { if (iscsi_check_for_auth_key(key) > 0) { - char *tmpptr = key + strlen(key); - *tmpptr = '='; kfree(tmpbuf); return 1; } diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h index 915b06798505..a47046a752aa 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.h +++ b/drivers/target/iscsi/iscsi_target_parameters.h @@ -1,8 +1,10 @@ #ifndef ISCSI_PARAMETERS_H #define ISCSI_PARAMETERS_H +#include <scsi/iscsi_proto.h> + struct iscsi_extra_response { - char key[64]; + char key[KEY_MAXLEN]; char value[32]; struct list_head er_list; } ____cacheline_aligned; diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 2cc6c9a3ffb8..08a3bacef0c5 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -676,40 +676,56 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) void iscsit_release_cmd(struct iscsi_cmd *cmd) { - struct iscsi_conn *conn = cmd->conn; - - iscsit_free_r2ts_from_list(cmd); - iscsit_free_all_datain_reqs(cmd); - kfree(cmd->buf_ptr); kfree(cmd->pdu_list); kfree(cmd->seq_list); kfree(cmd->tmr_req); kfree(cmd->iov_data); - if (conn) { + kmem_cache_free(lio_cmd_cache, cmd); +} + +static void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd, + bool check_queues) +{ + struct iscsi_conn *conn = cmd->conn; + + if (scsi_cmd) { + if (cmd->data_direction == DMA_TO_DEVICE) { + iscsit_stop_dataout_timer(cmd); + iscsit_free_r2ts_from_list(cmd); + } + if (cmd->data_direction == DMA_FROM_DEVICE) + iscsit_free_all_datain_reqs(cmd); + } + + if (conn && check_queues) { iscsit_remove_cmd_from_immediate_queue(cmd, conn); iscsit_remove_cmd_from_response_queue(cmd, conn); } - - kmem_cache_free(lio_cmd_cache, cmd); } -void iscsit_free_cmd(struct iscsi_cmd *cmd) +void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) { + struct se_cmd *se_cmd = NULL; + int rc; /* * Determine if a struct se_cmd is associated with * this struct iscsi_cmd. */ switch (cmd->iscsi_opcode) { case ISCSI_OP_SCSI_CMD: - if (cmd->data_direction == DMA_TO_DEVICE) - iscsit_stop_dataout_timer(cmd); + se_cmd = &cmd->se_cmd; + __iscsit_free_cmd(cmd, true, shutdown); /* * Fallthrough */ case ISCSI_OP_SCSI_TMFUNC: - transport_generic_free_cmd(&cmd->se_cmd, 1); + rc = transport_generic_free_cmd(&cmd->se_cmd, 1); + if (!rc && shutdown && se_cmd && se_cmd->se_sess) { + __iscsit_free_cmd(cmd, true, shutdown); + target_put_sess_cmd(se_cmd->se_sess, se_cmd); + } break; case ISCSI_OP_REJECT: /* @@ -718,11 +734,19 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd) * associated cmd->se_cmd needs to be released. */ if (cmd->se_cmd.se_tfo != NULL) { - transport_generic_free_cmd(&cmd->se_cmd, 1); + se_cmd = &cmd->se_cmd; + __iscsit_free_cmd(cmd, true, shutdown); + + rc = transport_generic_free_cmd(&cmd->se_cmd, 1); + if (!rc && shutdown && se_cmd->se_sess) { + __iscsit_free_cmd(cmd, true, shutdown); + target_put_sess_cmd(se_cmd->se_sess, se_cmd); + } break; } /* Fall-through */ default: + __iscsit_free_cmd(cmd, false, shutdown); cmd->release_cmd(cmd); break; } diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 4f8e01a47081..a4422659d049 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -29,7 +29,7 @@ extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_co extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *); extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *); extern void iscsit_release_cmd(struct iscsi_cmd *); -extern void iscsit_free_cmd(struct iscsi_cmd *); +extern void iscsit_free_cmd(struct iscsi_cmd *, bool); extern int iscsit_check_session_usage_count(struct iscsi_session *); extern void iscsit_dec_session_usage_count(struct iscsi_session *); extern void iscsit_inc_session_usage_count(struct iscsi_session *); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 1b1d544e927a..b11890d85120 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -153,6 +153,7 @@ static int fd_configure_device(struct se_device *dev) struct request_queue *q = bdev_get_queue(inode->i_bdev); unsigned long long dev_size; + fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev); /* * Determine the number of bytes from i_size_read() minus * one (1) logical sector from underlying struct block_device @@ -199,6 +200,7 @@ static int fd_configure_device(struct se_device *dev) goto fail; } + fd_dev->fd_block_size = FD_BLOCKSIZE; /* * Limit UNMAP emulation to 8k Number of LBAs (NoLB) */ @@ -217,9 +219,7 @@ static int fd_configure_device(struct se_device *dev) dev->dev_attrib.max_write_same_len = 0x1000; } - fd_dev->fd_block_size = dev->dev_attrib.hw_block_size; - - dev->dev_attrib.hw_block_size = FD_BLOCKSIZE; + dev->dev_attrib.hw_block_size = fd_dev->fd_block_size; dev->dev_attrib.hw_max_sectors = FD_MAX_SECTORS; dev->dev_attrib.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH; @@ -694,11 +694,12 @@ static sector_t fd_get_blocks(struct se_device *dev) * to handle underlying block_device resize operations. */ if (S_ISBLK(i->i_mode)) - dev_size = (i_size_read(i) - fd_dev->fd_block_size); + dev_size = i_size_read(i); else dev_size = fd_dev->fd_dev_size; - return div_u64(dev_size, dev->dev_attrib.block_size); + return div_u64(dev_size - dev->dev_attrib.block_size, + dev->dev_attrib.block_size); } static struct sbc_ops fd_sbc_ops = { diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4a793362309d..21e315874a54 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -65,7 +65,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd); static void transport_handle_queue_full(struct se_cmd *cmd, struct se_device *dev); static int transport_generic_get_mem(struct se_cmd *cmd); -static void transport_put_cmd(struct se_cmd *cmd); +static int transport_put_cmd(struct se_cmd *cmd); static void target_complete_ok_work(struct work_struct *work); int init_se_kmem_caches(void) @@ -221,6 +221,7 @@ struct se_session *transport_init_session(void) INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); INIT_LIST_HEAD(&se_sess->sess_cmd_list); + INIT_LIST_HEAD(&se_sess->sess_wait_list); spin_lock_init(&se_sess->sess_cmd_lock); kref_init(&se_sess->sess_kref); @@ -1943,7 +1944,7 @@ static inline void transport_free_pages(struct se_cmd *cmd) * This routine unconditionally frees a command, and reference counting * or list removal must be done in the caller. */ -static void transport_release_cmd(struct se_cmd *cmd) +static int transport_release_cmd(struct se_cmd *cmd) { BUG_ON(!cmd->se_tfo); @@ -1955,11 +1956,11 @@ static void transport_release_cmd(struct se_cmd *cmd) * If this cmd has been setup with target_get_sess_cmd(), drop * the kref and call ->release_cmd() in kref callback. */ - if (cmd->check_release != 0) { - target_put_sess_cmd(cmd->se_sess, cmd); - return; - } + if (cmd->check_release != 0) + return target_put_sess_cmd(cmd->se_sess, cmd); + cmd->se_tfo->release_cmd(cmd); + return 1; } /** @@ -1968,7 +1969,7 @@ static void transport_release_cmd(struct se_cmd *cmd) * * This routine releases our reference to the command and frees it if possible. */ -static void transport_put_cmd(struct se_cmd *cmd) +static int transport_put_cmd(struct se_cmd *cmd) { unsigned long flags; @@ -1976,7 +1977,7 @@ static void transport_put_cmd(struct se_cmd *cmd) if (atomic_read(&cmd->t_fe_count) && !atomic_dec_and_test(&cmd->t_fe_count)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return; + return 0; } if (cmd->transport_state & CMD_T_DEV_ACTIVE) { @@ -1986,8 +1987,7 @@ static void transport_put_cmd(struct se_cmd *cmd) spin_unlock_irqrestore(&cmd->t_state_lock, flags); transport_free_pages(cmd); - transport_release_cmd(cmd); - return; + return transport_release_cmd(cmd); } void *transport_kmap_data_sg(struct se_cmd *cmd) @@ -2152,13 +2152,15 @@ static void transport_write_pending_qf(struct se_cmd *cmd) } } -void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) +int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) { + int ret = 0; + if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) transport_wait_for_tasks(cmd); - transport_release_cmd(cmd); + ret = transport_release_cmd(cmd); } else { if (wait_for_tasks) transport_wait_for_tasks(cmd); @@ -2166,8 +2168,9 @@ void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) if (cmd->se_lun) transport_lun_remove_cmd(cmd); - transport_put_cmd(cmd); + ret = transport_put_cmd(cmd); } + return ret; } EXPORT_SYMBOL(transport_generic_free_cmd); @@ -2250,11 +2253,14 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) unsigned long flags; spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); - - WARN_ON(se_sess->sess_tearing_down); + if (se_sess->sess_tearing_down) { + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + return; + } se_sess->sess_tearing_down = 1; + list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); - list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) + list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) se_cmd->cmd_wait_set = 1; spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); @@ -2263,44 +2269,32 @@ EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); /* target_wait_for_sess_cmds - Wait for outstanding descriptors * @se_sess: session to wait for active I/O - * @wait_for_tasks: Make extra transport_wait_for_tasks call */ -void target_wait_for_sess_cmds( - struct se_session *se_sess, - int wait_for_tasks) +void target_wait_for_sess_cmds(struct se_session *se_sess) { struct se_cmd *se_cmd, *tmp_cmd; - bool rc = false; + unsigned long flags; list_for_each_entry_safe(se_cmd, tmp_cmd, - &se_sess->sess_cmd_list, se_cmd_list) { + &se_sess->sess_wait_list, se_cmd_list) { list_del(&se_cmd->se_cmd_list); pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" " %d\n", se_cmd, se_cmd->t_state, se_cmd->se_tfo->get_cmd_state(se_cmd)); - if (wait_for_tasks) { - pr_debug("Calling transport_wait_for_tasks se_cmd: %p t_state: %d," - " fabric state: %d\n", se_cmd, se_cmd->t_state, - se_cmd->se_tfo->get_cmd_state(se_cmd)); - - rc = transport_wait_for_tasks(se_cmd); - - pr_debug("After transport_wait_for_tasks se_cmd: %p t_state: %d," - " fabric state: %d\n", se_cmd, se_cmd->t_state, - se_cmd->se_tfo->get_cmd_state(se_cmd)); - } - - if (!rc) { - wait_for_completion(&se_cmd->cmd_wait_comp); - pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d" - " fabric state: %d\n", se_cmd, se_cmd->t_state, - se_cmd->se_tfo->get_cmd_state(se_cmd)); - } + wait_for_completion(&se_cmd->cmd_wait_comp); + pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d" + " fabric state: %d\n", se_cmd, se_cmd->t_state, + se_cmd->se_tfo->get_cmd_state(se_cmd)); se_cmd->se_tfo->release_cmd(se_cmd); } + + spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); + WARN_ON(!list_empty(&se_sess->sess_cmd_list)); + spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + } EXPORT_SYMBOL(target_wait_for_sess_cmds); diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 6d0c27cd03da..9bffcec5ad82 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -859,6 +859,7 @@ error: */ static void __exit ehv_bc_exit(void) { + platform_driver_unregister(&ehv_bc_tty_driver); tty_unregister_driver(ehv_bc_driver); put_tty_driver(ehv_bc_driver); kfree(bcs); diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 71d6eb2c93b1..4c4a23674569 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1618,8 +1618,12 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) if (ip->type == PORT_16550A) me->fifo[p] = 1; - opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2); - opmode &= OP_MODE_MASK; + if (ip->board->chip_flag == MOXA_MUST_MU860_HWID) { + opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2); + opmode &= OP_MODE_MASK; + } else { + opmode = RS232_MODE; + } me->iftype[p] = opmode; mutex_unlock(&port->mutex); } @@ -1676,6 +1680,9 @@ static int mxser_ioctl(struct tty_struct *tty, int shiftbit; unsigned char val, mask; + if (info->board->chip_flag != MOXA_MUST_MU860_HWID) + return -EFAULT; + p = tty->index % 4; if (cmd == MOXA_SET_OP_MODE) { if (get_user(opmode, (int __user *) argp)) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index d655416087b7..6c7fe90ad72d 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1573,6 +1573,14 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) ldata->real_raw = 0; } n_tty_set_room(tty); + /* + * Fix tty hang when I_IXON(tty) is cleared, but the tty + * been stopped by STOP_CHAR(tty) before it. + */ + if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) { + start_tty(tty); + } + /* The termios change make the tty ready for I/O */ wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 59bfaecc4e14..abfd99089781 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -244,14 +244,9 @@ static void pty_flush_buffer(struct tty_struct *tty) static int pty_open(struct tty_struct *tty, struct file *filp) { - int retval = -ENODEV; - if (!tty || !tty->link) - goto out; - - set_bit(TTY_IO_ERROR, &tty->flags); + return -ENODEV; - retval = -EIO; if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) goto out; if (test_bit(TTY_PTY_LOCK, &tty->link->flags)) @@ -262,9 +257,11 @@ static int pty_open(struct tty_struct *tty, struct file *filp) clear_bit(TTY_IO_ERROR, &tty->flags); clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); set_bit(TTY_THROTTLED, &tty->flags); - retval = 0; + return 0; + out: - return retval; + set_bit(TTY_IO_ERROR, &tty->flags); + return -EIO; } static void pty_set_termios(struct tty_struct *tty, diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 82d35c5a58fd..354564ea47c5 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -150,12 +150,14 @@ static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = { AIOP_INTR_BIT_3 }; +#ifdef CONFIG_PCI static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { UPCI_AIOP_INTR_BIT_0, UPCI_AIOP_INTR_BIT_1, UPCI_AIOP_INTR_BIT_2, UPCI_AIOP_INTR_BIT_3 }; +#endif static Byte_t RData[RDATASIZE] = { 0x00, 0x09, 0xf6, 0x82, @@ -227,7 +229,6 @@ static unsigned long nextLineNumber; static int __init init_ISA(int i); static void rp_wait_until_sent(struct tty_struct *tty, int timeout); static void rp_flush_buffer(struct tty_struct *tty); -static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model); static unsigned char GetLineNumber(int ctrl, int aiop, int ch); static unsigned char SetLineNumber(int ctrl, int aiop, int ch); static void rp_start(struct tty_struct *tty); @@ -241,11 +242,6 @@ static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); static void sModemReset(CONTROLLER_T * CtlP, int chan, int on); static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); -static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, - ByteIO_t * AiopIOList, int AiopIOListSize, - WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, - int PeriodicOnly, int altChanRingIndicator, - int UPCIRingInd); static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, ByteIO_t * AiopIOList, int AiopIOListSize, int IRQNum, Byte_t Frequency, int PeriodicOnly); @@ -1775,6 +1771,145 @@ static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = { }; MODULE_DEVICE_TABLE(pci, rocket_pci_ids); +/* Resets the speaker controller on RocketModem II and III devices */ +static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model) +{ + ByteIO_t addr; + + /* RocketModem II speaker control is at the 8th port location of offset 0x40 */ + if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) { + addr = CtlP->AiopIO[0] + 0x4F; + sOutB(addr, 0); + } + + /* RocketModem III speaker control is at the 1st port location of offset 0x80 */ + if ((model == MODEL_UPCI_RM3_8PORT) + || (model == MODEL_UPCI_RM3_4PORT)) { + addr = CtlP->AiopIO[0] + 0x88; + sOutB(addr, 0); + } +} + +/*************************************************************************** +Function: sPCIInitController +Purpose: Initialization of controller global registers and controller + structure. +Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, + IRQNum,Frequency,PeriodicOnly) + CONTROLLER_T *CtlP; Ptr to controller structure + int CtlNum; Controller number + ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. + This list must be in the order the AIOPs will be found on the + controller. Once an AIOP in the list is not found, it is + assumed that there are no more AIOPs on the controller. + int AiopIOListSize; Number of addresses in AiopIOList + int IRQNum; Interrupt Request number. Can be any of the following: + 0: Disable global interrupts + 3: IRQ 3 + 4: IRQ 4 + 5: IRQ 5 + 9: IRQ 9 + 10: IRQ 10 + 11: IRQ 11 + 12: IRQ 12 + 15: IRQ 15 + Byte_t Frequency: A flag identifying the frequency + of the periodic interrupt, can be any one of the following: + FREQ_DIS - periodic interrupt disabled + FREQ_137HZ - 137 Hertz + FREQ_69HZ - 69 Hertz + FREQ_34HZ - 34 Hertz + FREQ_17HZ - 17 Hertz + FREQ_9HZ - 9 Hertz + FREQ_4HZ - 4 Hertz + If IRQNum is set to 0 the Frequency parameter is + overidden, it is forced to a value of FREQ_DIS. + int PeriodicOnly: 1 if all interrupts except the periodic + interrupt are to be blocked. + 0 is both the periodic interrupt and + other channel interrupts are allowed. + If IRQNum is set to 0 the PeriodicOnly parameter is + overidden, it is forced to a value of 0. +Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller + initialization failed. + +Comments: + If periodic interrupts are to be disabled but AIOP interrupts + are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. + + If interrupts are to be completely disabled set IRQNum to 0. + + Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an + invalid combination. + + This function performs initialization of global interrupt modes, + but it does not actually enable global interrupts. To enable + and disable global interrupts use functions sEnGlobalInt() and + sDisGlobalInt(). Enabling of global interrupts is normally not + done until all other initializations are complete. + + Even if interrupts are globally enabled, they must also be + individually enabled for each channel that is to generate + interrupts. + +Warnings: No range checking on any of the parameters is done. + + No context switches are allowed while executing this function. + + After this function all AIOPs on the controller are disabled, + they can be enabled with sEnAiop(). +*/ +static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, + ByteIO_t * AiopIOList, int AiopIOListSize, + WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, + int PeriodicOnly, int altChanRingIndicator, + int UPCIRingInd) +{ + int i; + ByteIO_t io; + + CtlP->AltChanRingIndicator = altChanRingIndicator; + CtlP->UPCIRingInd = UPCIRingInd; + CtlP->CtlNum = CtlNum; + CtlP->CtlID = CTLID_0001; /* controller release 1 */ + CtlP->BusType = isPCI; /* controller release 1 */ + + if (ConfigIO) { + CtlP->isUPCI = 1; + CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL; + CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL; + CtlP->AiopIntrBits = upci_aiop_intr_bits; + } else { + CtlP->isUPCI = 0; + CtlP->PCIIO = + (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC); + CtlP->AiopIntrBits = aiop_intr_bits; + } + + sPCIControllerEOI(CtlP); /* clear EOI if warm init */ + /* Init AIOPs */ + CtlP->NumAiop = 0; + for (i = 0; i < AiopIOListSize; i++) { + io = AiopIOList[i]; + CtlP->AiopIO[i] = (WordIO_t) io; + CtlP->AiopIntChanIO[i] = io + _INT_CHAN; + + CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ + if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ + break; /* done looking for AIOPs */ + + CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ + sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ + sOutB(io + _INDX_DATA, sClockPrescale); + CtlP->NumAiop++; /* bump count of AIOPs */ + } + + if (CtlP->NumAiop == 0) + return (-1); + else + return (CtlP->NumAiop); +} + /* * Called when a PCI card is found. Retrieves and stores model information, * init's aiopic and serial port hardware. @@ -2519,147 +2654,6 @@ static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, return (CtlP->NumAiop); } -#ifdef CONFIG_PCI -/*************************************************************************** -Function: sPCIInitController -Purpose: Initialization of controller global registers and controller - structure. -Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, - IRQNum,Frequency,PeriodicOnly) - CONTROLLER_T *CtlP; Ptr to controller structure - int CtlNum; Controller number - ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. - This list must be in the order the AIOPs will be found on the - controller. Once an AIOP in the list is not found, it is - assumed that there are no more AIOPs on the controller. - int AiopIOListSize; Number of addresses in AiopIOList - int IRQNum; Interrupt Request number. Can be any of the following: - 0: Disable global interrupts - 3: IRQ 3 - 4: IRQ 4 - 5: IRQ 5 - 9: IRQ 9 - 10: IRQ 10 - 11: IRQ 11 - 12: IRQ 12 - 15: IRQ 15 - Byte_t Frequency: A flag identifying the frequency - of the periodic interrupt, can be any one of the following: - FREQ_DIS - periodic interrupt disabled - FREQ_137HZ - 137 Hertz - FREQ_69HZ - 69 Hertz - FREQ_34HZ - 34 Hertz - FREQ_17HZ - 17 Hertz - FREQ_9HZ - 9 Hertz - FREQ_4HZ - 4 Hertz - If IRQNum is set to 0 the Frequency parameter is - overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: 1 if all interrupts except the periodic - interrupt are to be blocked. - 0 is both the periodic interrupt and - other channel interrupts are allowed. - If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of 0. -Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller - initialization failed. - -Comments: - If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. - - If interrupts are to be completely disabled set IRQNum to 0. - - Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an - invalid combination. - - This function performs initialization of global interrupt modes, - but it does not actually enable global interrupts. To enable - and disable global interrupts use functions sEnGlobalInt() and - sDisGlobalInt(). Enabling of global interrupts is normally not - done until all other initializations are complete. - - Even if interrupts are globally enabled, they must also be - individually enabled for each channel that is to generate - interrupts. - -Warnings: No range checking on any of the parameters is done. - - No context switches are allowed while executing this function. - - After this function all AIOPs on the controller are disabled, - they can be enabled with sEnAiop(). -*/ -static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, - ByteIO_t * AiopIOList, int AiopIOListSize, - WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, - int PeriodicOnly, int altChanRingIndicator, - int UPCIRingInd) -{ - int i; - ByteIO_t io; - - CtlP->AltChanRingIndicator = altChanRingIndicator; - CtlP->UPCIRingInd = UPCIRingInd; - CtlP->CtlNum = CtlNum; - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - CtlP->BusType = isPCI; /* controller release 1 */ - - if (ConfigIO) { - CtlP->isUPCI = 1; - CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL; - CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL; - CtlP->AiopIntrBits = upci_aiop_intr_bits; - } else { - CtlP->isUPCI = 0; - CtlP->PCIIO = - (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC); - CtlP->AiopIntrBits = aiop_intr_bits; - } - - sPCIControllerEOI(CtlP); /* clear EOI if warm init */ - /* Init AIOPs */ - CtlP->NumAiop = 0; - for (i = 0; i < AiopIOListSize; i++) { - io = AiopIOList[i]; - CtlP->AiopIO[i] = (WordIO_t) io; - CtlP->AiopIntChanIO[i] = io + _INT_CHAN; - - CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ - if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - break; /* done looking for AIOPs */ - - CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ - sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ - sOutB(io + _INDX_DATA, sClockPrescale); - CtlP->NumAiop++; /* bump count of AIOPs */ - } - - if (CtlP->NumAiop == 0) - return (-1); - else - return (CtlP->NumAiop); -} - -/* Resets the speaker controller on RocketModem II and III devices */ -static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model) -{ - ByteIO_t addr; - - /* RocketModem II speaker control is at the 8th port location of offset 0x40 */ - if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) { - addr = CtlP->AiopIO[0] + 0x4F; - sOutB(addr, 0); - } - - /* RocketModem III speaker control is at the 1st port location of offset 0x80 */ - if ((model == MODEL_UPCI_RM3_8PORT) - || (model == MODEL_UPCI_RM3_4PORT)) { - addr = CtlP->AiopIO[0] + 0x88; - sOutB(addr, 0); - } -} -#endif - /*************************************************************************** Function: sReadAiopID Purpose: Read the AIOP idenfication number directly from an AIOP. diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 46528d57be72..86c00b1c5583 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -2755,7 +2755,7 @@ static void __init serial8250_isa_init_ports(void) if (nr_uarts > UART_NR) nr_uarts = UART_NR; - for (i = 0; i < UART_NR; i++) { + for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; struct uart_port *port = &up->port; @@ -2916,7 +2916,7 @@ static int __init serial8250_console_setup(struct console *co, char *options) * if so, search for the first available port that does have * console support. */ - if (co->index >= UART_NR) + if (co->index >= nr_uarts) co->index = 0; port = &serial8250_ports[co->index].port; if (!port->iobase && !port->membase) @@ -2957,7 +2957,7 @@ int serial8250_find_port(struct uart_port *p) int line; struct uart_port *port; - for (line = 0; line < UART_NR; line++) { + for (line = 0; line < nr_uarts; line++) { port = &serial8250_ports[line].port; if (uart_match_port(p, port)) return line; @@ -3110,7 +3110,7 @@ static int serial8250_remove(struct platform_device *dev) { int i; - for (i = 0; i < UART_NR; i++) { + for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; if (up->port.dev == &dev->dev) @@ -3178,7 +3178,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * /* * First, find a port entry which matches. */ - for (i = 0; i < UART_NR; i++) + for (i = 0; i < nr_uarts; i++) if (uart_match_port(&serial8250_ports[i].port, port)) return &serial8250_ports[i]; @@ -3187,7 +3187,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * * free entry. We look for one which hasn't been previously * used (indicated by zero iobase). */ - for (i = 0; i < UART_NR; i++) + for (i = 0; i < nr_uarts; i++) if (serial8250_ports[i].port.type == PORT_UNKNOWN && serial8250_ports[i].port.iobase == 0) return &serial8250_ports[i]; @@ -3196,7 +3196,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * * That also failed. Last resort is to find any entry which * doesn't have a real port associated with it. */ - for (i = 0; i < UART_NR; i++) + for (i = 0; i < nr_uarts; i++) if (serial8250_ports[i].port.type == PORT_UNKNOWN) return &serial8250_ports[i]; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index beaa283f5cc6..d07b6af3a937 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -338,7 +338,8 @@ static int dw8250_runtime_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); - clk_disable_unprepare(data->clk); + if (!IS_ERR(data->clk)) + clk_disable_unprepare(data->clk); return 0; } @@ -347,7 +348,8 @@ static int dw8250_runtime_resume(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); - clk_prepare_enable(data->clk); + if (!IS_ERR(data->clk)) + clk_prepare_enable(data->clk); return 0; } @@ -367,6 +369,7 @@ MODULE_DEVICE_TABLE(of, dw8250_of_match); static const struct acpi_device_id dw8250_acpi_match[] = { { "INT33C4", 0 }, { "INT33C5", 0 }, + { "80860F0A", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c index 097dff9c08ad..bb91b4713ebd 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_gsc.c @@ -30,6 +30,12 @@ static int __init serial_init_chip(struct parisc_device *dev) unsigned long address; int err; +#ifdef CONFIG_64BIT + extern int iosapic_serial_irq(int cellnum); + if (!dev->irq && (dev->id.sversion == 0xad)) + dev->irq = iosapic_serial_irq(dev->mod_index-1); +#endif + if (!dev->irq) { /* We find some unattached serial ports by walking native * busses. These should be silently ignored. Otherwise, @@ -51,7 +57,8 @@ static int __init serial_init_chip(struct parisc_device *dev) memset(&uart, 0, sizeof(uart)); uart.port.iotype = UPIO_MEM; /* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */ - uart.port.uartclk = 7272727; + uart.port.uartclk = (dev->id.sversion != 0xad) ? + 7272727 : 1843200; uart.port.mapbase = address; uart.port.membase = ioremap_nocache(address, 16); uart.port.irq = dev->irq; @@ -73,6 +80,7 @@ static struct parisc_device_id serial_tbl[] = { { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 }, { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c }, { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d }, + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x000ad }, { 0 } }; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8ab70a620919..e2774f9ecd59 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -332,7 +332,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * dmaengine_slave_config(chan, &rx_conf); uap->dmarx.chan = chan; - if (plat->dma_rx_poll_enable) { + if (plat && plat->dma_rx_poll_enable) { /* Set poll rate if specified. */ if (plat->dma_rx_poll_rate) { uap->dmarx.auto_poll_rate = false; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 147c9e193595..8cdfbd365892 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -761,6 +761,8 @@ static int imx_startup(struct uart_port *port) temp = readl(sport->port.membase + UCR2); temp |= (UCR2_RXEN | UCR2_TXEN); + if (!sport->have_rtscts) + temp |= UCR2_IRTS; writel(temp, sport->port.membase + UCR2); if (USE_IRDA(sport)) { diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index e956377a38fe..65be0c00c4bf 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -707,8 +707,10 @@ static int __init mcf_init(void) if (rc) return rc; rc = platform_driver_register(&mcf_platform_driver); - if (rc) + if (rc) { + uart_unregister_driver(&mcf_driver); return rc; + } return 0; } diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 018bad922554..f51b280f3bf2 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -1497,18 +1497,23 @@ mpc52xx_uart_init(void) if (psc_ops && psc_ops->fifoc_init) { ret = psc_ops->fifoc_init(); if (ret) - return ret; + goto err_init; } ret = platform_driver_register(&mpc52xx_uart_of_driver); if (ret) { printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", __FILE__, ret); - uart_unregister_driver(&mpc52xx_uart_driver); - return ret; + goto err_reg; } return 0; +err_reg: + if (psc_ops && psc_ops->fifoc_uninit) + psc_ops->fifoc_uninit(); +err_init: + uart_unregister_driver(&mpc52xx_uart_driver); + return ret; } static void __exit diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c index 77287c54f331..549c70a2a63e 100644 --- a/drivers/tty/serial/nwpserial.c +++ b/drivers/tty/serial/nwpserial.c @@ -199,7 +199,7 @@ static void nwpserial_shutdown(struct uart_port *port) dcr_write(up->dcr_host, UART_IER, up->ier); /* free irq */ - free_irq(up->port.irq, port); + free_irq(up->port.irq, up); } static int nwpserial_verify_port(struct uart_port *port, diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 30d4f7a783cd..f0b9f6b52b32 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -202,26 +202,6 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up) return pdata->get_context_loss_count(up->dev); } -static void serial_omap_set_forceidle(struct uart_omap_port *up) -{ - struct omap_uart_port_info *pdata = up->dev->platform_data; - - if (!pdata || !pdata->set_forceidle) - return; - - pdata->set_forceidle(up->dev); -} - -static void serial_omap_set_noidle(struct uart_omap_port *up) -{ - struct omap_uart_port_info *pdata = up->dev->platform_data; - - if (!pdata || !pdata->set_noidle) - return; - - pdata->set_noidle(up->dev); -} - static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) { struct omap_uart_port_info *pdata = up->dev->platform_data; @@ -298,8 +278,6 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } - serial_omap_set_forceidle(up); - pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); } @@ -364,7 +342,6 @@ static void serial_omap_start_tx(struct uart_port *port) pm_runtime_get_sync(up->dev); serial_omap_enable_ier_thri(up); - serial_omap_set_noidle(up); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); } diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 074b9194144f..0c8a9fa2be6c 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1166,6 +1166,18 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->tx_irq = ret; ourport->clk = clk_get(&platdev->dev, "uart"); + if (IS_ERR(ourport->clk)) { + pr_err("%s: Controller clock not found\n", + dev_name(&platdev->dev)); + return PTR_ERR(ourport->clk); + } + + ret = clk_prepare_enable(ourport->clk); + if (ret) { + pr_err("uart: clock failed to prepare+enable: %d\n", ret); + clk_put(ourport->clk); + return ret; + } /* Keep all interrupts masked and cleared */ if (s3c24xx_serial_has_interrupt_mask(port)) { @@ -1180,6 +1192,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, /* reset the fifos (and setup the uart) */ s3c24xx_serial_resetport(port, cfg); + clk_disable_unprepare(ourport->clk); return 0; } @@ -1803,6 +1816,7 @@ static int __init s3c24xx_serial_modinit(void) static void __exit s3c24xx_serial_modexit(void) { + platform_driver_unregister(&samsung_serial_driver); uart_unregister_driver(&s3c24xx_uart_drv); } diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index fbd447b390f7..740202d8a5c4 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -779,7 +779,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ con_set_default_unimap(vc); vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); if (!vc->vc_screenbuf) { - tty_port_destroy(&vc->port); kfree(vc); vc_cons[currcons].d = NULL; return -ENOMEM; @@ -986,26 +985,25 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws) return ret; } -void vc_deallocate(unsigned int currcons) +struct vc_data *vc_deallocate(unsigned int currcons) { + struct vc_data *vc = NULL; + WARN_CONSOLE_UNLOCKED(); if (vc_cons_allocated(currcons)) { - struct vc_data *vc = vc_cons[currcons].d; - struct vt_notifier_param param = { .vc = vc }; + struct vt_notifier_param param; + param.vc = vc = vc_cons[currcons].d; atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m); vcs_remove_sysfs(currcons); vc->vc_sw->con_deinit(vc); put_pid(vc->vt_pid); module_put(vc->vc_sw->owner); kfree(vc->vc_screenbuf); - if (currcons >= MIN_NR_CONSOLES) { - tty_port_destroy(&vc->port); - kfree(vc); - } vc_cons[currcons].d = NULL; } + return vc; } /* diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 98ff1735eafc..2bd78e2ac8ec 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -283,6 +283,48 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_ return 0; } +/* deallocate a single console, if possible (leave 0) */ +static int vt_disallocate(unsigned int vc_num) +{ + struct vc_data *vc = NULL; + int ret = 0; + + console_lock(); + if (VT_BUSY(vc_num)) + ret = -EBUSY; + else if (vc_num) + vc = vc_deallocate(vc_num); + console_unlock(); + + if (vc && vc_num >= MIN_NR_CONSOLES) { + tty_port_destroy(&vc->port); + kfree(vc); + } + + return ret; +} + +/* deallocate all unused consoles, but leave 0 */ +static void vt_disallocate_all(void) +{ + struct vc_data *vc[MAX_NR_CONSOLES]; + int i; + + console_lock(); + for (i = 1; i < MAX_NR_CONSOLES; i++) + if (!VT_BUSY(i)) + vc[i] = vc_deallocate(i); + else + vc[i] = NULL; + console_unlock(); + + for (i = 1; i < MAX_NR_CONSOLES; i++) { + if (vc[i] && i >= MIN_NR_CONSOLES) { + tty_port_destroy(&vc[i]->port); + kfree(vc[i]); + } + } +} /* @@ -769,24 +811,10 @@ int vt_ioctl(struct tty_struct *tty, ret = -ENXIO; break; } - if (arg == 0) { - /* deallocate all unused consoles, but leave 0 */ - console_lock(); - for (i=1; i<MAX_NR_CONSOLES; i++) - if (! VT_BUSY(i)) - vc_deallocate(i); - console_unlock(); - } else { - /* deallocate a single console, if possible */ - arg--; - if (VT_BUSY(arg)) - ret = -EBUSY; - else if (arg) { /* leave 0 */ - console_lock(); - vc_deallocate(arg); - console_unlock(); - } - } + if (arg == 0) + vt_disallocate_all(); + else + ret = vt_disallocate(--arg); break; case VT_RESIZE: diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index e92eeaf251fe..5295be0342c1 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -45,6 +45,7 @@ config UIO_PDRV_GENIRQ config UIO_DMEM_GENIRQ tristate "Userspace platform driver with generic irq and dynamic memory" + depends on HAS_DMA help Platform driver for Userspace I/O devices, including generic interrupt handling code. Shared interrupts are not supported. diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index b7eb86ad6bf2..8a7eb77233b4 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -686,7 +686,8 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ { int ret, len; __le32 *buf; - int offb, offd; + int offb; + unsigned int offd; const int stride = CMD_PACKET_SIZE / (4 * 2) - 1; int buflen = ((size - 1) / stride + 1 + size * 2) * 4; diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 608a2aeb400c..b2df442eb3e5 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -20,7 +20,7 @@ config USB_CHIPIDEA_UDC config USB_CHIPIDEA_HOST bool "ChipIdea host controller" depends on USB=y || USB=USB_CHIPIDEA - depends on USB_EHCI_HCD + depends on USB_EHCI_HCD=y select USB_EHCI_ROOT_HUB_TT help Say Y here to enable host controller functionality of the diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c index 8faec9dbbb84..73f9d5f15adb 100644 --- a/drivers/usb/chipidea/ci13xxx_imx.c +++ b/drivers/usb/chipidea/ci13xxx_imx.c @@ -173,17 +173,10 @@ static int ci13xxx_imx_probe(struct platform_device *pdev) ci13xxx_imx_platdata.phy = data->phy; - if (!pdev->dev.dma_mask) { - pdev->dev.dma_mask = devm_kzalloc(&pdev->dev, - sizeof(*pdev->dev.dma_mask), GFP_KERNEL); - if (!pdev->dev.dma_mask) { - ret = -ENOMEM; - dev_err(&pdev->dev, "Failed to alloc dma_mask!\n"); - goto err; - } - *pdev->dev.dma_mask = DMA_BIT_MASK(32); - dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask); - } + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); if (usbmisc_ops && usbmisc_ops->init) { ret = usbmisc_ops->init(&pdev->dev); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 49b098bedf9b..475c9c114689 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -276,8 +276,9 @@ static void ci_role_work(struct work_struct *work) ci_role_stop(ci); ci_role_start(ci, role); - enable_irq(ci->irq); } + + enable_irq(ci->irq); } static irqreturn_t ci_irq(int irq, void *data) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 519ead2443c5..b501346484ae 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1678,8 +1678,11 @@ static int udc_start(struct ci13xxx *ci) ci->gadget.ep0 = &ci->ep0in->ep; - if (ci->global_phy) + if (ci->global_phy) { ci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); + if (IS_ERR(ci->transceiver)) + ci->transceiver = NULL; + } if (ci->platdata->flags & CI13XXX_REQUIRE_TRANSCEIVER) { if (ci->transceiver == NULL) { @@ -1694,7 +1697,7 @@ static int udc_start(struct ci13xxx *ci) goto put_transceiver; } - if (!IS_ERR_OR_NULL(ci->transceiver)) { + if (ci->transceiver) { retval = otg_set_peripheral(ci->transceiver->otg, &ci->gadget); if (retval) @@ -1711,7 +1714,7 @@ static int udc_start(struct ci13xxx *ci) return retval; remove_trans: - if (!IS_ERR_OR_NULL(ci->transceiver)) { + if (ci->transceiver) { otg_set_peripheral(ci->transceiver->otg, NULL); if (ci->global_phy) usb_put_phy(ci->transceiver); @@ -1719,7 +1722,7 @@ remove_trans: dev_err(dev, "error = %i\n", retval); put_transceiver: - if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy) + if (ci->transceiver && ci->global_phy) usb_put_phy(ci->transceiver); destroy_eps: destroy_eps(ci); @@ -1747,7 +1750,7 @@ static void udc_stop(struct ci13xxx *ci) dma_pool_destroy(ci->td_pool); dma_pool_destroy(ci->qh_pool); - if (!IS_ERR_OR_NULL(ci->transceiver)) { + if (ci->transceiver) { otg_set_peripheral(ci->transceiver->otg, NULL); if (ci->global_phy) usb_put_phy(ci->transceiver); diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 8772b3659296..db535b0aa172 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -51,7 +51,7 @@ config USB_DYNAMIC_MINORS config USB_OTG bool "OTG support" - depends on USB_SUSPEND + depends on PM_RUNTIME default n help The most notable feature of USB OTG is support for a diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index caefc800f298..c88c4fb9459d 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1287,9 +1287,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, goto error; } for (totlen = u = 0; u < uurb->number_of_packets; u++) { - /* arbitrary limit, - * sufficient for USB 2.0 high-bandwidth iso */ - if (isopkt[u].length > 8192) { + /* + * arbitrary limit need for USB 3.0 + * bMaxBurst (0~15 allowed, 1~16 packets) + * bmAttributes (bit 1:0, mult 0~2, 1~3 packets) + * sizemax: 1024 * 16 * 3 = 49152 + */ + if (isopkt[u].length > 49152) { ret = -EINVAL; goto error; } diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ab5638d9c707..a63598895077 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -88,6 +88,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Edirol SD-20 */ { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Alcor Micro Corp. Hub */ + { USB_DEVICE(0x058f, 0x9254), .driver_info = USB_QUIRK_RESET_RESUME }, + /* appletouch */ { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index ea5ee9c21c35..757aa18027d0 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -19,21 +19,21 @@ choice config USB_DWC3_HOST bool "Host only mode" - depends on USB + depends on USB=y || USB=USB_DWC3 help Select this when you want to use DWC3 in host mode only, thereby the gadget feature will be regressed. config USB_DWC3_GADGET bool "Gadget only mode" - depends on USB_GADGET + depends on USB_GADGET=y || USB_GADGET=USB_DWC3 help Select this when you want to use DWC3 in gadget mode only, thereby the host feature will be regressed. config USB_DWC3_DUAL_ROLE bool "Dual Role mode" - depends on (USB && USB_GADGET) + depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3)) help This is the default mode of working of DWC3 controller where both host and gadget features are enabled. diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index a8afe6e26621..8ce9d7fd6cfc 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -95,8 +95,6 @@ static int dwc3_exynos_remove_child(struct device *dev, void *unused) return 0; } -static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32); - static int dwc3_exynos_probe(struct platform_device *pdev) { struct dwc3_exynos *exynos; @@ -118,7 +116,9 @@ static int dwc3_exynos_probe(struct platform_device *pdev) * Once we move to full device tree support this will vanish off. */ if (!dev->dma_mask) - dev->dma_mask = &dwc3_exynos_dma_mask; + dev->dma_mask = &dev->coherent_dma_mask; + if (!dev->coherent_dma_mask) + dev->coherent_dma_mask = DMA_BIT_MASK(32); platform_set_drvdata(pdev, exynos); @@ -164,9 +164,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev) { struct dwc3_exynos *exynos = platform_get_drvdata(pdev); + device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); platform_device_unregister(exynos->usb2_phy); platform_device_unregister(exynos->usb3_phy); - device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); clk_disable_unprepare(exynos->clk); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 227d4a7acad7..eba9e2baf32b 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -196,9 +196,9 @@ static void dwc3_pci_remove(struct pci_dev *pci) { struct dwc3_pci *glue = pci_get_drvdata(pci); + platform_device_unregister(glue->dwc3); platform_device_unregister(glue->usb2_phy); platform_device_unregister(glue->usb3_phy); - platform_device_unregister(glue->dwc3); pci_set_drvdata(pci, NULL); pci_disable_device(pci); } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2b6e7e001207..b5e5b35df49c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1706,11 +1706,19 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) dep = dwc->eps[epnum]; if (!dep) continue; - - dwc3_free_trb_pool(dep); - - if (epnum != 0 && epnum != 1) + /* + * Physical endpoints 0 and 1 are special; they form the + * bi-directional USB endpoint 0. + * + * For those two physical endpoints, we don't allocate a TRB + * pool nor do we add them the endpoints list. Due to that, we + * shouldn't do these two operations otherwise we would end up + * with all sorts of bugs when removing dwc3.ko. + */ + if (epnum != 0 && epnum != 1) { + dwc3_free_trb_pool(dep); list_del(&dep->endpoint.ep_list); + } kfree(dep); } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 83300d94a893..f41aa0d0c414 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -146,7 +146,6 @@ config USB_LPC32XX depends on ARCH_LPC32XX depends on USB_PHY select USB_ISP1301 - select USB_OTG_UTILS help This option selects the USB device controller in the LPC32xx SoC. diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index f2a970f75bfa..5a5128a226f7 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1992,8 +1992,6 @@ err_map_regs: err_get_hclk: clk_put(pclk); - platform_set_drvdata(pdev, NULL); - return ret; } diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index 792297798147..fd24cb4540a4 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -2410,7 +2410,6 @@ static int bcm63xx_udc_remove(struct platform_device *pdev) usb_del_gadget_udc(&udc->gadget); BUG_ON(udc->driver); - platform_set_drvdata(pdev, NULL); bcm63xx_uninit_udc_hw(udc); return 0; diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 3d5cfc9c2c78..80e7f75a56c7 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -821,8 +821,10 @@ static int configfs_composite_bind(struct usb_gadget *gadget, gi->gstrings[i] = NULL; s = usb_gstrings_attach(&gi->cdev, gi->gstrings, USB_GADGET_FIRST_AVAIL_IDX); - if (IS_ERR(s)) + if (IS_ERR(s)) { + ret = PTR_ERR(s); goto err_comp_cleanup; + } gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id; gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id; @@ -847,8 +849,10 @@ static int configfs_composite_bind(struct usb_gadget *gadget, } cfg->gstrings[i] = NULL; s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1); - if (IS_ERR(s)) + if (IS_ERR(s)) { + ret = PTR_ERR(s); goto err_comp_cleanup; + } c->iConfiguration = s[0].id; } diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index a792e322f4f1..c588e8e486e5 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -1001,7 +1001,6 @@ static int dummy_udc_remove(struct platform_device *pdev) struct dummy *dum = platform_get_drvdata(pdev); usb_del_gadget_udc(&dum->gadget); - platform_set_drvdata(pdev, NULL); device_remove_file(&dum->gadget.dev, &dev_attr_function); return 0; } @@ -2661,8 +2660,10 @@ static int __init init(void) } for (i = 0; i < mod_data.num; i++) { dum[i] = kzalloc(sizeof(struct dummy), GFP_KERNEL); - if (!dum[i]) + if (!dum[i]) { + retval = -ENOMEM; goto err_add_pdata; + } retval = platform_device_add_data(the_hcd_pdev[i], &dum[i], sizeof(void *)); if (retval) diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index d893d6929079..abf8a31ae146 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -816,6 +816,7 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f) * @c: the configuration to support the network link * @ethaddr: a buffer in which the ethernet address of the host side * side of the link was recorded + * @dev: eth_dev structure * Context: single threaded during gadget setup * * Returns zero on success, else negative errno. diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 185d6f5e4e4d..7be04b342494 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -373,6 +373,7 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f) * @c: the configuration to support the network link * @ethaddr: a buffer in which the ethernet address of the host side * side of the link was recorded + * @dev: eth_dev structure * Context: single threaded during gadget setup * * Returns zero on success, else negative errno. diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index c7468b6c07b0..03c1fb686644 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -456,8 +456,6 @@ static int snd_uac2_remove(struct platform_device *pdev) { struct snd_card *card = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); - if (card) return snd_card_free(card); diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index cec8871b77f9..b8632d40f8bf 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1461,8 +1461,10 @@ static int __init fusb300_probe(struct platform_device *pdev) fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep, GFP_KERNEL); - if (fusb300->ep0_req == NULL) + if (fusb300->ep0_req == NULL) { + ret = -ENOMEM; goto clean_up3; + } init_controller(fusb300); ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget); diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index b5cebd6b0d7a..9b2d24e4c95f 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1511,8 +1511,6 @@ static int __exit imx_udc_remove(struct platform_device *pdev) if (pdata->exit) pdata->exit(&pdev->dev); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 866ef0999247..51cfe72da5bb 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1660,8 +1660,10 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->epaddr2ep[0] = &m66592->ep[0]; m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL); - if (m66592->ep0_req == NULL) + if (m66592->ep0_req == NULL) { + ret = -ENOMEM; goto clean_up3; + } m66592->ep0_req->complete = nop_completion; init_controller(m66592); diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index ef47495dec8f..95c531d5aa4f 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -2236,7 +2236,6 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev) dev->transceiver = NULL; } - platform_set_drvdata(pdev, NULL); the_controller = NULL; return 0; } diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 0b742d171843..7ff7d9cf2061 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1977,8 +1977,10 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597->ep0_req = r8a66597_alloc_request(&r8a66597->ep[0].ep, GFP_KERNEL); - if (r8a66597->ep0_req == NULL) + if (r8a66597->ep0_req == NULL) { + ret = -ENOMEM; goto clean_up3; + } r8a66597->ep0_req->complete = nop_completion; ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget); diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index a3cdc32115d5..af22f24046b2 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -437,7 +437,7 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, if (hs_req->req.length == 0) return; - usb_gadget_unmap_request(&hsotg->gadget, hs_req, hs_ep->dir_in); + usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); } /** diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index d0e75e1b3ccb..09c4f70c93c4 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1851,6 +1851,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) irq = gpio_to_irq(udc_info->vbus_pin); if (irq < 0) { dev_err(dev, "no irq for gpio vbus pin\n"); + retval = irq; goto err_gpio_claim; } @@ -1948,8 +1949,6 @@ static int s3c2410_udc_remove(struct platform_device *pdev) iounmap(base_addr); release_mem_region(rsrc_start, rsrc_len); - platform_set_drvdata(pdev, NULL); - if (!IS_ERR(udc_clock) && udc_clock != NULL) { clk_disable(udc_clock); clk_put(udc_clock); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 2cd6262e8b71..0deb9d6cde26 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -284,12 +284,16 @@ static int __init zero_bind(struct usb_composite_dev *cdev) ss_opts->bulk_buflen = gzero_options.bulk_buflen; func_ss = usb_get_function(func_inst_ss); - if (IS_ERR(func_ss)) + if (IS_ERR(func_ss)) { + status = PTR_ERR(func_ss); goto err_put_func_inst_ss; + } func_inst_lb = usb_get_function_instance("Loopback"); - if (IS_ERR(func_inst_lb)) + if (IS_ERR(func_inst_lb)) { + status = PTR_ERR(func_inst_lb); goto err_put_func_ss; + } lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst); lb_opts->bulk_buflen = gzero_options.bulk_buflen; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index de94f2699063..344d5e2f87d7 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -507,7 +507,7 @@ endif # USB_OHCI_HCD config USB_UHCI_HCD tristate "UHCI HCD (most Intel and VIA) support" - depends on PCI || SPARC_LEON || ARCH_VT8500 + depends on PCI || USB_UHCI_SUPPORT_NON_PCI_HC ---help--- The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB @@ -524,26 +524,19 @@ config USB_UHCI_HCD config USB_UHCI_SUPPORT_NON_PCI_HC bool - depends on USB_UHCI_HCD - default y if (SPARC_LEON || ARCH_VT8500) + default y if (SPARC_LEON || USB_UHCI_PLATFORM) config USB_UHCI_PLATFORM - bool "Generic UHCI Platform Driver support" - depends on USB_UHCI_SUPPORT_NON_PCI_HC + bool default y if ARCH_VT8500 - ---help--- - Enable support for generic UHCI platform devices that require no - additional configuration. config USB_UHCI_BIG_ENDIAN_MMIO bool - depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON - default y + default y if SPARC_LEON config USB_UHCI_BIG_ENDIAN_DESC bool - depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON - default y + default y if SPARC_LEON config USB_FHCI_HCD tristate "Freescale QE USB Host Controller support" diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 66420097c242..02f4611faa62 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -63,8 +63,6 @@ static void atmel_stop_ehci(struct platform_device *pdev) /*-------------------------------------------------------------------------*/ -static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32); - static int ehci_atmel_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd; @@ -93,7 +91,9 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev) * Once we have dma capability bindings this can go away. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &at91_ehci_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 312fc10da3c7..246e124e6ac5 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1286,23 +1286,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_sead3_driver #endif -#if !IS_ENABLED(CONFIG_USB_EHCI_PCI) && \ - !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \ - !IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \ - !IS_ENABLED(CONFIG_USB_EHCI_MXC) && \ - !IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \ - !IS_ENABLED(CONFIG_USB_EHCI_HCD_ORION) && \ - !IS_ENABLED(CONFIG_USB_EHCI_HCD_SPEAR) && \ - !IS_ENABLED(CONFIG_USB_EHCI_S5P) && \ - !IS_ENABLED(CONFIG_USB_EHCI_HCD_AT91) && \ - !IS_ENABLED(CONFIG_USB_EHCI_MSM) && \ - !defined(PLATFORM_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && \ - !defined(OF_PLATFORM_DRIVER) && \ - !defined(XILINX_OF_PLATFORM_DRIVER) -#error "missing bus glue for ehci-hcd" -#endif - static int __init ehci_hcd_init(void) { int retval = 0; diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 3d1491b5f360..16d7150e8557 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -90,8 +90,6 @@ static const struct ehci_driver_overrides ehci_omap_overrides __initdata = { .extra_priv_size = sizeof(struct omap_hcd), }; -static u64 omap_ehci_dma_mask = DMA_BIT_MASK(32); - /** * ehci_hcd_omap_probe - initialize TI-based HCDs * @@ -146,8 +144,10 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &omap_ehci_dma_mask; + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + if (!dev->coherent_dma_mask) + dev->coherent_dma_mask = DMA_BIT_MASK(32); hcd = usb_create_hcd(&ehci_omap_hc_driver, dev, dev_name(dev)); diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 54c579485150..efbc588b48c5 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -137,8 +137,6 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, } } -static u64 ehci_orion_dma_mask = DMA_BIT_MASK(32); - static int ehci_orion_drv_probe(struct platform_device *pdev) { struct orion_ehci_data *pd = pdev->dev.platform_data; @@ -183,7 +181,9 @@ static int ehci_orion_drv_probe(struct platform_device *pdev) * now. Once we have dma capability bindings this can go away. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &ehci_orion_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); if (!request_mem_region(res->start, resource_size(res), ehci_orion_hc_driver.description)) { diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 635775278c7f..379037f51a2f 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -71,8 +71,6 @@ static void s5p_setup_vbus_gpio(struct platform_device *pdev) dev_err(dev, "can't request ehci vbus gpio %d", gpio); } -static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32); - static int s5p_ehci_probe(struct platform_device *pdev) { struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; @@ -90,7 +88,7 @@ static int s5p_ehci_probe(struct platform_device *pdev) * Once we move to full device tree support this will vanish off. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &ehci_s5p_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; if (!pdev->dev.coherent_dma_mask) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); @@ -107,6 +105,7 @@ static int s5p_ehci_probe(struct platform_device *pdev) if (IS_ERR(phy)) { /* Fallback to pdata */ if (!pdata) { + usb_put_hcd(hcd); dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); return -EPROBE_DEFER; } else { diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index acff5b8f6e89..f80d0330d548 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -213,7 +213,7 @@ static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask) } static const unsigned char -max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 125, 25 }; +max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; /* carryover low/fullspeed bandwidth that crosses uframe boundries */ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) @@ -646,6 +646,10 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) /* reschedule QH iff another request is queued */ if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) { rc = qh_schedule(ehci, qh); + if (rc == 0) { + qh_refresh(ehci, qh); + qh_link_periodic(ehci, qh); + } /* An error here likely indicates handshake failure * or no space left in the schedule. Neither fault @@ -653,9 +657,10 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) * * FIXME kill the now-dysfunctional queued urbs */ - if (rc != 0) + else { ehci_err(ehci, "can't reschedule qh %p, err %d\n", qh, rc); + } } /* maybe turn off periodic schedule */ diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index 61ecfb3d52f5..bd3e5cbc6240 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -58,8 +58,6 @@ static int ehci_spear_drv_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend, ehci_spear_drv_resume); -static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32); - static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd ; @@ -84,7 +82,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) * Once we have dma capability bindings this can go away. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &spear_ehci_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); usbh_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(usbh_clk)) { diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index e3eddc31ac83..59d111bf44a9 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -637,8 +637,6 @@ static void tegra_ehci_set_phcd(struct usb_phy *x, bool enable) writel(val, base + TEGRA_USB_PORTSC1); } -static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32); - static int tegra_ehci_probe(struct platform_device *pdev) { struct resource *res; @@ -661,7 +659,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) * Once we have dma capability bindings this can go away. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &tegra_ehci_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); setup_vbus_gpio(pdev, pdata); diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 125e261f5bfc..2facee53eab1 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1739,7 +1739,7 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) int retval = 1; unsigned long flags; - /* if !USB_SUSPEND, root hub timers won't get shut down ... */ + /* if !PM_RUNTIME, root hub timers won't get shut down ... */ if (!HC_IS_RUNNING(hcd->state)) return 0; diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index bbb791bd7617..a13709ee4e5d 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -373,8 +373,10 @@ static int isp1760_plat_probe(struct platform_device *pdev) irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { pr_warning("isp1760: IRQ resource not available\n"); - return -ENODEV; + ret = -ENODEV; + goto cleanup; } + irqflags |= irq_res->flags & IRQF_TRIGGER_MASK; if (priv) { diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index a0cb44f0e724..2ee1496dbc1d 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -504,8 +504,6 @@ static const struct of_device_id at91_ohci_dt_ids[] = { MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids); -static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32); - static int ohci_at91_of_init(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -522,7 +520,9 @@ static int ohci_at91_of_init(struct platform_device *pdev) * Once we have dma capability bindings this can go away. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &at91_ohci_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 07592c00af26..b0b542c14e31 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -98,8 +98,6 @@ static const struct hc_driver exynos_ohci_hc_driver = { .start_port_reset = ohci_start_port_reset, }; -static u64 ohci_exynos_dma_mask = DMA_BIT_MASK(32); - static int exynos_ohci_probe(struct platform_device *pdev) { struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; @@ -117,7 +115,7 @@ static int exynos_ohci_probe(struct platform_device *pdev) * Once we move to full device tree support this will vanish off. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &ohci_exynos_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; if (!pdev->dev.coherent_dma_mask) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 9e6de9586ae4..fc627fd54116 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -233,14 +233,14 @@ static int ohci_urb_enqueue ( urb->start_frame = frame; } } else if (ed->type == PIPE_ISOCHRONOUS) { - u16 next = ohci_frame_no(ohci) + 2; + u16 next = ohci_frame_no(ohci) + 1; u16 frame = ed->last_iso + ed->interval; /* Behind the scheduling threshold? */ if (unlikely(tick_before(frame, next))) { /* USB_ISO_ASAP: Round up to the first available slot */ - if (urb->transfer_flags & URB_ISO_ASAP) + if (urb->transfer_flags & URB_ISO_ASAP) { frame += (next - frame + ed->interval - 1) & -ed->interval; @@ -248,21 +248,25 @@ static int ohci_urb_enqueue ( * Not ASAP: Use the next slot in the stream. If * the entire URB falls before the threshold, fail. */ - else if (tick_before(frame + ed->interval * + } else { + if (tick_before(frame + ed->interval * (urb->number_of_packets - 1), next)) { - retval = -EXDEV; - usb_hcd_unlink_urb_from_ep(hcd, urb); - goto fail; - } + retval = -EXDEV; + usb_hcd_unlink_urb_from_ep(hcd, urb); + goto fail; + } - /* - * Some OHCI hardware doesn't handle late TDs - * correctly. After retiring them it proceeds to - * the next ED instead of the next TD. Therefore - * we have to omit the late TDs entirely. - */ - urb_priv->td_cnt = DIV_ROUND_UP(next - frame, - ed->interval); + /* + * Some OHCI hardware doesn't handle late TDs + * correctly. After retiring them it proceeds + * to the next ED instead of the next TD. + * Therefore we have to omit the late TDs + * entirely. + */ + urb_priv->td_cnt = DIV_ROUND_UP( + (u16) (next - frame), + ed->interval); + } } urb->start_frame = frame; } diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index f303cb04c2dd..5d7eb72c5064 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -223,8 +223,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) isp1301_i2c_client = isp1301_get_client(isp1301_node); if (!isp1301_i2c_client) { - ret = -EPROBE_DEFER; - goto out; + return -EPROBE_DEFER; } pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); @@ -234,7 +233,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) if (usb_disabled()) { dev_err(&pdev->dev, "USB is disabled\n"); ret = -ENODEV; - goto out; + goto fail_disable; } /* Enable AHB slave USB clock, needed for further USB clock control */ @@ -245,19 +244,19 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) if (IS_ERR(usb_pll_clk)) { dev_err(&pdev->dev, "failed to acquire USB PLL\n"); ret = PTR_ERR(usb_pll_clk); - goto out1; + goto fail_pll; } ret = clk_enable(usb_pll_clk); if (ret < 0) { dev_err(&pdev->dev, "failed to start USB PLL\n"); - goto out2; + goto fail_pllen; } ret = clk_set_rate(usb_pll_clk, 48000); if (ret < 0) { dev_err(&pdev->dev, "failed to set USB clock rate\n"); - goto out3; + goto fail_rate; } /* Enable USB device clock */ @@ -265,13 +264,13 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) if (IS_ERR(usb_dev_clk)) { dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n"); ret = PTR_ERR(usb_dev_clk); - goto out4; + goto fail_dev; } ret = clk_enable(usb_dev_clk); if (ret < 0) { dev_err(&pdev->dev, "failed to start USB DEV Clock\n"); - goto out5; + goto fail_deven; } /* Enable USB otg clocks */ @@ -279,7 +278,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) if (IS_ERR(usb_otg_clk)) { dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n"); ret = PTR_ERR(usb_otg_clk); - goto out6; + goto fail_otg; } __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL); @@ -287,7 +286,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) ret = clk_enable(usb_otg_clk); if (ret < 0) { dev_err(&pdev->dev, "failed to start USB DEV Clock\n"); - goto out7; + goto fail_otgen; } isp1301_configure(); @@ -296,14 +295,14 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) if (!hcd) { dev_err(&pdev->dev, "Failed to allocate HC buffer\n"); ret = -ENOMEM; - goto out8; + goto fail_hcd; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); - goto out8; + goto fail_resource; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); @@ -311,7 +310,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = -ENXIO; - goto out8; + goto fail_resource; } nxp_start_hc(); @@ -325,23 +324,24 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev) return ret; nxp_stop_hc(); -out8: +fail_resource: usb_put_hcd(hcd); -out7: +fail_hcd: clk_disable(usb_otg_clk); -out6: +fail_otgen: clk_put(usb_otg_clk); -out5: +fail_otg: clk_disable(usb_dev_clk); -out4: +fail_deven: clk_put(usb_dev_clk); -out3: +fail_dev: +fail_rate: clk_disable(usb_pll_clk); -out2: +fail_pllen: clk_put(usb_pll_clk); -out1: +fail_pll: +fail_disable: isp1301_i2c_client = NULL; -out: return ret; } diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c index ddfc31427bc0..8663851c8d8e 100644 --- a/drivers/usb/host/ohci-omap3.c +++ b/drivers/usb/host/ohci-omap3.c @@ -114,8 +114,6 @@ static const struct hc_driver ohci_omap3_hc_driver = { /*-------------------------------------------------------------------------*/ -static u64 omap_ohci_dma_mask = DMA_BIT_MASK(32); - /* * configure so an HC device and id are always provided * always called with process context; sleeping is OK @@ -168,8 +166,10 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &omap_ohci_dma_mask; + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + if (!dev->coherent_dma_mask) + dev->coherent_dma_mask = DMA_BIT_MASK(32); hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev, dev_name(dev)); diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index efe71f3ca477..279b2ef17411 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -282,8 +282,6 @@ static const struct of_device_id pxa_ohci_dt_ids[] = { MODULE_DEVICE_TABLE(of, pxa_ohci_dt_ids); -static u64 pxa_ohci_dma_mask = DMA_BIT_MASK(32); - static int ohci_pxa_of_init(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -298,7 +296,9 @@ static int ohci_pxa_of_init(struct platform_device *pdev) * Once we have dma capability bindings this can go away. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &pxa_ohci_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 9020bf0e2eca..3e19e0170d11 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -91,8 +91,6 @@ static const struct hc_driver ohci_spear_hc_driver = { .start_port_reset = ohci_start_port_reset, }; -static u64 spear_ohci_dma_mask = DMA_BIT_MASK(32); - static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) { const struct hc_driver *driver = &ohci_spear_hc_driver; @@ -114,7 +112,9 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) * Once we have dma capability bindings this can go away. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &spear_ohci_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); usbh_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(usbh_clk)) { diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 4f0f0339532f..0f401dbfaf07 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -3084,7 +3084,7 @@ static int oxu_hub_status_data(struct usb_hcd *hcd, char *buf) int ports, i, retval = 1; unsigned long flags; - /* if !USB_SUSPEND, root hub timers won't get shut down ... */ + /* if !PM_RUNTIME, root hub timers won't get shut down ... */ if (!HC_IS_RUNNING(hcd->state)) return 0; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index ad4483efb6d6..b2ec7fe758dd 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -22,7 +22,7 @@ * and usb-storage. * * TODO: - * - usb suspend/resume triggered by sl811 (with USB_SUSPEND) + * - usb suspend/resume triggered by sl811 (with PM_RUNTIME) * - various issues noted in the code * - performance work; use both register banks; ... * - use urb->iso_frame_desc[] with ISO transfers diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index f87bee6d2789..9189bc984c98 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -225,7 +225,8 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) /* auto-stop if nothing connected for 1 second */ if (any_ports_active(uhci)) uhci->rh_state = UHCI_RH_RUNNING; - else if (time_after_eq(jiffies, uhci->auto_stop_time)) + else if (time_after_eq(jiffies, uhci->auto_stop_time) && + !uhci->wait_for_hp) suspend_rh(uhci, UHCI_RH_AUTO_STOPPED); break; diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index 8c4dace4b14a..f1db61ada6a8 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -60,8 +60,6 @@ static const struct hc_driver uhci_platform_hc_driver = { .hub_control = uhci_hub_control, }; -static u64 platform_uhci_dma_mask = DMA_BIT_MASK(32); - static int uhci_hcd_platform_probe(struct platform_device *pdev) { struct usb_hcd *hcd; @@ -78,7 +76,9 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) * Once we have dma capability bindings this can go away. */ if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &platform_uhci_dma_mask; + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + if (!pdev->dev.coherent_dma_mask) + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev, pdev->name); diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index f0976d8190bc..041c6ddb695c 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1287,7 +1287,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, return -EINVAL; /* Can't change the period */ } else { - next = uhci->frame_number + 2; + next = uhci->frame_number + 1; /* Find the next unused frame */ if (list_empty(&qh->queue)) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 965b539bc474..fbf75e57628b 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1423,15 +1423,17 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, ep_ctx->ep_info2 |= cpu_to_le32(xhci_get_endpoint_type(udev, ep)); /* Set the max packet size and max burst */ + max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)); + max_burst = 0; switch (udev->speed) { case USB_SPEED_SUPER: - max_packet = usb_endpoint_maxp(&ep->desc); - ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet)); /* dig out max burst from ep companion desc */ - max_packet = ep->ss_ep_comp.bMaxBurst; - ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet)); + max_burst = ep->ss_ep_comp.bMaxBurst; break; case USB_SPEED_HIGH: + /* Some devices get this wrong */ + if (usb_endpoint_xfer_bulk(&ep->desc)) + max_packet = 512; /* bits 11:12 specify the number of additional transaction * opportunities per microframe (USB 2.0, section 9.6.6) */ @@ -1439,17 +1441,16 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, usb_endpoint_xfer_int(&ep->desc)) { max_burst = (usb_endpoint_maxp(&ep->desc) & 0x1800) >> 11; - ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_burst)); } - /* Fall through */ + break; case USB_SPEED_FULL: case USB_SPEED_LOW: - max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)); - ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet)); break; default: BUG(); } + ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet) | + MAX_BURST(max_burst)); max_esit_payload = xhci_get_max_esit_payload(xhci, udev, ep); ep_ctx->tx_info = cpu_to_le32(MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload)); @@ -1826,6 +1827,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } spin_unlock_irqrestore(&xhci->lock, flags); + if (!xhci->rh_bw) + goto no_bw; + num_ports = HCS_MAX_PORTS(xhci->hcs_params1); for (i = 0; i < num_ports; i++) { struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table; @@ -1844,6 +1848,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } } +no_bw: xhci->num_usb2_ports = 0; xhci->num_usb3_ports = 0; xhci->num_active_eps = 0; @@ -2255,6 +2260,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) u32 page_size, temp; int i; + INIT_LIST_HEAD(&xhci->lpm_failed_devs); + INIT_LIST_HEAD(&xhci->cancel_cmd_list); + page_size = xhci_readl(xhci, &xhci->op_regs->page_size); xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size); for (i = 0; i < 16; i++) { @@ -2333,7 +2341,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags); if (!xhci->cmd_ring) goto fail; - INIT_LIST_HEAD(&xhci->cancel_cmd_list); xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); xhci_dbg(xhci, "First segment DMA is 0x%llx\n", (unsigned long long)xhci->cmd_ring->first_seg->dma); @@ -2444,8 +2451,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) if (xhci_setup_port_arrays(xhci, flags)) goto fail; - INIT_LIST_HEAD(&xhci->lpm_failed_devs); - /* Enable USB 3.0 device notifications for function remote wake, which * is necessary for allowing USB 3.0 devices to do remote wakeup from * U3 (device suspend). diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 1a30c380043c..cc24e39b97d5 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -221,6 +221,14 @@ static void xhci_pci_remove(struct pci_dev *dev) static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + /* + * Systems with the TI redriver that loses port status change events + * need to have the registers polled during D3, so avoid D3cold. + */ + if (xhci_compliance_mode_recovery_timer_quirk_check()) + pdev->no_d3cold = true; return xhci_suspend(xhci); } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index b4aa79d154b2..d8f640b12dd9 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -466,7 +466,7 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci) * Systems: * Vendor: Hewlett-Packard -> System Models: Z420, Z620 and Z820 */ -static bool compliance_mode_recovery_timer_quirk_check(void) +bool xhci_compliance_mode_recovery_timer_quirk_check(void) { const char *dmi_product_name, *dmi_sys_vendor; @@ -517,7 +517,7 @@ int xhci_init(struct usb_hcd *hcd) xhci_dbg(xhci, "Finished xhci_init\n"); /* Initializing Compliance Mode Recovery Data If Needed */ - if (compliance_mode_recovery_timer_quirk_check()) { + if (xhci_compliance_mode_recovery_timer_quirk_check()) { xhci->quirks |= XHCI_COMP_MODE_QUIRK; compliance_mode_recovery_timer_init(xhci); } @@ -956,6 +956,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; int retval = 0; + bool comp_timer_running = false; /* Wait a bit if either of the roothubs need to settle from the * transition into bus suspend. @@ -993,6 +994,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* If restore operation fails, re-initialize the HC during resume */ if ((temp & STS_SRE) || hibernated) { + + if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && + !(xhci_all_ports_seen_u0(xhci))) { + del_timer_sync(&xhci->comp_mode_recovery_timer); + xhci_dbg(xhci, "Compliance Mode Recovery Timer deleted!\n"); + } + /* Let the USB core know _both_ roothubs lost power. */ usb_root_hub_lost_power(xhci->main_hcd->self.root_hub); usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub); @@ -1035,6 +1043,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) retval = xhci_init(hcd->primary_hcd); if (retval) return retval; + comp_timer_running = true; + xhci_dbg(xhci, "Start the primary HCD\n"); retval = xhci_run(hcd->primary_hcd); if (!retval) { @@ -1076,7 +1086,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) * to suffer the Compliance Mode issue again. It doesn't matter if * ports have entered previously to U0 before system's suspension. */ - if (xhci->quirks & XHCI_COMP_MODE_QUIRK) + if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running) compliance_mode_recovery_timer_init(xhci); /* Re-enable port polling. */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 29c978e37135..77600cefcaf1 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1853,4 +1853,7 @@ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); +/* xHCI quirks */ +bool xhci_compliance_mode_recovery_timer_quirk_check(void); + #endif /* __LINUX_XHCI_HCD_H */ diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 3a18e44e9391..e1b661d04021 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -560,6 +560,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) if (!config) { dev_err(&pdev->dev, "failed to allocate musb hdrc config\n"); + ret = -ENOMEM; goto err2; } diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 8914dec49f01..9d3044bdebe5 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1232,7 +1232,6 @@ void musb_host_tx(struct musb *musb, u8 epnum) void __iomem *mbase = musb->mregs; struct dma_channel *dma; bool transfer_pending = false; - static bool use_sg; musb_ep_select(mbase, epnum); tx_csr = musb_readw(epio, MUSB_TXCSR); @@ -1463,9 +1462,9 @@ done: * NULL. */ if (!urb->transfer_buffer) - use_sg = true; + qh->use_sg = true; - if (use_sg) { + if (qh->use_sg) { /* sg_miter_start is already done in musb_ep_program */ if (!sg_miter_next(&qh->sg_miter)) { dev_err(musb->controller, "error: sg list empty\n"); @@ -1484,9 +1483,9 @@ done: qh->segsize = length; - if (use_sg) { + if (qh->use_sg) { if (offset + length >= urb->transfer_buffer_length) - use_sg = false; + qh->use_sg = false; } musb_ep_select(mbase, epnum); @@ -1552,7 +1551,6 @@ void musb_host_rx(struct musb *musb, u8 epnum) bool done = false; u32 status; struct dma_channel *dma; - static bool use_sg; unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG; musb_ep_select(mbase, epnum); @@ -1878,12 +1876,12 @@ void musb_host_rx(struct musb *musb, u8 epnum) * NULL. */ if (!urb->transfer_buffer) { - use_sg = true; + qh->use_sg = true; sg_miter_start(&qh->sg_miter, urb->sg, 1, sg_flags); } - if (use_sg) { + if (qh->use_sg) { if (!sg_miter_next(&qh->sg_miter)) { dev_err(musb->controller, "error: sg list empty\n"); sg_miter_stop(&qh->sg_miter); @@ -1913,8 +1911,8 @@ finish: urb->actual_length += xfer_len; qh->offset += xfer_len; if (done) { - if (use_sg) - use_sg = false; + if (qh->use_sg) + qh->use_sg = false; if (urb->status == -EINPROGRESS) urb->status = status; diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 5a9c8feec10c..738f7eb60df9 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -74,6 +74,7 @@ struct musb_qh { u16 frame; /* for periodic schedule */ unsigned iso_idx; /* in urb->iso_frame_desc[] */ struct sg_mapping_iter sg_miter; /* for highmem in PIO mode */ + bool use_sg; /* to track urb using sglist */ }; /* map from control or bulk queue head to the first qh on that ring */ diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 3551f1a30c65..628b93fe5ccc 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -549,7 +549,8 @@ static int omap2430_probe(struct platform_device *pdev) glue->control_otghs = omap_get_control_dev(); if (IS_ERR(glue->control_otghs)) { dev_vdbg(&pdev->dev, "Failed to get control device\n"); - return -ENODEV; + ret = PTR_ERR(glue->control_otghs); + goto err2; } } else { glue->control_otghs = ERR_PTR(-ENODEV); diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 371d0e74e909..2311b1e4e43c 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -4,11 +4,17 @@ menuconfig USB_PHY bool "USB Physical Layer drivers" help - USB controllers (those which are host, device or DRD) need a - device to handle the physical layer signalling, commonly called - a PHY. + Most USB controllers have the physical layer signalling part + (commonly called a PHY) built in. However, dual-role devices + (a.k.a. USB on-the-go) which support being USB master or slave + with the same connector often use an external PHY. - The following drivers add support for such PHY devices. + The drivers in this submenu add support for such PHY devices. + They are not needed for standard master-only (or the vast + majority of slave-only) USB interfaces. + + If you're not sure if this applies to you, it probably doesn't; + say N here. if USB_PHY @@ -25,7 +31,7 @@ config AB8500_USB config FSL_USB2_OTG bool "Freescale USB OTG Transceiver Driver" - depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND + depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME select USB_OTG help Enable this to support Freescale USB OTG transceiver. @@ -139,7 +145,6 @@ config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET depends on I2C - select USB_OTG_UTILS help Say Y here to add support for the NXP ISP1301 USB transceiver driver. This chip is typically used as USB transceiver for USB host, gadget @@ -162,7 +167,7 @@ config USB_MSM_OTG config USB_MV_OTG tristate "Marvell USB OTG support" - depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND + depends on USB_EHCI_MV && USB_MV_UDC && PM_RUNTIME select USB_OTG help Say Y here if you want to build Marvell USB OTG transciever diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 4acef26a2ef5..e5eb1b5a04eb 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -892,8 +892,6 @@ static int ab8500_usb_remove(struct platform_device *pdev) else if (ab->mode == USB_PERIPHERAL) ab8500_usb_peri_phy_dis(ab); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 97b9308507c3..e771bafb9f1d 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -799,6 +799,7 @@ static int fsl_otg_conf(struct platform_device *pdev) /* initialize the otg structure */ fsl_otg_tc->phy.label = DRIVER_DESC; + fsl_otg_tc->phy.dev = &pdev->dev; fsl_otg_tc->phy.set_power = fsl_otg_set_power; fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy; diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 4c76074e518d..8443335c2ea0 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -266,6 +266,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gpio_vbus); gpio_vbus->dev = &pdev->dev; gpio_vbus->phy.label = "gpio-vbus"; + gpio_vbus->phy.dev = gpio_vbus->dev; gpio_vbus->phy.set_power = gpio_vbus_set_power; gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend; gpio_vbus->phy.state = OTG_STATE_UNDEFINED; @@ -343,7 +344,6 @@ err_irq: gpio_free(pdata->gpio_pullup); gpio_free(pdata->gpio_vbus); err_gpio: - platform_set_drvdata(pdev, NULL); kfree(gpio_vbus->phy.otg); kfree(gpio_vbus); return err; @@ -365,7 +365,6 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev) if (gpio_is_valid(pdata->gpio_pullup)) gpio_free(pdata->gpio_pullup); gpio_free(gpio); - platform_set_drvdata(pdev, NULL); kfree(gpio_vbus->phy.otg); kfree(gpio_vbus); diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c index 225ae6c97eeb..8a55b37d1a02 100644 --- a/drivers/usb/phy/phy-isp1301.c +++ b/drivers/usb/phy/phy-isp1301.c @@ -102,6 +102,7 @@ static int isp1301_probe(struct i2c_client *client, mutex_init(&isp->mutex); phy = &isp->phy; + phy->dev = &client->dev; phy->label = DRV_NAME; phy->init = isp1301_phy_init; phy->set_vbus = isp1301_phy_set_vbus; diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index c987bbe27851..4a6b03c73876 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -667,7 +667,6 @@ int mv_otg_remove(struct platform_device *pdev) mv_otg_disable(mvotg); usb_remove_phy(&mvotg->phy); - platform_set_drvdata(pdev, NULL); return 0; } @@ -850,8 +849,6 @@ err_destroy_workqueue: flush_workqueue(mvotg->qwork); destroy_workqueue(mvotg->qwork); - platform_set_drvdata(pdev, NULL); - return retval; } diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index eb25dd2a1429..bd601c537c8d 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -155,6 +155,7 @@ static int mxs_phy_probe(struct platform_device *pdev) mxs_phy->phy.set_suspend = mxs_phy_suspend; mxs_phy->phy.notify_connect = mxs_phy_on_connect; mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect; + mxs_phy->phy.type = USB_PHY_TYPE_USB2; ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier); @@ -175,8 +176,6 @@ static int mxs_phy_remove(struct platform_device *pdev) usb_remove_phy(&mxs_phy->phy); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-nop.c index 2b10cc969bbb..638cc5dade35 100644 --- a/drivers/usb/phy/phy-nop.c +++ b/drivers/usb/phy/phy-nop.c @@ -254,8 +254,6 @@ static int nop_usb_xceiv_remove(struct platform_device *pdev) usb_remove_phy(&nop->phy); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 3b16118cbf62..40e7fd94646f 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -43,7 +43,7 @@ #define DRIVER_NAME "ark3116" /* usb timeout of 1 second */ -#define ARK_TIMEOUT (1*HZ) +#define ARK_TIMEOUT 1000 static const struct usb_device_id id_table[] = { { USB_DEVICE(0x6547, 0x0232) }, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index d341555d37d8..082120198f87 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -65,6 +65,7 @@ static const struct usb_device_id id_table_earthmate[] = { static const struct usb_device_id id_table_cyphidcomrs232[] = { { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, + { USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) }, { } /* Terminating entry */ }; @@ -78,6 +79,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, + { USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) }, { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, { } /* Terminating entry */ }; @@ -229,6 +231,12 @@ static struct usb_serial_driver * const serial_drivers[] = { * Cypress serial helper functions *****************************************************************************/ +/* FRWD Dongle hidcom needs to skip reset and speed checks */ +static inline bool is_frwd(struct usb_device *dev) +{ + return ((le16_to_cpu(dev->descriptor.idVendor) == VENDOR_ID_FRWD) && + (le16_to_cpu(dev->descriptor.idProduct) == PRODUCT_ID_CYPHIDCOM_FRWD)); +} static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) { @@ -238,6 +246,10 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) if (unstable_bauds) return new_rate; + /* FRWD Dongle uses 115200 bps */ + if (is_frwd(port->serial->dev)) + return new_rate; + /* * The general purpose firmware for the Cypress M8 allows for * a maximum speed of 57600bps (I have no idea whether DeLorme @@ -448,7 +460,11 @@ static int cypress_generic_port_probe(struct usb_serial_port *port) return -ENOMEM; } - usb_reset_configuration(serial->dev); + /* Skip reset for FRWD device. It is a workaound: + device hangs if it receives SET_CONFIGURE in Configured + state. */ + if (!is_frwd(serial->dev)) + usb_reset_configuration(serial->dev); priv->cmd_ctrl = 0; priv->line_control = 0; diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h index 67cf60826884..b461311a2ae7 100644 --- a/drivers/usb/serial/cypress_m8.h +++ b/drivers/usb/serial/cypress_m8.h @@ -24,6 +24,10 @@ #define VENDOR_ID_CYPRESS 0x04b4 #define PRODUCT_ID_CYPHIDCOM 0x5500 +/* FRWD Dongle - a GPS sports watch */ +#define VENDOR_ID_FRWD 0x6737 +#define PRODUCT_ID_CYPHIDCOM_FRWD 0x0001 + /* Powercom UPS, chip CY7C63723 */ #define VENDOR_ID_POWERCOM 0x0d9f #define PRODUCT_ID_UPS 0x0002 diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 090b411d893f..7d8dd5aad236 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -165,11 +165,12 @@ static void f81232_set_termios(struct tty_struct *tty, /* FIXME - Stubbed out for now */ /* Don't change anything if nothing has changed */ - if (!tty_termios_hw_change(&tty->termios, old_termios)) + if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; /* Do the real work here... */ - tty_termios_copy_hw(&tty->termios, old_termios); + if (old_termios) + tty_termios_copy_hw(&tty->termios, old_termios); } static int f81232_tiocmget(struct tty_struct *tty) @@ -187,12 +188,11 @@ static int f81232_tiocmset(struct tty_struct *tty, static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct ktermios tmp_termios; int result; /* Setup termios */ if (tty) - f81232_set_termios(tty, port, &tmp_termios); + f81232_set_termios(tty, port, NULL); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 242b5776648a..7260ec660347 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -189,6 +189,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_BOOST_PID) }, { USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) }, + { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_CC_PID) }, + { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_AGP_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, @@ -924,8 +926,8 @@ static int ftdi_tiocmset(struct tty_struct *tty, static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); -static int ftdi_chars_in_buffer(struct tty_struct *tty); -static int ftdi_get_modem_status(struct tty_struct *tty, +static bool ftdi_tx_empty(struct usb_serial_port *port); +static int ftdi_get_modem_status(struct usb_serial_port *port, unsigned char status[2]); static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); @@ -961,7 +963,7 @@ static struct usb_serial_driver ftdi_sio_device = { .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, - .chars_in_buffer = ftdi_chars_in_buffer, + .tx_empty = ftdi_tx_empty, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -2056,27 +2058,18 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) } -static int ftdi_chars_in_buffer(struct tty_struct *tty) +static bool ftdi_tx_empty(struct usb_serial_port *port) { - struct usb_serial_port *port = tty->driver_data; - int chars; unsigned char buf[2]; int ret; - chars = usb_serial_generic_chars_in_buffer(tty); - if (chars) - goto out; - - /* Check if hardware buffer is empty. */ - ret = ftdi_get_modem_status(tty, buf); + ret = ftdi_get_modem_status(port, buf); if (ret == 2) { if (!(buf[1] & FTDI_RS_TEMT)) - chars = 1; + return false; } -out: - dev_dbg(&port->dev, "%s - %d\n", __func__, chars); - return chars; + return true; } /* old_termios contains the original termios settings and tty->termios contains @@ -2268,10 +2261,9 @@ no_c_cflag_changes: * Returns the number of status bytes retrieved (device dependant), or * negative error code. */ -static int ftdi_get_modem_status(struct tty_struct *tty, +static int ftdi_get_modem_status(struct usb_serial_port *port, unsigned char status[2]) { - struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned char *buf; int len; @@ -2336,7 +2328,7 @@ static int ftdi_tiocmget(struct tty_struct *tty) unsigned char buf[2]; int ret; - ret = ftdi_get_modem_status(tty, buf); + ret = ftdi_get_modem_status(port, buf); if (ret < 0) return ret; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 98528270c43c..6dd79253205d 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -772,6 +772,8 @@ */ #define NEWPORT_VID 0x104D #define NEWPORT_AGILIS_PID 0x3000 +#define NEWPORT_CONEX_CC_PID 0x3002 +#define NEWPORT_CONEX_AGP_PID 0x3006 /* Interbiometrics USB I/O Board */ /* Developed for Interbiometrics by Rudolf Gugler */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 297665fdd16d..ba45170c78e5 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -253,6 +253,37 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) } EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer); +void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout) +{ + struct usb_serial_port *port = tty->driver_data; + unsigned int bps; + unsigned long period; + unsigned long expire; + + bps = tty_get_baud_rate(tty); + if (!bps) + bps = 9600; /* B0 */ + /* + * Use a poll-period of roughly the time it takes to send one + * character or at least one jiffy. + */ + period = max_t(unsigned long, (10 * HZ / bps), 1); + period = min_t(unsigned long, period, timeout); + + dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n", + __func__, jiffies_to_msecs(timeout), + jiffies_to_msecs(period)); + expire = jiffies + timeout; + while (!port->serial->type->tx_empty(port)) { + schedule_timeout_interruptible(period); + if (signal_pending(current)) + break; + if (time_after(jiffies, expire)) + break; + } +} +EXPORT_SYMBOL_GPL(usb_serial_generic_wait_until_sent); + static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, int index, gfp_t mem_flags) { diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 158bf4bc29cc..1be6ba7bee27 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2019,8 +2019,6 @@ static int edge_chars_in_buffer(struct tty_struct *tty) struct edgeport_port *edge_port = usb_get_serial_port_data(port); int chars = 0; unsigned long flags; - int ret; - if (edge_port == NULL) return 0; @@ -2028,16 +2026,22 @@ static int edge_chars_in_buffer(struct tty_struct *tty) chars = kfifo_len(&edge_port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); - if (!chars) { - ret = tx_active(edge_port); - if (ret > 0) - chars = ret; - } - dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } +static bool edge_tx_empty(struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = usb_get_serial_port_data(port); + int ret; + + ret = tx_active(edge_port); + if (ret > 0) + return false; + + return true; +} + static void edge_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; @@ -2557,6 +2561,7 @@ static struct usb_serial_driver edgeport_1port_device = { .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, + .tx_empty = edge_tx_empty, .break_ctl = edge_break, .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, @@ -2589,6 +2594,7 @@ static struct usb_serial_driver edgeport_2port_device = { .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, + .tx_empty = edge_tx_empty, .break_ctl = edge_break, .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 9d74c278b7b5..790673e5faa7 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -287,7 +287,7 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count) usb_bulk_msg(serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), buf, - count, &actual, HZ * 1); + count, &actual, 1000); if (status != IUU_OPERATION_OK) dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status); @@ -307,7 +307,7 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count) usb_bulk_msg(serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), buf, - count, &actual, HZ * 1); + count, &actual, 1000); if (status != IUU_OPERATION_OK) dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index eb30d7b01f36..3549d073df22 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1548,7 +1548,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, struct keyspan_serial_private *s_priv; struct keyspan_port_private *p_priv; const struct keyspan_device_details *d_details; - int outcont_urb; struct urb *this_urb; int device_port, err; @@ -1559,7 +1558,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, d_details = s_priv->device_details; device_port = port->number - port->serial->minor; - outcont_urb = d_details->outcont_endpoints[port->number]; this_urb = p_priv->outcont_urb; dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe)); @@ -1685,14 +1683,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial, err = usb_submit_urb(this_urb, GFP_ATOMIC); if (err != 0) dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); -#if 0 - else { - dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__ - outcont_urb, this_urb->transfer_buffer_length, - usb_pipeendpoint(this_urb->pipe)); - } -#endif - return 0; } diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index cc0e54345df9..f27c621a9297 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -40,7 +40,7 @@ #define DRIVER_DESC "Moschip USB Serial Driver" /* default urb timeout */ -#define MOS_WDR_TIMEOUT (HZ * 5) +#define MOS_WDR_TIMEOUT 5000 #define MOS_MAX_PORT 0x02 #define MOS_WRITE 0x0E @@ -227,11 +227,22 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, __u8 requesttype = (__u8)0xc0; __u16 index = get_reg_index(reg); __u16 value = get_reg_value(reg, serial_portnum); - int status = usb_control_msg(usbdev, pipe, request, requesttype, value, - index, data, 1, MOS_WDR_TIMEOUT); - if (status < 0) + u8 *buf; + int status; + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + status = usb_control_msg(usbdev, pipe, request, requesttype, value, + index, buf, 1, MOS_WDR_TIMEOUT); + if (status == 1) + *data = *buf; + else if (status < 0) dev_err(&usbdev->dev, "mos7720: usb_control_msg() failed: %d", status); + kfree(buf); + return status; } @@ -1618,7 +1629,7 @@ static void change_port_settings(struct tty_struct *tty, mos7720_port->shadowMCR |= (UART_MCR_XONANY); /* To set hardware flow control to the specified * * serial port, in SP1/2_CONTROL_REG */ - if (port->number) + if (port_number) write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01); else write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02); @@ -1927,7 +1938,7 @@ static int mos7720_startup(struct usb_serial *serial) /* setting configuration feature to one */ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ); + (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000); /* start the interrupt urb */ ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL); @@ -1970,7 +1981,7 @@ static void mos7720_release(struct usb_serial *serial) /* wait for synchronous usb calls to return */ if (mos_parport->msg_pending) wait_for_completion_timeout(&mos_parport->syncmsg_compl, - MOS_WDR_TIMEOUT); + msecs_to_jiffies(MOS_WDR_TIMEOUT)); parport_remove_port(mos_parport->pp); usb_set_serial_data(serial, NULL); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index a0d5ea545982..7e998081e1cd 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2142,13 +2142,21 @@ static int mos7840_ioctl(struct tty_struct *tty, static int mos7810_check(struct usb_serial *serial) { int i, pass_count = 0; + u8 *buf; __u16 data = 0, mcr_data = 0; __u16 test_pattern = 0x55AA; + int res; + + buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL); + if (!buf) + return 0; /* failed to identify 7810 */ /* Store MCR setting */ - usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER, - &mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + if (res == VENDOR_READ_LENGTH) + mcr_data = *buf; for (i = 0; i < 16; i++) { /* Send the 1-bit test pattern out to MCS7810 test pin */ @@ -2158,9 +2166,12 @@ static int mos7810_check(struct usb_serial *serial) MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT); /* Read the test pattern back */ - usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data, - VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + res = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), MCS_RDREQ, + MCS_RD_RTYPE, 0, GPIO_REGISTER, buf, + VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + if (res == VENDOR_READ_LENGTH) + data = *buf; /* If this is a MCS7810 device, both test patterns must match */ if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001) @@ -2174,6 +2185,8 @@ static int mos7810_check(struct usb_serial *serial) MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT); + kfree(buf); + if (pass_count == 16) return 1; @@ -2183,11 +2196,17 @@ static int mos7810_check(struct usb_serial *serial) static int mos7840_calc_num_ports(struct usb_serial *serial) { __u16 data = 0x00; + u8 *buf; int mos7840_num_ports; - usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data, - VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL); + if (buf) { + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf, + VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + data = *buf; + kfree(buf); + } if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 || serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) { diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 734372846abb..bd4323ddae1a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -196,6 +196,7 @@ static void option_instat_callback(struct urb *urb); #define DELL_PRODUCT_5800_MINICARD_VZW 0x8195 /* Novatel E362 */ #define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */ +#define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */ #define KYOCERA_VENDOR_ID 0x0c88 #define KYOCERA_PRODUCT_KPC650 0x17da @@ -249,13 +250,7 @@ static void option_instat_callback(struct urb *urb); #define ZTE_PRODUCT_MF622 0x0001 #define ZTE_PRODUCT_MF628 0x0015 #define ZTE_PRODUCT_MF626 0x0031 -#define ZTE_PRODUCT_CDMA_TECH 0xfffe -#define ZTE_PRODUCT_AC8710 0xfff1 -#define ZTE_PRODUCT_AC2726 0xfff5 -#define ZTE_PRODUCT_AC8710T 0xffff #define ZTE_PRODUCT_MC2718 0xffe8 -#define ZTE_PRODUCT_AD3812 0xffeb -#define ZTE_PRODUCT_MC2716 0xffed #define BENQ_VENDOR_ID 0x04a5 #define BENQ_PRODUCT_H10 0x4068 @@ -341,8 +336,8 @@ static void option_instat_callback(struct urb *urb); #define CINTERION_PRODUCT_EU3_E 0x0051 #define CINTERION_PRODUCT_EU3_P 0x0052 #define CINTERION_PRODUCT_PH8 0x0053 -#define CINTERION_PRODUCT_AH6 0x0055 -#define CINTERION_PRODUCT_PLS8 0x0060 +#define CINTERION_PRODUCT_AHXX 0x0055 +#define CINTERION_PRODUCT_PLXX 0x0060 /* Olivetti products */ #define OLIVETTI_VENDOR_ID 0x0b3c @@ -494,18 +489,10 @@ static const struct option_blacklist_info zte_k3765_z_blacklist = { .reserved = BIT(4), }; -static const struct option_blacklist_info zte_ad3812_z_blacklist = { - .sendsetup = BIT(0) | BIT(1) | BIT(2), -}; - static const struct option_blacklist_info zte_mc2718_z_blacklist = { .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4), }; -static const struct option_blacklist_info zte_mc2716_z_blacklist = { - .sendsetup = BIT(1) | BIT(2) | BIT(3), -}; - static const struct option_blacklist_info huawei_cdc12_blacklist = { .reserved = BIT(1) | BIT(2), }; @@ -592,6 +579,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14ac, 0xff, 0xff, 0xff), /* Huawei E1820 */ + .driver_info = (kernel_ulong_t) &net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) }, @@ -771,6 +760,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, @@ -795,7 +785,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012, 0xff) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, - { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */ @@ -966,6 +955,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0330, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0395, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0412, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff), @@ -1195,16 +1186,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) }, + /* NOTE: most ZTE CDMA devices should be driven by zte_ev, not option */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) }, { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) }, @@ -1264,8 +1248,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AH6) }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLS8) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) }, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 7151659367a0..048cd44d51b1 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -284,7 +284,7 @@ static void pl2303_set_termios(struct tty_struct *tty, serial settings even to the same values as before. Thus we actually need to filter in this specific case */ - if (!tty_termios_hw_change(&tty->termios, old_termios)) + if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; cflag = tty->termios.c_cflag; @@ -293,7 +293,8 @@ static void pl2303_set_termios(struct tty_struct *tty, if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __func__); /* Report back no change occurred */ - tty->termios = *old_termios; + if (old_termios) + tty->termios = *old_termios; return; } @@ -433,7 +434,7 @@ static void pl2303_set_termios(struct tty_struct *tty, control = priv->line_control; if ((cflag & CBAUD) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); - else if ((old_termios->c_cflag & CBAUD) == B0) + else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) priv->line_control |= (CONTROL_DTR | CONTROL_RTS); if (control != priv->line_control) { control = priv->line_control; @@ -492,7 +493,6 @@ static void pl2303_close(struct usb_serial_port *port) static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct pl2303_serial_private *spriv = usb_get_serial_data(serial); int result; @@ -508,7 +508,7 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) /* Setup termios */ if (tty) - pl2303_set_termios(tty, port, &tmp_termios); + pl2303_set_termios(tty, port, NULL); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 59b32b782126..bd794b43898c 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -118,6 +118,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */ {USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */ {USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */ + {USB_DEVICE(0x0AF0, 0x8120)}, /* Option GTM681W */ /* non Gobi Qualcomm serial devices */ {USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 0)}, /* Sierra Wireless MC7700 Device Management */ diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index cf3df793c2b7..ddf6c47137dc 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -291,7 +291,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty, struct spcp8x5_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int cflag = tty->termios.c_cflag; - unsigned int old_cflag = old_termios->c_cflag; unsigned short uartdata; unsigned char buf[2] = {0, 0}; int baud; @@ -299,15 +298,15 @@ static void spcp8x5_set_termios(struct tty_struct *tty, u8 control; /* check that they really want us to change something */ - if (!tty_termios_hw_change(&tty->termios, old_termios)) + if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; /* set DTR/RTS active */ spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; - if ((old_cflag & CBAUD) == B0) { + if (old_termios && (old_termios->c_cflag & CBAUD) == B0) { priv->line_control |= MCR_DTR; - if (!(old_cflag & CRTSCTS)) + if (!(old_termios->c_cflag & CRTSCTS)) priv->line_control |= MCR_RTS; } if (control != priv->line_control) { @@ -394,7 +393,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty, static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct spcp8x5_private *priv = usb_get_serial_port_data(port); int ret; @@ -411,7 +409,7 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) spcp8x5_set_ctrl_line(port, priv->line_control); if (tty) - spcp8x5_set_termios(tty, port, &tmp_termios); + spcp8x5_set_termios(tty, port, NULL); port->port.drain_delay = 256; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index cac47aef2918..e581c2549a57 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -101,6 +101,7 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count); static int ti_write_room(struct tty_struct *tty); static int ti_chars_in_buffer(struct tty_struct *tty); +static bool ti_tx_empty(struct usb_serial_port *port); static void ti_throttle(struct tty_struct *tty); static void ti_unthrottle(struct tty_struct *tty); static int ti_ioctl(struct tty_struct *tty, @@ -171,7 +172,8 @@ static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, - { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) }, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) }, { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, }; @@ -222,6 +224,7 @@ static struct usb_serial_driver ti_1port_device = { .write = ti_write, .write_room = ti_write_room, .chars_in_buffer = ti_chars_in_buffer, + .tx_empty = ti_tx_empty, .throttle = ti_throttle, .unthrottle = ti_unthrottle, .ioctl = ti_ioctl, @@ -253,6 +256,7 @@ static struct usb_serial_driver ti_2port_device = { .write = ti_write, .write_room = ti_write_room, .chars_in_buffer = ti_chars_in_buffer, + .tx_empty = ti_tx_empty, .throttle = ti_throttle, .unthrottle = ti_unthrottle, .ioctl = ti_ioctl, @@ -684,8 +688,6 @@ static int ti_chars_in_buffer(struct tty_struct *tty) struct ti_port *tport = usb_get_serial_port_data(port); int chars = 0; unsigned long flags; - int ret; - u8 lsr; if (tport == NULL) return 0; @@ -694,16 +696,22 @@ static int ti_chars_in_buffer(struct tty_struct *tty) chars = kfifo_len(&tport->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); - if (!chars) { - ret = ti_get_lsr(tport, &lsr); - if (!ret && !(lsr & TI_LSR_TX_EMPTY)) - chars = 1; - } - dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } +static bool ti_tx_empty(struct usb_serial_port *port) +{ + struct ti_port *tport = usb_get_serial_port_data(port); + int ret; + u8 lsr; + + ret = ti_get_lsr(tport, &lsr); + if (!ret && !(lsr & TI_LSR_TX_EMPTY)) + return false; + + return true; +} static void ti_throttle(struct tty_struct *tty) { diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index b353e7e3d480..4a2423e84d55 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -52,7 +52,9 @@ /* Abbott Diabetics vendor and product ids */ #define ABBOTT_VENDOR_ID 0x1a61 -#define ABBOTT_PRODUCT_ID 0x3410 +#define ABBOTT_STEREO_PLUG_ID 0x3410 +#define ABBOTT_PRODUCT_ID ABBOTT_STEREO_PLUG_ID +#define ABBOTT_STRIP_PORT_ID 0x3420 /* Commands */ #define TI_GET_VERSION 0x01 diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index cf75beb1251b..5f6b1ff9d29e 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -359,20 +359,29 @@ static int serial_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = port->serial; - int count = 0; dev_dbg(tty->dev, "%s\n", __func__); - mutex_lock(&serial->disc_mutex); - /* if the device was unplugged then any remaining characters - fell out of the connector ;) */ if (serial->disconnected) - count = 0; - else - count = serial->type->chars_in_buffer(tty); - mutex_unlock(&serial->disc_mutex); + return 0; - return count; + return serial->type->chars_in_buffer(tty); +} + +static void serial_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; + + dev_dbg(tty->dev, "%s\n", __func__); + + if (!port->serial->type->wait_until_sent) + return; + + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + port->serial->type->wait_until_sent(tty, timeout); + mutex_unlock(&serial->disc_mutex); } static void serial_throttle(struct tty_struct *tty) @@ -399,7 +408,7 @@ static int serial_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - int retval = -ENODEV; + int retval = -ENOIOCTLCMD; dev_dbg(tty->dev, "%s - cmd 0x%.4x\n", __func__, cmd); @@ -411,8 +420,6 @@ static int serial_ioctl(struct tty_struct *tty, default: if (port->serial->type->ioctl) retval = port->serial->type->ioctl(tty, cmd, arg); - else - retval = -ENOIOCTLCMD; } return retval; @@ -1191,6 +1198,7 @@ static const struct tty_operations serial_ops = { .unthrottle = serial_unthrottle, .break_ctl = serial_break, .chars_in_buffer = serial_chars_in_buffer, + .wait_until_sent = serial_wait_until_sent, .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, .get_icount = serial_get_icount, @@ -1316,6 +1324,8 @@ static void usb_serial_operations_init(struct usb_serial_driver *device) set_to_generic_if_null(device, close); set_to_generic_if_null(device, write_room); set_to_generic_if_null(device, chars_in_buffer); + if (device->tx_empty) + set_to_generic_if_null(device, wait_until_sent); set_to_generic_if_null(device, read_bulk_callback); set_to_generic_if_null(device, write_bulk_callback); set_to_generic_if_null(device, process_read_urb); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 7573ec8a084f..9910aa2edf4b 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -560,10 +560,19 @@ static int treo_attach(struct usb_serial *serial) */ #define COPY_PORT(dest, src) \ do { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(src->read_urbs); ++i) { \ + dest->read_urbs[i] = src->read_urbs[i]; \ + dest->read_urbs[i]->context = dest; \ + dest->bulk_in_buffers[i] = src->bulk_in_buffers[i]; \ + } \ dest->read_urb = src->read_urb; \ dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;\ dest->bulk_in_buffer = src->bulk_in_buffer; \ + dest->bulk_in_size = src->bulk_in_size; \ dest->interrupt_in_urb = src->interrupt_in_urb; \ + dest->interrupt_in_urb->context = dest; \ dest->interrupt_in_endpointAddress = \ src->interrupt_in_endpointAddress;\ dest->interrupt_in_buffer = src->interrupt_in_buffer; \ diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index b9fca3586d74..347caad47a12 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -649,7 +649,7 @@ static void firm_setup_port(struct tty_struct *tty) struct whiteheat_port_settings port_settings; unsigned int cflag = tty->termios.c_cflag; - port_settings.port = port->number + 1; + port_settings.port = port->number - port->serial->minor + 1; /* get the byte size */ switch (cflag & CSIZE) { diff --git a/drivers/usb/serial/zte_ev.c b/drivers/usb/serial/zte_ev.c index 39ee7373b4ee..fca4c752a4ed 100644 --- a/drivers/usb/serial/zte_ev.c +++ b/drivers/usb/serial/zte_ev.c @@ -41,9 +41,6 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty, int len; unsigned char *buf; - if (port->number != 0) - return -ENODEV; - buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -53,7 +50,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty, result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x22, 0x21, 0x0001, 0x0000, NULL, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); dev_dbg(dev, "result = %d\n", result); /* send 2st cmd and recieve data */ @@ -65,7 +62,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty, result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x21, 0xa1, 0x0000, 0x0000, buf, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); debug_data(dev, __func__, len, buf, result); /* send 3 cmd */ @@ -84,7 +81,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty, result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x20, 0x21, 0x0000, 0x0000, buf, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); debug_data(dev, __func__, len, buf, result); /* send 4 cmd */ @@ -95,7 +92,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty, result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x22, 0x21, 0x0003, 0x0000, NULL, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); dev_dbg(dev, "result = %d\n", result); /* send 5 cmd */ @@ -107,7 +104,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty, result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x21, 0xa1, 0x0000, 0x0000, buf, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); debug_data(dev, __func__, len, buf, result); /* send 6 cmd */ @@ -126,7 +123,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty, result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x20, 0x21, 0x0000, 0x0000, buf, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); debug_data(dev, __func__, len, buf, result); kfree(buf); @@ -166,9 +163,6 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) int len; unsigned char *buf; - if (port->number != 0) - return; - buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL); if (!buf) return; @@ -178,7 +172,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x22, 0x21, 0x0002, 0x0000, NULL, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); dev_dbg(dev, "result = %d\n", result); /* send 2st ctl cmd(CTL 21 22 03 00 00 00 00 00 ) */ @@ -186,7 +180,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x22, 0x21, 0x0003, 0x0000, NULL, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); dev_dbg(dev, "result = %d\n", result); /* send 3st cmd and recieve data */ @@ -198,7 +192,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x21, 0xa1, 0x0000, 0x0000, buf, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); debug_data(dev, __func__, len, buf, result); /* send 4 cmd */ @@ -217,7 +211,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x20, 0x21, 0x0000, 0x0000, buf, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); debug_data(dev, __func__, len, buf, result); /* send 5 cmd */ @@ -228,7 +222,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x22, 0x21, 0x0003, 0x0000, NULL, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); dev_dbg(dev, "result = %d\n", result); /* send 6 cmd */ @@ -240,7 +234,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x21, 0xa1, 0x0000, 0x0000, buf, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); debug_data(dev, __func__, len, buf, result); /* send 7 cmd */ @@ -259,7 +253,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x20, 0x21, 0x0000, 0x0000, buf, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); debug_data(dev, __func__, len, buf, result); /* send 8 cmd */ @@ -270,7 +264,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x22, 0x21, 0x0003, 0x0000, NULL, len, - HZ * USB_CTRL_GET_TIMEOUT); + USB_CTRL_GET_TIMEOUT); dev_dbg(dev, "result = %d\n", result); kfree(buf); @@ -279,11 +273,29 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port) } static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x19d2, 0xffff) }, /* AC8700 */ - { USB_DEVICE(0x19d2, 0xfffe) }, - { USB_DEVICE(0x19d2, 0xfffd) }, /* MG880 */ + /* AC8710, AC8710T */ + { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffff, 0xff, 0xff, 0xff) }, + /* AC8700 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xfffe, 0xff, 0xff, 0xff) }, + /* MG880 */ + { USB_DEVICE(0x19d2, 0xfffd) }, + { USB_DEVICE(0x19d2, 0xfffc) }, + { USB_DEVICE(0x19d2, 0xfffb) }, + /* AC2726, AC8710_V3 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xfff1, 0xff, 0xff, 0xff) }, + { USB_DEVICE(0x19d2, 0xfff6) }, + { USB_DEVICE(0x19d2, 0xfff7) }, + { USB_DEVICE(0x19d2, 0xfff8) }, + { USB_DEVICE(0x19d2, 0xfff9) }, + { USB_DEVICE(0x19d2, 0xffee) }, + /* AC2716, MC2716 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffed, 0xff, 0xff, 0xff) }, + /* AD3812 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffeb, 0xff, 0xff, 0xff) }, + { USB_DEVICE(0x19d2, 0xffec) }, { USB_DEVICE(0x05C6, 0x3197) }, { USB_DEVICE(0x05C6, 0x6000) }, + { USB_DEVICE(0x05C6, 0x9008) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 8623577bbbe7..281be56d5648 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -105,8 +105,9 @@ struct rts51x_chip { int status_len; u32 flag; -#ifdef CONFIG_REALTEK_AUTOPM struct us_data *us; + +#ifdef CONFIG_REALTEK_AUTOPM struct timer_list rts51x_suspend_timer; unsigned long timer_expires; int pwr_state; @@ -988,6 +989,7 @@ static int init_realtek_cr(struct us_data *us) us->extra = chip; us->extra_destructor = realtek_cr_destructor; us->max_lun = chip->max_lun = rts51x_get_max_lun(us); + chip->us = us; usb_stor_dbg(us, "chip->max_lun = %d\n", chip->max_lun); @@ -1010,10 +1012,8 @@ static int init_realtek_cr(struct us_data *us) SET_AUTO_DELINK(chip); } #ifdef CONFIG_REALTEK_AUTOPM - if (ss_en) { - chip->us = us; + if (ss_en) realtek_cr_autosuspend_setup(us); - } #endif usb_stor_dbg(us, "chip->flag = 0x%x\n", chip->flag); diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index acb7121a9316..6d78736563de 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -1360,7 +1360,7 @@ static const struct file_operations vfio_device_fops = { */ static char *vfio_devnode(struct device *dev, umode_t *mode) { - if (MINOR(dev->devt) == 0) + if (mode && (MINOR(dev->devt) == 0)) *mode = S_IRUGO | S_IWUGO; return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev)); diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 2b51e2336aa2..f80d3dd41d8c 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -155,14 +155,11 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) static void vhost_net_clear_ubuf_info(struct vhost_net *n) { - - bool zcopy; int i; - for (i = 0; i < n->dev.nvqs; ++i) { - zcopy = vhost_net_zcopy_mask & (0x1 << i); - if (zcopy) - kfree(n->vqs[i].ubuf_info); + for (i = 0; i < VHOST_NET_VQ_MAX; ++i) { + kfree(n->vqs[i].ubuf_info); + n->vqs[i].ubuf_info = NULL; } } @@ -171,7 +168,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n) bool zcopy; int i; - for (i = 0; i < n->dev.nvqs; ++i) { + for (i = 0; i < VHOST_NET_VQ_MAX; ++i) { zcopy = vhost_net_zcopy_mask & (0x1 << i); if (!zcopy) continue; @@ -183,12 +180,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n) return 0; err: - while (i--) { - zcopy = vhost_net_zcopy_mask & (0x1 << i); - if (!zcopy) - continue; - kfree(n->vqs[i].ubuf_info); - } + vhost_net_clear_ubuf_info(n); return -ENOMEM; } @@ -196,12 +188,12 @@ void vhost_net_vq_reset(struct vhost_net *n) { int i; + vhost_net_clear_ubuf_info(n); + for (i = 0; i < VHOST_NET_VQ_MAX; i++) { n->vqs[i].done_idx = 0; n->vqs[i].upend_idx = 0; n->vqs[i].ubufs = NULL; - kfree(n->vqs[i].ubuf_info); - n->vqs[i].ubuf_info = NULL; n->vqs[i].vhost_hlen = 0; n->vqs[i].sock_hlen = 0; } @@ -436,7 +428,8 @@ static void handle_tx(struct vhost_net *net) kref_get(&ubufs->kref); } nvq->upend_idx = (nvq->upend_idx + 1) % UIO_MAXIOV; - } + } else + msg.msg_control = NULL; /* TODO: Check specific error and bomb out unless ENOBUFS? */ err = sock->ops->sendmsg(NULL, sock, &msg, len); if (unlikely(err < 0)) { @@ -1053,6 +1046,10 @@ static long vhost_net_set_owner(struct vhost_net *n) int r; mutex_lock(&n->dev.mutex); + if (vhost_dev_has_owner(&n->dev)) { + r = -EBUSY; + goto out; + } r = vhost_net_set_ubuf_info(n); if (r) goto out; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index beee7f5787e6..60aa5ad09a2f 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -344,13 +344,19 @@ static int vhost_attach_cgroups(struct vhost_dev *dev) } /* Caller should have device mutex */ +bool vhost_dev_has_owner(struct vhost_dev *dev) +{ + return dev->mm; +} + +/* Caller should have device mutex */ long vhost_dev_set_owner(struct vhost_dev *dev) { struct task_struct *worker; int err; /* Is there an owner already? */ - if (dev->mm) { + if (vhost_dev_has_owner(dev)) { err = -EBUSY; goto err_mm; } diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index a7ad63592987..64adcf99ff33 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -133,6 +133,7 @@ struct vhost_dev { long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs); long vhost_dev_set_owner(struct vhost_dev *dev); +bool vhost_dev_has_owner(struct vhost_dev *dev); long vhost_dev_check_owner(struct vhost_dev *); struct vhost_memory *vhost_dev_reset_owner_prepare(void); void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_memory *); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d71d60f94fc1..2e937bdace6f 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2199,7 +2199,7 @@ config FB_XILINX config FB_GOLDFISH tristate "Goldfish Framebuffer" - depends on FB + depends on FB && HAS_DMA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -2453,6 +2453,23 @@ config FB_HYPERV help This framebuffer driver supports Microsoft Hyper-V Synthetic Video. +config FB_SIMPLE + bool "Simple framebuffer support" + depends on (FB = y) && OF + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + Say Y if you want support for a simple frame-buffer. + + This driver assumes that the display hardware has been initialized + before the kernel boots, and the kernel will simply render to the + pre-allocated frame buffer surface. + + Configuration re: surface address, size, and format must be provided + through device tree, or potentially plain old platform data in the + future. + source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" source "drivers/video/exynos/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 7234e4a959e8..e8bae8dd4804 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -166,6 +166,7 @@ obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o obj-$(CONFIG_FB_MXS) += mxsfb.o obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o +obj-$(CONFIG_FB_SIMPLE) += simplefb.o # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 540909de6247..effdb373b8db 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -223,8 +223,14 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo) static void exit_backlight(struct atmel_lcdfb_info *sinfo) { - if (sinfo->backlight) - backlight_device_unregister(sinfo->backlight); + if (!sinfo->backlight) + return; + + if (sinfo->backlight->ops) { + sinfo->backlight->props.power = FB_BLANK_POWERDOWN; + sinfo->backlight->ops->update_status(sinfo->backlight); + } + backlight_device_unregister(sinfo->backlight); } #else @@ -461,8 +467,11 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, if (info->fix.smem_len) { unsigned int smem_len = (var->xres_virtual * var->yres_virtual * ((var->bits_per_pixel + 7) / 8)); - if (smem_len > info->fix.smem_len) + if (smem_len > info->fix.smem_len) { + dev_err(dev, "Frame buffer is too small (%u) for screen size (need at least %u)\n", + info->fix.smem_len, smem_len); return -EINVAL; + } } /* Saturate vertical and horizontal timings at maximum values */ diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index a862e9173ebe..48da25c96cd3 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -18,6 +18,8 @@ font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o font-objs += $(font-objs-y) +obj-$(CONFIG_FONTS) += font.o + # Each configuration option enables a list of files. obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 5855d17d19ac..9d8feac67637 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -42,6 +42,7 @@ #include <linux/kd.h> #include <linux/slab.h> #include <linux/vt_kern.h> +#include <linux/sched.h> #include <linux/selection.h> #include <linux/spinlock.h> #include <linux/ioport.h> @@ -1124,11 +1125,15 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) if (arg) { if (set) - for (i = 0; i < cmapsz; i++) + for (i = 0; i < cmapsz; i++) { vga_writeb(arg[i], charmap + i); + cond_resched(); + } else - for (i = 0; i < cmapsz; i++) + for (i = 0; i < cmapsz; i++) { arg[i] = vga_readb(charmap + i); + cond_resched(); + } /* * In 512-character mode, the character map is not contiguous if @@ -1139,11 +1144,15 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) charmap += 2 * cmapsz; arg += cmapsz; if (set) - for (i = 0; i < cmapsz; i++) + for (i = 0; i < cmapsz; i++) { vga_writeb(arg[i], charmap + i); + cond_resched(); + } else - for (i = 0; i < cmapsz; i++) + for (i = 0; i < cmapsz; i++) { arg[i] = vga_readb(charmap + i); + cond_resched(); + } } } diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c index 56009bc02b02..2894e0300a33 100644 --- a/drivers/video/of_display_timing.c +++ b/drivers/video/of_display_timing.c @@ -23,7 +23,7 @@ * Every display_timing can be specified with either just the typical value or * a range consisting of min/typ/max. This function helps handling this **/ -static int parse_timing_property(struct device_node *np, const char *name, +static int parse_timing_property(const struct device_node *np, const char *name, struct timing_entry *result) { struct property *prop; @@ -56,7 +56,8 @@ static int parse_timing_property(struct device_node *np, const char *name, * of_get_display_timing - parse display_timing entry from device_node * @np: device_node with the properties **/ -static struct display_timing *of_get_display_timing(struct device_node *np) +static struct display_timing *of_get_display_timing(const struct device_node + *np) { struct display_timing *dt; u32 val = 0; @@ -97,6 +98,8 @@ static struct display_timing *of_get_display_timing(struct device_node *np) dt->flags |= DISPLAY_FLAGS_INTERLACED; if (of_property_read_bool(np, "doublescan")) dt->flags |= DISPLAY_FLAGS_DOUBLESCAN; + if (of_property_read_bool(np, "doubleclk")) + dt->flags |= DISPLAY_FLAGS_DOUBLECLK; if (ret) { pr_err("%s: error reading timing properties\n", diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 60cc6fee6548..c9c2252e3719 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -53,6 +53,8 @@ static char *def_disp_name; module_param_named(def_disp, def_disp_name, charp, 0); MODULE_PARM_DESC(def_disp, "default display name"); +static bool dss_initialized; + const char *omapdss_get_default_display_name(void) { return core.default_display_name; @@ -66,6 +68,12 @@ enum omapdss_version omapdss_get_version(void) } EXPORT_SYMBOL(omapdss_get_version); +bool omapdss_is_initialized(void) +{ + return dss_initialized; +} +EXPORT_SYMBOL(omapdss_is_initialized); + struct platform_device *dss_get_core_pdev(void) { return core.pdev; @@ -603,6 +611,8 @@ static int __init omap_dss_init(void) return r; } + dss_initialized = true; + return 0; } @@ -633,7 +643,15 @@ static int __init omap_dss_init(void) static int __init omap_dss_init2(void) { - return omap_dss_register_drivers(); + int r; + + r = omap_dss_register_drivers(); + if (r) + return r; + + dss_initialized = true; + + return 0; } core_initcall(omap_dss_init); diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index c84bb8a4d0c4..856917b33616 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2416,6 +2416,9 @@ static int omapfb_probe(struct platform_device *pdev) DBG("omapfb_probe\n"); + if (omapdss_is_initialized() == false) + return -EPROBE_DEFER; + if (pdev->num_resources != 0) { dev_err(&pdev->dev, "probed for an unknown device\n"); r = -ENODEV; diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index d9f08c653d62..dbfe2c18a434 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -710,7 +710,7 @@ static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma) r = vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len); dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", - info->fix.smem_start + vma->vm_pgoff << PAGE_SHIFT, + info->fix.smem_start + (vma->vm_pgoff << PAGE_SHIFT), vma->vm_start); return r; diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c new file mode 100644 index 000000000000..e2e9e3e61b72 --- /dev/null +++ b/drivers/video/simplefb.c @@ -0,0 +1,234 @@ +/* + * Simplest possible simple frame-buffer driver, as a platform device + * + * Copyright (c) 2013, Stephen Warren + * + * Based on q40fb.c, which was: + * Copyright (C) 2001 Richard Zidlicky <rz@linux-m68k.org> + * + * Also based on offb.c, which was: + * Copyright (C) 1997 Geert Uytterhoeven + * Copyright (C) 1996 Paul Mackerras + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/errno.h> +#include <linux/fb.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +static struct fb_fix_screeninfo simplefb_fix = { + .id = "simple", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .accel = FB_ACCEL_NONE, +}; + +static struct fb_var_screeninfo simplefb_var = { + .height = -1, + .width = -1, + .activate = FB_ACTIVATE_NOW, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + u32 *pal = info->pseudo_palette; + u32 cr = red >> (16 - info->var.red.length); + u32 cg = green >> (16 - info->var.green.length); + u32 cb = blue >> (16 - info->var.blue.length); + u32 value; + + if (regno >= 16) + return -EINVAL; + + value = (cr << info->var.red.offset) | + (cg << info->var.green.offset) | + (cb << info->var.blue.offset); + if (info->var.transp.length > 0) { + u32 mask = (1 << info->var.transp.length) - 1; + mask <<= info->var.transp.offset; + value |= mask; + } + pal[regno] = value; + + return 0; +} + +static struct fb_ops simplefb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = simplefb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +struct simplefb_format { + const char *name; + u32 bits_per_pixel; + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; +}; + +static struct simplefb_format simplefb_formats[] = { + { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0} }, +}; + +struct simplefb_params { + u32 width; + u32 height; + u32 stride; + struct simplefb_format *format; +}; + +static int simplefb_parse_dt(struct platform_device *pdev, + struct simplefb_params *params) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + const char *format; + int i; + + ret = of_property_read_u32(np, "width", ¶ms->width); + if (ret) { + dev_err(&pdev->dev, "Can't parse width property\n"); + return ret; + } + + ret = of_property_read_u32(np, "height", ¶ms->height); + if (ret) { + dev_err(&pdev->dev, "Can't parse height property\n"); + return ret; + } + + ret = of_property_read_u32(np, "stride", ¶ms->stride); + if (ret) { + dev_err(&pdev->dev, "Can't parse stride property\n"); + return ret; + } + + ret = of_property_read_string(np, "format", &format); + if (ret) { + dev_err(&pdev->dev, "Can't parse format property\n"); + return ret; + } + params->format = NULL; + for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) { + if (strcmp(format, simplefb_formats[i].name)) + continue; + params->format = &simplefb_formats[i]; + break; + } + if (!params->format) { + dev_err(&pdev->dev, "Invalid format value\n"); + return -EINVAL; + } + + return 0; +} + +static int simplefb_probe(struct platform_device *pdev) +{ + int ret; + struct simplefb_params params; + struct fb_info *info; + struct resource *mem; + + if (fb_get_options("simplefb", NULL)) + return -ENODEV; + + ret = simplefb_parse_dt(pdev, ¶ms); + if (ret) + return ret; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "No memory resource\n"); + return -EINVAL; + } + + info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev); + if (!info) + return -ENOMEM; + platform_set_drvdata(pdev, info); + + info->fix = simplefb_fix; + info->fix.smem_start = mem->start; + info->fix.smem_len = resource_size(mem); + info->fix.line_length = params.stride; + + info->var = simplefb_var; + info->var.xres = params.width; + info->var.yres = params.height; + info->var.xres_virtual = params.width; + info->var.yres_virtual = params.height; + info->var.bits_per_pixel = params.format->bits_per_pixel; + info->var.red = params.format->red; + info->var.green = params.format->green; + info->var.blue = params.format->blue; + info->var.transp = params.format->transp; + + info->fbops = &simplefb_ops; + info->flags = FBINFO_DEFAULT; + info->screen_base = devm_ioremap(&pdev->dev, info->fix.smem_start, + info->fix.smem_len); + if (!info->screen_base) { + framebuffer_release(info); + return -ENODEV; + } + info->pseudo_palette = (void *)(info + 1); + + ret = register_framebuffer(info); + if (ret < 0) { + dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); + framebuffer_release(info); + return ret; + } + + dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node); + + return 0; +} + +static int simplefb_remove(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + + unregister_framebuffer(info); + framebuffer_release(info); + + return 0; +} + +static const struct of_device_id simplefb_of_match[] = { + { .compatible = "simple-framebuffer", }, + { }, +}; +MODULE_DEVICE_TABLE(of, simplefb_of_match); + +static struct platform_driver simplefb_driver = { + .driver = { + .name = "simple-framebuffer", + .owner = THIS_MODULE, + .of_match_table = simplefb_of_match, + }, + .probe = simplefb_probe, + .remove = simplefb_remove, +}; +module_platform_driver(simplefb_driver); + +MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>"); +MODULE_DESCRIPTION("Simple framebuffer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index e328a61b64ba..296279bc71d2 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -24,9 +24,6 @@ #ifdef CONFIG_X86 #include <video/vga.h> #endif -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif #include "edid.h" static struct cb_id uvesafb_cn_id = { @@ -1540,67 +1537,30 @@ static void uvesafb_init_info(struct fb_info *info, struct vbe_mode_ib *mode) static void uvesafb_init_mtrr(struct fb_info *info) { -#ifdef CONFIG_MTRR + struct uvesafb_par *par = info->par; + if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) { int temp_size = info->fix.smem_len; - unsigned int type = 0; - switch (mtrr) { - case 1: - type = MTRR_TYPE_UNCACHABLE; - break; - case 2: - type = MTRR_TYPE_WRBACK; - break; - case 3: - type = MTRR_TYPE_WRCOMB; - break; - case 4: - type = MTRR_TYPE_WRTHROUGH; - break; - default: - type = 0; - break; - } + int rc; - if (type) { - int rc; + /* Find the largest power-of-two */ + temp_size = roundup_pow_of_two(temp_size); - /* Find the largest power-of-two */ - temp_size = roundup_pow_of_two(temp_size); + /* Try and find a power of two to add */ + do { + rc = arch_phys_wc_add(info->fix.smem_start, temp_size); + temp_size >>= 1; + } while (temp_size >= PAGE_SIZE && rc == -EINVAL); - /* Try and find a power of two to add */ - do { - rc = mtrr_add(info->fix.smem_start, - temp_size, type, 1); - temp_size >>= 1; - } while (temp_size >= PAGE_SIZE && rc == -EINVAL); - } + if (rc >= 0) + par->mtrr_handle = rc; } -#endif /* CONFIG_MTRR */ } static void uvesafb_ioremap(struct fb_info *info) { -#ifdef CONFIG_X86 - switch (mtrr) { - case 1: /* uncachable */ - info->screen_base = ioremap_nocache(info->fix.smem_start, info->fix.smem_len); - break; - case 2: /* write-back */ - info->screen_base = ioremap_cache(info->fix.smem_start, info->fix.smem_len); - break; - case 3: /* write-combining */ - info->screen_base = ioremap_wc(info->fix.smem_start, info->fix.smem_len); - break; - case 4: /* write-through */ - default: - info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); - break; - } -#else - info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); -#endif /* CONFIG_X86 */ + info->screen_base = ioremap_wc(info->fix.smem_start, info->fix.smem_len); } static ssize_t uvesafb_show_vbe_ver(struct device *dev, @@ -1851,6 +1811,7 @@ static int uvesafb_remove(struct platform_device *dev) unregister_framebuffer(info); release_region(0x3c0, 32); iounmap(info->screen_base); + arch_phys_wc_del(par->mtrr_handle); release_mem_region(info->fix.smem_start, info->fix.smem_len); fb_destroy_modedb(info->monspecs.modedb); fb_dealloc_cmap(&info->cmap); @@ -1930,6 +1891,9 @@ static int uvesafb_setup(char *options) } } + if (mtrr != 3 && mtrr != 1) + pr_warn("uvesafb: mtrr should be set to 0 or 3; %d is unsupported", mtrr); + return 0; } #endif /* !MODULE */ diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c index 18e8bd8fa947..0f0493c63371 100644 --- a/drivers/xen/tmem.c +++ b/drivers/xen/tmem.c @@ -41,6 +41,8 @@ module_param(selfballooning, bool, S_IRUGO); #ifdef CONFIG_FRONTSWAP static bool frontswap __read_mostly = true; module_param(frontswap, bool, S_IRUGO); +#else /* CONFIG_FRONTSWAP */ +#define frontswap (0) #endif /* CONFIG_FRONTSWAP */ #ifdef CONFIG_XEN_SELFBALLOONING @@ -377,10 +379,10 @@ static int xen_tmem_init(void) #ifdef CONFIG_FRONTSWAP if (tmem_enabled && frontswap) { char *s = ""; - struct frontswap_ops *old_ops = - frontswap_register_ops(&tmem_frontswap_ops); + struct frontswap_ops *old_ops; tmem_frontswap_poolid = -1; + old_ops = frontswap_register_ops(&tmem_frontswap_ops); if (IS_ERR(old_ops) || old_ops) { if (IS_ERR(old_ops)) return PTR_ERR(old_ops); diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index a2278ba7fb27..4e8ba38aa0c9 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -106,7 +106,7 @@ static void pcistub_device_release(struct kref *kref) else pci_restore_state(dev); - if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { + if (dev->msix_cap) { struct physdev_pci_device ppdev = { .seg = pci_domain_nr(dev->bus), .bus = dev->bus->number, @@ -371,7 +371,7 @@ static int pcistub_init_device(struct pci_dev *dev) if (err) goto config_release; - if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) { + if (dev->msix_cap) { struct physdev_pci_device ppdev = { .seg = pci_domain_nr(dev->bus), .bus = dev->bus->number, diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 61786be9138b..ec097d6f964d 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -534,7 +534,7 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, err = xenbus_map_ring(dev, gnt_ref, &node->handle, addr); if (err) - goto out_err; + goto out_err_free_ballooned_pages; spin_lock(&xenbus_valloc_lock); list_add(&node->next, &xenbus_valloc_pages); @@ -543,8 +543,9 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, *vaddr = addr; return 0; - out_err: + out_err_free_ballooned_pages: free_xenballooned_pages(1, &node->page); + out_err: kfree(node); return err; } diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h index c8abd3b8a6c4..e74f9c1fbd80 100644 --- a/drivers/xen/xenbus/xenbus_comms.h +++ b/drivers/xen/xenbus/xenbus_comms.h @@ -45,6 +45,7 @@ int xb_wait_for_data_to_read(void); int xs_input_avail(void); extern struct xenstore_domain_interface *xen_store_interface; extern int xen_store_evtchn; +extern enum xenstore_init xen_store_domain_type; extern const struct file_operations xen_xenbus_fops; diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 3325884c693f..56cfaaa9d006 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -69,6 +69,9 @@ EXPORT_SYMBOL_GPL(xen_store_evtchn); struct xenstore_domain_interface *xen_store_interface; EXPORT_SYMBOL_GPL(xen_store_interface); +enum xenstore_init xen_store_domain_type; +EXPORT_SYMBOL_GPL(xen_store_domain_type); + static unsigned long xen_store_mfn; static BLOCKING_NOTIFIER_HEAD(xenstore_chain); @@ -719,17 +722,11 @@ static int __init xenstored_local_init(void) return err; } -enum xenstore_init { - UNKNOWN, - PV, - HVM, - LOCAL, -}; static int __init xenbus_init(void) { int err = 0; - enum xenstore_init usage = UNKNOWN; uint64_t v = 0; + xen_store_domain_type = XS_UNKNOWN; if (!xen_domain()) return -ENODEV; @@ -737,29 +734,29 @@ static int __init xenbus_init(void) xenbus_ring_ops_init(); if (xen_pv_domain()) - usage = PV; + xen_store_domain_type = XS_PV; if (xen_hvm_domain()) - usage = HVM; + xen_store_domain_type = XS_HVM; if (xen_hvm_domain() && xen_initial_domain()) - usage = LOCAL; + xen_store_domain_type = XS_LOCAL; if (xen_pv_domain() && !xen_start_info->store_evtchn) - usage = LOCAL; + xen_store_domain_type = XS_LOCAL; if (xen_pv_domain() && xen_start_info->store_evtchn) xenstored_ready = 1; - switch (usage) { - case LOCAL: + switch (xen_store_domain_type) { + case XS_LOCAL: err = xenstored_local_init(); if (err) goto out_error; xen_store_interface = mfn_to_virt(xen_store_mfn); break; - case PV: + case XS_PV: xen_store_evtchn = xen_start_info->store_evtchn; xen_store_mfn = xen_start_info->store_mfn; xen_store_interface = mfn_to_virt(xen_store_mfn); break; - case HVM: + case XS_HVM: err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); if (err) goto out_error; diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h index bb4f92ed8730..146f857a36f8 100644 --- a/drivers/xen/xenbus/xenbus_probe.h +++ b/drivers/xen/xenbus/xenbus_probe.h @@ -47,6 +47,13 @@ struct xen_bus_type { struct bus_type bus; }; +enum xenstore_init { + XS_UNKNOWN, + XS_PV, + XS_HVM, + XS_LOCAL, +}; + extern struct device_attribute xenbus_dev_attrs[]; extern int xenbus_match(struct device *_dev, struct device_driver *_drv); diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 3159a37d966d..a7e25073de19 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -29,6 +29,8 @@ #include "xenbus_probe.h" +static struct workqueue_struct *xenbus_frontend_wq; + /* device/<type>/<id> => <type>-<id> */ static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename) { @@ -89,9 +91,40 @@ static void backend_changed(struct xenbus_watch *watch, xenbus_otherend_changed(watch, vec, len, 1); } +static void xenbus_frontend_delayed_resume(struct work_struct *w) +{ + struct xenbus_device *xdev = container_of(w, struct xenbus_device, work); + + xenbus_dev_resume(&xdev->dev); +} + +static int xenbus_frontend_dev_resume(struct device *dev) +{ + /* + * If xenstored is running in this domain, we cannot access the backend + * state at the moment, so we need to defer xenbus_dev_resume + */ + if (xen_store_domain_type == XS_LOCAL) { + struct xenbus_device *xdev = to_xenbus_device(dev); + + if (!xenbus_frontend_wq) { + pr_err("%s: no workqueue to process delayed resume\n", + xdev->nodename); + return -EFAULT; + } + + INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume); + queue_work(xenbus_frontend_wq, &xdev->work); + + return 0; + } + + return xenbus_dev_resume(dev); +} + static const struct dev_pm_ops xenbus_pm_ops = { .suspend = xenbus_dev_suspend, - .resume = xenbus_dev_resume, + .resume = xenbus_frontend_dev_resume, .freeze = xenbus_dev_suspend, .thaw = xenbus_dev_cancel, .restore = xenbus_dev_resume, @@ -440,6 +473,8 @@ static int __init xenbus_probe_frontend_init(void) register_xenstore_notifier(&xenstore_notifier); + xenbus_frontend_wq = create_workqueue("xenbus_frontend"); + return 0; } subsys_initcall(xenbus_probe_frontend_init); |